🔧 CI/CD가 뭐야?
- CI (지속적 통합, Continuous Integration)
→ 개발자가 코드를 푸시(push)할 때마다 자동으로 테스트하거나 빌드하는 것.- 어떤 테스트? 코드가 잘 작동하는지 자동으로 검증하는 것
- 어떤 빌드? 소스 코드를 실제 실행 가능한 파일로 변환하는 것
- 즉, 코드가 정상 동작한다고 확인
- CD (지속적 배포, Continuous Deployment)
→ 코드가 문제 없다면 자동으로 서버나 클라우드에 배포하는 것.- 예를 들어 깃허브 액션을 사용해서 문제가 없다면 웹페이지에 실제 서비스에 반영되는 것을 배포라고 함
- 즉, 확인된 코드를 웹서버, 클라우드, AWS EC2 등에 자동 반영하는 것을 말함
즉, 코드를 바꾸면 -> 자동으로 테스트하고 -> 자동으로 서버에 반영되는 시스템
🔗 GitHub Actions가 뭐야?
GitHub 자체에서 제공하는 자동화 시스템
우리는 이를 이용해서 아래처럼 설정할 수 있음:
GitHub Actions = CI + CD
CI: 코드 테스트와 빌드를 자동으로 진행하는 역할을 함.
즉, 코드가 푸시되면 자동으로 테스트를 실행하고, 빌드를 돌려 문제가 없는지 확인함
CD: CI가 완료되면 자동으로 배포도 가능함. 예를 들어, 코드가 정상이라면, 자동으로 서버에 배포하여 실시간 서비스에 반영할 수 있음
즉, CI와 CD를 깃허브 액션으로 하나의 파이프라인에서 자동화할 수 있음.
하지만 여기서는 깃허브 액션을 CI 위주로 두고 실습을 할 예정임
누가 main 브랜치에 푸시하면 → 테스트하고 → 빌드하고 → 서버에 배포해 줘!
이걸 하기 위해서는 .github/workflows 폴더에 main.yml 같은 설정 파일을 만들면 됨!
여기서 중요한 건 파일을 저장할 때 꼭 yml이나 yaml파일로 저장해야 된다는 점!!
📁 폴더/파일 구조
/my-project
├── .github
│ └── workflows
│ └── main.yml ← 여기에 CI/CD 설정!
├── src/
└── Dockerfile
✅ 공통점 (GitHub Actions vs Jenkins)
🎯 자동화 도구 | 둘 다 "코드 변경 → 테스트/빌드/배포 자동 실행"을 해주는 CI/CD 도구 |
🛠️ 작업 구성 방식 | 둘 다 YAML 또는 스크립트 파일로 어떤 작업을 할지 정의함 |
⚙️ 플러그인/액션 존재 | 외부 도구(Git, Docker, AWS 등)와 연동할 수 있는 플러그인 또는 액션이 많음 |
⛓️ 빌드 파이프라인 구성 | 여러 작업(Job)을 순서대로 실행하는 파이프라인을 구성할 수 있음 |
✅ 차이점 (GitHub Actions vs Jenkins)
📦 설치 | GitHub에 내장되어 있어, 따로 설치할 필요 없음 | 직접 서버에 설치해야 해 (EC2, PC 등) |
🌐 연동 | GitHub에서 코드 변경 감지가 자동 | GitHub 연동은 별도 설정 필요 (Webhook 등) |
🛠️ 유지관리 | GitHub가 관리해줌 (서버 운영 불필요) | 서버 직접 관리해야 함 (버전 업데이트, 백업 등) |
🔌 확장성 | GitHub Marketplace에 있는 Action 사용 | Jenkins는 Plugin 사용 (더 다양하고 강력) |
💰 비용 | 개인/소규모는 무료 (분당 제한 있음) | Jenkins는 설치는 무료지만 서버 운영비가 듦 |
UI | GitHub 웹 UI에서 쉽게 사용 가능 | Jenkins는 전용 대시보드에서 관리함 |
플러그인(Plugin)이란?
- 기본 기능에 새로운 기능을 덧붙일 수 있는 확장 프로그램임
- 컴퓨터나 핸드폰 앱에 추가 기능을 붙이는 도구라고 보면 됨
GitHub Actions에서의 “Action”이란?
- CI/CD 자동화 작업을 구성하는 작은 명령 블록임
- 자동화 파이프라인 안에서 할 일 하나하나를 대신 수행해 주는 코드 조각이라고 보면 됨
EKS 클러스터 구성
LB controller도 설치
사용자이름 : user
암호 : test1234
암호화 x
초기 DB이름 : db
퍼블릭액세스 : 예
되도록이면 같은 VPC에 서브넷은 퍼블릭서브넷
보안그룹 source 0.0.0.0/0 포트 3306
pri에 있는 db를 강제로 pub으로 바꿔주기


https://github.com/oolralra/svelte-fast
- svelte - fastapi로 만든 앱.
- 이걸 fork 해서 가져오기


git clone <본인레포>/svelte-fast

- frontend 빼고 나머지 다 백엔드 관련 파일
apt install mysql-client-core-8.0
- mysql 명령어 설치
mysql -u user -ptest1234 -h <본인 RDS주소>

- 본인 RDS로 수정
그 앞에 user는 아이디
test1234는 비번임

- 접속되는지 확인
docker build -t backend:1 .
# 백엔드 앱 이미지빌드
docker run -dp 8000:8000 --name back backend:1
# 컨테이너 실행





- 필요하다면 자기 vm ip 넣어주기

root@aws-cli:~/svel-fast/frontend# docker build -t frontend:1 .
- 프론트엔드 앱 이미지빌드
root@aws-cli:~/svel-fast/frontend# docker run -dp 80:5173 --name front frontend:1
실습) ECR을 사용하여 이런 형태로 만들어서 NLB로 접속 가능하게 만들어보세요!
ECR 리포지토리 생성
aws ecr create-repository --repository-name web-front
aws ecr create-repository --repository-name web-back
로그인 (Amazon ECR 인증)
aws ecr get-login-password | docker login --username AWS --password-stdin <account>.dkr.ecr.<region>.amazonaws.com
태그 변경
docker tag frontend:1 922805825674.dkr.ecr.ap-northeast-2.amazonaws.com/web-front:1
docker tag backend:1 922805825674.dkr.ecr.ap-northeast-2.amazonaws.com/web-back:1
푸시
docker push 922805825674.dkr.ecr.ap-northeast-2.amazonaws.com/web-front:1
docker push 922805825674.dkr.ecr.ap-northeast-2.amazonaws.com/web-back:1
frontend Deployment/Service (ECR 이미지 사용) (type: LoadBalancer → NLB 생성)
apiVersion: v1
kind: Service
metadata:
name: svc-front
annotations:
alb.ingress.kubernetes.io/scheme: internet-facing
alb.ingress.kubernetes.io/target-type: ip
spec:
type: LoadBalancer
selector:
app: front
ports:
- port: 80
targetPort: 5173
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: dep-front
spec:
replicas: 1
selector:
matchLabels:
app: front
template:
metadata:
labels:
app: front
spec:
containers:
- name: front
image: 922805825674.dkr.ecr.ap-northeast-2.amazonaws.com/web-front:1
ports:
- containerPort: 5173
backend Deployment/Service (ECR 이미지 사용) (type: LoadBalancer → NLB 생성)
apiVersion: v1
kind: Service
metadata:
name: svc-backend
spec:
selector:
app: back
ports:
- port: 8000
targetPort: 8000
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: dep-backend
spec:
replicas: 1
selector:
matchLabels:
app: back
template:
metadata:
labels:
app: back
spec:
containers:
- name: back
image: 922805825674.dkr.ecr.ap-northeast-2.amazonaws.com/web-back:1
ports:
- containerPort: 8000


- 근데 앞에 실습을 하면 백엔드 연결이 안 되는 걸 알 수 있음

- 백엔드는 프라이빗한 곳에 있기 때문에 브라우저 입장에서는 찾아갈 수 없었다.
=> 해결법은 두 가지
1. 프론트를 띄운 nodejs앱에서 리버스프록시 코드를 추가
2. npm build를 통해 정적파일을 생성 후 nginx를 통해 리버스프록시.
앱 업데이트(CI 관점)
CI
1. 프로그래밍 언어로 짜인 코드를 수정
2. 새로 앱빌드
3. 새로 컨테이너이미지 빌드 = 이미지의 태그가 변경이 됐다는 뜻함.
4. 그렇다면 이미지의 태그가 변경이 됐다는 사실을 어디에 명시? => 매니페스트 파일에 명시
CD
5. argoCD가 이를 인지해서 자동으로 apply를 해준다.
root@aws-cli:~/svel-fast# cp -r frontend/ ~/frontend
# frontend 앱이 보이는 경로에서 디렉토리를 복사.

root@aws-cli:~/frontend# git init

- 여기는 깃허브의 로컬이 됨
git remote add origin https://github.com/YUMZII/src
- 아직 원격레포를 생성하진 않았지만 앞으로 만들 예정.

- 동기화된 상태는 아님
깃허브로 가서 레포지토리 만들기

- 깃허브에 레포만 생성하기
root@aws-cli:~/frontend# git add .
# 모든 변경사항 추가.
root@aws-cli:~/frontend# git commit -m "first"

- 아마 정보가 등록이 안되어 있을 것임
- 깃허브 아이디랑 이메일을 넣으면 됨
깃허브 토큰 넣어주기


aws ecr create-repository --repository-name frontend --region ap-northeast-2
- ECR 레포 생성
export ACCOUNT_ID= 922805825674
aws ecr get-login-password --region ap-northeast-2 | docker login --username AWS --password-stdin $ACCOUNT_ID.dkr.ecr.ap-northeast-2.amazonaws.com
- ECR 로그인
export FRONT=$ACCOUNT_ID.dkr.ecr.ap-northeast-2.amazonaws.com/frontend
- FRONT라는 이름으로 환경변수 처리.
docker build -t $FRONT:3 .
- 이렇게 사용가능
kubectl delete deploy,svc --all
- 기존 리소스 삭제
앱 배포를 위한 매니페스트
새로운 세션 복제해서
root@aws-cli:~# pwd
/root
root@aws-cli:~# mkdir deploy
root@aws-cli:~# cd deploy
root@aws-cli:~/deploy# vi deploy.yml
apiVersion: v1
kind: Service
metadata:
name: svc-front
annotations:
service.beta.kubernetes.io/aws-load-balancer-type: "nlb"
service.beta.kubernetes.io/aws-load-balancer-scheme: "internet-facing"
spec:
type: LoadBalancer
selector:
app: front
ports:
- port: 80
targetPort: 5173
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: dep-front
spec:
replicas: 1
selector:
matchLabels:
app: front
template:
metadata:
name: pod-front
labels:
app: front
spec:
containers:
- name: con-front
image: <내어카운트ID>.dkr.ecr.ap-northeast-2.amazonaws.com/frontend:1
root@aws-cli:~/frontend# echo $FRONT
922805825674.dkr.ecr.ap-northeast-2.amazonaws.com/frontend
- frontend 경로로 돌아와서
root@aws-cli:~/frontend# docker build -t $FRONT:1 .
root@aws-cli:~/frontend# docker push $FRONT:1

- 프론트만 잘 뜨는지 확인
그리고 깃허브에 src레포에 잘 생성된 걸 확인할 수 있음

root@aws-cli:~/deploy# cat deploy.yml
- 여기 경로에 있는 내용 복사해서
- 깃허브에 있던 dep디렉토리에 있던 deployment.yml파일 수정해주기

- 나중에 argoCD가 모니터링할 레포
apiVersion: v1
kind: Service
metadata:
name: svc-front
annotations:
service.beta.kubernetes.io/aws-load-balancer-type: "nlb"
service.beta.kubernetes.io/aws-load-balancer-scheme: "internet-facing"
spec:
type: LoadBalancer
selector:
app: front
ports:
- port: 80
targetPort: 5173
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: dep-front
spec:
replicas: 1
selector:
matchLabels:
app: front
template:
metadata:
name: pod-front
labels:
app: front
spec:
containers:
- name: con-front
image: 922805825674.dkr.ecr.ap-northeast-2.amazonaws.com/frontend:1
Github-Action
- 위 과정(CI, Continuous Integration)을 깃허브 액션을 통해 정의할 예정

- 패키징하고 통합하는 느낌

- 내가 직접 스크립트를 정의하겠다는 의미
name: fast CI/CD #이름
on: # on 언제 action을 동작시킬지
push: # push가 됐을때 동작시키겠다.
branches: [main] # 대상 브랜치.
paths-ignore: # push 이벤트가 발생해도 무시할 파일.
- '.gitignore'
- '.dockerignore'
- 메인브랜치에 push가 됐을 때 트리거가 될 예정
- 예외 할 디렉토리나 파일도 존재함
jobs:
ci:
runs-on: ubuntu-latest #깃액션이 동작하는 환경
steps:
- uses: actions/checkout@v4 #깃액션을 할 때 어떤걸 사용할지 모듈 형태로 만들어둔 걸 가져와서 사용
with:
fetch-depth: 1 #가장 최근 commit의 히스토리만 가져옴.
- checkout: 클론 한다는 의미임
- 다음 절차는 ECR에 push를 하기 위한 계정을 등록할 건데, ECR에 접근할 수 있는 최소한의 권한만 갖고 있는 계정을 생성해서 등록하는 게 좋음
- 절대 administrator 권한은 주면 안 됨




이 친구 추가해 주기







Access key ID,Secret access key
AKIA.... AWS_ACCESS_KEY_ID
GhNg3......AWS_SECRET_ACCESS_KEY

- 깃허브 토큰 것도 만들어주기
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v2
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ap-northeast-2
- aws configure와 비슷함
- 위에서 구성한 시크릿들은 secrets에 저장이 되어있음
- name: Login to Amazon ECR
id: login-ecr
uses: aws-actions/amazon-ecr-login@v2
- ECR에 로그인하기 위한 액션
- name: Set Variables
id: set-var
run: |
echo "ECR_REGISTRY=${{ steps.login-ecr.outputs.registry }}" >> $GITHUB_ENV
echo "ECR_REPOSITORY=frontend" >> $GITHUB_ENV #본인 ecr레포에 맞게 수정 frontend
echo "IMAGE_TAG=${{ github.run_number }}" >> $GITHUB_ENV -> 두번 액션 했을 경우 2로 됨
echo "GIT_EMAIL=rlarn2003@naver.com" >> $GITHUB_ENV
echo "GIT_NAME=YUMZII" >> $GITHUB_ENV
- 환경변수 선언 => GITHUB_ENV라는 파일에 저장해 놨다고 생각해도 좋음
-> 나중에 env로 호출 가능
- ${{ github.run_number }}= 깃허브액션에서 제공하는 액션넘버. CI/CD의 흐름을 이해하는 데 있어서 제일 중요한 포인트. "그래서 이걸 왜 바꿔줘야 하는데?"
-> ArgoCD에서 매니페스트 파일의 변경사항을 인지해야 하니까
- name: Docker Image Build
id: build-image
run: |
docker build -t ${{ env.ECR_REGISTRY }}/${{ env.ECR_REPOSITORY }}:${{ env.IMAGE_TAG }} .
docker build -t <레지스트리주소>/<레포이름>:<태그>
- name: Docker image Push
id: push-image
run: |
docker push ${{ env.ECR_REGISTRY }}/${{ env.ECR_REPOSITORY }}:${{ env.IMAGE_TAG }}
- ECR에 push
매니페스트 파일을 수정
매니페스트 파일이란?
주로 설정 파일을 말하는데, 프로그램이나 시스템이 실행될 때 필요한 설정과 구체적인 정보를 담고 있는 파일을 의미함.
이를 통해 프로그램이나 서비스가 어떻게 실행되고 동작할지를 정의할 수 있음.
깃허브 소스레포 = oolralra/src
깃허브 매니페스트레포 = oolralra/dep
변경이 된다는 것만 인지
oolralra/dep 에 있는 매니페스트를 clone 한 후, sed로 이미지 태그를 변경 후 push
- name: Checkout Deployment Repository
uses: actions/checkout@v4
with:
repository: YUMZII/dep #본인에 맞게 수정
ref: main # branch
token: ${{ secrets.GH_TOKEN }}
- 매니페스트 레포로 변경
- name: k8s manifest update
run: |
sed -i "s@ \
image: ${{ env.ECR_REGISTRY }}/${{ env.ECR_REPOSITORY }}:.*@ \
image: ${{ env.ECR_REGISTRY }}/${{ env.ECR_REPOSITORY }}:${{ env.IMAGE_TAG }}@g" deploy.yml
- 리눅스 환경에서는 구분자를 '/'로 해서 s/<바뀌기 전>/<바뀐 후>/g 이렇게 썼지만. 컨테이너 레지스트리와 레포를 구분하는 용도로 '/'가 쓰이기 때문에 구분자를 @로 했음
- name: Commit and Push
run: |
git config user.email ${{ env.GIT_EMAIL }}
git config user.name ${{ env.GIT_NAME }}
git add deploy.yml
git commit -m "Update image tag"
git push origin main
- git push
name: fast CI/CD #이름
on: # on 언제 action을 동작시킬지
push: # push가 됐을때 동작시키겠다.
branches: [main] # 대상 브랜치.
paths-ignore: # push 이벤트가 발생해도 무시할 파일.
- '.gitignore'
- '.dockerignore'
jobs:
ci:
runs-on: ubuntu-latest #깃액션이 동작하는 환경
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 1 #가장 최근 commit의 히스토리만 가져옴.
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v2
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ap-northeast-2
- name: Login to Amazon ECR
id: login-ecr
uses: aws-actions/amazon-ecr-login@v2
- name: Set Variables
id: set-var
run: |
echo "ECR_REGISTRY=${{ steps.login-ecr.outputs.registry }}" >> $GITHUB_ENV
echo "ECR_REPOSITORY=frontend" >> $GITHUB_ENV #본인 ecr레포에 맞게 수정
echo "IMAGE_TAG=${{ github.run_number }}" >> $GITHUB_ENV
echo "GIT_EMAIL=rlarn2003@naver.com" >> $GITHUB_ENV
echo "GIT_NAME=YUMZII" >> $GITHUB_ENV
- name: Docker Image Build
id: build-image
run: |
docker build -t ${{ env.ECR_REGISTRY }}/${{ env.ECR_REPOSITORY }}:${{ env.IMAGE_TAG }} .
- name: Docker image Push
id: push-image
run: |
docker push ${{ env.ECR_REGISTRY }}/${{ env.ECR_REPOSITORY }}:${{ env.IMAGE_TAG }}
- name: Checkout Deployment Repository
uses: actions/checkout@v4
with:
repository: YUMZII/dep #본인에 맞게 수정
ref: main # branch
token: ${{ secrets.GH_TOKEN }}
- name: k8s manifest update
run: |
sed -i "s@ \
image: ${{ env.ECR_REGISTRY }}/${{ env.ECR_REPOSITORY }}:.*@ \
image: ${{ env.ECR_REGISTRY }}/${{ env.ECR_REPOSITORY }}:${{ env.IMAGE_TAG }}@g" deploy.yml
- name: Commit and Push
run: |
git config user.email ${{ env.GIT_EMAIL }}
git config user.name ${{ env.GIT_NAME }}
git add deploy.yml
git commit -m "Update image tag"
git push origin main




'AWS Cloud School 8기 > CICD' 카테고리의 다른 글
[CI/CD] EKS 환경에서 동적 프로비저닝/ EBS/ EFS/ NFS/ EKS (1) | 2025.05.12 |
---|