AWS Cloud School 8기/쿠버네티스

89일차) 2025-05-08(svelte - front/back-fastapi, 앱 업데이트(CI 관점), Github-action을 통한 CI/CD)

eitherwho 2025. 5. 8. 10:07
  • 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

# frontend를 빼고 나머지 다 백엔드 관련 파일


  •  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로 열어주기 마려웠음 !


백엔드는 프라이빗한 곳에 있기때문에 브라우저 입장에서는 찾아갈 수 없음...

→ 해결법은 두가지

  1. 프론트를 띄운 nodejs앱에서 리버스프록시 코드를 추가
  2. npm build를 통해 정적파일을 생성 후 nginx를 통해 리버스프록시

앱 업데이트 (CI 관점)

  1. 프로그래밍 언어로 짜여진 코드를 수정
  2. 새로 앱빌드
  3. 새로 컨테이너이미지 빌드 = 이미지의 태그가 변경이 됐다는 뜻함.
  4. 그렇다면 이미지의 태그가 변경이 됐다는 사실을 어디에 명시? => 매니페스트 파일에 명시
  5. 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

# 이게 완료가 됐다면 CI가 성공한것


 

 

  • 소스코드 수정을 통한 깃액션 트리거


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