개발일기

Spring Github Action CI/CD docker-compose 자동화 배포 구축-완- 본문

photocard backend server 개발일기

Spring Github Action CI/CD docker-compose 자동화 배포 구축-완-

한둥둥 2024. 7. 1. 15:43

본격적인 Github Action CI/CD세팅 전에 CI/CD란 무엇인지 꼭 해야하는지 알아보자!

 

우선적으로, CI/CD란?

CI/CD는 Continuous Integration(CI)Continuous Delivery/Delpoyment(CD) 통합해서 부르는 용어이다. 

CI/CD는 개발 과정에서 필요한 빌드, 테스트, 배포 등의 과정을 자동화 해준다. CI/CD 자동화를 통해서 개발자들은 코드를 자동으로 테스트하고 배포할 수 있으며, 효율적인 작업이 가능해진다.

 

왜 CI/CD를 해야하는가?  

우선적으로, 위에 내용만 보았을 때, CI/CD는 무조건 해야한다고 판단한다. 물론 수동으로 서버를 배포하는 방법도 있겠지만, 앞으로 서비스를 계속해서 운영한다면 코드를 수정하고 이를 계속해서 배포해야하는데, ci/cd를 반드시 해야한다고 생각이 들었다. 

번외로 매번 EC2 서버에 코드 수정 후 들어가서 배포하는 방법이 진짜 많은 시간이 생각보다 소요가 되었고 때문에 CI/CD를 구축하는 결정을 하게 되었다. 

 

Jenkins VS Github Action ?

둘 중 어떤 것을 써야할 지 고민하게 되었고 각각의 장단점을 비교해보았다. 

 

Jenkins 특징들

1. 관련 문서나 자료들이 정말 많았습니다. 

2. 환경 호환성을 위해 Docker image에서 동작시켜야 한다. 

3. 다양한 플러그인이 있어서 다양한 설정이 가능함. 

4. Github 이벤트에 준수하지 않는 빌드 중심으로 한다. 

5. CI/CD 구성하는게 어려운 편

 

GithubAction들

1. 관련 문서가 상대적으로, Jenkins에 비하면 많이 없는 편

2. 손쉽게 Github Action을 통해서 CI/CD를 구성할 수 있다.

 

 

둘 중 어떤걸 사용할지 고민하다가 GithubAction으로 결정하였다. 

why?

저는 하나의 서버를 사용할 것이며 이를 통해서 Github Action을 작성할 때, 한 대의 서버에 대해서만 도커를 사용하여 자동화 배포를 진행하며 또한 Github에 좀 더 잘 동작하며 한 곳에서 관리한다는 느낌을 받았기에 GithubAction을 사용하였다. 

추가적인 이유에 자동화 배포를 할 때, 많은 플러그인과 기능을 사용하지 않기도 하며 이를 어느정도 GithubAction에서 커버 할 수 있지 않을까라는 생각으로 GithubAction 으로 진행

 

Dockerfile

services: #이 항목 밑에 실행하려는 컨테이너들을 정의

  server:
    container_name: back
    image: hanseu9839/back:latest
    expose:
      - 8080
    ports:
      - 8080:8080

  front:
    container_name: front
    image: hanseu9839/front:latest
    expose:
      - 3000

  nginx:
    container_name: nginx
    image: nginx:latest
    restart: unless-stopped
    volumes:
      - ./conf/nginx.conf:/etc/nginx/nginx.conf
      - ./data/certbot/conf:/etc/letsencrypt
      - ./data/certbot/www:/var/www/certbot
    ports:
      - 80:80
      - 443:443
    depends_on:
      - server
      - front

  certbot:
    image: certbot/certbot
    restart: unless-stopped
    volumes:
      - ./data/certbot/conf:/etc/letsencrypt
      - ./data/certbot/www:/var/www/certbot
    entrypoint: "/bin/sh -c 'trap exit TERM; while :; do certbot renew; sleep 12h & wait $${!}; done;'"

  mysql: # 서비스 명
    image: mysql/mysql-server:8.0.23 #사용할 이미지
    container_name: capo # 컨테이너 이름 설정
    ports :
      - "3306:3306" # 접근 포트 설정 ( 컨테이너 외부:컨테이너 내부)
    restart: always
    environment: # -e 옵션
      MYSQL_DATABASE: # 데이터 베이스 이름
      MYSQL_ROOT_HOST:  # MYSQL HOST
      MYSQL_ROOT_PASSWORD:  # MYSQL 패스워드 설정 옵션
      TZ: "Asia/Seoul"


github action 파일

name: Java CI/CD pipeline

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

permissions:
  contents: read

jobs:
  build:
    runs-on: ubuntu-latest
    
    steps:    
    - uses: actions/checkout@v4
    - name: Set up JDK 17
      uses: actions/setup-java@v4
      with:
        java-version: '17'
        distribution: 'temurin'
        java-package: 'jdk'  # JDK 패키지 설치
    - name: make application-dev.yml
      run: |
        cd ./src/main/resources
        touch ./application-dev.yml
        echo "${{ secrets.APPLICATION_DEV }}" > ./application-dev.yml
        
    - name: Grant execute permission for gradlew
      run: chmod +x gradlew
      
    - name: Build with Gradle # Gradle 설정
      run: ./gradlew build
      
  # Docker 이미지 빌드 
    - name: Docker build & Push
      run: |
        docker login -u ${{ secrets.DOCKERHUB_USERNAME }} -p ${{ secrets.DOCKERHUB_PASSWORD }}
        docker build -t ${{ secrets.DOCKERHUB_USERNAME }}/back .
        docker push ${{ secrets.DOCKERHUB_USERNAME }}/back
  
   # AWS 자격증명 부분 추가
    - name: Configure AWS credentials
      uses: aws-actions/configure-aws-credentials@v1
      with:
        aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
        aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
        aws-region: ap-northeast-2
        
    - name: Deploy to server
      uses: appleboy/ssh-action@master
      id: deploy
      env:
        APP: "back"
        COMPOSE: "/home/capo_project/docker-compose.yml"
      with:
        host: ${{ secrets.EC2_HOST }} # EC2_HOST 키
        username: ubuntu
        key: ${{ secrets.EC2_PRIVATE_KEY }} # PRIVATE_KEY
        port: 22
        envs: COMPOSE
        script: |
          sudo docker login -u ${{ secrets.DOCKER_USERNAME }} -p ${{ secrets.DOCKER_PASSWORD }}
          sudo docker rm -f $(docker ps -qa)
          sudo docker pull ${{ secrets.DOCKERHUB_USERNAME }}/back
          sudo docker-compose -f $COMPOSE up -d



 

 

해당 부분은 ssl인증 및 mysql도 image로 설정하기 위한 도커 파일이다. 

 

server:
    container_name: back
    image: hanseu9839/back:latest
    expose:
      - 8080
    ports:
      - 8080:8080

  front:
    container_name: front
    image: hanseu9839/front:latest
    expose:
      - 3000

 

해당 부분만 작성하면 된다.

** 여기서 주의할 점은 image로 설정해야한다는 것이다.

왜냐면 github action에서 docker image를 hub에 업로드하면 context를 통해서 path를 ec2내부에서 인식해서 잡을 수 없기 때문에 이미지로 바꿔서 띄워 주어야 한다. 

 

 

 # AWS 자격증명 부분 추가
    - name: Configure AWS credentials
      uses: aws-actions/configure-aws-credentials@v1
      with:
        aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
        aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
        aws-region: ap-northeast-2

aws 자격증명을 해주는 부분이다.

AWS에서 AWS_ACESS_KEY_ID 와 AWS_SECRET_ACCESS_KEY는 AWS IAM에서 IAM생성 후 발급 받을 수 있다. 

 

 

만들면서 느낀 점은 포토폴리오로 만들기 위해서 github repository를 public으로 제공해야하기 때문에 환경 변수를 통해서 제공하였다. 

또한 github자체에서 치명적인 키 여부는 github repository에 push하지 못하도록 만들어져있다. 

 

위에 코드 처럼 작성했을 때, 너무 코드가 더럽고 제대로 동작하지 않았다.. 그래서 다시 리팩토링을 한 결과 

 

이런식으로 작성해주게 되었으며 

  - name: make application-dev.yml
      run: |
        cd ./src/main/resources
        touch ./application-dev.yml
        echo "${{ secrets.APPLICATION_DEV }}" > ./application-dev.yml

해당 부분을 추가해주었고 환경변수에 관한 부분을 다 삭제해버렸다. dev에 해당하는 .yml을 정상적으로 읽어 프로젝트를 빈 설정 할 수 있게 되었다. 

 

    - name: Deploy to server
      uses: appleboy/ssh-action@master
      id: deploy
      env:
        APP: "back"
        COMPOSE: "/home/capo_project/docker-compose.yml"
      with:
        host: ${{ secrets.EC2_HOST }} # EC2_HOST 키
        username: ubuntu
        key: ${{ secrets.EC2_PRIVATE_KEY }} # PRIVATE_KEY
        port: 22
        envs: COMPOSE
        script: |
          sudo docker login -u ${{ secrets.DOCKER_USERNAME }} -p ${{ secrets.DOCKER_PASSWORD }}
          sudo docker rm -f $(docker ps -qa)
          sudo docker pull ${{ secrets.DOCKERHUB_USERNAME }}/back
          sudo docker-compose -f $COMPOSE up -d

ssh 접근을 해주는 부분이다. 

ssh 접근하여 실질적으로 docker 연결하는 형식이다.

 

 

출처:)

https://velog.io/@kimseungki94/Jenkins-vs-Github-Action-%EC%96%B4%EB%96%A4%EA%B1%B8-%EC%93%B0%EB%8A%94%EA%B2%8C-%EC%A2%8B%EC%9D%84%EA%B9%8C

 

Jenkins vs Github Action 어떤걸 쓰는게 좋을까?

개요 > IT-Hermes 프로젝트 개발 과정에서, 배포를 업데이트 하는 과정에 너무 오랜시간이 걸렸습니다. 특히 이번 프로젝트의 경우 주요 서버들이 너무 많았습니다. 프로젝트에 필요한 서버는 다음

velog.io

https://khys.tistory.com/77

 

CI/CD란? - 테스트, 배포 자동화

CI/CD CI/CD는 Continuous Integration(CI)와 Continuous Delivery/Deployment(CD)를 통합해서 부르는 용어다. CI/CD는 개발 과정에서 필요한 빌드, 테스트, 배포 등의 과정을 자동화한다. CI/CD 자동화를 통해서 개발자

khys.tistory.com

https://velog.io/@beardfriend/CICD%EA%B0%80-%ED%95%84%EC%9A%94%ED%95%9C-%EC%9D%B4%EC%9C%A0