-
GitHub Actions로 회사 서버에 WAR 파일 자동 배포하기GitHub/GitHub Actions 2024. 7. 10. 19:19
Spring Framework를 사용해서 만든 근태관리 사이트(회사 내부에서 사용하는)를 GitHub에서 버전관리 하고 있다.
이번에 받은 업무는 GitHub main 브랜치에 코드가 push되면 자동으로 Java 웹 애플리케이션을 빌드하고 WAR 파일을 원격 서버에 배포하는 작업을 맡게 되었다.
처음 해보는 작업이었지만 해보고 싶었던 작업이라서 열심히 작업을 했고 완성할 수 있었다.
많은 시행착오가 있었던 만큼 기록으로 남기려고 한다.
Project: Maven Project
Language: Java
Spring Framework
openjdk(Java 8)
GitHub Actions를 통한 ROOT.war 자동배포
1 ) 작성된 GitHub Actions workflow의 목적
1. Java 웹 애플리케이션을 빌드한다.
2. WAR 파일을 원격 서버에 배포한다.
name: remote ssh command on: push: branches: - main jobs: Spring-Build-ssh-action: runs-on: ubuntu-latest name: Build and Deploy steps: - name: Checkout Repository uses: actions/checkout@v2 - name: Set up JDK 8 uses: actions/setup-java@v1 with: java-version: 8 distribution: 'adopt' - name: Build with Maven run: mvn clean package - name: Rename WAR file to ROOT.war run: mv target/*.war target/ROOT.war - name: Verify if ROOT.war file exists run: ls target/ROOT.war - name: SSH remote command for backup and WAR deployment uses: appleboy/ssh-action@v1.0.3 with: host: ${{ secrets.SERVER_HOST }} username: ${{ secrets.SERVER_USERNAME }} key: ${{ secrets.SERVER_SSH_KEY }} port: ${{ secrets.PORT }} script: | TIMESTAMP=$(date +%Y%m%d%H%M) mv /[서버webapps경로입력]/ROOT.war /[서버webapps경로입력]/ROOT.war_$TIMESTAMP - name: Add SSH known hosts run: | mkdir -p ~/.ssh echo "${{ secrets.SERVER_SSH_KEY }}" | tr -d '\r' > ~/.ssh/id_rsa chmod 600 ~/.ssh/id_rsa echo "Scanning host: ${{ secrets.SERVER_HOST }}" ssh-keyscan -H ${{ secrets.SERVER_HOST }} >> ~/.ssh/known_hosts echo "Known hosts after scanning:" cat ~/.ssh/known_hosts - name: SCP transfer ROOT.war to remote server2 run: | scp -v -P ${{ secrets.PORT }} target/ROOT.war ${{ secrets.SERVER_USERNAME }}@${{ secrets.SERVER_HOST }}:/[서버webapps경로입력]
2 ) 자세한 진행과정
1 . Workflow 구조
- Trigger : 워크플로우를 실행시키는 조건을 정의.
- Jobs : 독립적으로 실행될 수 있는 하나 이상의 작업 단위를 정의. (여러 Jobs가 있을 때 기본적으로 병렬로 실행된다.)
- Steps : Jobs 내에서 실행되는 개별 명령이나 액션을 정의. (빌드, 테스트, 배포 작업 등)
2. deploy.yml 분석
(Trigger) - 트리거
on: push: branches: - main
- main 브랜치에 코드가 푸시될 때 실행된다.
(Jobs) - 작업
jobs: Spring-Build-ssh-action: runs-on: ubuntu-latest name: Build and Deploy
- Spring-Build-ssh-action 이라는 작업이름을 지음(내맘)
- ubuntu-latest 환경에서 실행된다는 것을 알려준다.
(Steps) - 단계
steps: - name: Checkout Repository uses: actions/checkout@v2
- Checkout Repository 이름을 정의
- actions/checkout@v2 액션을 사용하여 리포지토리를 체크아웃한다.
- name: Set up JDK 8 uses: actions/setup-java@v1 with: java-version: 8 distribution: 'adopt'
- Set up JDK 8 이름을 정의
- actions/setup-java@v1 액션을 사용해서 Java 8을 설치 및 설정한다.
- name: Build with Maven run: mvn clean package
- Maven을 사용해서 Java 프로젝트를 빌드한다.
- name: Rename WAR file to ROOT.war run: mv target/*.war target/ROOT.war
- 빌드된 WAR 파일을 ROOT.war로 이름을 변경한다.
- name: Verify if ROOT.war file exists run: ls target/ROOT.war
- ROOT.war 파일이 제대로 생성되었는지 확인한다.
- name: SSH remote command for backup and WAR deployment uses: appleboy/ssh-action@v1.0.3 with: host: ${{ secrets.SERVER_HOST }} username: ${{ secrets.SERVER_USERNAME }} key: ${{ secrets.SERVER_SSH_KEY }} port: ${{ secrets.PORT }} script: | TIMESTAMP=$(date +%Y%m%d%H%M) mv /[서버webapps 경로입력]/ROOT.war /[서버webapps 경로입력]/ROOT.war_$TIMESTAMP
- appleboy/ssh-action을 사용해서 원격서버에 접속 후 기존에 있던 ROOT.war 파일의 이름을 ROOT.war_오늘날짜시간으로 변경 및 백업.
- name: Add SSH known hosts run: | mkdir -p ~/.ssh echo "${{ secrets.SERVER_SSH_KEY }}" | tr -d '\r' > ~/.ssh/id_rsa chmod 600 ~/.ssh/id_rsa echo "Scanning host: ${{ secrets.SERVER_HOST }}" ssh-keyscan -H ${{ secrets.SERVER_HOST }} >> ~/.ssh/known_hosts echo "Known hosts after scanning:" cat ~/.ssh/known_hosts
- ~/.ssh 디렉토리가 존재하지 않으면 새로 생성한다.
- ${{ secrets.SERVER_SSH_KEY }} 에 저장된 개인 키를 읽어서 ~/.ssh/id_rsa 파일에 저장한다.
- ~/.ssh/id_rsa 파일의 권한을 설정한다. (600 권한은 파일 소유자에게 읽기 및 쓰기 권한을 부여하고 다른 사용자에게는 접근 권한을 부여하지 않는다.) - SSH 키 파일의 보안을 유지하기 위해 중요....!
- ssh-keyscan을 사용해서 원격 서버의 호스트 키를 스캔하고 ~/.ssh/known_hosts 파일에 추가한다. (known_hosts 파일은 SSH 클라이언트가 원격 서버의 호스트 키를 확인하는 데 사용한다. - 중간자 공격을 방지하고 SSH 연결을 할 때 호스트의 신뢰성을 확인하기 위해 필요)
- name: SCP transfer ROOT.war to remote server2 run: | scp -v -P ${{ secrets.PORT }} target/ROOT.war ${{ secrets.SERVER_USERNAME }}@${{ secrets.SERVER_HOST }}:/[서버webapps 경로입력]
- scp 명령어를 사용해서 GitHub Actions 가상 환경에서 빌드된 ROOT.war 파일을 원격 서버의 Tomcat 웹앱 디렉토리로 전송한다.
3 ) 사전작업으로 필요했던 일들
1. 내 로컬 컴퓨터에 SSH 키를 생성한다. (Windows PowerShell(관리자))
ssh-keygen -t rsa -b 4096 -C "your_email@example.com"
1-1. 서버 컴퓨터에서 기존 사용자 말고 새로운 사용자를 만들어서 작업을 해야한다면 (회사 서버컴퓨터는 ubuntu )
ssh username@server_ip //ssh를 통해 서버에 접속
sudo adduser [username]
- 기존에 존재하는 사용자로 ssh를 통해 서버에 접속을 한다.
- sudo adduser [사용할 아이디 입력] 을 통해서 새로운 유저를 만든다.
1-2. 만약 sudo 권한을 부여해야 한다면
sudo visudo
- sudo 권한이 있는 기존 사용자로 명령어 입력
- '[사용할 아이디] ALL=(ALL:ALL) ALL 를 입력한다.
- Ctrl + x 그리고 Y를 눌러서 저장한다. (마지막으로 Enter를 눌러서 나간다.)
2. 내 로컬에서 생성한 SSH 공개키(~/.ssh/id_rsa.pub)를 서버 컴퓨터에 등록한다.
(내 로컬 Windows PowerShell(관리자)에서 실행)
cat ~/.ssh/id_rsa.pub | ssh username@server_ip "mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys"
- username ==> 서버에 등록된 사용자 이름 입력
- server_ip ==> 서버의 ip주소를 입력 (우리회사 서버는 내부에서 관리하기 떄문에 내부ip 주소를 입력하면 된다.)
- 이 명령어를 실행하면 로컬에서 공개키 파일을 열어와서 SSH를 통해 서버에 전송하고 서버에서 사용자의 authorized_keys 파일에 추가한다.
3. 생성된 SSH 개인키(~/.hhs/id_rsa)를 GitHub의 Actions Secrete and Variables에 추가한다.
Get-Content ~/.ssh/id_rsa | Set-Clipboard
- SSH 개인 키 파일(~/.ssh/id_rsa)의 내용을 읽어와서 클립보드에 복사한다. (드래그로 복사하면 오류날까봐 불안해서...)
- 프로젝트명/settings/secrets/actions 경로에서 New repository secret 버튼을 눌러서 추가해준다.
4 ) 작업하면서 헤맸던 부분
debug1: Authentications that can continue: publickey,password
debug1: Next authentication method: publickey~~~~
~~~~
~~~~
debug1: Next authentication method: password
debug1: Authentications that can continue: publickey,password
Permission denied, please try again.GitHub Actions 디버깅 과정에서 이런 문구가 계속 나오면서 실패었었다.
GPT한테 물어보면 호스트 키 뭐라뭐라.....
이상했던건 이 부분은 잘 실행되는데
- name: SSH remote command for backup and WAR deployment uses: appleboy/ssh-action@v1.0.3 with: host: ${{ secrets.SERVER_HOST }} username: ${{ secrets.SERVER_USERNAME }} key: ${{ secrets.SERVER_SSH_KEY }} port: ${{ secrets.PORT }} script: | TIMESTAMP=$(date +%Y%m%d%H%M) mv /[서버webapps 경로입력]/ROOT.war /[서버webapps 경로입력]/ROOT.war_$TIMESTAMP
이 부분에서 오류가 난다는거 였는데.......(위쪽에서 ssh로 서버에 접속 잘 해서 ROOT.war 이름도 변경했으면서
왜 밑에서는 오류가 났는지 이해가 안되었다...
- name: SCP transfer ROOT.war to remote server2 run: | scp -v -P ${{ secrets.PORT }} target/ROOT.war ${{ secrets.SERVER_USERNAME }}@${{ secrets.SERVER_HOST }}:/[서버webapps 경로입력]
debug1: Authentications that can continue: publickey,password
debug1: Next authentication method: publickey~~~~
~~~~
~~~~
debug1: Next authentication method: password
debug1: Authentications that can continue: publickey,password
Permission denied, please try again.GPT한테 물어보거나 여러 블로그 및 여러 사이트를 방문해서 의심되는 부분은
내가 ssh key를 만드는 과정에서 "Enter passphrase (empty for no passphrase)" 라는 키페어에 암호를 설정해서 계속 오류가 난다는 생각이 들었다.
그래서 처음부터 서버에서 사용할 사용자를 만들고 로컬에 있는 ssh 키를 새로 만들고
Enter passphrase (empty for no passphrase): 문구가 나왔을 때 그냥 Enter를 눌렀다.
실행 결과 ssh 검증하는 과정이 통과되었다.
- name: SSH remote command for backup and WAR deployment uses: appleboy/ssh-action@v1.0.3 with: host: ${{ secrets.SERVER_HOST }} username: ${{ secrets.SERVER_USERNAME }} key: ${{ secrets.SERVER_SSH_KEY }} port: ${{ secrets.PORT }} script: | TIMESTAMP=$(date +%Y%m%d%H%M) mv /[서버webapps 경로입력]/ROOT.war /[서버webapps 경로입력]/ROOT.war_$TIMESTAMP
잠시 이부분을 주석처리 해놓고- name: SCP transfer ROOT.war to remote server2 run: | scp -v -P ${{ secrets.PORT }} target/ROOT.war ${{ secrets.SERVER_USERNAME }}@${{ secrets.SERVER_HOST }}:/[서버webapps 경로입력]
이 부분을 테스트 할 때
파일 전송을 시도할 때 기존에 있던 ROOT.war를 덮어씌울려고 하니깐 권한이 필요했었다.
위에 내용을 주석을 풀어줘서 기존에 있던 ROOT.war 이름을 바꿔서 백업을 해주고 실행하니깐 권한 오류가 사라졌다.
오류없이 잘 실행이 되었고 서버에 WAR파일이 잘 배포되었지만
궁금한 점이 생겼다...
ROOT.war 파일 이름 바꾸는건 권한 오류가 안뜨고 ROOT.war파일을 덮어쓰는거는 권한이 필요하다는게 이해가 안되었다... 둘다 쓰기 권한 있으면 되는거 아닌가...??
파일 덮어쓰기 할때는 상위 폴더의 권한에 쓰기 권한이 없으면 오류가 나는건가??? 아직도 이해가 안된다...
'GitHub > GitHub Actions' 카테고리의 다른 글
GitHub Actions를 통해서 빌드 후 서버 컴퓨터에 도커 컨테이너 실행 (Docker Hub 이용) (0) 2024.11.27