(CI/CD, Github Actions) Github Actions를 활용한 SSH 접속, git push 코드 자동 배포
CI/CD란 각각 CI(Continuous Integration/지속적 통합), CD(Continuous Deployment/지속적 배포)의 약어로, 코드를 수정하고 테스트 후 빌드, 배포 하는 과정을 개발자의 수동적인 개입 없이, 자동으로 진행하는 것을 의미한다.
이번 글에는 진짜 단순히 나의 편의를 위해 작성한, Github Actions를 활용한 CI 과정을 소개해 보려고 한다.
현재 내가 사용중인 코드는 SSH 터널링, AWS EC2 Security Group 수정, SLACK 배포 완료 / 배포 성공 알림 과정이 포함되어 있지만, 이 부분을 추가하면 내용이 길어질 것 같으므로 아래의 간단한 과정으로 진행해보려고 한다.
- Github Actions 설정
- Actions secrets 설정
- Workflow 파일 작성 (ssh, git pull, ci skip 분기)
- 실행 결과 (성공, 실패, 스킵)
이렇게 진행하는 게 정답이 아닐 수도 있지만, 로컬에서 개발 서버로 배포하는 시간만 체감상 3분 넘게 줄일 수 있다. 점점 코드를 수정해 나가야지..
1. Github Actions
Github Actions를 활용하는 과정에 알아야 하는 용어들과 개념은 대표적으로 Workflow, Event, Job, Step, Runner가 있다. 수많은 블로그에서 이 내용을 다뤘을 것이므로, 간단하게 한 줄씩만 쓰고 넘어갈 것이다.
- Workflow : 가장 최상위 개념으로, .github/workflows 폴더 안에 .yaml 파일로 저장된다.
- Event : push나 pr 등 Workflow를 실행하기 위한 활동들이다.
- Jobs : 하위 개념인 steps 들이 묶어져 하나의 job이 된다.
- Steps : 실제로 실행되는 내용이 정의되어 있는 블록이고, name, run, with 등으로 정의한다.
- Runner : 위의 Workflow를 실행하는 주체이다. 직접 host중인 인스턴스를 정의할 수 있고, 기본적으로는 github에서 제공하는 인스턴스가 활용된다.
Github Actions의 Workflow를 작성하는 방법은 두 가지가 있다.
- github actions에서 제공하는 템플릿을 수정
- 직접 .github/workflows 폴더 안에 파일 작성
어차피 나는 2번을 할 것이지만, 그래도 1번을 한번 살펴보면 다음과 같다.
본인의 repo에서 Actions 탭에 들어가면, (한 번도 workflow를 생성하지 않았다면) 아래와 같이 Get Started 창이 나타난다.
원하는 워크플로우에 Configure 버튼을 누르면 다음과 같이 .yaml 코드 프리셋이 작성되어 있다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | # This workflow will do a clean installation of node dependencies, cache/restore them, build the source code and run tests across different versions of node # For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions name: Node.js CI on: push: branches: [ "master" ] pull_request: branches: [ "master" ] jobs: build: runs-on: ubuntu-latest strategy: matrix: node-version: [12.x, 14.x, 16.x] # See supported Node.js release schedule at https://nodejs.org/en/about/releases/ steps: - uses: actions/checkout@v3 - name: Use Node.js $ uses: actions/setup-node@v3 with: node-version: $ cache: 'npm' - run: npm ci - run: npm run build --if-present - run: npm test | cs |
위의 코드를 토대로 Github Actions를 설명해 보면 다음과 같다.
- 4번째 줄 : 해당 워크플로우의 이름을 지정해 준다. 나중에 Actions 탭에서 나타나게 될 작업 이름이다.
- 6~10번째 줄 : 해당 워크플로우가 실행되는 event이다. 위의 코드의 경우 “master” branch에서 push 혹은 pr이 일어났을 경우 동작한다.
- 12~ 번째 줄 : jobs가 정의되는 부분이다. build 아래에 인스턴스의 이미지를 정의해 줄 수 있다.
- 22~ 번째 줄 : jobs가 실행되는 순서이다. 23 번째 줄과 같이 사용할 모듈을 정의해줄 수도 있고, run 커맨드에 의해 순서대로 실행된다.
저 상태로 Start commit 버튼을 클릭하면 그대로 파일이 생성되고, .github/workflows 폴더에 .yaml 파일이 생성되는 것을 확인할 수 있다.
나는 직접 .yaml 파일을 만드는 게 더 편해서(형식은 같다), 프로젝트 폴더에 .github/works 폴더를 만든 후 .yaml 파일을 만든 후 commit/push 할 예정이다.
workflow 파일을 작성하기 전, 배포되어서는 안되는 정보들을 Actions secrets에 넣는 과정을 먼저 진행해 보자.
2. Actions secrets
github에서는 code에 배포되어서는 안되는 secret 한 내용들을 위해 secret params를 저장할 공간을 제공하는데, 각 repo의 Settings - Secrets 탭에서 확인할 수 있다.
한번도 secret params를 만든 적이 없으면, 아래의 이미지처럼 나타난다.
New repository secret을 눌러 Host IP 혹은 port 등 secret params들을 입력해 주자.
참고로 이 글에서 활용하고자 하는 ssh 스크립트는 appleboy 의 스크립트이다. 필수적으로 필요한 항목은 ssh key, host, username, port 이니, 해당 항목들은 필수적으로 추가해주도록 하자.
추가한 이후엔 내용을 확인할 수는 없고 값을 수정/삭제만 가능하다. 본인이 활용할 이름과 값으로 잘 만들어 주자.
3. Workflow 작성
나의 경우에는 로컬에서 “dev” branch를 pull한 후 작업 후 push 하면 ec2 서버에서 git pull 명령어가 실행되게끔 하는게 목표이므로, 직접 아래와 같이 파일을 작성했다.
다만 커밋 메시지에 [skipci] 혹은 [ciskip]라는 문구가 포함되면 CI 과정을 건너뛰게끔 하기 위해, if를 활용해 추가해 주었다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | name: deploy dev code on: push: branches: [ "dev" ] jobs: SSH: runs-on: ubuntu-latest if: >- $ steps: - name: Run a multi-line script uses: appleboy/ssh-action@master with: key: $ host: $ username: $ port: $ script: | cd ~/src;git pull origin dev if: always() | cs |
위의 코드의 각 줄에 대해 살펴보자면 다음과 같다.
- 1번째 줄 : 위에서 설명했던 바와 같이 해당 workflow의 이름을 정의해줄 수 있다.
- 3~5번째 줄 : dev branch에서 push가 발생했을 시 아래의 명령을 수행한다.
- 10~13번째 줄 : commit 메시지에 [skipci] 혹은 [ciskip] 이 포함되어 있지 않을 경우만 아래의 명렁어가 실행된다 (!contains)
- 16~ 번째 줄 : appleboy의 ssh-action 모듈을 활용해 with 줄 아래의 key, host, username, port로 접속해, 그 아래의 script를 실행한다. 나의 경우엔 단순히 git pull origin dev를 진행하는 것을 목표로 했다.
- 25번째 줄 : 이번 코드엔 큰 영향이 없지만, 각 steps는 always() 혹은 failure() 를 갖게 되는데, 이에 따라 다른 내용들을 정의해줄 수도 있다. (ex: 성공시 slack post 등)
이제 코드가 잘 작동하는지 확인하기 위해, 해당 .yaml 파일을 커밋하고 실제로 push를 진행 해 보자.
4. 실행 결과
workflow가 성공했을 경우, 실패했을 경우, 스킵되었을 경우를 나누어서 살펴보면 아래와 같다.
- workflow가 성공했을 경우
- workflow가 실패했을 경우
- workflow가 스킵되었을 경우
3에서 언급했다시피 위의 경우는 always(), success(), failure() 등으로 잡을 수 있는데, 이를 활용해 다양한 과정을 정의할 수 있다.
5. 결론
나의 경우엔 [build] 명령어가 포함되면 build를 진행하고, docker container들이 성공적으로 띄워지면 slack post를 보내는 등의 내용을 정의해서 사용하는 중이다.
또한 위의 경우엔 cd, git pull 등의 명령어를 직접 입력했지만, alias를 활용하거나 sh 파일에 정의해 실행하는 등 상당히 다양한 커스터마이징이 가능하다.
덧붙여 테스트 코드를 실행하는 과정까지 추가한다면, Jenkins 등의 툴 없이도 소규모 서버에서의 CI/CD는 충분히 가능할 정도라고 생각된다(개인 생각).
이처럼 Github Actions를 잘 활용하면 CI 과정이 상당히 편해질 수 있고, 각자의 입맛에 맞게 정의할 수 있다. 다들 편하게 할 수 있는 부분은 편하게 할 수 있는 개발자가 되길 바라며..
댓글남기기