본문 바로가기

Infrastructure/Kubernetes

[K8S] 오브젝트 - 1

쿠버네티스 공식문서를 확인하며 쿠버네티스 오브젝트와 ID, 네임스페이스에 대해서 기억해야 하는 부분을 기록한다.

쿠버네티스 오브젝트가 쿠버네티스 API에서 어떻게 표현되고, 그 오브젝트를 어떻게 .yaml 형식으로 표현할 수 있는지에 대해 이해한다.


  • 쿠버네티스 오브젝트는 쿠버네티스 시스템에서 영속성을 가지는 오브젝트로 클러스터의 상태를 나타내기 위해 이 오브젝트를 이용하며 아래와 같은 정보를 포함할 수 있다.
    • 어떤 컨테이너화된 애플리케이션이 동작 중인지(그리고 어느 노드에서 동작 중인지)
    • 그 애플리케이션이 이용할 수 있는 리소스
    • 그 애플리케이션이 어떻게 재구동 정책, 업그레이드, 내고장성과 같은 것에 동작해야 하는지에 대한 정책
  • 쿠버네티스 오브젝트는 “하나의 의도를 담은 레코드”로 오브젝트를 생성하게 되면 쿠버네티스는 그 오브젝트 생성을 보장하기 위해 지속적으로 작동할 것이다.
  • 오브젝트를 생성하면서, 클러스터의 워크로드를 어떤 형태로 보이고자 하는지에 대해 쿠버네티스에 전달하고 이것이 클러스터에 대해 의도한 상태가 된다.
  • 쿠버네티스 오브젝트를 CRUD와 같이 동작시키기 위해서는 kubectl ~ 과 같이 쿠버네티스 API를 사용해야 한다. kubectl CLI를 사용하면 CLI는 필요한 쿠버네티스 API를 호출해 준다.
  • 클라이언트 라이브러리 중 하나를 이용하여 우리의 프로그램에서 쿠버네티스 API를 직접 이용할 수도 있다.

오브젝트 명세(spec)와 상태(status)

  • 대부분의 오브젝트의 구성을 결정하기 위해 두 개의 중첩된 오브젝트 필드를 포함하게 되는데 여기에 오브젝트 spec과 오브젝트 status가 포함된다.
  • spec을 가진 오브젝트는 오브젝트를 생성할 때 리소스에 의도한 상태와 같은 원하는 특징에 대한 설명을 제공해서 설정한다.
  • status는 쿠버네티스 시스템과 컴포넌트에 의해 제공되고 업데이트된 오브젝트의 현재 상태를 설명한다. 쿠버네티스 컨트롤 플레인은 모든 오브젝트의 실제 상태를 사용자가 의도한 상태와 일치시키기 위해 끊임없이 능동적으로 관리한다.
  • specstatus에 차이가 발생한다면 쿠버네티스는 이러한 차이를 제거하기 위해 대응한다.

쿠버네티스 오브젝트 기술

  • 쿠버네티스에서 오브젝트를 생성할 때, 이름과 같은 기본적인 정보와 함께, 의도한 상태를 기술하는 spec을 제시해야 한다.
  • 오브젝트를 생성하기 위해 API를 사용한다면 API 요청은 요청 내용 안에 JSON 형식으로 정보를 포함시켜 주어야 한다.
  • 대부분의 경우에는 정보를 .yaml 파일로 kubectl에 제공하며 kubectl은 API 요청이 이루어질 때 JSON 형식으로 정보를 변환해 준다.
    아래는 쿠버네티스 디플로이먼트를 위한 필수 필드와 오브젝트 spec을 보여주는 .yaml파일이다.
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 
  • 아래는 위에서 작성한 .yaml 파일을 kubectl CLI를 통해 쿠버네티스에 적용하는 커맨드 예시이다.
kubectl apply -f https://k8s.io/examples/application/deployment.yaml
  • 성공적으로 적용이 완료되면 아래와 같은 문구가 출력된다.
deployment.apps/nginx-deployment created

요구되는 필드

  • 생성하고자 하는 쿠버네티스 오브젝트에 대한 .yaml 파일은 아래의 필드를 포함해야 한다.
    • apiVersion: 오브젝트를 생성하기 위해 사용하고 있는 쿠버네티스 API 버전을 명시한다.
    • kind: 어떤 종류의 오브젝트를 생성하고자 하는지 명시한다.
    • metadata: 이름, UID, 네임스페이스를 포함하여 오브젝트를 구분지어 준다.
    • spec: 오브젝트에 대해 어떤 상태를 의도하는지 명시한다.
  • 오브젝트 spec에 대한 정확한 포맷은 모든 쿠버네티스 오브젝트마다 다르기 때문에 쿠버네티스 API 레퍼런스를 통해 확인해야 한다. 오브젝트는 특유의 중첩된 필드를 포함한다.

오브젝트 관리

  • kubectl CLI는 쿠버네티스 오브젝트를 생성하고 관리하기 위한 몇 가지 방법을 제공하지만 사용자는 단 하나의 기법만 사용해야 하며 그렇지 않은 경우 예상치 못한 동작을 초래하게 된다.
관리기법 대상 권장 환경 지원하는 작업자 수 학습 난이도
명령형 커맨드 활성 오브젝트 개발 환경 1+ 낮음
명령형 오브젝트 구성 개별 파일 프로덕션 환경 1 보통
선언형 오브젝트 구성 파일이 있는 디렉터리 프로덕션 환경 1+ 높음

명령형 커맨드

  • 명령형 커맨드를 사용하는 경우, 사용자는 클러스터 내 활성 오브젝트를 대상으로 직접 동작시키며 실행할 작업을 파라미터 또는 플래그로 kubectl 커맨드에 지정한다.
  • 클러스터에서 일회성 작업을 개시시키거나 동작시키기 위해 추천되는 방법이다. 활성 오브젝트를 대상으로 직접적인 영향을 미치기 때문에, 이전 구성에 대한 이력을 제공하지 않는다.
  • 아래와 같은 방식으로 디플로이먼트 오브젝트를 생성하여 nginx 컨테이너의 인스턴스를 구동시킨다.
kubectl create deployment nginx --image nginx

트레이드 오프

  • 오브젝트 구성에 비해 아래와 같은 장점을 가진다.
    • 커맨드는 하나의 동작을 나타내는 단어로 표현된다.
    • 커맨드는 클러스터를 수정하기 위해 단 하나의 단계만을 필요로 한다.
  • 오브젝트 구성에 비해 아래와 같은 단점을 가진다.
    • 커맨드는 변경 검토 프로세스와 통합되지 않는다.
    • 커맨드는 변경에 관한 감사 추적(audit trail)을 제공하지 않는다.
    • 커맨드는 활성 동작 중인 경우를 제외하고는 레코드의 소스를 제공하지 않는다.
    • 커맨드는 새로운 오브젝트 생성을 위한 템플릿을 제공하지 않는다.

명령형 오브젝트 구성

  • 명령형 오브젝트 구성에서는 kubectl 커맨드로 작업(생성, 교체 등), 선택적 플래그, 그리고 최소 하나의 파일 이름을 지정하며 yaml 또는 JSON 형식으로 오브젝트의 완전한 정의를 반드시 포함해야 한다.
  • 명령형 replace 커맨드는 기존 spec을 새로 제공된 spec으로 바꾸고 구성 파일에서 누락된 오브젝트의 모든 변경 사항을 삭제한다. LoadBalancer 유형의 서비스는 클러스터의 구성과 별도로 externalIPs 필드가 변경되기 때문에 spec이 구성 파일과는 별개로 업데이트되는 리소스 유형에는 사용하지 말아야 한다.
  • 아래와 같은 방식으로 nginx.yaml 에 정의된 오브젝트를 생성한다.
kubectl create -f nginx.yaml
  • 아래와 같은 방식으로 nginx.yamlredis.yaml 구성에 정의된 오브젝트를 삭제한다.
kubectl delete -f nginx.yaml -f redis.yaml
  • 아래와 같은 방식으로 기존에 정이되어 있는 오브젝트를 업데이트 한다.
kubectl replace -f nginx.yaml

트레이드 오프

  • 명령형 커맨드에 비해 아래와 같은 장점을 가지고 있다.
    • 오브젝트 구성은 Git과 같은 소스 컨트롤 시스템에 보관할 수 있다.
    • 오브젝트 구성은 푸시와 감사 추적 전에 변경사항을 검토하는 것과 같은 프로세스들과 통합할 수 있다.
    • 오브젝트 구성은 새로운 오브젝트 생성을 위한 템플릿을 제공한다.
  • 명령형 커맨드에 비해 아래와 같은 단점을 가지고 있다.
    • 오브젝트 구성은 오브젝트 스키마에 대한 기본적인 이해를 필요로 한다.
    • 오브젝트 구성은 YAML 파일을 기록하는 추가적인 과정을 필요로 한다.
  • 선언형 오브젝트 구성에 비해 아래와 같은 장점을 가지고 있다.
    • 명령형 오브젝트 구성의 동작은 보다 간결하고 이해하기 쉽다.
    • 쿠버네티스 버전 1.5 부터는 더 성숙한 명령형 오브젝트 구성을 제공한다.
  • 선언형 오브젝트 구성에 비해 단점은 아래와 같은 단점을 가지고 있다.
    • 명령형 오브젝트 구성은 디렉터리가 아닌, 파일에 가장 적합하다.
    • 활성 오브젝트에 대한 업데이트는 구성 파일에 반영되어야 한다. 그렇지 않으면 다음 교체 중에 손실된다.

선언형 오브젝트 구성

  • 선언형 오브젝트 구성을 사용하는 경우, 사용자는 로컬에 보관된 오브젝트 구성 파일을 대상으로 작동하지만 사용자는 파일에서 수행 할 작업을 정의하지 않는다. 생성, 업데이트, 그리고 삭제 작업은 kubectl에 의해 오브젝트마다 자동으로 감지되기 때문에 다른 오브젝트에 대해 다른 조작이 필요할 수 있는 디렉터리에서 작업할 수 있다.
  • 선언형 오브젝트 구성은 변경 사항이 오브젝트 구성 파일에 다시 병합되지 않더라도 다른 작성자가 작성한 변경 사항을 유지한다. 전체 오브젝트 구성 변경을 위한 replace API를 사용하는 대신, patch API를 사용하여 인지되는 차이만 작성이 가능하다.
  • configs 디렉터리 내 모든 오브젝트 구성 파일을 처리하고 활성 오브젝트를 생성 또는 패치한다. diff를 통해서 어떤 변경이 이루어지게 될지 알아볼 수 있고 apply를 통해서 변경사항을 적용할 수 있다.
kubectl diff -f configs/
kubectl apply -f configs/
kubectl diff -R -f configs/
kubectl apply -R -f configs/

트레이드 오프

  • 명령형 오브젝트 구성에 비해 장점은 아래와 같다.
    • 활성 오브젝트에 직접 작성된 변경 사항은 구성 파일로 다시 병합되지 않더라도 유지된다.
    • 선언형 오브젝트 구성은 디렉터리에서의 작업 및 오브젝트 별 작업 유형(생성, 패치, 삭제)의 자동 감지에 더 나은 지원을 제공한다.
  • 명령형 오브젝트 구성에 비해 단점은 아래와 같다.
    • 선언형 오브젝트 구성은 예상치 못한 결과를 디버깅하고 이해하기가 더 어렵다.
    • diff를 사용한 부분 업데이트는 복잡한 병합 및 패치 작업을 발생시킨다.

오브젝트 이름과 ID

  • 클러스터의 각 오브젝트는 해당 유형의 리소스에 대하여 고유한 이름을 가지고 있으며 모든 오브젝트는 전체 클러스터에 걸쳐 고유한 UID를 가지고 있다.
  • 이름이 myapp-1234인 파드는 동일한 네임스페이스 내에서 하나만 존재할 수 있지만, 이름이 myapp-1234인 파드와 디플로이먼트는 각각 존재할 수 있다.

이름

  • /api/v1/pods/some-name과 같이, 리소스 URL에서 오브젝트를 가리키며 클라이언트에게 제공하는 문자열이다.
  • 특정 시점에 같은 종류(kind) 내에서는 하나의 이름은 하나의 오브젝트에만 지정될 수 있지만 삭제되는 경우 삭제된 오브젝트와 동일한 이름을 새로운 오브젝트에 지정할 수 있다.
  • 물리적 호스트를 나타내는 노드와 같이 오브젝트가 물리적 엔티티를 나타내는 경우, 노드를 다시 삭제한 후 다시 생성하지 않은 채 동일한 이름으로 호스트를 다시 생성하면, 크버네티스는 새 호스트를 불일치로 이어질 수 있는 이전 호스트로 취급한다.

아래는 리소스에 일반적으로 사용되는 네 가지 유형의 이름 제한 조건이다.

DNS 서브도메인 이름

  • 대부분의 리소스 유형에는 RFC 1123에 정의된 대로 DNS 서브도메인 이름으로 사용할 수 있는 이름이 필요하며 아래와 같은 조건을 충족해야 한다.
    • 253자를 넘을 수 없다.
    • 영숫자(영문자 + 숫자) 그리고 - 또는 . 만 포함할 수 있다.
    • 영숫자로 시작해야 한다.
    • 영수자로 끝나야 한다.

RFC 1123 레이블 이름

  • 일부 리소스 유형은 RFC 1123에 정의된 DNS 레이블 표준에 따라 아래와 같은 조건을 충족해야 한다.
    • 63자를 넘을 수 없다.
    • 영숫자(영문자 + 숫자) 그리고 - 만 포함할 수 있다.
    • 영숫자로 시작해야 한다.
    • 영숫자로 끝나야 한다.

RFC 1035 레이블 이름

  • 일부 리소스 유형은 RFC 1035에 정의된 DNS 레이블 표준에 따라 아래와 같은 조건을 충족해야 한다.
    • 63자를 넘을 수 없다.
    • 영숫자(영문자 + 숫자) 그리고 - 만 포함할 수 있다.
    • 알파벳으로 시작해야 한다.
    • 영숫자로 끝나야 한다.

경로 세그먼트 이름

  • 일부 리소스 유형에서는 이름을 경로 세그먼트로 안전하게 인코딩 할 수 있어야 한다. 이름이 . 또는 ..이 아닐 수 있으며 이름에는 / 또는 %가 포함될 수 없다.

UID

  • 오브젝트를 중복 없이 식별하기 위해 쿠버네티스 시스템이 생성하는 문자열이다.
  • 쿠버네티스 클러스터가 구동되는 전체 시간이 걸쳐 생성되는 모든 오브젝트는 서로 구분되는 UID를 가지고 기록상에 유사한 오브젝트의 출현을 서로 구분하기 위해 사용된다.
  • 쿠버네티스 UID는 보편적으로 고유한 식별자로 UUID라고도 한다. UUID는 ISO/IEC 9834-8과 ITU-T X.667로 표준화 되어 있다.

네임스페이스

  • 쿠버네티스에서 네임스페이스는 단일 클러스터 내에서의 리소스 그룹 격리 메커니즘을 제공한다.
  • 리소스의 이름은 네임스페이스 내에서 유일해야 하며 네임스페이스가 다르다면 중복되어도 무관하다.
  • 네임스페이스에는 네임스페이스 기반의 오브젝트인 디플로이먼트, 서비스가 포함된다. 클러스터 범위의 오브젝트인 스토리지클래스와 노드 퍼시스턴트볼륨은 적용되지 않는다.

여러 개의 네임스페이스를 사용하는 경우

  • 네임스페이스는 여러 개의 팀이나, 프로젝트에 결쳐서 많은 사용자가 있는 환경에서 사용하도록 만들어졌기 때문에 수 십명 정도가 되는 경우에는 네임스페이스를 전혀 고려할 필요가 없으며 네임스페이스가 제공하는 기능이 필요할 때 도입하면 된다.
  • 네임스페이스는 서로 중첩될 수 없으며, 각 쿠버네티스 리소스는 하나의 네임스페이스에만 있을 수 있다.
  • 네임스페이스는 클러스터 자원을 리소스 쿼터를 통해 여러 사용자 사이에서 나누는 방법이다.
  • 동일한 소프트웨어의 다른 버전과 같이 약간 다른 리소스를 분리하기 위해 여러 네임스페이스를 사용할 필요는 없으며 동일한 네임스페이스 내에서 리소스를 구별하기 위해서는 레이블을 사용하면 된다.

네임스페이스 다루기

  • kube- 접두사로 시작하는 네임스페이스는 쿠버네티스 시스템용으로 예약되어 있으므로, 사용자는 이러한 네임스페이스를 생성하지 않는다.
  • 아래의 커맨드로 현재 사용 중인 네임스페이스를 나열할 수 있으며 기본으로 생성되는 네 개의 초기 네임스페이스의 역할을 아래와 같다.
kubectl get namespace
NAME              STATUS   AGE
default           Active   1d
kube-node-lease   Active   1d
kube-public       Active   1d
kube-system       Active   1d
  • default: 다른 네임스페이스가 없는 오브젝트를 위한 기본 네임스페이스.
  • kube-system: 쿠버네티스 시스템에서 생성한 오브젝트를 위한 네임스페이스.
  • kube-public: 네임스페이스는 자동으로 생성되며 인증되지 않은 사용자를 포함한 모든 사용자가 읽기 권한으로 접근할 수 있다. 주로 전체 클러스터 중에서 공개적으로 드러나서 읽을 수 있는 리소스를 위해 예약되어 있지만 공개적인 성격은 관례일 뿐 요구 사항은 아니다.
  • kube-node-lease: 각 노드와 연간된 리스 오브젝트를 갖는다. 노드 리스는 kubelet이 하트비트를 보내서 컨트롤 플레인이 노드의 장애를 탐지 할 수 있게 한다.

요청에 네임스페이스 설정하기

  • 요청에서 네임스페이스를 설정하려면 아래와 같이 --namespace 플래그를 사용해야 한다.
kubectl run nginx --image=nginx --namespace=<insert-namespace-name-here>
kubectl get pods --namespace=<insert-namespace-name-here>

선호하는 네임스페이스 설정하기

  • 선호하는 네임스페이스를 설정하면 이후 모든 kubectl 명령에서 네임스페이스를 영구적으로 저장할 수 있다.
kubectl config set-context --current --namespace=<insert-namespace-name-here>
# 확인하기
kubectl config view --minify | grep namespace:

네임스페이스와 DNS

  • 서비스를 생성하면 해당 DNS 엔트리가 생성된다. 이 엔트리는 <서비스-이름>.<네임스페이스-이름>.svc.cluster.local의 형식을 갖는다. 컨테이너가 <서비스-이름>만 사용하는 경우, 네임스페이스 내에 국한된 서비스로 연결된다.
  • 개발, 스테이징, 운영과 같이 여러 네임스페이스 내에서 동일한 설정을 사용하는 경우에 유용하게 사용된다.
  • 네임스페이스를 넘어서 접근하기 위해서는, 전체 주소 도메인 이름(FQDN)을 사용해야 한다.
  • 모든 네임스페이스 이름은 유효한 RFC 1123 DNS 레이블이어야 한다.
  • 네임스페이스의 이름을 공개 최상위 도메인 중 하나와 동일하게 만들면, 해당 네임스페이스 내의 서비스의 짧은 DNS 이름이 공개 DNS 레코드와 겹칠 수 있다.
  • 네임스페이스 내의 워크로드가 접미점(trailing dot) 없이 DNS 룩업을 수행하면 공개 DNS 레코드보다 우선하여 해당 서비스로 리다이렉트 될 것이다.
  • 신뢰하는 사용자만 네임스페이스를 생성할 수 있도록 권한을 제한하는 것이 좋다.
  • 어드미션 웹훅과 같은 써드파티 보안 컨트롤러를 구성하여 공개 TLD와 동일한 이름의 네임스페이스 생성을 금지시킬 수 있다.

모든 오브젝트가 네임스페이스에 속하지는 않음

  • 파드, 서비스, 레프릴케이션 컨트롤러와 같은 대부분의 쿠버네티스 리소스는 네임스페이스에 속한다. 하지만 네임스페이스 리소스 자체는 네임스페이스에 속하지 않는다.
  • 노드나 퍼시스턴트 볼륨과 같은 저수준 리소스 또한 어떠한 네임스페이스에도 속하지 않는다.
  • 아래의 커맨드로 네임스페이스에 속하거나 속하지 않는 리소스를 검색할 수 있다.
# 네임스페이스에 속하는 리소스
kubectl api-resources --namespaced=true

# 네임스페이스에 속하지 않는 리소스
kubectl api-resources --namespaced=false

자동 레이블링

  • 쿠버네티스 컨트롤 플레인은 NamespaceDefaultLabelName 기능 게이트가 활성화된 경우 모든 네임스페이스의 변경할 수 없는(immutable) 레이블인 kubernetes.io/metadata.name을 설정한다.
  • 레이블의 값은 네임스페이스의 이름이다.

참고 자료

'Infrastructure > Kubernetes' 카테고리의 다른 글

[클러스터 아키텍처] 노드  (0) 2022.10.13
[K8S] 오브젝트 - 2  (0) 2022.10.12
[K8S] 쿠버네티스란  (0) 2022.10.12
[K8S] 모범 사례  (0) 2022.10.12
[K8S] 컨테이너 런타임  (0) 2022.10.12