github actions와 docker를 이용한 배포과정

현서황·2024년 11월 26일

목차
1. EC2 생성
2. RDS 생성
3. Dockerfile 작성
4. github secrets에 환경변수 선언
5. github-actions.yml 코드 작성

EC2 생성과 RDS 생성은 자료들이 많을 것이라고 생성한다.
주의할 점은 같은 VPC 안에서 생성되어야하기 때문에 RDS 생성 시 기존에 생성해두었던 EC2를 지정해주어야 한다.
같은 VPC안에 있어야 서버에서 RDS를 찾아 생성할 수 있다.

1. EC2 생성

2. RDS 생성

3. DockerFile 작성

프로젝트의 루트 디렉토리 내에 생성하면 된다.

# 베이스 이미지: Java 17 (필요에 따라 Java 버전 변경 가능)
FROM openjdk:17-jdk-slim

# 컨테이너 내부의 작업 디렉토리 설정
WORKDIR /app

# 빌드된 JAR 파일을 컨테이너로 복사
COPY ./build/libs/*.jar app.jar

# 컨테이너에서 열릴 포트
EXPOSE 8080

# 애플리케이션 실행 명령어
ENTRYPOINT ["java", "-jar", "app.jar"]

4. github secrets 환경변수 선언

github actions를 이용할건데, github에 개인정보는 올리면 안되니까 환경변수를 이용한다.
아래의 github-actions.yml 코드 내부에 이용되는 것들을 환경변수로 미리 선언하는 것이다.

YML

YML
spring:
  application:
    name: forest
  profiles:
    group:
      dev: dev, local
      deploy: deploy
    active: dev

YML_DEV

spring:
  datasource:
    url: jdbc:mysql://<엔드포인트>:<포트번호>/<DB인스턴스식별자이름>
    username: <rds 생성  지정한 마스터사용자 이름>
    password: <rds 생성  지정한 마스터암호>
  jpa:
    show-sql: true
    hibernate:
      ddl-auto: update
logging:
  level:
    org.hibernate.SQL: debug

hibernate:
ddl-auto: update
데이터베이스 내부에 자동으로 테이블이 만들어지도록 하는 명령어이다.
이 코드를 써주지 않으면 actions파일을 실행시켰을 때 오류가 나므로 꼭 포함시켜주어야한다.

USERNAME

ubuntu

DOCKER_USERNAME

docker 가입할 때 지정한 사용자 이름

DOCKER_PASSWORD

docker 가입할 때 지정한 비밀번호

HOST_DEV

EC2로 할당받은 public IPv4 주소

PRIVATE KEY


ppk파일을 다운로드 했다면, 이를 cat명령어를 이용해 확인한 후, 키 부분을 떼어 위와같이 작성한 후 PRIVATE KEY 환경변수로 등록해준다.

5. github-actions.yml 코드 작성


먼저 루트 디렉토리 내부의 .github 패키지 내부에 workflows 패키지를 만들고, 그 안에 github-actions.yml 파일을 만든다.
나의 경우에는 dev를 실행하도록 코드를 작성했다.

# github repository actions 페이지에 나타날 이름
name: CI/CD using github actions & docker

# event trigger
# main브랜치에 push가 되었을 때 실행
on:
  push:
    branches: [ "main" ]

permissions:
  contents: read

jobs:
  CI-CD:
    runs-on: ubuntu-latest
    steps:

      # JDK setting - github actions에서 사용할 JDK 설정 (프로젝트나 AWS의 java 버전과 달라도 무방)
      - uses: actions/checkout@v3
      - name: Set up JDK 17
        uses: actions/setup-java@v3
        with:
          java-version: '17'
          distribution: 'temurin'

      # gradle caching - 빌드 시간 향상
      - 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-
      # 권한 부여
      - name: Add execution permissions to Gradle Wrapper
        run: chmod +x ./gradlew

      # 환경별 yml 파일 생성(1) - application.yml
      - name: make application.yml
        if: |
          contains(github.ref, 'main')
        run: |
          mkdir ./src/main/resources # resources 폴더 생성
          cd ./src/main/resources # resources 폴더로 이동
          touch ./application.yml # application.yml 생성
          echo "${{ secrets.YML }}" > ./application.yml # github actions에서 설정한 값을 application.yml 파일에 쓰기
        shell: bash

      # 환경별 yml 파일 생성(2) - dev
      - name: make application-dev.yml
        run: |
          cd ./src/main/resources
          touch ./application-dev.yml
          echo "${{ secrets.YML_DEV }}" > ./application-dev.yml
        shell: bash




      # gradle build
      - name: Build with Gradle
        run: ./gradlew build -x test


      # docker build & push to develop
      - name: Docker build & push to dev
        run: |
          docker login -u ${{ secrets.DOCKER_USERNAME }} -p ${{ secrets.DOCKER_PASSWORD }}
          docker build -f Dockerfile-dev -t ${{ secrets.DOCKER_USERNAME }}/docker-test-dev .
          docker push ${{ secrets.DOCKER_USERNAME }}/docker-test-dev

       

      ## deploy to develop
      - name: Deploy to dev
        uses: appleboy/ssh-action@master
        id: deploy-dev
        with:
          host: ${{ secrets.HOST_DEV }} # EC2 퍼블릭 IPv4 DNS
          username: ${{ secrets.USERNAME }} # ubuntu
          password: ${{ secrets.PASSWORD }}
          port: 22
          key: ${{ secrets.PRIVATE_KEY }}
          script: |
            port=8080
            echo "Checking for containers using port $port..."

            # Find the container ID using the specified port
            container_id=$(docker ps --filter "publish=$port" --format "{{.ID}}")

            if [ -n "$container_id" ]; then
              echo "Found container with ID: $container_id. Stopping it..."
              docker stop "$container_id"
              docker rm "$container_id"
              echo "Container stopped successfully."
            else
              echo "No container is using port $port."
            fi
            sudo docker ps
            sudo docker pull ${{ secrets.DOCKER_USERNAME }}/docker-test-dev
            sudo docker run --name team-18 -d -p 8080:8080 ${{ secrets.DOCKER_USERNAME }}/docker-test-dev




application.yml코드 작성

spring:
  application:
    name: <애플리케아션 이름>
  profiles:
    group:
      dev: dev, local
      deploy: deploy
    active: dev

💻 코드 설명

  • spring.application
    • name
      Spring Boot 애플리케이션의 이름을 지정하는데 사용된다. 지정된 이름은 주로 로그 출력, Spring Cloud 환경에서 서비스 식별, 그리고 애플리케이션 상태 모니터링 등 여러 곳에서 활용된다.
      로깅에 표시되는 예시는 다음과같다. 예를들어 애플리케이션 이름을 "hyeondooori"로 했다면
      2024-11-22 12:00:00.000 INFO 12345 --- [ main] hyeondooori.Application : Started Application in 5.123 seconds (JVM running for 5.678)
  • spring.profiles
    • group
      프로파일 그룹을 정의한다. dev그룹은 dev와 local프로파일이 함께 활성화되고,
      deploy그룹은 deploy 프로파일만 활성화된다.
      이를통해 여러 프로파일일을 하나의 그룹으로 묶어서 사용할 수 있다.
    • active
      현재 활성화된 프로파일을 지정한다. 여기서는 dev프로파일이 활성화된 상태이다.

💻동작 방식
1. spring.profiles.active에 따라 프로파일 로드

  • active: dev 설정에 따라 application-dev.yml 또는 dev 관련 설정이 로드된다.
  1. 그룹 활성화
  • dev 프로파일이 활성화되면, 그룹 설정에 따라 dev와 local 두 프로파일의 설정이 모두 적용된다.
  1. 우선순위
  • 기본설정(application.yml) -> 활성화된 프로파일(application-dev.yml 또는 application-deploy.yml) 순서로 설정이 병합된다.
  • 동일한 키가 중복되면, 활성화된 프로파일의 설정이 우선된다.

    개발 환경에 따라 application.yml 내부의 spring.profiles.active를 변경하여 활성되는 프로파일을 변경할 수 있다.
    로컬환경에서 작업할 때는 active를 local로 하고, 개발환경에서는 dev로 하는 방식!

❓AWS 서버에서의 Docker Desktop

로컬에서 Docker컨테이너를 실행하려면 Docker Desktop이 실행중이어야만 했다.
이는 Windows나 Mac과 같은 운영체제에서 Docker engine을 실행하는데 필요하다.

하지만, AWS에서 실행되는 Docker는 해당 서버(AWS 인스턴스)에 설치된 Docker engine 위에서 동작한다. 이 Docker engine은 AWS 서버 자체에서 관리되며, 로컬 Docker Desktop과는 전혀 관계가 없다.

AWS에서 퍼블릭IP를 할당받은 인스턴스(AWS EC2 등)에서 Docker컨테이너를 실행했다면:

  • docker 컨테이너는 AWS 인스턴스 내에서 자체적으로 동작한다.
  • 퍼블릭 IP를 통해 외부에서 접근할 수 있다.

컨테이너 실행 유지 조건
1. AWS EC2 인스턴스가 계속 실행 중이어야 한다.
EC2가 중지되면, Docker 컨테이너도 중단된다.
2. Docker 컨테이너가 백그라운드에서 실행중이어야한다.
컨테이너를 실행할 때 -d(detached mode)옵션을 사용하여 컨테이너를 백그라운드에 유지한다.
docker run -d -p 3306:3306 --name mysql-container -e MYSQL_ROOT_PASSWORD=<password> mysql

profile
노는 게 제일 좋은 뽀로로

0개의 댓글