T_era

깃 액션으로 CICD 사용하기 본문

Programing/Datababse

깃 액션으로 CICD 사용하기

블스뜸 2025. 7. 21. 17:29

1. Dockerfile 작성하기

프로젝트의 가장 최상위 위치(.gitignore 파일이 있는 곳)에 Dockerfile이라는 이름의 파일을 만들기 확장자 X

 
# 1. 베이스 이미지 선택 (JDK 17, MAC 기반)
FROM eclipse-temurin:17-jdk

# 2. JAR 파일이 생성될 경로를 변수로 지정
ARG JAR_FILE_PATH=build/libs/*.jar

# 3. build/libs/ 에 있는 JAR 파일을 app.jar 라는 이름으로 복사
COPY ${JAR_FILE_PATH} app.jar

# 4. 컨테이너가 시작될 때 이 명령어를 실행
ENTRYPOINT ["java", "-jar", "/app.jar"]

#FROM: 어떤 환경을 기반으로 이미지를 만들지 선택.
#
#COPY: 내 컴퓨터에 있는 파일(빌드된 .jar 파일)을 도커 이미지 안으로 복사하는 명령어
#
#ENTRYPOINT: 도커 컨테이너가 시작될 때 실행될 명령어. 즉, java -jar app.jar 명령으로 스프링 부트 애플리케이션을 실행
  • FROM: 어떤 환경을 기반으로 이미지를 만들지 선택합니다. openjdk:17-jdk-alpine은 JDK 17이 설치된 가벼운 리눅스 환경입니다.
  • COPY: 내 컴퓨터에 있는 파일(빌드된 .jar 파일)을 도커 이미지 안으로 복사하는 명령어입니다.
  • ENTRYPOINT: 도커 컨테이너가 시작될 때 실행될 명령어입니다. 즉, java -jar app.jar 명령으로 스프링 부트 애플리케이션을 실행합니다.

2. .dockerignore 작성하기

불필요한 파일들이 도커 이미지에 포함되지 않도록 .dockerignore 파일을 만듭니다. 이렇게 하면 이미지 용량이 줄고 빌드 속도가 빨라집니다.

# .dockerignore

.git
.idea
.gradle

3. 로컬에서 테스트 

# 1. 프로젝트 빌드 (Gradle 기준)
./gradlew build

# 2. 도커 이미지 빌드 (my-app 이라는 이름으로)
docker build -t my-app .

# 3. 빌드된 이미지로 컨테이너 실행
docker run -p 8080:8080 my-app

 http://localhost:8080로 접속해서 확인

 

도커 이미지를 배포할 EC2와 GitHub Actions가 AWS에 접근할 수 있도록 권한을 설정

1. AWS EC2 인스턴스 생성

  1. AWS 콘솔 접속 > EC2 > 인스턴스 시작
  2. 이름 설정: 알아보기 쉬운 이름
  3. OS 선택 (AMI): Ubuntu, 프리티어로 사용 가능한 버전
  4. 인스턴스 유형: t2.micro
  5. 키 페어 생성:
    • 생성 후 반드시 저장
  6. 네트워크 설정 (보안 그룹):
    • 보안 그룹 생성을 선택하고, 아래 규칙을 추가합니다.
      • SSH (22번 포트): 
      • HTTP (80번 포트): 0.0.0.0/0
      • 사용자 지정 TCP (8080번 포트): 0.0.0.0/0
  7. 스토리지 설정: 기본값(8GB)으로 충분
  8. 인스턴스 시작 

2. EC2 서버에 Docker 설치하기

# SSH 접속 명령어 (Mac 기준)
# chmod 400 your-key.pem  (최초 한 번만, 키 파일 권한 변경)
ssh -i "tera199810-KeyPair.pem" ubuntu@52.79.239.64
# 실행 최초에 yes입력해야함

# Ubuntu 패키지 업데이트
sudo apt-get update

# Docker 설치
sudo apt-get install -y docker.io

# ubuntu 사용자를 docker 그룹에 추가 (sudo 없이 docker 명령어 사용)
sudo usermod -aG docker ubuntu

# 변경사항 적용을 위해 SSH 접속 종료 후 재접속
exit

재접속 후 docker --version 명령어로 설치를 확인합니다.

3. GitHub Actions를 위한 IAM 사용자 생성

GitHub Actions가 내 AWS 계정에 접근해서 배포 작업을 하려면 권한이 필요

  1. AWS 콘솔 > IAM > 사용자 > 사용자 생성
  2. 사용자 이름: 알아볼 수 있도록 설정
  3. 권한 설정: 직접 정책 연결 선택 후 아래 내용 검색 후 선택.
    • AmazonEC2FullAccess (EC2 제어 권한)
    • AmazonS3FullAccess (S3 버킷 접근 권한, 배포 스크립트 저장용)
    • AmazonRDSFullAccess (RDS DB 접근 권한)
  4. 사용자 생성을 끝내고 들어가서 액세스 키 만들기
  5. CLI를 선택하고, 경고 문구를 확인한 뒤 키 생성
  6. CSV로 다운받아서 저장

3. GitHub Actions을 위한 Docker Token발급

도커에 접근하기 위한 토큰 발급

  1. 도커 UI > 우측 상단 프로필 > Account Settings > Personal access tokens > Generate new Token
    • 만료기한 설정
    • 접근 권한 설정 Read,Write,Delete
  2. Generate 선택
  3. 제일 하단에 나온 두가지 값 저장

GitHub Actions 자동화 파이프라인 설정하기

1. GitHub Repository Secrets 설정

  1. GitHub Repository > Settings > Secrets and variables > Actions 
  2. New repository secret로 하나씩 추가
  • AWS_ACCESS_KEY_ID: 위에서 발급받은 IAM 사용자의 액세스 키
  • AWS_SECRET_ACCESS_KEY: 위에서 발급받은 IAM 사용자의 비밀 액세스 키
  • AWS_REGION: 내 AWS 리전 코드 (예: ap-northeast-2 for Seoul)
  • AWS_S3_BUCKET: 배포 스크립트를 저장할 S3 버킷 이름 (직접 만드셔야 합니다. 예: my-cicd-deploy-scripts)
  • EC2_INSTANCE_ID: 배포할 EC2 인스턴스의 ID (EC2 콘솔에서 확인)
  • EC2_HOST: EC2 인스턴스의 퍼블릭 IP 주소
  • EC2_USERNAME: ubuntu (Ubuntu AMI 기준)
  • EC2_SSH_KEY: 위에서 다운로드한 .pem 키 파일의 내용을 그대로 복사해서 붙여넣기(메모장으로 열고 --begin--부터 --end까지 전부 복사 붙여넣기)
  • DOCKERHUB_TOKEN: 도커 토큰을 생성하며 나온 값 중dckr_pat_...으로 시작하는 값 복사 붙여넣기
  • DOCKERHUB_USERNAME: 도커 토큰을 생성하며 나온 값 중 유저이름 부분만 붙여넣기 예(ljy981008)
  •  

2. cicd.yml 수정 (SSH 방식)

.github/workflows 폴더의 cicd.yml 파일

# 워크플로우의 전체 이름을 "CI/CD Docker to EC2"로 정했음.
name: CI/CD Docker to EC2

# 언제 이 워크플로우를 실행할지 정하는 부분임.
on:
  push:
    # "main" 브랜치에 코드가 push 될 때마다 실행될 거임.
    branches: [ "main" ]

# 워크플로우가 해야 할 작업(job)들을 정의함.
jobs:
  # "build-and-deploy"라는 이름의 작업을 하나 만들었음.
  build-and-deploy:
    # 이 작업은 GitHub이 제공하는 최신 우분투 가상머신에서 돌아감.
    runs-on: ubuntu-latest
    # 이 작업이 수행할 단계(step)들을 순서대로 나열함.
    steps:
      # 1단계: 코드 내려받기
      - name: Checkout
        # GitHub 저장소에 있는 코드를 가상머신으로 복사해오는 액션을 사용함.
        uses: actions/checkout@v3

      # 2단계: 자바(JDK) 설치
      - name: Set up JDK 17
        # 가상머신에 특정 버전의 자바를 설치하는 액션을 사용함.
        uses: actions/setup-java@v3
        with:
          # 자바 버전을 '17'로 지정함.
          java-version: '17'
          # 'temurin'이라는 배포판을 사용함.
          distribution: 'temurin'
      
      # 3단계: gradlew 파일에 실행 권한 주기
      - name: Grant execute permission for gradlew
        # gradlew 파일이 실행될 수 있도록 권한을 변경함. 리눅스 환경이라 필수임.
        run: chmod +x gradlew
        
      # 4단계: 프로젝트 빌드
      - name: Build with Gradle
        # gradlew 명령어로 스프링 부트 프로젝트를 빌드함. 이걸 해야 .jar 파일이 생김.
        run: ./gradlew build

      # 5단계: 도커 빌드 환경 설정
      - name: Set up Docker Buildx
        # 도커 이미지를 효율적으로 빌드하기 위한 Buildx라는 툴을 설정함.
        uses: docker/setup-buildx-action@v2

      # 6단계: 도커 허브 로그인
      - name: Login to Docker Hub
        # 도커 이미지를 올릴 Docker Hub에 로그인하는 액션을 사용함.
        uses: docker/login-action@v2
        with:
          # 아이디는 GitHub Secrets에 저장된 DOCKERHUB_USERNAME 값을 사용함.
          username: ${{ secrets.DOCKERHUB_USERNAME }}
          # 비밀번호는 GitHub Secrets에 저장된 DOCKERHUB_TOKEN 값을 사용함.
          password: ${{ secrets.DOCKERHUB_TOKEN }}

      # 7단계: 도커 이미지 빌드 및 푸시(업로드)
      - name: Build and push
        # Dockerfile을 이용해 이미지를 만들고 Docker Hub에 올리는 액션을 사용함.
        uses: docker/build-push-action@v4
        with:
          # 현재 폴더(.)에 있는 Dockerfile을 사용해서 빌드함.
          context: .
          # 빌드 성공하면 바로 Docker Hub로 푸시(업로드)함.
          push: true
          # 이미지 이름(태그)은 "아이디/my-spring-app:latest" 형식으로 지정함.
          tags: ${{ secrets.DOCKERHUB_USERNAME }}/my-spring-app:latest

      # 8단계: EC2 서버에 배포
      - name: Deploy to EC2
        # SSH를 통해 원격 서버(EC2)에 접속해서 명령어를 실행하는 액션을 사용함.
        uses: appleboy/ssh-action@master
        with:
          # 접속할 EC2 서버의 IP 주소. Secrets에서 값을 가져옴.
          host: ${{ secrets.EC2_HOST }}
          # EC2 서버의 사용자 이름 (보통 ubuntu). Secrets에서 값을 가져옴.
          username: ${{ secrets.EC2_USERNAME }}
          # EC2 접속에 필요한 .pem 키. Secrets에서 값을 가져옴.
          key: ${{ secrets.EC2_SSH_KEY }}
          # EC2 서버에 접속해서 아래 스크립트를 순서대로 실행시킬 거임.
          script: |
            # EC2 서버에서도 Docker Hub에 로그인해야 이미지를 받을 수 있음.
            docker login -u ${{ secrets.DOCKERHUB_USERNAME }} -p ${{ secrets.DOCKERHUB_TOKEN }}
            # Docker Hub에서 방금 올린 최신 버전의 이미지를 내려받음 (pull).
            docker pull ${{ secrets.DOCKERHUB_USERNAME }}/my-spring-app:latest
            # 기존에 실행 중이던 'my-app' 컨테이너가 있으면 중지시킴. 없으면 그냥 넘어감 (|| true).
            docker stop my-app || true
            # 기존 'my-app' 컨테이너가 있으면 삭제함. 없으면 그냥 넘어감.
            docker rm my-app || true
            # 새로 받은 이미지로 'my-app'이라는 이름의 컨테이너를 실행함.
            # -d: 백그라운드에서 실행, -p 8080:8080: 포트 연결
            docker run -d -p 8080:8080 --name my-app ${{ secrets.DOCKERHUB_USERNAME }}/my-spring-app:latest

ECR을 쓰면 더 안전하고 빠르게 할 수 있다 하지만 복잡하다

 

RDS 연결

application.yml 프로젝트의 yml설정을 통해 rds 저장 설정을 추가

# 공통 설정
spring:
  # 기본 프로필을 dev로 설정
  profiles:
    active: dev
  jpa:
    hibernate:
      ddl-auto: update
    properties:
      hibernate:
        format_sql: true
        show_sql: true

---
# 개발 환경(dev) 설정 - 로컬 DB 정보
spring:
  config:
    activate:
      on-profile: dev
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/testDB
    username: root
    password: '비밀번호'

---
# 운영 환경(prod) 설정 - rds 설정
spring:
  config:
    activate:
      on-profile: prod
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: ${DB_URL}
    username: ${DB_USERNAME}
    password: ${DB_PASSWORD}
  jpa:
    hibernate:
      ddl-auto: update
    properties:
      hibernate:
        dialect: org.hibernate.dialect.MySQLDialect

---

로컬에서는 dev로 명시된 설정을 우선 실행하는데 후에 설정할 cicd.yml을 통해 우선순위를 prod를 했기 때문에 같은 yml에서 설정해도 된다

test/resources/application.yml
테스트 환경을 만들어놓지 않으면 rds가 작동하지않음 

# 테스트 환경 전용 설정
spring:
  datasource:
    # H2 데이터베이스를 사용하도록 설정
    url: jdbc:h2:mem:testdb
    driver-class-name: org.h2.Driver
    username: sa
    password:
  jpa:
    hibernate:
      ddl-auto: create-drop

 

  • RDS 인스턴스 생성
    • AWS 콘솔에서 RDS데이터베이스 생성
    • 표준 생성, 엔진 유형은 MySQL
    • 템플릿은 프리티어
    • DB 인스턴스 식별자 입력 
    • 마스터 사용자 이름마스터 암호를 설정하고 반드시 메모를 해놓든 기억해놓기
    • 연결 섹션에서 EC2 컴퓨팅 리소스에 연결은 연결 안 함으로. 보안 그룹을 직접 설정
  • 보안 그룹 설정
    • VPC 보안 그룹에서 새로 생성을 선택하고, 보안 그룹 이름 입력
    • 나머지 설정은 그대로 두고 데이터베이스 생성을 클릭
    • 생성이 완료되면 생성된 DB를 클릭하여 세부 정보 페이지로 이동 엔드포인트 주소를 복사해둔다. 이 주소가 yml의 DB_URL 환경변수 값
    • 연결 & 보안 탭에서 VPC 보안 그룹 이름을 클릭
    • 보안 그룹 페이지에서 인바운드 규칙 편집을 클릭하고 아래 규칙을 추가
      • 유형: MYSQL/Aurora (3306)
      • 소스: 규칙 추가를하고 사용자 지정을 선택, 검색창에 EC2 인스턴스가 사용 중인 보안 그룹의 ID(예: sg-...)를 찾아 선택
    • 추가구성 > 퍼블릭 엑세스 허용으로 변경
    • 규칙 저장

.GitHub Secrets 추가

  1.  GitHub Repository > Settings > Secrets and variables > Actions 
  2. New repository secret로 하나씩 추가
  • DB_URL: jdbc:mysql:// + 위에서 복사한 RDS 엔드포인트 주소 + /[데이터베이스명]
    • 예: jdbc:mysql://my-db.xxxxxxxx.ap-northeast-2.rds.amazonaws.com:3306/testDB
  • DB_USERNAME: 아까 기억해둔 RDS 생성 시 설정한 마스터 사용자 이름
  • DB_PASSWORD: 아까 기억해둔 RDS 생성 시 설정한 마스터 암호

cicd.yml 수정

docker run -d -p 8080:8080 --name my-app ${{ secrets.DOCKERHUB_USERNAME }}/my-spring-app:latest
->
docker run -d -p 8080:8080 --name my-app \
  -e SPRING_PROFILES_ACTIVE=prod \
  -e DB_URL=${{ secrets.DB_URL }} \
  -e DB_USERNAME=${{ secrets.DB_USERNAME }} \
  -e DB_PASSWORD=${{ secrets.DB_PASSWORD }} \
  ${{ secrets.DOCKERHUB_USERNAME }}/my-spring-app:latest

 

위의 내용을 아래 내용으로 변경 (yml우선순위 및 rds 환경변수 추가)