이번 글은 쿠버네티스의 API, 그리고 Object에 대해서 이야기를 해보겠습니다.


k8s API

쿠버네티스 컨트롤 플레인의 핵심은 API 서버로 API 서버는 최종 사용자, 클러스터의 다른 부분 그리고 외부 컴포넌트가 서로 통신할 수 있도록 HTTP API를 제공합니다.

쿠버네티스 API를 사용하면 쿠버네티스의 API 오브젝트(예: 파드(Pod), 네임스페이스(Namespace), 컨피그맵(ConfigMap) 그리고 이벤트(Event))를 질의(query) 및 조작 가능하고, 대부분의 작업은 kubectl 커맨드 라인 인터페이스를 통해 사용합니다.

레퍼런스:

쿠버네티스 API
쿠버네티스 API를 사용하면 쿠버네티스 오브젝트들의 상태를 쿼리하고 조작할 수 있다. 쿠버네티스 컨트롤 플레인의 핵심은 API 서버와 그것이 노출하는 HTTP API이다. 사용자와 클러스터의 다른 부분 및 모든 외부 컴포넌트는 API 서버를 통해 서로 통신한다.

reference: Kubernetes API

k8s Object

Object?

  • 쿠버네티스의 오브젝트(objects)는 클러스터의 상태를 나타내는 단위(entities)
  • 오브젝트는 “의도를 담은 레코드”입니다. 생성된 클러스터는 그 의도대로 존재할 수 있도록 최선을 다하며 이는 클러스터의 “의도한 상
    태(desired state)“라고 알려져 있음
  • 쿠버네티스는 항상 오브젝트의 “현재 상태”를 “의도한 상태”와 동일하게 만들게끔 작동

default object

  1. 파드 (Pod) - 쿠버네티스에서 실행되는 최소 단위 독립적인 공간과 IP를 가짐
  2. 네임스페이스 (Namespace) - 쿠버네티스 클러스터에서 사용되는 리소소들을 구분해서 관리하는 그룹
  3. 볼륨 (Volume) - 파드가 사라지더라고 저장/보존이 가능하며 파드에서 사용할 수 있는 스토리지를 제공
  4. 서비스 (Service) - 파드는 유동적이기 때문에 접속 정보가 고정되지 않으므로, 파드 접속을 안정적으로 유지하기 위한 기능

레퍼런스:

[Kubernetes] Kubernetes Object란
Kubernetes Object 쿠버네티스를 이해하기 위해서는 오브젝트에 대해 제대로 이해하고 넘어가야합니다. 쿠버네티스에서 오브젝트란 쿠버네티스를 구성하는 단위로, 가장 기본적인 구성단위인 기본 오브젝트(Basic Object)와 기본 오브젝트를 관리하고 추가적인 기능을 가진 컨트롤러(Controller)로 이루어져있습니다. 기본 오브젝트(Basic Object) 기본 오브젝트는 쿠버네티스에 의해서 배포 및 관리되는 가장 기본적인 오브젝트로, Pod, Service, Volume, Namespace 4가지가 있습니다. Pod Po…
쿠버네티스 #2 - 개념 이해 (1/2)
쿠버네티스 #2 개념 이해 (1/2) 조대협 (http://bcho.tistory.com) 쿠버네티스를 공부하면서 가장 헷갈리는 부분이 용어와 컨셉이다. 이 컨셉만 잘 이해하면 쿠버네티스를 쉽게 이해하고 사용할 수 있지만, 적어도 내 기준에서는 문서들의 용어나 개념 설명이 다소 어려웠다. 쿠버네티스의 개념은 크게 오브젝트 두개의 개념에서 출발한다. 각각을 살펴보도록 하자마스터와 노드쿠버네티스를 이해하기 위해서는 먼저 클러스터의 구조를 이해할 필요가 있는데, 구조는 매우 간단하다. 클러스터 전체를 관리하는 컨트롤러로써 마스터가 존재하…

Object Spec and Status

  apiVersion: apps/v1
kind: Deployment
metadata:
  name: boarder
  namespace: boarder
  uid: a1d511b9-f8a1-45be-903f-27beb9ec2674
  resourceVersion: '14861417'
  generation: 18
  creationTimestamp: '2023-03-21T09:49:50Z'
  labels:
    app.kubernetes.io/instance: boarder
    app.kubernetes.io/managed-by: Helm
    app.kubernetes.io/name: boarder
    argocd.argoproj.io/instance: boarder
    helm.sh/chart: autocrypt-dev-0.0.10
  annotations:
  deployment.kubernetes.io/revision: '16'
    kubectl.kubernetes.io/last-applied-configuration: >
          {"apiVersion":"apps/v1","kind":"Deployment","metadata":{"annotations":{},"labels":{"app.kubernetes.io/instance":"boarder","app.k
        managedFields:
          manager: argocd-controller
          manager: kube-controller-manager
          operation: Update
          apiVersion: apps/v1
          time: '2023-04-20T08:52:54Z'
          fieldsType: FieldsV1
          subresource: status
  selfLink: /apis/apps/v1/namespaces/boarder/deployments/boarder
  status:
  observedGeneration: 18
  replicas: 1
  updatedReplicas: 1
  readyReplicas: 1
  availableReplicas: 1
  conditions:
    type: Available
    status: 'True'
    lastUpdateTime: '2023-04-20T07:22:12Z'
    lastTransitionTime: '2023-04-20T07:22:12Z'
    reason: MinimumReplicasAvailable
    message: Deployment has minimum availability.
    type: Progressing
    status: 'True'
    lastUpdateTime: '2023-04-20T08:52:54Z'
    lastTransitionTime: '2023-04-11T01:36:36Z'
    reason: NewReplicaSetAvailable
    message: ReplicaSet "boarder-68b675fc6f" has successfully progressed.
spec:
  replicas: 1
  selector:
    matchLabels:
      app.kubernetes.io/instance: boarder
      app.kubernetes.io/name: boarder
template:
metadata:
  creationTimestamp: null
labels:
  app.kubernetes.io/instance: boarder
  app.kubernetes.io/name: boarder
  annotations:
    cluster-autoscaler.kubernetes.io/safe-to-evict: 'true'
  spec:
containers:
  name: boarder
  image: >-
      297752572146.dkr.ecr.ap-northeast-2.amazonaws.com/boarder/dev/k8s:f5e2641deb07792c3d19736a0c25c3b4bd5fffb2
      ports:
          name: http
          containerPort: 3003
          protocol:  TCP
        env:
          name: AWS_REGION
          value: ap-northeast-2
          name: PORT
        value: '3003'
      - name: APP_ENV
        value: dev
        resources:
        limits:
        cpu: 250m
        memory: 512M
        requests:
        cpu: 250m
        memory: 512M
    terminationMessagePath: /dev/termination-log
    terminationMessagePolicy: File
    imagePullPolicy: IfNotPresent
    securityContext:
      privileged: false
      allowPrivilegeEscalation: false
    restartPolicy: Always
    terminationGracePeriodSeconds: 30
    dnsPolicy: ClusterFirst
    serviceAccountName: boarder
    serviceAccount: boarder
    securityContext:
        fsGroup: 1337
        affinity: {}
      schedulerName: default-scheduler
        dnsConfig:
        options:
          - name: ndots
      value: '3'
strategy:
  type: RollingUpdate
  rollingUpdate:
      maxUnavailable: 25%
      maxSurge: 25%
revisionHistoryLimit: 2
progressDeadlineSeconds: 600


오브젝트는 spec(스펙, 명세)과 status(상태) 등의 값을 가지는데, 여기에는 오브젝트를 생성한 의도나 오브젝트를 관리할 때 원하는 상태 등을 설정

Wanted YAML sample

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  spec:
  selector:
  matchLabels:
    app: nginx
replicas: 2 # tells deployment to run 2 pods matching the template
template:
  metadata:
  labels:
    app: nginx
    spec:
  containers:
  - name: nginx
    image: nginx:1.14.2
    ports:
    - containerPort: 80

실제 적용은 kubectl apply -f {test}.yaml 명령어로 실행

Management

  1. 명령형 커맨드
  • command에 변수들을 수동 넣어 kubectl로 호출, ex:
 
kubectl create deployment nginx --image nginx

  • 단점: audit trail을 제공하지 않음
  1. 명령형 오브젝트
  • 위와 같이 yaml 파일을 만들고 이를 인자로 호출, ex:
 
kubectl create -f nginx.yaml
  1. 선언형 오브젝트
  • dir 에 파일들을 모아두고 통째로 호출, ex:
 
kubectl apply -f configs/

Required Field

  • apiVersion은 이 스크립트를 실행하기 위한 쿠버네티스 API 버전이다 보통 v1을 사용한다.
  • kind 에는 리소스의 종류를 정의하는데, Deployment를 정의하려고 하기 때문에, Deployment라고 넣는다.
  • metadata에는 이 리소스의 각종 메타 데이타를 넣는데, 라벨(뒤에서 설명할)이나 리소스의 이름등 각종 메타데이타를 넣는다
  • spec 부분에 리소스에 대한 상세한 스펙을 정의한다.
    • Pod는 컨테이너를 가지고 있기 때문에, container 를 정의한다. 이름은 nginx-deployment로 하고 도커 이미지 nginx:1.14.2 를 사용하고, 컨테이너 포트 80을 오픈한다.
💡
Pod 안에 한개 이상의 컨테이너를 가지고 있을 수 있다고 했는데 왜 개별적으로 하나씩 컨테이너를 배포하지 않고 여러개의 컨테이너를 Pod 단위로 묶어서 배포하는 것인가?

Pod는 다음과 같이 매우 재미있는 특징을 갖는다.

  • Pod 내의 컨테이너는 IP와 Port를 공유한다. 두 개의 컨테이너가 하나의 Pod를 통해서 배포되었을때, localhost를 통해서 통신이 가능하다.예를 들어 컨테이너 A가 8080, 컨테이너 B가 7001로 배포가 되었을 때, B에서 A를 호출할때는 localhost:8080 으로 호출하면 되고, 반대로 A에서 B를 호출할때에넌 localhost:7001로 호출하면 된다.
  • Pod 내에 배포된 컨테이너간에는 디스크 볼륨을 공유할 수 있다. 근래 애플리케이션들은 실행할때 애플리케이션만 올라가는것이 아니라 Reverse proxy, 로그 수집기등 다양한 주변 솔루션이 같이 배포 되는 경우가 많고, 특히 로그 수집기의 경우에는 애플리케이션 로그 파일을 읽어서 수집한다.
  • 애플리케이션 (Tomcat, node.js)와 로그 수집기를 다른 컨테이너로 배포할 경우, 일반적인 경우에는 컨테이너에 의해서 파일 시스템이 분리되기 때문에, 로그 수집기가 애플리케이션이 배포된 컨테이너의 로그파일을 읽는 것이 불가능 하지만, 쿠버네티스의 경우 하나의 Pod 내에서는 컨테이너들끼리 볼륨을 공유할 수 있기 때문에 다른 컨테이너의 파일을 읽어올 수 있다.

위와 같이 애플리케이션과 애플리케이션에서 사용하는 주변 프로그램을 같이 배포하는 패턴을 마이크로 서비스 아키텍쳐에서 사이드카 패턴(Side car pattern)이라고 하며 Istio등이 이와 같이 실행된다

(이후 사용될 filebeat도 이렇게 동작할것으로 보임)

Namespace

단일 클러스터 내에서 리소스 그룹을 격리하기 위한 메커니즘으로 Namespace라는 개념을 사용함. 리소스의 이름은 네임스페이스 내에서 유일해야 하며, 네임스페이스 간에서 유일할 필요는 없다.

네임스페이스 기반 스코핑은 네임스페이스 기반 오브젝트 (예: 디플로이먼트, 서비스 등)에만 적용 가능하며 클러스터 범위의 오브젝트 (예: 스토리지클래스, 노드, 퍼시스턴트볼륨 등)에는 적용 불가능

  • 처음에 4개의 초기 네임스페이스를 갖는다.
  1. default 다른 네임스페이스가 없는 오브젝트를 위한 기본 네임스페이스
  2. kube-system 쿠버네티스 시스템에서 생성한 오브젝트를 위한 네임스페이스
  3. kube-public 이 네임스페이스는 자동으로 생성되며 모든 사용자(인증되지 않은 사용자 포함)가 읽기 권한으로 접근할 수 있어 주로 전체 클러스터 중에 공개적으로 드러나서 읽을 수 있는 리소스를 위해 예약되어 있음
  4. kube-node-lease 이 네임스페이스는 각 노드와 연관된 리스 오브젝트를 갖는다. 노드 리스는 kubelet이 하트비트를 보내서 컨트롤 플레인이 노드의 장애를 탐지할 수 있게 한다.
🫣
<서비스-이름>.<네임스페이스-이름>.svc.ac-cluster-seoul 의 형식을 갖는다.

이는 컨테이너가 <서비스-이름> 만 사용하는 경우, 네임스페이스 내에 국한된 서비스로 연결된다. 그렇기 때문에, 모든 네임스페이스 이름은 유효한 RFC 1123 DNS 레이블이어야 한다.

Label

포드와 같은 객체(오브젝트)에 연결된 키/값 쌍으로 사용자에게 의미 있고 관련이 있는 객체(오브젝트)의 식별 속성을 지정하는 데 사용되지만 핵심 시스템에 의미 체계를 직접적으로 암시하지는 않음

쉽게 표현하자면 AWS의 TAG와 거의 같다고 보면 됨! 중요한 개념은 아래의 두가지가 있음.

  1. Label 규칙

레이블은 키와 값의 쌍이다. 유효한 레이블 키에는 슬래시 ( / )로 구분되는 선택한 접두사와 이름이라는 2개의 세그먼트가 있다. 이름 세그먼트는 63자 미만으로 시작과 끝은 알파벳과 숫자 ( [a-z0-9A-Z] )이며, 대시 ( - ), 밑줄 ( _ ), 점 ( . )과 함께 사용할 수 있다. 접두사는 선택이다. 만약 접두사를 지정한 경우 접두사는 DNS의 하위 도메인으로 해야 하며, 점 ( . )과 전체 253자 이후, 슬래시 ( / )로 구분되는 DNS 레이블이다.

접두사는 생략하면 키 레이블은 개인용으로 간주한다. 최종 사용자의 오브젝트에 자동화된 시스템 컴포넌트(예: kube-scheduler, kube-controller-manager, kube-apiserver, kubectl, 또는 다른 타사의 자동화 구성 요소)의 접두사를 지정해야 한다.

유효한 레이블 값은 다음과 같다:

  • 63자 이하여야 하고 (공백일 수도 있음),
  • (공백이 아니라면) 시작과 끝은 알파벳과 숫자 ( [a-z-9A-Z] )이며,
  • 알파벳과 숫자, 대시 ( - ), 밑줄 ( _ ), 점 ( . )을 중간에 포함할 수 있다.

Ref:

권장 레이블
kubectl과 대시보드와 같은 많은 도구들로 쿠버네티스 오브젝트를 시각화 하고 관리할 수 있다. 공통 레이블 셋은 모든 도구들이 이해할 수 있는 공통의 방식으로 오브젝트를 식별하고 도구들이 상호 운용적으로 작동할 수 있도록 한다. 권장 레이블은 지원 도구 외에도 쿼리하는 방식으로 애플리케이션을 식별하게 한다. 메타데이터는 애플리케이션 의 개념을 중심으로 정리된다. 쿠버네티스는 플랫폼 서비스(PaaS)가 아니며 애플리케이션에 대해 공식적인 개념이 없거나 강요하지 않는다. 대신 애플리케이션은 비공식적이며 메타데이터로 설명된다. 애플리…
잘 알려진 레이블, 어노테이션, 테인트(Taint)
운영 수준의 컨테이너 오케스트레이션
  1. Selector

오브젝트 이름과 UID와는 다르게 레이블은 고유하지 않아 일반적으로 많은 오브젝트에 같은 레이블을 가질것으로 예상한다. 따라서 레이블 셀렉터를 통해 클라이언트와 사용자는 오브젝트를 식별할 수 있다.

레이블 셀렉터는 쿠버네티스 코어 그룹의 기본 구성 요소중 하나로 현재 일치성 기준 과 집합성 기준 이라는 두 종류의 셀렉터를 지원하며, 쉼표로 AND 연산자와 같은 요구사항을 충족할 수 있음

  • 일치성 기준 요건: = , == , != 이 세 가지 연산자만 허용
  environment = production
  tier != frontend
  # ==
  environment=production,tier!=frontend
  • 일반적으로 많이 쓰는 pod에서 node selector 예시
apiVersion: v1
kind: Pod
metadata:
  name: cuda-test
  spec:
  containers:
    - name: cuda-test
    image: "registry.k8s.io/cuda-vector-add:v0.1"
    resources:
      limits:
      nvidia.com/gpu: 1
  nodeSelector:
    accelerator: nvidia-tesla-p100
# accelerator=nvidia-tesla-p100 레이블을 가진 노드에서만 뜨게 됨
  • 집합성 기준 요건: 집합성 기준 레이블 요건에 따라 값 집합을 키로 필터링
    • in , notin exists(키 식별자에만 해당) 3개의 연산자를 지원
      • environment in (production, qa)
        • environment가 production or qa인 리소스
      • tier notin (frontend, backend)
        • tier 가 frontend, backend가 아닌 리소스
      • partition (exists)
        • partition이라는 레이블 키가 존재하는 리소스
      • !partition (exists not)
        • partition이라는 레이블 키가 존재하지 않는 리소스
⚠️
집합성 기준과 일치성 기준은 조합해서 사용할 수 있다.
ex) partition in (customerA, customerB),environment!=qa
  • 테스트 방법
  kubectl get pods -l app.kubernetes.io/instance=boarder,pod-template-hash!=test -n boarder

Annotations

쿠버네티스 어노테이션을 사용하여 임의의 비-식별 메타데이터를 오브젝트에 첨부할 수 있다, 레이블과 같이 키/값 맵으로 구성된다. 정도가 공식 설명인데 여기서 핵심은 비-식별과 Annotation(주석) 이라는 이름.

  • 비-식별
    • label은 쿠버네티스 개체에 부여가 되는 key-value 값으로 index가 되어 리소스들을 구분하는데에 사용됩니다. 특정 레이블을 가진 녀석, 안가진 녀석 과 같이 쿼리를 하는것들이 가능해 리소스 그룹을 지정하는데에 사용
    • 하지만 Annotation은 그러한 식별이 되지 않는 비식별 정보로 쿠버네티스 내부에서 인식이 되어 사용되는 값은 아님
  • 주석
    • 위에서 말햇듯 식별이 되지는 않지만 추가적으로 정보를 기입한다는 점에서 코드에 실제로 적용은 되지 않지만 추가적인 것을 설명하는 “주석”과 같은 역할로 주로 쓰임
    • ex) 쿠버네티스 내부적으로 사용되지는 않지만 외부 3rd party에서 사용되기 위한 key-value 데이터, 프로젝트 담당자나, 비상연락처, repository를 기입해 빠르게 정보를 확인하게 하는 요소, 혹은 모니터링에 필요한 정보, 릴리즈 정보등

Finalizer

파이널라이저는 쿠버네티스가 오브젝트를 완전히 삭제하기 이전, 삭제 표시를 위해 특정 조건이 충족될 때까지 대기하도록 알려주기 위한 네임스페이스에 속한 키(namespaced key)

파이널라이저를 가진 특정한 오브젝트를 쿠버네티스가 삭제하도록 지시할 때, 쿠버네티스 API는 .metadata.delationTimestamp을 덧붙여 삭제하도록 오브젝트에 표시하며 202상태코드(HTTP"Accepted")을 리턴한다. 대상 오브젝트가 Terminating 상태를 유지하는 동안 컨트롤 플레인 또는 다른 컴포넌트는 하나의 파이널라이저에서 정의한 작업을 수행한다. 정의된 작업이 완료 후에, 그 컨트롤러는 대상 오브젝트로부터 연관된 파이널라이저를 삭제한다. metadata.finalizers 필드가 비어있을 때, 쿠버네티스는 삭제가 완료된 것으로 간주하고 오브젝트를 삭제한다.

  • argocd에서는 여러 리소스들을 application set 로 총괄 관리 및 운영하는데 이 finalizer 개념을 사용해 종종 지우는 요청을 하는데도 아무런 동작을 하지 않고 hang이 걸리는 경우가 있음
  • 이런 경우 문제가 되는 리소스의 finalizer가 제대로 지워지지 않아 (다른 과정이 동시에 일어나며 해당 작업이 무시됨) 리소스 삭제가 이루어지 않는게 원인임.

Owner and Dependents

  • 쿠버네티스에서 일부 오브젝트들은 다른 오브젝트의 owner인 경우가 있다
  • ex) deployment나 replicaset은 pod set의 owner이다.
  • 이러한 종속 관계를 보통 k8s에서 일반적으로 관계에 맞게 설정해주지만 수동으로 설정해야하는 경우가 있기에 이러한 옵션이 존재한다.
  • 특수한 경우에만 쓰이기에 그냥 이러한 것이 있다. 라는 정도만 알고 넘어가자.
⚠️
추가적으로 이 기능은 한 Namespace 내에서만 종속이 가능, 교차 네임스페이스로 타 네임스페이스에 있는것을 종속시키는것은 불가능함

Field Selector

  kubectl get pods --field-selector status.phase=Running

Ref:

필드 셀렉터
필드 셀렉터 는 한 개 이상의 리소스 필드 값에 따라 쿠버네티스 리소스를 선택하기 위해 사용된다. 필드 셀렉터 쿼리의 예시는 다음과 같다. metadata.name=my-service metadata.namespace!=default status.phase=Pending 다음의 kubectl 커맨드는 status.phase 필드의 값이 Running 인 모든 파드를 선택한다. kubectl get pods --field-selector status.phase=Running 참고: 필드 셀렉터는 본질적으로 리소스 필터 이다. 기본적으…

이렇게 해서 쿠버네티스에 대한 overview를 마무리 합니다! 🤓

혹시 part 1, 2 놓치셨다면 다시 확인 해보세요!