[CI/CD] Docker와 CI/CD 파이프라인 구축 - 실습편

gogori6565·2024년 7월 16일
0

Spring

목록 보기
6/7

🧷 CI/CD 란 무엇인가? - 이론편

개발 환경

AWS EC2 Free tier - Operating System : Ubuntu 24.04 Server
Docker - Docker Hub
Spring Boot 3.3.1 - Gradle, JDK17
GitHub - Action


1. GitHub Actions Repository Secret 설정

  1. Github Repository -> Settings -> Secrets and Variables -> Actions
  2. 아래 3가지 secrets 추가
Name : DOCKERHUB_USERNAME | Your DockerHub Username
Name : DOCKERHUB_PASSWORD | Your DockerHub Password
Name : APPLICATION_YML | Your SpringBoot Project application.yml Content
📌 Secret 설정을 왜 하는가?

환경변수 관리 문제
github actions를 사용할 때 한가지 걸림돌이 있는데, 바로 환경변수 문제다. api키나, 각종 password 등의 민감한 데이터들은 보안을 이유로 github에 직접 업로드하지 않는 것이 일반적이다. 때문에 이런 데이터들은 .env와 같이 환경변수 파일을 만들고, 이 환경변수 파일을 .gitignore에 등록하여 github에 올라가지 못하도록 막게 된다.

github actions는 workflow를 가상머신 위에서 테스트하고 빌드하기 때문에 환경변수가 없는 상태에서는 제대로된 테스트와 빌드가 이루어질 수 없다. 하지만 그렇다고 .env파일을 그대로 github에 업로드하기에는 굳이 .env파일을 분리한 목적 자체가 불문명해진다. 이런 문제를 해결하기 위해 github은 secrets라는 기능을 제공하고 있다.

Secrets
api키나 password와 같이 숨기고자 하는 데이터를 관리해준다.
사용 방법은 github에서 secrets에 원하는 값을 입력하면, actions의 workflow가 실행될 때 이 secrets에 접근이 가능해진다. 그러면 이때 동적으로 secrets의 데이터를 취합해 .env파일을 새로 생성하면 되는 것이다.

➕ 추후 CI/CD 를 설정할 때 ${{ secrets.APPLICATION_YML }}형식의 코드로 Secrets에 등록한 데이터를 불러온다.


2. Spring Boot 프로젝트에 Dokerfile 생성

# Dockerfile

# jdk17 Image Start
FROM openjdk:17

ARG JAR_FILE=build/libs/book-0.0.1-SNAPSHOT.jar
ADD ${JAR_FILE} book_Backend.jar
ENTRYPOINT ["java","-jar","book_Backend.jar"]
  • FROM baseImage : Docker 이미지 빌드 시 사용할 기본 이미지 지정
  • ARG(Build Argument) : JAR_FILE 변수를 정의해, 빌드 시 사용할 JAR 파일의 경로를 지정
  • ADD(Add JAR File) : 지정된 JAR 파일을 이미지에 추가
  • ENTRYPOINT : 컨테이너가 시작될 때 실행할 명령을 지정

이제 이 Dockerfile을 사용하여 Docker 이미지를 빌드하고 실행하면, 컨테이너 내에서 Java 17 환경에서 Spring Boot 애플리케이션이 실행된다!

📌 자세한 설명
  1. FROM baseImage : Docker 이미지 빌드 시 사용할 기본 이미지 지정

    • Docker base image = Docker 이미지를 빌드할 때 사용하는 기본 이미지.
    • 모든 Docker 이미지는 기본 이미지 위에 추가적인 Layer를 쌓아 올려서 만들어진다. 이때, 기본이 되는 이미지를 Docker base image라고 한다.
  2. ARG(Build Argument) : JAR_FILE 변수를 정의해, 빌드 시 사용할 JAR 파일의 경로(build/libs/book-0.0.1-SNAPSHOT.jar)를 지정

  3. ADD(Add JAR File) : 지정된 JAR 파일을 이미지에 추가

    • ${JAR_FILE} : ARG로 정의한 변수를 사용해 JAR 파일의 경로를 참조한다.
    • book_Backend.jar : 이미지 내부에 추가될 파일의 이름을 지정한다. 즉, build/libs/book-0.0.1-SNAPSHOT.jar 파일을 컨테이너 내부의 book_Backend.jar로 추가한다.
  4. ENTRYPOINT : 컨테이너가 시작될 때 실행할 명령을 지정

    • ["java","-jar","book_Backend.jar"] : 이 명령어는 java -jar book_Backend.jar을 실행한다. 즉, 추가된 JAR 파일을 실행하여 Spring Boot 애플리케이션을 시작한다.

💡Tip. Dockerfile을 작성할 때는 Layer 형태로 작성해주는 것이 좋다.

  • 제일 빈번히 변경되는 파일일수록 제일 마지막에 작성해야 함
    : 제일 빈번히 변경되는 파일을 제일 나중에 적으면 Layer에서 제일 위쪽에 배치되기 때문에, 이미지를 만들고 나중에 소스파일이 변경되어서 새로운 이미지를 만들어야 할 때 변경된 최상단의 Layer만 업데이트 해주고 나머지 Layer는 다시 만들지 않아도 된다!
    그래서 이미지를 다시 만들 때, 변경되지 않은 Layer까지는 재사용(캐시된 걸 사용), 변경된 Layer부터 그 위의 Layer까지는 다시 빌드를 하기 때문에 이미지를 만드는 시간을 단축할 수 있고 효율성도 높아진다.

3. Github Actions - CI

  1. Github Repository -> Actions -> Java with Gradle -> Configure
name: Java CI with Gradle

on:
  push:
    branches: [ "develop" ]

permissions:
  contents: read

jobs:
  # Spring Boot 애플리케이션을 빌드하여 도커허브에 푸시하는 과정
  build-docker-image:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v3
    # 1. Java 17 세팅
    - name: Set up JDK 17
      uses: actions/setup-java@v3
      with:
        java-version: '17'
        distribution: 'temurin'

    # 2. application.yml 파일 생성
    - name: Create application.yml
      run: |
        mkdir -p src/main/resources
        echo "${{ secrets.APPLICATION_YML }}" > src/main/resources/application.yml

    # 3. Spring Boot 애플리케이션 빌드
    - name: Build with Gradle
      uses: gradle/gradle-build-action@67421db6bd0bf253fb4bd25b31ebb98943c375e1
      with:
        arguments: clean bootJar

    # 4. Docker 이미지 빌드
    - name: docker image build
      run: docker build -t ${{ secrets.DOCKERHUB_USERNAME }}/book_cicd_action .

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

    # 6. Docker Hub 이미지 푸시
    - name: docker Hub push
      run: docker push ${{ secrets.DOCKERHUB_USERNAME }}/book_cicd_action
  • on : 트리거 이벤트를 정의

    • push: branches: [ "develop" ] : 'develop' 브랜치에 push 이벤트가 발생할 때 workflow 실행
  • permissions : workflow에서 사용할 권한을 설정

    • contents: read : workflow는 저장소의 콘텐츠를 읽을 수 있는 권한을 가짐
  • jobs : 작업(job)을 정의 (여러 개 정의 가능)

    • runs-on: ubuntu-latest : 최신 버전의 Ubuntu를 사용하는 가상 환경에서 실행
    • steps : 작업을 수행하기 위한 단계(step)들을 정의

4. EC2 Ubuntu 서버에 Docker 설치

#1. 프로그램 설치 전 Ubuntu 시스템 패키지 업데이트
sudo apt-get update

#2. 필요한 패키지 설치
sudo apt-get install apt-transport-https ca-certificates curl gnupg-agent software-properties-common

#3. Docker의 공식 GPG키 추가
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -

#4. Docker의 공식 apt 저장소 추가
sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"

#5. 시스템 패키지 업데이트
sudo apt-get update

#6. Docker 설치
sudo apt-get install docker-ce docker-ce-cli containerd.io

#7. Docker 설치 확인
sudo systemctl status docker

위 사진과 같이 Active: active (running) 이 뜨면 Docker 설치 성공!

5. GitHub Actions Runner (self-hosted runner) 설정

  1. Github Repository -> Settings -> Code and automation -> Actions -> Runners -> New self-hosted runner -> New self-hosted runner

  2. Runner Image : Linux (Ubuntu를 사용하기 때문에) (+1서버에 N개 runner를 설치해도 잘 작동한다)

  3. 아래 Download / Configure 에 나와있는 코드를 본인의 운영 환경(EC2 서버)에 접속해서 순차적으로 실행시키면 된다.

  4. 마지막으로 아래 두 명령어를 실행한다.

sudo ./svc.sh install
sudo ./svc.sh start
📌 자세한 설명

GitHub Actions Runner : GitHub Actions workflow으로부터 job을 실행시켜주는 어플리케이션.
runner가 서버에서 대기 상태로 있다가 선언된 트리거가 작동되면 workflow를 실행한다.

Github Actions에는 크게 두 종류의 runner가 있는데 그 중 self-hosted runner는 사용자의 PC or 서버에 runner를 위치시켜 workflow를 실행하는 개념이다.


6. GitHub Actions - CD

  1. .github/workflows/gradle.yml 파일에 아래 코드를 입력한다.
# 위 과정에서 푸시한 이미지를 ec2에서 풀받아서 실행시키는 과정 
  run-docker-image-on-ec2:
    # build-docker-image (위)과정이 완료되어야 실행됩니다.
    needs: build-docker-image
    runs-on: self-hosted

    steps:
      # 1. 최신 이미지를 풀받습니다
      - name: docker pull
        run: sudo docker pull ${{ secrets.DOCKERHUB_USERNAME }}/book_cicd_action
      
      # 2. 기존의 컨테이너를 중지시킵니다
      - name: docker stop container
        run: sudo docker stop $(sudo docker ps -q) 2>/dev/null || true

      # 3. 최신 이미지를 컨테이너화하여 실행시킵니다
      - name: docker run new container
        run: sudo docker run --name github-actions-demo --rm -d -p 8080:8080 ${{ secrets.DOCKERHUB_USERNAME }}/book_cicd_action

      # 4. 미사용 이미지를 정리합니다
      - name: delete old docker image
        run: sudo docker system prune -f
초록색이 뜨면 성공!
profile
p(´∇`)q

0개의 댓글