# 클러스터 생성
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
네트워크 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
네트워크 트래픽은 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이다.
kubernetes.io/ingress.class: alb 주석을 사용하여 클러스터에 Kubernetes 수신 리소스가 생성될 때마다 ALB 및 필요한 지원 AWS 리소스를 생성한다
annotations:
kubernetes.io/ingress.class: alb
AWS Load Balancer Controller는 다음과 같은 트래픽 모드를 지원한다.
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인 것을 확인 할 수있다.
Amazon Elastic Block Store(Amazon EBS) CSI(Container Storage Interface) 드라이버에서는 Amazon Elastic Kubernetes Service(Amazon EKS) 클러스터가 영구 볼륨을 위해 Amazon EBS 볼륨의 수명 주기를 관리할 수 있게 해준다.
# 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
nfs-client의 볼륨 바인딩모드: immediate(파드가 없어도 그냥 만들어버림)
aws에서의 볼륨 바인딩모드: WaitForFirstConsumer
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
자동 크기 조정은 변화하는 요구 사항에 맞게 리소스를 자동으로 확장하거나 축소하는 기능입니다. 이는 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
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상태가 된다.
-> 실제로 노드가 하나가 더 늘어난 것을 볼 수 있다.
= aws콘솔에 EC2 인스턴스에서 봐도 인스턴스의 개수가 2개인것을 확인
-> 새로 생성된 노드에 Pending상태였던 파드가 배치되면서 자동으로 Running상태가 된다.
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
aws 콘솔에 IAM 사용자에서 새로운 사용자가 있다는 가정하에 eksuser1을 생성한다.
eksuser1의 사용자 보안 자격 증명에서 엑세스 키 생성 (CLI)
# 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
# configure list 갱신
aws configure list-profiles
# 계정을 eksuser1으로 변경
export AWS_PROFILE=eksuser1
# 변경이 잘되었는지 확인
aws sts get-caller-identity --no-cli-pager
# default계정으로 다시 전환
export AWS_PROFILE=default
# 전환 확인
aws sts get-caller-identity --no-cli-pager
# 파일로 저장하는 방법
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
...
# 권한파일을 실행시킨다
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 -> 만든 클러스터 -> 컴퓨팅에서 확인 가능
노드그룹은 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
-> 경량의 Fargate 노드가 생성이 되면 자동으로 파드는 Running상태가 된다.
-> Fargate로 생성된 파드의 describe를 보면 어노테이션에 CapacityProvisioned라는 항목이 있는데 해당 용량에 따라 비용이 부과되고 달라진다.
fargate가 인스턴스보다 조금더 비싸다
💡 네트워크에서 NLB, ALB를 생성할 때 IP Target or Instance Target중 하나를 선택했었다.
Instance Target을 선택하려면 파드가 반드시 EC2 인스턴스(노드)에 배치되어야 한다.
Fargate를 사용해 파드를 배치하면 EC2 인스턴스(노드)가 존재하지 않기 때문에 IP Target을 선택해야 한다.