Kubernetes-Masterclass | LBC, Ingress & Service Account(SA) & Webhook Service & Ingress Class
Aug 20, 2024
AWS Load Balancer Controller(LBC) Ingress1. AWS 로드 밸런서 컨트롤러 개요2. 컨트롤러의 필요성 및 특징3. AWS 로드 밸런서 컨트롤러 Deployment4. 컨트롤러의 동작 방식AWS Application Load Balancer (ALB) 1. AWS 애플리케이션 로드 밸런서(ALB) 개요
2. ALB Ingress 컨트롤러(ALB IC)
3. ALB Ingress 컨트롤러의 작동 원리
CREATE IAM & Service Account(SA)1. IAM 정책 생성2. IAM 역할 및 서비스 계정 생성AWS LoadBalancer Controller Install & Helm1. Helm 설치2. AWS 로드 밸런서 컨트롤러 설치 전 준비3. AWS 로드 밸런서 컨트롤러 설치Load Balancer Controller & Webhook Service1. AWS 로드 밸런서 컨트롤러 설치 확인2. 웹후크 서비스 확인1. 로드 밸런서 컨트롤러 로그 확인2. 서비스 계정 및 비밀 검토3. 로드 밸런서 컨트롤러 제거 (선택 사항)Ingress Class인그레스 클래스(IngressClass) 개념문제 시나리오인그레스 클래스(IngressClass)인그레스 클래스 리소스의 구성기본 인그레스 클래스 설정인그레스 리소스(Ingress Resource)인그레스 클래스와 인그레스 리소스 간의 연결
AWS Load Balancer Controller(LBC) Ingress
AWS 로드 밸런서 컨트롤러를 설치합니다. 이 컨트롤러는 Kubernetes에서 ALB(Application Load Balancer)와 NLB(Network Load Balancer)를 관리하는 데 사용됩니다.
1. AWS 로드 밸런서 컨트롤러 개요
- 변경 사항: 이전에는 AWS ALB Ingress 컨트롤러가 사용되었으나, 이제는 AWS 로드 밸런서 컨트롤러로 이름이 변경되고 재설계되었습니다.
- 지원 기능: 이 컨트롤러는 애플리케이션 로드 밸런서(ALB)뿐만 아니라 네트워크 로드 밸런서(NLB)도 생성할 수 있습니다.
- Ingress 및 서비스 객체: ALB를 생성하려면 Kubernetes의 Ingress 객체를 사용하고, NLB를 생성하려면 서비스 객체에 NLB를 나타내는 주석을 추가해야 합니다.
2. 컨트롤러의 필요성 및 특징
- 최신 Ingress API 지원:
- 이전의 ALB Ingress 컨트롤러는 최신 Ingress API인
networking.k8s.io/v1
을 지원하지 않습니다. - Kubernetes 1.22 v 이후로 ALB Ingress 컨트롤러는 더 이상 지원되지 않고 사용 중단 될 예정입니다.
- 따라서 최신 AWS Load Balancer Controller를 활용해야 합니다. AWS 로드 밸런서 컨트롤러는 최신 Ingress API를 지원합니다.
- 기능 확장: 이 컨트롤러는 최신 Kubernetes 기능을 활용하며, EKS 클러스터에서 최신 Ingress 및 로드 밸런서 기능을 사용할 수 있도록 합니다.
3. AWS 로드 밸런서 컨트롤러 Deployment
- 네임스페이스
kube-system
네임스페이스: AWS 로드 밸런서 컨트롤러와 관련된 모든 리소스는 EKS 클러스터의kube-system
네임스페이스에 생성됩니다.
- 서비스 계정
- AWS Load Balancer Controller Service Account:
- 이 서비스 계정은 EKS 클러스터 내에서 AWS 로드 밸런서 컨트롤러를 위한 주요 계정입니다.
- IAM 정책 및 역할: 로드 밸런서 컨트롤러가 AWS 리소스를 생성, 업데이트, 삭제할 수 있도록
IAM 정책
과IAM 역할
을 정의합니다. 이 IAM 역할은 AWS Load Balancer Controller Service Account에 주석으로 추가됩니다.
- 컨트롤러 배포
- 컨트롤러를 배포하면 관련된 파드가 생성됩니다. 이 파드들은 EKS 클러스터 내에서 ALB와 NLB를 생성하고 관리할 수 있는 권한을 갖습니다.
- 이 컨트롤러 배포에는 로드 밸런서 컨트롤러 파드들이 있는데, 이 파드들은 EKS Cluster에서 AWS 서비스인 ALB를 생성할 능력을 가지고 있습니다.
- 이러한 작업이 가능한 이유는 로드 밸런서 컨트롤러에 부여된 권한(IAM) 때문입니다.
- 기타 생성 리소스
- Service Account: AWS 로드 밸런서 컨트롤러에 필요한 권한을 부여받는 계정입니다.
- AWS Load Balancer Controller Deployment: 로드 밸런서 컨트롤러의 주 배포 리소스입니다.
- AWS Load Balancer Controller Webhook Cluster IP Service: 웹훅 서비스로, 클러스터 내의 이벤트를 처리합니다.
- AWS Load Balancer TLS Service: 로드 밸런서와 관련된 TLS 비밀(Secret)을 관리합니다.
- 연결 및 권한
- 서비스 계정은 Deployment와 연결되며, 이 Deployment는 파드와도 연결됩니다.
- 따라서, 로드 밸런서 컨트롤러는 EKS 클러스터 내에서 Application Load Balancer (ALB)와 Network Load Balancer (NLB)를 생성하고 관리할 수 있는 권한을 가집니다.
4. 컨트롤러의 동작 방식
- Kubernetes API 감시: 컨트롤러는 Kubernetes API 서버에서 Ingress 이벤트를 감시하며, Ingress 리소스가 생성될 때 이를 감지하여 ALB를 생성합니다.
- AWS 리소스 생성: Kubernetes에서 Ingress 매니페스트를 배포하면, AWS에서 애플리케이션 로드 밸런서(ALB) 또는 네트워크 로드 밸런서(NLB)가 생성됩니다.
AWS Application Load Balancer (ALB)
1. AWS 애플리케이션 로드 밸런서(ALB) 개요
- ALB의 정의: ALB는 차세대 고급 로드 밸런서로, HTTP/HTTPS 트래픽의 라우팅을 담당하며, 다양한 라우팅 기능을 제공합니다.
- 주요 기능:
- 라우팅
- 경로 기반 라우팅: 특정 URL 경로에 따라 트래픽을 여러 애플리케이션으로 라우팅할 수 있습니다.
- /app1, /app2, /usermgmt ….
- 호스트 기반 라우팅: 도메인 이름에 따라 트래픽을 다른 애플리케이션으로 라우팅할 수 있습니다.
- web.example.com
- api.example.com …
- 다양한 라우팅 조건: HTTP 헤더, HTTP 메서드, 쿼리 매개변수, 소스 IP 주소 등의 조건을 기반으로 라우팅을 설정할 수 있습니다.
- Redirection
- 리디렉션 및 사용자 정의 응답: ALB는 요청을 다른 URL로 리디렉션하거나, 사용자 정의 HTTP 응답을 반환할 수 있습니다.
- Lambda 함수와 통합: ALB는 AWS Lambda 함수를 타겟으로 설정할 수 있으며, 서버리스 애플리케이션과의 통합을 지원합니다.
- 사용자 인증: ALB는 회사 또는 소셜 아이덴티티를 통한 사용자 인증을 지원하며, 이를 통해 애플리케이션에 대한 접근을 제어할 수 있습니다.
- 컨테이너화된 애플리케이션 지원:
- ALB는 AWS ECS와의 통합을 지원하며, 컨테이너 기반 애플리케이션의 로드 밸런싱을 제공합니다.
- ECS와의 통합을 아웃 오브 박스로 제공합니다.(기본 제공 기능)
- 상태 확인:
- 각 서비스의 상태를 독립적으로 모니터링할 수 있습니다.
- 타겟 그룹 레벨에서 상태 확인이 가능합니다.
- IP 기반 타겟 등록: ALB는 VPC 내부와 외부에서 IP 주소를 통해 타겟을 등록할 수 있습니다.
2. ALB Ingress 컨트롤러(ALB IC)
- 역할: ALB Ingress Controller는 Kubernetes 클러스터에서 Ingress 리소스를 생성할 때, 애플리케이션 로드 밸런서와 필요한 AWS 리소스를 자동으로 생성하고 관리합니다.
- ALB IC는 EKS 클러스터에서 Ingress 리소스가 생성될 때, Application Load Balancer와 필요한 AWS 리소스를 생성하는 작업을 트리거 합니다.
- Ingress 주석:
kubernetes.io/ingress.class=alb
주석을 사용해 ALB Ingress 컨트롤러를 트리거합니다. - 위 주석 이름과 함께 ALB IC가 Ingress 리소스와 함께 생성됩니다.
- 트래픽 모드:
- 인스턴스 모드: Ingress 컨트롤러가 클러스터의 노드를 ALB의 타겟으로 등록합니다.
- EKS 클러스터 내의 워커 노드가 ALB의 타겟으로 등록된다는 것을 의미합니다.
- 이 모드에서는 ALB에 도달한 트래픽이 Kubernetes의 NodePort로 라우팅됩니다.
- ALB ⇒ NodePort ⇒ Port로 Proxy, 이는 Application 앞에 NodePort 서비스를 생성할 때 ALB가 먼저 NodePort 서비스로 라우팅한 후 그 서비스가 포트로 라우팅되는 것을 의미합니다.
- 이 방식은 ALB Ingress manifest의 기본 트래픽 모드로, 기본 값 입니다.
- Ingress manifests에 alb.ingress.kubernetes.io/target-type: instance 주석을 추가하여 명시적으로 지정할 수 있습니다.
- IP 모드: Kubernetes 서비스의 포트가 직접 ALB의 타겟으로 등록됩니다.
- ALB에 도달하는 트래픽은 서비스의 Port로 직접 라우팅됩니다.
- Fargate를 사용하는 경우에는 반드시 IP 모드를 사용해야 합니다.
- Fargate 노드는 NodePort 서비스를 지원하지 않기 때문에(서버리스 개념) 백그라운드에서 생성된 노드에 대한 제어가 불가능합니다.
- 관리 노드 그룹을 사용할 때는 인스턴스 모드나 IP 모드 중 하나를 선택하는 개념입니다.
- 인스턴스 모드에서는 EKS 워커 노드가 ALB 타겟으로 등록 됐지만, IP 모드에서는 Port가 ALB의 타겟으로 등록됩니다.
- alb.ingress.kubernetes.io/target-type: IP를 사용하여 지정할 수 있습니다.
3. ALB Ingress 컨트롤러의 작동 원리
- Ingress 이벤트 감시:
- 컨트롤러는 Kubernetes API 서버에서 Ingress 이벤트를 감시합니다. Ingress 리소스가 요구 사항을 충족하면, 생성되면 필요한 AWS 리소스를 생성합니다.
- AWS 리소스 생성:
- 애플리케이션 로드 밸런서: Ingress 리소스가 생성되면, AWS에서 애플리케이션 로드 밸런서가 생성됩니다.
- 이 로드 밸런서는 ELB v2 유형을 가집니다.
- IAM 권한을 부여할 때 ELB v2도 포함되야 한다는 점에서 중요한 사항입니다.
- 타겟 그룹: 각 Kubernetes 서비스에서 Ingress 리소스에 정의된 각 서비스에 대해 타겟 그룹이 생성됩니다. 이는 매니페스트에 정의된 서비스와 연결됩니다.
- manifests에 정의된 Application 관련 NodePort 서비스가 생성되며 이에 따라 정의된 Port도 마찬가지로 생성됩니다.
- 리스너와 규칙: ALB에서 트래픽을 수신할 리스너(예: 포트 443)가 생성되며, Ingress 매니페스트에 정의된 경로 기반 및 호스트 기반 라우팅 규칙이 설정됩니다.
CREATE IAM & Service Account(SA)
1. IAM 정책 생성
- IAM 정책 파일 다운로드
- 최신 버전의 IAM 정책 파일을 다운로드합니다.
IAM policy latest.json
파일을 Visual Studio Code에서 열어 필요한 권한을 확인합니다.
iam
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "iam:CreateServiceLinkedRole" ], "Resource": "*", "Condition": { "StringEquals": { "iam:AWSServiceName": "elasticloadbalancing.amazonaws.com" } } }, { "Effect": "Allow", "Action": [ "ec2:DescribeAccountAttributes", "ec2:DescribeAddresses", "ec2:DescribeAvailabilityZones", "ec2:DescribeInternetGateways", "ec2:DescribeVpcs", "ec2:DescribeVpcPeeringConnections", "ec2:DescribeSubnets", "ec2:DescribeSecurityGroups", "ec2:DescribeInstances", "ec2:DescribeNetworkInterfaces", "ec2:DescribeTags", "ec2:GetCoipPoolUsage", "ec2:DescribeCoipPools", "elasticloadbalancing:DescribeLoadBalancers", "elasticloadbalancing:DescribeLoadBalancerAttributes", "elasticloadbalancing:DescribeListeners", "elasticloadbalancing:DescribeListenerCertificates", "elasticloadbalancing:DescribeSSLPolicies", "elasticloadbalancing:DescribeRules", "elasticloadbalancing:DescribeTargetGroups", "elasticloadbalancing:DescribeTargetGroupAttributes", "elasticloadbalancing:DescribeTargetHealth", "elasticloadbalancing:DescribeTags", "elasticloadbalancing:DescribeTrustStores" ], "Resource": "*" }, { "Effect": "Allow", "Action": [ "cognito-idp:DescribeUserPoolClient", "acm:ListCertificates", "acm:DescribeCertificate", "iam:ListServerCertificates", "iam:GetServerCertificate", "waf-regional:GetWebACL", "waf-regional:GetWebACLForResource", "waf-regional:AssociateWebACL", "waf-regional:DisassociateWebACL", "wafv2:GetWebACL", "wafv2:GetWebACLForResource", "wafv2:AssociateWebACL", "wafv2:DisassociateWebACL", "shield:GetSubscriptionState", "shield:DescribeProtection", "shield:CreateProtection", "shield:DeleteProtection" ], "Resource": "*" }, { "Effect": "Allow", "Action": [ "ec2:AuthorizeSecurityGroupIngress", "ec2:RevokeSecurityGroupIngress" ], "Resource": "*" }, { "Effect": "Allow", "Action": [ "ec2:CreateSecurityGroup" ], "Resource": "*" }, { "Effect": "Allow", "Action": [ "ec2:CreateTags" ], "Resource": "arn:aws:ec2:*:*:security-group/*", "Condition": { "StringEquals": { "ec2:CreateAction": "CreateSecurityGroup" }, "Null": { "aws:RequestTag/elbv2.k8s.aws/cluster": "false" } } }, { "Effect": "Allow", "Action": [ "ec2:CreateTags", "ec2:DeleteTags" ], "Resource": "arn:aws:ec2:*:*:security-group/*", "Condition": { "Null": { "aws:RequestTag/elbv2.k8s.aws/cluster": "true", "aws:ResourceTag/elbv2.k8s.aws/cluster": "false" } } }, { "Effect": "Allow", "Action": [ "ec2:AuthorizeSecurityGroupIngress", "ec2:RevokeSecurityGroupIngress", "ec2:DeleteSecurityGroup" ], "Resource": "*", "Condition": { "Null": { "aws:ResourceTag/elbv2.k8s.aws/cluster": "false" } } }, { "Effect": "Allow", "Action": [ "elasticloadbalancing:CreateLoadBalancer", "elasticloadbalancing:CreateTargetGroup" ], "Resource": "*", "Condition": { "Null": { "aws:RequestTag/elbv2.k8s.aws/cluster": "false" } } }, { "Effect": "Allow", "Action": [ "elasticloadbalancing:CreateListener", "elasticloadbalancing:DeleteListener", "elasticloadbalancing:CreateRule", "elasticloadbalancing:DeleteRule" ], "Resource": "*" }, { "Effect": "Allow", "Action": [ "elasticloadbalancing:AddTags", "elasticloadbalancing:RemoveTags" ], "Resource": [ "arn:aws:elasticloadbalancing:*:*:targetgroup/*/*", "arn:aws:elasticloadbalancing:*:*:loadbalancer/net/*/*", "arn:aws:elasticloadbalancing:*:*:loadbalancer/app/*/*" ], "Condition": { "Null": { "aws:RequestTag/elbv2.k8s.aws/cluster": "true", "aws:ResourceTag/elbv2.k8s.aws/cluster": "false" } } }, { "Effect": "Allow", "Action": [ "elasticloadbalancing:AddTags", "elasticloadbalancing:RemoveTags" ], "Resource": [ "arn:aws:elasticloadbalancing:*:*:listener/net/*/*/*", "arn:aws:elasticloadbalancing:*:*:listener/app/*/*/*", "arn:aws:elasticloadbalancing:*:*:listener-rule/net/*/*/*", "arn:aws:elasticloadbalancing:*:*:listener-rule/app/*/*/*" ] }, { "Effect": "Allow", "Action": [ "elasticloadbalancing:ModifyLoadBalancerAttributes", "elasticloadbalancing:SetIpAddressType", "elasticloadbalancing:SetSecurityGroups", "elasticloadbalancing:SetSubnets", "elasticloadbalancing:DeleteLoadBalancer", "elasticloadbalancing:ModifyTargetGroup", "elasticloadbalancing:ModifyTargetGroupAttributes", "elasticloadbalancing:DeleteTargetGroup" ], "Resource": "*", "Condition": { "Null": { "aws:ResourceTag/elbv2.k8s.aws/cluster": "false" } } }, { "Effect": "Allow", "Action": [ "elasticloadbalancing:AddTags" ], "Resource": [ "arn:aws:elasticloadbalancing:*:*:targetgroup/*/*", "arn:aws:elasticloadbalancing:*:*:loadbalancer/net/*/*", "arn:aws:elasticloadbalancing:*:*:loadbalancer/app/*/*" ], "Condition": { "StringEquals": { "elasticloadbalancing:CreateAction": [ "CreateTargetGroup", "CreateLoadBalancer" ] }, "Null": { "aws:RequestTag/elbv2.k8s.aws/cluster": "false" } } }, { "Effect": "Allow", "Action": [ "elasticloadbalancing:RegisterTargets", "elasticloadbalancing:DeregisterTargets" ], "Resource": "arn:aws:elasticloadbalancing:*:*:targetgroup/*/*" }, { "Effect": "Allow", "Action": [ "elasticloadbalancing:SetWebAcl", "elasticloadbalancing:ModifyListener", "elasticloadbalancing:AddListenerCertificates", "elasticloadbalancing:RemoveListenerCertificates", "elasticloadbalancing:ModifyRule" ], "Resource": "*" } ] }
- IAM 정책 생성
- AWS CLI를 사용하여 IAM 정책을 생성합니다.
- 명령어 예시:
- 생성된 IAM 정책의 ARN을 기록해 둡니다. 이 ARN은 이후 단계에서 사용됩니다.
aws iam create-policy \ --policy-name AWSLoadBalancerControllerIAMPolicy \ --policy-document file://iam_policy_latest.json
arn:aws:iam::{id}:policy/AWSLoadBalancerControllerIAMPolicy
2. IAM 역할 및 서비스 계정 생성
eksctl
명령어로 IAM 역할 및 서비스 계정 생성eksctl
을 사용하여 IAM 역할과 Kubernetes 서비스 계정을 생성하고 연결합니다.- 명령어 예시:
<region>
은 AWS 리전을,<cluster-name>
은 EKS 클러스터 이름을,<policy-arn>
은 생성한 IAM 정책의 ARN을 입력합니다.
eksctl create iamserviceaccount \ --cluster=eksdemo \ --namespace=kube-system \ --name=aws-load-balancer-controller \ --attach-policy-arn=arn:aws:iam::arn \ --override-existing-serviceaccounts \ --approve
- 서비스 계정 확인
- 명령어 예시:
AWS load balancer controller
라는 이름의 서비스 계정이 생성되었는지 확인합니다.- iam 역할의 ARN을 Kubernetes 서비스 계정에 추가합니다.
eksctl get iamserviceaccount --cluster eksdemo
- 클라우드 포메이션 스택 확인
eksctl
명령어는 클라우드 포메이션 스택을 생성하여 IAM 역할과 서비스를 설정합니다. 이 스택의 상태를 확인하여 작업이 완료되었는지 검토합니다.
AWS LoadBalancer Controller Install & Helm
1. Helm 설치
- Helm 설치 방법
- macOS:
brew install helm
명령어를 사용하여 설치합니다. - Windows: Chocolatey를 사용하여
choco install kubernetes-helm
명령어로 설치합니다. - Linux: Helm 바이너리를 다운로드하고, 설치 스크립트(gethelm.sh)를 사용하여 설치합니다.
brew install helm helm version
choco install kubernetes-helm
- Helm 설치 확인
- Helm이 설치된 후,
helm version
명령어를 사용하여 설치된 버전을 확인합니다. - 예시: Helm v3.8.0 설치 확인.
2. AWS 로드 밸런서 컨트롤러 설치 전 준비
- 중요 사항
- EC2 노드 IMDS 제한 또는 Fargate 사용 시:
- Helm 설치 명령어에 리전 코드와 VPC ID를 명시해야 합니다.
- U.S. West 2 외의 리전에서 배포 시:
- ECR 이미지 저장소를 해당 리전의 엔드포인트로 설정해야 합니다.
- Helm 차트 저장소 추가
helm repo add eks https://aws.github.io/eks-charts
명령어를 사용하여 EKS 차트 저장소를 추가합니다.helm repo update
명령어로 저장소를 업데이트하여 최신 버전으로 동기화합니다.
// 설치되지 않은 경우 "eks" has been added to your repositories // 설치된 경우 "eks" already exists with the same configuration, skipping
helm repo update Hang tight while we grab the latest from your chart repositories... ...Successfully got an update from the "eks" chart repository Update Complete. ⎈Happy Helming!⎈
3. AWS 로드 밸런서 컨트롤러 설치
- 설치 명령어 구성
- AWS-load-balancer-controller 패키지를 설치하며, 주요 설정은 다음과 같습니다:
- Namespace:
kube-system
- 클러스터 이름: 예시에서는
EKS-demo-one
- 서비스 계정: 이미 생성된
aws-load-balancer-controller
계정을 사용 - 리전 코드:
us-east-1
- VPC ID: AWS EKS VPC ID
- 설치 명령어 실행
- Helm 설치 명령어를 복사하여 실행합니다.
- 명령어가 성공적으로 실행되면, AWS 로드 밸런서 컨트롤러가 설치됩니다.
helm install aws-load-balancer-controller eks/aws-load-balancer-controller \ -n kube-system \ --set clusterName=eksdemo \ --set serviceAccount.create=false \ --set serviceAccount.name=aws-load-balancer-controller \ --set region=ap-northeast-2 \ --set vpcId=vpc-0acc1c37d73dd23ab \ --set image.repository=602401143452.dkr.ecr.ap-northeast-2.amazonaws.com/amazon/aws-load-balancer-controller NAME: aws-load-balancer-controller LAST DEPLOYED: Mon Aug 19 22:59:16 2024 NAMESPACE: kube-system STATUS: deployed REVISION: 1 TEST SUITE: None NOTES: AWS Load Balancer controller installed!
Load Balancer Controller & Webhook Service
1. AWS 로드 밸런서 컨트롤러 설치 확인
- 배포 상세 정보 확인:
- 배포의 이름을 사용하여 자세한 정보를 확인합니다.
- 여기에는 설치된 컨트롤러의 버전, Helm 차트 버전, 선택자 레이블, 사용된 포트, 서비스 계정, TLS 인증서 등의 정보가 포함됩니다.
- Labels를 통해 다음의 정보를 얻을 수 있습니다.
- Selector 를 통해 다음의 정보를 얻을 수 있습니다.
- StrategtyType 또한 확인할 수 있습니다.
- Containers의 Argument를 통해 다음을 확인할 수 있습니다.
- Container를 보면 Port가
kubectl -n kube-system get deployment aws-load-balancer-controller kubectl -n kube-system describe deployment aws-load-balancer-controller
app.kubernetes.io/instance=aws-load-balancer-controller app.kubernetes.io/managed-by=Helm app.kubernetes.io/name=aws-load-balancer-controller app.kubernetes.io/version=v2.8.2 // load balancer controlelr version helm.sh/chart=aws-load-balancer-controller-1.8.2 // helm chart version
app.kubernetes.io/instance=aws-load-balancer-controller, app.kubernetes.io/name=aws-load-balancer-controller
StrategyType: RollingUpdate RollingUpdateStrategy: 25% max unavailable, 25% max surge
Args: --cluster-name=eksdemo --ingress-class=alb --aws-region=ap-northeast-2 --aws-vpc-id=
Ports: 9443/TCP, 8080/TCP
인데 일반적으로 9443은 TLS/SSL 트래픽을 처리하는데 사용된다. 그리고 아래쪽으로 좀 더 내려보면
Volumes: cert: Type: Secret (a volume populated by a Secret) SecretName: aws-load-balancer-tls Optional: false
이런 정보가 있는데 이는 로드밸런서 컨트롤러가 9443 포트에 수신 대기하면서 TLS (SSL) 통신을 처리하고, 이 때문에 TLS 인증서가 필요하며 해당 인증서는 Secret으로 관리되다가 Volumes으로 마운드되어 Ingress Controller가 사용할 수 있게 된다는 것을 의미합니다.
2. 웹후크 서비스 확인
- 서비스 상태 확인:
kube-system
네임스페이스에서 실행되는 모든 서비스를 나열합니다.- AWS 로드 밸런서 웹후크 서비스가 포트 443에서 수신 대기하고 있는지 확인할 수 있습니다.
kubectl -n kube-system get svc aws-load-balancer-webhook-service ClusterIP 웹훅 클러스터 아이피 <none> 443/TCP 23m kube-dns ClusterIP 디엔에스 아이피 <none> 53/UDP,53/TCP,9153/TCP 29h
- 서비스와 배포의 선택자 레이블 확인:
- 예시: 서비스 Selector Lables가
app.kubernetes.io/instance
와app.kubernetes.io/name
이고, Deployment과 Selector Lable과 일치해야 합니다.
kubectl -n kube-system get svc aws-load-balancer-webhook-service -o yaml // 서비스 선택자 확인 kubectl -n kube-system get deployment aws-load-balancer-controller -o yaml // 배포 선택자 확인
webhook service
apiVersion: v1 kind: Service metadata: annotations: meta.helm.sh/release-name: aws-load-balancer-controller meta.helm.sh/release-namespace: kube-system creationTimestamp: "2024-08-19T13:59:17Z" labels: app.kubernetes.io/component: webhook app.kubernetes.io/instance: aws-load-balancer-controller app.kubernetes.io/managed-by: Helm app.kubernetes.io/name: aws-load-balancer-controller app.kubernetes.io/version: v2.8.2 helm.sh/chart: aws-load-balancer-controller-1.8.2 prometheus.io/service-monitor: "false" name: aws-load-balancer-webhook-service namespace: kube-system resourceVersion: "283699" uid: uid spec: clusterIP: ip clusterIPs: - ips internalTrafficPolicy: Cluster ipFamilies: - IPv4 ipFamilyPolicy: SingleStack ports: - name: webhook-server port: 443 protocol: TCP targetPort: webhook-server selector: app.kubernetes.io/instance: aws-load-balancer-controller app.kubernetes.io/name: aws-load-balancer-controller sessionAffinity: None type: ClusterIP status: loadBalancer: {}
load balancer controller
apiVersion: apps/v1 kind: Deployment metadata: annotations: deployment.kubernetes.io/revision: "1" meta.helm.sh/release-name: aws-load-balancer-controller meta.helm.sh/release-namespace: kube-system creationTimestamp: "2024-08-19T13:59:17Z" generation: 1 labels: app.kubernetes.io/instance: aws-load-balancer-controller app.kubernetes.io/managed-by: Helm app.kubernetes.io/name: aws-load-balancer-controller app.kubernetes.io/version: v2.8.2 helm.sh/chart: aws-load-balancer-controller-1.8.2 name: aws-load-balancer-controller namespace: kube-system resourceVersion: "283814" uid: uid spec: progressDeadlineSeconds: 600 replicas: 2 revisionHistoryLimit: 10 selector: matchLabels: app.kubernetes.io/instance: aws-load-balancer-controller app.kubernetes.io/name: aws-load-balancer-controller strategy: rollingUpdate: maxSurge: 25% maxUnavailable: 25% type: RollingUpdate template: metadata: annotations: prometheus.io/port: "8080" prometheus.io/scrape: "true" creationTimestamp: null labels: app.kubernetes.io/instance: aws-load-balancer-controller app.kubernetes.io/name: aws-load-balancer-controller spec: affinity: podAntiAffinity: preferredDuringSchedulingIgnoredDuringExecution: - podAffinityTerm: labelSelector: matchExpressions: - key: app.kubernetes.io/name operator: In values: - aws-load-balancer-controller topologyKey: kubernetes.io/hostname weight: 100 containers: - args: - --cluster-name= - --ingress-class=alb - --aws-region= - --aws-vpc-id= image: 602401143452.dkr.ecr.ap-northeast-2.amazonaws.com/amazon/aws-load-balancer-controller:v2.8.2 imagePullPolicy: IfNotPresent livenessProbe: failureThreshold: 2 httpGet: path: /healthz port: 61779 scheme: HTTP initialDelaySeconds: 30 periodSeconds: 10 successThreshold: 1 timeoutSeconds: 10 name: aws-load-balancer-controller ports: - containerPort: 9443 name: webhook-server protocol: TCP - containerPort: 8080 name: metrics-server protocol: TCP readinessProbe: failureThreshold: 2 httpGet: path: /readyz port: 61779 scheme: HTTP initialDelaySeconds: 10 periodSeconds: 10 successThreshold: 1 timeoutSeconds: 10 resources: {} securityContext: allowPrivilegeEscalation: false readOnlyRootFilesystem: true runAsNonRoot: true terminationMessagePath: /dev/termination-log terminationMessagePolicy: File volumeMounts: - mountPath: /tmp/k8s-webhook-server/serving-certs name: cert readOnly: true dnsPolicy: ClusterFirst priorityClassName: system-cluster-critical restartPolicy: Always schedulerName: default-scheduler securityContext: fsGroup: 65534 serviceAccount: aws-load-balancer-controller serviceAccountName: aws-load-balancer-controller terminationGracePeriodSeconds: 10 volumes: - name: cert secret: defaultMode: 420 secretName: aws-load-balancer-tls status: availableReplicas: 2 conditions: - lastTransitionTime: "2024-08-19T13:59:38Z" lastUpdateTime: "2024-08-19T13:59:38Z" message: Deployment has minimum availability. reason: MinimumReplicasAvailable status: "True" type: Available - lastTransitionTime: "2024-08-19T13:59:17Z" lastUpdateTime: "2024-08-19T13:59:38Z" message: ReplicaSet "aws-load-balancer-controller-567f5dff44" has successfully progressed. reason: NewReplicaSetAvailable status: "True" type: Progressing observedGeneration: 1 readyReplicas: 2 replicas: 2 updatedReplicas: 2
정리하자면 이렇다.
서비스 셀렉터와 레이블 셀렉터의 일치
- 서비스 셀렉터: Kubernetes 서비스는 특정 파드로 트래픽을 라우팅하기 위해 레이블 셀렉터를 사용합니다. 이 레이블 셀렉터는 서비스와 연결된 포드의 레이블과 일치해야 합니다.
- 여기서 사용할 서비스는 aws-load-balancer-webhook-service을 의미한다.
- 즉, 웹훅 서비스는 특정 파드로 트래픽을 라우팅하기 위해 Lable Selector를 사용하늗네 이 레이블 셀렉터는 연결된 파드의 레이블과 일치해야 하고 여기서 파드는 Kubernetes Controller를 의미한다.
aws-load-balancer-controller-567f5dff44-frz9f 1/1 Running 0 34m aws-load-balancer-controller-567f5dff44-gp6t5 1/1 Running 0 34m
트래픽 포트 매핑
- 443 포트: 일반적으로 HTTPS 트래픽이 들어오는 포트입니다.
- 9443 포트: 설명에 따르면, AWS Load Balancer Controller는 이 포트에서 TLS를 통해 통신합니다. 따라서 포트 443에서 들어오는 트래픽은 컨트롤러의 포트 9443으로 전달되어야 합니다.
웹후크 서비스와 컨트롤러 포트 확인
- 웹후크 서비스: 포트 443에서 수신 대기하고 있으며, AWS Load Balancer Controller가 이 포트에서 요청을 받는 웹후크 서비스와 상호작용합니다.
- 컨트롤러 포트: AWS Load Balancer Controller의 포트 9443은 이 웹후크 서비스와 상호작용하는 데 사용됩니다. 즉, 포트 9443이 웹후크 서비스와의 연결을 위해 설정된 것입니다.
1. 로드 밸런서 컨트롤러 로그 확인
- 파드 나열:
- 이 명령어를 사용하여
kube-system
네임스페이스에서 실행 중인 모든 파드를 나열합니다. - AWS 로드 밸런서 컨트롤러와 관련된 두 개의 파드를 확인할 수 있습니다.
kubectl get pods -n kube-system aws-load-balancer-controller-567f5dff44-frz9f 1/1 Running 0 41m aws-load-balancer-controller-567f5dff44-gp6t5 1/1 Running 0 41m aws-node-tkg7k 2/2 Running 0 29h aws-node-zkbdc 2/2 Running 0 29h coredns-5b9dfbf96-mwmng 1/1 Running 0 29h coredns-5b9dfbf96-z8pml 1/1 Running 0 29h kube-proxy-2464v 1/1 Running 0 29h kube-proxy-xbm4n 1/1 Running 0 29h
- 파드 로그 확인:
- 각 파드의 로그를 실시간으로 확인할 수 있습니다.
- 로그에 정보만 표시되는 경우, 문제가 없음을 의미합니다. 오류가 있을 경우, 로그에서 문제를 찾아볼 수 있습니다.
kubectl -n kube-system logs -f <POD-NAME> kubectl -n kube-system logs -f aws-load-balancer-controller-567f5dff44-gp6t5 {"level":"info","ts":"2024-08-19T13:59:20Z","msg":"version","GitVersion":"v2.8.2","GitCommit":"f39ae43121c3f4de0129dda483c10b17a687491d","BuildDate":"2024-08-09T20:18:06+0000"} {"level":"info","ts":"2024-08-19T13:59:20Z","logger":"setup","msg":"adding health check for controller"} {"level":"info","ts":"2024-08-19T13:59:20Z","logger":"setup","msg":"adding readiness check for webhook"} {"level":"info","ts":"2024-08-19T13:59:20Z","logger":"controller-runtime.webhook","msg":"Registering webhook","path":"/mutate-v1-pod"} {"level":"info","ts":"2024-08-19T13:59:20Z","logger":"controller-runtime.webhook","msg":"Registering webhook","path":"/mutate-v1-service"} {"level":"info","ts":"2024-08-19T13:59:20Z","logger":"controller-runtime.webhook","msg":"Registering webhook","path":"/validate-elbv2-k8s-aws-v1beta1-ingressclassparams"}
2. 서비스 계정 및 비밀 검토
- 서비스 계정 정보 확인:
- 서비스 계정의 상세 정보를 YAML 형식으로 확인합니다.
- 여기에는 서비스 계정 이름, 네임스페이스, 주석으로 IAM 역할 등이 포함되어 있습니다.
kubectl -n kube-system get sa aws-load-balancer-controller ------------------------ kubectl -n kube-system get sa aws-load-balancer-controller -o yaml apiVersion: v1 kind: ServiceAccount metadata: annotations: eks.amazonaws.com/role-arn: service account arn creationTimestamp: "2024-08-18T16:34:58Z" labels: app.kubernetes.io/managed-by: eksctl name: aws-load-balancer-controller namespace: kube-system resourceVersion: "76198" uid: uid ------------------------- kubectl -n kube-system get secret aws-load-balancer-tls kubernetes.io/tls 3 45m sh.helm.release.v1.aws-load-balancer-controller.v1 helm.sh/release.v1 1 45m -------------------------- kubectl -n kube-system get secret <GET_FROM_PREVIOUS_COMMAND - secrets.name> -o yaml
원래는 kubectl -n kube-system get sa aws-load-balancer-controller -o yaml
를 통해 secret을 확인할 수 있어야 하지만, 내 경우엔 확인할 수 없었습니다. 왜일까요?
K8s 1.24 이후에는 Service Account 으로 Secret을 만드는 것이 기본 설정이 아닙니다. 강의에서는 Secret을 확인하여 만들고 있지만 최신버전(나의 경우 1.3) SA 생성 시 기본적으로 Secret 생성을 지원하지 않아 표시되지 않습니다.
aws eks describe-cluster --name eksdemo --query "cluster.version" --output text // 1.30
apiVersion: v1 kind: Secret metadata: name: sa1-token annotations: kubernetes.io/service-account.name: sa1 type: kubernetes.io/service-account-token
필요한 경우 비밀을 명시적으로 만드는 것이 모든 버전에서 권장되는 접근 방식입니다.
- 비밀 확인:
- 비밀의 YAML 형식을 확인하여 CA 인증서 및 토큰 정보를 포함한 내용을 검토합니다.
- 물론 1.24 이후 버전에서는 확인할 수 없지만 이 CA 인증서 및 JWT 토큰은 매우 중요한데 그 이유는
- 로드 밸런서 컨트롤러가 AWS Application Load Balancer를 생성할 때
- Ingress manifests가 배포되면
- k8s API 서버가 정보를 받고
- 로드 밸런서 컨트롤러가 Ingress 이벤트를 감시하여
- AWS Load Balancer를 생성하게 되는데
- 이 때 EKS Cluster와 AWS Service 간의 인증 메커니즘이 필요하기 때문이며 이 때 사용하는 메커니즘이 JWT 토큰입니다.
- 좀 더 자세하게 설명하면,
- 기본적으로 IAM은 AWS Service에 접근할 수 있도록 하는 서비스 입니다.
- EKS는 IAM에서 관리하는 인증과 권한 시스템을 통해 AWS 서비스에 접근할 수 있습니다.
- 이를 통해 EKS는 AWS Service와 상호작용할 수 있는데, Cluster 내의 SA(Service Account)는 Container와 Application이 Cluster 내부에서 AWS Service와 통신할 때 사용되는 증명입니다.
- 이 때 이 서비스 계정인 SA는 EKS 클러스터 내에서 토큰을 사용하여 AWS Service와 인증을 수행하게 되기 때문에 중요하다고 볼수 있습니다.
- kubectl -n kube-system get pod <load balancer controller> -o yaml 를 통해 아래 정보를 확인할 수 있는데
kubectl -n kube-system get pods kubectl -n kube-system get pod <AWS-Load-Balancer-Controller-POD-NAME> -o yaml kubectl -n kube-system get deploy aws-load-balancer-controller -o yaml
env: - name: AWS_STS_REGIONAL_ENDPOINTS value: regional - name: AWS_DEFAULT_REGION value: ap-northeast-2 - name: AWS_REGION value: ap-northeast-2 - name: AWS_ROLE_ARN value: arn - name: AWS_WEB_IDENTITY_TOKEN_FILE value: /var/run/secrets/eks.amazonaws.com/serviceaccount/token volumeMounts: - mountPath: /tmp/k8s-webhook-server/serving-certs name: cert readOnly: true - mountPath: /var/run/secrets/kubernetes.io/serviceaccount name: kube-api-access-fkxb2 readOnly: true - mountPath: /var/run/secrets/eks.amazonaws.com/serviceaccount name: aws-iam-token readOnly: true
여기서 aws-iam-token를 통해 EC2 인스턴스의 값과 비밀 경로를 확인할 수 있습니다.
- 토큰 디코딩:
- 비밀의 JWT 토큰을 디코딩하여 서비스 계정, 네임스페이스, 메타데이터 등의 정보를 확인합니다.
- JWT 디코더를 사용하여 디코딩된 토큰을 검토하면, EKS 클러스터와 AWS 서비스 간의 인증 메커니즘을 이해하는 데 도움이 됩니다.
3. 로드 밸런서 컨트롤러 제거 (선택 사항)
- 로드 밸런서 컨트롤러 제거:
- 명령어:
kubectl delete -n kube-system deploy <로드 밸런서 컨트롤러 이름>
- AWS 로드 밸런서 컨트롤러를 클러스터에서 제거하는 명령어입니다.
- 이 단계는 필요하지 않다면 건너뛰어도 됩니다.
helm uninstall aws-load-balancer-controller -n kube-system
Ingress Class
인그레스 클래스(IngressClass) 개념
문제 시나리오
- Kubernetes 클러스터에서는 다양한 인그레스 컨트롤러가 동시에 운영될 수 있습니다. 예를 들어, EKS에서는 AWS ALB(Application Load Balancer) 인그레스 컨트롤러와 NGINX 인그레스 컨트롤러가 함께 사용될 수 있으며, AKS에서는 Azure Application Gateway 인그레스 컨트롤러가 사용될 수 있습니다.
- 이와 같은 멀티 컨트롤러 환경에서는 특정 인그레스 리소스가 어떤 인그레스 컨트롤러에 의해 관리될지를 명확히 정의해야 합니다.
인그레스 클래스(IngressClass)
- 정의: 인그레스 클래스는 Kubernetes 인그레스 리소스가 특정 인그레스 컨트롤러에 의해 처리되도록 매핑하는 Kubernetes 리소스입니다.
- 목표: 여러 인그레스 컨트롤러가 존재하는 클러스터에서 인그레스 리소스와 컨트롤러 간의 명확한 연결을 설정합니다.
인그레스 클래스 리소스의 구성
- API 버전:
networking.k8s.io/v1
- kind:
IngressClass
- metadata: 인그레스 클래스의 메타데이터를 정의하며, 주요 항목으로는 이름과 주석이 있습니다.
- 예:
name: my-aws-ingress-class
- spec: 인그레스 클래스의 동작을 정의합니다.
- controller: 인그레스 클래스가 연결될 인그레스 컨트롤러를 지정합니다. 예:
ingress.k8s.aws/alb
는 AWS ALB 인그레스 컨트롤러를 의미합니다.
기본 인그레스 클래스 설정
- 주석:
ingressclass.kubernetes.io/is-default-class
를 통해 인그레스 클래스를 기본 클래스로 지정할 수 있습니다. - *
true
*로 설정된 경우, 해당 인그레스 클래스가 클러스터의 기본 인그레스 클래스로 간주됩니다. 이 경우, 인그레스 리소스가 별도로 인그레스 클래스를 지정하지 않더라도 자동으로 이 클래스를 사용합니다. - 기본 클래스로 설정되지 않은 경우, 인그레스 리소스의
spec.ingressClassName
필드를 사용하여 명시적으로 인그레스 클래스를 지정해야 합니다.
인그레스 리소스(Ingress Resource)
- API 버전:
networking.k8s.io/v1
- kind:
Ingress
- metadata: 인그레스 리소스의 식별 정보와 메타데이터를 정의합니다.
- 예:
name: ingress-nginx-app
- spec: 인그레스 리소스가 관리할 백엔드 서비스 및 트래픽 라우팅 규칙을 정의합니다.
- defaultBackend: 기본 백엔드 서비스를 지정하며, 트래픽이 이 서비스로 전달됩니다.
- rules: 호스트 및 경로에 기반하여 트래픽을 다양한 백엔드 서비스로 라우팅합니다.
인그레스 클래스와 인그레스 리소스 간의 연결
- 명시적 연결: 인그레스 리소스의
spec.ingressClassName
필드를 통해 특정 인그레스 클래스를 지정하여 인그레스 컨트롤러와 연결할 수 있습니다.
- 기본 클래스 사용: 기본 인그레스 클래스를 설정한 경우,
spec.ingressClassName
을 생략할 수 있으며, 클러스터에서 기본으로 정의된 인그레스 클래스가 자동으로 적용됩니다.
Share article