MinUk.Dev
쿠버네티스 패턴 - minuk dev wiki

쿠버네티스 패턴

created : Tue, 16 Aug 2022 10:56:05 +0900
modified : Fri, 26 Aug 2022 16:08:59 +0900
  • 책 내용 정리 및 공식 문서와 비교하며 버전 확인

1장 개요

클라우드 네이티브로 가는길

  • 클린코드
  • 도메인 주도 설계
  • 마이크로서비스 아키텍처 방식
  • 컨테이너

분산 기본 요소

개념로컬 기본 요소분산 기본 요소
캡슐화 동작클래스컨테이너 이미지
인스턴스화 동작객체컨테이너
재사용 단위Jar 파일컨테이너 이미지
컴포지션포함 관계사이드카 패턴
상속확장 관계FROM 으로 부모 이미지 상속
배포 단위.jar/.war/.earpod
빌드타임/런타임 격리모듈, 패키지, 클래스namespace, pod, container
초기화 필요조건Constructor초기화 컨테이너
초기화 직 후 트리거Init methodpostStart
삭제 직전 트리거Destroy methodpreStop
정리 절차finalize(), shutdown hookDefer 컨테이너
비동기 & 병렬 칫행ThreadPoolExecutor, ForkJoinPoolJob
주기적 작업Timer, ScheduleExecutorServiceCronJob
백그라운드 작업Deamon ThreadDeamonSets
설정관리System.getenv(), PropertiesConfigMap, Secret

컨테이너

  • 컨테이너 이미지는 하나의 문제를 해결하는 기능 단위다.
  • 컨테이너 이미지는 하나의 팀에 의해 소유되며, 릴리즈 주기가 있다.
  • 컨테이너 이미지는 자기 완비적이며, 런타임 의존 성을 정의하고 수행한다.
  • 컨테이너 이미지는 불변적이며, 한번 만들어지면 변경되지 않는다. 즉 이미 설정 값이 정해져 있다.
  • 컨테이너 이미지는 런타임 의존성과 자원 요구사항이 정의되어 있다.
  • 컨테이너 이미지는 기능을 노출시키기 위해 잘 정의된 API가 있다.
  • 컨테이너는 일반적으로 하나의 유닉스 프로세스로 실행된다.
  • 컨테이너는 일회용이며 언제든지 스케일 업과 스케일 다운을 안전하게 수행할 수 있다.

파드

  • 파드는 스케줄링의 최소 단위이다.
  • 파드는 파드에 속한 컨테이너들의 동일 장소 배치를 보장한다.
  • 한 파드는 파드 안의 모든 컨테이너가 공유하는 하나의 IP 주소와 이름, 포트 범위를 갖는다.

서비스

  • 서비스는 애플리케이션에 접근하기 위한 이름으로 된 진입점이다.

레이블

  • 레이블은 실행 중인 특정 파드의 인스턴스들을 가리키기 위해 사용된다.
  • 레이블은 스케줄러에서 많이 사용된다.
  • 레이블은 파드를 논리적 그룹으로 묶어 가리킬 수 있다.
  • 미리 앞서서 레이블을 추가하지 않아야한다. 레이블 삭제가 어떤 영향을 일으키는지 알아낼 방법이 없다.

어노테이션

  • 레이블과 유사한 기능을 하지만, 사람보다는 봇을 위한 용도로 사용된다.
  • 검색 불가능한 메타데이터를 지정하는데 사용한다.

네임스페이스

  • 네임스페이스는 쿠버네티스 자원으로서 관리된다.
  • 네임스페이스는 컨테이너, 파드, 서비스, 레플리카세트 등의 자원에 대한 영역을 제공한다.
  • 네임스페이스 내에서 자원명은 고유해야한다.
  • 네임스페이스는 격리시키는 것이 아니므로 자원간 접근을 막을수는 없다.
  • 노드, PersistentVolume 등은 네임스페이스 내에 속하지 않는다.
  • 서비스는 <service-name>.<namespace-name>.svc.cluster.local 형식의 dns address 를 갖는다.
  • ResourceQuota는 네임스페이스 별로 제약조건을 걸 수 있다.

1부 기본 패턴

2장 예측 범위 내의 요구사항

  • 애플리케이션의 요구사항에 따라서 필요한 자원량은 달라지며, 이를 예측하는 것은 어려운 일이다.
  • 쿠버네티스를 사용하면서 런타임 요구사항을 알아야하는 이유:
    • 효율적인 하드웨어 사용을 위한 배치
    • 전체 클러스터 설계 및 관리

런타임 의존성

  • PersistentVolume
  • hostPort
  • configMap, secret

자원 프로파일

  • compressible resource : cpu, network
  • incompressible resource : memory
  • incompressible resource를 너무 많이 사용할 경우 컨테이너가 죽게 된다.
  • requests, limits 에 따른 서비스 구분:
    • Best-Effort:
      • requests, limits 를 갖고 있지 않다.
      • incompressible resource가 모자랄때, 가장 먼저 죽는다.
    • Burstable:
      • requests와 limits 가 다르다. (일반적으로 limits 가 requests 보다 크다.)
    • Guaranteed:
      • requests와 limts가 같다.
      • 가장 나중에 죽는다.

파드 우선순위

  • 책의 내용과 살짝 다르다. k8s v1.24 문서를 기준으로 작성되었다.
apiVersion: scheduling.k8s.io/v1
kind: PrioirtyClass
metadata:
  name: high-priority
value: 1000
globalDefault: flase
description: "This is a very high priority Pod class"
---
apiVersion: v1
kind: Pod
metadata:
  name: random-generator
  labels:
    env: random-generator
spec:
  containers:
  - image: k8spatterns/random-generator:1.0
    name: random-generator
  priorityClassName: high-prioirty

프로젝트 자원

  • 추가 참고자료 : 메모리 상승과 오버커밋
  • 메모리 오버커밋 : 요구된 메모리를 그대로 할당하는 것이 아닌 실제 사용되는 시점에서 필요한 만큼의 메모리를 할당하는 방식에 의해 요구되는 메모리의 총량이 100%를 넘기는 경우
  • 오버 커밋 상태에서 실제 메모리 사용 총량이 메모리 총량을 넘기게 될 수도 있는데, 이때 OOM-Killer에 의해 프로세스들을 죽여서 용량을 확보하게 된다.
  • 개인 해석:
    • 오버커밋에 의해 요청된 메모리와 사용하는 메모리는 차이가 날 수 있다.
    • 즉 requests는 250M를 하는데, pod에서 오버커밋을 이용해 500M를 할당하고, 사용은 200M를 하고 있는 상황같은게 발생 할 수 있다는 것이다.
    • kubernetes 는 기본적으로 requests 를 기준으로 스케줄링한다.

3장 선언적 배포

  • 선언적 업데이트를 작동시키기 위한 옵션:
    • kubectl replace로 새로운 버전의 deployment로 전체 deployment를 교체한다.
    • deployment를 kubectl patchkubectl edit으로 새로운 버전을 넣는다.
    • kubectl set image 을 통해서 deployment에 새로운 이미지를 넣는다.
  • deployment 의 장점:
    • deployment는 상태가 내부적으로 관리되는 객체이므로 클라이언트와 상호작용 없이, 서버측에서 실행된다.
    • deployment 의 선언적 특성은 배포에 필요한 단계보다는 배포된 상태가 어떻게 보여야하는지를 알 수 있다.
    • deployment의 정의는 운영 환경에 배포되기 전에 다양한 환경에서 테스트된 실행 가능한 객체이다.
    • 업데이트 프로세스는 모두 기록되며, 일시 중지 및 계속을 위한 옵션, 이전 버전으로 롤백을 위한 옵션으로 버전이 지정된다.

고정 배포

  • Recreate 전략:
    • 우선적으로 현재 버전의 모든 컨테이너를 죽이고, 이전 버전의 컨테이너가 축출될때 모든 신규 컨테이너를 동시에 시작한다.

블루-그린

  • 블루(이전 버전), 그린(현재 버전)
  • 블루와 그린을 모두 띄운뒤 신규 트래픽을 그린으로 보낸뒤, 기존 트래픽을 다 처리하면 블루를 삭제한다.
  • 블루와 그린이 순간적으로 동시에 뜨게 된다.
  • 즉, 자원이 2배로 필요하다.

카나리아

  • 소수의 인스턴스를 교체하면서 동작한다.

4장 정상상태 점검

  • 프로세스 상태는 애플리케이션의 정상상태를 결정하기에는 충분하지 않다.

Liveness probe

  • HTTP : 200~399 사이 응답코드

  • TCP : 성공적인 TCP connection

  • Exec : 성공적인 종료코드(0)

  • 한번쯤은 yaml을 써보는게 도움이 될거 같아서 써본다. 실제로는 문서를 참고해서 작성할것

apiVersion: v1
kind: Pod
metadata:
  name: pod-with-liveness-check
spec:
  containers:
  - image: k8spatterns/random-generator:1.0
    name: random-generator
    env:
    - name: DELAY_STARTUP
      value: "20"
    ports:
    - containerPort: 8080
    protocol: TCP
    livenessProbe:
      httpGet:
        path: /actuator/health
        port: 8080
      initialDelaySeconds: 30

Readiness probe

  • liveness와는 다르게 readiness probe 이 실패할 경우, service의 endpoint가 제거되어 새로운 트래픽을 수신할 수 없게 된다.

Others

  • spring actuator, wide-fly swarm, karaf, microprofile spec 등 애플리케이션 프레임워크는 정상상태 점검을 위한 인터페이스를 제공한다.
  • 로그는 표준스트림 이외에도 /dev/termination-log 에 남기는 것이 좋다.
  • OpenTracing이나 Prometheus 같은 트레이싱, 메트릭 수집 라이브러리와 통합하여 어플리케이션 상태를 관찰할 수 있도록 해야한다.

5장 수명주기 관리

  • k8s는 컨테이너를 종료시킬때, SIGTERM을 먼저, 그 다음 .spec.terminationGracePeriodSeconds 의 유예시간 이후 SIGKILL을 발생시킨다.
  • postStart, preStop 훅
apiVersion: v1
kind: Pod
metatdata:
  name: hooks
spec:
  containers:
  - image: k8spatterns/random-generator:1.0
  name: random-generator
  lifecycle:
    postStart:
      exec:
        command:
        - sh
        - -c
        - sleep 30 && echo "Wake up!" > /tmp/postStart_done
    preStop:
      httpGet:
        port: 8080
        path: /shutdown
  • 수명주기 훅과 초기화 컨테이너
측면수명주기 훅초기화 컨테이너
활성화 단계컨테이너 수명주기 단계파드 수명주기 단계
시작 단계 동작postStart 명령어실행될 초기화 컨테이너 목록
종료 단계 동작preStop 명령어X
타이밍(Timing) 보장postStart 명령은 컨테이너의 ENTRYPOINT 와 동시에 실행애플리케이션 컨테이너가 시작되기 전에 모든 초기화 컨테이너는 성공적으로 종료가 완료되어야 한다.
사용 사례컨테이너별로 트고하된 중요하지 않은 시작/정리 종료를 실행컨테이너를 사용해 워크플로우 같은 순차적 작업을 수행. 작업 실행을 위해 컨테이너를 재사용

6장 자동 배치

  • 가용한 노드 자원:
    • Allocatable = Node Capacity - Kube-Reserved - System-Reserved
    • Kube-Reserved : 쿠버네티스 데몬에 의해 사용되는 자원
    • System-Reserved : sshd, udev 와 같은 시스템 데몬에 사용되는 자원
    • OS와 Kubernetes가 사용하는 자원을 따로 예약해두지 않으면 자원 부족 문제가 생길 수 있다.

Node Affinity

  • .spec.affinity.nodeAffinity 를 통해서 선호 조건, 필수 조건을 걸 수 있다.

Pod Affinity

  • 다른 파드와 상대적인 위치

Taint 와 Toleration

  • taint 종류:
    • effect=NoSchedule : 스케줄링을 피하는
    • effect=PreferNoSchdule : 가급적 스케줄링을 피하는
    • effect=NoExecute : 이미 실행중인것을 빼도록

Descheduler

  • 처음 들어본 개념이라 좀 찾아봤는데, 기본적으로 지원하는 건 아니고 추가적으로 deployment 형태로 설치해야하는 것 같다.
  • 공식사이트 에서는 helm 이나 다른 방법으로 설치하는 것도 안내해주고 있다.
  • Scheduler 만으로는 앞으로 Balance 하는것을 만드는 거지, 이미 배포된 것들에 대해서 처리하지 못하기 때문에 사용한다.
  • 전략 종류:
    • RemoveDuplicates, LowNodeUtilization, RemovePodsViolatingInterPodAntiAffinity, RemovePodsViolatingNodeAffinity
  • Descheduler가 건들이지 않는 Pod:
    • Replicaset, Deployment, Job, DeamonSet에 의해서 관리되지 않는 파드
    • local storage을 갖는 pod
    • PodDisruptionBudget 규칙에 위배되는 Pod
    • Deschdeduler 파드

2부 행동 패턴

7장 배치 잡

  • 잡의 특징:

    • 잡은 일시적인 인메모리 작업이 아니라, 클러스터 재시작에도 살아남는 지속된 작업이다.
    • 잡은 완료되고 나면, 삭제되지 않고 추적 목적으로 유지된다. 잡의 일부분으로 생성된 파드도 삭제되지 않으며 검사가 가능하다.
    • 잡은 여러번 실행되어야 할 수 있다. (.spec.completions 항목 참조)
    • 잡이 여러번 실행되어야하는 경우 동시에 실행할 수도 있다. (.spec.parallelism 항목 참조)
    • Pod 가 실행 중인 동안 노드에 장애가 되거나 어떠한 이유로 Pod가 extract 되었을 때, Scheduler 는 Pod를 재배치 후 실행한다.
  • 잡의 종류:

    • 단일 파드 잡(Single Pod Job):
      • .spec.comletions.spec.parallelism 값을 생략 또는 모두 1로 세팅
    • 고정 완료 횟수 잡(Fixed completion count Job):
      • .spec.completions 은 1보다 크게, .spec.parallelism 은 1로 세팅
    • 작업 큐 잡(Work queue Job):
      • .spec.completions 은 생략, .spec.parllelism 은 1보다 크게 세팅
  • 복잡한 작업은 batch application framework(e.g. Spring Batch, JBeret) 으로 실행

8장 주기적 잡

  • 책에 있는 내용은 v1beta1 이지만, 현재(v1.24) 에서는 v1 이다.
apiVersion: batch/v1
kind: CronJob
metadata:
  name: random-generator
spec:
  schedule: "*/3 * * * *"
  jobTemplate:
    spec:
      template:
        spec:
          containers:
          - name: random-generator
            image: k8spatterns/random-generator:1.0
            command:
            - "java"
            - "-cp"
            - "/"
            - "RandomRunner"
            - "/numbers.txt"
            - "10000"
          restartPolicy: OnFailure
  • 주의사항:

    • CronJob은 특정 상황에서 여러 잡을 생성할 수 있다. 따라서 Job은 멱등성(idempotent)을 지니도록 구성해야한다.
    • v1 CronJob API 는 타임존 설정을 공식적으로 지원하지 않는다. 이는 내부 라이브러리가 어떻게 구현되었는 가에 따라서 다르게 동작할 수 있다. 즉, 프로덕션 레벨에서는 사용이 권장되지 않는다.
    • CronJob 은 kube-controller-manager 의 시간대를 기준으로 한다.
  • 개인 생각:

    • 시간대별로 필요한거면, 복잡한 Job에 해당한다고 생각한다. Spring Batch를 사용하는게 옳지 않나 싶다.

9장 데몬 서비스

  • DeamonSet 의 특징:

    • nodeSelector를 통해 제한하지 않는한, 모든 노드에 하나의 Pod가 배치된다.
    • DeamonSet 에 의해 생성된 Pod은 생성된 시점에 nodeName을 가진다. 따라서 Scheduler에 의해 배치 되지 않는다. 이는 Scheduler와 상관 없이 실행되며, Scheduler에 의해 Pod들이 배치 되기 전에 실행할 수 있다는 것을 의미한다.
    • 대부분의 컨트롤러는 DeamonSet에 의해 생성된 Pod를 더 높은 우선순위로 별개 취급한다.
  • DeamonSet 에 의해 생성되는 대표적인 오브젝트들:

    • Service
    • DNS
    • NodeIP with hostPort
    • Push
  • Static Pod 와 비교:

    • Static Pod 는 Kubelet에 의해서만 관리되며, controller는 없고 health check 를 실행하지 않는다. 이 모든 것이 kubelet에 의해서만 관리된다.

10장 싱글톤 서비스

애플리케이션 외부 잠금

  • 어플리케이션 외부에서 별도의 관리 프로세스를 통해서 싱글톤을 구현하는 방법
  • replica set으로 구현할 경우 replicas 숫자를 1로 유지한다는 보장이 없으므로 별도의 주의가 필요하다.
  • 일시적으로 node가 비정상 상태일 경우, 새롭게 Pod 가 생성되는데, 이때 비정상이였던 node가 살아나면 싱글톤 보장이 깨진다.
  • StatefulSet 을 사용해 구현할 경우, 강력하게 싱글톤 제약을 걸 수 있지만 복잡성 또한 증가한다.
  • 이렇게 StatefulSet 을 사용해 Singleton 서비스를 구성하면, Headless Service 를 사용해 묶어야한다.:
    • 책의 이 부분이 이해하기 어려운데, 참고자료 - 조대협의 블로그 를 읽어보면 이해가 쉽다.
    • 간략하게 요약하면, statfuleset 으로 만들어진 pod 같은 경우, 굳이 service를 통해서 접근할 필요가 없다. 하지만 service 가 없다면, pod 는 domain name을 가질수 없어 접근이 어렵다. 따라서 headless service 를 통해 pod를 묶기만 하고 접근은 pod로 한다.

애플리케이션 내부 잠금

  • distributed lock 을 활용하여 pod 가 여러개 뜨더라도 하나의 pod 만 active 상태로 만든다.
  • distributed lock 을 위하여 zookeeper, redis, etcd 등 이러한 내용이 구현되어 있는 프로그램 또는 프레임 워크가 필요하다.
  • k8s 에서는 master node 의 etcd 를 kubernetes api 를 통해서 노출하고 사용하는 편이 좋은 선택이다.:
    • 또한 이렇게 하는 것이 아닌 configmap 이 동시에 하나의 pod만 수정 가능하다는 것을 이용하여 분산락을 대체해서 사용하는 방법도 있다.

PodDisruptionBudget

  • 일정 비율의 파드가 임의의 한 시점에 노드에서 자발적으로 축출되지 않게 보장한다.
  • 관련해서 책에서는 v1beta1 이지만 kubernetes v1.24 기준, v1 버전을 지원한다.
apiVersion: policy/v1
kind: PodDistruptionBudget
metadata:
  name: random-generator-pdb
spec:
  selector:
    matchLabels:
      app: random-generator
  minAvailable: 2
  • .spec.minAvailable, spec.maxUnavilable 중에 하나만 사용가능하다.

11장 스테이트풀 서비스

  • [[Twelve-Factor-App]]

  • Stateful 한 자원 : Storage, Networking, Identifier

  • 기본 예제에 꽤나 직관적으로 특징을 알아볼수 있어서 기재

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: rg
spec:
  serviceName: random-generator
  replicas: 2
  selector:
    matchLabels:
      app: random-generator
  template:
    metadata:
      labels:
        app: random-generator
    spec:
      containers:
      - image: k8spatterns/random-generator:1.0
        name: random-generator
        ports:
        - containerPort: 8080
          name: http
        volumeMounts:
        - name: logs
          mountPath: /logs
  volumeClaimTemplates:
  - metadata:
      name: logs
    spec:
      accessModes: [ "ReadWriteOnce" ]
      resources:
        requests:
          storage: 10Mi
  • Scale 이 증가할 때는 pvc 가 자동생성, Scale이 감소할 때는 pvc 가 삭제되지 않는다. (데이터 보존을 위해)
    • 만약 PV 재사용을 원한다면 직접 pvc 삭제

네트워크

  • Headless Service 로 관리:
    • DNS 생성을 위해서
    • 단순히 묶기위한 객체

순서성

  • Pod 생성 순서가 Scale에 의해서 생긴 순서를 보장한다.
  • 내려갈때도 그 순서가 보장된다.

개인적인 궁금점

기타 기능

  • 분할 업데이트
  • 병렬 배포
  • at-most-one 보장

12장 서비스 디스커버리

  • proxy 레이어를 둬서 application이 간접적으로 service registry 를 참조하는 구조

내부 디스커버리

  • Service 객체를 사용하는 방법:
    • 환경 변수를 통한 방법:
      • 환경변수를 참조하도록 어플리케이션 개발, 환경변수 주입
    • DNS 참조를 통한 디스커버리
    • 다중 포트
    • 세션 어피니티
    • 레디니스 점검
    • 가상 IP:
    • ClusterIP 선택:
      • .spec.clusterIP를 사용

수동 서비스 디스커버리

  • Endpoint를 직접 만든다.
  • ExternalName을 사용하는 Service

클러스터 외부의 서비스 디스커버리

  • 외부에 서비스를 노출하는 방법:
    • nodePort 등으로 외부에 서비스를 노출, 이를 외부 서비스 디스커버리로 참조
    • LoadBalancer를 사용
    • Headless service 이용

어플리케이션 계층 서비스 디스커버리

  • ingress를 활용하여 만든다.

개인생각

  • 이 책을 쓰는 시점에는 Istio가 서비스디스커버리의 메타가 아니라서 이런 여러 방법을 소개함에도 소개가 되지 않은 것 같다.
  • 물론 어떤 관점에서 본다면 ingress의 일종이라고 여길수 있겠지만, istio 는 envoy를 활용하여 더 많은 메커니즘이 있다.
  • 서비스 디스커버리에 대해서는 istio를 추가로 공부하자.

13장 자기 인식

apiVersion: v1
kind: Pod
metadata:
  name: kubernetes-downwardapi-volume-example
  labels:
    zone: us-est-coast
    cluster: test-cluster1
    rack: rack-22
  annotations:
    build: two
    builder: john-doe
spec:
  containers:
    - name: client-container
      image: k8s.gcr.io/busybox
      command: ["sh", "-c"]
      args:
      - while true; do
          if [[ -e /etc/podinfo/labels ]]; then
            echo -en '\n\n'; cat /etc/podinfo/labels; fi;
          if [[ -e /etc/podinfo/annotations ]]; then
            echo -en '\n\n'; cat /etc/podinfo/annotations; fi;
          sleep 5;
        done;
      volumeMounts:
        - name: podinfo
          mountPath: /etc/podinfo
  volumes:
    - name: podinfo
      downwardAPI:
        items:
          - path: "labels"
            fieldRef:
              fieldPath: metadata.labels
          - path: "annotations"
            fieldRef:
              fieldPath: metadata.annotations

3부 구조 패턴

14장 초기화 컨테이너

  • 초기화 컨테이너가 실패하면, 전체 파드는 다시 시작되고, 모든 초기화 컨테이너도 다시 실행된다
  • 초기화 컨테이너 이외의 초기화 기법:
    • admission controller
    • admission webhook
    • initializer
    • PodPreset

15장 사이드카

  • 일반적으로 서비스의 네트워킹, 모니터링, 트레이싱에 쓰인다.
  • 관점지향 프로그래밍과 유사

16장 어댑터

  • application 이 쓰는 log의 형태가 모니터링할때 원하는 형태와 다를때 사용할 수 있다.
  • 일종의 사이드카

17장 앰배서더(Ambassador)

  • application 에서 외부에 접근할때, 외부 복잡성을 숨기고 간단하게 접근하도록 할수 있다.
  • cache, circuit-breaker 등에 활용 될 수 있다.
  • 일종의 사이드카

4부 설정 패턴

18장 EnvVar 설정

  • 한눈에 여러개 설정을 볼수 있어서 yaml을 기재
apiVersion: v1
kind: Pod
metadata:
  name: random-generator
spec:
  containers:
  - image: k8spatterns/random-generator:1.0
    name: random-generator
    env:
    - name: LOG_FILE
      value: /tmp/random.log
    - name: PATTERN
      valueFrom:
        configMapKeyRef:
          name: random-generator-config
          key: pattern
    - name: SEED
      valueFrom:
        secretKeyRef:
          name: random-generator-secret
          key: seed
  • 시작하고나서는 변수를 변경할수 없어, 변경을 원할경우 재시작을 해야한다.:
    • port, db connection configuration 등에 적합

19장 설정 자원

  • volume 으로 mount 하면 변경이 반영된다.
  • Secret 의 특징:
    • 자신에게 접근하는 파드가 실행 중인 노드에만 배포된다.
    • 노드에서 시크릿은 tmpfs의 메모리에 저장되며, 실제 스토리지에는 기록되지 않고 파드가 제거될 때 함께 제거된다.
    • etcd에 암호화된 형태로 저장된다.
  • configmap 과 secret 에는 자원 제약이 있으므로 무분별하게 사용해서는 안된다.

20장 불변 설정

  • 불변 설정 패턴에 데이터 컨테이너를 사용하는 것은 다소 복잡하지만 아래 장점이 있다.:
    • 환경별 설정은 컨테이너 안에 있으므로, 여타 컨테이너 이미지처럼 버전을 지정할 수 있다.
    • 이런 방식으로 생성된 설정은 컨테이너 레지스트리를 통해 배포될 수 있고, 클러스터에 접근하지 않아도 설정을 확인할 수 있다.
    • 컨테이너 이미지 안에 이쓴 설정을 직접 변경할 수는 없다. 설정을 변경하려면 버전을 업데이트한 새로운 컨테이너 이미지가 필요하다.
    • 설정 데이터 이미지는 설정 데이터가 너무 복잡해 환경 변수나 컨피그맵에 넣을 수 없을 때 유용하다. 임의의 대규모 설정 데이터를 수용할 수 있기 때문이다.
  • 단점:
    • 레지시트리를 통해 추가 컨테이너 이미지를 빌드하고 배포해야 하므로, 복잡성이 더 높다.
    • 민감한 설정 데이터를 처리하는 보안 문제에는 아무런 대책이 없다.
    • 쿠버네티스의 경우 별도의 초기화 컨테이너 처리가 필요하므로, 환경에 따라 다른 디플로이먼트 객체를 관리해야 한다.

21장 설정 템플릿

  • 어플리케이션이 시작되기 전에 설정 파일을 세팅하는 방법:
    • 템플릿 처리기를 ENTRYPOINT의 일부로 Dockerfile에 추가해서, 탬플릿 처리를 컨테이너 이미지에 포함시킬 수 있다.
    • 쿠버네티스의 경우 템플릿 처리기가 실행되고 파드의 어플리케이션 컨테이너에 대한 설정을 만드는 초기화 컨테이너를 사용할수 있다.
  • 모든 내용을 다 볼 필요는 없고, 아래 yaml 만 읽어도 대충은 어떻게 설정할지 보여서 yaml만 기재
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  labels:
    example: cm-template
  name: widfly-cm-template
spec:
  replicas: 1
  template:
    metadata:
      labels:
        example: cm-template
    spec:
      initContainers:
      - image: k8spatterns/example-config-cm-template-init
        name: init
        volumeMounts:
        - mountPath: "/params"
          name: wildfly-parameters
        - mountPath: "/out"
          name: widfly-config
      containers:
      - image: jboss/wildfly:10.1.0.Final
        name: server
        command:
        - "/opt/jboss/wildfly/bin/standalone.sh"
        - "-Djboss.server.config.dir=/config"
        ports:
        - containerPort: 8080
          name: http
          protocol: TCP
        volumeMounts:
        - mountPath: "/config"
          name: wildfly-config
        volumes:
        - name: wildfly-parameters
          configMap:
            name: wildfly-parameters
        - name: wildfly-config
          emptyDir: {}

5부 고급 패턴

22장 컨트롤러

  • reconciliation 과정:

    • observe : 관측하고 있는 자원이 변경될 때 쿠버네티스가 배포하는 이벤트를 watch 하여 actual state를 찾는다.
    • analyze : 실제 상태와 요청한 상태의 차이를 알아낸다.
    • act : 실제 상태가 요청한 상태로 구동되도록 작업을 수행한다.
  • reconciliation components:

    • controller : 표준 쿠버네티스 자원을 모니터링하고 작동하는 간단한 reconciliation process.
    • operator: CRD와 연동.
  • 컨트롤러는 Singletone Service 로 동작하여 동시성 문제를 방지한다.

  • controller 데이터를 저장할수 있는 위치:

    • label:
      • 자원 메타데이터의 일부인 label은 모든 컨트롤러에서 watch할 수 있으며, backend database 에서 indexing 되어 효율적인 쿼리검색이 가능하다.
      • selector 를 사용하기 위해서는 반드시 label을 사용해야한다.
      • label은 허용된 구문과 문자 집합이 따로 있다.
    • annotation:
      • label을 대체할 자원
      • 색인되지 않는다.
    • configmap:
      • configmap 보다는 CRD가 더 권장되지만, CRD는 클러스터 권한이 더 높게 요구된다.
  • 책에는 추가적인 다른 내용도 있긴하지만, deprecated 된 내용도 있어서 이정도만 알면 될것 같다.

23장 오퍼레이터

  • CRD 에는 특별한 두가지 자원이 존재한다.:

    • scale: 이 속성을 사용하면 CRD 에서 replica 수를 관리하는 방법을 지정할 수 있다. HorizontalPodAutoscaler를 사용한다면 필수로 지정되어야한다.
    • status: 외부에서 상태를 업데이트 할 수 있다.
  • 컨트롤러와 오퍼레이터 분류:

    • 설치 CRD:
      • 쿠버네티스 플랫폼에서 애플리케이션을 설치하고 운영하는 데 사용된다. 일반적인 예로 프로메테우스 자체를 설치하고 관리하는 프로메테우스 CRD가 있다.
    • 어플리케이션 CRD:
      • 어플리케이션별 도메인 컨셉을 나타낼때 사용한다.
  • 오퍼레이터 개발과 배포에 도움되는 프로젝트들:

    • CoreOS Operator Framework
    • Kubebuilder
    • Metacontroller

24장 탄력적스케일

  • HPA 관련
kubectl autoscale deployment <deployment name> --cpu-percent=50 --min=1 --max=5
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: random-generator
  spec:
    minReplicas: 1
    maxReplicas: 5
    scaleTargetRef:
      apiVersion: apps/v1
      kind: Deployment
      name: random-generator
    metrics:
    - resource:
        name: cpu
        target:
          averageUtilization: 50
          type: Utilization
      type: Resource
  • metric types:

    • standard metrics:
      • .spec.metrics.resource[:].type 으로 선언되며 CPU, Memory 등 자원 사용량 메트릭을 나타낸다.
    • user defined metrics:
      • .spec.metrics.resource[:].type 으로 선언되며 클러스터별로 각기 다른 클러스터링 모니터링 설정이 필요하다.
      • prometheus, datadog, azure 등등 에서 널리 사용되고 있다.
    • 외부 메트릭:
      • 메시지 큐와 같이 외부 서비스에 존재하는 지표를 사용하고 싶을때 사용
  • HPA 가 해주는 것들:

    • 메트릭 선택
    • 쓰래싱(thrashing) 방지
    • 지연된 반응

수직 Pod Autoscaling

  • Veritcal Pod Autoscaler (VPA)
  • 좀 찾아보니까 기본으로 제공되는 건 아닌것 같다. 공식 사이트:
    • 이것저것 민감한 이슈들이 많아서 아직까지 beta 상태이다. 글을 쓰는 이 시점에도 19시간 전에 커밋된게 있는 걸로 보아 아직까지 개발중인 것 같다.
  • 책이랑 좀 다르니 공식 사이트를 따르자.
apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
  name: my-app-vpa
spec:
  targetRef:
    apiVersion: "apps/v1"
    kind:       Deployment
    name:       my-app
  updatePolicy:
    updateMode: "Auto"

25장 이미지 빌더

  • 읽어보니까, 예전에 봤던 면접이 이걸 하라고 했던 것 같다.
  • 대충 yaml 만 적어둔다. 자세한건 공식 문서를 참고하자.
apiVersion: v1
kind: BuildConfig
metadata:
  name: runtime
spec:
  source:
    images:
    - from:
        kind: ImageStreamTag
        name: random-generator-build:latest
      paths:
      - sourcePath: /deployments/.
        destinationDir: "."
    dockerfile: |-
      FROM openjdk:8-alpine
      COPY *.jar /
      CMD java -jar /*.jar      
  strategy:
    type: Docker
  output:
    to:
      kind: ImageStreamTag
      name: random-generator:latest
  triggers:
  - imageChange:
      automatic: true
      from:
        kind: ImageStreamTag
        name: random-gnerator-build:latest
    type: ImageChange
  • KNative 도 이를 지원한다고 한다. KNative는 조금더 공부해봐야지 알 것 같다.:
    • 옮긴이의 말로는 중단되고, Tekton Pipelines 으로 대체되었다고 한다. 이것도 한번 찾아봐야지 알것 같다.

다읽은 후기

  • 책을 정리하면서 읽고, 최대한 모르는 건 찾아보면서 읽었으나 아직 잘 모르겠는게 많다.
  • 실습을 해보면서 익히는게 좋을 것 같다. 책이 좀 되서, 잘 안되는 예제를 몇개 만나고 나니 예제를 안하고 책 읽고, 공식문서 보고 넘어가는 식으로 공부하니 손에 익지 않았다.
  • 손으로 직접 해보고 싶은건 Builder, Autoscaler, Service Discovery 이다. 이렇게 3개는 다른 공부를 하면서도 접해본적이 없어서 책을 읽으면서도 꼭 나중에 손으로 해봐야겠다고 생각했다.
  • 전체적으로 훑기에 좋았던 것 같다. CKA 자격증 동영상만 볼때는 잘 몰랐던 내용들이 나와서 계속 찾아보면서 읽었고 전체적인 이해도에 도움을 주었다.:
    • 특히 StatefulSet 을 읽었을때, 아 이런식으로 돌리는구나 싶었다.
  • 단점은 책이 좀 나온지 돼서, version issue나 deprecated 된 프로젝트가 있었다는 것 정도이다.