오늘은 k8s를 활용하면서 겪었던 webhook issue에 대해 적어보려구 합니다 !!
일단 제가 k8s에 대한 경험이 많이 없어서 이 문제를 조금 오랫동안 해결하려고 노력했던 것 같고 진짜 허무하게도 CNI 플러그인 이슈였더라구요 ㅎ,,, 😂
저는 처음에 DNS 문제이거나 k8s apiserver가 webhook svc에 대한 ca를 제대로 읽지 못하는 문제, 아니면 저의 token이 잘못됐다는 생각을 했던 것 같아요.. 하지만 configmap과 secrets을 봤을 때 모두 다 정상적으로 되어 있었구 처음에는 DNS 오류가 있긴 했지만 이후에 해결해도 문제가 나더라구요 ㅎ,,
cert-manager는 certificate를 관리해주는 일종의 컴포넌트라고 생각하시면 될 것 같구 저는 flink가 cert-manager를 활용하고 있어서 해당 오픈소스를 활용하였습니다. 하지만 cert-manager를 yaml으로 배포했을 때 아래처럼 이슈가 뜨더라구요. 이러한 문제는 cert-manager에도 있듯이 common issue 중 하나였던 것 같고 오늘은 어떤 방법들을 활용했는지 공유해보고자 합니다.
Error from server (InternalError): error when creating "STDIN":
Internal error occurred: failed calling webhook "webhook.cert-manager.io":
Post https://cert-manager-webhook.cert-manager.svc:443/mutate?timeout=30s:
context deadline exceeded
일단 첫번째로 저는 k8s의 DNS를 debugging해보기 위해 공식 문서에서 제공해주는 pod을 활용해봤습니다. (https://kubernetes.io/docs/tasks/administer-cluster/dns-debugging-resolution/)
다음과 같이 pod을 제공되는 yaml을 이용해서 쉽게 배포할 수 있고 아래 명령어를 이용해 실제로 dns에 문제가 있는지 테스트를 진행해봤습니다
kubectl apply -f https://k8s.io/examples/admin/dns/dnsutils.yaml
kubectl exec -i -t dnsutils -- nslookup cert-manager-webhook.cert-manager.svc
수행 결과 아래처럼 문제 없이 서비스의 clusterIP를 찾아갔고 저는 dns 문제가 아니라고 생각했던 것 같아요.
Server: 10.92.0.10
Address 1: 10.92.0.10
Name: cert-manager-webhook.cert-manager.svc
Address 1: 10.x.x.x
저는 이 webhook이 cert-manager만의 문제인가 싶어서 cert-manager에서 eks의 해결 방법인 hostNetwork 옵션을 사용해서 해당 pod이 host의 ip를 가지도록 설정을 했습니다. 이때 value값을 지정하기 위해서 편리하게 helm을 이용했습니다.
이때, kubelet이 10250 포트를 사용하고 있기 때문에 충돌나지 않기 위해서는 10260 포트로 변경하였습니다.
helm install \
cert-manager jetstack/cert-manager \
--namespace cert-manager \
--create-namespace \
--version v1.13.3 --set installCRDs=true --set webhook.hostNetwork=true --set webhook.securePort=10260
실제로 이렇게 하고 cert-manager에는 여러가지 webhook을 check하는 방법이 있는데 저는 그중에서 cmctl을 활용하였어요.
설치 방법은 요기를 참고해주세요!! 이외에도 yaml으로 check도 가능하고 helm으로 설치시 api를 check하는 pod도 같이 job으로 배포되게 돼요~
이렇게 하니 갑자기!! 다른 서비스도 webhook이 먹더군요 하지만 안타깝게도 재설치시 같은 방법으로 진행했을 때 정상 동작하지는 않았던 것 같아요..
그래서 다음 방법으로는 k8s apiserver가 올바른 ca를 읽고 제대로 요청을 보내는가?에 대해 생각을 하게 되더라구요.
하지만 이 문제를 debugging하기에는 저에게도 너무나 어려운 일이었고.. 제가 할 수 있는건 flink를 k8s operator로 설치했을 때 issuer로부터 발급받은 ca가 잘만들어져있고 apiserver는 어떻게 validate 과정을 거치나 알아보는 것이었습니다...
그래서 k8s 공식 문서의 api access control 쪽을 뒤져보면서 실제로 apiserver에서 webhook 서비스로 어떻게 요청을 날리는가에 대해 확인해보고 validationwebhookconfiguration도 변경을 해보고 이것저것 해봤어요.. 하지만 저의 부족한 지식과 경험으로는 해결할 수 없었어요ㅠㅠ..
(https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/)
그 다음 해결 방법으로 고민했던게 CNI 플러그인이었어요. 저는 현재 k8s 1.27.10 버전을 사용하고 있었고 calico는 3.27의 최신 버전을 사용해서 default인 operator 제공 방식을 활용하였습니다.
하지만 calico issue에도 이런 issue들이 없지않아 있었고 calico에서 사용하는 api crd에 대한 의견도 조금 있더라구요. issue에 대한 내용들을 보다보니 이거.. calico 문제일 수도 있겠는데..? 라는 생각이 들더군요. 그래서 issue들을 참고해서 calico 버전도 바꿔보고 operator가 아닌 manifest 방식도 활용해봤습니다.
하지만 나중에 알았지만 제가 사용하고 있는 환경인 on-prem 환경에서는 이상하게도 IPIP 터널 모드를 활용한 bird를 사용하면 다른 서비스의 webhook pod을 찾아가지 못하더군요. 또한, calico의 operator를 활용했을때 vxlanCrossSubnet 모드였지만 calico apiserver(calico) 문제가 있고 그래서 namespace도 잘 안지워지고 그러더라구요..
그래서 찾다가 찾은 방법이 calico의 버전을 현재 다른 k8s 클라우드 서비스에서 쓰고 있는 3.24.x로 바꿨고 설치를 manifest로 진행을 하였습니다. 또한, 기존 IPIP터널 모드는 ACL도 필요하고 방화벽으로 인해 패킷이 드롭되는 이슈도 있어서 VXLAN모드를 always해서 사용하였습니다. 그랬더니 신기하게도 webhook issue가 자연스럽게 해결되더라구요..ㅎ,,
아래는 실제 제가 사용했던 calico file이고 해당 파일은 github에 가니 있더라구요 ㅎㅎ..(진작 해볼걸 그랬네요 ^^ㅎ)
curl https://raw.githubusercontent.com/projectcalico/calico/v3.24.6/manifests/calico-vxlan.yaml -O
sed 's/CrossSubnet/Always/g ./calico-vxlan.yaml
다른 calico troubleshooting도 공식 홈에 있으니 참고하면 좋을 것 같아요 ㅎ(https://docs.tigera.io/calico/latest/operations/troubleshoot/)
이 문제도 아니라면 방화벽이 활성화되어 있는지나 calico에서 요구하는 port를 열어주면 되고 플랫폼마다 사용하는 방법도 다르니 참고하셔서 진행하시면 좋을 것 같습니다 :)
'Infra > Kubernetes' 카테고리의 다른 글
Deployment (0) | 2023.02.20 |
---|---|
쿠버네티스 소개 (0) | 2023.02.12 |
ConfigMap과 Secret (0) | 2023.02.12 |