이전 블로그에서 말했다시피, 클라우드환경에서는 온프레미스와 다른점이 몇가지 존재한다.
이러한 다른점을 해결하기 위해 애드온을 설치해야한다.
클라우드환경(AWS)에서 ingress(L7)를 사용하기 위해서는 ALB(L7)를 사용해야하고, LoadBalancer(L4)를 사용하기 위해서는 NLB(L4)를 사용해야 한다. 따라서 ALB와 NLB를 사용하기위해 로드밸런서 컨트롤러 애드온이 필요하다.
# 이전 블로그에서 배포한 2번코드의 클러스터를 기반으로 한다.
# 해당 클러스터는 이미 애드온을 코드로 추가했기 때문에 설치만 해준다
helm repo add eks https://aws.github.io/eks-charts
# repo다운
helm repo update
# repo의 차트목록 업데이트
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 all -n kube-system
# 파드와 서비스 등이 잘 설치되었는지 확인
service.beta.kubernetes.io/aws-load-balancer-type: "external"
service.beta.kubernetes.io/aws-load-balancer-nlb-target-type: "ip"
# NLB 생성
service.beta.kubernetes.io/aws-load-balancer-scheme: "internet-facing"
# 코드 추가시 퍼블릭에 배치(외부에 노출), 추가 안할시 프라이빗에 배치
1 . 로드밸런서 타입의 서비스 생성
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
-> 어노테이션에서 ip타입인지 인스턴스 타입인지는 아직은 상관이없다.
2 . rs로 파드 생성
apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: myapp-rs
spec:
replicas: 2
selector:
matchLabels:
app: myapp-rs
template:
metadata:
labels:
app: myapp-rs
spec:
containers:
- name: myapp
image: ghcr.io/c1t1d0s7/go-myweb:alpine
ports:
- containerPort: 8080
kubernetes.io/ingress.class: alb
alb.ingress.kubernetes.io/target-type: instance
# ALB 생성
alb.ingress.kubernetes.io/scheme: internet-facing
# 코트 추가시 퍼블릭에 배치(외부에 노출), 추가 안할시 프라이빗에 배치
1 . Ingress 생성
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
-> 어노테이션에서 ip타입인지 인스턴스 타입인지는 아직은 상관이없다.
2 . NodePort타입 서비스 생성
apiVersion: v1
kind: Service
metadata:
name: myapp-svc-np
spec:
type: NodePort
ports:
- port: 80
targetPort: 8080
selector:
app: myapp-rs
3 . 파드 생성
apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: myapp-rs
spec:
replicas: 3
selector:
matchLabels:
app: myapp-rs
template:
metadata:
labels:
app: myapp-rs
spec:
containers:
- name: myapp
image: ghcr.io/c1t1d0s7/go-myweb:alpine
ports:
- containerPort: 8080
동적 프로비저닝을 하기 위해서는 pv의 프로파일 정보를 가지고 있는 스토리지 클래스가 필요하다.
eksctl create addon --name aws-ebs-csi-driver --cluster my-cluster --service-account-role-arn arn:aws:iam::111122223333:role/AmazonEKS_EBS_CSI_DriverRole --force
# EBS-CSI-Driver 생성 기본 형식
eksctl get iamserviceaccount --cluster myeks --name ebs-csi-controller-sa
# 서비스계정의 role-arn 확인
eksctl create addon --name aws-ebs-csi-driver --cluster myeks --service-account-role-arn < role-arn > --force
# 확인한 role-arn을 사용, 자신의 클러스터 이름 사용하여 애드온 생성
eksctl get addon --cluster myeks
# 생성한 애드온 확인
1 . pvc생성
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: myapp-pvc-dynamic
spec:
accessModes:
- ReadWriteOnce # EBS 전용 접근 모드
resources:
requests:
storage: 1Gi
storageClassName: gp2 # default로 존재하는 스토리지 클래스
2 . 파드 생성
apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: myapp-rs-dynamic
spec:
replicas: 2
selector:
matchLabels:
app: myapp-rs-dynamic
template:
metadata:
labels:
app: myapp-rs-dynamic
spec:
containers:
- name: web-server
image: nginx:alpine
volumeMounts:
- name: web-content
mountPath: /usr/share/nginx/html
ports:
- containerPort: 80
volumes:
- name: web-content
persistentVolumeClaim:
claimName: myapp-pvc-dynamic
1 . gp3 스토리지 클래스 생성
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
2 . pvc 생성
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: myapp-pvc
spec:
accessModes:
- ReadWriteOnce # EBS전용 접근 모드
resources:
requests:
storage: 1Gi
storageClassName: gp3 # 위에서 만든 gp3스토리지 클래스 사용
3 . 파드 생성
apiVersion: v1
kind: Pod
metadata:
name: myapp-pod
labels:
app: myapp-pod
spec:
containers:
- name: web-server
image: nginx:alpine
volumeMounts:
- name: web-content
mountPath: /usr/share/nginx/html
ports:
- containerPort: 80
volumes:
- name: web-content
persistentVolumeClaim:
claimName: myapp-pvc
-> 파드를 생성후에 pvc, pv를 확인해보면 정상적으로 pvc가 작동하고 pv를 생성하여 pvc에 bound 시킨 것을 확인할 수 있다.
kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml
# 메트릭 서버 애드온 설치
1 . 파드 생성
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp-deploy-hpa
spec:
replicas: 3
selector:
matchLabels:
app: myapp-deploy-hpa
template:
metadata:
labels:
app: myapp-deploy-hpa
spec:
containers:
- name: myapp
image: ghcr.io/c1t1d0s7/go-myweb:alpine
resources:
requests:
cpu: 50m
memory: 5Mi
limits:
cpu: 100m
memory: 20Mi
ports:
- containerPort: 8080
2 . HPA 생성
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: myapp-hpa-cpu
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: myapp-deploy-hpa
minReplicas: 2
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
-> Metric-server를 설치했기 때문에 HPA가 정상적으로 작동하는 것을 확인할 수 있다.
위에서 메트릭 서버를 설치해서 HPA(오토스케일링)를 하는 것은 파드에 대한 스케일링 이였다.
만약 파드가 계속 늘어나고 늘어나는 파드들은 계속해서
노드( =EC2 인스턴스)에 배치될 것이다. 파드의 request값이 존재하고 파드가 늘어남에 따라 노드가 더이상 request를 보장하지 못하게 된다. 이때는 노드를 스케일링 해야 한다.
Node( =EC2 인스턴스)에 대한 스케일링은 수동으로 하는 방법과 Clsuter Autoscaler 애드온을 설치해서 자동으로 스케일링 하는 방법이 있다.
< 수동 스케일링 >
eksctl scale nodegroup --name mynodes-t3 --cluster myeks -N 3
# Nodegroup설정해서 3으로 스케일링
eksctl get nodegroups --cluster myeks
# 스케일링된 노드그룹 확인
< 자동 스케일링 >
curl -O https://raw.githubusercontent.com/kubernetes/autoscaler/master/cluster-autoscaler/cloudprovider/aws/examples/cluster-autoscaler-autodiscover.yaml
# cluster autoscaler yaml파일 다운
vi cluster-autoscaler-autodiscover.yaml
# yaml파일 접속후 아래와 같이 수정
kubectl create -f cluster-autoscaler-autodiscover.yaml
# cluster-autoscaler애드온 설치
# 코드에서 이미 service계정이 존재하기 때문에 apply로 설치하면 덮어씌워진다
kubectl logs -n kube-system cluster-autoscaler-758f7f9485-q9v6g
# 생성한 cluster-autoscaler 애드온 로그 확인
# warning이 존재하면 안된다
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
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상태가 된다.
enableTypes: ["*"] # 모든 타입의 로그
ClusterName=myeks # 자신의 클러스터 이름
LogRegion=ap-northeast-2 # 자신의 리전
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}}/'${LogRegion}'/;s/{{http_server_toggle}}/"'${FluentBitHttpServer}'"/;s/{{http_server_port}}/"'${FluentBitHttpPort}'"/;s/{{read_from_head}}/"'${FluentBitReadFromHead}'"/;s/{{read_from_tail}}/"'${FluentBitReadFromTail}'"/' | kubectl apply -f -
kubectl get ns # amazon-cloudwatch 네임스페이스 생성된 것을 확인
kubectl get all -n amazon-cloudwatch
-> AWS 콘솔에서 CloudWatch의 Container Insights 항목에 들어가면 데이터를 수집해 분석 / 시각화 등의 되어 있는 것을 확인
aws 콘솔에 IAM 사용자에서 새로운 사용자가 있다는 가정하에 eksuser1을 생성한다.
eksuser1의 사용자 보안 자격 증명에서 엑세스 키 생성 (CLI)
cd ~/.aws # credential과 config파일 존재
vi credentials # 이전에 aws configure을 통해 입력했던 엑세스 키/ 시크릿 키 정보 존재
[default]
aws_access_key_id = AKIXXX
aws_secret_access_key = aGbm8XXX
[eksuser1]
aws_access_key_id = AKIXXX
aws_secret_access_key = mVoLGXXX
aws configure list-profiles # configure list 갱신
export AWS_PROFILE=eksuser1 # 계정을 eksuser1으로 변경
aws sts get-caller-identity --no-cli-pager # 변경이 잘되었는지 확인
export AWS_PROFILE=default # 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
# 권한파일을 실행시킨다
export AWS_PROFILE=eksuser1 # 권한이 부여된 eksuser1으로 다시 전환
kubectl get nodes
kubectl create deploy myweb --image nginx
kubectl get deploy
kubectl get po
kubectl get clusterroles
kubectl delete deploy myweb
# 여러 작업들이 가능해진걸 확인
export AWS_PROFILE=default # 다시 default로 전환
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가 인스턴스보다 조금더 비싸다
📗 네트워크에서 NLB, ALB를 생성할 때 IP Target or Instance Target중 하나를 선택했었다.