티스토리 뷰
최근 프로젝트를 하면서 직접 배포를 하게 되었는데, 생각보다 복잡하고 명령어들이 낯설어서 나중에 헷갈리지 않기 위해 정리하려고 한다.환경은 Spring boot(JAVA) + MySQL + Redis이며, Dockerfile + docker-compose.yml + .github/workflow/app-backend-deploy.yml방식을 사용하였다.
글의 순서는 인스턴스 생성 => ECR 생성 => GitHub 설정 => Spring boot 설정 => 배포하기이다
✏️ 인스턴스 설정
인스턴스 생성
인스턴스 유형 tr.micro는 너무 용량이 작아서 배포가 잘 안 될수도 있다.
pem 파일 생성
ec2에 원격으로 접속하기 위해서는 로컬 컴퓨터에서 pem파일(키)이 필요하다 사진과 같이 자신이 원하는 키 페어 이름, RSA를 선택 후 키 페어 생성을 클릭한다.
보안그룹 생성 및 적용
20번 포트(SSH): 내 로컬 PC에서 EC2에 원격 접속하기 위해 필요한 프로토콜이다.
8080번 포트: 스프링부트 서버가 동작할 포트번호이다.
6379번 포트 : Redis에 접속하기 위한 포트번호이다.
탄력적 IP 할당
인스턴스 자세히 보기를 클릭하면 퍼블릭 IPv4 주소라는 것이 있다. 이 주소는 EC2를 배포할 시에 할당되는 주소인데, 이 값을 따로 지정하지 않으면 인스턴스를 시작할 때마다 새롭게 할당된다. 이를 막기 위해서 탄력적 IP를 생성한 뒤 할당해준다.
EC2 ⇒ 인스턴스 ⇒ 네트워크 및 보안 ⇒ 탄력적 IP 클릭 ⇒ 생성하기 생성된 탄력적 IP 클릭한 뒤 탄력적 IP 주소 할당을 클릭한 뒤 아래 사진과 같이 설정한다.
생성된 탄력적 IP 주소를 클릭한 뒤 작업 ⇒ 탄력적 IP 주소 연결을 클릭한다. 두 번째 사진과 같이 리소스 유형 = 인스턴스, 인스턴스 = 본인의 인스턴스, 프라이빗 IP주소를 선택 후 연결하기 인스턴스로 돌아와서 본인의 인스턴스를 클릭하면 퍼블릭 IPv4주소에 탄력적 IP가 할당된 것을 볼 수 있다.
✏️ 인스턴스 접속하기
인스턴스를 생성하였으니 로컬에서 원격으로 EC2에 접속해보자 자신의 IPV4 도메인을 잘 모르겠다면 자신의 인스턴스 클릭 ⇒ 연결 ⇒ SSH 클라이언트를 클릭한다.
chmod 600 ssuketing.pem
ssh -i pem파일명 ubuntu or ec2-user @ + 본인 IPV4 도메인
ssh -i ssuketing.pem ubuntu@(우분투인 경우)
ssh -i ssuketing.pem ec2-user@(일반적)
간편하게 접속하기
먼저 자신의 pem파일을 ~/.ssh/로 위치를 변경한다
cp ssuketing.pem ~/.ssh/
cd ~/.ssh
ll => ssuketing.pem존재 확인 가능
~/.ssh에 pem파일이 존재한다면 아래와 같은 명령어를 입력한다. 모두 차례대로 입력하면 EC2 접속에 성공한다.
chmod 600 ~/.ssh/ssuketing.pem ## 소유자에게 읽고쓰기의 권한을 할당하고, 나머지에게는 아무런 권한을 주지 않는 명령어
vi ~/.ssh/config
# 슈케팅 서버
Host ssuketing-server(원하는 서버 명)
HostName 탄력적 IP 주소
User ubuntu
IdentityFile ~/.ssh/ssuketing.pem(pem키 주소)
chmod 700 ~/.ssh/config ## chmod 700 ⇒ 사용자만 읽기,쓰기,실행 모든권한이 있다.
cd ~/.ssh ## ssh로 이동
ssh ssuketing-server ## ssh config에 등록한 서비스명
✏️ ECR 설정
ECR 생성
먼저 콘솔창에서 ECS를 검색한 후 리포지토리 생성을 클릭한다
역할 생성
ECR로 접속하기 위해서는 권한이 필요하다
AWS 콘솔창에서 I AM 검색 ⇒ 역할 ⇒ 역할 생성
웹 자격 증명을 누르게 되면 공급자 유형을 선택해야 한다. 공급자 유형 생성 방법은 다음과 같다.
권한 추가에는 AmazonEC2ContainerRegistryReadOnly을 추가해준다
역할 클릭 → 신뢰 관계를 클릭하면 아래와 같은 JSON형식을 볼 수 있다.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Federated": "/token.actions.githubusercontent.com"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"token.actions.githubusercontent.com:aud": "sts.amazonaws.com",
"token.actions.githubusercontent.com:sub": "repo:"
}
}
}
]
}
✏️ Github 설정
Secrets and variables 생성
Github repository → settings → Secrets and variables 이동
- EC2_HOST: EC2 인스턴스의 호스트명 또는 IP 주소를 지정한다.
- EC2_USERNAME: EC2 인스턴스의 사용자명을 지정한다(일반적으로 ec2-user).
- EC2_SSH_KEY: SSH 접속을 위한 개인 키를 지정한다
- SSUKETING_ENV: .env파일에 저장된 값이다.
deploy.yml 생성
프로젝트 루트 디렉토리 → github → workflows → app-backend-deploy.yml 생성 각각의 코드에 대한 설명은 주석을 참고하자
# 워크플로우 이름
name: Build and Push Image to ECR
# 트리거 조건
on:
push:
branches: [ "main" ] # main 브랜치 기준 자동 배포
paths: ["app-backend/**"] # app-backend 하위 경로의 변동을 감지
# 전역 변수 설정
env:
AWS_REGION: "ap-northeast-2" # AWS REGION
ECR_REPOSITORY: "ssuketing/app-backend" # ECR
# 권한 설정
permissions:
id-token: write # OIDC 방식의 AWS 로그인
contents: write
# 할 일 정의
jobs:
deploy:
name: Deploy
runs-on: ubuntu-latest # VM?
environment: production # GitHub Actions 환경
steps:
- name: Checkout
uses: actions/checkout@v4 # 현재 저장소 코드 가져오기
- name: Configure AWS credentials # AWS 자격 증명 구성
uses: aws-actions/configure-aws-credentials@v3
with:
role-to-assume: ${{ secrets.ARN_ECR_PUSH_ROLE }}
role-session-name: ecrPrivatePushRole
aws-region: ${{ env.AWS_REGION }}
audience: sts.amazonaws.com
- name: Login to Amazon ECR # ECR 로그인
id: login-ecr
uses: aws-actions/amazon-ecr-login@v2
- name: Push image to Amazon ECR (api-server) # Docker 이미지 빌드 및 푸시
id: build-image
env:
ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
IMAGE_TAG: latest
run: |
# Build a docker container and
# push it to ECR so that it can
# be deployed to ECS.
cd app-backend
docker build -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG .
docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG
echo "image=$ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG" >> $GITHUB_OUTPUT
- name: Update Helm Chart Version
run: |
cd app-backend
# 파일 이름 지정
FILE="Chart.yaml"
# 변경된 버전을 저장
NEW_VERSION=$(sed -i '18s/\(version: 0.0.\)\([0-9]\+\)/echo "\1$((\2 + 1))"/ge' "$FILE" && grep -oP '(?<=version: )0\.0\.[0-9]+' "$FILE")
git config --global user.email "pooreumjung02@naver.com"
git config --global user.name "pooreumjung"
git add .
git commit -m "chore(api-server): bump version to $NEW_VERSION"
git push
- name: Create .env on EC2
uses: appleboy/ssh-action@v1.0.3
with:
host: ${{ secrets.EC2_HOST }}
username: ubuntu
key: ${{ secrets.EC2_KEY }}
script: |
echo "${{ secrets.SSUKETING_ENV }}" > ~/app-backend/app-backend/.env
- name: Deploy to EC2 via SSH
uses: appleboy/ssh-action@v0.1.10
with:
host: ${{ secrets.EC2_HOST }}
username: ${{ secrets.EC2_USER }}
key: ${{ secrets.EC2_KEY }}
script: |
cd ~/app-backend/app-backend
git pull origin main
docker-compose down
docker-compose up --build -d
docker-compose.yml 생성
redis 정보를 등록 + 환경 변수를 등록하는 파일이다. 또한 ports를 통해 외부에서 접속이 가능하도록 설정할 수 있다.
services:
redis_container:
image: redis:7
container_name: ssuketing-redis
hostname: redis
ports:
- 6379:6379
restart: always
networks:
- ssuketing-network
web-backend:
build: "./app-backend"
container_name: "app-backend"
environment:
- MYSQL_USERNAME=${MYSQL_USERNAME}
- MYSQL_PASSWORD=${MYSQL_PASSWORD}
- MYSQL_URL=${MYSQL_URL}
- AWS_SECRET_KEY=${AWS_SECRET_KEY}
- AWS_ACCESS_KEY=${AWS_ACCESS_KEY}
- AWS_SQS_ENDPOINT=${AWS_SQS_ENDPOINT}
- AWS_SQS_QUEUE_NAME=${AWS_SQS_QUEUE_NAME}
- SPRING_REDIS_HOST=${SPRING_REDIS_HOST}
- SPRING_REDIS_PORT=${SPRING_REDIS_PORT}
- WEB_SITE_CODE=${WEB_SITE_CODE}
- WEB_SITE_ID=${WEB_SITE_ID}
- PRIVATE_KEY=${PRIVATE_KEY}
- SPL_CERT_PEM=${SPL_CERT_PEM}
- SPL_PRIKEY_PEM=${SPL_PRIKEY_PEM}
ports:
- 8080:8080
networks:
- ssuketing-network
# networks 설정
networks:
ssuketing-network:
✏️Spring Boot 설정
application-dev.yml 환경변수 설정
spring :
application :
name : ssuketing
# MySQL
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
username: ${MYSQL_USERNAME}
password: ${MYSQL_PASSWORD}
url: ${MYSQL_URL}
hikari:
maximum-pool-size: 50
# JPA
jpa:
database: mysql
database-platform: org.hibernate.dialect.MySQLDialect
show-sql: false
hibernate:
ddl-auto: none
naming:
physical-strategy: org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
properties:
hibernate:
format_sql: true
use_sql_comments: true
auto_quote_keyword: true
open-in-view: false
# Spring Security
security:
user:
name:
password:
# AWS
cloud:
aws:
region:
static: ap-northeast-2
credentials:
secret-key: ${AWS_SECRET_KEY}
access-key: ${AWS_ACCESS_KEY}
sqs:
endpoint: ${AWS_SQS_ENDPOINT}
queue-name: ${AWS_SQS_QUEUE_NAME}
# redis
data:
redis:
host: ${SPRING_REDIS_HOST}
port: ${SPRING_REDIS_PORT}
# TOMCAT
server:
tomcat:
threads:
max: 500
min-spare: 50
accept-count: 2000
max-connections: 20000
connection-timeout: 15000
servlet:
encoding:
charset: UTF-8
enabled: true
force: true
force-response: true
# Swagger
springdoc:
swagger-ui:
# 각 API의 그룹 표시 순서
# path, query, body, response 순으로 출력
groups-order : DESC
# 태그 정렬 순서
# 알파벳 순 정렬
tags-sorter: alpha
# 컨트롤러 정렬 순서
# method는 delete - get - patch - post - put 순으로 정렬
operations-sorter: method
# swagger-ui default url인 petstore html의 비활성화 설정
disable-swagger-default-url: true
# swagger-ui에서 try 했을 때 request duration을 알려주는 설정
display-request-duration: true
# 모델 확장 깊이를 2단계로 설정
default-models-expand-depth: 2
# 개별 API 호출의 모델 확장 깊이를 2단계로 설정
default-model-expand-depth: 2
api-docs :
# OpenAPI 명세서의 경로를 /api/docs로 설정
# 기본값 : /v3/api-docs
path: /api-docs
# Spring Actuator의 엔드포인트를 Swagger에 표시
show-actuator: true
# API에서 사용할 기본 미디어 유형을 application/json으로 설정
default-consumes-media-type: application/json
default-produces-media-type: application/json
# Swagger UI에서 출력 포맷을 pretty-print 방식으로 설정
writer-with-default-pretty-printer: true
# Swagger API에서 Spring의 ModelAndView 객체를 허용
model-and-view-allowed: true
# Swagger 문서에 포함할 경로 패턴을 지정
paths-to-match: /**
kcp:
site-code: ${WEB_SITE_CODE}
up-hash-url:
ct-type-has:
ct-type-chk:
ct-type-dec:
order-prefix:
test-url :
prod-url :
website-id : ${WEB_SITE_ID}
private-key-password: ${PRIVATE_KEY}
splcert : ${SPL_CERT_PEM}
splprivate : ${SPL_PRIKEY_PEM}
.env 파일 생성
AWS_ACCESS_KEY=YOUR_AWS_ACCESS_KEY
AWS_SECRET_KEY=YOUR_AWS_SECRET_KEY
AWS_SQS_ENDPOINT=YOUR_AWS_SQS_ENDPOINT
AWS_SQS_QUEUE_NAME=YOUR_AWS_SQS_QUEUE_NAME
MYSQL_PASSWORD=YOUR_MYSQL_PASSWORD
MYSQL_URL=YOUR_MYSQL_URL
MYSQL_USERNAME=YOUR_MYSQL_USERNAME
SPL_CERT_PEM=YOUR_SPL_CERT_PEM
SPL_PRIKEY_PEM=YOUR_SPL_PRIKEY_PEM
SPRING_REDIS_HOST=YOUR_SPRING_REDIS_HOST
SPRING_REDIS_PORT=YOUR_SPRING_REDIS_PORT
WEB_SITE_CODE=YOUR_WEB_SITE_CODE
WEB_SITE_ID=YOUR_WEB_SITE_ID
DockerFile 생성
여기서 스냅샷의 이름은 setting.gradle의 rootProject.name - build.gradle의 version값 .jar으로 이루어진다
FROM bellsoft/liberica-openjdk-alpine:17 AS builder
COPY gradlew .
COPY gradle gradle
COPY build.gradle .
COPY settings.gradle .
COPY src src
RUN chmod +x ./gradlew
RUN ./gradlew clean bootJar
FROM bellsoft/liberica-openjdk-alpine:17
COPY --from=builder build/libs/.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java","-jar","/app.jar"]
✏️ 배포하기
EC2 설정
해당 글은 Github Actions를 이용한 자동 배포지만, 처음에는 EC2에 접속해서 초기 설정을 해야 한다. 그래서 아래와 같은 명령어를 차례대로 입력해야 한다.
sudo apt update ## 초기 설정
# 깃 관련
sudo apt-get install git ## 깃 설치
# Docker 관련
sudo apt install docker-compose -y ## docker-compose 설치
docker-compose up -d --build ## docker 실행
sudo usermod -aG docker $USER ## Docker 권한 설정 (옵션)
newgrp docker
sudo apt install openjdk-17-jdk -y => 자바 설치
./gradlew clean build => gradle로 jar 빌드
디렉토리 설정
위의 명령어들을 입력해서 필요한 패키지들을 설치하였다면 app-backend-deploy.yml이 잘 작동할 수 있도록 디렉토리 구조를 맞춰줘야 한다 EC2에서 git clone을 하기 위해서는 깃허브 PAT(Personal Access Tokens)가 필요하다
깃허브 프로필 → settings → Developers settings → Tokens 클릭 후 Generate new token
mkdir ~/your-app
cd ~/your-app
git clone https://pooreumjung:PAT값@github.com/SSUketing/app-backend.git ## 깃 클론
✏️ 수동 배포 해보기
위의 단계까지 모두 설정 후 로컬에서 깃허브로 푸쉬하면 자동으로 배포를 할 수 있지만 수동 배포하는 방법도 첨부하면 좋을 것 같아서 추가로 작성한다.
# 1. EC2에 SSH 접속
ssh -i ~/.ssh/ssuketing.pem ubuntu@<EC2 퍼블릭 IP 또는 도메인>
# 2. 시스템 업데이트
sudo apt update
sudo apt upgrade -y
# 3. Docker & Docker Compose 설치 (처음 한 번만)
sudo apt install -y docker.io
sudo curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" \
-o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
docker-compose --version
# 4. Docker 권한 설정 (옵션)
sudo usermod -aG docker $USER
newgrp docker
# 5. 배포 디렉토리 생성 및 Git clone
mkdir -p ~/app-backend
cd ~/app-backend
git clone https://github.com/리포지토리.git
# 6. .env 파일 생성
vi .env
# 또는 echo 방식
echo "MYSQL_USERNAME=pooreum" >> .env
# ... 필요한 환경변수 추가
# 7. Docker Compose로 빌드 및 실행
docker-compose down --volumes # 기존 컨테이너 완전 정리 (선택)
docker image prune -a -f # 캐시된 이미지 제거 (선택)
docker-compose build --no-cache # 새로 빌드
docker-compose up -d # 백그라운드 실행
# 8. 컨테이너 상태 확인
docker ps
# 9. 로그 확인 (에러 디버깅 시)
docker logs -f <컨테이너 이름>
코드 업데이트시
cd ~/app-backend
git pull origin main
docker-compose down
docker-compose up --build -d
에러시 초기화
docker-compose down --volumes
docker image prune -a -f
docker-compose build --no-cache
docker-compose up -d
'Back-end > Spring' 카테고리의 다른 글
[Spring/스프링] - KCP 본인인증 연동 (0) | 2025.05.22 |
---|---|
[Spring/스프링] - although at least one Creator exists 해결 (0) | 2025.05.21 |
[Spring/스프링] - 한글 인코딩 에러 해결 (0) | 2025.05.19 |
[Spring/스프링] - 스프링 부트 AWS SQS FIFO 연동 (0) | 2025.05.12 |
[Spring/스프링] - Apache JMeter로 성능 테스트 해보기 (0) | 2025.05.11 |
- Total
- Today
- Yesterday
- 백준
- 자바스크립트
- js
- 투 포인터
- 백준 풀이
- C++
- 자바
- c++ string
- Do it!
- 에라토스테네스의 체
- DP
- 유클리드 호제법
- html
- 스프링 부트 crud 게시판 구현
- 알고리즘
- 유니온 파인드
- 알고리즘 공부
- 이분 매칭
- 우선순위 큐
- 세그먼트 트리
- 카운팅 정렬
- CSS
- java
- HTML5
- 스택
- 자료구조
- 반복문
- C++ Stack
- BFS
- DFS
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 | 31 |