
이번 글은 내가 처음으로 CI/CD를 직접 구성해본 기록이다.
처음엔 도커도, 깃허브 액션도, EC2에 올리는 것도 하나하나가 낯설고 겁도 났다.
"내가 진짜 자동 배포를 만들 수 있을까?"
"내가 뭘 잘못하면 서버 다 날아가는 건 아닐까?"
이런 걱정을 수도 없이 하면서도, 작은 성공 하나하나에 계속 도전할 용기가 생겼다 !
직접 Docker 이미지를 빌드하고, Docker Hub에 푸시하고,
GitHub Actions로 자동 배포가 되고, 심지어 Discord 알림까지 받게 되었을 때는
"와... 진짜 내가 했구나" 싶었다 ㅠㅠ
아직 갈 길은 멀고, 더 자동화하고 싶은 것도 많지만
이번 경험 덕분에 CI/CD에 대한 두려움을 한 겹 벗겨낸 기분이다.
처음이라서 더디고 어설퍼도,
직접 부딪히며 만든 나만의 첫 자동화 파이프라인,
그 자체로 충분히 의미 있었다고 생각한다 ✨
📂 블로그 목차
1. 프로젝트 개요
2. EC2 인스턴스 구성
3. Docker & Docker Hub 설정
4. Route53 도메인 연결
5. GitHub Actions 구성
6. Discord 연동
⚙️ EC2 인스턴스 구성
(1) EC2 인스턴스 생성 (2025.05.13 생성)
1) 이름 생성

2) Quick Start → Ununtu 선택

3) 인스턴스 유형 → t3.medium 선택 (용량 부족 시 추후 업그레이드)

4) 키 페어 생성 (VYBZ.pem)

5) 키 페어 선택

6) 인스턴스 생성 완료

1) 탄력적 IP 주소 할당 (2025.05.13 할당)

2) 탄력적 IP 할당 완료

3) 생성된 탄력적 IP → VYBZ 인스턴스에 연결

4) 인스턴스에 연결된 탄력적 IP

5) VYBZ.pem 키를 가지고 SSH 접속
chmod 400 my-key.pem
ssh -i "my-key.pem" ubuntu@EC2-PUBLIC-IP

🚀 Route53이란 ?
Route 53은 AWS에서 제공하는 DNS (Domain Name System) 서비스
→ 도메인 이름을 IP 주소로 바꿔주는 역할
🔍 쉽게 예시로 이해하기
예를 들어:
- 사용자가 브라우저에 http://vybz.kr 입력 👩💻
- 👉 Route 53은 이 도메인을 "어디(IP 주소)"로 보내야 할지 알려주는 DNS 서버 역할
- 예: 3.123.45.67 (EC2 탄력 IP 주소)
가비아 도메인 구매 → vybz.kr (2025.05.09 구매)

🔗 Route53 도메인 연결하기
(1) Route 53 > 시작하기 > 호스팅 영역 생성 (2025.05.13 연결)

(2) 가비아에서 산 도메인과 똑같이 도메인 이름 설정
: 도메인 이름을 설정할 때는, 가비아에서 구매한 도메인과 "정확하게 일치"

(3) vybz.kr 도메인용 Route 53 퍼블릭 호스팅 영역 생성 완료
: NS와 SOA를 가진 같은 레코드가 2개 생성 → 구입한 도메인 사이트에 들어가서 입력

(4) 가비아 > 네임서버 > 설정

(5) NS 4개 입력 후 저장
: NS 타입 의 값/트래픽 라우팅 대상 값들을 뒤에 . 빼고 다 넣고 적용

(6) 네임서버 설정 저장 확인

(6) 생성한 주소를 선택 후 A 레코드 생성하기 (레코드 이름과 탄력적 IP 값 입력)
-> 레코드 이름 설정 안해야 함 !

(7) A 레코드 생성 확인 (실제 사용가능하게 도메인 생성)
: ec2에서 생성한 고정 ip주소값을 넣고 레코드 생성

✅ 1. 시스템 패키지 업데이트 (2025.05.13 작업)
sudo apt update && sudo apt upgrade -y
♻️ 명령어 의미
💡 즉, 서버 전체를 최신 상태로 만들기 위한 준비 명령어입니다.
| 명령어 | 설명 |
| sudo apt update | 패키지 목록(버전 정보)을 최신으로 갱신 |
| sudo apt upgrade -y | 설치된 패키지를 최신 버전으로 자동 업그레이드 (Y 응답 자동 승인) |
1) 시스템 패키지 업데이트 후 재부팅
sudo reboot
2) 다시 EC2에 SSH 접속
ssh -i "my-key.pem" ubuntu@EC2-PUBLIC-IP
3) 접속 후 커널 버전 확인
uname -r
출력이 아래와 같이 나오면 커널 업그레이드 및 재부팅 정상 적용 완료
6.8.0-1028-aws
✅ 2. 필수 패키지 설치
sudo apt install -y docker.io docker-compose git unzip
| 패키지 이름 | 설명 |
| docker.io | Docker 설치 – 컨테이너 실행 도구 |
| docker-compose | 여러 컨테이너를 함께 관리할 수 있는 도구 (ex: 프론트 + 백 + DB 한 번에 실행) |
| git | Git 설치 – GitHub에서 프로젝트를 clone 하려면 필요 |
| unzip | 압축파일(.zip)을 풀기 위한 유틸리티 (간단한 파일 배포나 인증서 설치 등에 쓰임) |
🌟 1. Docker 작동 확인
docker --version
- 🔍 설치된 Docker 버전이 출력되면 OK
docker ps
- 🔍 실행 중인 컨테이너가 없으면 빈 리스트 나오는 게 정상
🐳 Docker 실행 권한 오류 해결 가이드
❗ 오류 상황 : 현재 사용자가 docker 그룹에 속해 있지 않아 Docker 실행이 안 되는 상태입니다.
permission denied while trying to connect to the Docker daemon socket
✅ 해결 방법
👉 현재 유저를 docker 그룹에 추가 ($USER는 현재 로그인된 사용자를 의미)
sudo usermod -aG docker $USER
👉 세션 종료 (터미널 종료 또는 로그아웃)
exit # 터미널 종료
그리고 다시 SSH 접속:
ssh -i "my-key.pem" ubuntu@EC2-PUBLIC-IP
다시 docker ps 실행
: Docker 권한 문제 해결 완료

🌟 Git 작동 확인
git --version
✅ Docker Hub 이미지로 서버 배포 후 도메인 연결 확인하기 (2025.05.14 연결 확인)
(1) EC2 인스턴스에 SSH 접속
ssh -i "키.pem" ubuntu@ec2-탄-력-적-ip.ap-northeast-2.compute.amazonaws.com
(2) Docker 설치 확인 및 이미지 조회
docker images
(3) Docker Hub에서 httpd 이미지 가져오기
docker pull httpd

(4) docker image 확인
docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
httpd latest 0208f149a449 3 months ago 148MB
(5) httpd 컨테이너 실행
-p 80:80 옵션은 EC2의 80번 포트를 컨테이너의 80번 포트로 연결
docker run -d --name httpd -p 80:80 httpd
(6) 컨테이너 실행 확인
docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
0f22db0ea0ec httpd "httpd-foreground" 2 seconds ago Up 1 second 80/tcp httpd
(7) EC2 보안 그룹 설정
📂 EC2 > 보안 그룹 > 인바운드 규칙 편집 > 80 포트 추가


(8) 탄력적 IP 주소로 접속 테스트 (http://탄력적 IP/ 접속)

(9) 도메인 연결 상태 확인 (Route53 : http://vybz.kr/)

☁️ 내 도메인(vybz.kr)이 정상적으로 연결되었는지 확인하는 법
(1) https://www.whatsmydns.net/ 접속
(2) 검색창에 vybz.kr 입력, 레코드 종류(A, CNAME 등) 선택 → 주로 A 레코드 선택

(4) 조회 버튼 클릭 → 전 세계 DNS 서버에서의 결과 확인 가능

💡배포할 서비스 구축해서 혼자 CI/CD 연습
(1) eureka / gateway / auth-service 프로젝트 생성
(2) 서비스에 해당하는 repository 생성 후 프로젝트 연동




🐳 Eureka 프로젝트 Dockerfile 쉽게 이해하기
📦 Dockerfile이란?
- Dockerfile은 '이미지 만들기'를 위한 레시피입니다.
- 도커 컨테이너를 만들려면 먼저 "이미지"가 필요해요.
- 이미지는 코드, 설정, 실행 방법 등을 포함한 패키지예요.
- 이 이미지를 어떻게 만들지 적는 것이 바로 Dockerfile입니다.
eureka 프로젝트 Dockerfile 전체 코드 :
FROM gradle:8.4-jdk17 AS builder
COPY . /app
WORKDIR /app
RUN gradle clean build -x test
FROM openjdk:17-jdk-slim
WORKDIR /app
COPY --from=builder /app/build/libs/*-SNAPSHOT.jar ./app.jar
EXPOSE 8761
ENTRYPOINT ["java", "-jar", "app.jar"]
[ 1단계 ] 앱을 빌드(=포장 준비)하는 단계
FROM gradle:8.4-jdk17 AS builder
- gradle이 이미 설치되어 있는 이미지(환경)를 사용
- Java 17도 포함되어 있어서 코드를 바로 빌드할 수 있다
- AS builder는 "이 빌드 결과를 나중에 가져올게요!"라는 뜻
COPY . /app
- 내 컴퓨터의 현재 폴더(=소스코드)를 컨테이너 안 /app 폴더로 복사
WORKDIR /app
- 앞으로의 명령어는 /app 폴더 안에서 실행
RUN gradle clean build -x test
- Gradle로 프로젝트를 빌드
- -x test는 테스트 코드는 실행하지 않고 빌드만 하겠다는 뜻
- 빌드하면 JAR 파일이 build/libs 안에 생긴다
[ 2단계 ] 앱을 가볍고 빠르게 실행하는 단계
FROM openjdk:17-jdk-slim
- 실행용으로 가볍고 빠른 Java 17 환경을 불러온다
- 빌드 도구나 잡다한 파일은 없는 슬림한 이미지
WORKDIR /app
- 실행 준비도 /app 폴더 안에서 진행
COPY --from=builder /app/build/libs/*-SNAPSHOT.jar ./app.jar
- 위에서 만든 JAR 파일을 가져옴
- --from=builder는 1단계에서 만든 결과를 가져오는 거고,
- *-SNAPSHOT.jar는 JAR 이름이 매번 바뀌어도 알아서 가져오게 한다
- 가져온 파일은 app.jar라는 이름으로 저장
EXPOSE 8761
- 이 컨테이너가 사용하는 포트를 열어줌
- Eureka 서버는 기본적으로 8761 포트를 사용
ENTRYPOINT ["java", "-jar", "app.jar"]
- 컨테이너가 실행될 때 자동으로 이 명령을 실행
- java -jar app.jar → JAR 파일을 실행해서 서버를 띄우는 명령
✅ 1. JAR 파일 빌드 완료 여부 확인
Gradle 빌드가 되어 있어야 .jar 파일이 생성되어 도커 이미지에 포함
./gradlew clean build -x test
✅ 2. 빌드 명령어 입력
docker build -t eureka-service .
| 옵션 | 설명 |
| -t eureka-service | 이미지 이름 지정 |
| . | 현재 디렉토리에 있는 Dockerfile 기준으로 빌드 |
✅ 3. 도커 이미지 생성 확인
docker images
# 실행 결과
REPOSITORY TAG IMAGE ID CREATED SIZE
eureka-service latest 7f40d2cb1c55 About a minute ago 460MB
✅ 4. git commit 및 push
git add .
git commit -m "eureka dockerfile 추가"
git push -u origin main
🌟 나머지 프로젝트도 동일하게 docker image 생성 후 커밋 및 푸시
gateway-service dockerfile :
FROM gradle:8.4-jdk17 AS builder
COPY . /app
WORKDIR /app
RUN gradle clean build -x test
FROM openjdk:17-jdk-slim
WORKDIR /app
COPY --from=builder /app/build/libs/*-SNAPSHOT.jar ./app.jar
EXPOSE 8000
ENTRYPOINT ["java", "-jar", "app.jar"]
auth-service dockerfile :
FROM gradle:8.4-jdk17 AS builder
COPY . /app
WORKDIR /app
RUN gradle clean build -x test
FROM openjdk:17-jdk-slim
WORKDIR /app
COPY --from=builder /app/build/libs/*-SNAPSHOT.jar ./app.jar
EXPOSE 8100
ENTRYPOINT ["java", "-jar", "app.jar"]
auth-service > HealthCheckController
package com.practice.auth_service.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class HealthCheckController {
@GetMapping("/ping")
public String ping() {
return "pong from auth-service!";
}
}
🧱 MSA 인프라 환경 구성하기 - Git Submodule + Docker Compose
(1) msa-infra 레파지토리 생성

(2) msa-infra 레포지토리 생성 및 클론
먼저 모든 서비스를 통합 관리할 msa-infra 레포를 준비
git clone https://github.com/jijihorang/msa-infra.git
cd msa-infra
🔍 Submodule이란?
- Git 저장소 안에 또 다른 Git 저장소를 포함시키는 기능
- 즉, 하나의 레포(Git 프로젝트) 안에서 다른 레포를 하위 폴더처럼 연결해서 관리하는 기능
📦 언제 사용하냐?
✅ 대표적인 케이스
- 여러 마이크로서비스가 각각 독립된 레포로 운영됨
- 하지만 이들을 한곳에 모아 통합 배포해야 할 때
(3) 서비스별 Submodule 추가
아래 명령어로 원하는 마이크로서비스를 msa-infra에 연결
git submodule add https://github.com/jijihorang/msa-eureka-service.git
git submodule add https://github.com/jijihorang/msa-auth-service.git
git submodule add https://github.com/jijihorang/msa-gateway-service.git

(4) Docker Compose 설정
docker-compose.yml 파일을 만들어 Eureka + Gateway + Auth Service를 한 번에 실행할 수 있도록 구성
version: '3.8' # Docker Compose 파일의 버전
services:
# 서비스 1: Eureka (서비스 레지스트리 역할)
eureka:
build:
context: ./msa-eureka-service # 이 디렉토리에 있는 Dockerfile을 기준으로 빌드
ports:
- "8761:8761" # 로컬 포트 8761 → 컨테이너 포트 8761 (Eureka 대시보드)
container_name: eureka # 컨테이너 이름 지정
# 서비스 2: Gateway (API Gateway 역할, 모든 요청의 진입점)
gateway:
build:
context: ./msa-gateway-service # 이 디렉토리에서 Dockerfile로 빌드
ports:
- "8000:8000" # 로컬 8000포트를 Gateway 컨테이너와 연결
container_name: gateway # 컨테이너 이름 설정
depends_on:
- eureka # Gateway는 Eureka가 먼저 실행되어야 시작됨
environment:
- SPRING_PROFILES_ACTIVE=${SPRING_PROFILES_ACTIVE:-local} # spring.profile 설정 (기본값은 local)
# 서비스 3: Auth (로그인/회원가입 등 인증 서비스)
auth:
build:
context: ./msa-auth-service # Auth 서비스 빌드 경로
ports:
- "8100:8100" # 로컬 포트 8100 → 컨테이너 포트 8100
container_name: auth # 컨테이너 이름 설정
depends_on:
- eureka # Auth도 Eureka가 먼저 떠 있어야 등록 가능
environment:
- SPRING_PROFILES_ACTIVE=${SPRING_PROFILES_ACTIVE:-local} # Spring 실행 환경 설정
- DB_PASSWORD=${DB_PASSWORD:-1234} # DB 연결 시 사용할 비밀번호 (기본값은 1234)
📝 주요 설정 설명
| 항목 | 설명 |
| build.context | 해당 서비스의 Dockerfile 위치 |
| depends_on | 특정 컨테이너가 먼저 실행되어야 이 서비스가 시작됨 |
| environment | Spring Boot의 application-{profile}.yml 적용, DB 연결 등 환경변수 전달 |
| container_name | 실행 시 컨테이너 이름 고정 |
♻️ depends_on:
- 이건 해당 컨테이너(auth)가 실행되기 전에, 먼저 eureka 컨테이너가 실행되도록 실행 순서를 지정하는 설정이다
♻️ environment:
- 컨테이너에 환경변수를 주입하는 부분
| 환경 변수 | 설명 |
| SPRING_PROFILES_ACTIVE=local | Spring Boot에서 application-local.yml을 사용하라는 의미 |
| DB_PASSWORD=${DB_PASSWORD} | .env 파일이나 시스템 환경변수에서 DB_PASSWORD 값을 가져와서 사용함 |
(5) 서비스 전체 실행
아래 명령어 한 줄이면 세 개의 서비스를 빌드 + 실행
- --build: Dockerfile을 기준으로 이미지 다시 빌드
- -d: 백그라운드 모드
docker-compose up --build -d
🧪 docker-compose.yml란?
- docker-compose.yml은 '이미지들을 가지고 어떻게 실행할지'를 정리한 구성 파일입니다.
- 프로젝트에 서비스가 하나뿐이면 docker run 명령만으로 충분하지만,
- Eureka + Gateway + Service1 + DB + Redis + Nginx 등 여러 개를 같이 실행하려면 각 컨테이너를 어떻게 연결하고 설정할지 파일로 정리해두는 게 편합니다.
🔧 docker-compose.yml이 필요한 이유
| 항목 | 설명 |
| 💼 여러 컨테이너를 한 번에 실행 | ex. Eureka, Service, DB 등 |
| 📜 설정을 코드로 관리 | 포트, 환경변수, 볼륨 등 |
| 🛠️ 복잡한 실행 명령 없이 배포 | docker-compose up만 입력하면 끝 |
| 🔁 재사용 가능 | 테스트, 배포 환경에서도 그대로 사용 가능 |
🚀 Docker Hub를 이용한 EC2 수동 배포 가이드 (Spring Boot + MSA + Docker)
MSA 프로젝트를 실제 EC2 서버에 배포할 때,
가장 기본적이면서 확실한 방식은 Docker Hub에 이미지를 올리고, EC2에서 docker-compose로 실행하는 방법이다.
이번 글에서는 Eureka, Gateway, Auth 세 가지 서비스를 예시로 Docker Hub를 통한 EC2 배포 전체 흐름을 단계별로 정리
(1) Docker Hub 로그인
docker login
(2) 이미지 빌드 및 Docker Hub에 푸시
- 아래와 같이 서비스별로 이미지를 빌드하고, 태그를 붙인 뒤 Docker Hub로 푸시
dockerhub_id는 본인의 Docker Hub 사용자 이름으로 변경 !
# eureka-service
docker build -t eureka-service ./msa-eureka-service
docker tag eureka-service dockerhub_id/eureka-service:latest
docker push dockerhub_id/eureka-service:latest
# gateway-service
docker build -t gateway-service ./msa-gateway-service
docker tag gateway-service dockerhub_id/gateway-service:latest
docker push dockerhub_id/gateway-service:latest
# auth-service
docker build -t auth-service ./msa-auth-service
docker tag auth-service dockerhub_id/auth-service:latest
docker push dockerhub_id/auth-service:latest

⚠️ Mac 사용자 주의 : exec format error 발생 시
만약 로컬(Mac M1/M2)에서 위 명령으로 이미지를 빌드하고 EC2에서 실행했는데 exec format error가 발생했다면?
👉 원인은 아키텍처 차이이다:
| 환경 | 아키텍처 | 설명 |
| Mac (M1, M2) | arm64 | 로컬에서 빌드된 Docker 이미지 = ARM 기반 |
| AWS EC2 (t2 등) | amd64 | EC2는 일반적인 x86 기반 CPU 사용 |
| 결과 | ❌ 오류 발생 | 이미지 실행 불가 (아키텍처 불일치) |
✅ 해결 방법: --platform 명시
이미지를 빌드할 때 --platform linux/amd64 옵션을 추가하면 EC2 호환 x86 이미지로 빌드됩니다.
또한 buildx를 활용하면 자동으로 푸시까지 가능:
# eureka-service
docker buildx build --platform linux/amd64 -t dockerhub_id/eureka-service:latest ./msa-eureka-service --push
# gateway-service
docker buildx build --platform linux/amd64 -t dockerhub_id/gateway-service:latest ./msa-gateway-service --push
# auth-service
docker buildx build --platform linux/amd64 -t dockerhub_id/auth-service:latest ./msa-auth-service --push
📦 핵심 키워드
- --platform linux/amd64 → EC2 호환 이미지로 빌드
- --push → buildx는 로컬 저장 없이 바로 푸시
(3) 로컬에서 EC2로 docker-compose.yml 전송
scp -i ~/Desktop/key/VYBZ.pem ~/msa-infra/docker-compose.yml ubuntu@3.38.58.133:/home/ubuntu/msa-infra/
(4) EC2 접속
ssh -i "키.pem" ubuntu@ec2-탄-력-적-I-P.ap-northeast-2.compute.amazonaws.com
(5) ec2에 docker-compose.yml 확인
cat docker-compose.yml
version: '3.8' # Docker Compose 파일 버전 지정
services:
eureka :
image: dockerhub_id/eureka-service:latest
ports:
- "8761:8761"
container_name: eureka
networks:
- msa-network
gateway :
image: dockerhub_id/gateway-service:latest
ports:
- "8000:8000"
container_name: gateway
networks:
- msa-network
auth:
image: dockerhub_id/auth-service:latest
ports:
- "8100:8100"
container_name: auth
depends_on:
- eureka
- mysql
environment:
- SPRING_PROFILES_ACTIVE=${SPRING_PROFILES_ACTIVE:-local}
- DB_PASSWORD=password
networks:
- msa-network
healthcheck:
test: [ "CMD", "mysqladmin", "ping", "-h", "localhost" ]
interval: 10s
timeout: 5s
retries: 5
mysql:
image: mysql:8.0
container_name: mysql
environment:
MYSQL_ROOT_PASSWORD: password
MYSQL_DATABASE: msa-practice
ports:
- "3306:3306"
volumes:
- mysql-data:/var/lib/mysql
networks:
- msa-network
networks:
msa-network:
volumes:
mysql-data:
(6) 이미지 가져오고 실행
docker-compose pull # Docker Hub에서 이미지 가져오기
docker-compose up -d # 백그라운드 실행
(7) 컨테이너 실행 확인
docker ps
(8) 전체 초기화 후 재실행 (문제 발생 시)
docker-compose down --rmi all --volumes --remove-orphans
docker-compose pull
docker-compose up -d
(9) 로그 확인
docker logs eureka
docker logs auth
docker logs gateway
(10) 보안 그룹 설정
AWS EC2 콘솔에서 인바운드 규칙에 다음 포트를 추가 :
| 포트 | 설명 |
| 8761 | Eureka Dashboard |
| 8000 | Gateway |
| 8100 | Auth |
| 3306 | MySQL (선택적) |

(11) 서비스 접속 확인
- Eureka Dashboard
👉 http://vybz.kr:8761

- Auth Health Check
👉 http://vybz.kr:8100/ping

🚀 GitHub Actions로 EC2에 자동 배포하기 (Docker Hub 기반)
Spring Boot 기반 MSA 서비스들을 Docker Hub에 푸시하고, EC2 서버에서 자동으로 pull & 실행하는 방식
(1) GitHub Secrets 설정
먼저 GitHub에 민감 정보를 등록
🔐 위치
msa-infra 레포 → Settings → Secrets and variables → Actions → New repository secret
✅ 등록할 Secrets
| 이름 | 설명 |
| DOCKER_USERNAME | Docker Hub 사용자명 |
| DOCKER_PASSWORD | Docker Hub 비밀번호 또는 액세스 토큰 |
| EC2_HOST | EC2 퍼블릭 IP or 도메인 (예: 3.22.51.132) |
| EC2_USER | EC2 접속 계정명 (보통 ubuntu) |
| EC2_SSH_KEY | EC2 접속용 PEM 키 전체 내용 |

⚠️ ssh_key 터미널에서 열어서 복사 붙여넣기
cat ~/Desktop/key/MyKey.pem
-----BEGIN RSA PRIVATE KEY-----
블라 블라 블라 블라 블라 블라 블라 블라
블라 블라 블라 블라 블라 블라 블라 블라
블라 블라 블라 블라 블라 블라 블라 블라
-----END RSA PRIVATE KEY-----%
(2) GitHub Actions 설정 (.github/workflows/deploy.yml)
msa-infra 프로젝트 루트에 .github/workflows/deploy.yml 파일 생성
name: CI/CD Docker Deploy to EC2
on:
push:
branches:
- main
jobs:
build:
runs-on: ubuntu-latest
steps:
# 1. GitHub 리포지토리 체크아웃
- name: Checkout code
uses: actions/checkout@v4
with:
submodules: recursive
# 2. Docker Hub 로그인
- name: Log in to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
# 3. 도커 이미지 빌드 & 푸시 - eureka-service
- name: Build & Push eureka-service
working-directory: ./msa-eureka-service
run: |
docker build -t ${{ secrets.DOCKER_USERNAME }}/eureka-service .
docker push ${{ secrets.DOCKER_USERNAME }}/eureka-service
# 4. 도커 이미지 빌드 & 푸시 - gateway-service
- name: Build & Push gateway-service
working-directory: ./msa-gateway-service
run: |
docker build -t ${{ secrets.DOCKER_USERNAME }}/gateway-service .
docker push ${{ secrets.DOCKER_USERNAME }}/gateway-service
# 5. 도커 이미지 빌드 & 푸시 - auth-service
- name: Build & Push auth-service
working-directory: ./msa-auth-service
run: |
docker build -t ${{ secrets.DOCKER_USERNAME }}/auth-service .
docker push ${{ secrets.DOCKER_USERNAME }}/auth-service
# 6. EC2에 SSH 접속 & 배포
- name: Deploy to EC2 via SSH
uses: appleboy/ssh-action@v1.0.0
with:
host: ${{ secrets.EC2_HOST }}
username: ${{ secrets.EC2_USER }}
key: ${{ secrets.EC2_SSH_KEY }}
script: |
cd ~/msa-infra
docker-compose down --rmi all --volumes --remove-orphans
docker-compose pull
docker-compose up -d
docker image prune -f
(3) git actions 확인하기 위해 auth-service > controller > HealthCheckController 수정
@RestController
public class HealthCheckController {
@GetMapping("/ping")
public String ping() {
return "git actions + discord 연동 후 알림이 가는지 확인해보자 !"; // 변경 후 확인해보자 !
}
}
(4) 변경 사항 커밋 & 푸시
🔁 1. msa-auth-service 레포에서 커밋 & 푸시
git add .
git commit -m "fix : HealthCheckController"
git push -u origin main
🔁 2. msa-infra 레포에서 submodule 업데이트
- 이제야 msa-infra의 변경이 GitHub에 반영되므로, .github/workflows 기준으로 GitHub Actions가 동작
git add vybz-auth
git commit -m "chore: update submodule - auth-service"
git push origin main
(5) 결과 확인
💻 EC2 접속 없이 바로 확인!
- http://vybz.kr:8761 → Eureka 서버
- http://vybz.kr:8100/ping → 변경된 /ping 응답 확인
🔔 GitHub Actions + Discord 연동으로 배포 알림 받기
CI/CD 자동화는 끝이 아니다.
실제 배포가 잘 되었는지, 실패했는지 바로 알 수 있어야 진짜 자동화라고 생각한다 !
이번에는 GitHub Actions를 통해 EC2에 배포한 뒤, Discord 채널에 자동으로 알림이 가도록 설정하는 방법 알아보자 !
(1) Discord에서 웹훅(Webhook) 생성
1. 디스코드 서버에서 우측 상단 서버 설정 클릭

2. 앱 설정 > 연동 메뉴로 이동

3. 웹후크 탭에서 새 웹후크 만들기 클릭

4. 이름, 채널 설정 후 웹후크 URL 복사

(2) GitHub Secrets에 웹후크 URL 등록
📂 msa-infra 레포 → Settings → Secrets and variables → Actions → New repository secret

(3) ./deploy.yml에 추가 (7번 참고)
name: CI/CD Docker Deploy to EC2
on:
push:
branches:
- main
jobs:
build:
runs-on: ubuntu-latest
steps:
# 1. GitHub 리포지토리 체크아웃
- name: Checkout code
uses: actions/checkout@v4
with:
submodules: recursive
# 2. Docker Hub 로그인
- name: Log in to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
# 3. 도커 이미지 빌드 & 푸시 - eureka-service
- name: Build & Push eureka-service
working-directory: ./msa-eureka-service
run: |
docker build -t ${{ secrets.DOCKER_USERNAME }}/eureka-service .
docker push ${{ secrets.DOCKER_USERNAME }}/eureka-service
# 4. 도커 이미지 빌드 & 푸시 - gateway-service
- name: Build & Push gateway-service
working-directory: ./msa-gateway-service
run: |
docker build -t ${{ secrets.DOCKER_USERNAME }}/gateway-service .
docker push ${{ secrets.DOCKER_USERNAME }}/gateway-service
# 5. 도커 이미지 빌드 & 푸시 - auth-service
- name: Build & Push auth-service
working-directory: ./msa-auth-service
run: |
docker build -t ${{ secrets.DOCKER_USERNAME }}/auth-service .
docker push ${{ secrets.DOCKER_USERNAME }}/auth-service
# 6. EC2에 SSH 접속 & 배포
- name: Deploy to EC2 via SSH
uses: appleboy/ssh-action@v1.0.0
with:
host: ${{ secrets.EC2_HOST }}
username: ${{ secrets.EC2_USER }}
key: ${{ secrets.EC2_SSH_KEY }}
script: |
cd ~/msa-infra
docker-compose down --rmi all --volumes --remove-orphans
docker-compose pull
docker-compose up -d
docker image prune -f
# 7-1. 성공 시 알림
- name: Send Discord Success Notification
if: success()
uses: Ilshidur/action-discord@master
env:
DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }}
with:
args: |
✅ [${{ github.actor }}]님이 `${{ github.repository }}` 레포지토리에서 **배포를 완료**했어요!
🔗 커밋: ${{ github.sha }}
# 7-2. 실패 시 알림
- name: Send Discord Failure Notification
if: failure()
uses: Ilshidur/action-discord@master
env:
DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }}
with:
args: |
❌ [${{ github.actor }}]님이 `${{ github.repository }}` 레포지토리에서 **배포에 실패**했어요!
🔍 에러 로그를 확인해주세요.
🔔 알림 메시지 예시
성공 시:
✅ [choejiho]님이 `jijihorang/msa-infra` 레포지토리에서 배포를 완료했어요!
🔗 커밋: 2bcbd41df28e4b...

실패 시:
❌ [choejiho]님이 `jijihorang/msa-infra` 레포지토리에서 배포에 실패했어요!
🔍 에러 로그를 확인해주세요.
'Study > TIL | AWS' 카테고리의 다른 글
| Route53부터 Certbot까지 : HTTPS 서버 구축 초기 과정 (2) | 2025.07.21 |
|---|---|
| EC2 인스턴스 메모리 부족 문제 해결기 (2) | 2025.07.14 |
| EC2 인스턴스 EBS 볼륨 확장 및 파일 시스템 확장 방법 (0) | 2025.06.15 |
| AWS S3 사용 전 꼭 알아야 할 IAM 권한 설정 가이드 (2) | 2025.06.15 |
| 2차 개인 프로젝트 CI/CD 배포 자동화 구축 (0) | 2025.05.22 |