Docker, DockerHub, Github-Actions 로 편하게 CI/CD 구성하기

Kim Dong Kyun·2024년 9월 23일
0
post-thumbnail

개요

PR-Deliver 사이드 프로젝트를 하면서, 무료이고, 간단하게 인프라를 구성하고 싶었다. 특히 CI/CD 를 좀 편하게 하고 싶어서 (Code-deploy 등 다른거 없이 순수 GIthub-Actions로만) 이 방식으로 진행 해 보았다.

장점으로는 빌드, 컨테이너 이미지 생성 등 프리티어 환경에서는 다소 무거울 수 있는(사실 그렇게 무겁지도 않지만, t2-micro 라는 귀여운 사이즈 때문에...무겁다) 작업을 Github-Actions 로 해결해서, EC2 메모리가 터져버리는 상황을 막을 수 있을 것이다. (메모리 가상화 등도 필요가 없다)


1. Dockerfile 작성하기

FROM openjdk:17
# JDK17 사용
ARG JAR_FILE_PATH=./build/libs/*.jar

# gradle build 후 생성되는 jar 파일
COPY ${JAR_FILE_PATH} app.jar
# jar 파일을 app.jar 파일로 카피

ENV JASYPT_ENCRYPTOR_PASSWORD="" 
#JASYPT 패스워드를 명시적으로 "" 선언함으로써, 변수가 주입되지 않으면 빈 문자열이 주입

ENTRYPOINT ["java", "-Djasypt.encryptor.password=${JASYPT_ENCRYPTOR_PASSWORD}","-jar", "/app.jar"]
# "-Djasypt.encryptor.password=${JASYPT_ENCRYPTOR_PASSWORD}" Jasypt 패스워드 주입 (Github Actions)
  • 나의 경우엔 Jasypt 를 통해 application.yml 파일을 암호화하여 관리하고 있기 때문에, Docker run 시에 Jasypt 비밀번호를 환경변수로 주입하는 형식으로 관리했다.

  • 비밀번호는 Github 시크릿으로 관리되며, Github-Actions 워크플로우로 트리거 되어 변수 주입된다.


2. Github Repository Secret 설정하기

  • 레포지토리의 Settings -> Scretes and variables -> Actions 로 진입한다.
  • 이후, New Repository Secret 버튼을 클릭해서 깃헙 액션 트리거시 환경변수로 사용할 비밀 값들을 입력해준다.
  • 꼭 필요한것은 도커허브 유저네임, 패스워드 그리고 EC2 HOST 도메인(혹은 IP), EC2 서버에서 발급한 SSH 프라이빗 키 이다.
  • 기본적으로 EC2에 SSH로 접속해서, Docker run 시키는 구조이다.
  • SSH 접속 관련 문제가 있다면, 이전 글 을 참고해주시길.

3. gradle.yml 작성하기

name: Java CI with Gradle and Docker

on:
  push:
    branches:
      - main

jobs:
  build-and-deploy:
    runs-on: ubuntu-latest

    steps:
      # 1. GitHub 저장소에서 코드 체크아웃
      - name: Checkout repository
        uses: actions/checkout@v4

      # 2. JDK 17 설치
      - name: Set up JDK 17
        uses: actions/setup-java@v4
        with:
          java-version: '17'
          distribution: 'temurin'

      # 3. Gradle 빌드
      - name: Build with Gradle
        run: ./gradlew build

      # 4. Docker 이미지 빌드
      - name: Build Docker image
        run: docker build -f Dockerfile -t ${{ secrets.DOCKERHUB_USERNAME }}/pr-deliver .

      # 5. Docker Hub 로그인
      - name: DockerHub login
        uses: docker/login-action@v2
        with:
          username: ${{ secrets.DOCKERHUB_USERNAME }}
          password: ${{ secrets.DOCKERHUB_PASSWORD }}

      # 6. Docker Hub에 이미지 푸시
      - name: Push Docker image
        run: docker push ${{ secrets.DOCKERHUB_USERNAME }}/pr-deliver

      # 7. SSH를 통해 EC2 인스턴스에 접속하여 애플리케이션 배포
      - name: Deploy to EC2 via SSH
        uses: appleboy/ssh-action@master
        with:
          host: ${{ secrets.EC2_HOST }}
          username: ubuntu
          key: ${{ secrets.SSH_PRIVATE_KEY }}
          port: 22
          script: |
            # Docker Hub에서 최신 이미지 풀
            docker pull ${{ secrets.DOCKERHUB_USERNAME }}/pr-deliver
            
            # 기존 컨테이너가 실행 중이면 중지
            docker stop pr-deliver || true
            
            # 기존 컨테이너 삭제
            docker rm pr-deliver || true
            
            # 새로운 컨테이너 실행
            docker run --name pr-deliver --rm -d -p 8080:8080 \
              -e JASYPT_ENCRYPTOR_PASSWORD=${{ secrets.JASYPT_PASSWORD }} \
              ${{ secrets.DOCKERHUB_USERNAME }}/pr-deliver

시퀀스는 아래와 같다

  1. 깃 체크아웃 (나의 경우 main)
  2. JDK 17 설치
  3. 그래들 빌드 (이 과정에서./build/libs/"프로젝트이름".jar 경로에 jar 파일이 생성되며, 도커파일에서 이 파일을 참조한다)
  4. 도커파일을 기반으로 Docker Image 를 만들어준다.
  5. 만들어진 이미지를 도커허브에 푸시한다 (이 과정에서 로그인이 필요하다)

위까지가 CI 과정이며,

  1. EC2에 접속하고
  2. 도커허브에 올려둔 이미지를 풀받고,
  3. 기존 컨테이너가 실행중이면 중지하고
  4. 삭제한다.
  5. 그리고 다시 컨테이너를 실행한다. 이 과정에서 환경변수로 JASYPT_ENCRYTOR_PASSSWORD 를 주입하여 사용한다

잘 배포되는 모습!

--

TODO LIST

  1. HTTPS 처리
  2. 무중단 배포 (nGinx 블루그린)

0개의 댓글