89일차) 2025-05-08(svelte - front/back-fastapi, 앱 업데이트(CI 관점), Github-action을 통한 CI/CD)
- EKS 클러스터 구성
eksctl create cluster --vpc-private-subnets subnet-033d8f789eee8880d,subnet-0ca72dc02ff537a25 --name pric --region ap-northeast-2 --version 1.32 --nodegroup-name mycng --node-type t3.small --nodes 1 --nodes-min 1 --nodes-max 3 --node-private-networking
- LB controller 설치
export CLUSTER_NAME=pric
export ACCOUNT_ID=651109015678
export VPC_ID=vpc-0a4d6d7b49d1ecafc
export REGION=ap-northeast-2
eksctl utils associate-iam-oidc-provider --cluster $CLUSTER_NAME --approve
eksctl create iamserviceaccount --cluster=$CLUSTER_NAME --namespace=kube-system --name=aws-load-balancer-controller --role-name AmazonEKSLoadBalancerControllerRole --attach-policy-arn=arn:aws:iam::$ACCOUNT_ID:policy/AWSLoadBalancerControllerIAMPolicy --override-existing-serviceaccounts --approve
- NGINX Ingress Controller 설치
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm repo update
helm install ingress-nginx ingress-nginx/ingress-nginx \
--namespace ingress-nginx --create-namespace
kubectl get pods -n ingress-nginx
kubectl get svc -n ingress-nginx
- RDS 생성
사용자이름 : user
암호 : test1234
암호화x
초기DB이름 : db
퍼블릭엑세스 : 예
되도록이면 같은 VPC에 서브넷은 퍼블릭서브넷
서브넷 그룹 : rapa-pub-subgroup
보안그룹 : rapa-rds-allow, source 0.0.0.0/0, 포트 3306
svelte - fastapi 로 만든 앱
- 아래의 Github fork하기
https://github.com/oolralra/svelte-fast
- git clone <본인레포>/svelte-fast
root@aws-cli:~# git clone https://github.com/leeseohoo/svelte-fast.git
- mysql 명령어 설치
E: Failed to fetch http://kr.archive.ubuntu.com/ubuntu/... 404 Not Found
♨ APT 저장소의 패키지 버전이 더 이상 존재하지 않거나 갱신되지 않아서 생기는 문제
apt-get update
apt-get install --fix-missing mysql-client-core-8.0
- mysql -u user -ptest1234 -h <본인 RDS주소>
mysql -u user -ptest1234 -h database-0.c7agowsw8ogt.ap-northeast-2.rds.amazonaws.com
backend 컨테이너를 띄워보자 !
# 백엔드의 Dockerfile에서 수정해야할 부분. 마지막에 db = 초기데이터베이스이름
- 백엔드 앱 이미지빌드
docker build -t backend:1 .
- 컨테이너 실행
docker run -dp 8000:8000 --name back backend:1
- 백엔드 앱에 접속
- 아예 여기로 접속해서 리스트가 뜨는지 확인 가능
http://211.183.3.99:8000/api/question/list
이번에는 frontend 컨테이너를 띄워보자 !
root@aws-cli:~/svel-fast# cd frontend
root@aws-cli:~/svel-fast/frontend# vi Dockerfile
root@aws-cli:~/svelte-fast/frontend# vi .env
- 프론트엔드 앱 이미지빌드
root@aws-cli:~/svel-fast/frontend# docker build -t frontend:1 .
- 프론트앱이 5173번으로 동작 중
root@aws-cli:~/svel-fast/frontend# docker run -dp 80:5173 --name front frontend:1
- 컨테이너 중지
docker stop $(docker ps -q)
실습)
ECR을 사용하여 아래처럼 NLB로 접속 가능하게 만들어보세요! 백엔드앱에 /health라는 경로로 헬스체크를 할 수 있습니다.
no basic auth credentials
♨ 로그인 안해서 생기는 문제
aws ecr get-login-password --region ap-northeast-2 | docker login --username AWS --password-stdin 651109015678.dkr.ecr.ap-northeast-2.amazonaws.com
1. 프론트/백엔드 ECR 이미지 푸시
- Svelte 프론트 빌드 & 푸시
docker build -t svelte-front .
docker tag svelte-front:latest 651109015678.dkr.ecr.ap-northeast-2.amazonaws.com/svelte-front:latest
docker push 651109015678.dkr.ecr.ap-northeast-2.amazonaws.com/svelte-front:latest
- FastAPI 백 빌드 & 푸시
docker build -t svelte-back .
docker tag svelte-back:latest 651109015678.dkr.ecr.ap-northeast-2.amazonaws.com/svelte-back:latest
docker push 651109015678.dkr.ecr.ap-northeast-2.amazonaws.com/svelte-back
2. Kubernetes 배포 설정 (YAML 예시)
- backend-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: backend
spec:
replicas: 1
selector:
matchLabels:
app: backend
template:
metadata:
labels:
app: backend
spec:
containers:
- name: backend
image: 651109015678.dkr.ecr.ap-northeast-2.amazonaws.com/svelte-back:latest
ports:
- containerPort: 8000
---
apiVersion: v1
kind: Service
metadata:
name: svc-back
spec:
selector:
app: backend
ports:
- port: 8000
targetPort: 8000
type: ClusterIP
root@aws-cli:~/svelte-fast# kubectl apply -f backend-deployment.yaml
- frontend-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: frontend
spec:
replicas: 1
selector:
matchLabels:
app: frontend
template:
metadata:
labels:
app: frontend
spec:
containers:
- name: frontend
image: 651109015678.dkr.ecr.ap-northeast-2.amazonaws.com/svelte-front:latest
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: svc-front
annotations:
service.beta.kubernetes.io/aws-load-balancer-type: "external" # NLB 생성
spec:
selector:
app: frontend
ports:
- port: 80
targetPort: 5173
type: LoadBalancer
root@aws-cli:~/svelte-fast/frontend# kubectl apply -f frontend-deployment.yaml
Svelte에서 API 호출 시, http://svc-back:8000/ 형태로 DNS 이름을 부르면 Kubernetes 내부에서 FastAPI로 연결됩니다.
3. Svelte에서 API 연결 시 주의할 점
개발 환경: localhost:8000 등으로 되어 있을 가능성 있음 → env 파일이나 .env.production 등을 사용해서 도커 빌드 시 API 주소를 svc-back으로 지정해야 함.
vi frontend/.env
VITE_SERVER_URL=http://svc-back:8000
4. 배포 후 외부 접속 확인
kubectl get svc svc-front
외부 IP (NLB 주소)가 할당되면 브라우저에서 접속해 확인하면 됩니다.
root@aws-cli:~/svelte-fast/frontend# kubectl rollout restart deployment frontend
백엔드는 프라이빗한 곳에 있기때문에 브라우저 입장에서는 찾아갈 수 없는 문제가 발생
ClusterIP가 아니고 NodePort로 열어주기 마려웠음 !
♨ 백엔드는 프라이빗한 곳에 있기때문에 브라우저 입장에서는 찾아갈 수 없음...
→ 해결법은 두가지
- 프론트를 띄운 nodejs앱에서 리버스프록시 코드를 추가
- npm build를 통해 정적파일을 생성 후 nginx를 통해 리버스프록시
앱 업데이트 (CI 관점)
- 프로그래밍 언어로 짜여진 코드를 수정
- 새로 앱빌드
- 새로 컨테이너이미지 빌드 = 이미지의 태그가 변경이 됐다는 뜻함.
- 그렇다면 이미지의 태그가 변경이 됐다는 사실을 어디에 명시? => 매니페스트 파일에 명시
- argoCD가 이를 인지해서 자동으로 apply를 해준다.
Github-action을 통한 CI/CD
위에서 했었던 front 앱만 CI를 해보자.
- frontend 앱이 보이는 경로에서 디렉토리를 복사
root@aws-cli:~/svel-fast# cp -r frontend/ ~/frontend
root@aws-cli:~/svel-fast# cd ~/frontend
- 여기를 깃허브의 로컬로 함
root@aws-cli:~/frontend# git init
- 아직 원격레포를 생성하진 않았지만 앞으로 만들 예정
root@aws-cli:~/frontend# git remote add origin https://github.com/<계정>/src
git remote add origin https://github.com/leeseohoo/src
git remote -v
- 깃허브에서 레포 생성
- 모든 변경사항 추가
root@aws-cli:~/frontend# git add .
root@aws-cli:~/frontend# git commit -m "first"
# 정보가 등록 안되어있으면 아디랑 이메일을 대충넣어도 된다.
- 브랜치 지정
root@aws-cli:~/frontend# git branch -M main
- push
root@aws-cli:~/frontend# git push origin main
- 토근 한 번 입력하고 엔터, 엔터
앱 배포를 위한 SVC
- ECR 레포 생성
aws ecr create-repository --repository-name frontend --region ap-northeast-2
- ECR 로그인
export ACCOUNT_ID=651109015678
aws ecr get-login-password --region ap-northeast-2 | docker login --username AWS --password-stdin $ACCOUNT_ID.dkr.ecr.ap-northeast-2.amazonaws.com
- FRONT라는 이름으로 환경변수 처리
export FRONT=$ACCOUNT_ID.dkr.ecr.ap-northeast-2.amazonaws.com/frontend
- 이렇게 사용가능
docker build -t $FRONT:3 .
- 기존 리소스 삭제
root@aws-cli:~/frontend# kubectl delete deploy,svc --all
앱 배포를 위한 매니페스트
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: 651109015678.dkr.ecr.ap-northeast-2.amazonaws.com/frontend:2
root@aws-cli:~/deploy# kubectl apply -f deploy.yml
# frontend 경로로 돌아와서
root@aws-cli:~/frontend# docker build -t $FRONT:1 .
root@aws-cli:~/frontend# docker push $FRONT:1
♨ 만약에 이미지 관련 에러가 났다면
빌드 후에 파일을 수정하진 않았는지 확인하고, 수정했다면 태그를 달리 지정해 다시 빌드&푸시
root@aws-cli:~/frontend# docker build -t $FRONT:2 .
root@aws-cli:~/frontend# docker push $FRONT:2
- 깃허브 창을 두개 열어놓기
Github-Action
위 과정을 깃허브 액션을 통해 정의할 예정
- 직접 스크립트를 정의
name: fast CI/CD on: # on 언제 action을 동작시킬지 push: # push가 됐을때 동작시키겠다. branches: [main] # 대상 브랜치. paths-ignore: # push 이벤트가 발생해도 무시할 파일. - '.gitignore' - '.dockerignore' |
# 메인브랜치에 push가 됐을때 트리거될 것이다. 예외할 디렉토리나 파일(.gitignore,.dockerignore)도 존재한다.
jobs: ci: runs-on: ubuntu-latest #깃액션이 동작하는 환경 steps: - uses: actions/checkout@v4 with: fetch-depth: 1 #가장 최근 commit의 히스토리만 가져옴. |
# 다음 절차는 ECR에 push를 하기 위한 계정을 등록할건데, ECR에 접근할 수 있는 최소한의 권한만 갖고있는 계정을 생성해서 등록하는게 베스트다. (절대 administrator 권한은 주지마세요!!)
# ECR에 접근할 수 있는 권한만 부여
- 엑세스 키 생성 후 저장
- leeseohoo/src 페이지를 새롭게 띄운 후
- aws 액세스 키를 안전하게 저장해놓고 나중에 워크플로우에서 환경변수처럼 호출해서 쓸 예정
- AWS_ACCESS_KEY_ID 추가
- AWS_SECRET_ACCESS_KEY 추가
- GH_TOKEN 추가
- 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레포에 맞게 수정 echo "IMAGE_TAG=${{ github.run_number }}" >> $GITHUB_ENV echo "GIT_EMAIL=pcmin929@gmail.com" >> $GITHUB_ENV echo "GIT_NAME=pcmin929" >> $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
매니페스트 파일을 수정
깃허브 소스레포 = leeseohoo/src
깃허브 매니페스트레포 = leeseohoo/dep
변경이 된다는것만 인지
oolralra/dep 에 있는 매니페스트를 clone한 후, sed로 이미지 태그를 변경 후 push
- name: Checkout Deployment Repository uses: actions/checkout@v4 with: repository: leeseohoo/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 이렇게 썼지만. 컨테이너 레지스트리와 레포를 구분하는 용도로 '/'가 쓰이기때문에 구분자를 @로 했다.
# sed -i 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
- 소스코드 수정을 통한 깃액션 트리거
ArgoCD를 설치후 dep 레포지토리를 등록하고, 소스레포에 변경사항을 발생하여 앱이 업데이트가 되는지를 확인
자율과제)
backend를 온프레미스에 CI/CD 해보세요!
- 클러스터 삭제전에는 꼭 aws의 리소스를 생성하는 svc 같은거 지우기
kubectl delete svc --all
eksctl delete cluster pric
- EIP, NATGW, RDS 제거
aws ec2 release-address --allocation-id eipalloc-06c26ae37751f6770