Project/์‹นํ‹”์›€

[์‹นํ‹”์›€] 11/15 ๊ฐœ๋ฐœ์ผ์ง€ Github Actions ๋ฅผ ์‚ฌ์šฉํ•œ CI/CD ์ž๋™ํ™”

ํ•œ33 2024. 11. 30. 17:23

๐Ÿ’ก ๋ชฉํ‘œ

CI/CD ์ž๋™ํ™”๋ฅผ ํ†ตํ•ด main ๋ธŒ๋žœ์น˜๋กœ Pull Request ๊ฐ€ ์ด๋ฃจ์–ด์ง€๋ฉด ์ž๋™์œผ๋กœ ๋ฐฐํฌ๊นŒ์ง€ ๋˜๋„๋ก ์„ค์ •ํ•˜๊ณ ์ž ํ–ˆ๋‹ค.

 

 

DockerFile

FROM amazoncorretto:17-alpine-jdk
EXPOSE 8080
ARG JAR_FILE=build/libs/*.jar
COPY ${JAR_FILE} app.jar
ENTRYPOINT ["java", "-jar", "app.jar"]

 

Github Actions ๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด์„œ Docker File ์„ ๋งŒ๋“ค์–ด์ค€๋‹ค.

 

CICD.yml

name: CI/CD

on:
  pull_request:
    branches: ["main"]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v3

      - name: Install JDK 17
        uses: actions/setup-java@v3
        with:
          java-version: '17'
          distribution: 'temurin'

      - name: Build with Gradle
        run: |
          chmod +x ./gradlew
          ./gradlew clean build -x test

      - name: Login to DockerHub
        uses: docker/login-action@v1
        with:
          username: ${{ secrets.DOCKERHUB_USERNAME }}
          password: ${{ secrets.DOCKERHUB_TOKEN }}

      - name: Build Docker Image
        run: docker build -t ${{ secrets.DOCKERHUB_USERNAME }}/ssak:v1 .

      - name: Push Docker Image
        run: docker push ${{ secrets.DOCKERHUB_USERNAME }}/ssak:v1

  deploy:
    needs: build
    runs-on: ubuntu-latest
    steps:
      - name: Deploy to Server
        uses: appleboy/ssh-action@master
        with:
          username: ubuntu
          host: ${{ secrets.SSAKTIUM_SERVER_IP }}
          key: ${{ secrets.EC2_SSH_KEY }}
          script_stop: true
          script: |
            # Pull the latest image from DockerHub
            sudo docker pull ${{ secrets.DOCKERHUB_USERNAME }}/ssak:v1
            
            # Stop and remove the existing container if it exists
            if [ "$(sudo docker ps -q -f name=daegyuhan-ssak)" ]; then
              sudo docker stop daegyuhan-ssak
            fi
            
            if [ "$(sudo docker ps -aq -f status=exited -f name=daegyuhan-ssak)" ]; then
              sudo docker rm daegyuhan-ssak
            fi
            
            # Run the new container with the .env file for environment variables
            sudo docker run -d --name daegyuhan-ssak --env-file /home/ubuntu/.env -p 8080:8080 ${{ secrets.DOCKERHUB_USERNAME }}/ssak:v1

 

์ด๋ฒคํŠธ๊ฐ€ ์ผ์–ด๋‚ฌ์„ ๋•Œ ์ž๋™์œผ๋กœ ์‹คํ–‰๋˜๋Š” ๊ฒƒ์ด ํŠธ๋ฆฌ๊ฑฐ.

 

main ๋ธŒ๋žœ์น˜์— pull request ๊ฐ€ ์ผ์–ด๋‚˜๋ฉด ์ด ํŒŒ์ผ์„ ์‹คํ–‰ํ•˜๊ฒ ๋‹ค๋Š” ๋œป์ด๋‹ค.


๐Ÿ’ก Work Flow ๋ถ„์„: Build

jobs:
  build:
    runs-on: ubuntu-latest

 

runs on : ubuntu ์ตœ์‹ ๋ฒ„์ „ 

๊ฐ€์ƒ์˜ pc ๊ฐ€ ์‹คํ–‰๋ ํ…๋ฐ ์„ค์ •ํ•ด์ฃผ๋Š” ๊ฒƒ

ubuntu  ๊ฐ€ ๊ฐ€์žฅ ๊ฐ€๋ณ๊ณ  ๋ณดํŽธ์ ๊ณ  ์„œ๋ฒ„๋กœ ๋งŽ์ด ์‚ฌ์šฉ๋จ

 

    steps:
      - name: Checkout code
        uses: actions/checkout@v3

      - name: Install JDK 17
        uses: actions/setup-java@v3
        with:
          java-version: '17'
          distribution: 'temurin'

      - name: Build with Gradle
        run: |
          chmod +x ./gradlew
          ./gradlew clean build -x test

steps:

๋‹จ์œ„๋Š” name ์œผ๋กœ ๋Š์–ด์„œ ์‹คํ–‰ํ•œ๋‹ค.

 

uses:

github action ์— ํ…œํ”Œ๋ฆฟ์ด ๋ช‡ ๊ฐ€์ง€ ์žˆ๋‹ค.

์ด ๋ ˆํฌ์ง€ํ† ๋ฆฌ์— pull request ๊ฐ€ ์ผ์–ด๋‚˜๋ฉด checkout, ์ž๋™์œผ๋กœ ํŒจ์น˜ํ•˜๊ณ  ํ’€ ํ•˜๊ฒ ๋‹ค๋Š” ๋œป์ด๋‹ค.

ubuntu ์—๋‹ค๊ฐ€ ์ž๋™์œผ๋กœ git ์„ค์น˜ํ•˜๊ณ  repository ๋ฅผ pull ํ•˜๋Š” ๊ณผ์ •์„ ๋‹ค ์ƒ๋žตํ•ด์ฃผ๋Š” ํŽธํ•œ ๊ธฐ๋Šฅ์ด๋‹ค.

 

install JDK 17

clean ํ•˜๊ณ  build ๋ˆ„๋ฅด๋ฉด jar ํŒŒ์ผ ๋งŒ๋“ค์–ด์ง€๋Š”๋ฐ jar ํŒŒ์ผ์ด ์žˆ์–ด์•ผ์ง€ ๋‹ค๋ฅธ ํ™˜๊ฒฝ์—์„œ ์‹คํ–‰์„ ํ•  ์ˆ˜ ์žˆ๋‹ค.

์ด jar ํŒŒ์ผ์„ ๊ฐ€์ง€๊ณ  docker ๋ฅผ ์‹คํ–‰์‹œํ‚ฌ ๊ฒƒ์ธ๋ฐ ๊ทธ๋ ‡๊ฒŒ ํ•˜๊ธฐ ์œ„ํ•ด์„œ 

      - name: Build with Gradle
        run: |
          chmod +x ./gradlew
          ./gradlew clean build -x test

 

clean, build ์ž‘์—…์„ ์ง„ํ–‰ํ•œ๋‹ค.

์ด๋Ÿฌ๋ฉด jar ํŒŒ์ผ์ด ๋งŒ๋“ค์–ด์ง„๋‹ค.

 

์ง€๊ธˆ ๋‹จ๊ณ„์—์„œ ํ…Œ์ŠคํŠธ์ฝ”๋“œ๊ฐ€ ์™„์„ฑ์ด ์•ˆ๋˜์–ด์žˆ๊ธฐ ๋•Œ๋ฌธ์— -x test ๋ฅผ ํ†ตํ•ด test ์ฝ”๋“œ ์‹คํ–‰์€ ์Šคํ‚ตํ•ด์ฃผ์—ˆ๋‹ค.

 

      - name: Login to DockerHub
        uses: docker/login-action@v1
        with:
          username: ${{ secrets.DOCKERHUB_USERNAME }}
          password: ${{ secrets.DOCKERHUB_TOKEN }}

      - name: Build Docker Image
        run: docker build -t ${{ secrets.DOCKERHUB_USERNAME }}/ssak:v1 .

      - name: Push Docker Image
        run: docker push ${{ secrets.DOCKERHUB_USERNAME }}/ssak:v1

 

build ๋ฅผ ํ†ตํ•ด ๋งŒ๋“  jar ํŒŒ์ผ์„ Docker ์ด๋ฏธ์ง€๋กœ ๋งŒ๋“ค๊ณ  Docker Hub ์— ์˜ฌ๋ฆฌ๊ธฐ ์œ„ํ•ด์„œ Docker Hub ์— ๋กœ๊ทธ์ธ์„ ํ•ด์•ผํ•œ๋‹ค.

์ดํ›„์— Docker Hub ์— ์˜ฌ๋ ค์ง„ ์ด ์ด๋ฏธ์ง€ ํŒŒ์ผ์„ EC2 ์— ์ ‘์†ํ•ด ๋‹ค์šด๋ฐ›๊ฒŒ ํ•˜๊ธฐ ์œ„ํ•จ์ด๋‹ค.

 

github ํ™ˆํŽ˜์ด์ง€์—์„œ ์„ค์ •ํ•œ ํ™˜๊ฒฝ๋ณ€์ˆ˜๋ฅผ ํ™œ์šฉํ•ด์„œ ํ•ด๋‹น ์ด๋ฆ„์œผ๋กœ ์ด๋ฏธ์ง€๋ฅผ ๋งŒ๋“ค๊ณ ,

๊ทธ ์ด๋ฏธ์ง€๋ฅผ Docker Hub ์— push ๋ฅผ ํ•œ๋‹ค.

 

Repository Secrets ์„ค์ •ํ•˜๊ธฐ

๋”๋ณด๊ธฐ

 

์ด๋ ‡๊ฒŒ ์ •๋ณด๋“ค์„ ๋‹ค ๋„ฃ์–ด์ค€๋‹ค.

๊ทธ๋Ÿผ ํ•ด๋‹น secrets ์˜ ๊ฐ’์„ ๋„ฃ์„ ์ˆ˜ ์žˆ๋‹ค.


๐Ÿ’ก Work Flow ๋ถ„์„: Deploy

deploy:
  needs: build
  runs-on: ubuntu-latest
  steps:
    - name: Deploy to Server
      uses: appleboy/ssh-action@master
      with:
        username: ubuntu
        host: ${{ secrets.SSAKTIUM_SERVER_IP }}
        key: ${{ secrets.EC2_SSH_KEY }}
        script_stop: true
        script: |
          # Pull the latest image from DockerHub
          sudo docker pull ${{ secrets.DOCKERHUB_USERNAME }}/ssak:v1
          
          # Stop and remove the existing container if it exists
          if [ "$(sudo docker ps -q -f name=daegyuhan-ssak)" ]; then
            sudo docker stop daegyuhan-ssak
          fi
          
          if [ "$(sudo docker ps -aq -f status=exited -f name=daegyuhan-ssak)" ]; then
            sudo docker rm daegyuhan-ssak
          fi
          
          # Run the new container with the .env file for environment variables
            sudo docker run -d --name daegyuhan-ssak --env-file /home/ubuntu/.env -p 8080:8080 ${{ secrets.DOCKERHUB_USERNAME }}/ssak:v1

 

deploy ํ™˜๊ฒฝ์—์„œ๋„ build ์™€ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ubuntu ํ™˜๊ฒฝ์—์„œ ์ž‘์—…ํ–ˆ๋‹ค.

EC2 ์— ์ ‘์†ํ•˜๊ธฐ ์œ„ํ•ด์„œ ํ•ด๋‹น IP ์™€ SSH_KEY ๋ฅผ ์ž…๋ ฅํ–ˆ๋‹ค.

 

Build ๋‹จ๊ณ„์—์„œ Push ํ–ˆ๋˜ Docker ์ด๋ฏธ์ง€๋ฅผ Pull ๋กœ ๋‹น๊ฒจ์™”๋‹ค.

 

์ด์ „์— ์‹คํ–‰๋˜๊ณ  ์žˆ๋Š” ๋™์ผํ•œ ์ด๋ฆ„์˜ ์ปจํ…Œ์ด๋„ˆ๊ฐ€ ์žˆ์œผ๋ฉด ์ถฉ๋Œ์ด ์ผ์–ด๋‚˜๊ธฐ ๋•Œ๋ฌธ์— 

์กฐ๊ฑด๋ฌธ์„ ์‚ฌ์šฉํ•ด์„œ ๋ฉˆ์ถ˜ ํ›„ ์‚ญ์ œ์ฒ˜๋ฆฌ๋ฅผ ํ–ˆ๋‹ค.

 

# Run the new container with the .env file for environment variables
sudo docker run -d --name daegyuhan-ssak --env-file /home/ubuntu/.env -p 8080:8080 ${{ secrets.DOCKERHUB_USERNAME }}/ssak:v1

 

ํ•„์ž๋Š” EC2 ์— .env ํŒŒ์ผ์„ ๋งŒ๋“ค์–ด์„œ ํ”„๋กœ์ ํŠธ yml ํŒŒ์ผ์—์„œ ์‚ฌ์šฉ๋œ ํ™˜๊ฒฝ๋ณ€์ˆ˜๋“ค์„ ์ฒ˜๋ฆฌํ–ˆ๋‹ค.

 

๋•Œ๋ฌธ์— ์ปจํ…Œ์ด๋„ˆ๋ฅผ ์‹คํ–‰์‹œํ‚ฌ ๋•Œ EC2 ๋‚ด๋ถ€์— .env ๋ฅผ ์ฐธ๊ณ ํ•ด์„œ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋„๋ก ์œ„์™€ ๊ฐ™์ด ์ฝ”๋“œ๋ฅผ ์งœ์คฌ๋‹ค.


์ด์ „์— ๋ฐœํ‘œํ–ˆ๋˜ CI, CD ์— ๋Œ€ํ•œ ๋‚ด์šฉ๊ณผ ํŒŒ์ดํ”„๋ผ์ธ ๊ตฌ์ถ•์— ๋Œ€ํ•ด ๊ณต๋ถ€๋ฅผ ํ–ˆ๋˜ ๋‚ด์šฉ๋“ค์„ ์ฐธ๊ณ ํ–ˆ๋‹ค.

https://hanstory33.tistory.com/241

 

[CS] CI ์™€ CD ๋ž€?

PPT : CI/CD - ํ”„๋ ˆ์  ํ…Œ์ด์…˜ YOUTUBE : [CS๋ฐœํ‘œ] CI / CD - YouTube

hanstory33.tistory.com

https://hanstory33.tistory.com/243

 

[CS] CI/CD ํŒŒ์ดํ”„๋ผ์ธ ๊ตฌ์ถ•์„ ์œ„ํ•œ ์ดํ•ด

1. CI/CD ๋Š” ์„ธ ๋‹จ๊ณ„๋ฅผ ๊ฐ€์ง„๋‹ค. ๊ฐœ๋ฐœ, ๋นŒ๋“œ, ๋ฐฐํฌ๊ฐ ๋‹จ๊ณ„๋Š” ํ•˜๋‚˜์˜ ์„œ๋ฒ„ ๊ฐœ๋…์ด๋‹ค.2. Jar ํŒŒ์ผ ๋นŒ๋“œ ์‹œ์ ์— ๋Œ€ํ•œ ๊ณ ๋ฏผ .jar ํŒŒ์ผ์„ ๋นŒ๋“œํ•ด์•ผํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ด ๊ณผ์ •์„ ๊ฐœ๋ฐœ ๋‹จ๊ณ„์—์„œ ํฌํ•จํ•ด์„œ ๊ฐ€์ ธ๊ฐ€๋ƒ,

hanstory33.tistory.com