1️⃣ EC2 서버 준비
- 목표: GitHub → EC2로 JAR 파일을 수동 배포 가능한 상태 만들기
- 자동화하려면 우선 수동으로도 배포가 잘 되는지 확인하는 게 기본이다!
🔹 Java 설치 (EC2에서 JAR 실행에 필요)
sudo apt update
sudo apt install openjdk-17-jdk -y
java -version # 설치 확인
🔹 디렉토리 구조 생성
mkdir -p ~/app/deploy
mkdir -p ~/app/logs
- ~/app/deploy: jar 파일을 배포할 위치
- ~/app/logs: 실행 로그 저장할 위치
2️⃣ GitHub Actions 자동화 + S3 업로드
🔹 AWS CLI 설치 (로컬/Actions runner에 설치되어 있어야 함)
sudo apt install awscli -y
aws configure
- AWS Access Key, Secret Key, region, output 설정 필요
GitHub Actions runner 안에서 AWS CLI가 필요하다는 의미
- GitHub Actions는 내부적으로 Ubuntu 환경의 가상 머신을 띄워서 코드를 빌드하고 배포한다.
- 이 GitHub Actions 환경에서는 S3나 Secrets Manager 같은 AWS 리소스에 접근하려면 AWS CLI가 필요함.
- 다행히, GitHub Actions의 기본 Ubuntu runner에는 이미 awscli가 설치돼 있어.
- 👉 그래서 추가로 설치할 필요는 거의 없다!
🔹 GitHub Secrets 등록
이름 | 설명 |
AWS_ACCESS_KEY_ID | AWS IAM 사용자 access key (3단계 이후 추가해주세요!) |
AWS_SECRET_ACCESS_KEY | AWS IAM 사용자 secret key (3단계 이후 추가해주세요!) |
AWS_REGION | 예: ap-northeast-2 |
EC2_HOST | 예: ec2-user@xxx.xxx.xxx.xxx 탄력적 IP 안 쓰는 경우: (퍼블릭 DNS) |
EC2_KEY | PEM 키 파일 전체 문자열 (Base64 인코딩 권장) |
GitHub 저장소 > Settings > Secrets → New repository secret 클릭
✏️ pem 키 파일 전체 문자열 여는법
📁 터미널에서 열기
cat ~/Downloads/your-key.pem
# 형식은 아래와 같음
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEAzla1d3J...
...중략...
F8+kxP2LPk3Z5TR7e+5nQA==
-----END RSA PRIVATE KEY-----
- ~/Downloads/your-key.pem 부분은 저장되어 있는 .pem 파일 경로로 바꿔준다.
- 이 명령은 .pem 내용 전체를 터미널에 출력해줌.
🔹 .github/workflows/deploy.yml 예시
name: Deploy Spring Boot to AWS
on:
push:
branches: [ main ] # main 브랜치에 push 될 때마다 이 워크플로우가 실행됨
jobs:
build-and-upload: # 작업(Job) 이름
runs-on: ubuntu-latest # GitHub에서 제공하는 최신 Ubuntu 가상환경에서 실행
steps:
- name: Checkout code
uses: actions/checkout@v4
# 현재 리포지토리의 코드를 체크아웃 (가져오기) 해서 다음 단계에서 사용할 수 있게 함
- name: Set up JDK
uses: actions/setup-java@v3
with:
distribution: 'temurin' # OpenJDK 배포판 중 하나인 Temurin 사용
java-version: '17' # Java 17 버전 설치
- name: Give gradlew permission
run: chmod +x ./gradlew
- name: Build with Gradle
run: ./gradlew clean build
# Gradle 빌드 실행 (clean: 기존 빌드 파일 삭제, build: 새로 빌드 생성)
# 결과물은 보통 build/libs 디렉토리에 생성됨
- name: Rename jar for deployment
run: mv build/libs/*.jar build/libs/app.jar
# S3에 업로드할 때 파일명을 고정하기
- name: Upload jar to S3
uses: jakejarvis/s3-sync-action@master
with:
args: --acl private --follow-symlinks
# --acl private: S3 객체를 비공개로 업로드
# --follow-symlinks: 심볼릭 링크도 따라가서 업로드
env:
AWS_S3_BUCKET: ${{ secrets.S3_BUCKET_NAME }}
# S3 버킷 이름 (예: my-app-deploy-bucket) — GitHub Secrets에 저장되어 있어야 함
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
# AWS IAM 사용자의 액세스 키 ID (보안상 Secrets에 저장)
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
# AWS IAM 사용자의 비밀 액세스 키 (보안상 Secrets에 저장)
AWS_REGION: ${{ secrets.AWS_REGION }}
# S3 버킷이 있는 AWS 리전 (예: ap-northeast-2)
SOURCE_DIR: build/libs
# S3에 업로드할 파일들이 있는 디렉토리 (예: 빌드된 .jar 파일)
빌드시 plain.jar 생기지 않게 설정하기(build.gradle에 다음 옵션을 추가)
jar {
enabled = false
}
main 브랜치에 push 발생 시
- ✅ 코드 checkout
- ✅ JDK 17 설정
- ✅ gradlew 실행 권한 부여
- ✅ Gradle 빌드 수행 (./gradlew clean build)
- ✅ 빌드된 JAR 파일을 S3 버킷에 업로드
3️⃣ S3 연동 및 빌드 파일 업로드 자동화 (GitHub Actions에서 실행)
🤔 S3 왜 해야 할까?
- GitHub Actions에서 생성한 .jar 파일을 EC2에 직접 복사하지 않고,
- S3 버킷에 먼저 업로드하고, EC2 인스턴스에서는 그걸 받아서 실행하게 할 수 있다.
- → 무중단 배포 스크립트에서 이 방식이 깔끔하고 보안적으로도 좋다.
📦 준비물
- S3 버킷 생성 (한 번만)
- IAM 사용자의 Access Key / Secret Key
- GitHub Secrets에 등록
- Actions에서 aws s3 cp 명령어로 업로드
🧱 S3 버킷 생성 (한 번만 하면 됨)
- S3 콘솔 접속
- “버킷 만들기” 클릭
- 이름: your-app-deploy-bucket (원하는 이름)
- 리전은 EC2와 동일한 리전 선택 (예: ap-northeast-2)
- 나머지는 기본 설정 → “버킷 만들기” 클릭
🛠️ GitHub에 AWS 인증 정보 등록
1. IAM → 사용자 추가
2. 이름: github-deploy-user
3. 권한 정책 추가
- 정책: AmazonEC2FullAccess, AmazonS3FullAccess, SecretsManagerReadWrite
이름 | 설명 |
AmazonEC2FullAccess | EC2 인스턴스에 접근 및 명령 실행 |
AmazonS3FullAccess | S3 버킷에서 .jar 파일 다운로드 등 |
SecretsManagerReadWrite | Secrets Manager에 저장된 비밀을 읽기/쓰기 가능 |
4. 사용자 만들고 Access Key 생성
- 상단 탭에서 "보안 자격 증명(Security credentials)" 클릭
- 아래로 내려서 "액세스 키" 섹션으로 이동
- "새 액세스 키 만들기(Create access key)" 버튼 클릭
- 사용 사례 → "명령줄 인터페이스(CLI), SDK, 코드" 선택
- 다음 → 생성하면 Access Key ID / Secret Access Key 가 나옴
5. GitHub → 저장소 Settings → Secrets and variables → Actions
- AWS_ACCESS_KEY_ID = 발급받은 액세스 키
- AWS_SECRET_ACCESS_KEY = 발급받은 시크릿 키
- AWS_REGION = ex. ap-northeast-2
⚠️ Secret Access Key는 다시 볼 수 없으니까 꼭 복사해서 따로 저장하거나 바로 Secrets에 추가해줘야 함.
🧱 S3 버킷 생성
🤔 왜 S3 버킷을 쓰는가?
- GitHub Actions → EC2로 직접 파일 전송하려면 복잡할 수 있음.
- 대신 GitHub Actions → S3 업로드 → EC2에서 다운로드 방식으로 간단하고 깔끔하게 파일을 전달할 수 있다.
- 그리고 S3는 안전하고 빠름.
1. 버킷 생성
- 🔒 [모두 차단] 체크 상태 유지 (기본값) → 나중에 EC2에서 IAM 권한으로 접근하게 설정할 거라서 퍼블릭 오픈은 안 해도 됨
- 버전 관리, 암호화, 태그 등은 기본값 그대로 둬도 됨
2. GitHub → 저장소 Settings → Secrets and variables → Actions
- S3_BUCKET_NAME = 아까 만든 버킷 이름
🧑💻 EC2에서 접근할 수 있도록 IAM 역할 만들기 (선택)
EC2에서 S3에 접근하려면 “나 이 버킷에 접근해도 되지?” 하고 허락이 있어야 한다. 그걸 IAM 역할로 설정해줘야 함.
IAM 역할은 이번 자동 배포엔 필요 없음, 하지만 EC2에서 AWS 자원 직접 쓸 땐 고려할 것!
- 정책: AmazonEC2FullAccess, AmazonS3FullAccess, SecretsManagerReadWrite
- 역할 이름: ec2-s3-access-role (예시)
- EC2 콘솔 이동 → EC2 인스턴스 선택
- [작업] → [보안] → [IAM 역할 수정]
- 아까 만든 역할(github-deploy-user) 선택 → 저장
IAM 사용자 vs 역할 차이
구분 | IAM 사용자 | IAM 역할 |
용도 | 사람이 직접 로그인하거나 프로그램(GitHub 등)이 사용할 계정 |
EC2, Lambda 같은 AWS 리소스나, 외부 서비스가 잠깐 빌려쓰는 권한 |
인증 방식 | Access Key & Secret Key 사용 (GitHub Actions 등에서 사용) |
EC2 등 AWS 서비스에 자동으로 붙음 (권한을 위임받아 쓰기 때문에 Access Key 없이도 가능) |
EC2에 붙일 수 있는가? |
❌ 못 붙임 | ✅ 가능 |
상황 | GitHub Actions → EC2 자동 배포 (키가 필요하니까) |
EC2 안의 앱 → S3 접근 (키 없이 안전하게 접근하려고) |
🚨 예시 상황
- EC2에 배포한 애플리케이션이 로그 파일이나 이미지를 S3에 저장하려고 함.
- 애플리케이션 안에서 AWS SDK를 써서 putObject() 같은 걸 호출하는 등.
💡 해결법
- 애플리케이션이 S3에 접근하려면 AWS 인증 정보가 필요함.
- 여기에 IAM 사용자 Access Key를 넣으면 되긴 하는데… ❌ 보안에 매우 취약함.
- 대신! EC2 인스턴스에 역할(Role) 을 붙여서,
- AWS가 자동으로 해당 EC2 인스턴스에 권한을 줌
- 키 파일 없이도 S3Client 같은 걸 쓸 수 있음!
4️⃣ GitHub Actions 스크립트 작성 – EC2에 배포 자동화
EC2에 자동 배포 (CD 단계)
- EC2에 JAR을 자동 다운로드 후 재시작하는 과정은 아직 없다.
- 이건 두 가지 방식 중 택할 수 있다:
- S3에 업로드된 파일을 EC2에서 감지해서 가져오는 방식
- GitHub Actions에서 EC2에 SSH 접속해서 직접 배포하는 방식(선택)
1. GitHub Actions에서 EC2에 SSH 접속해서 배포하는 방식
[GitHub Action]
|
| SSH로 접속
↓
[EC2 서버] ← GitHub가 직접 명령어 실행 (예: java -jar ~)
📦 GitHub Actions → EC2 직접 SSH 접속 → 빌드된 파일 복사 & 실행
⭐ 장점
- 빠르고 단순하다 (셋업 쉬움)
- GitHub에서 PR 머지 → 바로 EC2에 적용됨
- 실시간 로그 보기 쉬움 (nohup, log.txt 등)
⚠️ 단점
- EC2에 SSH 키를 GitHub Secrets에 저장해야 함 (보안주의)
- EC2에 직접 접근하는 것이기 때문에 보안적으로 신중해야 함
- SSH 연결이 실패하면 배포가 중단됨
🧰 많이 쓰는 툴
- appleboy/ssh-action: 가장 널리 쓰이는 GitHub Action
2. EC2에서 S3를 감지하거나 주기적으로 pull해서 배포하는 방식
[GitHub Action]
|
| S3에 빌드된 zip 업로드
↓
[S3 Bucket]
↑
| 서버가 주기적/수동으로 deploy.sh 실행
[EC2 서버] → zip 다운로드 → 실행
📦 GitHub Actions → S3 업로드 → EC2에서 감지 또는 크론탭으로 pull
⭐ 장점
✅ 오토스케일링/동적 IP 대응 가능
- EC2 인스턴스는 껐다 켜면 IP가 바뀌어.
- SSH 방식은 GitHub에서 EC2의 고정 IP를 알아야 접속할 수 있어.
- 그런데 IP가 바뀌면 GitHub Actions에서 연결 불가 ❌
✅ 반대로 Pull 방식은 EC2가 S3를 보고 스스로 가져오기 때문에,
- IP가 바뀌든,
- 인스턴스가 새로 생기든 (오토스케일링),
- 전혀 상관 없음
⚠️ 단점
- 감지 로직이나 크론탭 등을 EC2에서 설정해야 함 (조금 복잡)
- GitHub Actions만으로는 배포가 완료되지 않음 (EC2 설정 따로 필요)
EC2에 배포 스크립트 만들기
📌 목표
- EC2 인스턴스가 GitHub Actions가 올린 파일을 S3에서 받아서 배포하는 쉘 스크립트 작성
- 보통 다음 경로에 저장함: /home/ec2-user/deploy/deploy.sh
1. EC2에 SSH 접속
ssh ec2-user@<EC2_PUBLIC_IP>
2. 배포 스크립트 작성
vim ~/app/deploy/deploy.sh
✏️ deploy.sh
#!/bin/bash
# -----------------------
# 환경 설정
# -----------------------
APP_NAME=study-app
JAR_NAME=app.jar
DEPLOY_PATH=/home/ubuntu/app/deploy
LOG_PATH=/home/ubuntu/app/logs
S3_BUCKET=!!!!자신의 버킷명으로 바꿔주세요!!!!
S3_KEY=app.jar
echo "⬇️ S3에서 최신 JAR 다운로드"
aws s3 cp s3://$S3_BUCKET/$S3_KEY $DEPLOY_PATH/$JAR_NAME
if [ $? -ne 0 ]; then
echo "❗ JAR 다운로드 실패 - S3에 파일이 없습니다: $S3_BUCKET/$S3_KEY"
exit 1
fi
if [ -f "$DEPLOY_PATH/$JAR_NAME" ]; then
echo "✅ JAR 다운로드 성공: $JAR_NAME"
else
echo "❗ JAR 파일이 존재하지 않습니다 (경로: $DEPLOY_PATH/$JAR_NAME)"
exit 1
fi
echo "🛑 기존 프로세스 종료 (있다면)"
PID=$(pgrep -f $JAR_NAME)
if [ -n "$PID" ]; then
kill -9 $PID
echo "✅ 프로세스 종료 완료 (PID: $PID)"
else
echo "ℹ️ 종료할 프로세스가 없습니다"
fi
echo "🚀 새 버전 실행"
nohup java -jar $DEPLOY_PATH/$JAR_NAME > $LOG_PATH/app.log 2>&1 &
NEW_PID=$(pgrep -f $DEPLOY_PATH/$JAR_NAME | head -n 1)
if [ -n "$NEW_PID" ]; then
echo "✅ 새 버전 실행 완료 (PID: $NEW_PID)"
else
echo "❗ 실행 실패 - 프로세스가 시작되지 않았습니다"
exit 1
fi
3. 실행 권한 주기
chmod +x ~/app/deploy/deploy.sh
4. AWS CLI 설치하기
sudo apt update
sudo apt install awscli -y
🚨 에러 상황
- EC2 인스턴스에서 awscli를 설치하려고 했는데, apt로 설치할 수 없다는 에러가 떴다.
- 이건 EC2에 따라 기본 저장소에서 AWS CLI를 못 찾는 경우가 있어서 그렇다.
- 그래서 수동 설치 방식으로 AWS CLI를 설치해야 함!
✅ AWS CLI v2 수동 설치 (Ubuntu 기준)
1. 먼저 EC2에 접속한 상태에서 최신 버전 다운로드
curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
2. 압축 해제
unzip awscliv2.zip
만약 unzip 명령어가 없다고 하면 먼저 설치
sudo apt update
sudo apt install unzip -y
sudo ./aws/install
aws --version
5. 이렇게 나오면 성공
6. 실행해보기
sh ~/app/deploy/deploy.sh
🧠 현재 상태 요약
항목 | 상태 |
Spring Boot 빌드 자동화 | ✅ 완료 |
JAR S3 업로드 | ✅ 완료 |
EC2 수동 배포 스크립트 | ✅ 완료 |
배포 스크립트 검증 | ✅ 성공 |
Secrets Manager 적용 | 🟡 준비 중 |
CodeDeploy 연동 | 🟡 준비 중 |
완전 자동화 | 🔜 곧 가능! |
🔐 AWS Secrets Manager 적용
1. AWS 콘솔 접속 → Secrets Manager로 이동
2. "새 보안 암호 저장" 클릭
키 값 예시:
{
"spring.datasource.url": "jdbc:mysql://localhost:3306/devdb",
"spring.datasource.username": "devuser",
"spring.datasource.password": "devpass"
}
3. 비밀 키-값 추가
4. 보안 암호 이름 정하기
- 나머지 설정은 기본값으로 두고 저장
5. Gradle 의존성 추가
// AWS secret manager (Spring Cloud AWS)
implementation platform("io.awspring.cloud:spring-cloud-aws-dependencies:3.0.1")
implementation 'io.awspring.cloud:spring-cloud-aws-starter-secrets-manager'
6. AWS CLI 설치 및 설정
aws configure
- Access Key ID: 기존에 발급했던 키
- Secret Access Key: 기존에 발급했던 키
- 리전: ap-northeast-2
- 출력 형식: json
7. Java 코드 작성 및 테스트
@Service
public class SecretsManagerService {
public static void main(String[] args) {
getSecret();
}
private final SecretsManagerClient secretsClient;
private final ObjectMapper objectMapper;
public SecretsManagerService() {
this.secretsClient = SecretsManagerClient.builder()
.region(Region.AP_NORTHEAST_2) // 서울 리전
.build();
this.objectMapper = new ObjectMapper();
}
public static void getSecret() {
String secretName = "prod/switching";
Region region = Region.of("ap-northeast-2");
// Create a Secrets Manager client
SecretsManagerClient client = SecretsManagerClient.builder()
.region(region)
.build();
GetSecretValueRequest getSecretValueRequest = GetSecretValueRequest.builder()
.secretId(secretName)
.build();
GetSecretValueResponse getSecretValueResponse;
try {
getSecretValueResponse = client.getSecretValue(getSecretValueRequest);
} catch (Exception e) {
// For a list of exceptions thrown, see
// https://docs.aws.amazon.com/secretsmanager/latest/apireference/API_GetSecretValue.html
throw e;
}
String secret = getSecretValueResponse.secretString();
// Your code goes here.
System.out.println(secret);
}
}
- 위 코드를 통해 Secret 값을 정상적으로 받아오는 데 성공!
8. yml 파일 수정 🌟
spring:
config:
import: aws-secretsmanager:secretswitching_${spring.profiles.active}
profiles:
active: dev
이 설정만 있으면, secretswitching_dev 라는 이름의 secret을 AWS Secrets Manager에서 자동으로 불러오고,
그 안의 key-value(JSON)가 application.yml처럼 속성으로 적용돼.
yml 파일 전체 예시
## applicaton-prod.yml
spring:
config:
activate:
on-profile: prod
#이름의 secret을 AWS Secrets Manager에서 자동으로 불러옴
import: aws-secretsmanager:${spring.profiles.active}/switching
datasource:
url: ${spring.datasource.url}
username: ${spring.datasource.username}
password: ${spring.datasource.password}
driver-class-name: com.mysql.cj.jdbc.Driver
jpa:
hibernate:
ddl-auto: validate
properties:
hibernate:
dialect: org.hibernate.dialect.MySQLDialect
# show_sql: true
format_sql: true
logging.level:
org.hibernate.SQL: debug
# org.hibernate.type: trace
custom:
secret:
name: prod/switching
server:
port: 9090
# application.yml
spring:
application:
name: study-matching-site
profiles:
active: prod
jwt:
secret: ${spring.jwt.secret}
springdoc:
swagger-ui:
path: /swagger-ui
api-docs:
path: /v3/api-docs
server:
port: 8080 # 기본 포트 (환경별로 덮어쓰기 가능)
9. 로컬에서 테스트
Secrets Manager에 접근하려면 AWS 자격증명이 필요함.(로컬은 이미 6번에서 했음)
aws configure
# AWS Access Key ID [None]: YOUR_KEY
# AWS Secret Access Key [None]: YOUR_SECRET
# Default region name [None]: ap-northeast-2
- 스프링 애플리케이션 로그에서 다음 메시지가 보이면 성공
10. EC2 or ECS or Lambda 같은 AWS 환경
AWS 콘솔 → IAM → 역할(Roles) → 역할 생성(Create role)
신뢰할 수 있는 엔터티 선택: EC2 선택
권한 정책 추가에서 아래 정책을 선택
- 역할 이름 예시: EC2SecretsManagerRole
- 역할 생성 완료
AWS CodeDeploy를 써서 EC2 인스턴스에 자동 배포를 설정
✅ CodeDeploy란?
AWS CodeDeploy는 애플리케이션을 EC2, Lambda, 또는 온프레미스 서버에 자동으로 배포해주는 서비스이다.
특히 EC2에서 사용할 경우에는 앱이 수정되었을 때 자동으로 EC2에 배포하고, 지정된 스크립트를 실행할 수 있다.
💡 기본 개념
1. AppSpec 파일
version: 0.0
os: linux
files:
- source: /
destination: /home/ec2-user/app
hooks:
AfterInstall:
- location: scripts/deploy.sh
timeout: 180
runas: ec2-user
- 배포 중 어떤 스크립트를 언제 실행할지 정의한 YAML 파일 (appspec.yml)을 작성해야 한다.
2. CodeDeploy 애플리케이션 만들기
- 애플리케이션 이름: 아무 이름이나 가능하지만, 예: my-ec2-app
- 컴퓨팅 플랫폼 선택: EC2/온프레미스
- 💡 Amazon ECS는 Docker 컨테이너 기반의 서비스에 배포할 때 선택하는 옵션이다.
3. CodeDeploy 서비스 역할 만들기
- 왼쪽 메뉴에서 역할 클릭
- 역할 만들기(Create role) 클릭
- 신뢰할 엔터티 유형: AWS 서비스 선택
- 사용 사례 선택: 검색창에 codedeploy 입력 후 CodeDeploy 선택
- 기본 정책에서 AWSCodeDeployRole 또는 AWSCodeDeployRoleForEC2 선택 (둘 중 하나면 됨)
- 역할 이름 지정: CodeDeployServiceRole (예시)
서비스 역할은 IAM에서 미리 만들어 둬야 CodeDeploy 설정 시 선택할 수 있다.
CodeDeploy는 EC2 인스턴스에 접근해서 배포 명령을 실행해야 하니까, 그 권한을 가진 역할이 필요하다.
3. 배포 그룹 만들기
✅ CodeDeploy 배포 그룹이란?
배포할 EC2 인스턴스, 배포 방식, 그리고 사용할 배포 스크립트(AppSpec 파일) 등을 설정하는 곳
- 애플리케이션 상세 페이지에서 상단에 "배포 그룹 생성" 클릭
- 태그: 이건 CodeDeploy가 "어떤 EC2 인스턴스에 배포할지"를 식별하는 데 꼭 필요
- CodeDeploy는 배포 그룹에서 "태그 기준으로 EC2를 찾는다"고 되어 있다
- 그래서 우리가 EC2에 특정 태그를 직접 붙여줘야 CodeDeploy가 이 인스턴스를 찾아서 배포해준다.
🧩 태그
- Key/Value는 자유롭게 정해도 돼, 꼭 Name이 아니어도 된다.
- 하지만 배포 그룹과 EC2가 정확히 같은 키-값을 가져야 매칭됨.
- 여러 인스턴스에 같은 태그 붙이면 동시에 여러 대에 배포 가능함.
- AllAtOnce, HalfAtATime, OneAtATime 등은 CodeDeploy의 배포 방식 옵션이다.
- 배포를 어떻게, 어떤 속도로 EC2 인스턴스에 적용할지를 결정
💡 배포 구성(Deployment Configuration) 종류
배포 방식 | 설명 | 장점 | 단점 | 적합한 상황 |
AllAtOnce | 모든 인스턴스에 동시에 배포함 | - 가장 빠름 - 설정 간단 |
- 오류 발생 시 전체 장애 - 롤백 어려움 |
- 개발/테스트 서버 - 트래픽 없는 환경 |
HalfAtATime | 전체 인스턴스의 절반에 먼저 배포 → 성공 시 나머지 절반에 배포 |
- 부분 장애에 대비 가능 - 일정 속도와 안정성 균형 |
- 속도는 느리고 완전한 안전도는 아님 | - 스테이징 서버 - 안정성과 속도의 균형 필요 시 |
OneAtATime | 한 번에 하나의 인스턴스에 순차적으로 배포 | - 가장 안전 - 오류 발생 시 빠른 대응 가능 |
- 가장 느림 - 시간이 오래 걸림 |
- 프로덕션 서버 - 실시간 서비스 |
항목 | 설정 예시 및 설명 |
배포 그룹 이름 | my-ec2-deploy-group (원하는 이름) |
서비스 역할 | IAM에서 만들어진 CodeDeployRole (예: CodeDeploy-EC2-Role) * 역할은 IAM에서 미리 만들어 둬야 CodeDeploy 설정 시 선택(위 처럼) |
배포 유형 | 인플레이스 배포 (기본값 유지) |
환경 구성 | 태그 또는 인스턴스 직접 선택 가능. 보통 태그로 EC2를 찾음 |
대상 선택 방법 | 예: Key=Name, Value=MyEC2Instance (EC2 인스턴스에 붙은 태그 기준) |
로드 밸런서 설정 | 안 써도 됨 (단일 EC2인 경우 생략 가능) |
4. appspec.yml 파일 작성
version: 0.0
os: linux
files: 👈 어떤 파일들을 EC2 어디에 복사할지?
- source: /
destination: /home/ubuntu/app/deploy
hooks: 👈 복사 후 어떤 작업을 할지 정의 (예: 스크립트 실행)
AfterInstall:
- location: deploy.sh 👈 파일 복사 후 실행될 작업 (여기서 deploy.sh)
timeout: 180
runas: ubuntu
- CodeDeploy가 어떤 스크립트를 실행할지 정의하는 파일
5. git actions 스크립트 수정
name: Deploy Spring Boot to AWS
on:
push:
branches: [ main ] # main 브랜치에 push 될 때마다 이 워크플로우가 실행됨
jobs:
build-and-upload: # 작업(Job) 이름
runs-on: ubuntu-latest # GitHub에서 제공하는 최신 Ubuntu 가상환경에서 실행
steps:
- name: Checkout code
uses: actions/checkout@v4
# 현재 리포지토리의 코드를 체크아웃 (가져오기) 해서 다음 단계에서 사용할 수 있게 함
- name: Set up JDK
uses: actions/setup-java@v3
with:
distribution: 'temurin' # OpenJDK 배포판 중 하나인 Temurin 사용
java-version: '17' # Java 17 버전 설치
- name: Give gradlew permission
run: chmod +x ./gradlew
- name: Build with Gradle
run: ./gradlew clean build
# Gradle 빌드 실행 (clean: 기존 빌드 파일 삭제, build: 새로 빌드 생성)
# 결과물은 보통 build/libs 디렉토리에 생성됨
- name: Rename jar for deployment
run: mv build/libs/*.jar build/libs/app.jar
# S3에 업로드할 때 파일명을 고정하기
- name: Create deploy-package directory # 배포 디렉토리 생성
run: mkdir -p deploy-package
# CodeDeploy용 디렉토리 생성
- name: Copy deploy files to deploy-package # deploy-package에 파일 복사
run: |
cp appspec.yml deploy-package/ # 루트에서 appspec.yml 복사
cp deploy.sh deploy-package/ # 루트에서 deploy.sh 복사
cp build/libs/app.jar deploy-package/ # 빌드된 app.jar 복사
- name: Upload deploy package to S3
uses: jakejarvis/s3-sync-action@master
with:
args: --acl private --follow-symlinks
# --acl private: S3 객체를 비공개로 업로드
# --follow-symlinks: 심볼릭 링크도 따라가서 업로드
env:
AWS_S3_BUCKET: ${{ secrets.S3_BUCKET_NAME }} # S3 버킷 이름
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} # AWS IAM 액세스 키
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} # AWS IAM 비밀 키
AWS_REGION: ${{ secrets.AWS_REGION }} # S3 버킷이 있는 AWS 리전
SOURCE_DIR: deploy-package # S3에 업로드할 디렉토리
- 현재 GitHub Actions는 JAR 파일 하나만 S3에 업로드하고 있다.
- 그런데 CodeDeploy는 appspec.yml 파일을 기준으로 동작하기 때문에, appspec.yml과 deploy.sh가 같이 있어야 배포 스크립트가 자동 실행된다.
💡 git actions 가 동작한 후 디렉토리 상황
my-spring-app/ 👈 "프로젝트 루트"
├── deploy-package/ 👈 ⭐ CodeDeploy용 디렉토리 (S3로 업로드할 폴더)
│ ├── appspec.yml ✅ CodeDeploy 설정
│ ├── deploy.sh ✅ 배포 스크립트
│ └── app.jar ✅ 빌드된 JAR 파일
├── src/
├── build.gradle
- 이 세 개를 하나의 디렉토리에 같이 두고 S3에 업로드해야 CodeDeploy가 인식 가능하므로 git actions 스크립트 수정
6. EC2 인스턴스에 CodeDeploy Agent 설치 및 구성
ssh -i your-key.pem ubuntu@<EC2_PUBLIC_IP>
- SSH로 EC2 인스턴스에 접속
sudo apt update
sudo apt install ruby wget
# 실행하기 전 I AM 권한 추가 필요!
# AWS CodeDeploy 에이전트 설치 스크립트를 다운로드([ ]자신의 버킷 이름 입력)
sudo wget https://[switching-bucket-202504].s3.amazonaws.com/latest/install
sudo wget https://aws-codedeploy-ap-northeast-2.s3.amazonaws.com/latest/install
# 설치 스크립트 실행
sudo chmod +x ./install
sudo ./install auto
# CodeDeploy Agent 상태 확인
sudo service codedeploy-agent status
- CodeDeploy Agent 설치: EC2 인스턴스에 접속한 후, 위 명령어로 CodeDeploy Agent를 설치
실행하기 전 IAM 권한 추가 필요❗️
EC2 인스턴스에 S3 액세스 권한을 부여❗️
- EC2 인스턴스 역할에도 S3 액세스 권한을 추가해야 한다.
- EC2 인스턴스에서 실행 중인 애플리케이션이나 명령어가 S3에 접근할 때, 해당 EC2 인스턴스에 할당된 IAM 역할이 권한을 가져야 하기 때문이다.
S3에 install 파일 업로드
- AWS 콘솔에서 S3 서비스를 열고, 해당 버킷을 선택
- 자신의 버킷에 latest/install 폴더 생성
- install.sh 파일 업로드
install.sh
#!/bin/bash
# AWS CodeDeploy Agent 설치 스크립트
yum update -y
yum install -y ruby
yum install -y wget
cd /home/ec2-user
wget https://github.com/aws/aws-codedeploy-agent/releases/download/latest/install
chmod +x install
sudo ./install auto
- 이제 install.sh 파일을 S3에 업로드한 후, EC2 인스턴스에서 그 파일을 다운로드하여 실행하면 된다.
- 다시 말해, install.sh 파일을 latest 폴더에 업로드하고, EC2 인스턴스에서 해당 파일을 다운로드한 뒤 실행하는 방식이다.
💡 버킷 정책을 사용하여 퍼블릭 액세스 허용 설정
- 권한 (Permissions) 탭을 선택하고, 버킷 정책 (Bucket Policy)을 클릭
- 버킷 정책에 아래와 같은 JSON 정책을 추가
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "PublicReadGetObject",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::switching-bucket-202504/latest/install/*"
}
]
}
# AWS CodeDeploy 에이전트 설치 스크립트를 다운로드([ ]자신의 버킷 이름 입력)
sudo wget https://[switching-bucket-202504].s3.amazonaws.com/latest/install
# 설치 스크립트 실행
sudo chmod +x ./install
sudo ./install auto
# CodeDeploy Agent 상태 확인
sudo service codedeploy-agent status
- 서비스 상태: active (running)
- 프로세스 ID: 84289 (실행 중인 codedeploy-agent 프로세스)
- 시간: 2025-04-14 11:56:45부터 실행 중
✅ GitHub Actions에서 CodeDeploy를 직접 트리거
업로드 끝난 직후, CodeDeploy에 API 요청을 보내서 배포 시작하는 방식이다.
- 지금 상황 보니까 .jar, appspec.yml, deploy.sh 파일이 전부 S3에 개별 파일로 올라가 있다.
- CodeDeploy는 하나의 압축 파일(zip) 안에 모든 배포 리소스가 들어 있어야 동작하기 때문에 S3에 배포용 zip 파일 만들기어야 한다.
📁 압축할 구조 예시
deploy/
├── appspec.yml
├── deploy.sh
└── app.jar (혹은 study-matching-site-0.0.1-SNAPSHOT.jar)
- zip으로 묶는 건 GitHub Actions 스크립트에서 자동으로 처리해야 CodeDeploy가 사용할 수 있다.
- 지금까지 스크립트에서 deploy-package 디렉토리까지 잘 만들고 있고, 그 안에 필요한 파일들만 잘 들어가게 해서 zip으로 묶고 S3에 올리기만 추가하면 된다.
name: Deploy Spring Boot to AWS
on:
push:
branches: [ main ] # main 브랜치에 push 될 때만 실행
jobs:
build-and-upload:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4 # GitHub repo의 소스 코드 가져오기
- name: Set up JDK
uses: actions/setup-java@v3
with:
distribution: 'temurin'
java-version: '17'
- name: Grant execute permission to Gradle wrapper
run: chmod +x ./gradlew
- name: Build with Gradle
run: ./gradlew clean build # 프로젝트 빌드
- name: Rename JAR for deployment
run: mv build/libs/*.jar build/libs/app.jar # app.jar로 고정 (CodeDeploy에서 사용하기 쉽게)
- name: Prepare deploy package
run: |
mkdir -p deploy-package
cp build/libs/app.jar deploy-package/
cp appspec.yml deploy-package/
cp deploy.sh deploy-package/
- name: Zip the deploy package
run: |
cd deploy-package
zip -r deploy.zip . # deploy.zip 생성
# AWS 자격 증명 설정 (Secrets에 저장된 값 사용)
- name: Configure AWS credentials
run: |
aws configure set aws_access_key_id ${{ secrets.AWS_ACCESS_KEY_ID }}
aws configure set aws_secret_access_key ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws configure set default.region ${{ secrets.AWS_REGION }}
# S3에 deploy.zip 업로드
- name: Upload to S3
run: aws s3 cp deploy-package/deploy.zip s3://switching-bucket-202504/app.zip
🚀 배포 트리거 설정 (CodeDeploy)
- 우리는 이미 배포 그룹과 애플리케이션을 생성한 상태이다.
- S3에 app.zip 파일이 업로드된 후 AWS CodeDeploy를 사용해 배포를 시작하려면, 배포를 트리거해야 한다.
- 이를 위해 배포를 수동으로 트리거하거나 자동화된 트리거를 사용할 수 있다.
GitHub Actions 워크플로우에서 배포 트리거하기
- name: Trigger CodeDeploy Deployment
run: |
aws deploy create-deployment \
--application-name switching-ec2-app \
--deployment-group-name switching-deploy-group \
--revision revisionType=S3,s3Location={bucket=${{ secrets.S3_BUCKET_NAME }},key=app.zip,bundleType=zip} \
--deployment-config-name CodeDeployDefault.OneAtATime \
--region ${{ secrets.AWS_REGION }} \
--no-wait
- --application-name : 배포할 애플리케이션 이름 (switching-ec2-app).
- --deployment-group-name : 배포 그룹 이름 (switching-deploy-group).
- --revision : S3 버킷에서 배포할 파일(app.zip).
- --deployment-config-name : 배포 구성 (CodeDeployDefault.OneAtATime - 하나씩 배포).
- --region : 배포할 리전 (AWS_REGION).
🚨 IAM CodeDeployFullAccess 권한 추가 ❗️
📄 전체 스크립트
name: Deploy Spring Boot to AWS # 워크플로우 이름 설정
# main 브랜치에 push가 발생할 때마다 이 워크플로우가 실행됩니다.
on:
push:
branches: [ main ] # main 브랜치에 변경 사항이 있을 때 실행
jobs:
build-and-upload: # 작업 이름 설정 (이 작업은 빌드 후 S3에 업로드하는 역할)
runs-on: ubuntu-latest # GitHub에서 제공하는 최신 Ubuntu 환경에서 실행
steps:
- name: Checkout code # 코드 체크아웃
uses: actions/checkout@v4
# GitHub 리포지토리의 코드를 현재 워크플로우 환경에 다운로드
- name: Set up JDK # Java 환경 설정
uses: actions/setup-java@v3
with:
distribution: 'temurin' # OpenJDK 배포판 중 하나인 Temurin 사용
java-version: '17' # Java 17 버전 설치
- name: Give gradlew permission # gradlew 실행 권한 부여
run: chmod +x ./gradlew
# 프로젝트 내 gradlew 파일에 실행 권한을 부여합니다.
- name: Build with Gradle # Gradle 빌드 실행
run: ./gradlew clean build
# clean: 기존 빌드를 삭제하고, build: 새로 빌드를 생성
- name: Rename jar for deployment # 빌드된 jar 파일 이름 변경
run: mv build/libs/*.jar build/libs/app.jar
# 빌드된 JAR 파일 이름을 고정하여 S3에 업로드할 때 동일한 이름으로 사용
- name: Create deploy-package directory # 배포 디렉토리 생성
run: mkdir -p deploy-package
# 배포 파일들을 저장할 디렉토리 생성
- name: Copy deploy files to deploy-package # 배포 파일들 복사
run: |
cp appspec.yml deploy-package/ # appspec.yml 복사
cp deploy.sh deploy-package/ # deploy.sh 복사
cp build/libs/app.jar deploy-package/ # 빌드된 app.jar 복사
- name: Upload deploy package to S3 # S3에 배포 파일 업로드
uses: jakejarvis/s3-sync-action@master
with:
args: --acl private --follow-symlinks # --acl private: S3에 비공개로 업로드
# --follow-symlinks: 심볼릭 링크도 따라가서 업로드
env:
AWS_S3_BUCKET: ${{ secrets.S3_BUCKET_NAME }} # S3 버킷 이름 (GitHub Secrets에서 설정)
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} # AWS IAM 액세스 키
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} # AWS IAM 비밀 키
AWS_REGION: ${{ secrets.AWS_REGION }} # AWS 리전
SOURCE_DIR: deploy-package # 배포 파일을 포함한 디렉토리
- name: Trigger CodeDeploy Deployment # AWS CodeDeploy 배포 트리거
run: |
aws deploy create-deployment \ # 배포를 트리거하는 AWS CLI 명령어
--application-name switching-ec2-app \ # CodeDeploy 애플리케이션 이름
--deployment-group-name switching-deploy-group \ # 배포 그룹 이름
--revision revisionType=S3,s3Location={bucket=${{ secrets.S3_BUCKET_NAME }},key=app.zip,bundleType=zip} \ # S3 위치와 배포 파일 설정
--deployment-config-name CodeDeployDefault.OneAtATime \ # 하나씩 배포하는 기본 설정
--region ${{ secrets.AWS_REGION }} \ # 리전 정보
--no-wait # 배포 완료까지 기다리지 않고 즉시 종료 (백그라운드에서 진행)
하지만 막상 실행했더니 아래 오류가 생기게 됐다...
이 오류는 AWS CodeDeploy가 deploy.sh 스크립트를 배포하려고 할 때, 해당 위치에 이미 동일한 파일이 존재하기 때문에 발생하는 문제였다. 기본적으로 AWS CodeDeploy는 배포 시 파일을 덮어쓰지 않으므로, 이미 존재하는 파일에 대해 덮어쓰기를 시도할 때 문제가 생긴 것이다.
해결 방법
- 파일 삭제 후 배포하는 방식으로 진행했다.
- 배포 전에 deploy.sh와 같은 기존 파일을 명시적으로 삭제하는 절차를 추가하는 방법이다.
- 이를 위해 BeforeInstall 훅에서 deploy.sh 파일을 삭제하도록 스크립트를 수정할 수 있다.
1단계: clean-up.sh 파일 만들기
#!/bin/bash
echo "Checking for existing deploy.sh file..."
# 기존 deploy.sh 파일이 존재하면 삭제
if [ -f /home/ubuntu/app/deploy/deploy.sh ]; then
echo "Found existing deploy.sh, removing it..."
rm -f /home/ubuntu/app/deploy/deploy.sh
else
echo "No deploy.sh found, proceeding..."
fi
2단계: start.sh 파일 만들기
#!/bin/bash
# -----------------------
# 환경 설정
# -----------------------
APP_NAME=study-app
JAR_NAME=app.jar
DEPLOY_PATH=/home/ubuntu/app/deploy
LOG_PATH=/home/ubuntu/app/logs
S3_BUCKET=switching-bucket-202504
S3_KEY=app.zip # 이제 zip 파일을 다운로드
echo "⬇️ S3에서 최신 배포 파일 다운로드"
aws s3 cp s3://$S3_BUCKET/$S3_KEY $DEPLOY_PATH/app.zip
if [ $? -ne 0 ]; then
echo "❗ ZIP 파일 다운로드 실패 - S3에 파일이 없습니다: $S3_BUCKET/$S3_KEY"
exit 1
fi
echo "✅ ZIP 파일 다운로드 성공: $S3_KEY"
echo "📦 ZIP 파일 풀기"
unzip -o $DEPLOY_PATH/app.zip -d $DEPLOY_PATH # -o는 기존 파일 덮어쓰기를 허용
if [ $? -ne 0 ]; then
echo "❗ ZIP 파일 압축 해제 실패"
exit 1
fi
if [ ! -f "$DEPLOY_PATH/$JAR_NAME" ]; then
echo "❗ JAR 파일이 존재하지 않습니다 (경로: $DEPLOY_PATH/$JAR_NAME)"
exit 1
fi
echo "✅ JAR 파일 압축 해제 완료: $JAR_NAME"
echo "🛑 기존 프로세스 종료 (있다면)"
PID=$(pgrep -f "java.*$JAR_NAME")
if [ -n "$PID" ]; then
kill -9 $PID
echo "✅ 프로세스 종료 완료 (PID: $PID)"
else
echo "ℹ️ 종료할 프로세스가 없습니다"
fi
echo "🚀 새 버전 실행"
nohup java -jar $DEPLOY_PATH/$JAR_NAME > $LOG_PATH/app.log 2>&1 &
NEW_PID=$(pgrep -f "java.*$JAR_NAME" | head -n 1)
if [ -n "$NEW_PID" ]; then
echo "✅ 새 버전 실행 완료 (PID: $NEW_PID)"
else
echo "❗ 실행 실패 - 프로세스가 시작되지 않았습니다"
exit 1
fi
- 기존에 있던 deploy.sh 를 복사해서 이름만 바꿔줬다.
3단계: appspec.yml 수정
version: 0.0
os: linux
files:
- source: .
destination: /home/ubuntu/app/deploy
permissions:
- object: /home/ubuntu/app/deploy
owner: ubuntu
group: ubuntu
hooks:
BeforeInstall:
- location: clean-up.sh # clean-up.sh 파일 경로
timeout: 180
AfterInstall:
- location: start.sh # 기존 start.sh 파일 경로
timeout: 180
4단계: git actions 스크립트 변경
name: Deploy Spring Boot to AWS
on:
push:
branches: [ main ] # main 브랜치에 push 될 때마다 이 워크플로우가 실행됨
jobs:
build-and-upload:
runs-on: ubuntu-latest # GitHub에서 제공하는 최신 Ubuntu 가상환경에서 실행
steps:
- name: Checkout code
uses: actions/checkout@v4
# 현재 리포지토리의 코드를 체크아웃 (가져오기) 해서 다음 단계에서 사용할 수 있게 함
- name: Set up JDK
uses: actions/setup-java@v3
with:
distribution: 'temurin' # OpenJDK 배포판 중 하나인 Temurin 사용
java-version: '17' # Java 17 버전 설치
- name: Give gradlew permission
run: chmod +x ./gradlew
- name: Build with Gradle
run: ./gradlew clean build
# Gradle 빌드 실행 (clean: 기존 빌드 파일 삭제, build: 새로 빌드 생성)
# 결과물은 보통 build/libs 디렉토리에 생성됨
- name: Rename jar for deployment
run: mv build/libs/*.jar build/libs/app.jar
# S3에 업로드할 때 파일명을 고정하기
- name: Create deploy-package directory # 배포 디렉토리 생성
run: mkdir -p deploy-package
# CodeDeploy용 디렉토리 생성
- name: Copy deploy files to deploy-package # deploy-package에 파일 복사
run: |
cp appspec.yml deploy-package/ # 루트에서 appspec.yml 복사
cp clean-up.sh deploy-package/ # scripts 폴더에서 clean-up.sh 복사
cp start.sh deploy-package/ # scripts 폴더에서 start.sh 복사
cp build/libs/app.jar deploy-package/ # 빌드된 app.jar 복사
- name: Zip deploy package
run: zip -r app.zip deploy-package
- name: Upload to S3
run: aws s3 cp app.zip s3://switching-bucket-202504/app.zip
env:
AWS_S3_BUCKET: ${{ secrets.S3_BUCKET_NAME }} # S3 버킷 이름
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} # AWS IAM 액세스 키
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} # AWS IAM 비밀 키
AWS_REGION: ${{ secrets.AWS_REGION }} # S3 버킷이 있는 AWS 리전
SOURCE_DIR: deploy-package # S3에 업로드할 디렉토리
- name: Trigger CodeDeploy deployment
run: |
aws deploy create-deployment \
--application-name "switching-ec2-app" \
--deployment-group-name "switching-deploy-group" \
--revision "revisionType=S3,s3Location={bucket=switching-bucket-202504,key=app.zip,bundleType=zip}" \
--deployment-config-name "CodeDeployDefault.AllAtOnce"
env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} # AWS IAM 액세스 키
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} # AWS IAM 비밀 키
AWS_REGION: ${{ secrets.AWS_REGION }} # AWS 리전
- deploy.sh는 더 이상 필요하지 않으므로 관련된 부분을 삭제
- 배포 압축 구조가 잘못되어 있었음
app.zip
└── deploy-package/
├── app.jar
├── start.sh
├── clean-up.sh
└── appspec.yml
CodeDeploy는 압축을 풀었을 때 appspec.yml과 스크립트들이 최상위(root)에 있어야 작동한다고 함.
app.zip
├── app.jar
├── start.sh
├── clean-up.sh
└── appspec.yml
git actions 스크립트 수정
name: Deploy Spring Boot to AWS # 워크플로우 이름
on:
push:
branches: [ main ] # main 브랜치에 push가 발생할 때 실행됨
jobs:
build-and-upload:
runs-on: ubuntu-latest # GitHub에서 제공하는 Ubuntu 최신 환경에서 실행
steps:
- name: Checkout code
uses: actions/checkout@v4 # GitHub 레포지토리 코드를 가져옴
- name: Set up JDK
uses: actions/setup-java@v3 # Java 환경 설정
with:
distribution: 'temurin' # OpenJDK 배포판
java-version: '17' # Java 17 사용
- name: Give gradlew permission
run: chmod +x ./gradlew # gradlew에 실행 권한 부여
- name: Build with Gradle
run: ./gradlew clean build # Gradle로 빌드 (clean + build)
- name: Rename jar for deployment
run: mv build/libs/*.jar build/libs/app.jar # 빌드된 JAR 파일 이름을 app.jar로 변경
- name: Prepare deploy-package directory
run: |
rm -rf deploy-package # 기존 디렉토리 삭제 (있다면)
mkdir -p deploy-package # 새 디렉토리 생성
cp appspec.yml deploy-package/ # CodeDeploy 스펙 복사
cp start.sh deploy-package/ # 시작 스크립트 복사
cp clean-up.sh deploy-package/ # 종료 스크립트 복사
cp build/libs/app.jar deploy-package/ # 빌드된 JAR 복사
- name: Zip for deployment
run: |
cd deploy-package # 패키징 디렉토리로 이동
zip -r ../app.zip ./* # 전체 파일을 app.zip으로 압축
- name: Upload to S3
run: aws s3 cp app.zip s3://switching-bucket-202504/app.zip # 압축파일 S3에 업로드
env:
AWS_S3_BUCKET: ${{ secrets.S3_BUCKET_NAME }} # S3 버킷 이름 (Secrets에서 가져옴)
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} # AWS 인증 키
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
AWS_REGION: ${{ secrets.AWS_REGION }}
- name: Trigger CodeDeploy deployment
run: |
aws deploy create-deployment \
--application-name "switching-ec2-app" \ # CodeDeploy 애플리케이션 이름
--deployment-group-name "switching-deploy-group" \ # 배포 그룹 이름
--revision "revisionType=S3,s3Location={bucket=switching-bucket-202504,key=app.zip,bundleType=zip}" \ # 배포할 파일 정보
--deployment-config-name CodeDeployDefault.AllAtOnce \ # 한 번에 전체 배포
--description "GitHub Actions Deployment" # 배포 설명
env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} # AWS 인증 정보
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
AWS_REGION: ${{ secrets.AWS_REGION }}
🚀 지금까지의 GitHub Actions → S3 → EC2 (CodeDeploy) 배포 흐름
👨💻 You push to `main`
│
▼
🌐 GitHub Actions (CI/CD)
────────────────────────────────────────────────────────────
1. ✅ Checkout 소스 코드
2. ✅ Gradle로 빌드 → app.jar 생성
3. ✅ 필요한 파일 모으기:
- app.jar
- appspec.yml
- start.sh
- clean-up.sh
4. ✅ ZIP으로 압축 → app.zip
5. ✅ app.zip 을 S3 버킷에 업로드
6. ✅ CodeDeploy에게 배포 요청
────────────────────────────────────────────────────────────
│
▼
📦 S3 Bucket
switching-bucket-202504/
└── app.zip
├── app.jar
├── appspec.yml
├── start.sh
└── clean-up.sh
│
▼
🏃 AWS CodeDeploy
────────────────────────────────────────────
1. EC2 인스턴스에 app.zip 다운로드
2. 압축 해제 → /home/ubuntu/app/deploy/
3. `appspec.yml` 기준으로:
- BeforeInstall: clean-up.sh 실행
- AfterInstall: start.sh 실행
────────────────────────────────────────────
│
▼
🖥️ EC2 인스턴스
/home/ubuntu/app/deploy/
├── app.jar ◀── 실행 대상
├── appspec.yml
├── start.sh ◀── 새 버전 실행
└── clean-up.sh ◀── 이전 프로세스 종료
'[배포]' 카테고리의 다른 글
[AWS] EC2에 MySQL 설치 및 접속 (0) | 2025.04.05 |
---|---|
[AWS] 🔐 보안 그룹 설정 (0) | 2025.04.05 |
[GitHub Actions] GitHub Actions 명령어 (0) | 2025.03.14 |
[배포] 배포 방식 (0) | 2025.02.04 |
[DevOps] GitHub Actions (0) | 2025.01.18 |