Amazon EKS 원클릭 배포 환경에서 진행
먼저 OIDC 공급자를 확인해보자.
aws eks describe-cluster --name $CLUSTER_NAME \
--query "cluster.identity.oidc.issuer" \
--output text
쿠버네티스가 AWS 서비스에 접근하고 AWS LoadBalancer를 사용하기 위해서는 쿠버네티스 Service Account에 적절한 IAM 역할이 부여되어야 한다.
이 과정은 어떻게 수행되는 것일까?
AWS LoadBalancer Controller를 사용하기 위해서는 다음과 같은 과정이 필요하다.
IAM 정책 생성 ➡️ IAM Role에 정책을 붙임 ➡️ IAM Role과 SA를 연결 (IRSA) ➡️ 해당 SA로 AWS LB Controller 설치(생성)
이 과정에서 2번째 과정인 IAM Role에 정책을 붙임을 할 때 신뢰관계에 정책에 OIDC 인증 방식이 사용된다.
OIDC 즉, OpenID Connect의 약자로 일종의 권한을 갖기위한 열쇠다.
쿠버네티스 클러스터를 생성하면 자동적으로 OIDC 공급자 URL이 생성되는데, 이 공급자 URL을 사용해서 IAM Role의 신뢰관계 정책을 생성한다.
다음과 같이 실제로 IAM Role을 생성 시, 쿠버네티스의 OIDC를 정책을 다룰 주체(Principal)에 넣어 IAM Role을 생성하는 것을 볼 수 있다.
실제 이후 과정을 수행해보게 되면, IAM Role에 신뢰관계 정책으로 OIDC 인증 방식을 등록하는 것을 볼 수 있다.
💡이처럼 IAM Role을 생성할 때, 이 IAM Role을 누가맡을 지를 OIDC를 통해 신뢰관계 정책에 정의해 두었으므로, 이후 IRSA 과정에서 문제 없이 쿠버네티스의 SA가 IAM Role을 가질 수 있는 것이다.
AWSLoadBalancerControllerIAMPolicy를 생성해 주어야한다. 기본적으로 AWS ELB를 다루기 위한 정책으로 AWS 계정 내 해당 정책은 기본적으로는 없으므로 생성해준다.
// IAM Policy json 파일 다운로드
curl -o iam_policy.json https://raw.githubusercontent.com/kubernetes-sigs/aws-load-balancer-controller/v2.4.7/docs/install/iam_policy.json
// AWSLoadBalancerControllerIAMPolicy 생성
aws iam create-policy --policy-name AWSLoadBalancerControllerIAMPolicy --policy-document file://iam_policy.json
이후, 생성한 IAM 정책을 IAM Role에 연결하고(OIDC를 신뢰관계 정책에 넣는 과정 포함) SA를 생성한 뒤, IAM Role과 연결하는 과정까지 한번에 수행해보자.
// IRSA 수행
eksctl create iamserviceaccount \
--cluster=$CLUSTER_NAME \
--namespace=kube-system \
--name=aws-load-balancer-controller \
--attach-policy-arn=arn:aws:iam::$ACCOUNT_ID:policy/AWSLoadBalancerControllerIAMPolicy \
--override-existing-serviceaccounts \
--approve
// IRSA 정보 확인
eksctl get iamserviceaccount --cluster $CLUSTER_NAME
// Kubernetes 서비스 어카운트 확인
kubectl get serviceaccounts -n kube-system aws-load-balancer-controller -o yaml | yh
이제 AWS Load Balancer Controller를 Helm을 통해서 설치해보자.
// Helm Chart Repository 추가 및 업데이트
helm repo add eks https://aws.github.io/eks-charts
helm repo update
// Helm Chart - AWS Load Balancer Controller 설치
helm install aws-load-balancer-controller eks/aws-load-balancer-controller -n kube-system \
--set clusterName=$CLUSTER_NAME \
--set serviceAccount.create=false \
--set serviceAccount.name=aws-load-balancer-controller
다음과 같이 파드형태로 AWS Load Balancer Controller가 설치되는 것을 확인할 수 있다.
다음과 같이 AWS Load Balancer Controller를 생성하면서 함께 만들어진 CRD 및 ClusterRole
그리고 AWS Load Balancer Controller의 상세 정보를 확인할 수 있다.
// Kubernetes CRD 확인
kubectl get crd
// AWS Load Balancer Controller Role 확인
kubectl describe clusterroles.rbac.authorization.k8s.io aws-load-balancer-controller-role
// AWS Load Balancer Controller 확인
kubectl get deployment -n kube-system aws-load-balancer-controller
kubectl describe deploy -n kube-system aws-load-balancer-controller
NLB는 4계층 로드밸런서로 EKS에서는 Service(LoadBalancer)에 해당한다.
// 파드, 서비스, 엔드포인트 모니터링
watch -d kubectl get pod,svc,ep
NLB를 배포하기 전에 터미널을 추가로 하나 더 만들고, 어떤 방식으로 AWS LoadBalancer Controller로 배포한 NLB가 동작하는지 확인해 보도록 하자.
쿠버네티스에서 AWS LoadBalancer Controller 설치한 상태에서 Service를 LoadBalancer로 하고, nlb 어노테이션과 함께 배포하게 되면, AWS LoadBalancer로 NLB가 생성된다.
# 파드 배포
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy-echo
spec:
replicas: 2
selector:
matchLabels:
app: deploy-websrv
template:
metadata:
labels:
app: deploy-websrv
spec:
terminationGracePeriodSeconds: 0
containers:
- name: akos-websrv
image: k8s.gcr.io/echoserver:1.5
ports:
- containerPort: 8080
---
# NLB 배포
apiVersion: v1
kind: Service
metadata:
name: svc-nlb-ip-type
annotations:
service.beta.kubernetes.io/aws-load-balancer-nlb-target-type: ip
service.beta.kubernetes.io/aws-load-balancer-scheme: internet-facing
service.beta.kubernetes.io/aws-load-balancer-healthcheck-port: "8080"
service.beta.kubernetes.io/aws-load-balancer-cross-zone-load-balancing-enabled: "true"
spec:
ports:
- port: 80
targetPort: 8080
protocol: TCP
type: LoadBalancer
loadBalancerClass: service.k8s.aws/nlb
selector:
app: deploy-websrv
위와 같이 yaml 파일을 적절하게 만들어 주고, 해당 파일을 배포하도록 한다.
// 디플로이먼트 & 서비스 배포
kubectl apply -f echo-service-nlb.yaml
// 정보 확인
kubectl get pod -owide
kubectl get targetgroupbindings
배포된 파드와 해당 파드들을 타켓 그룹으로 가지는 서비스(NLB)를 확인할 수 있다.
새로운 로드밸런서 서비스(NLB)가 생성되었고, 생성된 서비스(NLB)의 엔드포인트가 각 파드의 IP를 가리키고 있다.
실제로 NLB가 생성된 것을 AWS콘솔에서 직접 확인해 보자.
먼저 EC2의 로드밸런서 탭에 진입하면, 실제로 NLB가 생성된 것을 확인할 수 있다.
이제 이러한 NLB가 실제로 로드밸런싱하는 타겟 그룹(대상 그룹)을 확인해 보자.
대상은 실제로 이전 확인했던 파드 IP라는 것을 확인할 수 있다.
이제 트래픽을 보내보고 확인해 보자.
// 웹 접속 주소 확인
kubectl get svc svc-nlb-ip-type -o jsonpath={.status.loadBalancer.ingress[0].hostname} | awk '{ print "Pod Web URL = http://"$1 }'
// NLB 도메인 변수 선언
NLB=$(kubectl get svc svc-nlb-ip-type -o jsonpath={.status.loadBalancer.ingress[0].hostname})
// 확인
echo $NLB
// 웹 접속 확인 (1회)
curl -s $NLB
// 웹 접속 확인 (100회 - 카운팅)
for i in {1..100}; do curl -s $NLB | grep Hostname ; done | sort | uniq -c | sort -nr
NLB를 통해서 2개의 파드에게 대략 5:5의 비율로 로드밸런싱이 수행되는 것을 확인할 수 있다.
파드의 수를 변경하면🆙 어떻게 될까? 자동으로 타켓 그룹으로 새롭게 생긴 파드도 들어갈까?
// 파드 3대로 조정
kubectl scale deployment deploy-echo --replicas=3
// 웹 접속 확인 (100회 - 카운팅)
for i in {1..100}; do curl -s $NLB | grep Hostname ; done | sort | uniq -c | sort -nr
새롭게 생성된 파드 또한 자동으로 같은 타겟 그룹에 들어가 NLB를 통해서 트래픽을 함께 나눠받는 것을 확인할 수 있다.
ALB는 7계층 로드밸런서로 EKS에서 Ingress에 해당한다.
Ingress 생성 시 자동으로 생성되며, Ingress를 사용하므로 파드까지의 라우팅을 담당하는 k8s 내부 서비스(ClusterIP 또는 NodePort)가 필요하다.
파드를 배포하고 인그레스를 생성하도록 하자.
인그레스를 배포하므로 앞서 말했듯, 인그레스가 라우팅할 k8s 서비스가 당연히 필요로 하다. (여기서는 NodePort 형식으로 사용하였다)
apiVersion: v1
kind: Namespace
metadata:
name: game-2048
---
apiVersion: apps/v1
kind: Deployment
metadata:
namespace: game-2048
name: deployment-2048
spec:
selector:
matchLabels:
app.kubernetes.io/name: app-2048
replicas: 2
template:
metadata:
labels:
app.kubernetes.io/name: app-2048
spec:
containers:
- image: public.ecr.aws/l6m2t8p7/docker-2048:latest
imagePullPolicy: Always
name: app-2048
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
namespace: game-2048
name: service-2048
spec:
ports:
- port: 80
targetPort: 80
protocol: TCP
type: NodePort
selector:
app.kubernetes.io/name: app-2048
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
namespace: game-2048
name: ingress-2048
annotations:
alb.ingress.kubernetes.io/scheme: internet-facing
alb.ingress.kubernetes.io/target-type: ip
spec:
ingressClassName: alb
rules:
- http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: service-2048
port:
number: 80
위 yaml 파일을 배포하고 확인해 보도록 하자.
// 디플로이먼트 & 인그레스 배포
kubectl apply -f ingress1.yaml
// 정보 확인
kubectl get pod -n game-2048 -o wide
kubectl get targetgroupbindings -n game-2048
// Ingress 확인
kubectl describe ingress -n game-2048 ingress-2048
다음과 같이 파드 2개가 배포되고, ClusterIP 서비스에 연결된 상태로 Ingress가 이를 라우팅하고 있는 형태이다.
실제로 Ingress에 의해서 ALB가 생성된 것을 확인할 수 있다.
리스너 및 규칙을 확인해보자.
/
로 시작하는 경우, 파드IP로 라우팅 되도록 지정된 것을 확인할 수 있다.
ALB의 DNS 주소로 접속하면 다음과 같이 배포된 파드(2048게임)으로 접속할 수 있다.
// 파드 5대로 조정
kubectl scale deployment -n game-2048 deployment-2048 --replicas 3
파드 수량을 조절하면 실제 대상 그룹 또한 늘어나는 것을 NLB와 동일하게 확인할 수 있다.
Reference📎 | CloudNet@와 함께하는 Amazon EKS 기본 강의