리소스 헬스
리소스 헬스 (Resource Health)
Argo CD는 여러 표준 Kubernetes 유형에 대한 내장 헬스 평가를 제공하며, 이것이 전체 Application 헬스 상태로 합산돼요. Kubernetes 리소스 유형별로 어떤 헬스 체크가 수행되는지 알아보고, 필요한 경우 Lua로 커스텀 헬스 체크를 작성하는 방법을 배워볼게요.
출처: 문서
본문
개요 (Overview)
Argo CD는 여러 표준 Kubernetes 유형에 대한 내장 헬스 평가를 제공하며, 이것이 전체 Application 헬스 상태로 합산돼요. 특정 유형의 Kubernetes 리소스에 대해 다음과 같은 검사가 수행돼요:
Deployment, ReplicaSet, StatefulSet, DaemonSet
- 관찰된 generation(observed generation)이 원하는 generation과 같아요.
- 업데이트된(updated) 레플리카 수가 원하는 레플리카 수와 같아요.
Service
- 서비스 유형이
LoadBalancer이면status.loadBalancer.ingress목록이 비어 있지 않고,hostname또는IP값이 하나 이상 있어요.
Ingress
status.loadBalancer.ingress목록이 비어 있지 않고,hostname또는IP값이 하나 이상 있어요.
CronJob
- 이 CronJob에 대해 마지막으로 예약된 작업(job)이 실패했다면 CronJob은 "Degraded"로 표시돼요
- 이 CronJob에 대해 마지막으로 예약된 작업이 실행 중이면 CronJob은 "Progressing"으로 표시돼요
Job
- job의
.spec.suspended가true로 설정되어 있으면, job과 app 헬스가 suspended로 표시돼요.
PersistentVolumeClaim
status.phase가Bound예요.
Argocd App
argoproj.io/Application CRD의 헬스 평가는 argocd 1.8에서 제거되었어요(자세한 내용은 #3781 참고). app-of-apps 패턴을 사용하고 sync waves로 동기화를 조율한다면 이를 복원해야 할 수 있어요. argocd-cm ConfigMap에 다음 리소스 커스터마이즈를 추가하세요:
apiVersion: v1
kind: ConfigMap
metadata:
name: argocd-cm
namespace: argocd
labels:
app.kubernetes.io/name: argocd-cm
app.kubernetes.io/part-of: argocd
data:
resource.customizations.health.argoproj.io_Application: |
hs = {}
hs.status = "Progressing"
hs.message = ""
if obj.status ~= nil then
if obj.status.health ~= nil then
hs.status = obj.status.health.status
if obj.status.health.message ~= nil then
hs.message = obj.status.health.message
end
end
end
return hs
커스텀 헬스 체크 (Custom Health Checks)
머리말 (Preface)
Argo CD는 Lua로 작성된 커스텀 헬스 체크를 지원해요. 다음의 경우에 유용해요:
- 리소스 컨트롤러의 버그 때문에
Ingress나StatefulSet리소스가Progressing상태에 갇히는 알려진 문제의 영향을 받는 경우 - Argo CD에 내장 헬스 체크가 없는 커스텀 리소스가 있는 경우
Argo CD는 Kubernetes CRD가 제공하는 헬스와 상태 필드에 의존해요. 이 필드는 Argo CD가 아니라 각 CRD의 생성자가 정의하고 유지보수해요. CRD는 일관되거나 표준화된 상태 형식을 따르지 않으므로, 각 CRD에 대해 커스텀 헬스 체크가 명시적으로 기여될 때만 Argo CD가 그 헬스를 안정적으로 결정할 수 있어요.
좋은 헬스 체크 작성 가이드라인 (Guidelines for Writing Good Health Checks)
관련 K8s 컨트롤러의 문서/코드 탐색 (Exploring the documentation/code of the relevant K8s controller)
CRD는 일관되거나 표준화된 상태 형식을 따르지 않지만, 대부분의 경우 K8s 클러스터에서 만나는 여러 조건에 대해 status 하위 리소스를 관찰해서 커스텀 헬스 체크를 작성하는 것은 꽤 쉬워요.
하지만 일부 컨트롤러의 경우 status 하위 리소스가 복잡하고 올바르게 이해하고 해석하기 어려워요. 그런 경우 헬스 체크를 올바르게 작성하려면 컨트롤러의 문서나 코드(특히 상태 조건이 처리되는 곳)를 참고하는 것이 좋아요.
kstatus 사용 (Using kstatus)
CRD 상태가 kstatus 형식이라면 이를 헬스 체크에 주석으로 명시하세요(Argo CD 유지보수자들이 kstatus 기반 헬스 계산의 사용을 평가하고 있으므로, 어떤 CRD가 이 표준을 따르는지 아는 것은 채택에 도움이 될 수 있어요).
K8s observedGeneration 필드 사용 (Using K8s observedGeneration field)
CRD가 observedGeneration 필드를 올바르게 사용하고 status 하위 리소스에 있다면, 이 필드를 헬스 체크에 사용하세요. CRD 헬스 계산에 이 필드를 사용하는 것은 CRD 컨트롤러가 변경된 CR을 reconcile하기 전에 Argo CD가 헬스 상태를 평가해서 Argo CD의 헬스 상태가 흔들리는(flap) 상황을 막는 데 중요해요. 이 필드를 헬스 체크에 사용한 예시가 있어요.
커스텀 헬스 체크 구성 (Configuring Custom Health Checks)
커스텀 헬스 체크를 구성하는 방법은 두 가지가 있어요. 다음 두 섹션에서 그 방법을 설명해요.
방법 1. argocd-cm ConfigMap에서 커스텀 헬스 체크 정의 (Way 1. Define a Custom Health Check in argocd-cm ConfigMap)
커스텀 헬스 체크는 argocd-cm의 다음 필드에 정의할 수 있어요:
resource.customizations.health.<group>_<kind>: |
argocd-operator를 사용한다면 argocd-operator의 resourceCustomizations에 의해 덮어써져요.
다음 예시는 cert-manager.io/Certificate에 대한 헬스 체크를 보여줘요.
data:
resource.customizations.health.cert-manager.io_Certificate: |
hs = {}
if obj.status ~= nil then
if obj.status.conditions ~= nil then
for i, condition in ipairs(obj.status.conditions) do
if condition.type == "Ready" and condition.status == "False" then
hs.status = "Degraded"
hs.message = condition.message
return hs
end
if condition.type == "Ready" and condition.status == "True" then
hs.status = "Healthy"
hs.message = condition.message
return hs
end
end
end
end
hs.status = "Progressing"
hs.message = "Waiting for certificate"
return hs
잠재적으로 여러 리소스에 대한 커스텀 헬스 체크의 중복을 막기 위해, 리소스 종류(kind)에 와일드카드를 지정하고 리소스 그룹 어디든 와일드카드를 지정할 수도 있어요:
resource.customizations: |
ec2.aws.crossplane.io/*:
health.lua: |
...
# If a key _begins_ with a wildcard, please ensure that the GVK key is quoted.
resource.customizations: |
"*.aws.crossplane.io/*":
health.lua: |
...
[!IMPORTANT] 와일드카드는
resource.customizations키를 사용할 때만 지원된다는 점을 유의하세요.resource.customizations.health.<group>_<kind>스타일 키는 Kubernetes configmap 키에서 와일드카드(*)가 지원되지 않으므로 동작하지 않아요.
obj는 리소스를 포함하는 전역 변수예요. 스크립트는 상태와 선택적 message 필드가 있는 객체를 반환해야 해요. 커스텀 헬스 체크는 다음 헬스 상태 중 하나를 반환할 수 있어요:
Healthy- 리소스가 healthy 해요Progressing- 리소스가 아직 healthy 하지 않지만 진행 중이며 곧 healthy 해질 수 있어요Degraded- 리소스가 degraded 해요Suspended- 리소스가 suspended 되어 일부 외부 이벤트가 재개되기를 기다리고 있어요 (예: suspended된 CronJob 또는 paused된 Deployment)
기본적으로 헬스는 일반적으로 Progressing 상태를 반환해요.
[!NOTE] 보안 조치로 표준 Lua 라이브러리에 대한 접근은 기본적으로 비활성화돼요. 관리자는
resource.customizations.useOpenLibs.<group>_<kind>를 설정해 접근을 제어할 수 있어요. 다음 예시에서cert-manager.io/Certificate의 헬스 체크에 표준 라이브러리가 활성화돼요.
data:
resource.customizations.useOpenLibs.cert-manager.io_Certificate: true
resource.customizations.health.cert-manager.io_Certificate: |
# Lua standard libraries are enabled for this script
방법 2. 커스텀 헬스 체크 기여 (Way 2. Contribute a Custom Health Check)
헬스 체크는 Argo CD에 번들로 포함될 수 있어요. 커스텀 헬스 체크 스크립트는 https://github.com/argoproj/argo-cd의 resource_customizations 디렉터리에 위치해요. 다음 디렉터리 구조를 가져야 해요:
argo-cd
|-- resource_customizations
| |-- your.crd.group.io # CRD group
| | |-- MyKind # Resource kind
| | | |-- health.lua # Health check
| | | |-- health_test.yaml # Test inputs and expected results
| | | +-- testdata # Directory with test resource YAML definitions
각 헬스 체크는 health_test.yaml 파일에 정의된 테스트가 있어야 해요. health_test.yaml은 다음 구조의 YAML 파일이에요:
tests:
- healthStatus:
status: ExpectedStatus
message: Expected message
inputPath: testdata/test-resource-definition.yaml
testdata 폴더에 추가한 파일은 kubectl get ... -oyaml을 실행해 컨트롤러가 설치된 클러스터에서 추출한 전체 K8s 매니페스트인지 확인하세요. 결과 파일이 매우 길면 spec의 일부를 생략할 수 있지만, testdata의 파일이 클러스터에서 추출한 전체 status 하위 리소스를 포함하는 것이 중요해요.
status 하위 리소스가 복잡해서 헬스 체크를 작성하기 위해 컨트롤러 문서/코드를 참고해야 했던 경우, health.lua 파일에 헬스 체크의 기반이 된 컨트롤러 문서/코드 링크가 있는 주석을 제공하세요.
[!IMPORTANT] Argo CD 유지보수자들은 서로 다른 CRD와 그 헬스 조건에 대한 완전한 전문성은 없어요. 그래서 복잡한
status조건의 경우 Argo CD 유지보수자들이 헬스 체크 PR 검토를 돕기 위해 CRD 유지보수자에게 문의할 것을 요청할 수 있어요.
구현된 커스텀 헬스 체크를 테스트하려면 go test -v ./util/lua/를 실행하세요.
PR#1139은 Cert Manager CRD 커스텀 헬스 체크의 예시예요.
내장 헬스 체크의 와일드카드 지원 (Wildcard Support for Built-in Health Checks)
그룹이나 종류 디렉터리 이름에 와일드카드를 사용해 단일 헬스 체크를 여러 리소스에 사용할 수 있어요.
_ 문자는 * 와일드카드처럼 동작해요. 예를 들어 다음 디렉터리 구조를 고려하세요:
argo-cd
|-- resource_customizations
| |-- _.group.io # CRD group
| | |-- _ # Resource kind
| | | |-- health.lua # Health check
.group.io로 끝나는 그룹을 가진 모든 리소스는 health.lua의 헬스 체크를 사용해요.
와일드카드 체크는 그 리소스에 대한 특정 체크가 없을 때만 평가돼요.
여러 와일드카드 체크가 일치하면 디렉터리 구조에서 첫 번째 것이 사용돼요.
와일드카드 체크를 일치시키는 데 doublestar glob 라이브러리를 사용해요. 현재 _ 문자를 포함하는 경로만 와일드카드로 취급하지만, 이는 향후 변경될 수 있어요.
[!IMPORTANT] 거대한 스크립트 피하기 (Avoid Massive Scripts)
여러 리소스를 처리하기 위해 거대한 스크립트를 작성하는 것을 피하세요. 읽고 유지보수하기 어려워질 거예요. 대신 관련 부분을 리소스별 스크립트에서 복제하세요.
Go 기반 헬스 체크 덮어쓰기 (Overriding Go-Based Health Checks)
일부 리소스의 헬스 체크는 Lua 지원이 나중에 도입되었기 때문에 Go 코드로 하드코딩되었어요. 또한 일부 리소스의 헬스 체크 로직이 너무 복잡해서 Go로 구현하는 것이 더 쉬웠어요.
내장 리소스의 헬스 체크를 덮어쓰는 것이 가능해요. Argo는 Go 기반 내장 체크보다 구성된 헬스 체크를 선호해요.
다음 리소스에 Go 기반 헬스 체크가 있어요:
- PersistentVolumeClaim
- Pod
- Service
- apiregistration.k8s.io/APIService
- apps/DaemonSet
- apps/Deployment
- apps/ReplicaSet
- apps/StatefulSet
- argoproj.io/Workflow
- autoscaling/HorizontalPodAutoscaler
- batch/Job
- extensions/Ingress
- networking.k8s.io/Ingress
헬스 체크 (Health Checks)
Argo CD App 헬스는 애플리케이션 소스에 표현된 즉시 자식 리소스의 헬스에서 추론돼요. App 헬스는 다음 우선순위(가장 healthy부터 가장 덜 healthy까지)를 기반으로 한 직계 자식 리소스의 최악의 헬스가 돼요: Healthy, Suspended, Progressing, Missing, Degraded, Unknown. 예를 들어 App에 Missing 리소스와 Degraded 리소스가 있으면 App의 헬스는 Degraded가 돼요.
하지만 리소스의 헬스는 자식 리소스에서 상속되지 않아요. 리소스 자체에 대한 정보만 사용해 계산되거든요. 리소스의 status 필드는 자식 리소스의 헬스에 대한 정보를 포함할 수도 있고 아닐 수도 있으며, 리소스의 헬스 체크가 그 정보를 고려할 수도 있고 아닐 수도 있어요.
상속이 없는 것은 의도적이에요. 리소스의 헬스는 자식에서 추론될 수 없어요. 자식 리소스의 헬스가 부모 리소스의 헬스와 관련이 없을 수 있기 때문이에요. 예를 들어 Deployment의 헬스는 반드시 그 Pod의 헬스에 영향을 받는 것은 아니에요.
App (healthy)
└── Deployment (healthy)
└── ReplicaSet (healthy)
└── Pod (healthy)
└── ReplicaSet (unhealthy)
└── Pod (unhealthy)
자식 리소스의 헬스가 부모의 헬스에 영향을 주길 원한다면, 자식의 헬스를 고려하도록 부모의 헬스 체크를 구성해야 해요. 헬스 체크에는 부모 리소스의 상태만 사용할 수 있으므로, 부모 리소스의 컨트롤러가 자식 리소스의 헬스를 부모 리소스의 status 필드에 제공해야 해요.
App (healthy)
└── CustomResource (healthy) <- This resource's health check needs to be fixed to mark the App as unhealthy
└── CustomChildResource (unhealthy)
Application에서 자식 리소스 헬스 체크 무시 (Ignoring Child Resource Health Check in Applications)
Application 안에서 즉시 자식 리소스의 헬스 체크를 무시하려면 argocd.argoproj.io/ignore-healthcheck 어노테이션을 true로 설정하세요. 예를 들어:
apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
argocd.argoproj.io/ignore-healthcheck: "true"
이렇게 하면 Deployment의 헬스 상태가 부모 Application의 헬스에 영향을 주지 않아요.