강의 정보

강의 필기록 원본이라 글이 좀 어수선할 수 있습니다.

Kubernetes API

K8s API 는 ReST 에 아주 진심이다

  • 쿠버네티스 API 에서 Content-Type 으로 형식을 지정해줄 수 있다
    • 즉, application/json 으로 보내면 JSON 응답이
    • application/yaml 로 보내면 YAML 응답이
    • protobuf 로 보내면 Binary (와 비슷한..) 로 온다
  • ReST API 도 어떤 괴짜 박사과정이 졸업논문으로 만든거다.
    • 참고) Fielding Dissertation: CHAPTER 5: Representational State Transfer (REST)
    • “State” 가 핵심이다: Action 이 아니라 Resource 의 State 를 변경하는 것이 중요한거다
    • 그래서 Action 이 아닌 Resource 를 URL path 에 기술하게 되고, Action 은 HTTP Method 를 활용해라
      • 안좋은 예) Docker 의 /container/{id}/start
      • 좋은 예) Kubernetes 는 모든 것이 state 로 관리되기에 그에 따라 API 도 ReST 에 입각하여 정의해 놓았다

Kube-apiserver 의 ReST API

API 설계

  • 모든 리소스는 TypeMeta, ObjectMeta, Spec, Status 로 구성된다
    • TypeMeta: GVK (Group, Version, Kind)
      • 모든 K8s 에의 state 는 GVK 로 분류가 된다 (스키마가 정의가 된다)
      • apiVersion: 모든 apiVersion 은 (core를 제외하면) ${GROUP}/${VERSION} 로 구성된다.
        • Core 의 경우에는 Group 없이 v1 만 드가고 이것은 legacy 지만 의존성이 너무 강해 고치지는 않았다고 한다.
      • Kind: 뭐 리소스 종류 (Pod, Deployment, …)
    • ObejctMeta: Resource.metadata 의 내용
      • GVK 와 ns, name 으로 클러스터 내에서 특정 리소스를 global 하게 특정이 가능하다
    • Spec (바람직한 상태): Defaulting 되는 것 이외에는 Controlplane component 가 건들지 않는다
      • DeletionTimestamp: Delete API 를 호출했을 때 삭제되는데 시간이 오래 걸리는 경우가 있고 이럴때 실제로 삭제되지 않았는데 etcd 에서 바로 지워버리면 안되기 때문에 약간 GracePeriod 같은 이 값을 걸어버리고 이 시간이 지나면 지워지길 “희망” 한다는 의미
      • 실제로는 이런식으로 진행
        1. Delete API 호출
        2. DeletionTimespamp 설정
        3. Controller 가 DeleteTimestamp 가 걸린놈을 보고 자신이 담당하고 있는 Finalizer 를 수행 후 해당 line 삭제
        4. GarbageCollector 는 DeletionTimestamp 가 설정되어 있고 Finalizer 가 비워져있는 놈을 찾아서 지워야 한다.
      • 따라서 Finalizer 를 임의로 지워서 stuck 걸린 리소스를 지우는 것은 state 에서만 지우는 거고 실제 자원은 남아있기 때문에 Controller 의 이슈를 먼저 해결해야 한다
      • Scale subresource: CRD 를 생성했을 때 Scale subresource 를 정의할 수 있고, 이것을 이용해 HPA 같은 것을 사용할 수 있음
        • 이것을 자동화해주는게 Keda 라는 솔루션이다
    • Status (실제 상태): Controlplane component 는 이것만 건든다
  • 팁) API reference 에도 defaulting 에 관한 내용은 제대로 적혀있지 않기에 직접 코드를 까보는 것도 좋다더라

Authorization & Authentication

  • 김해람이 맞나? Authentication (인증)
    • 인증서의 CN(user) OU(group) 로 User 와 Group 을 확인하고 그 결과를 반환
      • CN 은 GetUser 로 변환,
      • OU 는 GetGroup 로 변환
    • Token 으로도 가능한데, Kubeconfig 의 인증서를 사용하는 경우에는 대부분 Token 을 사용
  • 김해람이 권한이 있나? Authorization (인가)
    • 인증과정에서 나온 유저 정보가
    • GVK, ns, name 에 권한이 있는가 확인
      • func Authorizer.Authorize() 가 담당한다고 한다.
    • 결과로 DecisionAllow, DecisionDeny, DecisionNoOpinion 을 반환
  • RBAC
    • 세가지: 나, 역할, 나와 역할의 관계
    • ABAC: Action Based
      • 얘는 누가 뭘 할수 있는지를 명시적으로 정의한 JSON 파일을 node 에 저장하고 Apiserver 가 readfs 하게 하는 방식이었지만 지금은 완전히 deprecated 되어 활성화되어있지 않음
  • NodeAuthorizer
    • 파드가 노드 A 에 떠있을 때 NodeAuthorizer 는 BFS 로 확인하며 노드 A 에만 파드가 접근할 수 있는 정보 (eg, Secret) 접근 권한을 준다.
    • 마찬가지로 해당 파드가 노드 C 로 이동하면 노드 A 의 권한은 드랍되고 C 로 권한이 옮겨간다
    • 따라서 직접적인 관계가 없는 노드가 털려도 정보를 갈취해 갈 수 없다.
    • 이러한 관계를 그래프로 관리하며 BFS 로 순회하며 권한을 지속적으로 갱신한다.
    • API server flag 로 RBAC 과 함께 기본적으로 활성화되어 있다
  • Kube-apiserver 옵션 확인:
kubectl -n kube-system get po kube-apiserver-week2 -oyaml | yq '.spec.containers.[0].command'
- kube-apiserver
- --advertise-address=192.168.100.18
- --allow-privileged=true
- --authorization-mode=Node,RBAC
- --client-ca-file=/etc/kubernetes/pki/ca.crt
- --enable-admission-plugins=NodeRestriction
- --enable-bootstrap-token-auth=true
- --etcd-cafile=/etc/kubernetes/pki/etcd/ca.crt
- --etcd-certfile=/etc/kubernetes/pki/apiserver-etcd-client.crt
- --etcd-keyfile=/etc/kubernetes/pki/apiserver-etcd-client.key
- --etcd-servers=https://127.0.0.1:2379
- --kubelet-client-certificate=/etc/kubernetes/pki/apiserver-kubelet-client.crt
- --kubelet-client-key=/etc/kubernetes/pki/apiserver-kubelet-client.key
- --kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname
- --proxy-client-cert-file=/etc/kubernetes/pki/front-proxy-client.crt
- --proxy-client-key-file=/etc/kubernetes/pki/front-proxy-client.key
- --requestheader-allowed-names=front-proxy-client
- --requestheader-client-ca-file=/etc/kubernetes/pki/front-proxy-ca.crt
- --requestheader-extra-headers-prefix=X-Remote-Extra-
- --requestheader-group-headers=X-Remote-Group
- --requestheader-username-headers=X-Remote-User
- --secure-port=6443
- --service-account-issuer=https://kubernetes.default.svc.cluster.local
- --service-account-key-file=/etc/kubernetes/pki/sa.pub
- --service-account-signing-key-file=/etc/kubernetes/pki/sa.key
- --service-cluster-ip-range=10.96.0.0/12
- --tls-cert-file=/etc/kubernetes/pki/apiserver.crt
- --tls-private-key-file=/etc/kubernetes/pki/apiserver.key
  • SA: hehe ns 의 boi sa 는 system:serviceaccount:hehe:boi User 와 동치이다. 즉,
- kind: ServiceAccount
  namespace: hehe
  name: boi
- kind: User
  name: system:serviceaccount:hehe:boi
  • 는 동치인데 실험해보지는 않았다고 한다

Admission Webhook

  • MutationWebHook: Pod 등이 생성되기 전에 외부에 구현되어 있는 mutation webhook 을 호출하도록 하여 추가적으로 변경할 수 있는 것들을 변경
  • ValidationWebHook: 이름에서부터 보이다시피 manifest 를 보고 허용되지 않은 작업을 드랍
  • ingress nginx 에서 사용해보기만 하고 뭔지는 잘 몰랐는데 이 수업을 듣는 중에서도 설명을 자세히는 안해줘서 디테일한건 모르겠다
kubectl api-resources | grep validating
# validatingwebhookconfigurations                  admissionregistration.k8s.io/v1        false        ValidatingWebhookConfiguration
kubectl api-resources | grep mutating
# mutatingwebhookconfigurations                  admissionregistration.k8s.io/v1        false        MutatingWebhookConfiguration

Extension API

CRD vs Aggregation layer

  • CRD 로 정의된 리소스는 etcd 에 저장되기 때문에 조회의 속도가 느림
  • 그래서 metrics server 나 calico 같은 경우에는 Aggregation layer 를 사용하여 kube-apiserver 를 proxy bypass 하여 속도를 취하는 방법이 있댄다

Helm controller: Helm release 를 CRD 로 작성하여 자동으로 배포