EKS Thanos 배포 트러블슈팅 — StorageClass·IRSA 연쇄 오류
kube-prometheus-stack 위에 Thanos 를 올리다 배포가 끝날 때까지 일곱 번 멈춰 섰고, 하나를 고치면 그게 가리고 있던 다음 문제가 드러나는 식이었습니다.
Thanos 를 붙인 건 Prometheus 혼자로는 안 되는 게 둘 있어서입니다. Prometheus 는 지표를 자기 로컬 디스크에 쌓으니 보관 기간을 길게 잡으면 디스크가 계속 커집니다. 그리고 클러스터가 여러 개면 지난달 지표를 보려고 그때 그 클러스터의 Prometheus 를 따로 열어야 합니다.
Thanos 는 이 두 가지를 같이 푸는 물건입니다. Prometheus 파드 옆에 Sidecar 를 붙여 블록이 닫힐 때마다 S3 로 올리고, Store Gateway 가 S3 에 있는 블록을 읽어 주고, Query 가 여러 Prometheus 와 Store 를 한 번에 조회해서 하나처럼 보여주고, Compactor 가 S3 에 쌓인 블록을 주기적으로 합칩니다. 컴포넌트가 여럿인 데다 그중 셋이 S3 를 직접 건드려서, 어긋나는 자리도 그만큼 늘어납니다.
Thanos Sidecar의 S3 쓰기 실패
level=error err="Access Denied" msg="failed to upload"
ServiceAccount 에 IAM Role annotation 이 없거나 있더라도 Trust Policy 에 그 ServiceAccount 가 없으면 이렇게 나옵니다.
kubectl annotate serviceaccount my-prometheus -n monitoring \
eks.amazonaws.com/role-arn=arn:aws:iam::123456789012:role/ThanosS3AccessRole \
--overwrite
# annotation은 파드가 새로 떠야 반영됩니다
kubectl delete pod prometheus-my-prometheus-0 -n monitoring
붙었는지는 컨테이너 안에서 확인합니다.
kubectl exec -n monitoring prometheus-my-prometheus-0 -c thanos-sidecar -- \
env | grep AWS
kubectl exec -n monitoring prometheus-my-prometheus-0 -c thanos-sidecar -- \
AWS_ROLE_ARN 과 AWS_WEB_IDENTITY_TOKEN_FILE 이 안 보이면 IRSA 가 안 붙은 겁니다. 붙어 있는데
업로드가 안 되면 이번엔 Trust Policy 쪽이고, 그건 sidecar 로그에 AccessDenied 로 찍힙니다.
Trust Policy — Thanos 컴포넌트 전부 포함
Sidecar 를 고쳤으니 S3 쪽은 끝났다고 봤지만, 다른 곳에서 같은 에러가 나왔습니다.
# Compactor
level=error err="BaseFetcher: iter bucket: Access Denied"
# StoreGateway
level=error err="bucket store initial sync: Access Denied"
S3 에 올리는 건 Sidecar 니까 Trust Policy 에도 my-prometheus 하나면 될 거라고 봤는데, S3 를
읽고 쓰는 컴포넌트가 그것만이 아니었습니다. StoreGateway 와 Compactor 도 각자의 ServiceAccount
로 붙어서, 컴포넌트를 추가할 때마다 Trust Policy 를 같이 늘려야 합니다.
클러스터에 gp3 StorageClass 가 없음
권한을 다 풀었으니 이번엔 뜨겠거니 했지만, 컴포넌트가 또 다른 데서 걸렸습니다.
level=error err="sync \"monitoring/my-prometheus\" failed:
storage class \"gp3\" does not exist"
values 에 storageClassName: gp3 이 들어 있었지만 클러스터에 그 StorageClass 가 없었습니다.
kubectl get sc
gp2 로 바꿔 재배포했지만 이미 만들어진 StatefulSet 은 그대로였습니다.
StatefulSet volumeClaimTemplates는 immutable
StorageClass 를 만들어 주니 이번엔 StoreGateway 가 Pending 에서 안 넘어갔습니다.
0/6 nodes are available: pod has unbound immediate PersistentVolumeClaims
values 를 gp2 로 고쳤으니 helm upgrade 만 다시 돌리면 될 줄 알았습니다. 그런데 StatefulSet 은
이미 gp3 로 만들어져 있었고, volumeClaimTemplates 는 immutable 이라 upgrade 로는 안 바뀝니다.
PVC 는 계속 없는 StorageClass 를 요구하며 Pending 으로 남습니다.
지우고 다시 만들어야 합니다.
helm uninstall thanos -n monitoring
kubectl delete pvc data-thanos-storegateway-0 -n monitoring
나중에 바꾸려면 StatefulSet 을 통째로 다시 만들어야 하니, StorageClass 는 처음 배포할 때 맞춰 두는 편이 낫습니다.
Bitnami 기본 이미지 pull 실패
Failed to pull image "docker.io/bitnami/thanos:0.39.2-debian-12-r2": not found
2025년 8월부터 docker.io/bitnami 의 기존 태그가 정리되면서, 차트 기본값 그대로는 pull 이 안
됩니다.
Bitnami 이미지 대신 Thanos 업스트림이 배포하는 quay.io 이미지를 가리키게 합니다.
image:
registry: quay.io
repository: thanos/thanos
tag: v0.39.2
pullPolicy: IfNotPresent
차트가 이미지 출처를 검증해서 설치할 때 우회 플래그를 붙여야 합니다.
helm install thanos bitnami/thanos \
-n monitoring \
-f values/thanos-values.yaml \
--set global.security.allowInsecureImages=true
이 플래그가 없으면 차트가 이미지 태그를 보고 설치 자체를 거부합니다.
ALB에서 path /는 다른 Ingress에 밀림
Query Frontend 가 브라우저에서는 404 였지만 포트포워드로는 정상이었습니다.
이 Ingress 의 path 가 / 였고 같은 ALB 를 쓰는 다른 Ingress 들은 /* 였습니다. ALB 리스너
규칙은 패턴이 구체적인 순서가 아니라 우선순위 번호가 낮은 것부터 평가되니, 같은 ALB 를 나눠 쓰는
Ingress 들 사이에서 /* 쪽 규칙이 앞에 서면 / 로 들어온 요청이 그 Target Group 으로 갑니다.
queryFrontend:
ingress:
path: /*
바꾼 뒤 Ingress 에 반영됐는지부터 봅니다.
kubectl describe ingress thanos-query-frontend -n monitoring | grep Path
/* 가 찍혔으면 컨트롤러가 ALB 규칙을 다시 쓴 것이고, 실제로 바뀐 순서는 ALB 리스너 규칙
목록에서 확인합니다.
Operator가 StatefulSet reconcile 안 함
values 에서 이미지를 v0.39.2 로 바꿨는데 StatefulSet 은 v0.34.1 그대로였습니다.
차트를 다시 올렸으니 반영됐겠거니 했지만, 갱신된 건 Prometheus 커스텀 리소스까지였고 Operator 가 그걸 보고 StatefulSet 을 맞추지는 않은 상태였습니다. Operator 를 재시작하면 리소스를 다시 읽고 StatefulSet 을 맞춥니다.
kubectl rollout restart deployment my-operator -n monitoring
kubectl delete pod prometheus-my-prometheus-0 -n monitoring
kubectl get pod prometheus-my-prometheus-0 -n monitoring \
-o jsonpath='{.spec.containers[?(@.name=="thanos-sidecar")].image}'
마지막 줄로 사이드카 이미지 태그를 확인해서, values 에 적은 버전이 나오면 반영된 겁니다.
하나를 고치면 다음이 드러나는 배포
일곱 번 멈춰 섰고, 그중 넷은 성격이 둘로 묶입니다. IRSA 쪽은 S3 를 건드리는 컴포넌트가 여럿인데도 Trust Policy 에는 하나만 넣어 뒀고, StorageClass 쪽은 처음에 잘못 적은 값이 immutable 필드에 박혀서 StatefulSet 재생성으로 번진 것이었습니다.
Thanos 처럼 컴포넌트가 여러 개인 차트를 올릴 때는 이 둘을 먼저 맞춰 둡니다. S3 를 읽거나 쓰는
컴포넌트를 전부 세어서 Trust Policy 에 한 번에 넣고, StorageClass 는 kubectl get sc 로 실제
있는 이름을 확인하고 적습니다. 나머지는 이미지 경로나 Ingress path 처럼 원인이 그대로 드러나는
것들입니다. Operator 가 StatefulSet 을 안 맞추는 건만 에러가 없어서, 실제 파드 이미지를 직접
확인해야 합니다.
댓글 0