쿠버네티스 API 구조
개요
쿠버네티스를 다룰 때 kubectl을 이용하여 요청을 날리고는 한다.
또 이때 manifests라고 부르는 yaml 파일을 작성하여 전달을 하는데, 실제로 이것들은 어떤 구조로 이뤄진 것일까?
이 모든 요청들은 실제로 kube-apiserver가 처리하는데, 어떤 방식으로 api서버가 요청을 받아들이고 처리하는지 알아보자.
처음 공부할 때 간과하기 쉬운 게, api 서버를 조작하는 방법에 대한 것이다.
사실 이름만 봐도 알 수 있듯이, api 서버는 말그대로 Web Application Server, 그냥 WAS다.
그렇기 때문에 kubectl로 가하는 모든 조작은 사실 curl 같은 http 요청으로 똑같이 날릴 수가 있다.
개발 언어로 라이브러리를 쓸 때 역시 까보면 결국 api 요청을 날리는 식으로 환원된다는 것을 알 수 있다.
API 서버 접근
먼저 api 서버에 요청을 날릴 때 앞단에서 발생하는 일을 간단하게 본다.
api 서버니까 당연히 특정 주소에 특정 포트(기본 6443) api를 노출하고 있을 텐데, 아무나 접근하고 아무나 명령을 내릴 수 있는 것은 아니다.
이를 위해 api 서버에서 실제 요청이 수행되기 이전에 4가지의 단계가 일어난다.
자세한 내용은 시큐리티#API 서버 보안을 참고하자.
API 구조
모든 요청을 수행하는 것은 kube-apiserver이다.
이 api 서버에는 요청을 어떻게 날려야 하는가?
그냥 WAS일 뿐이라 실제로 curl https://{api server address}/
이런 식으로 요청을 날리는 것이 가능하다.
근데 이 내부적으로 꽤나 정교하게 만들어진 하위 엔드포인트가 있다.
이를 명확히 하기 위해서 먼저 API 구조에 대해서 알아본다.
일단 가장 큰 범주에서 API는 두 가지로 구분지을 수 있다.
비 리소스(Non-resource)
아래 리소스에 해당하지 않는 모든 엔드포인트는 비 리소스로 간주된다.
클러스터에 대한 조작을 가하지 않거나, 클러스터 내부의 요소들에 대한 상태를 확인하지 않는 요청들이 여기에 해당한다.
대표적으로 /statusz
, /healthz
등이 여기에 해당한다.
여기에 해당하는 것은 거의 없으니, 대체로 api라고 한다면 다음의 리소스를 생각해도 무방하다.
리소스(Resource)
리소스는 클러스터를 조작하거나 관리하는데 사용되는 모든 엔드포인트를 말한다.
이 엔드포인트에 각종 HTTP 메서드를 이용해 요청을 날리는 방식으로 api 서버를 조작하게 된다.
POST /api/v1/namespaces/default/pods
가령 default 네임스페이스에 파드를 만든다면, 이런 식으로 요청을 날리면 된다.
(바디에 파드 관련 스펙을 적어줘야 한다.)
개념 정리
명확한 용어 정의를 조금 더 내려보자.
- Resource Type
- 말 그대로 리소스 유형이다.
- 실제 URL에
pods
,services
와 같은 식으로 복수형으로 명시된다. - 일반 명사라고 이해하면 조금 더 편할 듯하다.
- 모든 리소스 유형은 저마다의 표현 형식이 지정돼있는데, 이 고정된 형식의 스키마를 kind라고 부른다.
- Resource
- Collection
- 복수 개의 리소스를 말한다.
- 이 표현 자체는 거의 쓸 일도 없고, URL에 이런 식으로 사용하는 방법도 없으니 그냥 개념적인 차원에서만 이해해도 좋다.
파드로 예를 들어본다면, 파드 자체는 리소스 유형이고, 그 중에서 A 파드 자체를 꼭 집어 말한다면 그것은 리소스이다.
그리고 여러 파드를 한꺼번에 표현한다면 그것은 컬렉션이라 부른다.
근데 뭐.. 실제로는 그냥 파드라 하면 우리는 흔히 리소스를 떠올리고 그렇게 표현하곤 한다.
그렇게 표현해도 어차피 의사소통에 그다지 문제될 게 없으니 개념을 이런 식으로 볼 수 있다고만 알고 있으면 된다.
참고로 굳이 컬렉션을 명시적으로 개념화한 이유는 이런 것 때문이다.
여러 개의 리소스를 조회하는 요청을 할 때 돌아오는 응답은 큰 kind가 {어떤 리소스}List
가 되고, items
필드에 어떤 리소스들의 원소가 들어가게 된다.
api 서버가 응답을 하는 값에는 이 컬렉션이 활용되기 때문에 이를 굳이 컬렉션이라고 부른다.
이 말을 듣고 kubectl에 -o json
으로 명령을 내려본 당신, 막상 보니 kind가 List로 돼있을 것이다.
kubectl은 여러 개의 리소스 유형을 한꺼번에 조회하는 기능을 지원하기 때문에, 기본적으로 모든 아이템을 받은 후에 이를 List라는 kind로 출력해서 보여준다.
즉 그저 클라이언트 사이드에서만 kind: List가 있을 뿐, 실제로 api 서버에는 그런 kind가 없다는 것에 유의하자.
API 그룹
/api/v1/pods
/apis/apps/v1/deployments
/apis/apps/v1/namespaces/my-namespace/deployments/my-deployment
이 모든 리소스는 저마다 그룹에 속해있는데, 이를 API 그룹이라 부른다.
위의 예시에서, 파드 리소스 유형은 v1이라는 그룹에 속해있는 것이다.
그리고 디플로이먼트 리소스 유형은 apps/v1이라는 그룹에 속한다.
보다시피 API 그룹은 기본적으로 버전 정보와 어떤 역할을 한다던지에 대한 정보가 담긴다.
그럼 /api
와 /apis
는 무엇인가?
모든 리소스는 경로 상으로 /api
나 /apis
로 시작한다.
- api
- apis
- 네임드 그룹이라고 부르며, 여타 모든 리소스를 포함한다.
- 이들은 그룹과 버전에 대한 정보를 가지며,
/apis/{그룹 이름}/{버전}
과 같은 형식으로 엔드포인트를 시작한다.
코어 그룹이라 하니 여기에만 클러스터에 필수적인 요소들이 들어갈 것만 같지만, 실상은 다르다.
네임드 그룹에는 현재 흔하디 흔하게 쓰이는 디플로이먼트, 인그레스, 컨피그맵 등 다양한 리소스들이 들어가 있다.
그래서 실질적으로 코어 그룹은 처음 쿠버네티스가 만들어질 당시 지정된 리소스들을 규정하는 방식의 잔재라고 보는 게 낫다.
kind
위에서 리소스 타입은 명확한 스키마자 정해져있다고 했는데, 그 스키마를 쿠버네티스에서는 kind라고 부른다.
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
containers:
- name: nginx
image: nginx:1.14.2
ports:
- containerPort: 80
가장 기본이 되는 파드의 양식을 이렇게 작성하는데, 이제 친숙한 것들이 눈에 띈다.
구조 정리
간단하게 도식을 정리하면 이렇게 볼 수 있다. 결론적으로 api 서버에 명령을 내려 클러스터를 조작하고 싶다면, 먼저 대상이 될 리소스를 지정한다. 그리고 그 리소스의 API 그룹과 버전을 앞단 경로로 작성하고, 리소스 유형을 적는다. (만약 특정 네임스페이스로 한정 짓고 싶다면 네임스페이스를 먼저 적어준다.) 그 다음에는 거기에 HTTP 메서드를 이용해서 명령을 내리면 되는 것이다! 이러한 방식을 쉽게 지원하는 명령줄 도구 중 하나가 바로 kubectl인 것이다.참고로 모든 api를 올인원으로 보고 싶다면 이 문서를 참고하자.[1]
API 확장
api 확장 방식에는 API Aggregation Layer, CRD가 있다.
미완성된 글입니다!!
추가 작성해야 하는 글입니다!!!
관련 문서
이름 | noteType | created |
---|---|---|
API 접근 제어 우회 | knowledge | 2025-01-13 |
Authentication | knowledge | 2025-01-13 |
Authorization | knowledge | 2025-01-19 |
Prometheus-Adapter | knowledge | 2025-03-04 |
kube-apiserver | knowledge | 2025-03-12 |
쿠버네티스 API 구조 | knowledge | 2025-03-19 |
6W - PKI 구조, CSR 리소스를 통한 api 서버 조회 | published | 2025-03-15 |
6W - api 구조와 보안 1 - 인증 | published | 2025-03-15 |
6W - EKS api 서버 접근 보안 | published | 2025-03-16 |
E-api 서버 감사 | topic/explain | 2025-01-21 |