개요
GiHub Actions에 대해 학습하고, GitHub Actions를 사용한 CI/CD 과정과 프로젝트에서 사용한 Docker 설정 파일에 대해 분석을 해 볼 것이다.
GitHub Actions
깃허브 액션은 깃허브에서 제공하는 CI/CD 플랫폼으로 빌드, 테스트, 배포를 자동화 시키는 파이프라인을 만들 수 있다.
GitHub Action 구성 요소
Workflow
- 한 개 이상의 job을 실행할 수 잇는 자동화된 작업
- YAML 파일로 저장되며 event에 의해 실행된다.
Event
- workflow 실행을 발동시키는 특정한 활동
- 깃허브에 소스코드를 푸시하면 발생하는 push event, pull request event, issue event 등 깃허브에서 발생하는 대부분의 작업을 event로 정의할 수 있다.
Jobs
- 한 가지 러너 안에서 실행되는 여러 가지 step들의 모음
- 각각의 step들은 일종의 shell script처럼 실행이 된다.
- Step들은 순서에 따라 실행되며 Step끼리 데이터들을 공유할 수 있다.
- Job은 다른 Job에 의존관계를 가질 수 있으며, 병렬 실행도 가능하다.
Actions
- 복잡하고 자주 반복되는 작업을 정의한 커스텀 어플리케이션
- workflow 파일 안에서 자주 반복되는 코드를 미리 정의해 코드의 양을 줄일 수 있다.
- 깃허브 마켓플레이스를 통해 공용 Action 또는 다른 사람들이 만든 Action을 사용할 수 있다.
예시
name: learn-github-actions
on: [push]
jobs:
check-bats-version:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
with:
node-version: '14'
- run: npm install -g bats
- run: bats -v
name
- workflow의 name을 정의
- 선택사항이며 깃허브 저장소의 깃허브 액션 탭에서 workflow의 이름을 보여준다.
on
- 해당 workflow를 실행시키는 이벤트를 정의
- push 이벤트가 발생했을 때 workflow가 실행되도록 정의
jobs
- check-bats-version-job의 이름을 정의
- runs-on : 어떤 호스트에서 실행될지 정의 - ubuntu 가상 머신에서 실행되도록 정의
step
- uses: actions/checkout@v2 - 해당 레포지토리를 pull 받고 이동하는 action 대부분의 workflow에 사용
- uses: actions/setup-node@v2 - 노드를 설치하는 action으로 가상 머신 안에는 대부분의 프로그래밍 언어가 설치되어 있지 않기 대문에 프로젝트 실행에 필요한 언어들을 action을 통해 설치
- run: npm install -g bats - run 키워드를 통해 러너가 실행되는 서버에서 명령어를 실행
GitHub Action으로 CI/CD 구축
GitHub Action 시작
- 깃허브 레포지토리의 Actions 탭으로 가면 GitHub Actions Workflow 파일을 작성할 수 있다.
- 처음 workflow 생성 시 깃허브에서 적절한 Template을 제공한다.
- 원하는 템플릿을 선택하면 해당 템플릿을 바탕으로 workflow를 자유롭게 만들 수 있으며 저장소의 .github/workflows에 yaml 파일이 생성된다.
Secret 환경 변수 등록하기
- 깃허브에서는 organization, Repository에 Secret 변수를 등록
- 해당 변수를 workflow에서 사용하면 workflow의 로그에서는 환경 변수로 나오며 해당 값을 노출시키지 않는다.
- Repository Setting에서 Secret 탭으로 들어가면 환경변수 설정 가능
- username, password 등 보안이 필요한 부분을 환경 변수로 저장
GitHub Action Workflow
프로젝트에서 사용한 workflow을 분석한다.
name: Deploy to AWS EC2
on:
push:
branches:
- develop
pull_request:
branches:
- develop
# 사용할 인프라의 이름을 변수 형태로 저장
jobs:
build-and-deploy:
# 실행 환경 지정
runs-on: ubuntu-latest
# Task sequence 명시
steps:
- uses: actions/checkout@v2
- name: Set up JDK 17
uses: actions/setup-java@v1
with:
java-version: 17
# Github Actions 워크플로우가 실행되는 가상 환경내에 application-dev 설정
- name: Generate application-secret.yml
run: |
echo "${{ secrets.APPLICATION_SECRET_CONTENT }}" > ./src/main/resources/yml/application-secret.yml
# Github Actions 워크플로우가 실행되는 가상 환경내에 application-dev 설정
- name: Generate application-oauth.yml
run: |
echo "${{ secrets.APPLICATION_OAUTH }}" > ./src/main/resources/yml/application-oauth.yml
# Gradle 빌드 할 때, 이미 저장한 데이터를 캐싱하여 빌드시 이를 사용하도록함.
- name: Gradle Caching
uses: actions/cache@v3
with:
path: |
~/.gradle/caches
~/.gradle/wrapper
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
restore-keys: |
${{ runner.os }}-gradle-
# Github Actions 워크플로우 가상환경이 grdlew 실행할 수 있도록 ./gradlew 파일에 실행 권한을 부여
- name: Grant execute permission for gradlew
run: chmod +x ./gradlew
shell: bash
# Gradle build (Test 제외)
- name: Build with Gradle
run: ./gradlew clean build -x test
# Docker 이미지 빌드
- name: Build Docker image
run: docker build -f Dockerfile -t myapp:${{ github.sha }} .
# ECR에 docker image push
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v1
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ap-northeast-2
# ECR에 Login
- name: Log in to Amazon ECR
run: |
aws ecr get-login-password --region ap-northeast-2 | docker login --username AWS --password-stdin ${{ secrets.AWS_ECR_REPOSITORY_URL }}
# ECR에 이미지 push
- name: Push image to Amazon ECR
run: |
docker tag myapp:${{ github.sha }} ${{ secrets.AWS_ECR_REPOSITORY_URL }}:latest
docker push ${{ secrets.AWS_ECR_REPOSITORY_URL }}:latest
# EC2에 ssh로 접속 후 ECR에서 docker로 이미지 pull & docker container
- name: Deploy to EC2
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.HOST }}
username: ${{ secrets.USERNAME }}
key: ${{ secrets.SSH_KEY }}
port: 22
script: |
sudo docker login -u AWS -p $(aws ecr get-login-password --region ap-northeast-2) ${{ secrets.AWS_ECR_REPOSITORY_URL }}
sudo docker pull ${{ secrets.AWS_ECR_REPOSITORY_URL }}:latest
sudo docker-compose down
sudo docker-compose up -d
sudo docker image prune -f
Job and Steps
1. 환경 설정
- 환경: ubuntu-latest를 사용하여 작업을 수행한다.
- 작업: build-and-deploy 작업을 정의한다.
2. 작업 순서(Steps)
- 코드 체크아웃
- GitHub 리포지토리의 코드를 체크아웃 한다.
- uses: actions/checkout@v2
- JDK 17 설정
- name: Set up JDK 17
uses: actions/setup-java@v1
with:
java-version: 17
- 환경 파일 생성
- application-secret.yml, application-monitoring.yml, application-oauth.yml 생성
- name: Generate application-secret.yml
run: |
echo "${{ secrets.APPLICATION_SECRET_CONTENT }}" > ./src/main/resources/yml/application-secret.yml
- name: Generate application-monitoring.yml
run: |
echo "${{ secrets.APPLICATION_MONITORING }}" > ./src/main/resources/yml/application-monitoring.yml
- name: Generate application-oauth.yml
run: |
echo "${{ secrets.APPLICATION_OAUTH }}" > ./src/main/resources/yml/application-oauth.yml
- Gradle 캐싱
- Gradle 빌드 시 캐시를 사용해 빌드 속도를 향상시킨다.
- name: Gradle Caching
uses: actions/cache@v3
with:
path: |
~/.gradle/caches
~/.gradle/wrapper
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
restore-keys: |
${{ runner.os }}-gradle-
- gradlew 실행 권한 부여
- gradlew 파일에 실행 권한을 부여한다.
- name: Grant execute permission for gradlew
run: chmod +x ./gradlew
shell: bash
- Gradle 빌드 (테스트 제외)
- 테스트를 제외하고 Gradle 빌드를 수행한다.
- name: Build with Gradle
run: ./gradlew clean build -x test
- Docker 이미지 빌드
- Docker 이미지를 빌드한다. 'myapp:${{ github.sha }}' 형식으로 태그를 지정한다.
- name: Build Docker image
run: docker build -f Dockerfile -t myapp:${{ github.sha }} .
- AWS 자격 증명 구성
- AWS 자격 증명을 설정한다.
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v1
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ap-northeast-2
- Amazon ECR 로그인
- Amazon ECR에 로그인한다.
- name: Log in to Amazon ECR
run: |
aws ecr get-login-password --region ap-northeast-2 | docker login --username AWS --password-stdin ${{ secrets.AWS_ECR_REPOSITORY_URL }}
- 이미지 ECR에 푸시
- Docker 이미지를 ECR에 푸시한다.
- name: Push image to Amazon ECR
run: |
docker tag myapp:${{ github.sha }} ${{ secrets.AWS_ECR_REPOSITORY_URL }}:latest
docker push ${{ secrets.AWS_ECR_REPOSITORY_URL }}:latest
- EC2에 배포
- SSH를 통해 EC2 인스턴스에 접속하여, 최신 이미지를 풀(Pull)하고, docker-compose를 사용해 컨테이너를 재시작하며, 사용하지 않는 이미지를 삭제한다.
- name: Deploy to EC2
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.HOST }}
username: ${{ secrets.USERNAME }}
key: ${{ secrets.SSH_KEY }}
port: 22
script: |
sudo docker login -u AWS -p $(aws ecr get-login-password --region ap-northeast-2) ${{ secrets.AWS_ECR_REPOSITORY_URL }}
sudo docker pull ${{ secrets.AWS_ECR_REPOSITORY_URL }}:latest
sudo docker-compose down
sudo docker-compose up -d
sudo docker image prune -f
Secret 사용
- APPLICATION_SECRET_CONTENT, APPLICATION_MONITORING, APPLICATION_OAUTH 등은 GitHub Secrets로부터 가져온다.
- AWS 자격 증명 및 ECR URL, EC2 접속 정보 등도 Secrets에 저장된 값을 사용한다.
GitHub Action 실행 및 결과 확인
- GitHub develop 레포지토리로 push하면 workflow가 실행
- 깃허브 저장소의 Actions 탭에서 workflow 실행 결과 확인 가능
- 각 Step들의 로그 확인 가능
주의 사항
- EC2 인스턴스 생성 후 보안 인바운드 규칙 설정 시 Spring은 t2.small로 할 것(CI/CD를 담당한 팀원이 이 문제를 해결하기 위해 고생을 했다)
- Elastic Container Registry에 리포지토리 생성
- Nginx 설치 후 Cerbot으로 Let's Encrypt SSL 인증서 발급, 적용
- Proxy 설정
정리
GitHub Actions와 Docker를 통해 CI/CD를 간편하게 설정할 수 있지만 설정 시 고려해야할 사항이나 주의점을 잘 파악하고 애플리케이션 환경에 맞는 설정을 하는 것이 필요하다는 것을 느꼈다.
'항해 99 > Spring' 카테고리의 다른 글
Spring - Image Resize (5) | 2024.09.03 |
---|---|
프로젝트 코드 리팩토링 (0) | 2024.06.04 |
CI / CD (0) | 2024.05.11 |
ORM (0) | 2024.05.03 |
Web Game 코드 설계 정리 (0) | 2024.04.23 |