CI / CD - 1

yanju·2023년 1월 22일
0

전체 CI CD 구조

우리 프로젝트의 현재(3주차) CI / CD 구조는 다음과 같다.

Docker, Docker Compose, Github Actions, EC2를 이용해 CI CD를 구성했다.

Docker Compose

여러 개의 도커 컨테이너를 정의하여 한번에 많은 컨테이너를 실행하고 관리할 수 있는 툴이다.

도커 컨테이너로 시스템을 구축하면 하나 이상의 컨테이너가 서로 통신할 때 의존 관계가 생긴다.

각 컨테이너를 따로 실행하여 관리하면 힘들다.

docker-compose.yml 파일에 여러 컨테이너에 대한 옵션을 작성하면, docker-compose up 이라는 명령어로 서비스를 시작할 수 있다.

CI Pipeline

CI 과정은 다음과 같다.

  1. Gradle Build
  2. Docker Image Build
  3. Docker Image Push

CI는 develop 브랜치를 향해 Pull Request를 작성하면 실행한다.

다음은 CI 과정에 대한 상세한 이미지다.

달라진 점은 다음과 같다.

  • MySQL 접속 정보, JWT 인증 정보는 github secrets로 관리를 하였다.
  • 테스트 코드에서 redis 접속이 필요해서 redis container를 띄우는 작업을 추가했다.

CI 코드는 다음과 같다.

name: Java CI with Gradle And Docker Image Deploy

on:
  pull_request:
    branches: [ "develop" ]

permissions:
  contents: read

jobs:
  build:
    name: Gradle Build
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Set up JDK 17
        uses: actions/setup-java@v3
        with:
          java-version: '17'
          distribution: 'temurin'

      # jwt 정보 로딩
      - name: Copy Secret
        env:
          OCCUPY_SECRET: ${{ secrets.OCCUPY_SECRET }}
          OCCUPY_SECRET_DIR: src/main/resources
          OCCUPY_SECRET_DIR_FILE_NAME: application-config.properties
        run: echo $OCCUPY_SECRET | base64 --decode > $OCCUPY_SECRET_DIR/$OCCUPY_SECRET_DIR_FILE_NAME

      # dev 정보 로딩
      - name: Copy Secret1
        env:
          OCCUPY_SECRET1: ${{ secrets.OCCUPY_SECRET1 }}
          OCCUPY_SECRET1_DIR: src/main/resources
          OCCUPY_SECRET1_DIR_FILE_NAME: application-dev.properties
        run: echo $OCCUPY_SECRET1 | base64 --decode > $OCCUPY_SECRET1_DIR/$OCCUPY_SECRET1_DIR_FILE_NAME

      # gradle 캐싱
      - 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-

      # gradle 빌드 권한 설정
      - name: Grant execute permission for gradlew
        run: chmod +x gradlew

      # gradle 빌드
      - name: Build with Gradle
        uses: gradle/gradle-build-action@67421db6bd0bf253fb4bd25b31ebb98943c375e1
        with:
          arguments: build

      # 임시 저장
      - name: Temporarily save build artifact
        uses: actions/upload-artifact@v2
        with:
          name: build-artifact
          path: build
          retention-days: 1

  build-docker-image:
    needs: build
    name: Deploy Docker Image
    runs-on: ubuntu-latest
    steps:
      # 임시 저장 결과 로딩
      - uses: actions/checkout@v2
      - name: Retrieve built
        uses: actions/download-artifact@v2
        with:
          name: build-artifact
          path: build

      # 도커 허브 로그인
      - name: Docker Hub Sign-in
        run: docker login -u ${{ secrets.DOCKERHUB_USERNAME }} -p ${{ secrets.DOCKERHUB_PASSWORD }}

      # 도커 이미지 빌드
      - name: Building Docker Image
        run: docker build --build-arg JAR_FILE=build/libs/\*.jar -t ${{ secrets.DOCKERHUB_USERNAME }}/hanbange .

      # 도커 이미지 푸시
      - name: Publish Docker Image
        run: docker push ${{ secrets.DOCKERHUB_USERNAME  }}/hanbange

CD Pipeline

CD 과정은 다음과 같다.

  1. ec2로 docker-compose 파일 배포
  2. docker-compose 파일 실행

CD는 PR을 develop에 merge하면 실행한다.

다음은 CD 과정에 대한 상세 이미지다.

docker-compose.yml 파일은 다음과 같다.

CD 작업에서는 새로운 스프링 이미지를 받아와서 실행한다.

version: "3.9"

services:
  spring:
    container_name: hanbange_app
    image: yanjuicy/hanbange:latest
    ports:
      - "80:8080"

  redis_container:
    container_name: redis_boot
    image: redis:latest
    ports:
      - 6379:6379
    labels:
      - "name=redis"
      - "mode=standalone"
    restart: always
    command: redis-server

CD 코드는 다음과 같다.

0개의 댓글