안녕하세요! 깃허브 액션(GitHub Actions)을 활용하여 SSH를 이용해 Node 어플리케이션을 손쉽게 자동으로 배포하는 방법에 대해 알아보겠습니다. 

이 글을 따라 진행하면, 코드 변경 사항이 발생할 때마다 신속하게 프로젝트를 업데이트하고 서버에서 어플리케이션을 다시 시작할 수 있도록 여러분의 개발 환경을 구성할 수 있습니다.
특별히 빌드와 테스트 보다는 배포에 중심을 둔 글이니 이 점 참고하시고 보시길 바랍니다.

GitHub Actions?

GitHub Actions는 GitHub에서 제공하는 CI(Continuous Integration, 지속적 통합)/CD(Continuous Deployment, 지속 배포) 파이프라인을 구성할수 있게 해주는 플랫폼 입니다.
Workflow를 작성하여 빌드, 테스트, 배포를 자동화 할 수 있게 서비스를 제공하고 있습니다.

GitHub Actions Workflow 작성하기

우선 깃허브 액션을 사용하기 위해서는 워크플로를 작성할 Git 저장소가 필요합니다.
GitHub 계정이 없으신 분들은 GitHub을 계정을 생성하신 후에 GitHub Actions를 사용할 Repository를 생성해주세요.

Workflow

워크플로는 Github actions가 실행되기 위한 모든 과정을 작성하는 문서입니다.
YAML 포맷을 이용해 작성하며 저장위치는 repository 내 .githubs/workflows 디렉토리 아래 저장하여 관리합니다.

Workflow 파일 생성하기

워크플로를 생성하는 방법은 두가지입니다.
- 직접 에디터를 통해 작성하는 방법
- GitHub에서 제공하는 샘플들을 이용해 작성하는 방법

첫번째, 직접 에디터를 통해 작성하는 방법입니다.
아래 이미지처럼 직접 YAML 파일을 작성한 후 Repository에 커밋을 통해 저장소에 등록할 수 있습니다.

두번째, 제공된 샘플을 이용해 작성하는 방법입니다.

GitHub에서 자신의 저장소로 이동해 Actions 탭을 클릭하면 아래 이미지와 같이 여러 상황에 맞게 끔 GitHub 또는 여러 사용자들이 제공하고 있는 Sample 워크플로는 선택할 수 있습니다.

Workflow 분석하기

name은 워크플로의 이름입니다. 작성하지 않아도 워크플로의 동작에는 영향을 주지 않는 속성입니다.

on속성은 언제 이 워크플로가 실행되는지를 정의하는 속성입니다. 지금 작성 된 코드에서는 deploy 브랜치에 push 또는 PR(PullRequest)이 발생했을 때 이 워크플로를 실행하라고 정의하고 있습니다.
단순히 push와 PR에 대해서만 정의하는게 아니라 cron 방식을 사용해 특정 시점에 실행되도록 정의할 수도 있습니다.
아래 코드는 매일 오전 4시에 workflow 실행하라고 정의합니다.

jobs는 워크플로에서 실행될 작업을 정의하는 속성입니다.
워크플로는 기본적으로는 병렬로 실행되는 하나이상의 jobs로 구성된다고 github actions docs에서 설명하고 있습니다.
아래 작성 된 워크플로는 여러 개의 job으로 구성되어 있고, 각각의 job_id를 통해 어떤 환경에서 어떤 작업을 할 지 정의 하고 있니다.
 

jobs 안에 build, test, deploy 의 job들이 정의되어 있는 것을 볼 수 있습니다.
name 속성은 워크플로 상단의 name필드와 같은 역할을 합니다.
워크플로 상단의 name 속성은 워크플로의 이름을, jobs의 job 아래 있는 name 속성은 작업의 이름을 정의합니다.
여기서 정의한 이름은 GitHub UI에서 작업 이름으로 표시 됩니다.

각각의 작업은 같은 워크플로 내에 정의되어 있더라도 모두 다른 환경에서 독립적으로 실행 됩니다.
깃허브 액션에서는 각각의 작업이 실행되는 환경을 runner라고 합니다.

runs-on 속성은 어떤 runner 유형을 사용할지 정의하는 속성입니다. 
위에 작성된 코드에서는 깃허브에서 호스팅 해주는 서버를 사용하고 OS로는 ubuntu-latest 버전을 사용한다고 정의하고 있습니다.
깃허브에서 호스팅하는 서버를 이용하지 않고, 직접 runner를 등록하는 방법도 사용할 수 있습니다.
직접 runner를 등록하는 방법은 GitHub Docs에 나와 있으니 참고하시기 바랍니다.

실행환경까지 구성한 후에는 어떤 행동들을 할지 steps을 통해 정의해줄 수 있습니다.
워크플로가 한개 이상의 job(작업)으로 구성되어 있는것 처럼 작업 또한 한개 이상의 step들로 구성되어 있습니다.
step은 작업 안에서 순차적으로 실행됩니다.
run을 통해 실제로 step에서 실행할 행동들을 작성할 수 있습니다.
build 작업 안에 Hello와 Hello2 라는 step을 정의 했고, Hello에서는 “Hello, GitHub Actions!” 를, Hello2 에서는 “Hello, everyone!”를 출력하게 했습니다.

github에서 제공해주는 build 작업에 대한 실행 결과 입니다. Hello와, Hello2로 정의한 step들이 순차적으로 실행 된 모습을 볼 수 있습니다.

이렇게 워크플로의 기본적인 구성요소들을 보았습니다.
Github Docs에는 더 상세한 내용들이 기술되어 있으니, 실제 워크플로를 작성할 때에는 공식문서를 참고하셔서 작성하시면 더 많은 도움을 받을 수 있습니다.

다른 사람이 만들어둔 action 사용해보기

이미 많은 사람들이 GitHub를 이용해 개발을 하고 있습니다. GitHub Actions이 등장한 이후로 GitHub 그리고 많은 사용자들이 공통적인 흐름으로 진행되는 CI/CD를 더 편하게 사용하게 하기 위해 Workflow를 공유 한것처럼 공통적으로 사용하는 기능들을 Action으로 만들어두고 공유하고 있습니다.
공유 된 Actions들은 깃허브 마켓플레이스에서 확인하고 이용할 수 있습니다.

공유되어 있는 action을 사용하여 작업을 구성하는 연습을 해보겠습니다.

actions/checkout은 소스를 저장소(Repository)에서 내려받을 수 있게 도와주는 액션입니다.
위 액션을 사용하면 깃허브에서 제공해주는 runner에서 저장소의 소스를 내려받아 사용할 수 있습니다.
물론 직접 작업을 작성해서 runner에 저장소의 소스코드를 내려받을 수 있겠지만, 여러 사용자들이 업로드 한 액션을 이용한다면 더 빠르고 편리하게 여러가지 기능들을 이용할 수 있습니다.

Github Actions Secret

깃허브에서는 Secret이라는 것을 제공합니다.
Secret을 통해 actions를 사용하며 저장소에 올리기 민감한 정보들을 직접적으로 업로드하지 않고 사용할 수 있습니다.
Github Actions Secret은 Actions를 사용하려는 Repository의 Settings에서 등록할 수 있습니다.
Secrets and variables > actions로 접근하면 Actions에서 사용할 secret들을 등록할 수 있습니다.

등록은 등록 버튼을 통해 쉽게 등록할 수 있으며, 수정도 등록하는 것과 마찬가지의 방법으로 할 수 있지만 이전에 등록해 둔 값을 다시 확인할 수는 없습니다.

이렇게 저장소에 환경변수를 등록하면 워크플로에서도 등록된 변수명을 이용해 원하는 값을 직접 노출시키지 않고 사용할 수 있게 됩니다.
워크플로에서 환경변수로 저장한 시크릿을 사용하는 방법은 SSH로 직접 서버 연결하는 워크플로를 작성하며 확인하겠습니다.

SSH 연결을 이용해 반영 대상 서버 접속 시도하는 워크플로 작성하기

위에 작성된 YAML 파일을 사용하면 우리가 원하는 기능을 확인할 수 있습니다.
이제 작성한 워크플로를 다시 한번 살펴보겠습니다.
- deploy라는 이름을 가진 워크플로는 deploy 브랜치에 PR 이벤트가 발생했을 때 실행되며 build작업과 deploy 작업을 실행합니다.
- deploy 작업은 build작업이 실행 된 이후에 실행되게끔 needs 키워드를 통해 순서를 제어합니다.
- 모든 작업은 깃허브에서 제공하는 ubuntu runner 위에서 실행 됩니다.
- build 작업은 Hello와 Hello2 step을 실행해 정상적으로 작업이 실행되는지 확인합니다.
- deploy 작업은 appleboy/ssh-action을 이용해 원격서버에 ssh로 접근을 하고 해당 서버에서 아래의 스크립트를 실행함으로 git 소스를 받아옵니다.

작성된 워크플로에는 우리가 자세히 이야기하지 않은 몇가지의 내용이 있습니다.
- needs
- with
- secrets

needs 는 짧게 설명한 것처럼 작업(job)의 순서를 제어하는 속성입니다.
위에서 작업을 설명하며 워크플로 내에 있는 작업들이 병렬적으로 실행된다고 이야기했는데, needs 키워드를 사용하면 특정 작업이 완료된 이후에 실행되게 끔 설정해줄 수 있습니다.

with는 우리가 사용하는 액션에 필요한 매개변수값을 입력하는 속성입니다.
위에서 actions/checkout을 사용할 때는 매개변수 없이도 실행이 되기 때문에 with 속성을 작성하지 않고 바로 실행했지만, appleboy/ssh-action는 필수적으로 몇개의 매개변수를 요구하고 있고 제대로 사용하기 위해서 매개변수를 정의하고 값을 입력하기 위해 with 키워드를 사용했습니다.

secrets은 우리가 저장소에 직접 저장한 환경변수를 ${{ secrets.TEST_DEPLOY_REMOTE_HOST }}의 방식으로 Git에 업로드 된 소스나 Actions console에 노출되지 않게 사용할 수 있습니다.

마무리

기본적인 워크플로 작성 방법과 작업에서 SSH를 통해 원격 서버로 접근해 깃을 이용해 소스를 내려받는 방법을 알아보았습니다.
SSH연결을 위해 환경변수를 추가 등록한다거나, 원격 서버에서 깃을 사용하기 위해 기본 설정을 해주어야 하는 부분들에 대해서는 자세히 설명하기보다는 생략했지만,
그러한 기본적인 설정들을 모두 마친 서버에서는 마지막에 작성한 워크플로를 그대로 사용하면 개발한 소스의 변경점을 바로 반영할 수 있게 되었습니다.

워크플로에 대한 작성 방법을 알아보았기 때문에, 원한다면 빌드와 테스트에 대한 부분 또 빌드/테스트가 성공했을 때 배포가 되게 끔 설정하는 것도 충분히 할 수 있게 됐으리라 생각합니다.
SSH로 직접 연결하지 않고 다른 방법을 통해서도 CD(Continuous Deployment)를 구성할 수 있으니 더 다양한 방법을 통해 CI/CD를 구성해보는 경험을 해보시기 바랍니다.