8w8u8

Docker CI/CD 본문

back-end

Docker CI/CD

jud1th 2025. 7. 5. 19:04

Docker Hub Repository 생성하기

https://hub.docker.com/

Docker 설치

EC2에 연결하여, 아래 명령어로 Docker를 설치해줍니다.

curl -fsSL https://get.docker.com/ | sudo sh

Github Actions Secrets 설정하기

깃허브 레포지토리의 Settings 탭 > Security > Secrets and variables > Actions 탭 > New repository secrets

  • APPLICATION: application.yml 내용
  • DOCKER_USERNAME: Docker Hub 계정 아이디
  • DOCKER_PASSWORD: Docker Hub 계정 패스워드
  • DOCKER_REPO: Docker 리포지토리
  • HOST: EC2의 IPv4
  • KEY: EC2 pem key (*참고: vscode로 pem 파일을 열고 내용 전체를 복붙)
  • USERNAME: EC2 username (ubuntu)

Dockerfile 작성하기

프로젝트 루트 위치(build.gradle있는 곳)에 Dockerfile 이라는 파일을 생성 후, 아래 내용을 입력해줍니다.

FROM openjdk:17-slim # x86_64 (AMD64)용 이미지

ARG JAR_FILE=build/libs/*.jar
COPY ${JAR_FILE} app.jar

ENTRYPOINT ["java","-jar","-Duser.timezone=Asia/Seoul","/app.jar"]

deploy.yml 작성하기

프로젝트 구조 참고용 사진


위의 구조는 deploy.yml 위치가 이상한데 깃허브 액션이 작동하긴 했습니다.
(아마 AWS EC2 CI/CD 가 되면서 한번에 된듯?)


일반적으로 GitHub Actions에서 사용하는 deploy.yml 파일은 루트 디렉토리에 있는 .github/workflows/ 폴더에 위치합니다.

deploy.yml에 아래의 내용을 작성하고 커밋해주면 됩니다.
({프로젝트루트}, {브랜치명} 엔 적절한 값 입력)

name: CI/CD with Docker


on:
  push:
    branches: [ "{브랜치명}" ]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3

      - name: Set up JDK 17
        uses: actions/setup-java@v3
        with:
          java-version: 17
          distribution: 'zulu'

      - name: Make application.yml
        run: |
          # mkdir ./{프로젝트루트}/src/main/resources # 디렉토리를 무조건 생성
          mkdir -p ./{프로젝트루트}/src/main/resources # 디렉토리가 없으면 생성
          cd ./{프로젝트루트}/src/main/resources
          touch ./application.yml
          echo "${{ secrets.APPLICATION }}" > ./application.yml

      - 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: Build with Gradle
        run: |
          cd ./{프로젝트루트}
          chmod +x ./gradlew
          ./gradlew build -x test

      - name: Login to DockerHub
        uses: docker/login-action@v2
        with:
          username: ${{ secrets.DOCKER_USERNAME }}
          password: ${{ secrets.DOCKER_PASSWORD }}

      - name: Docker build & push
        uses: docker/build-push-action@v2
        with:
          context: ./{프로젝트루트}
          file: ./{프로젝트루트}/Dockerfile
          push: true
          platforms: linux/amd64 # EC2 아키텍쳐에 맞게 (x86 = amd64, arm = arm64)
          tags: ${{ secrets.DOCKER_REPO }}:latest

      - name: Deploy to Server
        uses: appleboy/ssh-action@master
        with:
          host: ${{ secrets.HOST }}
          username: ${{ secrets.USERNAME }}
          key: ${{ secrets.KEY }}
          envs: GITHUB_SHA
          script: |
            sudo docker rm -f $(sudo docker ps -qa)
            sudo docker pull ${{ secrets.DOCKER_REPO }}:latest
            sudo docker run -d -p 8080:8080 ${{ secrets.DOCKER_REPO }}:latest
            sudo docker image prune -f

Docker 관련 에러

exec /usr/local/openjdk-17/bin/java: exec format error

sudo docker ps 명령어를 입력했을 때 컨테이너가 나오질 않아서,


sudo docker ps -a 명령어로 이전에 생성된 컨테이너를 확인한 결과, 컨테이너가 종료되어있는 상태였습니다.
sudo docker logs {CONTAINER ID} 로 로그를 살펴보니
exec /usr/local/openjdk-17/bin/java: exec format error 에러가 발생한 걸 확인할 수 있었습니다.

찾아보니, 문제는 이미지를 Ubuntu 서버에 올릴 때 발생한 것 같습니다.
Ubuntu와 같은 운영체제는 x86_64 아키텍쳐를 사용하므로 도커 이미지를 사용하고자 하는 운영체제에 맞춰 빌드를 진행해야 합니다.

docker buildx build --push --platform linux/amd64 -t {도커 사용자명}/{레포지토리 이름}:latest.


성공적으로 동작하는 걸 이제 볼 수 있습니닷