CNPA — 클라우드 네이티브 플랫폼 엔지니어링 어소시에이트 · 플랫폼 기준선과 준수 · 이론
기준선은 어디에 못박아야 지켜지는가
한 줄 요약
플랫폼의 최소 기준선(baseline)은 위키 문서가 아니라 API 서버가 거절할 수 있는 형태 로 있어야 지켜집니다. 그리고 기준선을 올릴 때는 먼저 경고로 알리고, 영향을 조사하고, 못 지키는 쪽에는 만료일이 붙은 예외를 줍니다.
왜 이게 필요했나
플랫폼 팀이 가장 먼저 만드는 산출물은 대개 문서입니다. "모든 파드는 루트로 돌지 않습니다", "이미지 태그는 고정합니다", "지표 포트를 열어 두십시오" 같은 규칙을 정리해 사내 위키에 올립니다. 그리고 반년 뒤에 클러스터를 훑어보면 그 규칙을 지키는 워크로드가 절반이 안 됩니다.
이유는 단순합니다. 문서는 아무것도 거절하지 않습니다. 규칙을 어긴 배포도 성공하고, 성공한 배포는 아무도 되돌리지 않습니다. 반면 API 서버가 거절하면 그 자리에서 알게 되고, 고치지 않으면 배포가 되지 않습니다. 기준선의 실체는 문서가 아니라 거절할 수 있는 능력 입니다.
그렇다고 처음부터 전부 막으면 다른 문제가 생깁니다. 어제까지 되던 배포가 오늘 갑자기 막히면 플랫폼은 장애의 원인으로 기억됩니다. 그래서 기준선에는 등급과 절차가 함께 필요합니다.
어떻게 동작하나
Pod Security Admission 의 세 등급과 세 모드
쿠버네티스에 내장된 Pod Security Admission 은 네임스페이스 라벨만으로 동작합니다. 등급은 privileged, baseline, restricted 세 가지이고, 각 등급마다 모드 를 따로 걸 수 있습니다.
| 모드 | 하는 일 | 쓰는 자리 |
| --- | --- | --- |
| enforce | 위반한 파드를 만들지 못하게 한다 | 지금 지킬 수 있는 등급 |
| audit | 감사 로그에만 남긴다 | 나중에 통계를 볼 때 |
| warn | 만드는 사람에게 경고를 보여 준다 | 다음에 올릴 등급 |
여기서 나오는 요령이 하나 있습니다. enforce 는 지금 지킬 수 있는 등급에, warn 은 다음에 올릴 등급에 걸어 둡니다. 그러면 개발자는 배포할 때마다 "다음 단계에서는 이게 막힙니다" 를 미리 읽게 되고, 상향하는 날에 놀라지 않습니다.
라벨에는 등급뿐 아니라 버전 도 함께 적습니다(enforce-version: v1.30). 등급의 정의는 쿠버네티스 버전마다 조금씩 넓어지는데, 버전을 적지 않으면 클러스터를 올리는 순간 정책의 내용이 조용히 바뀝니다. 그날 아무도 정책을 건드리지 않았는데 배포가 막히면 원인을 찾는 데 하루가 갑니다.
올리기 전에 조사하는 방법
등급을 올려도 되는지는 짐작하지 말고 서버에 물어봅니다. 네임스페이스 라벨을 바꾸는 요청을 서버 dry-run 으로 보내면, API 서버가 그 네임스페이스에 지금 떠 있는 파드를 새 등급으로 평가해 경고로 돌려줍니다. 어떤 파드가 무엇 때문에 걸리는지가 그대로 나옵니다. 아무것도 만들지 않고 답만 받는 방법입니다.
준수(conformance)는 곧 이식성입니다
CNCF 가 말하는 준수는 "인증 도장" 이 아니라 상위 API 만 쓰면 어느 클러스터에서도 같게 동작한다 는 약속입니다. 그래서 폐기된 API 를 남겨 두면 준수가 깨집니다. extensions/v1beta1 로 쓰인 매니페스트는 최신 클러스터에서 문법 오류가 아니라 매핑 실패 로 거절됩니다. 그 그룹 자체가 제공되지 않기 때문입니다. 이때 나오는 말은 "no matches for kind" 이고, 이 문장을 읽을 줄 알면 원인을 1분 안에 압니다.
옮길 때 필드가 늘어나는 경우도 있습니다. Ingress 를 networking.k8s.io/v1 로 옮기면 경로마다 pathType 을 반드시 적어야 합니다. 예전에는 컨트롤러마다 해석이 달랐던 부분을 API 가 명시하게 만든 것입니다.
관측은 계약입니다
플랫폼이 "지표를 자동으로 수집해 준다" 고 말하려면, 무엇을 근거로 수집할지가 오브젝트로 있어야 합니다. Prometheus Operator 의 ServiceMonitor 가 그 자리를 맡습니다. ServiceMonitor 는 Service 의 라벨 로 대상을 고르고 Service 의 포트 이름 으로 스크레이프 대상을 고릅니다. 둘 중 하나만 어긋나도 오브젝트는 멀쩡히 만들어지고 지표만 조용히 비어 있습니다. 그래서 이 관계는 만들고 나서 "정말 무엇을 골랐는지" 를 되물어 확인해야 합니다.
예외는 만료일과 함께 줍니다
기준선을 지금 못 지키는 팀은 반드시 있습니다. 여기서 선택지는 셋입니다. 기준선을 낮추거나, 그 팀을 막거나, 만료일이 붙은 예외를 주는 것입니다. 앞의 둘은 각각 플랫폼을 무의미하게 만들거나 플랫폼을 적으로 만듭니다. 예외에는 왜 예외인지와 언제까지인지 를 오브젝트에 적어 둡니다. 적어 두지 않은 예외는 영구 면제가 되고, 영구 면제가 쌓이면 기준선은 다시 문서로 돌아갑니다.
현장에서 만나는 모습
이 코스가 돌아가는 홈랩에서도 같은 일이 있었습니다. 실습 파드는 특권 없이(capability 를 전부 뺀 채로) 뜨는데, 그 전제를 문서로만 적어 두었다면 편의를 위해 하나씩 열렸을 것입니다. 지금은 파드 스펙 자체가 그것을 강제하므로, 실습이 안 되면 권한을 여는 대신 실습 설계를 바꿉니다. 기준선이 오브젝트에 있으면 논쟁이 설계로 옮겨 갑니다.
관측 계약 쪽에서도 같은 종류의 사고가 있었습니다. 지표 수집 대상이 라벨 한 글자 때문에 붙지 않았는데, 오브젝트는 정상이고 대시보드만 비어 있어서 한동안 아무도 몰랐습니다. "만들어졌다" 와 "실제로 무언가를 고르고 있다" 는 다른 명제이고, 이 구분은 클러스터에 되물어야만 확인됩니다.
다음 실습에서 할 것
네임스페이스 하나에 기준선을 세우고 그것이 실제로 거절하는지 확인합니다. 폐기된 API 가 왜 거절되는지 눈으로 보고 상위 API 로 옮긴 뒤, 스크레이프 계약을 ServiceMonitor 로 맺고 그 셀렉터가 정말 그 Service 를 고르는지 되물어 봅니다. 마지막으로 기준선을 한 단계 올리는 영향을 서버에 물어보고, 못 지키는 네임스페이스에는 만료일이 붙은 예외를 남깁니다.