이번 글에서는 쿠버네티스를 설정하면서 겪은 삽질들에 대해서 다뤄보고자합니다.
해당 글에는 코드를 많이 소개하기 보다는, 원인 및 원인 분석, 해결 방법 위주로 작성해볼 예정입니다. 코드의 경우 필요할 경우 최대한 깃허브 링크로 소개해드릴 예정입니다.
0. EKS 세팅 (feat. Terraform)
우선 저는 Kubernetes 환경을 AWS에서 제공하는 EKS 매니지드 서비스를 사용해보기로 결정하였습니다.
그리고 해당 EKS를 IaC로 관리하기 위해서 terraform 이라는 툴을 사용하였는데요, 해당 코드에 대한 뼈대 코드는 아래의 링크를 참고하시면 되겠습니다.
1. AWS LoadBalancer Controller 설치
EKS에서는 ingress 리소스를 사용하기 위해서는 loadbalancer controller를 설치해야만합니다.
해당 AWS LoadBalancer Controller를 설치하는 방법은 AWS 도큐먼트에서도 잘 소개가 되어있으나, 저는 공식문서의 방법을 조금 변형해서 terraform, helm 으로 설치하는 방법을 채택하였습니다.
자세한 코드는 아래의 링크를 참고해주시길 바랍니다.
(1) AWS LoadBalancer의 iamserviceaccount에 적용할 policy를 생성하는 테라폼 코드
(2) AWS LoadBalancer를 생성하는 스크립트
AWS LoadBalancer는 Kubernetes 버전에 따른 호환성이 존재하기 때문에 버전 호환성 (Capability)를 잘 체크하셔야합니다. 저는 Kubernetes 1.24 버전을 사용중이므로 AWS LoadBalancer Controller 이미지 버전을 2.4.4 로 설치하였습니다.
제가 겪었던 문제점 3가지만 소개시켜드리도록 하겠습니다.
1) Terraform으로 EKS를 생성하면 보안그룹을 매우 보수적으로 생성하더라
테라폼을 이용해서 EKS를 생성하면 기본적으로 노드그룹에 적용되는 보안그룹은 Control Plane에 대해서 일부 포트(443, 10250 등등)만 열려있습니다.
이로 인해 벌어지는 현상 중 하나는, AWS LoadBalancer는 컨트롤 플레인에 대해서 웹훅을 통해 로드밸런서 생성을 요청하는데요, 여기에서 웹훅 포트가 열려있지 않기 때문에 AWS LoadBalancer Controller 설치 과정에서 CrashLoopBackOff 에러가 발생하게됩니다.
이는 모든 포트를 모든 소스 대상으로 인바운드를 열어버리면 제일 간단하게 해결이 되지만, 쿠버네티스의 보안을 신경쓰기 위해선 가장 최소한의 방화벽 설정을 적용해야만합니다.
해결 방법은, 아래의 코드 스니펫을 노드 그룹의 보안 규칙에 추가하는 것이었습니다. 아래의 코드를 테라폼에 추가하면 9443 포트로 워커노드는 컨트롤 플레인과 통신할 수 있게됩니다.
alb_controller_webhook_rule = {
description = "Cluster API to AWS LB Controller webhook"
protocol = "all"
from_port = 9443
to_port = 9443
type = "ingress"
source_cluster_security_group = true
}
2) STS 권한 문제
사실 위의 방식으로 모든게 해결될줄 알았지만, 아직 남아있는 문제는 있었습니다.
쿠버네티스 위에서 젠킨스를 설치하고 ingress를 이용해서 젠킨스 서비스를 노출시키려고 했을 때 문제점이 발견되었는데요, ingress 리소스에 로드밸런서 주소가 잡히지 않고 있었던 것이었습니다.
NAME CLASS HOSTS ADDRESS PORTS AGE
jenkins <none> jenkins.example.com 80 157m
그래서 AWS LoadBalancer Controller의 로그를 확인해보았는데, sts 권한 인증을 하는 과정에서 dial tcp time out이 발생하고 있었습니다.
{"level":"error","ts":1643192131.4378264,"logger":"controller-runtime.manager.controller.ingress","msg":"Reconciler error","name":"ingress-2048","namespace":"game-2048","error":"WebIdentityErr: failed to retrieve credentials\ncaused by: RequestError: send request failed\ncaused by: Post \"https://sts.ap-southeast-1.amazonaws.com/\": dial tcp 103.246.148.245:443: i/o timeout"}
이는 sts 권한이 iamserviceaccount에 존재하지 않기 때문에 벌어지는 현상이었는데, sts 권한을 alb-controller-policy에 추가함으로써 해결하였습니다. 해당 코드는 여기서 확인하시면 되겠습니다.
2. Jenkins 설치
저는 Jenkins를 Kubernetes 위에 설치하기로 하였습니다. 제가 Jenkins를 외부가 아닌 Kubernetes 내부에 설치하려고 한 이유는 아래와 같습니다.
- Jenkins는 하나의 프로세스당 적어도 메모리만 2Gi 씩 할당이 요구됩니다. 그리고 제대로된 세팅을 위해서라면 master/slave 구조로 jenkins를 구성해야하기 때문에 세팅이 여간 까다로운게 아닙니다.
- 그리고 master/slave 구조로 Jenkins를 구성한다고 하더라도, 현실적으로 해당 slave의 자원을 계속 사용하는게 아닙니다. 그 말인 즉슨, 제가 운영하는 환경 상에서는 빌드의 양이 slave를 가득 채울만큼은 아니기 때문에 유휴 리소스는 계속 발생할 수 밖에 없어집니다. 곧 이는 비용의 문제로 귀결됩니다.
- Jenkins는 플러그인을 설치하면 Restart가 반드시 필요합니다. 이 과정에서 빌드중인 젠킨스 파이프라인이 존재한다면 CI/CD 과정에서 장애가 발생합니다
따라서 Jenkins를 Kubernetes에 설치하기로 하였는데요, 방법은 크게 2가지가 존재합니다.
- Helm Chart로 Jenkins를 마음 편하게 설치한다. (물론 values.yaml을 커스텀하는게 불편하긴합니다)
- Jenkins 공식문서에 따라서 쿠버네티스 리소스를 할당한다 (이것도 사실 helm chart로 묶어서 관리할수는 있지만...귀찮아서 그렇게 하진 않았습니다)
결론부터 말씀드리자면, helm chart로 설치하는게 실패해서 후자의 방법을 선택하였습니다.
helm chart로 Jenkins를 설치하게되면, Pod가 Initialize 단계에서 깨져버리는 현상이 발생하였습니다.
cache miss for: update-center-2.375.2
해당 현상이 무엇인지 몰라 계속 구글링을 해보고, ChatGPT에게도 물어보았지만 하루 허탕만 치고 해결을 못했습니다. 그래서 그냥 공식문서 따라서 쿠버네티스 리소스를 정의해서 배포하는 것으로 마무리 하였습니다.
3. Prometheus + Grafana를 통한 모니터링 환경 배포
저는 Prometheus + Grafana를 통해서 모니터링 환경을 배포하였습니다. 이 과정도 생각보다 쉽지는 않았습니다.
1) Prometheus가 AlertManager에 요청을 보냈으나, 계속 TCP Timeout이 뜨던 현상
저는 Prometheus + Grafana를 prometheus-community/kube-prometheus-stack 이라는 helm chart를 통해서 배포를 진행하였는데요, 배포 직후에 그라파나 보드를 들어가서 대시보드를 조회하였으나, 계속 모니터링 지표들이 No Data로 뜨던 현상이 있었습니다.
그래서 프로메테우스의 로그를 조회해보았는데, AlertManager 주소로 요청을 보내는데 있어서 tcp timeout 현상이 뜨는것을 발견하였습니다.
AlertManager: ClusterIP 10.0.1.172 dial tcp timeout
저는 쿠버네티스의 모든 서비스가 같은 네임스페이스에 있기 때문에 통신이 가능할거라고 생각하였으나, 서비스에 대한 ClusterIP가 아닌 private dns를 통해서 요청을 보내고있는 것을 확인하였습니다.
이러한 timeout 현상을 해결하기 위해선 방화벽 규칙을 오픈해줘야하는데요, 이 현상에 대한 제일 최소한의 방화벽 규칙은 Inbound/Outbound에 대해서 TCP 10.0.0.0/16 을 열어주는 것이었습니다.
해당 방화벽 규칙을 노드그룹의 보안그룹에서 열어준 후 해당 오류를 해결되었습니다
4. GitHub Links
글을 마무리 지으면서 제가 사용하고있는 테라폼 코드들, 쿠버네티스 매니페스트들을 모아둔 레포지토리 주소를 공유하겠습니다.
https://github.com/doccilabs/terraform-codes
https://github.com/doccilabs/kubernetes-utils
'devOps' 카테고리의 다른 글
서비스 장애 잘 이해하고 대비하기 (0) | 2024.07.06 |
---|---|
Redis OOM 장애 (0) | 2024.06.25 |
Docker File System (Overlay2) (0) | 2023.08.06 |
Kubernetes 워커노드의 OOM에 의한 클러스터 장애 (0) | 2023.04.11 |
Jenkins on K8S를 설정하며 겪은 일들 (0) | 2023.03.04 |