CI/CD 개념 이해
- Continuous Integration (CI): 지속적 통합으로 소스코드를 Docker 이미지로 빌드
- Continuous Deployment (CD): 지속적 배포로 이미지를 ECR에 업로드하고 Pod 재생성
배포 작업의 분류
일회성 작업 (한 번만 설정)
- RDS 생성
- Redis Pod/Service 생성
- ECR Repository 생성
- Kubernetes Secret 생성
- Ingress 생성
- HTTPS 인증서 생성
반복적 작업 (코드 변경 시마다)
- Docker 이미지 빌드
- Docker 이미지 Push
- Pod 재생성 (새 이미지 적용)
자동화가 필요한 이유
수동 배포의 문제점
- GitHub에서 최신 코드 Pull
- 로컬에서 Docker 이미지 빌드
- ECR 로그인
- ECR에 이미지 Push
- kubectl rollout restart 실행
실수 가능성이 높고 시간 소모적이다
자동화의 장점
- GitHub에 코드 Push만 하면
- GitHub Actions가 모든 작업 자동 수행
- 실수 방지, 일관된 배포 프로세스
GitHub Actions 핵심 개념
- Workflow: 자동화된 프로세스 전체 (YAML 파일로 정의)
- Event: Workflow를 트리거하는 조건 (예: push, pull_request)
- Job: 여러 step의 묶음
- Step: 개별 작업 단위
- Runner: Workflow를 실행하는 가상 서버
- Action: 재사용 가능한 작업 단위
Workflow 파일 위치
프로젝트-root/ ├── .github/ ← 이 이름은 고정 │ └── workflows/ ← 이 이름도 고정 │ └── deploy.yml ← 파일명은 자유 ├── src/ └── Dockerfile
중요: .github/workflows 경로는 Github와의 약속이다. 이 경로에 YAML 파일이 있으면 GitHub가 자동으로 인식한다

Runner (실행 환경)
GitHub Actions의 가상 PC
코드 Push
↓
GitHub Actions가 가상 PC 생성 (Ubuntu)
↓
환경 설정 (kubectl, AWS CLI 등)
↓
이미지 빌드 및 배포
↓
작업 완료 후 가상 PC 삭제
- 매번 새로운 가상 PC가 생성된다
- GitHub이 제공하는 클라우드 환경이다
- 개발자의 로컬 PC를 사용하지 않는다
Workflow 파일 구조 분석
deploy_order_with_k8s.yml
name: deploy order order-backend
on:
push:
branches:
- main # 본인의 브랜치명으로 변경 가능
jobs:
build-and-deploy:
runs-on: ubuntu-latest
steps:
- name: checkout github
uses: actions/checkout@v2
- name: install kubectl
uses: azure/setup-kubectl@v3
with:
version: "v1.25.9"
id: install
- name: configure aws
uses: aws-actions/configure-aws-credentials@v1
with:
aws-access-key-id: ${{ secrets.AWS_KEY }}
aws-secret-access-key: ${{ secrets.AWS_SECRET }}
aws-region: ap-northeast-2
- name: update cluster infomation
run: aws eks update-kubeconfig --name my-cluster --region ap-northeast-2
- name: Login to ECR
id: login-ecr
uses: aws-actions/amazon-ecr-login@v1
- name: build and push docker image to ecr
env:
REGISTRY: 123456789012.dkr.ecr.ap-northeast-2.amazonaws.com
REPOSITORY: order-backend
IMAGE_TAG: latest
run: |
docker build \
--platform linux/amd64 \
-t $REGISTRY/$REPOSITORY:$IMAGE_TAG \
-f ./ordersystem/Dockerfile ./ordersystem
docker push $REGISTRY/$REPOSITORY:$IMAGE_TAG
- name: eks kubectl apply
run: |
kubectl rollout restart deployment ordersystem-backend -n hyeok
Workflow 구성 요소 상세 설명
이벤트 정의 (on)
on:
push:
branches:
- main
main 브랜치에 코드가 Push 되면 Workflow 실행
다른 브랜치 예시
on:
push:
branches:
- dev # dev 브랜치로 변경 가능
다른 이벤트 예시
on: pull_request: # Pull Request 시 issues: # Issue 생성 시
Job 정의
jobs:
build-and-deploy:
runs-on: ubuntu-latest
- build-and-deploy: Job의 이름으로 임의로 지정이 가능하다
- runs-on: 가상 PC의 운영체제를 정한다
사용 가능한 runs-on 옵션
- ubuntu-latest (가장 일반적)
- windows-latest
- macos-latest
Step별 상세 설명
uses와 run
- uses: 미리 만들어진 Action 사용 (actions/checkout@v2)
- run: 직접 명령어 실행 (docker build …)
GitHub 소스코드 체크아웃
- name: checkout github uses: actions/checkout@v2
역할: “GitHub Repository의 소스코드를 가상 PC로 가져오기”로 git clone과 내부동작이 유사하다
kubectl 설치
- name: install kubectl
uses: azure/setup-kubectl@v3
with:
version: "v1.25.9"
id: install
역할: Kubernetes 명령어 도구 설치로 Pod 재생성을 위해 kubectl rollout restart 명령어를 실행하기 위해 필요하다
AWS 설정
- name: configure aws
uses: aws-actions/configure-aws-credentials@v1
with:
aws-access-key-id: ${{ secrets.AWS_KEY }}
aws-secret-access-key: ${{ secrets.AWS_SECRET }}
aws-region: ap-northeast-2
역할: AWS CLI 설치와 AWS 계정 인증 설정을 한다
Secret 참조
- ${{ secrets.AWS_KEY }}: GitHub Secret에 저장된 값 참조
- 소스코드에 민감 정보가 노출되지 않는다
EKS 클러스터 연결
- name: update cluster infomation run: aws eks update-kubeconfig --name my-cluster --region ap-northeast-2
역할: kubectl이 EKS 클러스터에 접근할 수 있도록 설정한다
클러스터 이름 변경: my-cluster를 본인의 클러스터 이름으로 변경
ECR 로그인
- name: Login to ECR id: login-ecr uses: aws-actions/amazon-ecr-login@v1
역할: Docker 이미지를 ECR에 Push하기 위한 인증
Docker 이미지 빌드 및 Push
- name: build and push docker image to ecr
env:
REGISTRY: 123456789012.dkr.ecr.ap-northeast-2.amazonaws.com
REPOSITORY: order-backend
IMAGE_TAG: latest
run: |
docker build \
--platform linux/amd64 \
-t $REGISTRY/$REPOSITORY:$IMAGE_TAG \
-f ./ordersystem/Dockerfile ./ordersystem
docker push $REGISTRY/$REPOSITORY:$IMAGE_TAG
- REGISTRY: ECR URI로 ECR Repository 주소 (본인 것으로 변경 필수)
- REPOSITORY: order-backend는 ECR Repository 이름
- IMAGE_TAG: latest는 이미지 태그
명령어 분석
docker build \ --platform linux/amd64 \ # ARM(M1 Mac) 호환성 해결 -t $REGISTRY/$REPOSITORY:$IMAGE_TAG \ # 이미지 이름 -f ./ordersystem/Dockerfile \ # Dockerfile 위치 ./ordersystem # 빌드 컨텍스트
Workflow는 항상 프로젝트 루트에서 실행되므로
- -f 옵션으로 Dockerfile 경로 명시 필수
- 빌드 컨텍스트 경로도 명시 필수
로컬 VS GitHub Actions
- 로컬
- 실행 위치: ordersystem/폴더내부
- 명령어: docker build -t … .
- GitHub Actions
- 실행 위치: 프로젝트 루트
- 명령어: docker build -t … -f ./ordersystem/Dockerfile ./ordersystem
Pod 재생성
- name: eks kubectl apply
run: |
kubectl rollout restart deployment ordersystem-backend -n hyeok
역할: ECR에 새 이미지가 올라갔으므로 Pod를 재시작하여 새 이미지를 Pull
주의사항
- Deployment 이름 (ordersystem-backend)은 depl_svc.yml의 이름과 일치해야 함
- Namespace (hyeok)도 본인의 네임스페이스로 변경
GitHub Secret 설정
Secret이 필요한 이유
# 문제 상황
aws-access-key-id: AKIAIOSFODNN7EXAMPLE # 노출 위험
# 해결
aws-access-key-id: ${{ secrets.AWS_KEY }} # 안전
Secret 등록 방법
GitHub Repository → Settings → Secrets and variables → Actions → New repository secret 클릭

Secret 추가 및 입력


IAM에서 확인
- AWS Console → IAM → 사용자
- 본인 사용자 선택 → 보안 자격 증명 탭
- 엑세스 키 생성 (없는 경우)
배포 실습
Git 초기화 (신규 프로젝트인 경우)
# 프로젝트 루트에서 실행 git init
기존 .git 제거
다른 Repository에서 클론한 경우나 필요한 경우
# 기존 .git 폴더 삭제 rm -rf .git # 새로 초기화 git init
GitHub Repository 연결
# Repository 추가 git remote add origin https://github.com/your-username/your-repo.git # 브랜치를 main으로 변경 git checkout -b main # 확인 git branch
Workflow 파일 수정
수정해야 할 부분
# 1. 브랜치 이름 확인
on:
push:
branches:
- main # 본인의 브랜치명
# 2. ECR URI 변경
env:
REGISTRY: 123456789012.dkr.ecr.ap-northeast-2.amazonaws.com # 본인 ECR URI
# 3. Dockerfile 경로 확인
run: |
docker build \
-f ./ordersystem/Dockerfile ./ordersystem # 본인 프로젝트 경로
# 4. Namespace 변경
kubectl rollout restart deployment ordersystem-backend -n hyeok # 본인 namespace
첫 배포 실행
# 1. 모든 파일 추가 git add . # 2. 커밋 git commit -m "CI/CD 자동화 테스트" # 3. Push git push origin main

GitHub Actions 확인
- GitHub Repository → Actions 탭
- 실행 중인 Workflow 확인 (빙글빙글 돌아가는 아이콘)
- Workflow 클릭하여 각 Step 로그 확인

배포 (Pod 상태) 확인
kubectl get pods -n hyeok # 예상 결과 NAME READY STATUS RESTARTS AGE ordersystem-backend-56975q86qq-2q7qq 1/1 Running 0 77s ordersystem-backend-56975q86qq-qqqqq 1/1 Running 0 51s
AGE가 짧으면 새로 생성된 Pod이다
코드 변경 및 자동 배포 테스트
코드 수정
@RestController
public class HealthController {
@GetMapping("/health")
public String healthCheck() {
return "ok2"; // ok1 → ok2로 변경
}
}
배포
git add . git commit -m "health check 응답 변경" git push origin main
자동화 프로세스
코드 Push
↓
GitHub Actions 자동 트리거
↓
├─ 소스코드 체크아웃
├─ kubectl 설치
├─ AWS 설정
├─ 클러스터 연결
├─ ECR 로그인
├─ 이미지 빌드 (변경된 코드 포함)
├─ ECR Push
└─ Pod 재생성 (새 이미지로)
↓
배포 완료
변경 사항 확인
ECR 확인
- AWS Console → ECR → Repository
- 새 이미지가 ‘latest’ 태그로 Push 됨
- 이전 이미지는 태그가 제거됨

API 테스트
GET https://server.hyeok9244.shop/health → 응답: "ok2" (변경된 값)
트러블 슈팅
문제 1: Actions 실행 안됨
증상: Push 했는데 Actions 탭에 아무것도 안 나타나는 경우로 Workflow 파일 경로 오류이거나 브랜치 이름이 불일치한 경우이다
# 경로 확인
ls .github/workflows/
# 브랜치 확인
git branch
# Workflow 파일의 브랜치 설정 확인
on:
push:
branches:
- main # 현재 브랜치와 일치해야 함
문제 2: AWS 인증 실패
증상: Error: The security token included in the request is invalid으로 원인은 GitHub Secret의 AWS 키가 잘못 된 경우
- GitHub → Settings → Secrets and variables 확인
- AWS_KEY, AWS_SECRET 값 재확인
- IAM에서 새 엑세스 키 생성 후 재등록
문제 3: Docker 빌드 실패
증상 1: no match for platform in manifest으로 원인은 ARM(M1 Mac)아키텍처 문제이다
docker build \ --platform linux/amd64 \ # 이 줄 추가 -t $REGISTRY/$REPOSITORY:$IMAGE_TAG \

배포가 2개가 된 이유는 .github/workflow의 디렉터리에 yml 파일이 2개였기 때문이다 (처음에는 몰랐다)
증상 2: failed to solve: openjdk:17-jdk… Error: Process completed with exit code 1.

Dockerfile # 필요프로그램 설치 # FROM openjdk:17-jdk-alpine as stage1 에러의 원인 FROM eclipse-temurin:17-jdk-jammy as stage1 # 변경

문제 4: kubectl 명령어 실패
증상: error: You must be logged in to the server으로 클러스터 이름의 오류가 원인이다
run: aws eks update-kubeconfig --name my-cluster # 실제 클러스터 이름으로 변경
클러스터 이름 확인
aws eks list-clusters --region ap-northeast-2
로그 확인 방법
- Repository → Actions
- 실패한 Workflow 클릭
- 실패한 Step 클릭
- 상세 에러 로그 확인
Pod 로그 (배포 후)
kubectl logs -f <pod-name> -n hyeok
CI/CD 흐름 정리
[개발자]
소스코드 수정
↓
git push origin main
↓
[GitHub Actions - 가상 PC]
├─ 1. 소스코드 체크아웃 (git clone)
├─ 2. kubectl 설치
├─ 3. AWS CLI 설치 및 인증
├─ 4. EKS 클러스터 연결
├─ 5. ECR 로그인
├─ 6. Docker 이미지 빌드
├─ 7. ECR에 이미지 Push
└─ 8. Pod 재생성 (rollout restart)
↓
[Kubernetes]
새 이미지로 Pod 재생성
(무중단 롤링 업데이트)
↓
[완료]
사용자는 새 버전 사용

반복 작업 vs 일회성 작업
매 배포마다 실행 (자동화)
- 소스코드 체크아웃
- 환경 설정 (kubectl, AWS CLI)
- 이미지 빌드
- ECR Push
- Pod 재생성
한 번만 실행 (수동)
- Github Secret 등록
- Workflow 파일 작성
- ECR Repository 생성
- EKS 클러스터 생성
- Deployment, Service, Ingress 생성
실무 팁
브랜치 전략
# 개발 환경
on:
push:
branches:
- dev
# 프로덕션 환경
on:
push:
branches:
- main
팀 협업 시
- dev 브랜치: 개발 서버 자동 배포
- main 브랜치: 운영 서버 자동 배포
- Pull Request: 코드 리뷰 후 Merge
이미지 태그 전략
IMAGE_TAG: latest # 현재 방식
IMAGE_TAG: ${{ github.sha }} # Git commit SHA 사용
장점으로는 각 배포마다 고유한 이미지 태그가 생성되고 롤백이 수비다
슬랙 알람 추가 (선택 사항)
- name: Slack Notification
uses: 8398a7/action-slack@v3
with:
status: ${{ job.status }}
webhook_url: ${{ secrets.SLACK_WEBHOOK }}