์ํํธ์จ์ด ๊ฐ๋ฐ lifecycle ๋ด์์ Pull Request, Push ๋ฑ์ ์ด๋ฒคํธ ๋ฐ์์ ๋ฐ๋ผ ์๋ํ๋ ์์ ์ ์งํํ ์ ์๋๋ก ํ๋ ๊ธฐ๋ฅ
์๋ํ๋ ์์ ์ด ํ์ํ ๊ฒฝ์ฐ๋ ์๋์ ๊ฐ๋ค.
.github/workflows directory์ .yaml ํํ๋ก ์ ์ฅEC2 instance ์์ฑ, docker ์ค์น ๋ฐ ํ์ ๊ฐ์ ์ด ์ด๋ฏธ ๋์ด์๋ค๊ณ ๊ฐ์
Docker๋ฅผ ํ์ฉํด ๋ฐฐํฌํ๊ธฐ ์ํด์๋ DockerFile์ ์์ฑํด์ผ ํ๋ค. ํด๋น ํ์ผ์ ํ๋ก์ ํธ ๋ฃจํธ ๋๋ ํ ๋ฆฌ ๋ด์ ๋ง๋ค๋ฉด ๋๋ค.(README.md, gradlew ๋ฑ๊ณผ ๊ฐ์ path)
๋๋ DockerFile์ ์ด์ฉํ ๋ฐฐํฌ ์ deploy profile์ active๋ก ์ค์ ํ๊ธฐ ์ํด ์๋์ ๊ฐ์ด ์์ฑํด์ฃผ์๋ค.
FROM openjdk:17
LABEL authors="zero-zero" # ๊ฐ๋ฐ์ ์ด๋ฆ์ผ๋ก ์ค์
ARG JAR_FILE=build/libs/*.jar
COPY ${JAR_FILE} app.jar
ENTRYPOINT ["java", "-jar", "-Dspring.profiles.active=deploy", "app.jar"]
.github/workflows ๋๋ ํ ๋ฆฌ ๋ด์ .ymlํ์ผ์ ์์ฑํด๋ ๋์ง๋ง, Repository > Actions ํญ์์ ์๋์ผ๋ก template์ ๋ง๋ค์ด์ฃผ๋ ๊ธฐ๋ฅ์ ์ด์ฉํ๋ ๊ฒ์ด ํธ๋ฆฌํ๋ค.

set up a workflow yourself ๋ฅผ ์ ํํ๋ค.

Repository > Settings > Secrets and variables ๋ฉ๋ด์์ ๋ณ์๋ฅผ ๋ฑ๋กํ๋ค. ํด๋น ๋ณ์๋ฅผ workflow์ ์ฌ์ฉํ๋ฉด workflow log์์๋ ํ๊ฒฝ ๋ณ์๋ก ๋์ค๋ฉฐ ํด๋น ๊ฐ์ด ๋
ธ์ถ๋์ง ์๋๋ค. ์๋ฅผ ๋ค์ด docker image name์ ํ๊ฒฝ ๋ณ์๋ก ๋ฑ๋กํ๋ฉด ๋ก๊ทธ ์์๋ ***๋ก ์ฒ๋ฆฌ๋์ด ๋์จ๋ค.

DOCKER_USERNAME : ์ฌ์ฉํ docker hub user nameDOCKER_PASSWORD : ์ฌ์ฉํ docker hub passwordDOCKER_IMAGE_NAME : docker image ์ด๋ฆ(์ฌ๊ธฐ์๋ project name์ ์ฌ์ฉํจ)PORT : Docker๋ฅผ ์คํ์ํฌ ํฌํธ ๋ฒํธ(์ฌ๊ธฐ์๋ 8080)EC2_HOST : AWS EC2 instance์ public IPv4 DNS โ IP ์ฃผ์๊ฐ ์๋๋คEC2_USERNAME : AWS EC2 instance์ username(์ฌ๊ธฐ์๋ ubuntu)EC2_KEY : AWS EC2 instance๋ฅผ ์์ฑํ ๋ ์ ์ฅ๋ pem keycat <pem key path> > copy and paste-----BEGIN RSA PRIVATE KEY----- ๋ถํฐ -----END RSA PRIVATE KEY-----๊น์งmain.yml ์์ฑ์ด ๊ธ์์๋ CI/CD pipeline ๊ตฌ์ถ์ ๋ชฉ์ ์ผ๋ก ํ๊ณ ์๊ธฐ ๋๋ฌธ์ Docker image build โ push โ EC2 deploy ๊ณผ์ ์ workflow๋ก ์์ฑํ๋ค. ์์ฑํ workflow๋ ๋ค์ ์ฝ๋์ ๊ฐ๋ค.
์๋ ์ฝ๋์์๋ dev branch์ push or PR ๋ฐ์ ์ ์คํ๋๋๋ก ์ค์ ํด๋์๋ค.
# Workflow name
name: Gradle Build and EC2 Deploy - dev server
# ์ด๋ค event๊ฐ ๋ฐ์ํ๋ฉด workflow๋ฅผ ์คํํ ์ ๋ช
์
on:
# dev branch์ push or pull request ๋ฐ์ ์
push:
branches: ["dev"]
pull_request:
branches: ["dev"]
# ์ ์ด๋ฒคํธ ๋ฐ์ ์ ์คํ๋ ์์
๋ค
jobs:
build:
# VM์ ์คํ ํ๊ฒฝ ์ง์ -> ubuntu์ ์ต์ ๋ฒ์
runs-on: ubuntu-latest
# ์คํ๋ jobs ์์๋๋ก ๋ช
์
steps:
- name: Checkout
# uses keyword๋ฅผ ํตํด action ๋ถ๋ฌ์ค๊ธฐ
# ์ฌ๊ธฐ์๋ ํด๋น repository๋ก checkoutํด ์ ๊ทผํ ์ ์๋ action์ ๋ถ๋ฌ์จ๋ค. v3๋ ์์ผ๋ ๊ฒฝ์ฐ์ ๋ฐ๋ผ ์ ์ฉํ ๊ฒ.
uses: actions/checkout@v2
- name: Set up JDK 17
uses: actions/setup-java@v3
with:
java-version: '17'
distribution: 'temurin'
# yml ํ์ผ์ ์๋ ๋ณ์๋ค์ secrets๋ก๋ถํฐ ๊ฐ์ ธ์์ yml ํ์ผ์ ์ ์ฉ
- name: Set yml file
uses: microsoft/variable-substitution@v1
with:
files: 'src/main/resources/application.yml'
env:
cloud.aws.credentials.access-key: ${{ secrets.AWS_ACCESS_KEY }}
cloud.aws.credentials.secret-key: ${{ secrets.AWS_SECRET_KEY }}
# Gradle Build๋ฅผ ์ํ ๊ถํ ๋ถ์ฌ
- name: Grant execute permission for gradlew
run: chmod +x gradlew
# Gradle Build (test ์ ์ธ)
- name: Build with Gradle
run: ./gradlew clean build --exclude-task test
- name: DockerHub Login
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Docker Image Build
run: docker build -t ${{ secrets.DOCKER_USERNAME }}/${{ secrets.DOCKER_IMAGE_NAME }}:latest .
- name: Docker Push
run: docker push ${{ secrets.DOCKER_USERNAME }}/${{ secrets.DOCKER_IMAGE_NAME }}:latest
- name: EC2 instance ์ ์ ๋ฐ app ์คํ
uses: appleboy/ssh-action@v0.1.6
with:
host: ${{ secrets.EC2_HOST }}
username: ${{ secrets.EC2_USERNAME }}
key: ${{ secrets.EC2_KEY }}
script: |
sudo docker kill ${{ secrets.DOCKER_IMAGE_NAME }}
sudo docker rm -f ${{ secrets.DOCKER_IMAGE_NAME }}
sudo docker rmi ${{ secrets.DOCKER_USERNAME }}/${{ secrets.DOCKER_IMAGE_NAME }}
sudo docker pull ${{ secrets.DOCKER_USERNAME }}/${{ secrets.DOCKER_IMAGE_NAME }}
sudo docker run -p ${{ secrets.PORT }}:${{ secrets.PORT }} \
--name ${{ secrets.DOCKER_IMAGE_NAME }} \
-d ${{ secrets.DOCKER_USERNAME }}/${{ secrets.DOCKER_IMAGE_NAME }}
์์ฑ ์๋ฃ ํ ์ปค๋ฐํด์ฃผ๋ฉด ์๋์ ๊ฐ์ด ์ฒดํฌ ํ์๊ฐ ๋จ๋ฉฐ ์ ์์ ์ผ๋ก ์ ์ฉ๋ ๊ฒ์ ํ์ธํ ์ ์๋ค.

Reference : Github actions๋ฅผ ํ์ฉํ CI/CD ํ์ดํ๋ผ์ธ ๊ตฌ์ถ