[쿠버네티스] AWS LB Controller & EBS CSI Provisioner & Cluster AutoscalerController & RBAC & EKS Fargate

신현식·2023년 2월 28일
0

구름_Kubernetes

목록 보기
12/25
post-thumbnail

클러스터 실행 후 확인

# 클러스터 생성
eksctl create cluster -f myeks.yaml

# 클러스터 확인
eksctl get cluster

# 노드 그룹 확인
eksctl get nodegroup --cluster myeks

# Fargate 프로파일 확인
eksctl get fargateprofile --cluster myeks

# IAM 서비스 계정 확인
eksctl get iamserviceaccount --cluster myeks

# 클러스터 삭제
eksctl delete cluster -f myeks.yaml

AWS LB Controller

네트워크 LoadBalance 서비스와 인그레스를 사용할 수 있게 해준다.
AWS 로드 밸런서 컨트롤러 추가 기능 설치
AWS Load Balancer Controller는 Kubernetes 클러스터의 AWS Elastic Load Balancer를 관리한다. 이 컨트롤러는 다음 리소스를 프로비저닝한다.

  • AWS Kubernetes를 생성할 때 Ingress Application Load Balancer(ALB).

  • LoadBalancer 유형의 Kubernetes 서비스를 생성할 때 AWS Network Load Balancer(NLB). 과거에는 인스턴스 대상에 대해 Kubernetes Network Load Balancer를 사용했지만 IP 대상에 대해서는 AWS Load Balancer Controller를 사용했습니다.

1 IAM 정책을 생성.

# 기타 모든 AWS 리전
curl -O https://raw.githubusercontent.com/kubernetes-sigs/aws-load-balancer-controller/v2.4.4/docs/install/iam_policy.json

2 IAM 역할 생성. AWS Load Balancer Controller의 kube-system 네임스페이스에 aws-load-balancer-controller라는 Kubernetes 서비스 계정을 생성하고 IAM 역할의 이름으로 Kubernetes 서비스 계정에 주석을 단다.

eksctl create iamserviceaccount \
  --cluster=myeks \
  --namespace=kube-system \
  --name=aws-load-balancer-controller \
  --role-name AmazonEKSLoadBalancerControllerRole \ 
  --attach-policy- arn:aws:iam::609292702544:role/eksctl-myeks-addon-iamserviceaccount-kube-sy-Role1-33EPZ7QQLQS1 \
  --approve

여기까지는 야물파일에서 직접 설정 해주었기 때문에 따로 설정할 필요는 없다!!!


3 Helm V3 이상을 사용하여 AWS Load Balancer Controller를 설치한다. Helm 절차에서는 자체 서명된 인증서를 생성하기 때문에 cert-manager에 의존하지 않는다.

helm repo add eks https://aws.github.io/eks-charts
helm repo update

# 내 클러스터 이름으로 설정, 이미 서버스 계정을 만들었기에 false, 이름은 설정, 
helm install aws-load-balancer-controller eks/aws-load-balancer-controller \
-n kube-system \
--set clusterName=myeks \
--set serviceAccount.create=false \
--set serviceAccount.name=aws-load-balancer-controller 

helm list -A

# 컨트롤러가 설치되어 있는지 확인
kubectl get deployment -n kube-system aws-load-balancer-controller

Amazon EKS의 네트워크 로드 밸런싱

네트워크 트래픽은 OSI 모델의 L4에서 로드 밸런싱된다. L7에서 애플리케이션 트래픽을 로드 밸런싱하려면 Kubernetes ingress를 배포한다.
AWS Network Load Balancer는 Amazon EC2 IP 및 인스턴스 대상 또는 pods IP 대상에 배포된 AWS Fargate로 네트워크 트래픽을 로드 밸런싱할 수 있다.

  • IP 대상을 사용하는 로드 밸런서를 생성하려면 서비스 매니페스트에 다음 주석을 추가하고 서비스를 배포해야 한다. aws-load-balancer-type의 external 값은 AWS 클라우드 공급자 로드 밸런서 컨트롤러가 아닌 AWS Load Balancer Controller가 Network Load Balancer를 생성하도록 한다.

  • Amazon EC2 노드로 로드 밸런싱하기 위해 퍼블릭 서브넷에 Network Load Balancer를 생성하려는 경우(Fargate는 프라이빗만 가능) 다음 주석을 추가해야함

service.beta.kubernetes.io/aws-load-balancer-scheme: "internet-facing"

네트워크 로드 밸런스 실습

cd goorm-8th-k8s/manifests/14_eks/02_addon/01_awslb/service/

kubectl create -f myapp-rs.yaml

vi myapp-svc-nlb.yaml

apiVersion: v1
kind: Service
metadata:
  name: myapp-svc-nlb
  annotations:
    service.beta.kubernetes.io/aws-load-balancer-type: "external"
    service.beta.kubernetes.io/aws-load-balancer-nlb-target-type: "ip"
    # service.beta.kubernetes.io/aws-load-balancer-nlb-target-type: "instance"
    service.beta.kubernetes.io/aws-load-balancer-scheme: "internet-facing"   # 퍼블릭으로 전환
    # service.beta.kubernetes.io/aws-load-balancer-scheme: "internal"
spec:
  type: LoadBalancer
  ports:
  - port: 80
    targetPort: 8080
  selector:
    app: myapp-rs

# 로드밸런서 서비스 확인
kubectl get svc

# 로드밸런스가 실행되는 것을 기다렸다가 윈도우 인터넷에서 외부 IP를 검색하면 접속이 가능한 것을 확인 할 수 있다.

aws ec2 로드밸런스에서 로드밸런스 타입을 확인해보면 network이다.

Amazon EKS의 애플리케이션 로드 밸런싱

kubernetes.io/ingress.class: alb 주석을 사용하여 클러스터에 Kubernetes 수신 리소스가 생성될 때마다 ALB 및 필요한 지원 AWS 리소스를 생성한다

annotations:
    kubernetes.io/ingress.class: alb

AWS Load Balancer Controller는 다음과 같은 트래픽 모드를 지원한다.

  • 인스턴스 - 클러스터 내의 노드를 ALB의 대상으로 등록한다. ALB에 도달하는 트래픽은 서비스를 위해 pods로 라우팅된 다음 NodePort로 프록시된다. alb.ingress.kubernetes.io/target-type: instance 주석을 사용하여 명시적으로 지정할 수도 있다.
  • IP - pods를 ALB의 대상으로 등록한다. ALB에 도달하는 트래픽은 서비스를 위해 pods로 직접 라우팅된다. 이 트래픽 모드를 사용하려면 alb.ingress.kubernetes.io/target-type: ip 주석을 지정해야 한다. Fargate에서 대상 pods가 실행 중인 경우 IP 대상 유형이 필요하다.
cd ../ingress

vi myapp-ing.yaml

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: myapp-ing
  annotations:
    kubernetes.io/ingress.class: alb
    alb.ingress.kubernetes.io/scheme: internet-facing  # 퍼블릭으로 전환
    #alb.ingress.kubernetes.io/scheme: internal
    alb.ingress.kubernetes.io/target-type: instance
    #alb.ingress.kubernetes.io/target-type: ip
spec:
  defaultBackend:
    service:
      name: myapp-svc-np
      port:
        number: 80
  rules:
  - http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: myapp-svc-np
            port:
              number: 80


kubectl create -f myapp-ing.yaml -f myapp-svc-np.yaml

# 주소가 나옴
kubectl get ing

aws ec2 로드밸런스에서 로드밸런스 타입을 확인해보면 application으로 바뀌었고, scheme가 internet-facing인 것을 확인 할 수있다.

EBS CSI Provisioner

Amazon Elastic Block Store(Amazon EBS) CSI(Container Storage Interface) 드라이버에서는 Amazon Elastic Kubernetes Service(Amazon EKS) 클러스터가 영구 볼륨을 위해 Amazon EBS 볼륨의 수명 주기를 관리할 수 있게 해준다.

  • Amazon EBS CSI add-on(추가 기능) 추가
# iam 서비스 계정 확인, 이중 ebs-csi ...인 것을 보면 된다.
eksctl get iamserviceaccount --cluster myeks

#
eksctl create addon --name aws-ebs-csi-driver --cluster myeks --service-account-role-arn arn:aws:iam::609292702544:role/eksctl-myeks-addon-iamserviceaccount-kube-sy-Role1-UJYQ357PGNFM --force

# 설치 확인
eksctl get addon --cluster myeks

# 데몬셋으로 구성되어 있음
kubectl get pod -n kube-system -l "app.kubernetes.io/component=csi-driver"

vi gp3-sc.yaml

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: gp3
  #annotations:
  #  storageclass.kubernetes.io/is-default-class: "true"
provisioner: ebs.csi.aws.com
volumeBindingMode: WaitForFirstConsumer
reclaimPolicy: Delete
parameters:
  csi.storage.k8s.io/fstype: ext4
  type: gp3


vi myapp-pvc.yaml

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: myapp-pvc
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 1Gi
  storageClassName: gp3

  • PVC의 액세스 모드는 제한사항때문에 ReadWriteOnce만 가능하다.

nfs-client의 볼륨 바인딩모드: immediate(파드가 없어도 그냥 만들어버림)
aws에서의 볼륨 바인딩모드: WaitForFirstConsumer

  • 파드보다 먼저 PVC를 만들었을때 생성이 되지 않는다. 이 후 파드를 생성하면 그때 PVC가 생성된다. 이를 WaitForFirstConsumer라고 한다. PVC를 사용하는 파드가 존재하지 않기 떄문에 굳이 PVC를 미리 만들 필요가 없기 때문이다.

Metric-Server 설치

HPA와 같은 오토스케일링, top 커멘드를 통한 cpu, metric 상태 수집은 metric-server가 존재해야 한다.
이전에 온프레미스 실습은 metric-server 애드온을 추가했지만 현재 클러스터에는 metric-server가 존재하지 않아 HPA나 TOP커멘드를 할 수 없다.
Kubernetes metric-server는 클러스터에서 리소스 사용량 데이터의 집계자이며, 기본적으로 Amazon EKS 클러스터에 배포되어 있지 않다. 따라서 따로 배포를 해줘야한다.

kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml

# 설치 확인
kubectl get deployment metrics-server -n kube-system


# top 명령 사용가능
kubectl top nodes
kubectl top pods

Cluster AutoscalerController

자동 크기 조정은 변화하는 요구 사항에 맞게 리소스를 자동으로 확장하거나 축소하는 기능입니다. 이는 Kubernetes의 주요 기능이다.
Kubernetes Cluster Autoscaler는 pods가 실패하거나 다른 노드로 다시 예약될 때 클러스터의 노드 수를 자동으로 조정한다. Cluster Autoscaler는 일반적으로 클러스터에 배포로 설치된다. 우리는 IAM 정책 및 역할을 클러스터를 만들때 이미 생성했기 때문에 따로 안해줘도 된다. 또한 생성한 IAM 역할의 ARN을 사용하여 cluster-autoscaler 서비스 계정에 어노테이션도 이미 지정이 되어있다.

kubectl describe sa -n kube-system cluster-autoscaler

수동으로 스케일 컨트롤

# 스케일 업
eksctl scale nodegroup --name mynodes-t3 --cluster myeks -N 3
kubectl get nodes

# 스케일 다운
eksctl scale nodegroup --name mynodes-t3 --cluster myeks -N 2
kubectl get nodes

Autoscale

cd ~

# 야물파일 다운로드
curl -O https://raw.githubusercontent.com/kubernetes/autoscaler/master/cluster-autoscaler/cloudprovider/aws/examples/cluster-autoscaler-autodiscover.yaml

# 파일 수정
vi cluster-autoscaler-autodiscover.yaml

...
apiVersion: apps/v1
kind: Deployment
...
spec:
  template
    metadata:
      ...
      annotations:
        ...
        cluster-autoscaler.kubernetes.io/safe-to-evect: 'false'  # 추가
    spec:
      serviceAccountName: cluster-autoscaler
      containers:
        - image: k8s.gcr.io/autoscaling/cluster-autoscaler:v1.24.0  # 버전 맞추기
            ...
          command:
            - ./cluster-autoscaler
            - --v=4
            - --stderrthreshold=info
            - --cloud-provider=aws
            - --skip-nodes-with-local-storage=false
            - --expander=least-waste
            - --node-group-auto-discovery=asg:tag=k8s.io/cluster-autoscaler/enabled,k8s.io/cluster-autoscaler/myeks  # 수정
            - --balance-similar-node-groups  # 추가
            - --skip-nodes-with-system-pods=false  # 추가
...

# 하나가 오류나는데 괜찮음, 서비스 계정이 이미 존재하기 때문
kubectl create -f cluster-autoscaler-autodiscover.yaml
# 로그로 에러 있나 확인 
kubectl logs -f deployment/cluster-autoscaler -n kube-system

# 노드 그룹에서 용량 확인
eksctl get nodegroups --cluster myeks
  • Cluster Autoscaler와 우리가 사용하고 있는 쿠버네티스의 버전을 맞춰 줘야한다.(1.24.x 중에 제일 최신인 버전 -> 1.24.0)

  • 현재 존재하는 서비스 계정에 어노테이션이 설정되어 있기 때문에 파드를 만들 때 apply를 실행하면 다른 내용으로 바뀌기 때문에 사용하면 안된다.

1 . 파드 생성

apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: myapp-rs
spec:
  replicas: 1
  selector:
    matchLabels:
      app: myapp-rs
  template:
    metadata:
      labels:
        app: myapp-rs
    spec:
      containers:
      - name: myweb
        image: ghcr.io/c1t1d0s7/go-myweb:alpine
        ports:
        - containerPort: 8080
        resources:
          requests:
            cpu: 200m
            memory: 200M
          limits:
            cpu: 200m
            memory: 200M

간단하게 rs로 파드하나 생성한다.
노드에 어떠한 파드도 존재하지 않아 cluster-autoscaler에 의해 자동으로 min값인 1개로 노드를 줄인상태이다.

kubectl scale rs myapp-rs --replicas 7

-> 파드의 개수를 7개로 늘렸을때, 하나의 노드에 6개의 파드가 배치되었고, 7번째 파드의 request값(200m)을 보장해줄수 있는 용량이 현재 노드(=EC2 인스턴스)에는 남아있지 않아 해당 파드를 생성하지 못하고 Pending상태가 된다.

  • Pending상태인 파드의 로그를 보면 pod에 의해 trigger된
    cluster-autoscaler가 node를 1->2로 증가시킨다는 것을 볼 수 있다.

-> 실제로 노드가 하나가 더 늘어난 것을 볼 수 있다.
= aws콘솔에 EC2 인스턴스에서 봐도 인스턴스의 개수가 2개인것을 확인

-> 새로 생성된 노드에 Pending상태였던 파드가 배치되면서 자동으로 Running상태가 된다.

CloudWatch & Container Insights

  • CloudWatch -> 로그 -> 로그그룹
    맨 아래가 컨트롤 플레인의 로그이고 나머지들은 워커노드의 로그이다.

  • 인사이트 -> container insight
    성능 모니터링을 확인 할 수 있다.

ec2에 역할 부여를 클러스터를 만들때 이미 진행했다. 또한 컨트롤 플레인의 로그 5가지를 클라우드 워치에 모두 남겨두는 설정을 미리 진행하였다.

managedNodeGroups:
  # On-Demand Instance
  - name: mynodes-t3
    instanceType: t3.medium
   ...
    availabilityZones: ["ap-northeast-2a", "ap-northeast-2b", "ap-northeast-2c"]
    iam:
      withAddonPolicies:
        autoScaler: true
        albIngress: true
        cloudWatch: true
        ebs: true
   ...

# CloudWatch Logging 
cloudWatch:
  clusterLogging:
    enableTypes: ["*"]

시각화 및 분석

이전에 온프레미스에서 prometheus(시각화,분석), EFK(로그수집)를 사용하여 데이터의 시각화를 하였다.
물론 prometheus나 EFK를 완벽히 대체하는 것은 아니지만 AWS에서도 Container Insights라는 데이터 시각화 도구가 있다.
컨테이너 인사이트 설치 참조

CloudWatch 에이전트가 Amazon EKS 및 Kubernetes와 작동하는 방식에 대한 추가 구성 세부 정보를 제공한다.

ClusterName=myeks   # <my-cluster-name> 
RegionName=ap-northeast-2     # <my-cluster-region>
FluentBitHttpPort='2020'
FluentBitReadFromHead='Off'
[[ ${FluentBitReadFromHead} = 'On' ]] && FluentBitReadFromTail='Off'|| FluentBitReadFromTail='On'
[[ -z ${FluentBitHttpPort} ]] && FluentBitHttpServer='Off' || FluentBitHttpServer='On'
curl https://raw.githubusercontent.com/aws-samples/amazon-cloudwatch-container-insights/latest/k8s-deployment-manifest-templates/deployment-mode/daemonset/container-insights-monitoring/quickstart/cwagent-fluent-bit-quickstart.yaml | sed 's/{{cluster_name}}/'${ClusterName}'/;s/{{region_name}}/'${RegionName}'/;s/{{http_server_toggle}}/"'${FluentBitHttpServer}'"/;s/{{http_server_port}}/"'${FluentBitHttpPort}'"/;s/{{read_from_head}}/"'${FluentBitReadFromHead}'"/;s/{{read_from_tail}}/"'${FluentBitReadFromTail}'"/' | kubectl apply -f - 

# amazon-cloudwatch 네임스페이스 생성된 것을 확인 
kubectl get ns 

kubectl get all -n amazon-cloudwatch 
  • cloudwatch agent와 fluent-bit가 각각 파드, 데몬셋으로 생성되어 있는 것을 확인
  • fluent-bit = 로그를 수집
  • cloudwatch agent = 수집된 로그를 cloudwatch에 전달하는 역할
    -> AWS 콘솔에서 CloudWatch의 Container Insights -> 컨테이너 맵, 리소스 등 데이터를 수집해 분석 / 시각화 등의 되어 있는 것을 확인

RBAC

aws 콘솔에 IAM 사용자에서 새로운 사용자가 있다는 가정하에 eksuser1을 생성한다.

  • 직접 정책 연결 선택 : AdministratorAccess
    -> 모든 권한을 가진 가장 강력한 정책 부여

eksuser1의 사용자 보안 자격 증명에서 엑세스 키 생성 (CLI)

  • CSV파일 다운 후 쿠버네티스와 연결
# credential과 config파일 존재
cd ~/.aws 

# 이전에 aws configure을 통해 입력했던 엑세스 키/ 시크릿 키 정보 존재
vi credentials 

[default]
aws_access_key_id = AKIXXX
aws_secret_access_key = aGbm8XXX

[eksuser1]
aws_access_key_id = AKIXXX
aws_secret_access_key = mVoLGXXX
  • 새로 생성한 eksuser1에 대해서 csv파일에 있는 액세스 키 / 시크릿 액세스 키 정보 추가
# configure list 갱신 
aws configure list-profiles

# 계정을 eksuser1으로 변경 
export AWS_PROFILE=eksuser1 

# 변경이 잘되었는지 확인
aws sts get-caller-identity --no-cli-pager 
  • eksuser1은 아직은 권한 설정이 안되었기 때문에 해당 계정으로는 어떤것도 할 수가 없다.
# default계정으로 다시 전환
export AWS_PROFILE=default 
# 전환 확인
aws sts get-caller-identity --no-cli-pager 
  • aws-auth 컨피그맵으로부터 권한 파일 생성
# 파일로 저장하는 방법
kubectl get cm -n kube-system aws-auth -o yaml > aws-auth.yaml

vi aws-auth.yaml # 권한 파일 접속 및 아래의 내용 추가  

apiVersion: v1
data:
  ...
    mapUsers: |
    - userarn: <ARN> 
      username: eksuser1
      groups:
      - system:masters
...
  • < ARN >은 AWS 콘솔에 IAM 사용자에 eksuser1을 클릭하면 알
    수 있다.
# 권한파일을 실행시킨다
kubectl apply -f aws-auth.yaml


# 권한이 부여된 eksuser1으로 다시 전환 
export AWS_PROFILE=eksuser1 

# 여러 작업들이 가능해진걸 확인
kubectl get nodes
kubectl create deploy myweb --image nginx
kubectl get deploy
kubectl get po
kubectl get clusterroles
kubectl delete deploy myweb

  • 여러명의 개발자가 있을 때 같은 환경(= 같은 클러스터)에서 서로 다른 계정으로 작업을 할 수 있게 된다.
  • 각 계정마다 할 수 있는 권한을 달리할 수도 있다.

플러그를 추가하여 보기 쉽게 zsh를 꾸밀 수 있다.

# 플로그 몇개더 추가
vi ~/.zshrc

plugins=(
  aws
  git
  zsh-syntax-highlightinf
  zsh-autosuggestions
)

source ~/.zshrc

# 명령을 실행하면 default로 변환된 것을 잘 보여줌
export AWS_PROFILE=default
aws sts get-caller-identity --no-cli-pager

EKS Fargate

EKS -> 만든 클러스터 -> 컴퓨팅에서 확인 가능

노드그룹은 ec2기반의 vm을 사용하는 노드이다. Fargate는 VM을 사용하지 않는 AWS의 서버리스를 위한 제품으로 EC2를 만들지 않고 바로 파드만 생성한다.

클러스터를 생성할 때 2번 코드에서 Fargate Profiles을 지정했다.
쉽게말해, Fargate가 될 수 있는 조건을 명시한것이다.
= 명시한 조건의 namespace, label이 일치하면 EC2인스턴스가 아닌 Fargate로 파드를 생성-> 실제로 aws콘솔에 eks에 컴퓨팅에 Fargate profile에 가보면 위와같이 조건이 명시되어 있는 것을 볼 수 있다.

1 . 파드 생성

kubectl create ns dev # dev네임스페이스 생성 

apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: myapp
  namespace: dev
spec:
  replicas: 1
  selector:
    matchLabels:
      env: dev
  template:
    metadata:
      name: nginx
      labels:
        env: dev
    spec:
      containers:
      - name: nginx
        image: nginx:alpine

-> Fargate 프로파일의 namespace와 label을 일치시켜 파드를 생성하면 일정시간 Pending 상태가 된다

kubectl get nodes -n dev
  • node를 확인해보면 fargate노드가 생성되어 있는 것을 확인
  • 이건 아주 경량의 node(EC2 인스턴스,VM)를 띄워서 파드를 생성한 것이다.
  • 즉, 노드이자 파드, 노드가 생성되지만 실제로는 노드가 아닌 것이다.
  • AWS 콘솔에도 인스턴스(노드)가 보이지 나타나지 않는다.
    -> 따라서 인스턴스를 관리할 필요가 없고, 스케일링도 필요하지 않다.

-> 경량의 Fargate 노드가 생성이 되면 자동으로 파드는 Running상태가 된다.

-> Fargate로 생성된 파드의 describe를 보면 어노테이션에 CapacityProvisioned라는 항목이 있는데 해당 용량에 따라 비용이 부과되고 달라진다.

  • 현재는 request / limits를 지정하기 않았기 때문에 자동으로 용량이 설정된 것이고, request/ limits를 지정함에 따라 비용을 조절해야 한다.

fargate가 인스턴스보다 조금더 비싸다

💡 네트워크에서 NLB, ALB를 생성할 때 IP Target or Instance Target중 하나를 선택했었다.

  • Instance Target을 선택하려면 파드가 반드시 EC2 인스턴스(노드)에 배치되어야 한다.

  • Fargate를 사용해 파드를 배치하면 EC2 인스턴스(노드)가 존재하지 않기 때문에 IP Target을 선택해야 한다.

profile
전공 소개

0개의 댓글