스터디/AEWS

[AEWS] 6주차 쿠버네티스 API Server 이해하기

안녕유지 2025. 3. 12. 03:43
Cloudnet AWES 6주차 스터디를 진행하며 정리한 글입니다.

 
하..... 여담이지만 2시간 넘게 걸려 작성한 포스팅이 날라가서 다시 작성하니 속상합니다..... 처음 쓴 글보다 느낌상 짧은 포스팅이 될 것 같은 느낌이 드네요......
 
쿠버네티스는 RESTful API 서버를 사용하여 클러스터 리소스 관리, 인증 인가 및 클러스터 상태 저장을 합니다.
이번 포스팅에서는 쿠버네티스 API 서버가 무엇인지, API 요청이 어떻게 처리되는지, 그리고 kubectl을 이용해 직접 API 요청을 실습하는 내용을 소개하겠습니다.

 

Kubernetes API의 구조

출처 : https://blog.kubesimplify.com/practical-guide-to-kubernetes-api

1. 리소스와 동사

쿠버네티스 API는 리소스와 동사를 기반으로 동작합니다.

  • 리소스 : 쿠버네티스에서 관리하는 객체 - Pod, Deployment, Service 등
  • 동사: API 요청의 유형 - get, list, create, update, delete  

 

2. API 그룹 및 버전

쿠버네티스 API는 시간이 지남에 따라 독립적인 버전이 개발되기 때문에 API 그룹은 여러 단계가 존재합니다. 
 

Core Group

  • 기본 API 그룹이며 api/v1에서 사용
  • 파드나, 컨피그맵 등 기본 쿠버네티스 컴포넌트에서 사용
  • ex) /api/v1/pods, /api/v1/nodes

 

Named Group

  • 확장 API 그룹이며 /apis/ 하위에 위치
  • 사용자 정의 리소스를 포함한 모든 리소스에서 사용
  • ex) /apis/apps/v1/deployments, /apis/batch/v1/jobs

 
API 그룹 상태

  • alpha실험적이며 잠재적으로 불안정함.
  • beta더 많은 테스트를 거쳤지만 아직 변경될 수 있음.
  • stable또는 GA(일반 제공) - 안정적이며 프로덕션에 바로 사용할 수 있습니다.

 

3. Kind

kind는 API에서 다루는 특정 리소스 유형의 구조와 동작을 나타냅니다.
사용자가 쿠버네티스 오브젝트를 만들 때 리소스의 유형을 구분하는 키워드로, API 서버에서 리소스를 저장하고 처리하는 방식 결정합니다.
 

 

Kubernetes API 호출하기

kubectl을 사용한 API 리소스 조회

아래 명령어를 실행하면 API 서버에서 지원하는 모든 리소스 목록을 확인할 수 있습니다.

❯ kubectl api-resources                  
NAME                                SHORTNAMES   APIVERSION                        NAMESPACED   KIND
bindings                                         v1                                true         Binding
componentstatuses                   cs           v1                                false        ComponentStatus
configmaps                          cm           v1                                true         ConfigMap
endpoints                           ep           v1                                true         Endpoints
events                              ev           v1                                true         Event
limitranges                         limits       v1                                true         LimitRange
namespaces                          ns           v1                                false        Namespace
nodes                               no           v1                                false        Node
persistentvolumeclaims              pvc          v1                                true         PersistentVolumeClaim
persistentvolumes                   pv           v1                                false        PersistentVolume
pods                                po           v1                                true         Pod
podtemplates                                     v1                                true         PodTemplate
replicationcontrollers              rc           v1                                true         ReplicationController
resourcequotas                      quota        v1                                true         ResourceQuota
secrets                                          v1                                true         Secret
serviceaccounts                     sa           v1                                true         ServiceAccount
services                            svc          v1                                true         Service
mutatingwebhookconfigurations                    admissionregistration.k8s.io/v1   false        MutatingWebhookConfiguration
validatingadmissionpolicies                      admissionregistration.k8s.io/v1   false        ValidatingAdmissionPolicy
validatingadmissionpolicybindings                admissionregistration.k8s.io/v1   false        ValidatingAdmissionPolicyBinding
validatingwebhookconfigurations                  admissionregistration.k8s.io/v1   false        ValidatingWebhookConfiguration
customresourcedefinitions           crd,crds     apiextensions.k8s.io/v1           false        CustomResourceDefinition
apiservices                                      apiregistration.k8s.io/v1         false        APIService
controllerrevisions                              apps/v1                           true         ControllerRevision
daemonsets                          ds           apps/v1                           true         DaemonSet
deployments                         deploy       apps/v1                           true         Deployment
replicasets                         rs           apps/v1                           true         ReplicaSet
statefulsets                        sts          apps/v1                           true         StatefulSet
selfsubjectreviews                               authentication.k8s.io/v1          false        SelfSubjectReview
tokenreviews                                     authentication.k8s.io/v1          false        TokenReview
localsubjectaccessreviews                        authorization.k8s.io/v1           true         LocalSubjectAccessReview
selfsubjectaccessreviews                         authorization.k8s.io/v1           false        SelfSubjectAccessReview
selfsubjectrulesreviews                          authorization.k8s.io/v1           false        SelfSubjectRulesReview
subjectaccessreviews                             authorization.k8s.io/v1           false        SubjectAccessReview
horizontalpodautoscalers            hpa          autoscaling/v2                    true         HorizontalPodAutoscaler
cronjobs                            cj           batch/v1                          true         CronJob
jobs                                             batch/v1                          true         Job
certificatesigningrequests          csr          certificates.k8s.io/v1            false        CertificateSigningRequest
leases                                           coordination.k8s.io/v1            true         Lease
eniconfigs                                       crd.k8s.amazonaws.com/v1alpha1    false        ENIConfig
endpointslices                                   discovery.k8s.io/v1               true         EndpointSlice
events                              ev           events.k8s.io/v1                  true         Event
flowschemas                                      flowcontrol.apiserver.k8s.io/v1   false        FlowSchema
prioritylevelconfigurations                      flowcontrol.apiserver.k8s.io/v1   false        PriorityLevelConfiguration
nodes                                            metrics.k8s.io/v1beta1            false        NodeMetrics
pods                                             metrics.k8s.io/v1beta1            true         PodMetrics
policyendpoints                                  networking.k8s.aws/v1alpha1       true         PolicyEndpoint
ingressclasses                                   networking.k8s.io/v1              false        IngressClass
ingresses                           ing          networking.k8s.io/v1              true         Ingress
networkpolicies                     netpol       networking.k8s.io/v1              true         NetworkPolicy
runtimeclasses                                   node.k8s.io/v1                    false        RuntimeClass
poddisruptionbudgets                pdb          policy/v1                         true         PodDisruptionBudget
clusterrolebindings                              rbac.authorization.k8s.io/v1      false        ClusterRoleBinding
clusterroles                                     rbac.authorization.k8s.io/v1      false        ClusterRole
rolebindings                                     rbac.authorization.k8s.io/v1      true         RoleBinding
roles                                            rbac.authorization.k8s.io/v1      true         Role
priorityclasses                     pc           scheduling.k8s.io/v1              false        PriorityClass
csidrivers                                       storage.k8s.io/v1                 false        CSIDriver
csinodes                                         storage.k8s.io/v1                 false        CSINode
csistoragecapacities                             storage.k8s.io/v1                 true         CSIStorageCapacity
storageclasses                      sc           storage.k8s.io/v1                 false        StorageClass
volumeattachments                                storage.k8s.io/v1                 false        VolumeAttachment
volumeattributesclasses             vac          storage.k8s.io/v1beta1            false        VolumeAttributesClass
cninodes                            cnd          vpcresources.k8s.aws/v1alpha1     false        CNINode
securitygrouppolicies               sgp          vpcresources.k8s.aws/v1beta1      true         SecurityGroupPolicy

 
 

1) kubectl 명령어를 통한 조회 (단, 디버그 모드를 켜서 상세 호출 흐름 확인)

kubectl을 통해 조회하면 다음과 같은 흐름으로 API 서버에 호출이 보내집니다. 

  1. kubectl 설정 로드 (~/.kube/config에서 API 서버 정보 로드)
  2. API 서버에 HTTP GET 요청 전송 (/api/v1/namespaces/default/pods?limit=500)
  3. API 요청 헤더 정보 확인 (Accept: application/json;as=Table → Table 형태 요청)
  4. API 응답 데이터 변환 (kubectl이 사람이 읽기 쉬운 Table 형식으로 가공하여 출력)
❯ kubectl get pod -v8                   
I0312 03:59:28.241564   66913 loader.go:402] Config loaded from file:  /Users/yoo/.kube/config
I0312 03:59:28.244057   66913 envvar.go:172] "Feature gate default state" feature="WatchListClient" enabled=false
I0312 03:59:28.244069   66913 envvar.go:172] "Feature gate default state" feature="ClientsAllowCBOR" enabled=false
I0312 03:59:28.244074   66913 envvar.go:172] "Feature gate default state" feature="ClientsPreferCBOR" enabled=false
I0312 03:59:28.244077   66913 envvar.go:172] "Feature gate default state" feature="InformerResourceVersion" enabled=false
I0312 03:59:28.250394   66913 helper.go:113] "Request Body" body=""
I0312 03:59:28.251230   66913 round_trippers.go:470] GET https://8FA477A1B30E5E6D6E7473BD5FA8EA94.sk1.ap-northeast-2.eks.amazonaws.com/api/v1/namespaces/default/pods?limit=500
I0312 03:59:28.251237   66913 round_trippers.go:476] Request Headers:
I0312 03:59:28.251244   66913 round_trippers.go:480]     Accept: application/json;as=Table;v=v1;g=meta.k8s.io,application/json;as=Table;v=v1beta1;g=meta.k8s.io,application/json
I0312 03:59:28.251248   66913 round_trippers.go:480]     User-Agent: kubectl/v1.32.1 (darwin/arm64) kubernetes/e9c9be4
I0312 03:59:29.336667   66913 round_trippers.go:581] Response Status: 200 OK in 1085 milliseconds
I0312 03:59:29.336712   66913 round_trippers.go:584] Response Headers:
I0312 03:59:29.336718   66913 round_trippers.go:587]     Audit-Id: abc59597-eaa7-44b7-9211-3c59d4afcddc
I0312 03:59:29.336730   66913 round_trippers.go:587]     Cache-Control: no-cache, private
I0312 03:59:29.336733   66913 round_trippers.go:587]     Content-Type: application/json
I0312 03:59:29.336735   66913 round_trippers.go:587]     X-Kubernetes-Pf-Flowschema-Uid: f2eae594-9812-48f0-8003-3796638545c3
I0312 03:59:29.336737   66913 round_trippers.go:587]     X-Kubernetes-Pf-Prioritylevel-Uid: 3a378eab-9e17-41df-ad0d-4fc68ef3bada
I0312 03:59:29.336745   66913 round_trippers.go:587]     Date: Tue, 11 Mar 2025 18:59:29 GMT
I0312 03:59:29.336885   66913 helper.go:113] "Response Body" body="{\"kind\":\"Table\",\"apiVersion\":\"meta.k8s.io/v1\",\"metadata\":{\"resourceVersion\":\"421105\"},\"columnDefinitions\":[{\"name\":\"Name\",\"type\":\"string\",\"format\":\"name\",\"description\":\"Name must be unique within a namespace. Is required when creating resources, although some resources may allow a client to request the generation of an appropriate name automatically. Name is primarily intended for creation idempotence and configuration definition. Cannot be updated. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#names\",\"priority\":0},{\"name\":\"Ready\",\"type\":\"string\",\"format\":\"\",\"description\":\"The aggregate readiness state of this pod for accepting traffic.\",\"priority\":0},{\"name\":\"Status\",\"type\":\"string\",\"format\":\"\",\"description\":\"The aggregate status of the containers in this pod.\",\"priority\":0},{\"name\":\"Restarts\",\"type\":\"string\",\"format\":\"\",\"description\":\"The number of times the containers in this pod have been restarted and when the last container in this pod has restarted.\",\"priority\":0},{ [truncated 3936 chars]"
NAME    READY   STATUS    RESTARTS   AGE
nginx   1/1     Running   0          3h44m

 

2) kubectl 명령어로 raw 데이터 호출을 통한 조회

kubectl을 통해 raw 옵션을 통해 호출하면 API 서버의 RESTful 엔드포인트를 직접 호출하여 JSON 형식의 원본 API 응답을 출력합니다. 

❯ kubectl get --raw /api/v1/namespaces/default/pods | jq
{
  "kind": "PodList",
  "apiVersion": "v1",
  "metadata": {
    "resourceVersion": "420807"
  },
  "items": [
    {
      "metadata": {
        "name": "nginx",
        "namespace": "default",
        "uid": "662787b8-6863-4615-9457-a8fa98be8ee3",
        "resourceVersion": "365442",
        "creationTimestamp": "2025-03-11T15:15:02Z",
        "labels": {
          "run": "nginx"
        },
        "managedFields": [
          {
            "manager": "kubectl-run",
            "operation": "Update",
            "apiVersion": "v1",
            "time": "2025-03-11T15:15:02Z",
            "fieldsType": "FieldsV1",
            "fieldsV1": {
              "f:metadata": {
                "f:labels": {
                  ".": {},
                  "f:run": {}
                }
              },
              "f:spec": {
                "f:containers": {
                  "k:{\"name\":\"nginx\"}": {
                    ".": {},
                    "f:image": {},
                    "f:imagePullPolicy": {},
                    "f:name": {},
                    "f:resources": {},
                    "f:terminationMessagePath": {},
                    "f:terminationMessagePolicy": {}
                  }
                },
                "f:dnsPolicy": {},
                "f:enableServiceLinks": {},
                "f:restartPolicy": {},
                "f:schedulerName": {},
                "f:securityContext": {},
                "f:terminationGracePeriodSeconds": {}
              }
            }
          },
          ...

 

3) curl 등 간단한 REST 호출을 통한 조회

해당 호출은 kubectl 명령줄 도구 없이 REST 호출을 통해 쿠버네티스 API 서버에 요청을 전송하였습니다.
하지만, 기존 1,2 번 방법과는 달리 왜 파드가 조회되지 않고 403 응답이 나왔을까요?
 
그것은 바로 API 서버가 사용자를 'system:anonymous'로 인증했지만, 해당 사용자에게는 Pods 조회 권한이 없어서 403 응답이 리턴한 것입니다. 하지만, 해당 호출은 API 서버에 인증은 성공했으나, 인가가 실패한 경우인데요.
API 서버는 기본적으로 클라이언트가 제공하는 인증 정보가 없을 경우 system:anonymous라는 기본 사용자로 인증을 처리합니다.
curl 요청을 보낼 때 별도 인증 정보를제공하지 않았기 때문에, API 서버는 자동으로 system:anonymous라는 익명 사용자로 요청을 처리했지만 이 사용자는 파드 조회 등 어떠한 권한도 없기 때문에 403 오류가 발생했습니다.
 
++ 참고)

  • 401 Unauthorized → API 서버가 클라이언트의 신원을 확인할 수 없는 경우 (잘못된 토큰, 유효하지 않은 인증서 등)
  • 403 Forbidden → 인증은 되었지만, 해당 사용자가 요청한 리소스에 대한 권한이 없는 경우
❯ curl -X GET $APISERVER/api/v1/namespaces/default/pods
 --insecure
{
  "kind": "Status",
  "apiVersion": "v1",
  "metadata": {},
  "status": "Failure",
  "message": "pods is forbidden: User \"system:anonymous\" cannot list resource \"pods\" in API group \"\" in the namespace \"default\"",
  "reason": "Forbidden",
  "details": {
    "kind": "pods"
  },
  "code": 403
}
 

 
다음 포스팅에서는 이러한 쿠버네티스 API에 접근하기 위한 Kubeconfig 및 CSR을 통한 신규 인증서 발급  (사실 다음 포스팅이었지만, 포스팅 삭제 이슈로,, ㅠㅠ 이전 포스팅입니다.) Kubernetes API의 인증 인가 등 액세스 제어에 대해 자세히 다뤄보겠습니다.