04 Amazon EKS 클러스터 구축 및 서비스 배포

shin·2023년 6월 13일
0

Kubernetes

목록 보기
7/12
post-thumbnail

Amazon EKS로 웹 애플리케이션 구축하기

1. eksctl로 클러스터 생성

Amazon EKS 클러스터는 다양한 방식으로 배포될 수 있지만 해당 실습에서는 eksctl을 사용하여 EKS 클러스터를 생성

  • root 폴더(/home/ec2-user/environment) 위치에서 아래의 값을 붙여넣음
cd ~/environment
cat << EOF > eks-demo-cluster.yaml
---
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: m5.large # 클러스터 워커 노드의 인스턴스 타입
    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
EOF
  • Cluster 배포(약 20분 정도 소요됨)
eksctl create cluster -f eks-demo-cluster.yaml
  • node가 제대로 배포 완료되었는지 확인

현재까지 구성된 서비스 아키텍처


2. Ingress Controller 만들기

  • AWS Load Balancer Controller를 사용하여 실습 진행

  • Ingress(인그레스)

    • 주로 클러스터 외부에서 쿠버네티스 내부로 접근할 때, 요청들을 어떻게 처리할지 정의해놓은 규칙이자 리소스 오브젝트
    • 외부의 요청이 내부로 접근하기 위한 관문의 역할
    • 외부 요청에 대한 로드 밸런싱, TLS/SS 인증서 처리, HTTP 경로에 대한 라우팅 등을 설정
    • L7 영역의 요청 처리
    • Ingress Controller : 이런 설정이 동작하기 위해서 필요한 것(직접 구현 필요)

1) AWS Load Balancer 컨트롤러 만들기

  • Amazon EKSApplication Load Balancing

    • 클러스터에 인그레스 자원이 생성될 때에 ALB(Application Load Balancer) 및 필요한 자원이 생성되도록 트리거하는 컨트롤러
    • 인그레스 자원들은 ALB를 구성하여 HTTP 또는 HTTPS 트래픽을 클러스터 내 파드로 라우팅
    • 쿠버네티스의 Ingress의 경우, Application Load Balancers으로 프로비저닝
    • 쿠버네티스의 Service의 경우, etwork Load Balancers으로 프로비저닝
  • AWS Load Balancer Controller에서 지원하는 트래픽 모드

    • Instance(default)
      • 클러스터 내 노드를 ALB의 대상으로 등록
      • ALB에 도달하는 트래픽은 NodePort로 라우팅된 다음 파드로 프록시됨
    • IP
      • 파드를 ALB 대상으로 등록
      • ALB에 도달하는 트래픽은 파드로 직접 라우팅됨
      • 해당 트래픽 모드를 사용하기 위해선 ingress.yaml 파일에 주석을 사용하여 명시적으로 지정해야 함
  • controller가 워커 노드 위에서 동작되기 때문에 IAM permissions를 통해, AWS ALB/NLB 리소스에 접근할 수 있도록 만들어야 함

  • 클러스터에 대한 IAM OIDC(OpenID Connect) identity Provider를 생성

    • 쿠버네티스가 직접 관리하는 사용자 계정을 의미하는 service accountIAM role을 사용하기 위해, 생성한 클러스터(현재 실습에서의 eks-demo)에 IAM OIDC provider가 존재해야 함
eksctl utils associate-iam-oidc-provider \
    --region ${AWS_REGION} \
    --cluster eks-demo \
    --approve
  • 클러스터의 OIDC provider URL 확인하고, 결과 값에서 /id/ 뒤에 있는 값을 복사한 후, 아래와 같이 명령어 수행

  • 결과 값이 출력되지 않았으면 생성 작업을 수행해야 함

  • AWS Load Balancer Controller에 부여할 IAM Policy를 생성하는 작업 수행

curl -o iam-policy.json https://raw.githubusercontent.com/kubernetes-sigs/aws-load-balancer-controller/v2.4.7/docs/install/iam_policy.json

aws iam create-policy \
    --policy-name AWSLoadBalancerControllerIAMPolicy \
    --policy-document file://iam-policy.json
  • AWS Load Balancer Controller를 위한 ServiceAccount를 생성
eksctl create iamserviceaccount \
    --cluster eks-demo \
    --namespace kube-system \
    --name aws-load-balancer-controller \
    --attach-policy-arn arn:aws:iam::$ACCOUNT_ID:policy/AWSLoadBalancerControllerIAMPolicy \
    --override-existing-serviceaccounts \
    --approve

2) 클러스터에 컨트롤러 추가하기

  • 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 파일에서 클러스터의 cluster-name을 편집

  • yaml 파일에서 ServiceAccount yaml spe을 없애줌

    • WS Load Balancer Controller를 위한 ServiceAccount를 이미 생성했기 때문에
  • 변경 내역 저장 후 AWS Load Balancer controller 파일 배포

kubectl apply -f v2_4_4_full.yaml
  • 배포가 성공적으로 되고 컨트롤러가 실행되는지 확인(결과값이 도출되면 정상)

  • service account 생성 확인

  • 클러스터 내부에서 필요한 기능들을 위해 실행되는 파드들을 애드온(Addon)이라고 함

    • 애드온에 사용되는 파드들은 디플로이먼트, 리플리케이션 컨트롤러 등에 의해 관리됨
    • 이 애드온이 사용하는 네임스페이스가 kube-system인데, Yaml 파일에서 네임스페이스를 kube-system으로 명시했기에 위의 명령어로 파드 이름이 도출되면 정상적으로 배포된 것
    • 아래의 명령어로 관련 로그 확인 가능
      kubectl logs -n kube-system $(kubectl get po -n kube-system | egrep -o "aws-load-balancer[a-zA-Z0-9-]+")
  • 자세한 속성 값 파악

ALBPOD=$(kubectl get pod -n kube-system | egrep -o "aws-load-balancer[a-zA-Z0-9-]+")

kubectl describe pod -n kube-system ${ALBPOD}

3. 서비스 배포

  • 웹 서비스를 구성하는 백엔드, 프론트엔드를 Amazon EKS에 배포
  • 각 서비스를 배포하는 순서
  1. 소스 코드 다운로드
  2. Amazon ECR에 각 서비스에 대한 리포지토리 생성
  3. Dockerfile을 포함한 소스 코드 위치에서 Container image를 build한 후 Repository에 push
  4. 각 서비스에 대한 Deployment, Service, Ingress 매니페스트 파일 생성 및 배포
  • 사용자가 실제 서비스를 접근하는 순서

1) 첫번째 백엔드 배포(flask 백엔드 배포)

  • manifests 폴더 위치로(/home/ec2-user/environment/manifests)로 이동
cd ~/environment/manifests/
  • deploy manifest를 생성
cat <<EOF> flask-deployment.yaml
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: demo-flask-backend
  namespace: default
spec:
  replicas: 3
  selector:
    matchLabels:
      app: demo-flask-backend
  template:
    metadata:
      labels:
        app: demo-flask-backend
    spec:
      containers:
        - name: demo-flask-backend
          image: $ACCOUNT_ID.dkr.ecr.$AWS_REGION.amazonaws.com/demo-flask-backend:latest
          imagePullPolicy: Always
          ports:
            - containerPort: 8080
EOF
  • service manifest 파일을 생성
cat <<EOF> flask-service.yaml
---
apiVersion: v1
kind: Service
metadata:
  name: demo-flask-backend
  annotations:
    alb.ingress.kubernetes.io/healthcheck-path: "/contents/aws"
spec:
  selector:
    app: demo-flask-backend
  type: NodePort
  ports:
    - port: 8080 # 서비스가 생성할 포트  
      targetPort: 8080 # 서비스가 접근할 pod의 포트
      protocol: TCP
EOF
  • ingress manifest 파일을 생성
cat <<EOF> flask-ingress.yaml
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
    name: "flask-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: '1'
spec:
    rules:
    - http:
        paths:
          - path: /contents
            pathType: Prefix
            backend:
              service:
                name: "demo-flask-backend"
                port:
                  number: 8080
EOF
  • 위에서 생성한 매니페스트를 아래의 순서대로 배포
    • Ingree를 생성하면 AWS Application Load Balancer(ALB)가 프로비저닝됨
kubectl apply -f flask-deployment.yaml
kubectl apply -f flask-service.yaml
kubectl apply -f flask-ingress.yaml

  • 아래 명령어 수행 결과를 웹 브라우저 및 API 플랫폼에 붙여넣어 확인
echo http://$(kubectl get ingress/flask-backend-ingress -o jsonpath='{.status.loadBalancer.ingress[*].hostname}')/contents/aws
  • 인그레이스 오브젝트가 배포되는 동안 약간의 시간이 소요되기 때문에, EC2 콘솔창에서 Load Balancers 상태가 active가 될 때까지 기다려야 함

  • 현재까지의 아키텍처

2) 두번째 백엔드 배포(express)

cd ~/environment/manifests/
  • 이미 만들어진 컨테이너 이미지를 포함한 deploy manifest를 생성
cat <<EOF> nodejs-deployment.yaml
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: demo-nodejs-backend
  namespace: default
spec:
  replicas: 3
  selector:
    matchLabels:
      app: demo-nodejs-backend
  template:
    metadata:
      labels:
        app: demo-nodejs-backend
    spec:
      containers:
        - name: demo-nodejs-backend
          image: public.ecr.aws/y7c9e1d2/joozero-repo:latest
          imagePullPolicy: Always
          ports:
            - containerPort: 3000
EOF
  • service manifest 파일을 생성
cat <<EOF> nodejs-service.yaml
---
apiVersion: v1
kind: Service
metadata:
  name: demo-nodejs-backend
  annotations:
    alb.ingress.kubernetes.io/healthcheck-path: "/services/all"
spec:
  selector:
    app: demo-nodejs-backend
  type: NodePort
  ports:
    - port: 8080
      targetPort: 3000
      protocol: TCP
EOF
  • ingree manifest 파일 생성
cat <<EOF> nodejs-service.yaml
---
apiVersion: v1
kind: Service
metadata:
  name: demo-nodejs-backend
  annotations:
    alb.ingress.kubernetes.io/healthcheck-path: "/services/all"
spec:
  selector:
    app: demo-nodejs-backend
  type: NodePort
  ports:
    - port: 8080
      targetPort: 3000
      protocol: TCP
EOF
  • 매니페스트 배포
kubectl apply -f nodejs-deployment.yaml
kubectl apply -f nodejs-service.yaml
kubectl apply -f nodejs-ingress.yaml
  • 다음 명령어 수행 결과를 웹 브라우저 및 API 플랫폼에 붙여넣어 확인
echo http://$(kubectl get ingress/nodejs-backend-ingress -o jsonpath='{.status.loadBalancer.ingress[*].hostname}')/services/all
http://k8s-eksdemogroup-ac5f71b163-2133791238.ap-northeast-2.elb.amazonaws.com/services/all

  • 현재까지의 아키텍처

3) 프론트엔드 배포(React)

  • 컨테이너라이징할 소스 코드 다운로드 받기
cd /home/ec2-user/environment
git clone https://github.com/joozero/amazon-eks-frontend.git
  • AWS CLI를 통해 이미지 리포지토리 생성
aws ecr create-repository \
--repository-name demo-frontend \
--image-scanning-configuration scanOnPush=true \
--region ${AWS_REGION}
  • 두 개의 백엔드 결과 값을 화면에 뿌리기 위해 일부 소스 코드를 수정해야 함

  • App.js 파일의 url 값을 앞서 배포한 인그레이스 주소로 변경

    • 아래 명령어의 출력 결과를 인그레스 주소로 붙여넣음
      echo http://$(kubectl get ingress/flask-backend-ingress -o jsonpath='{.status.loadBalancer.ingress[*].hostname}')/contents/'${search}'
  • page/UpperPage.js 파일의 url 값을 앞서 배포한 인그레이스 주소로 변경

    • 아래 명령어의 출력 결과를 인그레스 주소로 붙여넣음
      echo http://$(kubectl get ingress/nodejs-backend-ingress -o jsonpath='{.status.loadBalancer.ingress[*].hostname}')/services/all
  • amazon-eks-frontend 폴더에서 아래 명령어 수행

cd /home/ec2-user/environment/amazon-eks-frontend
npm install
  • npm install 이후 vulnerability가 나온다면, nam audit fix 명령어를 수행한 후 npm run build를 적용해야 함
nam audit fix
npm run build

  • 이미지 리포지토리 생성 및 이미지 푸시
docker build -t demo-frontend .

docker tag demo-frontend:latest $ACCOUNT_ID.dkr.ecr.$AWS_REGION.amazonaws.com/demo-frontend:latest


  • manifests 폴더로 이동하여 deploy manifests 생성
cd /home/ec2-user/environment/manifests

cat <<EOF> frontend-deployment.yaml
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: demo-frontend
  namespace: default
spec:
  replicas: 3
  selector:
    matchLabels:
      app: demo-frontend
  template:
    metadata:
      labels:
        app: demo-frontend
    spec:
      containers:
        - name: demo-frontend
          image: $ACCOUNT_ID.dkr.ecr.$AWS_REGION.amazonaws.com/demo-frontend:latest
          imagePullPolicy: Always
          ports:
            - containerPort: 80
EOF
  • service manifests 생성
cat <<EOF> frontend-service.yaml
---
apiVersion: v1
kind: Service
metadata:
  name: demo-frontend
  annotations:
    alb.ingress.kubernetes.io/healthcheck-path: "/"
spec:
  selector:
    app: demo-frontend
  type: NodePort
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80
EOF
  • ingress manifests 생성
cat <<EOF> frontend-ingress.yaml
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: "frontend-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: '3'
spec:
  rules:
    - http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: "demo-frontend"
                port:
                  number: 80
EOF
  • 매니페스트 배포
kubectl apply -f frontend-deployment.yaml
kubectl apply -f frontend-service.yaml
kubectl apply -f frontend-ingress.yaml
  • 다음 명령어 수행 결과를 웹 브라우저에 붙여넣어서 확인
echo http://$(kubectl get ingress/frontend-ingress -o jsonpath='{.status.loadBalancer.ingress[*].hostname}')

profile
Backend development

0개의 댓글