๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
๐Ÿ““ Cloud/CI-CD

[CI-CD ๊ตฌ์ถ•] AWS EC2, Docker ๋ฅผ ์ด์šฉํ•œ Spring Boot ์ž๋™ ๋ฐฐํฌ

by GroovyArea 2023. 6. 18.
์ธํ”„๋ผ ๊ตฌ์ถ•์€ ์ฐธ ์‰ฝ์ง€ ์•Š๋‹ค. ์ธํ”„๋ผ ๊ณต๋ถ€๋Š” ๋”๋”์šฑ ์–ด๋ ค์šด ๊ฒƒ ๊ฐ™๋‹ค.
๋ฌด์—‡๋ณด๋‹ค ์‹ค์Šต์„ ํ•˜๋ ค๋ฉด ๋น„์šฉ์ด ์ฐธ ๋งŽ์ด ๋“ ๋‹ค.

ํ•˜์ง€๋งŒ, ์›ํ™œํ•œ ๊ฐœ๋ฐœ์„ ์œ„ํ•ด์„œ๋Š” ์ž๋™ ๋ฐฐํฌ๋ฅผ ๊ตฌ์ถ•ํ•ด์•ผ์ง€๋งŒ, ์„œ๋น„์Šค ๊ฐœ๋ฐœ์—๋งŒ ์ง‘์ค‘ํ•  ์ˆ˜ ์žˆ๋‹ค.
๊ทธ๋ž˜์„œ ๋ฐฑ์—”๋“œ ๊ฐœ๋ฐœ์ž๋Š” ์„œ๋ฒ„ ๊ฐœ๋ฐœ ๋Šฅ๋ ฅ ์ด์™ธ์—, ์–ด๋Š ์ •๋„ ์ธํ”„๋ผ ๊ตฌ์ถ• ๋ฐ ํ™˜๊ฒฝ์— ๋Œ€ํ•œ ๊ฐœ๋…์„ ๊ธฐ๋ณธ์ ์œผ๋กœ ํƒ‘์žฌํ•ด์•ผ ๋œ๋‹ค๊ณ  ์ƒ๊ฐํ•œ๋‹ค.

์ด๋ฒˆ์— ์‚ฌ์ด๋“œ ํ”„๋กœ์ ํŠธ ๊ธฐํš ๋ฐ ์ธํ”„๋ผ ๊ตฌ์ถ•์„ ํ•ด์•ผ๋  ์ผ์ด ์ƒ๊ฒผ๋‹ค.
์–ด๋–ป๊ฒŒ ์ตœ๋Œ€ํ•œ ์‰ฝ๊ณ  ๋น ๋ฅด๊ฒŒ ๊ตฌ์ถ•ํ• ์ง€ ๊ณ ๋ฏผ์„ ํ•ด๋ตœ๋‹ค.

์ด ์ „์—๋Š” jar ํŒŒ์ผ์„ ๊ทธ๋Œ€๋กœ ์‹คํ–‰ํ•˜๊ธฐ ์œ„ํ•ด AWS EC2 ์ธ์Šคํ„ด์Šค์— ๊ณ ๋Œ€๋กœ ๋กœ์ปฌ๊ณผ ๋น„์Šทํ•œ ํ™˜๊ฒฝ์„ ๊ตฌ์„ฑํ•ด ๋†“๊ณ , yaml ๋„ ๊ทธ๋Œ€๋กœ ๋„ฃ์–ด๋†“๊ณ , ๋ฌด์ค‘๋‹จ ๋ฐฐํฌ๋ฅผ ์‹œ๋„ํ–ˆ๋‹ค. Ubuntu ์„œ๋ฒ„์—์„œ ํ• ๊ฒŒ ์ฐธ ๋งŽ์•˜๋‹ค.

๋„์ปค๋ฅผ ๊ณต๋ถ€ํ•˜๊ณ , ์‚ฌ์šฉํ•ด๋ณด๋ฉด์„œ EC2 ์— ์ง์ ‘์ ์ธ ํ™˜๊ฒฝ ๊ตฌ์ถ• ๋Œ€์‹  ์ด ๋„์ปค๋ฅผ ์จ๋ณด๋ฉด ์–ด๋–จ๊นŒ ํ•˜๋Š” ์ƒ๊ฐ์ด ๋“ค์—ˆ๋‹ค.

๊ทธ๋ž˜์„œ ๊ณ ๋ฏผ ๊ณผ์ • ๋ฐ ๊ฒฐ๊ณผ๋ฅผ ๋‚˜์—ดํ•ด๋ณด๊ฒ ๋‹ค.

 

์ƒ๊ฐํ•œ ํ”Œ๋กœ์šฐ

์ถœ์ฒ˜ : ์œ„์™€ ๊ฐ™์Œ.

  • Github actions ๋กœ CI ์ง„ํ–‰
  • Github actions ๋กœ Docker image (Spring boot application) ์ƒ์„ฑ ํ›„ Docker hub ์— ํ‘ธ์‹œ,
  • Docker hub ์— ์ตœ์‹  image ๊ฐ€ ํ‘ธ์‹œ๋  ๊ฒฝ์šฐ, EC2 ์—์„œ ์ด๋ฅผ ๊ฐ์ง€, Docker hub ์—์„œ pull ๋ฐ›์•„์„œ docker image run 

์ด๊ฒŒ ๋์ด๋‹ค.

 

ํ•˜์ง€๋งŒ, ์ตœ์‹  ์ด๋ฏธ์ง€๊ฐ€ ํ—ˆ๋ธŒ์— ์˜ฌ๋ผ๊ฐ”๋‹ค๋Š” ๊ฒƒ์„ EC2 ์—์„œ ์–ด๋–ป๊ฒŒ ๊ฐ์ง€ํ•˜์ง€?

๋‹ค Shell Script ๋กœ ์งœ์•ผ ํ•˜๋‚˜ (๋„์ปค ํ—ˆ๋ธŒ์— ์ ‘์†ํ•ด์„œ ์ตœ์‹  ์ด๋ฏธ์ง€๊ฐ€ ์žˆ์œผ๋ฉด ์ฐพ๊ณ , pull ๋ฐ›์•„์„œ run) 

์ƒ๊ฐ๋งŒ ํ•ด๋„ ๋ง‰๋ง‰ํ•˜๋‹ค.

 

๋„์›€์„ ์–ป๊ณ ์ž, ๋‚˜๋ณด๋‹ค ๊ฒฝ๋ ฅ ์žˆ๋Š” ์ฃผ๋ณ€ ์ง€์ธ๋“ค๊ป˜ ๋‚ด๊ฐ€ ์ƒ๊ฐํ•œ ์ž๋™ ๋ฐฐํฌ ํ”Œ๋กœ์šฐ๋ฅผ ์„ค๋ช… ๋“œ๋ ธ๋‹ค.

 

์•„๋‹ˆ..??

Github actions ๋กœ ์ถฉ๋ถ„ํžˆ ๋‹ค ๊ฐ€๋Šฅํ•˜๋‹จ๋‹ค.

์—ญ์‹œ๋‚˜ ๋ˆ„๊ตฐ๊ฐ€ ๋งŒ๋“ค์–ด ๋†“์€ Github Actions ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ์žˆ๋‹ค.

์ฐธ ์„ธ์ƒ ํŽธํ•˜๋‹ค..

 

https://github.com/appleboy/ssh-action

 

GitHub - appleboy/ssh-action: GitHub Actions for executing remote ssh commands.

GitHub Actions for executing remote ssh commands. Contribute to appleboy/ssh-action development by creating an account on GitHub.

github.com

์ด apple boy ๋ฅผ ์ด์šฉํ•˜๋ฉด, ์ถฉ๋ถ„ํžˆ ๊ฐ€๋Šฅํ•˜๋‹ค.

๊ตณ์ด ์ตœ์‹  docker image ์ž๋™ ๊ฐ์ง€๋‹ˆ ๋ญ๋‹ˆ, shell ์„ ์งค ํ•„์š”๊ฐ€ ์—†๋‹ค.

 

Github actions ์ž‘์„ฑํ•˜๊ธฐ

ํ•„๋…!!

- AWS EC2 ์ธ์Šคํ„ด์Šค๋Š” ์ด๋ฏธ ๋งŒ๋“ค์–ด์„œ (๋‚˜๋Š” Ubuntu 22.4) ์‹คํ–‰์ค‘์ด๋ผ๊ณ  ๊ฐ€์ •ํ•˜๊ณ  ์ง„ํ–‰ํ•˜๊ฒ ๋‹ค.

- spring boot application ๋„ ์ด๋ฏธ ๋งŒ๋“ค์–ด์กŒ๋‹ค๊ณ  ์ƒ๊ฐํ•˜๋ฉด ๋œ๋‹ค.

- docker hub ์— repository ๋„ ์ด๋ฏธ ๋งŒ๋“ค์—ˆ๋‹ค๊ณ  ์ƒ๊ฐํ•˜๋ฉด ๋œ๋‹ค.

 

name: deploy

on:
  push:
    branches: [ "master" ]

jobs:
  deploy:
    name: spring boot server ci-cd
    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: 'temurin'
        
      - name: Build
        run: ./gradlew build -x test

      - name: Test
        #run: ./gradlew asciidoctor
        run: echo 'empty test'
        
        # ๋„์ปค๋ฅผ ํ—ˆ๋ธŒ์— ๋กœ๊ทธ์ธ ํ•˜๊ธฐ, docker hub username ๊ณผ token ์ด ํ•„์š”ํ•˜๋‹ค.
      - name: Login to Docker Hub
        uses: docker/login-action@v1
        with:
          username: ${{ secrets.DOCKERHUB_USERNAME }}
          password: ${{ secrets.DOCKERHUB_TOKEN }}
          
        # Jib ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์‚ฌ์šฉ, docker file, docker compose ๋ฅผ ์ง์ ‘ ์ž‘์„ฑํ•  ํ•„์š”๊ฐ€ ์—†์ด ์ž๋™์œผ๋กœ ๋งŒ๋“ค์–ด ์ฃผ๊ณ , docker hub ์— push ๊นŒ์ง€ ํ•ด์ค€๋‹ค..
      - name: Jib
        env:
          DOCKERHUB_REPOSITORY_PATH: ${{ secrets.DOCKERHUB_REPOSITORY_PATH }}
          SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
        run: ./gradlew jib -x test
          -Djib.to.image=$DOCKERHUB_REPOSITORY_PATH
          -Djib.to.tags=latest
          -Djib.container.creationTime=USE_CURRENT_TIMESTAMP
          -Djib.container.environment=SLACK_WEB_HOOK_URL=$SLACK_WEBHOOK_URL
          -Djib.container.jvmFlags=-XX:MaxRAMPercentage=30.0,-XX:MinRAMPercentage=30.0,-Duser.timezone=Asia/Seoul,-Dspring.profiles.active=dev
          
        # ์ง€๊ธˆ ์‹คํ–‰์ค‘์ธ github actions ํ™˜๊ฒฝ์˜ ip ๋ฅผ ๋”ฐ์˜จ๋‹ค.
      - name: Get Github action IP
        id: ip
        uses: haythem/public-ip@v1.2              
        
        # ๋”ฐ์˜จ github actions ip ๋ฅผ ๋ฐฐํฌํ•  EC2 ์˜ ๋ณด์•ˆ ๊ทธ๋ฃน์— ์ถ”๊ฐ€ํ•˜๋Š” AWS CLI ์‹คํ–‰.
      - name: Add Github Actions IP to Security group
        env:
          AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
          AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          AWS_DEFAULT_REGION: ${{ secrets.AWS_DEFAULT_REGION }}
        run: |
          aws ec2 authorize-security-group-ingress --group-id ${{ secrets.AWS_Security_Group_ID }} --protocol tcp --port 22 --cidr ${{ steps.ip.outputs.ipv4 }}/32

		# apple boy ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์ด์šฉ, EC2 ์— ์ง์ ‘ ์ ‘์†ํ•ด์„œ, docker hub ์— push ๋œ spring boot image ๋ฅผ pull ๋ฐ›๊ณ  ์ž‘์„ฑ๋œ docker compose ๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ์‹คํ–‰ํ•œ๋‹ค.
      - name: spring boot server deploy
        uses: appleboy/ssh-action@master
        env:
          DOCKERHUB_REPOSITORY_PATH: ${{ secrets.DOCKERHUB_REPOSITORY_PATH }}
        with:
          host: ${{ secrets.REMOTE_IP }}
          username: ${{ secrets.REMOTE_EC2_NAME }}
          key: ${{ secrets.REMOTE_SSH_KEY }}
          script: |
            cd ~/app
            sudo docker-compose down --rmi all
            sudo docker-compose up -d
          
        # docker ์ปจํ…Œ์ด๋„ˆ๊ฐ€ ์ •์ƒ ์‹คํ–‰๋˜๋ฉด, ๋ณด์•ˆ ๊ทธ๋ฃน์— ์ถ”๊ฐ€ํ–ˆ๋˜ github actions ip ๋ฅผ ์‚ญ์ œํ•œ๋‹ค.
      - name: Remove Github Actions IP from security group
        env:
          AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
          AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          AWS_DEFAULT_REGION: ${{ secrets.AWS_DEFAULT_REGION }}
        run: |
          aws ec2 revoke-security-group-ingress --group-id ${{ secrets.AWS_Security_Group_ID }} --protocol tcp --port 22 --cidr ${{ steps.ip.outputs.ipv4 }}/32 > /dev/null
        if: always()

		# ์ด๊ฑด ์ž์œ ์ง€๋งŒ, slack ์•Œ๋ฆผ๋„ ๋ฐฐํฌ ์„ฑ๊ณต ์—ฌ๋ถ€์— ๋”ฐ๋ผ ์˜ค๊ฒŒ ํ•  ์ˆ˜ ์žˆ๋‹ค.
      - name: Slack notification
        uses: 8398a7/action-slack@v3
        with:
          username: github action
          status: ${{ job.status }}
          author_name: Github Action
          fields: repo,message,commit # repo,message,commit,author,action,eventName,ref,workflow,job,took
        env:
          SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
        if: always()

์ด๊ฑธ .github ํด๋” ์•ˆ์— ๋„ฃ์–ด์ฃผ์ž.

์•ˆ์— ${{secrets.~~~}} ๋กœ ๋˜์–ด ์žˆ๋Š” ๊ฑด github secret ํ™˜๊ฒฝ ๋ณ€์ˆ˜์— ๋„ฃ์–ด์ฃผ๋ฉด ๋œ๋‹ค.

 

  • AWS_ACCESS_KEY :  AWS iam ์‚ฌ์šฉ์ž access key
  • AWS_SECRET_ACCESS_KEY : iam ์‚ฌ์šฉ์ž secret key
  • REMOTE_IP : EC2 ํผ๋ธ”๋ฆญ ip
  • REMOTE_EC2_NAME : ๋‚˜๋Š” ubuntu ์ด๋ฏ€๋กœ, ubuntu ๋ผ ์ ์œผ๋ฉด ๋จ. (ssh ์ ‘์† ํ• ๋•Œ, ~~@ํผ๋ธ”๋ฆญip ์ด๋ ‡๊ฒŒ ์ ์„ ๋•Œ, ์ด ๋ฌผ๊ฒฐ ์ด๋ฆ„์ž„.)
  • REMOTE_SSH_KEY : EC2 ์ƒ์„ฑํ•  ๋•Œ, ๋ณดํ†ต pem ํ‚ค ๋ฐœ๊ธ‰ ๋ฐ›๋Š” ๊ทธ๊ฑฐ์ž„.
  • ๋‚˜๋จธ์ง€ snake ์ผ€์ด์Šค ์•„๋‹Œ ๋ณ€์ˆ˜๋“ค์€, github actions ์—์„œ ์ œ๊ณตํ•˜๋Š” ๋ณ€์ˆ˜๋“ค์ด๋‹ค.

 

EC2 ์—์„œ ํ•ด์•ผํ•  ๊ฒƒ.

์ผ๋‹จ EC2 ์— ์ ‘์†ํ•ด๋ณด์ž์ž‰.

 

๊ทธ๋ฆฌ๊ณ , app ์ด๋ผ๋Š” ๋””๋ ‰ํ„ฐ๋ฆฌ๋ฅผ ๋งŒ๋“ค์–ด๋ผ.

ํ•„์š”ํ•˜๋ฉด ์•„๋ž˜๋Œ€๋กœ, log ๋””๋ ‰ํ„ฐ๋ฆฌ๋„ ๋งŒ๋“ค์–ด๋ผ.

 

๊ทธ๋ฆฌ๊ณ  docker-compose.yml ์„ ์ƒ์„ฑํ•˜์ž.

### docker-compose.yml

version: "3.7"
services:
  attieadconfig:
    container_name: springbootapp
    image: {์ด๋ฏธ์ง€ ๊ฒฝ๋กœ ์ ๊ธฐ}:latest
    ports:
      - 80:8080
    deploy:
      resources:
        limits:
          cpus: '0.30'
          memory: 700m
    logging:
      driver: "json-file"
      options:
        max-file: "3"
        max-size: "10m"
    volumes:
      - ~/app/logs:/logs

 

๊ทธ๋ฆฌ๊ณ  ์‹คํ–‰

github actions ๊ฐ€ ์‹คํ–‰๋˜๊ณ , 

๋ฐฐํฌ๊ฐ€ ์ƒ๊ณตํ–ˆ๋‹ค๋ฉด ์ž๋™ ๋ฐฐํฌ๊ฐ€ ์ข…๋ฃŒ๋˜์—ˆ๋‹ค.

 

๋ณดํ†ต ์—๋Ÿฌ๋Š” apple boy ์Šคํ…์—์„œ ํ„ฐ์งˆ ๊ฒƒ์ด๋‹ค.

๊ทธ๋•Œ ์œ„์— ์˜ฌ๋ ค๋‘์—ˆ๋˜, apple boy github README ๋ฅผ ์ž˜ ์ฝ์–ด๋ณด๋ฉด, ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์ด ์ƒ์„ธํžˆ ์ ํ˜€์žˆ์„ ๊ฒƒ์ด๋‹ค.

 

๋‚˜์˜ ๊ฒฝ์šฐ๋Š”, authorized keys ์—์„œ ๊ถŒํ•œ์„ ์ฃผ์–ด ํ•ด๊ฒฐํ–ˆ๋˜ ๊ธฐ์–ต์ด ์žˆ๋‹ค.

 

๊ทธ๋Ÿผ ๊ตฌ์ถ•๋œ ์ž๋™ ๋ฐฐํฌ๊ฐ€ ๋“ ๋“ ํžˆ ๋’ท๋ฐ›์นจ ๋˜์—ˆ์œผ๋‹ˆ,
์ฆ๊ฑฐ์šด ๊ฐœ๋ฐœ์„ ์ง„ํ–‰ํ•ด๋ณด์ž~~!

๋ฐ˜์‘ํ˜•