EKS는 파드 네트워킹을 위한 CNI 플러그인으로 Amazon VPC CNI 플러그인을 사용한다. 문제는 이 CNI가 각 파드 마다 ENI를 통해 IP를 추가하는데, ENI는 EC2 인스턴스 크기에 따라 개수가 제한되어 있다.
예를 들어 m5.large (2 CPU, 8GB RAM) 인스턴스의 경우 29개의 파드 개수 제한이 생긴다. (각 인스턴스 별 제한은 이 문서 참고)
무거운 파드 몇 개를 돌릴 목적이라면 모르겠지만 개발 환경 처럼 가벼운 파드를 여러 개 띄우게 되면 이 제한에 금방 다다르게 된다.
이 제한을 벗어나려면 다른 CNI 플러그인을 설치하면 된다. 하지만 이 방법은 마스터 노드와 일꾼 노드가 다른 CNI를 사용하게 되어 여러 가지 문제를 발생시킨다. 대표적으로 ALB 인그레스 컨트롤러 설치가 제대로 되지 않는다.
ALB 인그레스 컨트롤러 설치
공식 문서를 통해 ALB 인그레스 컨트롤러를 설치하다 보면 1~6단계까지는 별문제 없이 진행되지만 7번 단계에서 문제가 발생한다.
1. IAM OIDC provider 생성
eksctl utils associate-iam-oidc-provider \
--region <region-code> \
--cluster <my-cluster> \
--approve
2. IAM policy 파일 다운로드
curl -o iam-policy.json https://raw.githubusercontent.com/kubernetes-sigs/aws-load-balancer-controller/main/docs/install/iam_policy.json
3. 다운받은 파일로 policy 생성
aws iam create-policy \
--policy-name AWSLoadBalancerControllerIAMPolicy \
--policy-document file://iam-policy.json
이 명령의 결과로 나오는 policy ARN을 기억한다.
4. IAM Role과 iamserviceaccount 생성
아래 명령에서 ARN 부분은 3번의 결과로 나온 policy-arn을 사용한다.
eksctl create iamserviceaccount \
--cluster=<my-cluster> \
--namespace=kube-system \
--name=aws-load-balancer-controller \
--attach-policy-arn=arn:aws:iam::<AWS_ACCOUNT_ID>:policy/AWSLoadBalancerControllerIAMPolicy \
--override-existing-serviceaccounts \
--approve
이렇게 생성된 Role과 여기에 붙은 Policy는 IAM에서 확인할 수 있다.
5. 기존에 ALB 인그레스 컨트롤러가 있었다면 삭제
없음으로 생략한다.
6. Helm을 사용해서 cert-manager 설치
매니페스트를 사용해 설치할 것이므로 생략한다.
7. 수동으로 cert-manager 설치
이 단계에서 Calico와의 문제가 생긴다. Webhook 을 사용하면 이벤트 발생 시 마스터 노드에서 일꾼 노드에 요청을 보내는 것으로 보이는데, CNI가 달라서 연결에 실패하는 것으로 보인다.
피해갈 수 있는 방법은 파드가 hostNetwork
을 사용해야 하며 이럴 경우 호스트에서 사용 중이지 않은 포트를 사용해야 한다.
참고 문서
- https://cert-manager.io/docs/concepts/webhook/#webhook-connection-problems-on-aws-eks
- https://cert-manager.io/docs/installation/compatibility/#aws-eks
a. cert-manager 설치
helm을 사용한 경우라면 파라메터를 바꿔서 해결할 수 있지만 여기서는 매니페스트를 직접 다운받아 변경해서 설치해 보도록 한다.
curl -L -o cert-manager.yaml https://github.com/jetstack/cert-manager/releases/download/v1.0.2/cert-manager.yaml
다운 받은 파일에서 아래 굵게 표시한 것과 같이 hostNetwork
을 추가하고 포트를 변경한다. (기본값은 kubelet 포트와 충돌한다.)
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: webhook
app.kubernetes.io/component: webhook
app.kubernetes.io/instance: cert-manager
app.kubernetes.io/name: webhook
name: cert-manager-webhook
namespace: cert-manager
spec:
replicas: 1
selector:
matchLabels:
app.kubernetes.io/component: webhook
app.kubernetes.io/instance: cert-manager
app.kubernetes.io/name: webhook
template:
metadata:
labels:
app: webhook
app.kubernetes.io/component: webhook
app.kubernetes.io/instance: cert-manager
app.kubernetes.io/name: webhook
spec:
hostNetwork: true
containers:
- args:
- --v=2
- --secure-port=10255
- --dynamic-serving-ca-secret-namespace=$(POD_NAMESPACE)
- --dynamic-serving-ca-secret-name=cert-manager-webhook-ca
- --dynamic-serving-dns-names=cert-manager-webhook,cert-manager-webhook.cert-manager,cert-manager-webhook.cert-manager.svc
변경한 파일을 적용한다.
kubectl apply --validate=false cert-manager.yaml
b. 컨트롤러 설치
매니패스트 파일 다운 받는다.
curl -o v2_0_0_full.yaml https://raw.githubusercontent.com/kubernetes-sigs/aws-load-balancer-controller/main/docs/install/v2_0_0_full.yaml
다운받은 파일에서 아래 굵게 표시한 것과 같이 hostNetwork
을 추가하고 cluster-name
을 변경한다.
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app.kubernetes.io/component: controller
app.kubernetes.io/name: aws-load-balancer-controller
name: aws-load-balancer-controller
namespace: kube-system
spec:
replicas: 1
selector:
matchLabels:
app.kubernetes.io/component: controller
app.kubernetes.io/name: aws-load-balancer-controller
template:
metadata:
labels:
app.kubernetes.io/component: controller
app.kubernetes.io/name: aws-load-balancer-controller
spec:
hostNetwork: true
containers:
- args:
- --cluster-name=<my-cluster>
- --ingress-class=alb
문서에서 권장하는 것처럼 서비스 어카운트도 삭제한다.
변경한 파일을 적용한다.
kubectl apply -f v2_0_0_full.yaml
8. 확인
kubectl get deployment -n kube-system aws-load-balancer-controller