$ kubectl describe ingress my_ingress -n my_namespace
Type Reason Age From Message
---- ------ ---- ---- -------
Warning FailedDeployModel 3m41s ingress Failed deploy model due to AccessDenied: User: arn:aws:sts::110111011101:assumed-role/myEKSLoadBalancerControllerRole/1234561234561234561 is not authorized to perform: elasticloadbalancing:AddTags on ause no identity-based policy allows the elasticloadbalancing:AddTags action
구글에서는 위 에러 메시지와 관련된 내용은 찾기 어려웠다. AWS 문서 뒤적이며 loadBalancerController 생성하는 부분을 찾아보니, iam_policy.json 파일이 v2.3.0 에서 v.2.5.4 로 업데이트 되어 있었고, 아래 정책이 추가된 것을 확인했다.
maxSurge 와 maxUnavailable 값은 배포시 최대 생성 pod 수와 종료 수를 명시할 수 있다. 각각 0/1, 1/0 으로 설정할 경우 running 상태 이후에 terminating 을 시키느냐, pending 과 동시에 terminating 을 시키느냐의 차이이며 약 30초 정도의 차이를 확인했다.
겉보기에는 잘 작동하는 것처럼 보이나 배포시 약 5~10초간 502 Gateway Error 뒤에 504 Gateway Time-out 이 발생한다. 우선 502 에러가 발생하는 시점을 찾아봤다.
쿠버네티스에서 kubectl rollout restart 명령으로 배포할 경우, 새 pod 가 추가되고 Running 상태가 되면 기존 포드가 삭제되는 식이다. 확인 결과 pod 가 Terminating 되는 순간에 502 에러가 발생했다. ALB 의 Target 이 동시에 draining 되는 시점이기도 하다. 인터넷을 후벼파서 결과, 502 에러를 최소화 할 수 있는 방법을 찾아 결국 해냈다.
readiness-gate 옵션을 활성화 하여 새로운 target 이 healthy 상태로 연결되기 전까지 기존 target 을 종료하지 않음. (마찬가지로 502 에러는 발생하나, ALB 내의 target 이 healthy 상태가 한개도 유지되지 않는 어이없는 상황은 막을 수 있음). 반드시 필요!
readiness-gate 옵션을 활성화할 namespace 에 레이블을 설정하고, target-health.alb.ingress.k8s.aws/{ingress-name}_{service-name}_{port} 를 위처럼 삽입한다. 설정이 올바르지 않으면 ALB 에서 target 그룹을 인식하지 못할 수도 있으니 주의!
3. pod : preStop설정
life-cycle hooks 에서 pod 가 중지되기 전에(preStop) 딜레이를 가지며 기존 연결을 마저 처리한다. 새로운 연결이 이루어지지 않는다. (인터넷에서 좋아요도 가장 많고, 실제로 preStop 설정만으로 502 에러를 해결하였음.)
pod 의 활성화 상태를 나타내는 livenessProbe 가 실패하면 재시작 정책의 대상이 된다. pod 준비 상태를 나타내는 readinessProbe 가 실패하면 해당 pod 는 모든 엔드포인트에서 제거된다. (두 방법 모두 비정상 pod 에 연결을 못받게 하여 502 에러를 줄인다고는 하는데 효과는 잘 모르겠음.)
readinessGates 설정을 가장 먼저 한 바람에 필수요소인지는 확실치 않다. (조만간 테스트 예정) preStop 설정으로 무중단 배포를 해결했다. (본인의 서비스와 사양에 맞는 설정이 필요할 수 있다.) terminationGracePeriodSeconds 설정을 하지 않아도 문제는 없었다. 내 경우 기본값이 45초 만으로 충분한 듯.
한가지 더... kubectl rollout 으로 테스트 할 때 기존의 pod 가 원치 않는 동작을 할 수도 있다. 항상 기존 pod 는 delete 로 삭제한 후에 새로 생성하여 테스트 하는 것이 원하는 결과를 얻는데 도움이 될 것 같다.
무중단 배포도 안된다고 며칠을 eks 욕하고 있었는데... 정말 다행이다. ^_______________^
EKS 에서 ingress 와 loadbalancer 를 생성했는데 pending 상태라 살펴보니 자격증명 실패 에러가 발생했다.
$ kubectl describe ingress my-ingress
Warning FailedBuildModel 32m (x9 over 47m) ingress (combined from similar events): Failed build model due to WebIdentityErr: failed to retrieve credentials
caused by: InvalidIdentityToken: Incorrect token audience
status code: 400, request id: 4599a6da-7a29-4d82-baf7-d546e7811234
확인하고 삭제하려는데 삭제가 안된다.ㅋ 강제 삭제(--force --grace-period=0)도 안된다; 시간이 한참 지나도 프롬프트가 멈춰버림.
$ kubectl describe svc my-nlb
...
Normal DeletedLoadBalancer 40m service-controller Deleted load balancer
Warning FailedDeployModel 38m service Failed deploy model due to WebIdentityErr: failed to retrieve credentials
Warning ClusterIPNotAllocated 75s (x5 over 37m) ipallocator-repair-controller Cluster IP [IPv4]:172.20.23.140 is not allocated; repairing
Warning PortNotAllocated 75s (x5 over 37m) portallocator-repair-controller Port 32083 is not allocated; repairing
권한은 없는데 복구 의지가 강해서 그런건지, 안죽고 계속 살아나려고 발버둥 치는 느낌. 다른 서비스들과 결합이 되어 있는건지... 클러스터를 거의 초기화 수준으로 다른 모든 리소스를 다 지웠는데도 삭제가 안되는 생명줄 긴 로드 밸런서들. 구글님 덕에 겨우 찾아 삭제했다.
finalizers 는 리소스를 완전히 삭제하기 전에 특정 조건이 충족될 때까지 대기하게 한다. 삭제가 완료되면 대상에서 관련 finalizers 를 삭제하는데, 위처럼 metadata.finalizers 필드를 비워주면 Kubernetes 는 삭제가 완료된 것으로 인식하게 된다.
ALB 생성 역시 NLB 와 흡사하지만 ingress 리소스를 생성해야 하고, NodePort 나 LoadBalancer 타입의 Service 를 생성하는 것이 다르다. 마찬가지로 nginx 의 첫화면을 확인하는 샘플. 어플리케이션 배포는 NLB 테스트에 사용한 것과 동일, ALB / NodePort 정상 구동 확인하고, 브라우저에서 nginx 확인하고...
1. Sample namespace
$ kubectl create namespace alb-sample-app
& 해당 namespace 로 fargate 프로파일도 작성
2. nginx Application, NLB 생성
로드밸런서의 타입인 Instance 와 IP 중 Fargate 는 IP 타겟만 지정 가능하다. Instance 는 node 로, IP 는 pod 로 라우팅된다. 아래 스크립트는 선택기가 app=nginx 인 pod 로 라우팅하는 ALB 를 생성한다.
$ kubectl apply -f sample.yaml
Deployment/sample-app created
Service/sample-service-nodeport created
Ingress/sample-ingress created
3. 서비스 확인
$ kubectl get svc sample-service-nodeport -n alb-sample-app
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
sample-service-nodeport NodePort 172.20.23.108 <none> 80:31517/TCP 4s
$ kubectl get ingress sample-ingress -n alb-sample-app
NAME CLASS HOSTS ADDRESS PORTS AGE
sample-ingress <none> * k8s-samplein-1234d81632-1363801234.ap-northeast-2.elb.amazonaws.com 80 3h43m
여기까지 진행하였으면, AWS 관리콘솔에서 [로드밸런서] 와 [대상 그룹] 이 정상적으로 구동되었는지 확인한다.
로드밸런서 : DNS 이름 / application 유형 / internet-facing 체계
대상그룹 : 80 port / HTTP protocal / IP target / Health status
4. 결과 확인
상단 ingress DNS 주소로 curl 이나 browser 를 사용하여 nginx 첫 페이지를 확인한다.