Git Actions์ Docker๋ฅผ ์ด์ฉํ CI/CD pipeline ๊ตฌ์ถ
by rlaehddnd0422์ด ํฌ์คํ ์์๋ Docker์ Git Action์ ์ฌ์ฉํ์ฌ CI/CD๋ฅผ ๊ตฌ์ถํฉ๋๋ค.
CI/CD๋ ์ง์์ ํตํฉ(Continuous Integration) ๋ฐ ์ง์์ ์ ๊ณต/๋ฐฐํฌ(Continuous Delivery/Deployment)๋ฅผ ์๋ฏธํ๋ฉฐ, ์ํํธ์จ์ด ๊ฐ๋ฐ ๋ผ์ดํ์ฌ์ดํด์ ๊ฐ์ํํ๊ณ ๊ฐ์ํํ๋ ๊ฒ์ ๋ชฉํ๋ก ํฉ๋๋ค.
- ์์ฑํ ์ฝ๋๋ฅผ pushํ๊ณ , ๋ฆฌ๋ชจํธ ์๋ฒ์์ pullํ๊ณ buildํ๊ณ runํ๋ ์ผ๋ จ์ ๊ณผ์ ๋ค์ ์๋ํํ๋ค๋ฉด, ๊ฐ๋ฐ์๋ ๊ฐ๋ฐ์๋ง ์ง์คํ ์ ์๊ฒ ์ฃ ??
- ์ด๋ ๊ฒ push -> pull -> build -> run ํ๋ ๊ณผ์ ๋ค์ ํ๋์ ํ์ดํ๋ผ์ธ์ผ๋ก ๊ตฌ์ถํ์ฌ ์๋ํํ๋ ๊ฒ์ CI/CD๋ผ๊ณ ์๊ฐํ์๋ฉด ๋๊ฒ ์ต๋๋ค!
CI/CD ์ค ์ง์์ ํตํฉ(CI)์ ์ฝ๋ ๋ณ๊ฒฝ ์ฌํญ์ ๊ณต์ ์์ค ์ฝ๋ ๋ฆฌํฌ์งํ ๋ฆฌ์ ํตํฉํ๋ ๊ฒ์, ์ง์์ ์ ๊ณต(CD)๋ ์ฝ๋ ๋ณ๊ฒฝ์ฌํญ์ ํตํฉ๋ฏผ ์ ๊ณต, ๋ฐฐํฌ๋ฅผ ๋ํ๋ด๋ ํ๋ก์ธ์ค๋ก CI์ CD ๋ ๊ฐ์ง ๋ถ๋ถ์ผ๋ก ๊ตฌ์ฑ๋ฉ๋๋ค.
์กฐ๊ธ ๋ ๊ฐ๋จํ ๋งํ์๋ฉด ์ ๋ฐ์ดํธ ๋ ์ฝ๋๋ฅผ ์๋ฒ์ ํตํฉ ํ๋ ๊ณผ์ ์ CI, ํตํฉ๋ ์ฝ๋๋ฅผ ๋ฐฐํฌํ๋ ๊ณผ์ ์ CD๋ผ๊ณ ๋ณด์๋ฉด ๋๊ฒ ์ต๋๋ค.
CI/CD๋ฅผ ๊ตฌ์ถํ๋ ๋ฐฉ๋ฒ์ Jenkins, Travis CI ๋ฑ ๋ง์ ๋๊ตฌ๋ค์ด ์์ง๋ง, ์ด ํฌ์คํ ์์๋ Git Action์ ์ฌ์ฉํ์ฌ CI/CD๋ฅผ ๊ตฌ์ถํด๋ณด๋ คํฉ๋๋ค.
+ ์ถ๊ฐ์ ์ผ๋ก ํ์๋ Docker๋ฅผ ์ฌ์ฉํ์ฌ ํ๋ก์ ํธ์ ์ด๋ฏธ์ง๋ฅผ ๋น๋ํ๊ณ , ์ปจํ ์ด๋๋ฅผ ๋์ฐ๋ ๋ฐฉ์์ผ๋ก ํ๋ก์ ํธ๋ฅผ ๋ฐฐํฌํ์๋๋ฐ์. Docker๋ฅผ ์ฌ์ฉํ์ฌ ํ๋ก์ ํธ๋ฅผ ๋น๋ํ๊ณ ๋ฐฐํฌ๋ ์ด๋ป๊ฒ ํ๋์ง๋ ์ถํ์ ์์ฑํ๋๋ก ํ๊ฒ ์ต๋๋ค.
์ํคํ ์ฒ ๊ตฌ์กฐ
๋ก์ปฌ ์ฝ๋ ๋ณ๊ฒฝ ๋ฐ Git Commit & Push
โถ๏ธ Repository์์ Push ๊ฐ์ง
โถ๏ธ Docker-Compose๋ก ํ๋ก์ ํธ ๋น๋ (CI) ๋ฐ Docker hub์ ๋น๋ํ ์ด๋ฏธ์ง PUSH
โถ๏ธ Git Action์์ EC2 ์๋ฒ ์ ๊ทผ
โถ๏ธ Docker hub๋ก๋ถํฐ ์ด๋ฏธ์ง PULL
โถ๏ธ ๋น๋ํ ์ด๋ฏธ์ง๋ก ์ปจํ ์ด๋ ๊ตฌ์ถ ๋ฐ ์ปจํ ์ด๋ run (CD)
๊ทธ๋ ๊ฒ ๋ณต์กํ์ง ์์ต๋๋ค. ์ด ๊ณผ์ ๋ค์ ์ง๊ธ๋ถํฐ ๊ตฌ์ถํด๋ณด๊ฒ ์ต๋๋ค.
Workflow ๊ตฌ์ฑ์์
ํ๋ก์ ํธ์ .github/workflows ๋๋ ํ ๋ฆฌ์์ ์ง์ ์ ์ผ๋ก .yml ํ์ผ์ ์์ฑํ๋ ๋ฐฉ๋ฒ๋ ์์ง๋ง, ์๋์ ๊ฐ์ด Github์์ Actionsํญ์ ๋ค์ด๊ฐ์ ์๋์ผ๋ก ํ ํ๋ฆฟ์ ๋ง๋ค์ด ์ฃผ๋ ๋ฐฉ๋ฒ์ ์ ๊ณตํ๊ธฐ ๋๋ฌธ์ ์ด ๋ฐฉ๋ฒ์ ์ฌ์ฉํ๊ฒ ์ต๋๋ค.
Java with Gradle - Configure๋ฅผ ํด๋ฆญํ์ฌ ์ ๊ณตํ๋ ํ ํ๋ฆฟ ์ฝ๋๋ฅผ ์์ ํ๋ฉด์ CI, CD๋ฅผ ๊ตฌ์ถํ ๊ฑด๋ฐ, Git Action์ ๊ตฌ์ฑ์์๋ค์ ๋จผ์ ์์๋ณด๊ฒ ์ต๋๋ค.
Workflow(yml)
# This workflow uses actions that are not certified by GitHub.
# They are provided by a third-party and are governed by
# separate terms of service, privacy policy, and support
# documentation.
# This workflow will build a Java project with Gradle and cache/restore any dependencies to improve the workflow execution time
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-java-with-gradle
name: Java CI with Gradle
on:
push:
branches: [ "develop" ]
pull_request:
branches: [ "develop" ]
jobs:
build:
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- uses: actions/checkout@v4
- name: Set up JDK 17
uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'temurin'
# Configure Gradle for optimal use in GiHub Actions, including caching of downloaded dependencies.
# See: https://github.com/gradle/actions/blob/main/setup-gradle/README.md
- name: Setup Gradle
uses: gradle/actions/setup-gradle@417ae3ccd767c252f5661f1ace9f835f9654f2b5 # v3.1.0
- name: Build with Gradle Wrapper
run: ./gradlew build
# NOTE: The Gradle Wrapper is the default and recommended way to run Gradle (https://docs.gradle.org/current/userguide/gradle_wrapper.html).
# If your project does not have the Gradle Wrapper configured, you can use the following configuration to run Gradle with a specified version.
#
# - name: Setup Gradle
# uses: gradle/actions/setup-gradle@417ae3ccd767c252f5661f1ace9f835f9654f2b5 # v3.1.0
# with:
# gradle-version: '8.5'
#
# - name: Build with Gradle 8.5
# run: gradle build
dependency-submission:
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/checkout@v4
- name: Set up JDK 17
uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'temurin'
# Generates and submits a dependency graph, enabling Dependabot Alerts for all project dependencies.
# See: https://github.com/gradle/actions/blob/main/dependency-submission/README.md
- name: Generate and submit dependency graph
uses: gradle/actions/dependency-submission@417ae3ccd767c252f5661f1ace9f835f9654f2b5 # v3.1.0
- ๋ฆฌํฌ์งํ ๋ฆฌ์ ์ถ๊ฐํ ์ ์๋ ์ผ๋ จ์ ์๋ํ๋ ์ปค๋งจ๋ ์งํฉ์ผ๋ก ์ yml ํ์ผ์ ์ผ์ปฌ์ด workflow๋ผ๊ณ ๋ณผ ์ ์๊ฒ ์ต๋๋ค.
Event
on:
push:
branches: [ "develop" ]
pull_request:
branches: [ "develop" ]
- Workflow๊ฐ ๊ตฌ๋์ํค๊ธฐ ์ํ ํธ๋ฆฌ๊ฑฐ๋ก, ์ฌ๊ธฐ์ ์์ฑ๋ ๋์๋ค์ด ์ด๋ฃจ์ด ์ง ๋ Workflow๊ฐ ๊ตฌ๋๋ฉ๋๋ค.
- ์์ ๊ฐ์ด push, pull_request์ ๊ฐ์ด ํน์ ํ ์์ ์ด ์ด๋ฃจ์ด์ง ๋ workflow๊ฐ ์คํ๋๋๋ก ์์ฑํ ์ ์์ต๋๋ค.
- ์ ์์์์๋ develop ๋ธ๋์น์ pushํ๊ฑฐ๋ develop ๋ธ๋์น์ PR์ ๋ณด๋ผ ๋ ์ด workflow๊ฐ ๋์ํ๋ค๊ณ ๋ณผ ์ ์๊ฒ ์ฃ .
Runner
- Workflow์ ๋์๋ค์ ๊ตฌ๋ํ๊ธฐ ์ํ ์ ํ๋ฆฌ์ผ์ด์ ์ผ๋ก, Github์์ ๊ฐ์ ํ๊ฒฝ์ ์ ๊ณตํ์ฌ ์ด ๊ฐ์ ํ๊ฒฝ ์์์ workflow๊ฐ ๊ตฌ๋๋๋ค๊ณ ๋ณด์๋ฉด ๋๊ฒ ์ต๋๋ค.
Action
- ์ฌ์ฌ์ฉ ๊ฐ๋ฅํ Workflow์ ๊ฐ์ฅ ์์ ๋จ์๋ธ๋ญ์ผ๋ก, ์ง์ ๋ง๋ Action์ ์ฌ์ฉํ๊ฑฐ๋ Github ์ปค๋ฎค๋ํฐ์ ์ํด ์์ฑ๋ Action์ ๋ถ๋ฌ์ ์ฌ์ฉํ ์ ์์ต๋๋ค.
- ํ์๊ฐ ์์ฑํ Workflow์์๋ ์ฌ์ฉ๋์ง๋ ์๊ธฐ ๋๋ฌธ์ ์ด๋ฐ ๊ตฌ์ฑ์์๋ ์๋ค ์ ๋๋ก ์๊ณ ๋ง ๋์ด๊ฐ์ ๋ ์ข์ต๋๋ค.
Step
- workflow์ ์์ฑ๋ ์ค์ ๊ตฌ๋๋๋ ์ปค๋งจ๋๋ค์ ๋ฌถ์ด Step์ผ๋ก ๊ด๋ฆฌํฉ๋๋ค. ์คํญ์ผ๋ก ๋ฌถ์ฌ์ ์์ฑ๋ ์ปค๋งจ๋๋ค์ ์คํ ๋ฐ์ด ์คํ ์ผ๋ก ์คํ๋๊ธฐ ๋๋ฌธ์ CI/CD์ ํ์ํ ์์ ๋ค์ ์์ฐจ์ ์ผ๋ก ์งํ์ํฌ ์ ์๊ฒ ์ต๋๋ค.
Job
- ์ฌ๋ฌ Step๋ค์ ์งํฉ์ ํ๋์ Job์ผ๋ก ์ ์ํฉ๋๋ค.
- ๋ณดํต ํ๋์ Workflow์ ์ฌ๋ฌ Job์ด ์๋ค๋ฉด ๊ฐ๊ฐ์ Job๋ค์ ์์์ ์๊ด์์ด ๋ ๋ฆฝ์ ์ผ๋ก ์คํ๋์ง๋ง, ํ์์ ๋ฐ๋ผ ์์กด๊ด๊ณ๋ฅผ ์ค์ ํ์ฌ ์์๋ฅผ ์ง์ ํ ์๋ ์๋ค๊ณ ํฉ๋๋ค.
- ์ฐธ๊ณ ๋ก CI์ CD๋ฅผ ๋๋์ด ๊ฐ๊ฐ์ Job์ผ๋ก ์ค์ ํ๊ณ , CI๊ฐ ๋๋ ํ CD๊ฐ ์คํ๋๋๋ก ์์กด๊ด๊ณ๋ฅผ ์ค์ ํ ์๋ ์๊ฒ ์ง๋ง, ํ์๋ ๊ตณ์ด ๊ทธ๋ด ํ์์ฑ์ด ์๋ค๊ณ ํ๋จํ์ฌ, CI/CD๊ณผ์ ์ ํ๋์ Job์ผ๋ก ๊ด๋ฆฌํ์ต๋๋ค.
CI/CD๋ฅผ ์ํ workflow - 0. ๋น๋ ํ๊ฒฝ ๊ตฌ์ถ
name: Java CI with Gradle
on:
push:
branches: [ "develop" ]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Set up JDK 17
uses: actions/setup-java@v3
with:
java-version: '17'
distribution: 'adopt'
- name: Copy Secret
env:
OCCUPY_SECRET: ${{ secrets.OCCUPY_SECRET }}
OCCUPY_SECRET_DIR: src/main/resources
OCCUPY_SECRET_DIR_FILE_NAME: application-secret.yml
run: echo $OCCUPY_SECRET | base64 --decode > $OCCUPY_SECRET_DIR/$OCCUPY_SECRET_DIR_FILE_NAME
- name: gradlew mod modify
run: chmod +x gradlew
# gradle ์บ์ฑ (0)
- 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-
# Spring Boot ์ดํ๋ฆฌ์ผ์ด์
Build (1)
- name: Spring Boot Build
run: ./gradlew clean build --exclude-task test
# Docker ์ด๋ฏธ์ง Build (2)
- name: docker image build
run: docker build -t rlaehddnd0422/dnd .
# DockerHub Login (3)
- name: docker login
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
# Docker Hub push (4)
- name: docker Hub push
run: docker push rlaehddnd0422/dnd
# GET GitHub IP (5)
- name: get GitHub IP
id: ip
uses: haythem/public-ip@v1.2
# Configure AWS Credentials (6) - AWS ์ ๊ทผ ๊ถํ ์ทจ๋(IAM)
- 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
# Add github ip to AWS (7)
- name: Add GitHub IP to AWS
run: |
aws ec2 authorize-security-group-ingress --group-id ${{ secrets.AWS_SG_ID }} --protocol tcp --port 22 --cidr ${{ steps.ip.outputs.ipv4 }}/32
# AWS EC2 Server Connect & Docker ๋ช
๋ น์ด ์คํ (8)
- name: AWS EC2 Connection
uses: appleboy/ssh-action@v0.1.6
with:
host: ${{ secrets.EC2_HOST }}
username: ubuntu
password: ${{ secrets.EC2_PASSWORD }}
port: ${{ secrets.EC2_SSH_PORT }}
timeout: 60s
script: |
sudo docker stop dnd2
sudo docker rm dnd2
sudo docker rmi rlaehddnd0422/dnd
sudo docker pull rlaehddnd0422/dnd
sudo docker run -it -d -p 8080:8080 --name dnd2 rlaehddnd0422/dnd
# REMOVE GitHub IP FROM security group (9)
- name: Remove IP FROM security group
run: |
aws ec2 revoke-security-group-ingress --group-id ${{ secrets.AWS_SG_ID }} --protocol tcp --port 22 --cidr ${{ steps.ip.outputs.ipv4 }}/32
- ํ๋ก์ ํธ์ CI/CD๋ฅผ ๊ตฌ์ถํ ์ํฌํ๋ก์ฐ ํ์ผ์ ๋๋ค.
- Step ๋ณ๋ก ํ๋์ฉ ์ด๋ป๊ฒ ๋์ํ๋์ง ์ฝ๋๋ฅผ ๋ฏ์ด๋ด ์๋ค.
0. Event ์์ฑ
on:
push:
branches: [ "develop" ]
- PR์ ๊ฐ์งํ์ฌ PR ์์๋ ์ํ๋๋๋ก ์์ฑํ ์๋ ์๊ฒ ์ง๋ง, ํ์๋ ๋์ผํ ์์ ์ ๋ํด CI CD๋ฅผ PR์์ ํ ๋ฒ, merge์์ ํ ๋ฒ ์ด๋ ๊ฒ ์ด ๋ ๋ฒ ๋์ํ ์ด์ ๊ฐ ์๋ค๊ณ ํ๋จํ์ฌ ์ ๋ develop ๋ธ๋์น์ pushํ๋ event ๋ฐ์ ์์๋ง workflow๊ฐ ๋์ํ๋๋ก ์์ฑํ์์ต๋๋ค.
1. Runner ํ๊ฒฝ์ JDK 17 ์ค์น
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Set up JDK 17
uses: actions/setup-java@v3
with:
java-version: '17'
distribution: 'adopt'
- Runner ์ ํ๋ฆฌ์ผ์ด์ ์ ์ฐ๋ถํฌ์ ๊ฐ์ฅ ์ต๊ทผ ๋ฒ์ ์์์ ํ๋ก์ ํธ๋ฅผ ๋น๋ํ๊ธฐ ์ํด JDK 17์ ์ค์นํด์ค๋๋ค.
2. ์ค์ ์ ๋ณด secret ํ์ผ ์ฃผ์
ํ์๋ ์ฐธ๊ณ ๋ก application.yml์ ์์ฑ๋ JWT ์ํฌ๋ฆฟ ํค์ ๊ฐ์ด ๋ณด์์ฑ์ด ๋์ ์ฝ๋๋ค์ application-secret.yml๋ก ๊ด๋ฆฌํ์ต๋๋ค.
์ ์ถ๋๋ฉด ์๋๋ ์ฝ๋๋ฅผ ์ฌ์ฉํ์ง ์๋ ๊ฒฝ์ฐ์ ์ด ๊ณผ์ ์ ํจ์คํ์๋ฉด ๋ฉ๋๋ค.
application.yml
jwt:
secret_key: ${jwt.secret.secret_key}
application-secret.yml
jwt:
secret:
secret_key: ~~
- name: Copy Secret
env:
OCCUPY_SECRET: ${{ secrets.OCCUPY_SECRET }}
OCCUPY_SECRET_DIR: src/main/resources
OCCUPY_SECRET_DIR_FILE_NAME: application-secret.yml
run: echo $OCCUPY_SECRET | base64 --decode > $OCCUPY_SECRET_DIR/$OCCUPY_SECRET_DIR_FILE_NAME
- ํ๋ก์ ํธ๋ฅผ ๋น๋ํ๊ธฐ์ ์์, Git์์ ๊ด๋ฆฌํ์ง ์๋ ๋ณด์์ฑ์ด ๋์ ์ฝ๋๋ค์ secret์ผ๋ก ์ฃผ์ ์์ผ ์ค์๋ค.
- ๋จผ์ ์ฃผ์ ํ์ง ์๋ ๊ฒฝ์ฐ ๋น๋๊ฐ ์ ๋๋ก ์ด๋ฃจ์ด์ง์ง ์๊ธฐ ๋๋ฌธ์, ๋ฐ๋์ ์ฃผ์ ์ ๋จผ์ ์๋์ผ๋ก ํด์ค์๋ค.
run: echo $OCCUPY_SECRET | base64 --decode > $OCCUPY_SECRET_DIR/$OCCUPY_SECRET_DIR_FILE_NAME
โถ๏ธ run ์ปค๋งจ๋๋ฅผ ํตํด ์ธ์ฝ๋ฉ๋ secret ํ์ผ์ base64๋ก ๋์ฝ๋ฉํ์ฌ SECRET_DIR ์ ์์ฑํ ๋๋ ํ ๋ฆฌ์ FILE_NAME์ผ๋ก ์ธํ ํฉ๋๋ค.
3. secret ํ์ผ ํ๊ฒฝ ๋ณ์์ ์ธํ ํ๊ธฐ
Github์์ CI/CD๋ฅผ ๊ตฌ์ถํ ํ๋ก์ ํธ์ Setting ํญ์์ Secrets and variables์ Actions ํญ์์ Git Action์์ ์ฌ์ฉ๋๋ ํ๊ฒฝ๋ณ์๋ฅผ ์ค์ ํ ์ ์์ต๋๋ค.
- New Repository secret์ ๋๋ฌ ์ํ๋ ์ด๋ฆ๊ณผ ์ํฌ๋ฆฟ ๊ฐ๋ค์ ์ค์ ํ์๋ฉด ๋ฉ๋๋ค.
- ์ฐธ๊ณ ๋ก secret ํ์ผ์ base64๋ก ์ธ์ฝ๋ฉํ์ฌ ์ค์ ํ๋๋ก ํฉ์๋ค.
- ๋งํฌ ์ฐธ๊ณ : https://www.base64decode.org/
CI/CD๋ฅผ ์ํ workflow - 1. CI ๊ตฌ์ถ
- name: gradlew mod modify
run: chmod +x gradlew
# gradle ์บ์ฑ (0)
- 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 mod modify: Gradle ๋ํผ ์คํฌ๋ฆฝํธ์ ๊ถํ์ ์์ ํฉ๋๋ค.
- Gradle Caching: Gradle ์ข ์์ฑ์ ์บ์ฑํ์ฌ ์ํฌํ๋ก์ฐ ์คํ ์๊ฐ์ ๋จ์ถํฉ๋๋ค.
# Spring Boot ์ดํ๋ฆฌ์ผ์ด์
Build (1)
- name: Spring Boot Build
run: ./gradlew clean build --exclude-task test
# Docker ์ด๋ฏธ์ง Build (2)
- name: docker image build
run: docker build -t rlaehddnd0422/dnd .
# DockerHub Login (3)
- name: docker login
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
# Docker Hub push (4)
- name: docker Hub push
run: docker push rlaehddnd0422/dnd
- Spring Boot Build: Spring Boot ์ ํ๋ฆฌ์ผ์ด์ ์ ๋น๋ํ๋ฉฐ ํ ์คํธ๋ ์ ์ธํฉ๋๋ค.
- Docker ์ด๋ฏธ์ง build: rlaehddnd0422/dnd ํ๊ทธ๋ก Docker ์ด๋ฏธ์ง๋ฅผ ๋น๋ํฉ๋๋ค.
- Docker login: ์ ๊ณต๋ ์๊ฒฉ ์ฆ๋ช
์ ์ฌ์ฉํ์ฌ Docker Hub์ ๋ก๊ทธ์ธํฉ๋๋ค.
- ์ฌ๊ธฐ์ ์ ๊ณตํ ์๊ฒฉ ์ฆ๋ช ๊ฐ ๋ํ secret ํ์ผ์ฒ๋ผ ํ๊ฒฝ๋ณ์๋ก ์ฃผ์ ํด์ฃผ์์ต๋๋ค. ๊ณผ์ ์ ๋์ผํ๋ฏ๋ก ์ค๋ช ์๋ต
- Docker Hub push: Docker ์ด๋ฏธ์ง๋ฅผ Docker Hub์ ํธ์ํฉ๋๋ค.
์ด๋ ๊ฒ develop ๋ธ๋์น์ push๊ฐ ๊ฐ์ง๋๋ ๊ฒฝ์ฐ ํ๋ก์ ํธ๋ฅผ ๋น๋ํ๊ณ , ๋์ปค ์ด๋ฏธ์ง๋ฅผ ๋น๋ํ์ฌ ๋์ปค ํ๋ธ์ ํธ์ฌํ๋ ๊ณผ์ ์ธ CI๊ณผ์ ์ด ์๋ฃ๋์์ต๋๋ค.
CI/CD๋ฅผ ์ํ workflow - 2. CD ๊ตฌ์ถ
์ด์ ๋ฆฌ๋ชจํธ ์๋ฒ์์ ๋์ปค ํ๋ธ์ ์๋ ์ด๋ฏธ์ง๋ฅผ pullํ์ฌ runํ๋ CD๊ณผ์ ๊น์ง ๊ตฌ์ถํด๋ณผ๊ฑด๋ฐ, ๊ณผ์ ์ด ๋น๊ต์ ๋ณต์กํ์ง๋ง ์ ๋ฐ๋ผ์จ๋ค๋ฉด ๊ทธ๋ ๊ฒ ์ด๋ ต์ง ์์ต๋๋ค.
์ฌ์ ์์ ์ผ๋ก ๋จผ์ Runner์์ ๋ฆฌ๋ชจํธ EC2 ์๋ฒ์ ์ ๊ทผํ ์ ์๋๋ก ํ๊ธฐ ์ํด ๋ณด์๊ทธ๋ฃน์ ์ด์ด์ฃผ์ด์ผ ํฉ๋๋ค.
EC2์ IAM Role์ ํตํด ์ธ๋ถ ์ ๊ทผ ๊ถํ์ ์ด์ด์ฃผ๊ธฐ ์ํด IAM Role์ ์์ฑํ๋๋ก ํฉ์๋ค.
EC2 -> IAM ์๋น์ค ์ ์
์ฌ์ฉ์ ์์ฑ ํด๋ฆญ
์๋์ ๊ฐ์ด ์ ํ ํ ๋ค์ ํด๋ฆญ
๊ถํ ์ค์ - ๊ทธ๋ฃน ์์ฑ
AmazonEc2FullAccess ์ ํ ๋ฐ ์ฌ์ฉ์ ๊ทธ๋ฃน ์์ฑ
์ฌ์ฉ์ ๊ทธ๋ฃน์ ์์ฑํ๋ฉด ์๋์ ๊ฐ์ด ์ํธ๊ฐ ์ ๊ณต๋๋๋ฐ, ์ํธ๋ ์ด ๋ ํ๋ฒ๋ง ํ์ธํ ์ ์๊ธฐ ๋๋ฌธ์ csvํ์ผ๋ก ๋ค์ด๋ฐ์ ๊ด๋ฆฌํ๊ฑฐ๋, ์๋ฐํ ๊ณณ์ ์ ์ฅํด๋์.
๋ค์ ์ฌ์ฉ์ ํญ์ผ๋ก ๋ค์ด์ ์ก์ธ์ค ํค ๋ง๋ค๊ธฐ๋ฅผ ํด๋ฆญํ์ฌ ์ก์ธ์ค ํค๋ฅผ ๋ฐ๊ธ๋ฐ๋๋ก ํฉ์๋ค.
์ฉ๋์ ๋ง๊ฒ ๋ฐ๊ธ๋ฐ์ผ๋ฉด ๋๋๋ฐ, ์๋ฌด๊ฑฐ๋ ํด๋ ์๊ด์๋ ๋ฏ ํฉ๋๋ค. ํ์๋ ์ฒซ๋ฒ์งธ CLI๋ก ๋ฐ๊ธ๋ฐ์์ต๋๋ค.
๋ฐ๊ธ๋ฐ์ ACCESS_KEY์ SECRET์ ์๊น์ ๋ง์ฐฌ๊ฐ์ง๋ก ํ๋ก์ ํธ ํ๊ฒฝ๋ณ์์ ์ธํ ํด์ฃผ์๋ฉด ๋ฉ๋๋ค.
# GET GitHub IP (5)
- name: get GitHub IP
id: ip
uses: haythem/public-ip@v1.2
# Configure AWS Credentials (6) - AWS ์ ๊ทผ ๊ถํ ์ทจ๋(IAM)
- 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
EC2์ ์ ๊ทผํ๊ธฐ ์ํ IP๋ฅผ ๊ฐ์ ธ์ค๊ณ , ์์์ ๋ฑ๋กํ id์ ์ํฌ๋ฆฟ ๊ฐ์ ์ฃผ์ ํ์ฌ, AWS EC2์ ์ ๊ทผํ๊ธฐ ์ํ IAM ๊ถํ์ ์ป์ต๋๋ค.
# Add github ip to AWS (7)
- name: Add GitHub IP to AWS
run: |
aws ec2 authorize-security-group-ingress --group-id ${{ secrets.AWS_SG_ID }} --protocol tcp --port 22 --cidr ${{ steps.ip.outputs.ipv4 }}/32
์ด์ ๊ฐ์ ธ์จ ์์ดํผ๋ฅผ AWS์ ์ ๊ทผํ์ฌ ์ ๊ทผํ ์ ์๋๋ก AWS์ ํด๋น ๊นํ๋ธ ์์ดํผ๋ฅผ ๋ฑ๋กํด์ฃผ๊ณ , EC2์ ์ ๊ทผํ์ฌ Docker ๋ช ๋ น์ด ์์ ์คํํ์ฌ CD ๊ตฌ์ถํ ์์ ์ ๋๋ค.
# AWS EC2 Server Connect & Docker ๋ช
๋ น์ด ์คํ (8)
- name: AWS EC2 Connection
uses: appleboy/ssh-action@v0.1.6
with:
host: ${{ secrets.EC2_HOST }}
username: ubuntu
password: ${{ secrets.EC2_PASSWORD }}
port: ${{ secrets.EC2_SSH_PORT }}
timeout: 60s
script: |
sudo docker stop dnd2
sudo docker rm dnd2
sudo docker rmi rlaehddnd0422/dnd
sudo docker pull rlaehddnd0422/dnd
sudo docker run -it -d -p 8080:8080 --name dnd2 rlaehddnd0422/dnd
ํ๊ฒฝ๋ณ์์ ๋ฑ๋กํ EC2 ์์ด๋์ ๋น๋ฐ๋ฒํธ, ๊ทธ๋ฆฌ๊ณ ํฌํธ๋ฒํธ๋ฅผ ํตํด EC2์ ์ ๊ทผํ์ฌ docker ๋ช ๋ น์ด๋ฅผ ํตํด ๋ฆฌ๋ชจํธ ์๋ฒ์ ์กด์ฌํ๋ ๊ธฐ์กด์ ์ด๋ฏธ์ง๋ฅผ ์ ๊ฑฐํ๊ณ , ๋์ปค ํ๋ธ์์ ์ด๋ฏธ์ง๋ฅผ pullํ๊ณ ์๋กญ๊ฒ run ํฉ๋๋ค.
# REMOVE GitHub IP FROM security group (9)
- name: Remove IP FROM security group
run: |
aws ec2 revoke-security-group-ingress --group-id ${{ secrets.AWS_SG_ID }} --protocol tcp --port 22 --cidr ${{ steps.ip.outputs.ipv4 }}/32
- CD ๊ตฌ์ถ์ด ๋๋ฌ์ผ๋ Github ์์ดํผ๋ฅผ ๋ณด์ ๊ทธ๋ฃน์์ ์ ๊ฑฐํด์ค์ผ๋ก์จ ์ถํ ์ธ๋ถ ์ ์์ ๋ง์์ฃผ๋๋ก ํฉ์๋ค.
CI/CD ํ์ดํ๋ผ์ธ ๊ตฌ์ถ์ ์ฌ์ฉ๋ ํ๊ฒฝ๋ณ์ ์ ๋ฆฌ
- AWS_ACCESS_KEY_ID : IAM Role์์ ์์ฑํ ์ก์ธ์ค ํค์ ID
- AWS_ACCESS_KEY_PASSWORD : IAM Role๋ก ์์ฑํ ์ก์ธ์ค ํค์ PASSWORD
- AWS_SG_ID : EC2 ๋ณด์๊ทธ๋ฃน ID
- DOCKERHUB_PW : ๋์ปค ํ๋ธ ๋น๋ฐ๋ฒํธ
- DOCKERHUB_TOKEN : ๋์ปค ํ๋ธ์์ ๋ฐ๊ธ๋ฐ์ ์ก์ธ์ค ํ ํฐ
- DOCKERHUB_USERNAME : ๋์ปค ํ๋ธ์ ์์ด๋
- EC2_HOST : AWS EC2 ์ธ์คํด์ค์ ํผ๋ธ๋ฆญ IPv4 DNS
- EC2_PASSWORD : EC2์ ์ ๊ทผ/์ฐ๊ฒฐ ์ค์ ํด๋์๋ ํจ์ค์๋
- EC2_SSH_PORT : SSH๋ก ์ ๊ทผํ port. (22)
- EC2_USERNAME : AWS EC2 ์ธ์คํด์ค์ username
- OCCUPY_SECRET : application-secret.yml (encoded with base 64)
์ด๋ ๊ฒ ์ด๋ฒ ํฌ์คํ ์์ Git Action์ ์ฌ์ฉํ์ฌ CI/CD ํ์ดํ๋ผ์ธ์ ๊ตฌํํ์ฌ ๋ฐฐํฌ๋ฅผ ์๋ํํด๋ณด์์ต๋๋ค.
๋ค์ ํฌ์คํ ์์๋ ์ด์ด Docker๋ฅผ ์ฌ์ฉํด ์ด๋ป๊ฒ ํ๋ก์ ํธ๋ฅผ ๊ด๋ฆฌ(๋น๋/๋ฐฐํฌ)ํ๋์ง ์์๋ณด๋๋ก ํ๊ฒ ์ต๋๋ค.
<์ฐธ๊ณ ์๋ฃ>
'๐ Etc > Sol' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
axios ์์ฒญ ์ header์ Token์ด ๋ด๊ธฐ์ง ์๋ ๋ฌธ์ ํด๊ฒฐ (0) | 2023.09.22 |
---|---|
[AWS] Amazon S3 ๋ฒํท์์ ํ์ผ ๊ฐ์ ธ์ค๊ธฐ (0) | 2023.09.12 |
[AWS] S3(Simple Storage Service)์๋ฒ์ Spring Boot ์ฐ๋ (0) | 2023.08.17 |
[MySQL] blocked because of many connection errrors ์๋ฌ ํด๊ฒฐ (0) | 2023.08.17 |
[DB] EC2 MySQL ์ฐ๋ ์ค ๋๋ฏธ ๋ฐ์ดํฐ ์ฝ์ ์ค๋ฅ ํด๊ฒฐ (0) | 2023.08.16 |
๋ธ๋ก๊ทธ์ ์ ๋ณด
Study Repository
rlaehddnd0422