문제 해결 및 상태¶
쿠버네티스 오브젝트를 사용할 때 가장 큰 문제 중 하나는, 해당 오브젝트가 요청한 상태(일반적으로 spec 스탠자에 인코딩됨)가 수락되었는지, 그리고 언제 해당 상태가 달성되었는지를 아는 것이다.
대부분의 쿠버네티스 오브젝트의 현재 상태는 status 서브리소스와 스탠자에 저장되지만, Gateway API에서는 status의 활용을 강조하는 데 더욱 집중해야 했다.
Gateway API 오브젝트 설계의 핵심 원칙 중 하나는, 사용자가 오브젝트를 생성할 때 해당 오브젝트의 상태에서 시스템의 상태를 최대한 많이 확인할 수 있도록 하는 것이다. 그리고 그것이 불가능한 경우, 어떤 다른 오브젝트가 관련되어 있는지 알아낼 수 있는 방법이 있어야 한다.
상태와 컨디션¶
특히 Gateway API는 Conditions(컨디션) 규칙을 적극적으로 활용해 왔으며, 이는 주어진 오브젝트의 상태를 이식 가능한 형태로 표현한 것이다.
컨디션은 다음과 같은 항목을 가진다:
type(CamelCase로 작성된, 상태를 나타내는 한 단어 이름),status(해당 상태가 활성 상태인지 아닌지를 나타내는 불리언 값),reason(컨디션이 해당 상태이거나 아닌 이유를 나타내는 CamelCase, 한 단어),- 그리고
message(사람이 읽을 수 있도록 의도된 이유의 문자열 표현).
Gateway API가 필수로 요구하는 선택적 필드 중 하나는 observedGeneration 필드로, 상태가 기록된 시점의 오브젝트에 대한 자동 증가하는 metadata.generation 필드 값을 나타낸다.
이것은 데이터 신선도 검출 체크섬으로 기능한다 - 모든 Gateway API 상태에 대해, conditions의 observedGeneration이 metadata.generation 필드와 일치하는지 확인해야 한다.
일치하지 않는다면, 해당 상태는 오래된 것이며, 어떤 이유로 인해 Gateway API 구현체가 상태를 올바르게 업데이트하지 않고 있는 것이다. (이는 컨트롤러의 결함이거나, 오브젝트가 해당 구현체의 범위를 벗어났을 수 있다.)
또한 Gateway API의 목적 중 하나는 이전 접근 방식의 문제점을 수정하는 것이며, 무슨 일이 일어나고 있는지 확인하기 위해 구현체의 로그를 살펴봐야 하는 요구 사항을 피하고자 했다.
오브젝트의 상태가 가능한 한 해당 오브젝트 위에서 확인할 수 있기를 원한다.
이것은 Gateway API를 사용할 때 가장 중요한 첫 번째 규칙으로 이어진다:
Info
Gateway API 오브젝트의 문제를 해결할 때, 항상 해당 오브젝트의 status.conditions를 먼저 확인하라.
모든 Gateway 오브젝트는 status 어딘가에 conditions 배열을 가지고 있으며, 대부분은 status.conditions에 위치한다.
또한 가능한 한 동일한 컨디션 type을 재사용하려고 노력했으며, 여러 오브젝트에 걸쳐 자주 사용되는 몇 가지 컨디션이 있다:
Accepted: 오브젝트가 의미적으로나 구문적으로 유효하고, 기반 데이터 플레인에서 일부 구성을 생성하며, 컨트롤러에 의해 수락되었을 때 True이다.Programmed: 오브젝트의 구성이 완전히 파싱되었고, 데이터 플레인에 구성을 위해 성공적으로 전송되었을 때 True이다. "곧" 준비될 것이며, "곧"의 정의는 정확한 구현체에 따라 다를 수 있다.ResolvedRefs: 오브젝트 내부의 다른 오브젝트에 대한 모든 참조가 유효할 때 True이다. 즉, 참조된 오브젝트가 존재하고, 각각이 사용된 필드에 대해 유효한 참조인 경우이다.
Gateway(게이트웨이) 오브젝트와 같은 일부 경우에는 추가적인 컨디션 배열이 있다 - Gateway 오브젝트에는 listener 필드당 컨디션이 있으며, 해당 상태 역시 추가적인 설명이 필요할 만큼 복잡하기 때문이다.
컨디션은 한 줄로 요약하기 어려울 만큼 복잡하므로, 대부분의 kubectl get 명령어로는 이를 올바르게 요약할 수 없다.
상태를 확인하려면 몇 가지 옵션이 있다:
kubectl get -o yaml-status를 포함한 전체 오브젝트를 YAML 형식으로 가져온다.gwctl은 Gateway API 서브프로젝트에서 만든 커맨드라인 도구로, Gateway API 리소스 관리를 더 쉽게 할 수 있도록 설계되었다. Github 저장소에서 사용할 수 있다.kubectl describe- 전체 출력의 더 읽기 쉬운 버전을 가져오며, 일반적으로 컨디션 배열을 올바르게 파싱하여 보여줄 수 있다. 그러나 CustomResourceDefinition을 올바르게 디코딩하는 데 종종 어려움을 겪으며, 특히 리스트를 렌더링할 때 그렇다.
범위와 상태¶
Gateway API의 또 다른 특이한 점은 동일한 클러스터에서 여러 구현체가 실행될 수 있도록 설계되었다는 것이다. 이를 위해, 구현체가 어떤 오브젝트의 상태를 업데이트할 수 있는지에 대한 엄격한 요구 사항이 있다. 이는 특정 구현체에 대해 오브젝트가 범위 내(in scope)에 있다고 표현한다.
Info
구현체가 자신이 소유한 GatewayClass로부터 어떤 오브젝트까지의 소유권 체인을 설정할 수 없다면, 해당 오브젝트는 그 구현체의 범위에 속하지 않으며, 해당 구현체가 그 상태를 업데이트해서는 안 된다(MUST NOT).
이는 여러 구현체가 상태를 두고 경쟁하여, 반복적으로 상태를 업데이트하려 시도하다가 한 구현체의 변경 사항이 다른 구현체에 의해 덮어쓰이는 상황을 방지하기 위함이다.
이것의 중요한 효과 중 하나는, Route(라우트)가 유효한 부모를 가리키지 않는 parentRef를 가지고 있을 경우, 이를 나타내는 상태 업데이트가 없다는 것이다.
구현체는 자신이 관리하는 Gateway를 가리키는 데 실수가 있었다고 알려줄 수 없는데, 해당 parentRef가 자신의 책임인지 아닌지를 알 수 있는 방법이 없기 때문이다.
다시 말해, 유효하지 않은 parentRef를 가진 라우트는 이를 나타내는 상태가 없다. 범위 내 오브젝트에 대한 모든 변경에 대해, 단순히 observedGeneration을 업데이트하는 것뿐이라 하더라도, 항상 상태 업데이트가 있을 것으로 기대해야 한다.