삽집하는 개발들/AWS

[Git Action][Docker][CD/CI][GitFlow] 구축

악투 2023. 9. 7. 15:22
반응형

1. Docker

  • Docker Build
########################################################1
# 1. 기본 이미지로 먼저 빌드를 한다.
From node:16 AS builder
WORKDIR /app
COPY . .

# 패키지를 복사한다.
COPY package*.json ./
# npm 인스톨시 종속성 관련되서, force는 충돌을 우회, --legacy-peer-deps 충돌을 무시
RUN npm install --force
RUN npm install rimraf -g
RUN npm install -g @nestjs/cli
RUN npm install bcrypt --force

#build 전에 eslint, tsc확인
RUN npm run build

# 2. 이미지 경량화 
FROM node:16-alpine
WORKDIR /app
ENV NODE_ENV production
COPY --from=builder /app ./
CMD ["npm", "run" , "start:prod"]


########################################################2
# node 버전 맞추기
FROM node:15.14.0

# 컨테이너 내에서 작업 디렉토리를 설정합니다.
WORKDIR /usr/src/app

# package.json 및 package-lock.json을 작업 디렉토리로 복사합니다.
COPY package*.json ./

# 애플리케이션 종속성을 설치합니다.
RUN npm install

# 소스 코드를 작업 디렉토리로 복사합니다.
COPY . .

# 애플리케이션을 빌드합니다.
RUN npm run build

# 컨테이너에서 실행할 명령을 지정합니다.
CMD ["node", "dist/main"]

 

  • Docker RUN
# Docker 빌드 및 실행.
docker build . -t babayo_api

# -d : 백그라운드 실행.
docker run -d -p 3000:10107 babayo_api

# 상태 확인
docker ps -all

2. GitFlow Setting

  • Main 브랜치
    • 출시 가능한 프로덕션 코드를 모아두는 브랜치.
  • Develop 브랜치
    • 다음 버전 개발을 위한 코드를 모아두는 브렌치, 개발 완료 시 Main 브랜치로 머지.
  • Feature 브랜치
    • 하나의 기능을 개발하기 위한 브랜치, Develop 기준으로 브랜치를 생성.
  • Release 브랜치
    • 소프트 웨어 배포를 준비하기 위한 브랜치.
    • Develop 브랜치에서 생성, 버전 이름 등의 소소한 데이터를 수정하거나, 배포전 사소한 버그를 수정하기 위해 사용.
    • 배포 준비가 완료되었다면, Main과 Develop 브랜치에 둘다 머지.
    • Main 브랜치에 태그를 이용하여 버전 표시.
    • Release 브랜치를 따로 운용하면서, 배포 업무와 관련 없는 팀원들은 병렬적으로 Feature브렌치에서 이어서 기능을 개발.
  • Hotfix 브랜치
    • 이미 배포된 버전에 문제가 발생, Hotfix 브랜치를 사용하여 문제 해결.
    • Main 브랜치에서 생성, 문제 해결이 완료되면 Main과 Develop 브랜치에 둘다 머지.

3. CD (Continuous Deployment)

  • ECR 이용.
  • EKS 이용.
    • 클러스터 IAM 생성
  • 흐름도

 

  • 코드 흐름

1) GitHub 푸쉬

git commit -m "블라블라"

git tag v0.1.18

git push —tags

2) .github/workflows

  • EKS
apiVersion: eksctl.io/v1alpha5
kind: ClusterConfig

metadata:
  name: eks-demo # 생성할 EKS 클러스터명
  region: ${AWS_REGION} # 클러스터를 생성할 리전
  version: "1.23"

vpc:
  cidr: "10.0.0.0/16" # 클러스터에서 사용할 VPC의 CIDR
  nat:
    gateway: HighlyAvailable

managedNodeGroups:
  - name: node-group # 클러스터의 노드 그룹명
    instanceType: t3.medium # 클러스터 워커 노드의 인스턴스 타입
    desiredCapacity: 3 # 클러스터 워커 노드의 갯수
    volumeSize: 20  # 클러스터 워커 노드의 EBS 용량 (단위: GiB)
    privateNetworking: true
    ssh:
      enableSsm: true
    iam:
      withAddonPolicies:
        imageBuilder: true # Amazon ECR에 대한 권한 추가
        albIngress: true  # albIngress에 대한 권한 추가
        cloudWatch: true # cloudWatch에 대한 권한 추가
        autoScaler: true # auto scaling에 대한 권한 추가
        ebs: true # EBS CSI Driver에 대한 권한 추가

cloudWatch:
  clusterLogging:
    enableTypes: ["*"]

iam:
  withOIDC: true
# 클러스터 생성
eksctl create cluster -f eks-demo-cluster.yaml
kubectl get nodes
  • AWS Load Balancer
cd ~/environment

mkdir -p manifests/alb-ingress-controller && cd manifests/alb-ingress-controller

# 최종 폴더 위치
/home/ec2-user/environment/manifests/alb-ingress-controller

#AWS Load Balancer 컨트롤러를 배포하기 전, 클러스터에 대한 IAM OIDC(OpenID Connect) identity Provider를 생성
eksctl utils associate-iam-oidc-provider \
    --region ${AWS_REGION} \
    --cluster eks-demo \
    --approve

#클러스터의 OIDC provider URL
aws eks describe-cluster --name eks-demo --query "cluster.identity.oidc.issuer" --output text


aws iam list-open-id-connect-providers | grep {위에서 URL이 나오는데 /id/ 뒤에 값으로 검색}

# 클러스터에 컨트롤러 추가
# AWS Load Balancer controller를 클러스터에 추가하는 작업을 수행합니다. 먼저, 인증서 구성을 웹훅에 삽입할 수 있도록 cert-manager 를 설치합니다. Cert-manager는 쿠버네티스 클러스터 내에서 TLS인증서를 자동으로 프로비저닝 및 관리하는 오픈 소스
kubectl apply --validate=false -f https://github.com/jetstack/cert-manager/releases/download/v1.5.4/cert-manager.yaml

# Load balancer controller yaml 파일을 다운로드
wget https://github.com/kubernetes-sigs/aws-load-balancer-controller/releases/download/v2.4.4/v2_4_4_full.yaml


# 위 해당 yaml 파일에서 이부분만 수정
spec:
    containers:
    - args:
        - --cluster-name=eks-demo # 생성한 클러스터 이름을 입력
        - --ingress-class=alb
        image: amazon/aws-alb-ingress-controller:v2.4.4

# yaml 파일에서 ServiceAccount yaml spec 삭제
apiVersion: v1
kind: ServiceAccount
metadata:
  labels:
    app.kubernetes.io/component: controller
    app.kubernetes.io/name: aws-load-balancer-controller
  name: aws-load-balancer-controller
  namespace: kube-system

# 로드 밸런서 배포
kubectl apply -f v2_4_4_full.yaml

# 로드밸런서 배포 체크
kubectl get deployment -n kube-system aws-load-balancer-controller
kubectl get sa aws-load-balancer-controller -n kube-system -o yaml
  • HPA ( Horizontal Pod Autoscaler )
# Metrics Server는 쿠버네티스 클러스터 전체의 리소스 사용 데이터를 집계
# CPU, MEMORY 사용량 같은 메트릭을 수집
kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml

# Metrics Server가 정상 생성 되었는지 확인.
kubectl get deployment metrics-server -n kube-system


apiVersion: apps/v1
kind: Deployment
metadata:
  name: test-backend
  namespace: default
spec:
	# 레플리카 1로 설정하여 임계치값에 따른 변화를 설정할 수 있게 작업할 것임.
  replicas: 1
  selector:
    matchLabels:
      app: test-backend
  template:
    metadata:
      labels:
        app: test-backend
    spec:
      containers:
        - name: test-backend
          image: *********.dkr.ecr.ap-northeast-2.amazonaws.com/babayo_api:${TAG_NAME}
          imagePullPolicy: Always
          ports:
            - containerPort: 10107
##############이부분에서 설정하면 됩니다.##############
            resources:
              requests:
                 cpu: 250m
              limits:
                 cpu: 500m


# 현재 HPA 설정이 안되어있음.
# 이부분에 대해서 메트릭 값을 체크 한 후 설정 작업해야함.
# hpa.yaml 생성
apiVersion: autoscaling/v1
kind: HorizontalPodAutoscaler
metadata:
  name: demo-flask-backend-hpa
  namespace: default
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: demo-flask-backend
  minReplicas: 1
  maxReplicas: 5
  targetCPUUtilizationPercentage: 30

# 설정후
kubectl get hpa

# 부하테스트 진행해야하는데 파드의 변화량 부터 파악 후 진행.
kubectl get hpa -w
  • ECR + EKS PUSH and Deploy
name: ECR Push

on:
  push:
    branches:
      - main # 원하는 브랜치로 변경
    tags:
      - 'v*'

jobs:
  build-and-deploy:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout repository
        uses: actions/checkout@v2

      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v1
        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@v1

      - name: Build and tag Docker image
        run: |
          TAG_NAME=$(echo "${{ github.ref }}" | sed 's/refs\/tags\///')
          echo "TAG_NAME=$TAG_NAME" >> $GITHUB_ENV 
          docker build -t babayo_api:$TAG_NAME .
          docker tag babayo_api:$TAG_NAME **********.dkr.ecr.ap-northeast-2.amazonaws.com/babayo_api:$TAG_NAME

      - name: Push Docker image to Amazon ECR
        run: |
          docker push ${{ steps.login-ecr.outputs.registry }}/babayo_api:$TAG_NAME

      - name: Set execute permissions
        run: |
          chmod +x ./version_check.sh
          ./version_check.sh $TAG_NAME

      - name: Deploy to EKS
        run: |
          aws eks update-kubeconfig --region ap-northeast-1 --name eks-demo
          kubectl apply -f ./backend-deployment.yaml
          kubectl apply -f ./backend-service.yaml
          kubectl apply -f ./backend-ingress.yaml

backend-deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: test-backend
  namespace: default
spec:
  replicas: 3
  selector:
    matchLabels:
      app: test-backend
  template:
    metadata:
      labels:
        app: test-backend
    spec:
      containers:
        - name: test-backend
          image: ********.dkr.ecr.ap-northeast-2.amazonaws.com/babayo_api:${TAG_NAME}
          imagePullPolicy: Always
          ports:
            - containerPort: 10107

backend-service.yaml

apiVersion: v1
kind: Service
metadata:
  name: test-backend
  annotations:
    alb.ingress.kubernetes.io/healthcheck-path: '/'
spec:
  selector:
    app: test-backend
  type: NodePort
  ports:
    - protocol: TCP
      port: 80
      targetPort: 10107

backend-ingress.yaml

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: "backend-ingress"
  namespace: default
  annotations:
    kubernetes.io/ingress.class: alb
    alb.ingress.kubernetes.io/scheme: internet-facing
    alb.ingress.kubernetes.io/target-type: ip
    alb.ingress.kubernetes.io/group.name: eks-demo-group
    alb.ingress.kubernetes.io/group.order: '2'
spec:
  rules:
  - http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: "test-backend"
                port:
                  number: 80
반응형