일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- webp
- 성능 개선
- ec2
- nginx
- 로드 밸런싱
- TLS
- tcp
- 배포
- 인증서
- 렌더링 과정
- 이미지 압축
- CI
- SSH
- gitgub actions
- certbot
- aws
- https
- 3-Way HandShake
- SSL
- 검색엔진최적화
- nextJS
- 이미지 최적화
- DNS
- 브라우저
- pm2
- 무중단
- 이미지 포맷 변경
- workflow
- 자동화
- 리버스 프록시
- Today
- Total
개발일기
Github Actions로 CI/CD 구축하기 본문
📋 개요
현재 나의 시점으로 이야기를 하자면 AWS의 EC2를 사용해서 프로젝트를 배포까지 완료 했다면 한가지 불편한 점이 생길 것이다.
개발 서버에서의 변경점을 배포서버까지 옮길려면 얼마나 많은 단계와 귀찮음이 존재하는지.
우리는 귀찮음을 Github Actions를 사용하여 해결해 보려고 한다.
🏴 Github Actions
Github 공식문서를 보려면 여기를 눌러주세요.
Github 공식문서
GitHub Actions는 빌드, 테스트 및 배포 파이프라인을 자동화할 수 있는 CI/CD(연속 통합 및 지속적인 업데이트) 플랫폼입니다. 리포지토리에 대한 모든 끌어오기 요청을 빌드 및 테스트하거나 병합된 끌어오기 요청을 프로덕션에 배포하는 워크플로를 만들 수 있습니다.
프로젝트는 보통 여러명에서 개발을 한다.
각자 다양한 기능을 추가하고 수정하다 보면 코드 충돌이 발생할 수 있고,
이런 문제가 바로 서버에 배포된다면 서비스 장애가 생길 수도 있다.
Github Actions는 코드가 push되거나 PR(Pull Request) 될 때,
자동으로 해당 코드의 테스트를 수행 및 배포 해주는 역할들을 한다.
⚗️ CI/CD란?
1. CI (Continuous Integration) - 지속적 통합
CI는 여러 개발자들이 작업한 코드를 자주 통합(merge)하고,
매번 자동으로 빌드와 테스트를 수행하는 과정을 의미한다.
개발자들은 서로 다른 기능을 개발하다 보면 코드가 충돌할 수 있다.
이를 방지하기 위해, 코드를 자주 통합하고, 통합될 때마다 자동으로 문제를 확인한다.
테스트 실패나 빌드 오류를 빠르게 잡아서, 이후의 문제를 최소화할 수 있다.
쉽게 말해서 개발자들이 작성한 코드를 하나로 합치는 작업을 자동화 하는 것이다.
나는 이번 프로젝트를 혼자 진행했기 때문에 CI가 그렇게 와닿지는 않았다.
2. CD (Continuous Delivery / Continuous Deployment) - 지속적 제공/배포
CI를 통해 코드가 안정적으로 통합된 이후, CD는 그 코드를 실제 서버에 배포하는 과정을 자동화 한다.
즉, 개발자는 코드를 올리기만 하면, 자동으로 서버까지 반영이 되는 구조를 만드는 것이다.
⚙️ 워크플로우 생성하기
1️⃣ GitHub Actions 워크플로우 생성
먼저, GitHub 리포지토리에서 Actions 탭으로 이동해 새로운 워크플로우를 생성한다.
Actions 탭으로 들어간 후, "set up a workflow yourself"를 클릭하여 새로운 워크플로우 파일을 생성한다.
기본 제공되는 템플릿을 선택할수 있지만 해당되는것이 없으니 패스한다.
2️⃣ SSH 액션 설정
이 액션은 GitHub Actions 워크플로우에서 원격 서버에 SSH 명령을 안전하고 쉽게 실행할 수 있도록 도와주는 오픈소스이다.
appleboy/ssh-action을 사용하여 원격 서버에서 SSH 명령어를 실행하는 워크플로우를 작성한다.
이를 위해 다음과 같은 기본 YAML 파일을 사용한다.
name: Remote SSH Command
on:
push: # push 이벤트가 발생할 때 실행
jobs:
build:
name: Build
runs-on: ubuntu-latest
steps:
- name: Execute remote SSH commands using password
uses: appleboy/ssh-action@v1
with:
host: ${{ secrets.IP }} # 인스턴스 IP
username: ${{ secrets.USER }} # 우분투 아이디
password: ${{ secrets.KEY }} # ec2 instance pem key
port: ${{ secrets.PORT }} # 접속포트 22
script: whoami # 실행할 스크립트
여기서 우리가 설정할 것은 주석이 달려있는 부분이다.
name 부분은 알아서 설정하면 될 것 같다.
🧩 코드 설정하기
1️⃣ on 이벤트 설정하기
push 이벤트 설정하기
push 이벤트는 코드가 특정 브랜치에 푸시될 때 워크플로우 실행.
on:
push:
branches: [ main ] # 코드를 메인 브랜치에 push할 시 아래 job들이 실행
pull_request 이벤트 설정하기
pull_request 이벤트는 PR이 생성되거나 업데이트될 때 워크플로우 실행.
on:
pull_request:
branches:
- main # main 브랜치로 PR이 들어오면 아래 job들이 실행
2️⃣ secret 환경 변수 설정
1. EC2 인스턴스 정보
➀ 우분투 아이디 (${{ secrets.USER }})
whoami 명령어를 통해 EC2 서버의 사용자 아이디를 확인할 수 있다.
EC2에 접속하여 터미널에 whoami를 입력하면 해당 사용자를 확인할 수 있다.
➁ ec2 인스턴스 pem 키 (${{ secrets.KEY }})
pem 키는 현재 가지고 있는 pem 파일을 말하는 건데 파일의 이름만 넣으면 안되고 그 파일의 내용물(?)을 넣어야 한다.
넣는 방법은 해당 파일을 vscode나 메모장에 올려두면 암호화된 키가 나온다.
그러면 아래와 같이 암호화된 키가 나오는데 시작 부분부터 끝 부분 전부 복사해서 붙여넣는다.
-----BEGIN RSA PRIVATE KEY----- // 여기부터
암호화된 키
-----END RSA PRIVATE KEY----- // 여기까지 전부 복사
2. Secret 설정 방법
➀ 🛠 설정 하는 곳: settings > secrets and variables > Actions > Repository secrets
➁ New repository secret을 클릭하여 필요한 Secret을 추가
- USER: EC2의 사용자 아이디
- KEY: EC2 인스턴스의 PEM 키
- IP: 퍼블릭 IPv4 주소
- PORT: SSH 접속 포트 (기본 22)
3. script 실행
script 부분에 원격 서버에서 실행하고자 하는 명령어를 입력한다.
우리가 해야할 일은 간단하다.
script:
cd my-app # 내 프로젝트로 이동
git pull origin main # Git 리포지토리에서 최신 버전 pull
yarn install or npm install # 필요한 패키지 설치
yarn build or npm run build # 빌드 실행
pm2 restart my-app # 애플리케이션 재시작
⚠️ yarn, pm2를 글로벌로 설치해야 하는 이유
ec2에는 설치되어 있는데 워크플로우 실행시 yarn: command not found 에러가 나온다면 보통 이 상황이다.
nvm(Node Version Manager)을 사용하는 경우, 기본적으로 설치한 Node.js, npm, yarn 같은 패키지들은 사용자의 로컬(nvm 경로)에 설치된다.
그래서 그냥 script에 yarn 명령어로 실행하려고 하면 찾을 수 없다는 에러가 나온다.
nvm의 내부 경로를 직접 지정 해서 입력해야 한다.
하지만 글로벌 설치를 하면 nvm의 내부 경로를 직접 지정하지 않고 yarn 과 pm2 명령어를 사용 해도 에러가 나오지 않는다.
sudo npm install -g yarn
sudo npm install -g pm2
⚠️ excuting remote ssh commands 오류
인바운드 규칙에서 SSH 설정이 잘 되어 있다면 excuting remote ssh commands 오류가 뜨는 것은 당연하다.
아마도 SSH규칙을 설정할 때 보안을 위해 내IP로만으로 접근 가능하게 설정해두기 때문에 Github Actions에서 접근할 수 없다.
그러면 어떤 방법으로 접근해야 할까? 첫번째로는 SSH가 어디에서도 접근 가능하도록 설정(0.0.0.0/0)하는 것이다. 하지만 SSH를 어디에서도 접근 가능하게 설정한다면 보안에 문제가 생길 수 있다. 그렇기 때문에 이 방법은 지양하는 것이 좋다.
두번째로는 Github Actions IP의 접근을 허용하는 것이다. Github Actions의 IP는 자주 변경되기 때문에 workflow를 실행할 때 SSH 접근을 허용해 주고, 모든 실행이 끝난다면 허용해준 IP를 삭제한다면 가장 좋은 방법이 될 것 같다. 단계별로 확인해 보자.
➀ Github Actions IP 얻기
haythem/public-ip 문서 확인하기
Github Actions용 오픈소스 액션으로 해당 코드를 통해 IP를 얻어올 수 있다.
steps:
- name: Get Github Actions IP
id: ip
uses: haythem/public-ip@v1.2
② AWS에 접근할 수 있도록 IAM 자격 증명 설정
configure-aws-credentials 문서 확인하기
GitHub Actions가 AWS 리소스에 접근할 수 있도록 하기 위한 설정이다.
AWS 리소스에 접근하기 위해서는 IAM user를 생성해야 한다.
- name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v1
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} # IAM user access_key_id
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} # IAM user secret_access_key
aws-region: ap-northeast-2
📌 IAM 사용자 생성
IAM > 사용자(User) > 사용자 추가 > 권한 설정(AmazonEC2FullAccess 권한 정책에서 추가 해줘야함) > 액세스 키 확인 및 저장(파일 저장해서 키 확인)
저장한 파일에서 액세스 키 아이디와 시크릿 액세스 키를 확인 할 수 있다.
GitHub Repository > Settings > Secrets에서 추가해 주면 된다.
➂ Github Actions 퍼블릭 IP를 보안 그룹에 등록(SSH 허용)
우리는 아래 코드를 통해 보안 그룹 인바운드 규칙의 SSH에 github Actions의 IP를 추가할 수 있다.
${{ secrets.AWS_SECURITY_GROUP_ID }}는 EC2 인스턴스가 속한 보안 그룹 ID이다.
- name: Add Github Actions IP to Security group
run: |
aws ec2 authorize-security-group-ingress \
--group-id ${{ secrets.AWS_SECURITY_GROUP_ID }} \ # EC2 인스턴스가 속한 보안 그룹 ID
--protocol tcp --port 22 \
--cidr ${{ steps.ip.outputs.ipv4 }}/32 # Github Actions IP
여기까지가 excuting remote ssh commands 오류를 해결할 수 있는 방법이다.
하지만 코드를 확인해 보면 Github Actions의 IP를 보안 그룹에 추가하는 코드만 있을 뿐 삭제해주는 코드는 없다.
그렇다면 계속해서 IP가 추가되고, IP가 추가되면 해당 IP를 계속 허용 한다는 말이기 때문에 보안에도 좋지 않을 수 있다.
그렇기 때문에 IP를 허용하고 모든 작업을 끝내면 다시 해당 IP를 삭제해 주면 좋을 것 같다.
➃ 배포 완료 후 Github Actions 퍼블릭 IP 삭제하기
- name: Remove Github Actions IP from Security group
run: |
aws ec2 revoke-security-group-ingress \
--group-id ${{ secrets.AWS_SECURITY_GROUP_ID }} \ # EC2 인스턴스가 속한 보안 그룹 ID
--protocol tcp \
--port 22 \
--cidr ${{ steps.ip.outputs.ipv4 }}/32 # Github Actions IP
➄ 전체 코드 확인하기
# main.yml
name: main branch auto ci process script
on: # 아래 job을 실행시킬 상황
push:
branches: [ main ]
jobs:
deploy:
name: deploy
runs-on: ubuntu-latest # 실행될 인스턴스 OS와 버전
steps:
- name: Get Github Actions IP
id: ip
uses: haythem/public-ip@v1.2
- name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v1
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} # IAM user access_key_id
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} # IAM user secret_access_key
aws-region: ap-northeast-2
- name: Add Github Actions IP to Security group
run: |
aws ec2 authorize-security-group-ingress \
--group-id ${{ secrets.AWS_SECURITY_GROUP_ID }} \ # EC2 인스턴스가 속한 보안 그룹 ID
--protocol tcp --port 22 \
--cidr ${{ steps.ip.outputs.ipv4 }}/32 # Github Actions IP
- name: excuting remote ssh commands
uses: appleboy/ssh-action@v0.1.6 # ssh 접속하는 오픈소스
with:
host: ${{ secrets.REMOTE_IP }} # 인스턴스 IP
username: ${{ secrets.REMOTE_USER }} # 우분투 아이디
key: ${{ secrets.REMOTE_PRIVATE_KEY }} # ec2 instance pem key
port: ${{ secrets.REMOTE_SSH_PORT }} # 접속포트
script: | # 실행할 스크립트
cd mySelectshop
git pull origin main
yarn install
npx prisma generate
yarn build
pm2 start npm --name mySelectshop -- start
- name: Remove Github Actions IP from Security group
run: |
aws ec2 revoke-security-group-ingress \
--group-id ${{ secrets.AWS_SECURITY_GROUP_ID }} \ # EC2 인스턴스가 속한 보안 그룹 ID
--protocol tcp \
--port 22 \
--cidr ${{ steps.ip.outputs.ipv4 }}/32 # Github Actions IP
마무리
이렇게 해서 모든 배포 과정을 마무리 했다.
이전 프로젝트에서는 Vercel을 통해 간편하게 배포를 진행했기 때문에, 이번에도 쉽게 끝날 것이라 생각했다.
하지만 그것은 어디까지나 Vercel이었기에 가능했다.
AWS를 사용한 배포는 더 많은 것을 알아야 했고, 많은 공부를 필요로 했다.
모든 것을 완벽히 이해했다고 말하긴 어렵지만, 오히려 그렇기 때문에 더 많은 것을 배울 수 있었고, 컴퓨터 지식을 쌓을 수 있는 좋은 경험 이었다.
이번 경험을 통해 AWS 배포에 대한 이해도가 높아졌고, 다음에 다시 배포를 하게 된다면 보다 능숙하게 진행할 수 있을 것이라 확신한다.
'배포 > aws' 카테고리의 다른 글
pm2로 무중단 배포하기(AWS, NextJs) (0) | 2025.04.24 |
---|---|
NginX, Certbot으로 HTTPS 인증하기 (0) | 2025.04.23 |
가비아 도메인과 EC2 연결하기 (Route53 사용 안함) (0) | 2025.04.22 |
AWS EC2 배포 환경 만들기 (준비하기) (0) | 2025.04.19 |
EC2에 내 프로젝트 클론하기, 리눅스 명령어 파악하기, env파일 생성하기 (0) | 2025.04.18 |