본문 바로가기

CICD

[CI/CD] Github Actions + AWS EC2 + Docker 파이프라인 구축

🍪파이프라인 구축 왜 해야 해?

처음에는 직접 EC2에 접속해서 git pull하고 JAR파일을 직접 실행 하다가 코드가 수정 될 때 마다 계속 접속해서 명령어 쳐 주는게 귀찮아서, 쉘 스크립트를 도입해서 반복 작업을 줄이다가 이것도 귀찮아서 git에 push만 하면 자동으로 배포 되게 하기 위해 CI/CD 파이프라인을 구축해서 완전 자동화를 구현 해 볼려고 해 

🤖CI/CD 란?

CI는 Continuous Integration 지속적 통합으로 개발자들이 코드를 중앙 저장소에 통합 문제를 최소화하고 코드 변경이 일어날 때 마다 자동으로 빌드 및 테스트가 실행되어 문제가 있는지 즉시 확인할 수 있다.

 

CD는 Continuous Deployment 지속적 배포로 CI를 통과한 이후 자동으로 운영 서버에 배포 하는 파이프라인 구축을 목적으로 한다.

🐻Github Actions 선택

GitHub Actions는 GitHub 내에서 모든 빌드, 테스트, 배포 작업을 자동화할 수 있고 GitHub 레포지토리와 자연스럽게 통합되어 있어 다른 도구 없이 바로 CI/CD 파이프라인을 구축 할 수 있으며 GitHub Secrets을 활용해 환경변수를 안전하게 관리 할 수 있다는 장점이 있어 GitHub Actions을 선택했어

😱파이프라인 과정

  1. 개인 브랜치에서 코드 수정
  2. main브랜치로 PR & Merge
  3. Github Actions에서 코드 문제 검사 후 빌드, Docker Image 빌드
  4. Docker 로그인 후 이미지 Docker Hub에 Push  
  5. SSH로 EC2 인스턴스 접속 후 Docker Hub에서 Pull받아 컨테이너 실행

🙊DockerFile 준비

ARG 를 사용하는 이유는 GitHub Actions에서 빌드할 때 환경 변수가 없으면 에러가 나기 때문에 ARG로 환경 변수를 설정하고 GitHub Actions에서 빌드할 때 --build-arg로 값을 주입해줘야 해

FROM openjdk:17-jdk-slim

WORKDIR /app

ARG DB_PASSWORD
ARG DB_URL
ARG DB_USERNAME

ARG JAR_FILE=build/libs/dev-0.0.1-SNAPSHOT.jar

COPY ${JAR_FILE} dev-0.0.1-SNAPSHOT.jar

ENTRYPOINT ["java", "-jar", "dev-0.0.1-SNAPSHOT.jar"]

🎃GitHub Actions .yml파일 작성

GitHub Actions 파일 작성 하는 거랑 환경변수는 밑에 내가 따로 "상세하게 작성한 블로그 확인 해 줘"

 

GitHub Actions

🧐 Github Action란? GitHub Actions은 GitHub에서 제공하는 빌드, 테스트 및 배포 파이프라인을 자동화할 수 있는 CI/CD(연속 통합 및 지속적인 업데이트) 플랫폼입니다.  🥺 CI/CD 란?반복적인 일 들을 처

imdo714.tistory.com

 

name: Java CI with Gradle

on:
  push:
    branches: [ "V1" ]
  pull_request:
    branches: [ "V1" ]

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
    # 1. 코드 체크아웃
    - name: Check out code
      uses: actions/checkout@v4

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

    # 3. 현재 작업 디렉토리 확인
    - name: Print working directory
      run: pwd

    # 4. gradlew 파일 확인
    - name: List files in the directory
      run: ls -la

    # 5. Gradle 캐시 설정
    - name: Cache Gradle packages
      uses: actions/cache@v3
      with:
        path: ~/.gradle/caches
        key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
        restore-keys: |
          ${{ runner.os }}-gradle-

    # 6. Gradle Wrapper 실행 권한 추가
    - name: Set executable permission for gradlew
      run: chmod +x ./gradlew

    # 7. Gradle 빌드 및 테스트 실행
    - name: Build with Gradle
      run: ./gradlew build -x test --no-daemon
      
    # 8. Docker 이미지 빌드
    - name: docker image build
      run: docker build -t ${{ secrets.DOCKERHUB_USERNAME }}/test-cicd .

    - name: docker image build
      run: |
        docker build \
        --build-arg DB_PASSWORD=${{ secrets.DB_PASSWORD }} \
        --build-arg DB_URL=${{ secrets.DB_URL }} \
        --build-arg DB_USERNAME=${{ secrets.DB_USERNAME }} \
        -t ${{ secrets.DOCKERHUB_USERNAME }}/test-cicd .

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

    # 10. Docker Hub 이미지 푸시
    - name: docker Hub push
      run: docker push ${{ secrets.DOCKERHUB_USERNAME }}/test-cicd

🐯EC2 추가 부분

GitHub Actions에서 Docker Hub에 이미지를 푸시한 후, SSH를 통해 EC2에 접속하여 컨테이너를 배포하는 스크립트를 실행하는 부분이다. 스크립트 부분을 보면 SSH로 EC2 접속 후 Docker Hub에서 이미지를  Pull받고 기존 컨테이너 멈추고 삭제 후 8080포트로 재 실행하는 코드야

  1. EC2_HOST 는 EC2 퍼블릭 IP이다.
  2. EC2_USER 는 EC2 접속할 때 사용하는 사용자 이름이야 나는 Ubuntu를 사용해서 ubuntu로 설정했어
  3. EC2_SSH_KEY 는 EC2를 생성할 때 .pem 형식의 키 페어를 만들었는 그 키 값이야
# 11. EC2 자동 배포 명령어
- name: SSH to EC2 and deploy
  uses: appleboy/ssh-action@master
  with:
    host: ${{ secrets.EC2_HOST }}
    username: ${{ secrets.EC2_USER }}
    key: ${{ secrets.EC2_SSH_KEY }}
    script: |
      docker pull ${{ secrets.DOCKERHUB_USERNAME }}/test-cicd
      docker stop myapp || true
      docker rm myapp || true
      docker run -d --name myapp -p 8080:8080 ${{ secrets.DOCKERHUB_USERNAME }}/test-cicd

💣트러블 슈팅

나는 계속 EC2_SSH_KEY 를 입력 했는데 ssh.ParsePrivateKey: ssh: no key found라는 에러가 떴다. 첫 번째 이유는 앞에 띄어쓰기 하나가 있었는데 그거 때문에 에러가 났다. 두 번째는 "인코딩 되어있는 데이터만 넣으면 되는 줄 알고" 위아래 값들을 안 넣었었다.

-----BEGIN RSA PRIVATE KEY-----
 (Base64 인코딩된 키 데이터)
-----END RSA PRIVATE KEY-----

👏결과

이제 Git에 Push만 하면 GitHub Actions 가 빌드 테스트 모두 통과하고 EC2에 접속해 자동으로 컨테이너 실행까지 해 주어 아주 편하게 자동 배포까지 해 주게 되었다.


 

'CICD' 카테고리의 다른 글

GitHub Actions  (0) 2024.11.16
Docker & Docker Hub  (1) 2024.11.16