Github Action 워크플로우에서 SSH 접속하여 배포 자동화하기

usealarm.com 서비스는 프론트엔드와 포켓베이스(Pocketbase) 백엔드로 구성되어있다. 프론트엔드는 Cloudflare Pages로 배포하도록 세팅했고, 백엔드는 변경사항이 발생할 때마다 SSH로 클라우드 가상 머신에 접속하여 서버를 수동으로 업데이트하고 있었다.
레포지터리를 업데이트해도 서버를 배포하는 걸 잊어버릴 때도 종종 있어서 백엔드 업데이트를 자동화할 수 있지 않을까 싶어서 방법을 찾아봤다.
가상 머신 상태
현재 가상 머신에는 깃허브 레포지터리에 접근할 수 있는 SSH 키가 이미 세팅되어있다.
추가적인 보안을 위해 SSH 키에 비밀번호까지 설정했다.
깃허브 설정에 공개 키를 등록하고 git clone 명령어로 프로젝트를 클론했다. 공개 키가 known_host 파일에 등록되어 있어 연결하려는 호스트에 대한 추가적인 검증이 필요하지 않았다.
깃허브 액션을 도입해서 레포지터리의 특정 브랜치가 업데이트되었을 때 워크플로우가 실행되도록 했다. .github/workflows 폴더 내 yaml 파일을 생성하고 워크플로우를 작성한다.
name: Backend Deploy
on:
push:
branches: [main]
paths:
- "!web/**"
main 브랜치가 업데이트(push)되면 액션이 실행되도록 한다. paths에 값을 지정함으로써 어떤 파일이 업데이트되었을 때 액션 실행의 여부를 결정할 수 있다. 파일명 앞에 느낌표(!)가 있으면 이 파일이 업데이트되었을 때는 액션이 실행되지 않는다.
여러 프로젝트 내 의존성 관리를 용이하게 하기 위해 모노레포로 구성되었고 web 폴더에는 프론트엔드 프로젝트가 세팅되어 있기 때문에 web 폴더가 업데이트될 때는 백엔드를 업데이트할 필요가 없었다.
수동으로 배포할 땐 터미널에서 ssh 명령어로 가상 머신에 접속할 수 있었는데 워크플로우에서는 가상 머신에 접속하기 위해 appleboy/ssh-action
액션을 도입할 수 있다. 액션에서 SSH를 통해 가상 머신에 접속할 수 있고 원하는 스크립트를 실행시킬 수 있다.
jobs:
deploy:
runs-on: ubuntu-latest
steps:
# Previous Steps
- name: SSH connection
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.REMOTE_SSH_HOST }}
username: ${{ secrets.REMOTE_SSH_USERNAME }}
key: ${{ secrets.REMOTE_SSH_KEY }}
port: ${{ secrets.REMOTE_SSH_PORT }}
script: |
cd ${{ secrets.REMOTE_HOME }}
echo 'echo ${{ secrets.REMOTE_GIT_PASSWORD }}' > ~/.ssh/passphrase.sh && chmod a+x ~/.ssh/passphrase.sh
eval `ssh-agent -s`
DISPLAY=1 SSH_ASKPASS=~/.ssh/passphrase.sh SSH_ASKPASS_REQUIRE=force ssh-add ${{ secrets.REMOTE_GIT_KEY }}
cd ${{ secrets.PROJECT }}
export NVM_DIR=~/.nvm
source ~/.nvm/nvm.sh
git pull
nvm use 22
pnpm install
sudo systemctl restart SERVICE_NAME
rm ~/.ssh/passphrase.sh
SSH 접속을 하기 위해서는 접속하려는 가상 머신의 주소, 계정, 개인 키, 포트 등이 필요하다. YAML 파일에 값을 그대로 적으면 제 3자가 탈취하여 악용할 수 있다. 깃허브 레포지터리 설정에서 액션에 필요한 암호(Action secrets)를 작성할 수 있다.
REMOTE_SSH_HOST: SSH로 접속하려는 주소
REMOTE_SSH_USERNAME: 계정 이름
REMOTE_SSH_KEY: SSH로 접속하기 위한 개인 키
REMOTE_SSH_PORT: 접속 포트
REMOTE_HOME: 홈 디렉토리 경로
REMOTE_GIT_KEY: 가상 머신에서 깃허브 계정에 접근할 수 있는 개인 키 경로. 액션에서 가상 머신에 접속하기 위한 SSH 키와는 다른 키이다.
REMOTE_GIT_PASSWORD: REMOTE_GIT_KEY의 비밀번호(Passphrase)
PROJECT: 프로젝트 경로
가상 머신에 직접 접속했을 때는 프로젝트를 git pull
명령어로 업데이트할 때 비밀번호를 직접 입력할 수 있었다. 액션에서 SSH 접속을 한 상태에서는 깃허브 SSH 키에 대해 비밀번호를 입력하기 위해 다음과 같은 방법을 쓸 수 있었다.
echo 'echo ${{ secrets.REMOTE_GIT_PASSWORD }}' > ~/.ssh/passphrase.sh && chmod a+x ~/.ssh/passphrase.sh
eval `ssh-agent -s`
DISPLAY=1 SSH_ASKPASS=~/.ssh/passphrase.sh SSH_ASKPASS_REQUIRE=force ssh-add ${{ secrets.REMOTE_GIT_KEY }}
passphrase.sh
파일을 생성하여 파일을 실행시키면 SSH 키 암호를 입력하도록 할 수 있다.
SSH Agent를 세팅하면 사용자가 한 번 입력한 비밀번호를 암호화 및 기억하여 다음 SSH 접속에 이용할 수 있다. SSH 접속을 사용하는 클라이언트는 에이전트와 통신하여 비밀번호를 입력하지 않고 안전하게 작업을 수행할 수 있다.
ssh-agent -s
명령어를 실행시키면 SSH 명령어가 에이전트와 통신하는데 필요한 환경 변수를 반환한다. eval
명령어를 통해 환경 변수를 등록할 수 있다. SSH 에이전트에 키를 등록하기 위해 ssh-add
명령어를 실행시킨다.
DISPLAY: 이 환경변수가 지정되어 있어야 SSH_ASKPASS에 지정된 프로그램을 실행시킨다.
SSH_ASKPASS: ssh-add 명령어를 실행시킬 때 SSH 키에 대해 비밀번호를 어디서 입력받을지 명시할 수 있다.
SSH_ASKPASS_REQUIRE: SSH_ASKPASS에 지정된 프로그램을 반드시 실행시키도록 한다.
프로젝트 업데이트가 끝나면 깃허브 SSH 키에 대한 비밀번호가 임시적으로 적혀있던 파일을 삭제해준다.
Subscribe to my newsletter
Read articles from Nowon Lee directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
