이전 게시글에서 이어지는 내용입니다.
Github Actions 설정
Repository secret 설정
Secret의 경우, deploy.yml에서 사용되는 정보들이다. 이는 유출되면 위험하기 때문에, Github secrets에서 관리를 하고, deploy.yml에서 변수 이름으로 가져와 사용하게 된다. 배포할 리포지토리의 Settings → Secrets and variables → Actions에 들어가서, 다음 항목들을 New repository secret을 눌러 입력해준다.
| 이름 | 값 |
|---|---|
| EC2_HOST | EC2 퍼블릭 IPv4 주소 (예: 13.125.xxx.xxx) |
| EC2_USER | 보통 ec2-user (Amazon Linux), ubuntu (Ubuntu) |
| EC2_SSH_KEY | 이전 게시글에서 만든 private key 전체 (줄바꿈 포함) |
| DOCKER_USERNAME | Docker hub 아이디 |
| DOCKER_PASSWORD | Docker hub 비밀번호 |

Workflow 생성
이제 deploy.yml을 만들어주자. 이 파일을 만드는 방법은 여러 가지가 있는데, 이 중에 편한걸로 하면 된다.
yml,yaml모두 동일한 포맷이기에 상관없다.
- 프로젝트 내부에
.github/workflows/deploy.yml을 생성 - Github Repository → Code → Add file →
.github/workflows/deploy.yml생성 - Github Repository → Actions → New workflow → set up a workflow yourself →
deploy.yml
결국에는 위 3가지 방법 모두 다음과 같은 위치에 파일이 생기기 때문에 뭘 하든 똑같다.

CI 구성하기
CI의 목적은 코드 변경을 자동으로 빌드 및 검증해서 배포 가능한 산출물을 만드는 것이다.
name: Deploy to EC2
on:
push:
branches: [ master ]
jobs:
build:
runs-on: self-hosted
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Set up JDK
uses: actions/setup-java@v3
with:
distribution: 'temurin'
java-version: '21'
- name: Grant execute permission for Gradle wrapper
run: chmod +x ./gradlew
- name: Build with Gradle
run: ./gradlew clean build
- name: Upload JAR artifact
uses: actions/upload-artifact@v4
with:
name: app-jar
path: build/libs/*.jar
dockerize:
runs-on: self-hosted
needs: build
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Download JAR artifact
uses: actions/download-artifact@v4
with:
name: app-jar
- name: Move JAR to expected path
run: |
mkdir -p build/libs
mv *.jar build/libs/
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Build and push Docker image
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: ${{ secrets.DOCKER_USERNAME }}/hits-backend:latest
platforms: linux/amd64,linux/arm64
deploy:
runs-on: self-hosted
needs: dockerize
steps:
- name: Setup SSH
uses: webfactory/ssh-agent@v0.7.0
with:
ssh-private-key: ${{ secrets.EC2_SSH_KEY }}
- name: Deploy to EC2
run: ssh -v -o StrictHostKeyChecking=no ${{ secrets.EC2_USER }}@${{ secrets.EC2_HOST }} './deploy.sh'
CD 구성하기
CD의 목적은 CI에서 만든 산출물을 환경(테스트/스테이징/프로덕션)에 실제 배포하는 것이다.
deploy:
runs-on: self-hosted
needs: dockerize
steps:
- name: Setup SSH
uses: webfactory/ssh-agent@v0.7.0
with:
ssh-private-key: ${{ secrets.EC2_SSH_KEY }}
- name: Deploy to EC2
run: ssh -v -o StrictHostKeyChecking=no ${{ secrets.EC2_USER }}@${{ secrets.EC2_HOST }} './deploy.sh'
최종 파일
name: Deploy to EC2
on:
push:
branches: [ master ]
jobs:
build:
runs-on: self-hosted
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Set up JDK
uses: actions/setup-java@v3
with:
distribution: 'temurin'
java-version: '21'
- name: Grant execute permission for Gradle wrapper
run: chmod +x ./gradlew
- name: Build with Gradle
run: ./gradlew clean build
- name: Upload JAR artifact
uses: actions/upload-artifact@v4
with:
name: app-jar
path: build/libs/*.jar
dockerize:
runs-on: self-hosted
needs: build
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Download JAR artifact
uses: actions/download-artifact@v4
with:
name: app-jar
- name: Move JAR to expected path
run: |
mkdir -p build/libs
mv *.jar build/libs/
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Build and push Docker image
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: ${{ secrets.DOCKER_USERNAME }}/hits-backend:latest
platforms: linux/amd64,linux/arm64
deploy:
runs-on: self-hosted
needs: dockerize
steps:
- name: Setup SSH
uses: webfactory/ssh-agent@v0.7.0
with:
ssh-private-key: ${{ secrets.EC2_SSH_KEY }}
- name: Deploy to EC2
run: ssh -v -o StrictHostKeyChecking=no ${{ secrets.EC2_USER }}@${{ secrets.EC2_HOST }} './deploy.sh'
EC2 배포 스크립트 생성
배포 스크립트 생성
CI를 통해 만들어진 산출물을 CD 과정에서 EC2에서 실행할 수 있도록 Deploy to EC2 하는 부분이 있다. 이 때, ./deploy.sh를 실행하기 때문에, EC2에 만들어주자.
vim ~/deploy.sh
deploy.sh파일명을 다른 것으로 할 경우, 추후에 생성할deploy.yml파일에는 수정사항을 반영해야 한다.
Docker Hub 관련 변수 디렉토리 경로 및 branch는 본인 환경에 맞게 설정하면 된다.
${docker-usename}/${docker-project-name}는 Docker Hub 아이디 및 프로젝트 이름과 Docker에 표시될 컨테이너 이름을 입력해주면 된다.
#!/bin/bash
IMAGE_NAME=${docker-usename}/${docker-project-name}
CONTAINER_NAME=${docker-container-name}
echo "Stopping existing container..."
docker stop $CONTAINER_NAME || true
docker rm $CONTAINER_NAME || true
echo "Pulling latest image..."
docker pull $IMAGE_NAME:latest
echo "Starting new container..."
docker run -d \
--name $CONTAINER_NAME \
-p 8080:8080 \
--restart always \
$IMAGE_NAME:latest
예를 들면 다음과 같이 설정하면 된다.
#!/bin/bash
IMAGE_NAME=jwhy/service-backend
CONTAINER_NAME=service
echo "Stopping existing container..."
docker stop $CONTAINER_NAME || true
docker rm $CONTAINER_NAME || true
echo "Pulling latest image..."
docker pull $IMAGE_NAME:latest
echo "Starting new container..."
docker run -d \
--name $CONTAINER_NAME \
-p 8080:8080 \
--restart always \
$IMAGE_NAME:latest
마무리
이 과정까지 했다면, master 혹은 main 브랜치에 push를 하거나, Pull Request가 merge 되었을 경우, actions가 잘 동작할 것이다. 만약 actions가 잘 동작하지 않는다면, self-hosted를 사용해보는 것도 좋다.

New self-hosted runner를 눌러서 나오는대로 하면 된다. 인텔 맥의 경우 x64를 사용하면 되고, Apple silicon의 경우 ARM64를 선택하면 된다.
'DevOps > AWS' 카테고리의 다른 글
| [AWS] 프리티어 - Spring 프로젝트 배포 (1) (0) | 2025.10.29 |
|---|---|
| [AWS] - Spring Boot 프로젝트 배포(2) (0) | 2023.09.11 |
| [AWS] - Spring Boot 프로젝트 배포(1) (0) | 2023.09.11 |