# Git Actions์™€ Docker๋ฅผ ์ด์šฉํ•œ CI/CD pipeline ๊ตฌ์ถ•
Study Repository

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 ํ”„๋กœ์ ํŠธ - Setting ํƒญ

Github์—์„œ CI/CD๋ฅผ ๊ตฌ์ถ•ํ•  ํ”„๋กœ์ ํŠธ์˜ Setting ํƒญ์—์„œ Secrets and variables์˜ Actions ํƒญ์—์„œ Git Action์—์„œ ์‚ฌ์šฉ๋˜๋Š” ํ™˜๊ฒฝ๋ณ€์ˆ˜๋ฅผ ์„ค์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

 

  • New Repository secret์„ ๋ˆŒ๋Ÿฌ ์›ํ•˜๋Š” ์ด๋ฆ„๊ณผ ์‹œํฌ๋ฆฟ ๊ฐ’๋“ค์„ ์„ค์ •ํ•˜์‹œ๋ฉด ๋ฉ๋‹ˆ๋‹ค.
ex) ์„ค์ •ํ•œ ์‹œํฌ๋ฆฟ ํŒŒ์ผ
  • ์ฐธ๊ณ ๋กœ secret ํŒŒ์ผ์€ base64๋กœ ์ธ์ฝ”๋”ฉํ•˜์—ฌ ์„ค์ •ํ•˜๋„๋ก ํ•ฉ์‹œ๋‹ค.
  • ๋งํฌ ์ฐธ๊ณ  :  https://www.base64decode.org/
 

Base64 Decode and Encode - Online

Decode from Base64 format or encode into it with various advanced options. Our site has an easy to use online tool to convert your data.

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
  • 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๋ฅผ ์‚ฌ์šฉํ•ด ์–ด๋–ป๊ฒŒ ํ”„๋กœ์ ํŠธ๋ฅผ ๊ด€๋ฆฌ(๋นŒ๋“œ/๋ฐฐํฌ)ํ–ˆ๋Š”์ง€ ์•Œ์•„๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

 


<์ฐธ๊ณ ์ž๋ฃŒ>

 

GitHub Actions๋ฅผ ์ด์šฉํ•œ CI/CD ๊ตฌ์ถ•ํ•˜๊ธฐ

Github Actions๋ฅผ ํ†ตํ•ด ์–ด๋–ป๊ฒŒ React ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์ž๋™์œผ๋กœ ๋ฐฐํฌํ•  ์ˆ˜ ์žˆ๋Š”์ง€ ์•Œ์•„๋ด…์‹œ๋‹ค.

ji5485.github.io

 

[Github Action, AWS] Github Action ์‚ฌ์šฉ์„ ์œ„ํ•œ AWS ํ‚ค ๋ฐœ๊ธ‰ ๋ฐ›๊ธฐ

github action์„ ํ™œ์šฉํ•ด์„œ EC2์™€์˜ CI/CD ํŒŒ์ดํ”„๋ผ์ธ์„ ๊ตฌ์ถ•ํ•  ๋•Œ, workflow์˜ .yml ํŒŒ์ผ์— secrets.AWS_ACCESS_KEY_ID, secrets.AWS_SECRET_ACCESS_KEY๋ฅผ ์ž…๋ ฅํ•ด์•ผํ•œ๋‹ค.

velog.io

 

[CI/CD] GitHub Action AWS์— IAM Role๋กœ ์ ‘๊ทผํ•˜๊ธฐ

์•ˆ๋…•ํ•˜์„ธ์š”! zerone-code์ž…๋‹ˆ๋‹ค. ์˜ค๋Š˜์€ ์•„๋งˆ ๋Œ€๋ถ€๋ถ„์˜ ๊ฐœ๋ฐœ์ž๋“ค์ด Github์„ ์ด์šฉํ•œ๋‹ค๋ฉด ์‚ฌ์šฉํ•ด๋ดค์„ GitHub Action์— ๋Œ€ํ•ด ๋งํ•ด๋ณด๊ณ ์ž ํ•ฉ๋‹ˆ๋‹ค. GitHub Action์„ ์ด์šฉํ•ด์„œ CI/CD๋ฅผ ๋งŽ์ด ํ•˜๋Š”๋ฐ, ์ด ๊ณผ์ •์—์„œ AWS

zerone-code.tistory.com

 

๋ธ”๋กœ๊ทธ์˜ ํ”„๋กœํ•„ ์‚ฌ์ง„

๋ธ”๋กœ๊ทธ์˜ ์ •๋ณด

Study Repository

rlaehddnd0422

ํ™œ๋™ํ•˜๊ธฐ