無知

갈 길이 먼 공부 일기

기술 공부/쿠버네티스

쿠버네티스 (17) | 모범 사례 탐구

moozii 2022. 3. 31. 19:12
앞으로의 스터디 내용은 <Kubernetes in Action>을 기반으로 진행합니다.
자세한 내용은, 해당 책을 확인해주세요! 
http://www.yes24.com/Product/Goods/89607047 

 

 

실제 애플리케이션 구성

https://livebook.manning.com/book/kubernetes-in-action/chapter-17/11

 

  • 개발자의 애플리케이션 메니페스트
    • 디플로이먼트
      • 파드 템플릿
        • 컨테이너 정의 : 
          라이브니스 프로브, 레디니스 프로브 / 환경변수 설정 / 마운트할 볼륨 명세 / 리소스 요청량 제한량 지정
        • 레이블과 어노테이션으로 추가 메타데이터 제공 가능
        • 클러스터 관리자가 생성한 시크릿을 imagePullSecret으로 프라이빗 레지스트리에서 이미지 참조

      • 볼륨 :
        환경변수 초기화나 컨피그맵 볼륨으로 마운트되는 컨피그맵이 존재
        퍼시스턴트볼륨 클레임을 작성 (관리자 생성 스토리지클래스 참조 가능)

      • 오토스케일링 : 디플로이먼트를 바라보는 수평 파드 오토스케일러를 시스템에 추가

    • 외부 노출용 인그레스 및 서비스 (로드밸런서 혹은 노드포트)
    • 스테이트풀셋 / 잡 / 크론잡
    • 데몬셋 : 디플로이먼트 범위 바깥, 시스템 운영자의 시스템 서비스 실행 목적 생성

  • 클러스터 관리자의 생성 리소스
    • 서비스 어카운트 / 스토리지 클래스
    • 리소스 사용량 조절 목적 리소스 : limitRange, 리소스쿼터
    • 시크릿 : 개별 파드에 할당된 서비스어카운트에 일반적으로 시크릿을 직접 할당
      1. 프라이빗 이미지 레지스트리에서 컨테이너 이미지를 가져오는 데에 사용하는 시크릿
      2. 파드 내 실행 프로세스에서 직접 참고하는 시크릿
  • 런타임에 자동 생성되는 리소스
    • 퍼시스턴트 볼륨 : 동적 프로비저닝으로 생성 가능
    • 레플리카셋 : 디플로이먼트 컨트롤러가 생성해 파드 템플릿 기반으로 파드를 생성
    • 엔드포인트 : 엔드포인트 컨트롤러가 생성해 서비스와 연결
    • 레이블셀렉터와 레이블

 

 

 

 

 

파드 라이프사이클

1. 파드와 가상 머신의 차이점

1.1. 스케일 다운 요청이 있으면 파드는 반드시 다른 노드로 재배치되어야 하므로 애플리케이션은 항상 종료 가능하다

1.2. 애플리케이션 배포 담당자는 애플리케이션 간 의존성을 알지만, 파드의 경우 자동 배포되므로 의존성 고려가 어려움

 

[파드의 수명]

개별 애플리케이션 컨테이너와 마찬가지로, 파드는 비교적 임시(계속 이어지는 것이 아닌) 엔티티로 간주된다. 파드가 생성되고, 고유 ID(UID)가 할당되고, 종료(재시작 정책에 따라) 또는 삭제될 때까지 남아있는 노드에 스케줄된다. 만약 노드가 종료되면, 해당 노드에 스케줄된 파드는 타임아웃 기간 후에 삭제되도록 스케줄된다. 파드는 자체적으로 자가 치유되지 않는다. 파드가 노드에 스케줄된 후에 해당 노드가 실패하면, 파드는 삭제된다. 마찬가지로, 파드는 리소스 부족 또는 노드 유지 관리 작업으로 인한 축출에서 살아남지 못한다. 쿠버네티스는 컨트롤러라 부르는 하이-레벨 추상화를 사용하여 상대적으로 일회용인 파드 인스턴스를 관리하는 작업을 처리한다. UID로 정의된 특정 파드는 다른 노드로 절대 "다시 스케줄"되지 않는다. 대신, 해당 파드는 사용자가 원한다면 이름은 같지만, UID가 다른, 거의 동일한 새 파드로 대체될 수 있다. 볼륨과 같은 어떤 것이 파드와 동일한 수명을 갖는다는 것은, 특정 파드(정확한 UID 포함)가 존재하는 한 그것이 존재함을 의미한다. 어떤 이유로든 해당 파드가 삭제되고, 동일한 대체 파드가 생성되더라도, 관련된 그것(이 예에서는 볼륨)도 폐기되고 새로 생성된다.

https://kubernetes.io/ko/docs/concepts/workloads/pods/pod-lifecycle/ 
 

파드 라이프사이클

이 페이지에서는 파드의 라이프사이클을 설명한다. 파드는 정의된 라이프사이클을 따른다. Pending 단계에서 시작해서, 기본 컨테이너 중 적어도 하나 이상이 OK로 시작하면 Running 단계를 통과하

kubernetes.io

 

 

 

2. 애플리케이션 종료 후 파드 재배치 과정

2.1. 파드 종료 후 다른 노드에서 새로운 파드 인스턴스가 재시작

2.2. 새로운 IP 주소 및 새로운 이름, 새로운 호스트 이름을 부여

2.2.1. 스테이트풀 애플리케이션의 경우 스테이트풀셋을 활용, 동일 호스트네임 및 동일 퍼시스턴트 상태를 유지 (IP만 변경)

 

 

2.3. 애플리케이션의 디스크 기록 데이터 상실

2.3.1. 퍼시스턴트 스토리지를 애플리케이션 기록 디스크에 마운트할 경우 데이터 유지

2.3.2. 애플리케이션 캐시의 경우 컨테이너 파일 시스템에 기록되므로 종료 후 다른 파드가 생성되면서 상실

2.3.3. 프로세스 크래시, 라이브니스 프로브 실패, OOM Killed 등 컨테이너 종료 시 데이터 손실 방지를 위한 파드 범위 볼륨 사용 권고

2.3.4. 데이터 손상 시 프로세스 크래시 반복으로 CrashLoopBackOff 상태에 도달하는 연속 크래시 루프 발생 시 볼륨 사용이 역효과를 발생시킬 수 있음에 유의. 

 

 

2.4. 파드 리스케줄링

2.4.1. 파드 컨테이너 크래시 지속 시 Kubelet 파드 재시작 

2.4.1.1. 재시작 간격은 10초에서 300초로 지속적으로 간격이 증가

2.4.2. 파드 컨테이너의 크래시는 파드의 종료 혹은 일부 종료를 의미

 

2.4.3. 레플리카셋 아래의 파드도 프로세스 크래시된 파드가 자동으로 제거 후 리스케줄링되지 않음

2.4.3.1. 레플리카셋 컨트롤러는 파드가 죽은 상태인지 상관하지 않고 존재하는 파드 수와 희망 레플리카 수의 일치만 상관

 

2.4.5. 파드 재시작 시 파드의 순서를 지정하는 방법은 없다. 즉, 파드간 의존성 처리가 어렵다.

2.4.5.1. 매니페스트 오브젝트 상의 나열 순서대로 API 서버가 처리하지만 이는 ETCD 기록 순서에 불과하기 때문.

2.4.5.2. 초기화 컨테이너를 파드에 포함시키면 전제 조건 충족 이전까지 파드 주 컨테이너 시작을 막을 수 있음

 

2.4.5.2.1. 초기화 컨테이너의 이해

2.4.5.2.1.1. 초기화 컨테이너는 파드를 초기화하는 데에 사용. 주 파드의 볼륨에 데이터를 기록한 뒤 다음 주 컨테이너에 마운트.

2.4.5.2.1.2. 파드는 여러 개의 초기화 컨테이너를 보유 가능. 

2.4.5.2.1.3. 초기화 컨테이너는 순차적으로 실행되어, 마지막 초기화 컨테이너 이후에 파드의 주 컨테이너가 시작되므로 파드 주 컨테이너의 시작을 지연하는 기능을 수행할 수 있음.

2.4.5.2.1.4. 주 컨테이너 시작 시 초기화 컨테이너는 종료. 사전 작업인 서비스 요청 응답 여부 확인 용도로 사용 가능. 

[초기화 컨테이너]

초기화 컨테이너는 파드의 앱 컨테이너들이 실행되기 전에 실행되는 특수한 컨테이너이며, 앱 이미지에는 없는 유틸리티 또는 설정 스크립트 등을 포함할 수 있다. 초기화 컨테이너는 containers 배열(앱 컨테이너를 기술하는)과 나란히 파드 스펙에 명시할 수 있다.

초기화 컨테이너 이해하기
파드는 앱들을 실행하는 다수의 컨테이너를 포함할 수 있고, 또한 앱 컨테이너 실행 전에 동작되는 하나 이상의 초기화 컨테이너도 포함할 수 있다. 다음의 경우를 제외하면, 초기화 컨테이너는 일반적인 컨테이너와 매우 유사하다.
1. 초기화 컨테이너는 항상 완료를 목표로 실행된다.
2. 각 초기화 컨테이너는 다음 초기화 컨테이너가 시작되기 전에 성공적으로 완료되어야 한다.
만약 파드의 초기화 컨테이너가 실패하면, kubelet은 초기화 컨테이너가 성공할 때까지 반복적으로 재시작한다. 그러나, 만약 파드의 restartPolicy 를 절대 하지 않음(Never)으로 설정하고, 해당 파드를 시작하는 동안 초기화 컨테이너가 실패하면, 쿠버네티스는 전체 파드를 실패한 것으로 처리한다. 컨테이너를 초기화 컨테이너로 지정하기 위해서는, 파드 스펙에 initContainers 필드를 container 항목(앱 container 필드 및 내용과 유사한)들의 배열로서 추가한다. 컨테이너에 대한 더 상세한 사항은 API 레퍼런스를 참고한다. 초기화 컨테이너의 상태는 컨테이너 상태의 배열(.status.containerStatuses 필드와 유사)로 .status.initContainerStatuses 필드에 반환된다.

https://kubernetes.io/ko/docs/concepts/workloads/pods/init-containers/
 

초기화 컨테이너

이 페이지는 초기화 컨테이너에 대한 개요를 제공한다. 초기화 컨테이너는 파드의 앱 컨테이너들이 실행되기 전에 실행되는 특수한 컨테이너이며, 앱 이미지에는 없는 유틸리티 또는 설정 스크

kubernetes.io

$ cat fortune-client.yaml
...
spec:
  initContainers:
  - name: init
    image: busybox
    command:
    - sh
    - -c
    - 'while true; do echo "Waiting for fortune service to come up..."; wget http://fortune -q -T 1 -O /dev/null >/dev/null 2>/dev/null && break; sleep 1; done; echo "Service is up! Starting main container."'
  containers:
  - image: busybox
    name: main
    command:
    - sh
    - -c
    - 'echo "Main container started. Reading fortune very 10 seconds."; while true; do echo "-------------"; wget -q -O - http://fortune; sleep 10; done'

 

2.4.5.3. 파드 간 의존성 처리 방법 정리

2.4.5.3.1. 초기화 컨테이너를 사용해 주 컨테이너 시작을 지연시켜 전제 조건 및 의존성 충족 대기

2.4.5.3.2. 애플리케이션 시작 전 의존성이 필요하지 않도록 애플리케이션을 설계

2.4.5.3.3. 의존성이 준비되지 않았을 가능성을 내부적으로 처리하기 위해 레디니스 프로브를 활용

 

 

 

3. 라이프사이클 훅

3.1. 라이프사이클 훅 개념

3.1.1. 기능 : 컨테이너 별로 시작 시 / 중지 시에 실행되는 리소스로, 프로브와 유사하게 기능을 수행

3.1.1.1. 기능 1 : 컨테이너 내부에서 명령을 실행

3.1.1.2. 기능 2 : URL로 HTTP GET 요청을 수행

3.1.2. 애플리케이션을 수정하지 않고 추가 명령을 수행할 수 있다는 장점을 보유

 

3.2. 시작 후 훅, post-start hook

3.2.1. 시점 : 컨테이너 주 프로세스 시작 직후 실행

3.2.1.1. 주 프로세스와 병렬로 실행되므로 주 프로세스의 완전한 시작을 대기하지 않는 비동기 실행

3.2.1.1.1. 비동기 실행임에도 훅 완료시까지 컨테이너는 ContainerCreating 상태로 대기, 파드는 Pending

3.2.1.1.2. 훅 실행 실패 혹은 0이 아닌 종료 코드 반환 시 주 컨테이너 종료

3.2.2. 기능 : 애플리케이션이 시작 시 추가 작업을 수행하는 데에 사용

3.2.2.1. 예시 1 : 애플리케이션이 시작되고 있는 외부 리스너에 시그널을 발송

3.2.2.2. 예시 2 : 애플리케이션 초기화 작업

3.2.3. 디버깅이 어려운 이유 : 훅에 의해 시작된 프로세스는 표준 출력 기록 시 기록 확인 불가

3.2.3.1. 디버깅 : 훅 실패 시 파드 이벤트 상 FailedPostStartHook 경고 표시

$ cat post-start-hook.yaml
...
spec:
  containers:
  - image: luksa/kubia
    name: kubia
    lifecycle:
      postStart:
        exec:
          command:
          - sh
          - -c
          - "echo 'hook will fail with exit code 15'; sleep 5 ; exit 15"

 

3.3. 종료 전 훅, pre-stop hook

https://livebook.manning.com/book/kubernetes-in-action/chapter-17/109

3.3.1. 시점 : 컨테이너 종료 직전 실행

3.3.1.1. 컨테이너 종료 필요 > kubelet의 종료 전 훅 실행 > SIGTERM 전송 > 프로세스 종료

3.3.1.1.1. SIGTERM 전송으로도 프로세스 정상 종료되지 않을 시 종료 전 훅으로 컨테이너 정상 종료 가능

 

3.3.1.1.1.1. 애플리케이션이 SIGTERM 신호를 수신하지 못하는 문제

3.3.1.1.1.1.1. 잘못된 해결책 : SIGTERM 전송 용도로만 종료 전 훅을 정의하는 실수

3.3.1.1.1.1.1.1. 잘못된 이유 : 애플리케이션의 신호 미수신은 신호 미발송이 아닌 프로세스의 수신 문제로 셸 내 프로세스 실행으로 인한 셸의 신호 차단 케이스일 확률이 있음.

3.3.1.1.1.1.2. 올바른 해결책 : 셸이 신호를 프로세스에 전달하도록 처리하거나, 이미지가 셸 실행 대신 바이너리 직접 실행을 하도록 처리

3.3.1.1.1.1.2.1. 해결책 상세 : Dockerfile ENTRYPOINT /mybinary (X) ENTRYPOINT ["/mybinary"] (O) 

 

3.3.2. 기능 : 애플리케이션이 종료 전 임의의 작업을 수행하는 데에 사용

3.3.3. 특징 : 시작 후 훅과 달리 컨테이너가 훅 결과와 무관히 종료

3.3.3.1. 결과 상세 : 파드 이벤트 FailedPreStopHook 발생하나 파드 삭제로 인지 어려움

 

[컨테이너 라이프사이클 훅(Hook)]

Angular와 같이, 컴포넌트 라이프사이클 훅을 가진 많은 프로그래밍 언어 프레임워크와 유사하게, 쿠버네티스도 컨테이너에 라이프사이클 훅을 제공한다. 훅은 컨테이너가 관리 라이프사이클의 이벤트를 인지하고 상응하는 라이프사이클 훅이 실행될 때 핸들러에 구현된 코드를 실행할 수 있게 한다.

1. PostStart
이 훅은 컨테이너가 생성된 직후에 실행된다. 그러나, 훅이 컨테이너 엔트리포인트에 앞서서 실행된다는 보장은 없다. 파라미터는 핸들러에 전달되지 않는다.

2. PreStop
이 훅은 API 요청이나 활성 프로브(liveness probe) 실패, 선점, 자원 경합 등의 관리 이벤트로 인해 컨테이너가 종료되기 직전에 호출된다. 컨테이너가 이미 terminated 또는 completed 상태인 경우에는 PreStop 훅 요청이 실패하며, 훅은 컨테이너를 중지하기 위한 TERM 신호가 보내지기 이전에 완료되어야 한다. 파드의 그레이스 종료 기간(termination grace period)의 초읽기는 PreStop 훅이 실행되기 전에 시작되어, 핸들러의 결과에 상관없이 컨테이너가 파드의 그레이스 종료 기간 내에 결국 종료되도록 한다. 어떠한 파라미터도 핸들러에게 전달되지 않는다. 

https://kubernetes.io/ko/docs/concepts/containers/container-lifecycle-hooks/ 
 

컨테이너 라이프사이클 훅(Hook)

이 페이지는 kubelet이 관리하는 컨테이너가 관리 라이프사이클 동안의 이벤트에 의해 발동되는 코드를 실행하기 위해서 컨테이너 라이프사이클 훅 프레임워크를 사용하는 방법에 대해서 설명한

kubernetes.io

 

 

 

4. 파드 셧다운

4.1. 파드 셧다운의 단계적 과정

4.1.1. API 서버로 파드 오브젝트를 삭제

4.1.2. API 서버의 HTTP DELETE 요청 수신

4.1.3. API 서버가 오브젝트 내에 deletedTimeStamp 필드만 설정

 

4.1.4. deletedTimeStamp 필드가 설정된 파드가 종료

4.1.4.1. Kubelet이 파드 종료 요청을 확인한다

4.1.4.2. Kubelet의 종료 유예 기간, termination grace period 타이머가 시작된다.

 

4.1.4.2.1. 종료 유예 기간, termination grace period은 파드가 종료되어야 하는 시간 제한이다.

4.1.4.2.1.1. 종료 유예기간은 포스 스펙에서 terminationGracePeriods 필드로 설정한다

4.1.4.2.1.2. 기본값은 30(초)이며, 파드 삭제 시 파라미터로 재정의가 가능하다.

4.1.4.2.1.3. 프로세스가 시간 내 종료되도록 유예 기간을 충분히 설정해야 한다

4.1.4.2.1.4. kubectl delete po {pod_name} --grace-period=0 --force 를 통해 유예기간을 0으로 설정하고 즉시 파드 리소스 삭제를 명령할 수 있다.

4.1.4.2.1.4.1. 즉시 강제 종료 방법의 경우 곧바로 컨트롤러가 교체 파드를 생성하므로 스테이트풀셋 파드의 경우 스테이트풀 클러스터 상 오작동이 발생할 수 있다.

 

4.1.4.3. Kubelet이 파드 내 컨테이너를 종료시킨다

4.1.4.3.1. 종료 전 훅이 구성되었을 경우 실행 후 완료를 대기한다.

4.1.4.3.2. SIGTERM 신호를 컨테이너 주 프로세스로 발송한다.

4.1.4.3.3. 컨테이너 완전 종료 시 혹은 종료 유예기간 종료 시까지 대기한다.

4.1.4.3.4. 컨테이너가 종료되지 않은 비정상 상태의 경우 SIGKILL을 통해 프로세스를 강제로 종료한다.

4.1.4.3.5. 파드 내 모든 컨테이너가 중지되면 kubelet이 API 서버에 해당 사실을 알린다

 

4.1.4.4. 파드 리소스가 삭제된다.

 

[파드의 종료]

파드는 클러스터의 노드에서 실행되는 프로세스를 나타내므로, 해당 프로세스가 더 이상 필요하지 않을 때 정상적으로 종료되도록 하는 것이 중요하다(KILL 시그널로 갑자기 중지되고 정리할 기회가 없는 것 보다). 디자인 목표는 삭제를 요청하고 프로세스가 종료되는 시기를 알 수 있을 뿐만 아니라, 삭제가 결국 완료되도록 하는 것이다. 사용자가 파드의 삭제를 요청하면, 클러스터는 파드가 강제로 종료되기 전에 의도한 유예 기간을 기록하고 추적한다. 강제 종료 추적이 적용되면, kubelet은 정상 종료를 시도한다. 일반적으로, 컨테이너 런타임은 각 컨테이너의 기본 프로세스에 TERM 신호를 전송한다. 많은 컨테이너 런타임은 컨테이너 이미지에 정의된 STOPSIGNAL 값을 존중하며 TERM 대신 이 값을 보낸다. 일단 유예 기간이 만료되면, KILL 시그널이 나머지 프로세스로 전송되고, 그런 다음 파드는 API 서버로부터 삭제된다. 프로세스가 종료될 때까지 기다리는 동안 kubelet 또는 컨테이너 런타임의 관리 서비스가 다시 시작되면, 클러스터는 전체 원래 유예 기간을 포함하여 처음부터 다시 시도한다.

플로우의 예는 다음과 같다.
1. 이 kubectl 도구를 사용하여 기본 유예 기간(30초)으로 특정 파드를 수동으로 삭제한다.

2. API 서버의 파드는 유예 기간과 함께 파드가 "dead"로 간주되는 시간으로 업데이트된다. kubectl describe 를 사용하여 삭제하려는 파드를 확인하면, 해당 파드가 "Terminating"으로 표시된다. 파드가 실행 중인 노드에서, kubelet이 파드가 종료된 것(terminating)으로 표시되었음을 확인하는 즉시(정상적인 종료 기간이 설정됨), kubelet은 로컬 파드의 종료 프로세스를 시작한다.

2.1. 파드의 컨테이너 중 하나가 preStop 훅을 정의한 경우, kubelet은 컨테이너 내부에서 해당 훅을 실행한다. 유예 기간이 만료된 후 preStop 훅이 계속 실행되면, kubelet은 2초의 작은 일회성 유예 기간 연장을 요청한다. 참고: preStop 훅을 완료하는 데 기본 유예 기간이 허용하는 것보다 오랜 시간이 필요한 경우, 이에 맞게 terminationGracePeriodSeconds 를 수정해야 한다.

2.2. kubelet은 컨테이너 런타임을 트리거하여 각 컨테이너 내부의 프로세스 1에 TERM 시그널을 보낸다. 참고: 파드의 컨테이너는 서로 다른 시간에 임의의 순서로 TERM 시그널을 수신한다. 종료 순서가 중요한 경우, preStop 훅을 사용하여 동기화하는 것이 좋다.

3. kubelet이 정상 종료를 시작하는 동시에, 컨트롤 플레인은 구성된 셀렉터가 있는 서비스를 나타내는 엔드포인트(Endpoint)(그리고, 활성화된 경우, 엔드포인트슬라이스(EndpointSlice)) 오브젝트에서 종료된 파드를 제거한다. 레플리카셋(ReplicaSet)과 기타 워크로드 리소스는 더 이상 종료된 파드를 유효한 서비스 내 복제본으로 취급하지 않는다. 로드 밸런서(서비스 프록시와 같은)가 종료 유예 기간이 시작되는 즉시 엔드포인트 목록에서 파드를 제거하므로 느리게 종료되는 파드는 트래픽을 계속 제공할 수 없다.

4. 유예 기간이 만료되면, kubelet은 강제 종료를 트리거한다. 컨테이너 런타임은 SIGKILL 을 파드의 모든 컨테이너에서 여전히 실행 중인 모든 프로세스로 전송한다. kubelet은 해당 컨테이너 런타임이 하나를 사용하는 경우 숨겨진 pause 컨테이너도 정리한다.

5. kubelet은 유예 기간을 0(즉시 삭제)으로 설정하여, API 서버에서 파드 오브젝트의 강제 삭제를 트리거한다.

6. API 서버가 파드의 API 오브젝트를 삭제하면, 더 이상 클라이언트에서 볼 수 없다.

https://kubernetes.io/ko/docs/concepts/workloads/pods/pod-lifecycle/#pod-termination 
 

파드 라이프사이클

이 페이지에서는 파드의 라이프사이클을 설명한다. 파드는 정의된 라이프사이클을 따른다. Pending 단계에서 시작해서, 기본 컨테이너 중 적어도 하나 이상이 OK로 시작하면 Running 단계를 통과하

kubernetes.io

 

 

 

5. 셧다운 핸들러

5.1. 애플리케이션 종료 시간이 예측되는 경우

5.1.1. 애플리케이션이 SIGTERM 신호에 대응해 셧다운 절차 진행 후 종료

5.1.2. SIGTERM 신호 처리 대신 종료 전 훅으로 애플리케이션 종료

 

5.2. 애플리케이션 종료 시간이 예측되지 않는 경우

5.2.1. 파드가 종료 시 데이터 마이그레이션이 필요한 경우

5.2.1.1. 파드 종료 신호 수신 후 데이터 마이그레이션 시작을 권장하지 않는 이유

5.2.1.1.1. 컨테이너 종료는 파드 전체 종료를 의미하지 않으므로

5.2.1.1.2. 프로세스 종료 이전 종료 절차 완료 보장이 없으므로

5.2.2. 종료 시간 예측이 어려운 케이스의 우려점

5.2.2.1. 애플리케이션 정상 종료 수행 이전 종료 유예 기간 만료 가능성

5.2.2.2. 컨테이너 셧다운 중간 과정 중 파드 실행 노드의 실패 발생 가능성

 

 

5.3. 셧다운 절차의 완료를 보장하는 방법

5.3.1. 애플리케이션이 종료 신호 수신 시 신규 파드 실행하는 새로운 잡 리소스를 생성

5.3.1.1. 신규 파드의 역할은 삭제 파드 데이터를 다른 파드로 마이그레이션

5.3.1.2. 애플리케이션의 잡 오브젝트 생성 성공 보장이 없고 노드 실패에 대한 방비가 부족함

 

5.3.2. 분산된 데이터의 존재를 확인하는 전용 셧다운 절차 파드의 항시 실행

https://livebook.manning.com/book/kubernetes-in-action/chapter-17/136

5.3.2.1. 전용 파드가 분산 데이터를 찾아 다른 파드로 마이그레이션을 수행

5.3.2.2. 항시 실행 파드가 아닌 크론잡 리소스를 통한 정기적 파드 수행도 가능

 

5.3.2.3. 스테이트풀셋 리소스를 활용하기에는 어려운 이유

5.3.2.3.1. 스케일 다운 시 퍼시스턴트볼륨 내 데이터는 잔류하는 등의 문제가 발생

5.3.2.3.2. 따라서 데이터 마이그레이션 파드를 별도 실행하는 것은 어차피 불변

5.3.2.3.3. 애플리케이션 업그레이드 중 데이터 마이그레이션 발생치 않도록 마이그레이션 수행 이전 스테이트풀셋 파드 재시작 시간 여유를 마련하는 것이 필요

 

 

 

 

 

클라이언트 요청의 처리 보장

1. 파드 시작 시 클라이언트 연결 끊김 방지

1.1. 파드 시작 시 상황 : 클라이언트 파드의 서비스 연결 시도 이후 거의 즉시 요청 수신이 시작됨

1.1.0. 파드는 레디니스 프로브 지정 없을 시 항상 준비되었다고 간주

1.1.1. 파드는 쿠버네티스에 준비가 완료되었다는 신호를 발송

1.1.2. 파드 시작 시 레이블 셀렉터가 레이블이 일치하는 모든 서비스의 엔드포인트에 추가됨

1.1.3. 서비스 엔드포인트가 추가되었으므로 클라이언트 요청을 수신

 

1.2. 방지책 : 요청 수신 준비가 될 때만 레디니스 프로브가 성공 반환하도록 해야

1.2.1. HTTP GET 레디니스 프로브를 추가하고 애플리케이션 기본 URL을 가리키기

 

 

 

2. 파드 셧다운 시 클라이언트 연결 끊김 방지

2.1. 파드 삭제 시 이벤트 순서

https://livebook.manning.com/book/kubernetes-in-action/chapter-17/150
https://livebook.manning.com/book/kubernetes-in-action/chapter-17/153

2.1.1. API 서버가 파드 삭제 요청을 수신

2.1.1.1. API 서버가 ETCD 상태를 수정

2.1.1.2. API 서버가 다음 감시자(kubelet, Endpoint Controller)에게 삭제를 알림

 

2.1.2-A.1. kubelet이 파드 종료 알림 수신 후 컨테이너 셧다운

2.1.2-A.1.1. 종료 전 훅이 구성되었을 경우 실행 후 완료를 대기한다.

2.1.2-A.1.2. SIGTERM 신호를 컨테이너 주 프로세스로 발송한다.

2.1.2-A.1.3. 컨테이너 완전 종료 시 혹은 종료 유예기간 종료 시까지 대기한다.

2.1.2-A.1.4. 컨테이너가 종료되지 않은 비정상 상태의 경우 SIGKILL을 통해 프로세스를 강제로 종료한다.

** 애플리케이션은 이후 서버 소켓을 닫고 클라이언트 요청을 즉시 받지 않으므로 클라이언트는 이후 connection refused 오류가 발생함

 

2.1.2-B.1. 엔드포인트 컨트롤러가 파드 종료 알림 수신 후 파드가 속한 모든 서비스의 엔드포인트에서 삭제 대상 파드를 제거

2.1.2-B.1.1. API 서버에 REST 요청을 보내 엔드포인트 API 오브젝트를 수정

2.1.2-B.1.1.1. API 서버가 엔드포인트 오브젝트를 보고 있는 모든 클라이언트 (워커노드 내 모든 kube-proxy 포함)에 알림 발송

 

2.1.2-B.2. 각 워커노드 내 kube-proxy가 노드 내 iptables 규칙을 업데이트해 종료 예정 파드로의 연결을 차단

 

 

 

2.2. 문제 해결

2.2.1. 후보 ) 모든 kube-proxy가 iptables 규칙을 업데이트할 때까지 종료 신호를 수신했음에도 파드가 연결 수락을 지속

2.2.1.1. 한계 ) 서비스를 거치지 않는 인그레스 컨트롤러 및 로드밸런서 상의 문제 발생 시 해결하지 못함

2.2.2. 채택안 ) 모든 프록시가 작업 완료하도록 충분한 시간을 대기 

2.2.2.1. 우려 ) API 서버 및 엔드포인트 컨트롤러 과부하 가능성 있어 대기 시간 늘어날 우려. 

2.2.2.2. 우려 ) 지연 시간이 너무 길어지면 컨테이너가 즉시 종료되지 않은 채 파드가 삭제되어 목록에 표시되는 혼란의 가능성

 

 

 

 

 

쿠버네티스 내 애플리케이션의 쉬운 실행 및 관리

1. 관리 가능한 컨테이너 이미지 만들기

2. 이미지 태그 지정 및 imagePullPolicy 활용

3. 일차원 레이블 대신 다차원 레이블 활용

4. 어노테이션을 통한 리소스 설명

5. 프로세스 종료 원인 정보 제공

6. 애플리케이션 로깅 처리

 

1. 관리 가능한 컨테이너 이미지 만들기

1.1. 불필요한 것 없는 작은 이미지를 사용

1.1.1. Go 언어 사용을 통해 바이너리 실행파일만 포함하는 이미지를 제작

1.2. 최소한의 이미지는 디버깅에 어려움이 있으므로 최소한의 도구 세트를 추가하는 등 본인만의 작업 방식 확립

 

 

2. 이미지 태그 지정 및 imagePullPolicy 활용

2.1. 레플리카 내 이미지 버전 확인이 어려운 latest 태그 사용에 유의하기 

2.2. 적절한 버전 지정자를 포함하는 태그를 사용하기

 

2.3. 변경 가능한 태그를 사용하는 경우 파드 스펙의 imagePullPolicy를 always로 설정하기

2.3.1. 신규 파드 배포시마다 컨테이너 런타임이 레지스트리 접속 후 이미지를 가져오는 특징 보유

2.3.2. 프로덕션 환경에서는 노드 이미지 수정 확인 과정에서 파드 시작 속도 지연

2.3.3. 레지스트리 연결 불가의 경우 파드가 시작하지 않는 문제 보유

 

Episode from Senior

실제 내가 있는 팀에서도 관련한 문제가 발생한 적이 있다. 이미지를 latest로 배포하는 설정에서 비롯된 문제다. 쿠버네티스는 동일한 이미지 태그를 사용하면, 새로이 배포하기보다 기존에 저장한 캐시를 활용하는데, latest 태그를 사용하면 항상 같다고 간주하고 신규 이미지로 배포되지 않는 문제가 발생한 것이다. 그 해결을 위해 imagePullPolicy를 Always로 우선 바꿔서 배포를 진행했지만, 이럴 경우 매번 이미지를 풀한다는 점에서 프로세스가 둔화되는 단점이 존재한다. 따라서 우리 팀은 다시 이미지 태그 관련 설정을 올바르게 조정하고 Always 정책을 폐기해서, 보다 빠른 배포가 정상적으로 작동하게 했다. 

 

3. 일차원 레이블 대신 다차원 레이블 활용

3.1. 모든 리소스에 레이블을 지정할 것

3.1.1. 각 리소스에 개별 차원에서 레이블을 선택해 관리할 것

3.1.2. 그룹을 통한 리소스 관리 및 리소스 소속 위치 판별에 용이

 

3.2. 레이블 포함 가능 항목

3.2.1. 리소스가 있는 애플리케이션 혹은 마이크로서비스의 이름

3.2.2. 애플리케이션 계층

3.2.3. 환경 (개발인지 QA인지 스테이징인지 프로덕션인지)

3.2.4. 릴리스 유형 (안정, 카나리, 블루그린 등)

3.2.5. 테넌트 (네임스페이스가 아닌 테넌트별 별도 파드 실행 시)

3.2.6. 샤드된 시스템용 샤드

 

 

4. 어노테이션을 통한 리소스 설명

4.1. 리소스 설명 어노테이션 필수

4.2. 리소스 담당자 연락처 정보 포함 어노테이션 필수

4.3. 파드 간 의존성 표시를 위한, 다른 서비스의 이름을 나열하는 어노테이션

4.4. 도구 및 그래픽 유저 인터페이스 내 사용되는 빌드 버전 정보 및 메타데이터 어노테이션

 

 

5. 프로세스 종료 원인 정보 제공

5.1. 로그 파일에 모든 디버그 정보를 포함해 운영의 편의 증대 도모

5.2. 프로세스가 컨테이너 파일 시스템 내 특정 파일에 종료 메시지를 작성하도록 설정

5.2.1. kubelet으로부터 정보를 받아 kubectl describe pod의 출력에 표시

5.2.2. 프로세스 메시지 작성 디폴트 파일인 /dev/termination-log를 파드 스펙 컨테이너 정의에서 terminationMessagePath 필드를 설정해 변경

5.2.3. 크래시 발생 사례가 아니더라도 완료 가능 작업 실행 후 성공적으로 종료할 때에도 활용 가능

$ cat termination-message.yaml
...
spec:
  containers:
  - image: busybox
    name: main
    command:
    - sh
    - -c
    - 'echo "I''ve had enough" > /var/termination-reason ; exit 1'
    terminationMessagePath: /var/termination-reason
[종료 메시지 사용자 정의하기]

쿠버네티스는 컨테이너의 terminationMessagePath 필드에 지정된 종료 메시지 파일에서 종료 메시지를 검색하며, 이 필드의 기본값은 /dev/termination-log 이다. 이 필드를 사용자 정의 함으로써 쿠버네티스가 종료 메시지를 검색할 때 다른 파일을 사용하도록 조정할 수 있다. 쿠버네티스는 지정된 파일의 내용을 사용하여 컨테이너의 성공 및 실패에 대한 상태 메시지를 채운다. 종료 메시지는 assertion failure 메세지처럼 간결한 최종 상태로 생성된다. kubelet은 4096 바이트보다 긴 메시지를 자른다. 모든 컨테이너의 총 메시지 길이는 12KiB로 제한된다. 기본 종료 메시지 경로는 /dev/termination-log이다. 파드가 시작된 후에는 종료 메시지 경로를 설정할 수 없다.

또한 사용자는 추가적인 사용자 정의를 위해 컨테이너의 terminationMessagePolicy 필드를 설정할 수 있다. 이 필드의 기본 값은 File 이며, 이는 오직 종료 메시지 파일에서만 종료 메시지가 조회되는 것을 의미한다. terminationMessagePolicy 필드의 값을 "FallbackToLogsOnError 으로 설정함으로써, 종료 메시지 파일이 비어 있고 컨테이너가 오류와 함께 종료 되었을 경우 쿠버네티스가 컨테이너 로그 출력의 마지막 청크를 사용하도록 지시할 수 있다. 로그 출력은 2048 바이트나 80 행 중 더 작은 값으로 제한된다.

https://kubernetes.io/ko/docs/tasks/debug-application-cluster/determine-reason-pod-failure/ 
 

파드 실패의 원인 검증하기

이 페이지는 컨테이너 종료 메시지를 읽고 쓰는 방법을 보여준다. 종료 메시지는 컨테이너가 치명적인 이벤트에 대한 정보를, 대시보드나 모니터링 소프트웨어 도구와 같이 쉽게 조회 및 표시

kubernetes.io

 

 

6. 애플리케이션 로깅 처리

6.1. 애플리케이션이 표준 출력에 로그를 작성하는 경우

6.1.1.kubectl logs 명령어로 로그 조회

6.1.1.1. 컨테이너 크래시 이후 컨테이너 교체 시 이전 컨테이너 로그는 kubectl logs --previous로 확인

 

6.2. 애플리케이션이 표준 출력이 아닌 파일에 로깅하는 경우

6.2.1. kubectl exec <pod> cat <logfile>로 조회

 

6.3. kubectl cp 명령어를 통한 로그 파일의 로그시스템으로의 복사

6.3.1. kubectl cp {pod_name}:{log_file_directory} {local_directory} -c {containerName}

 

6.4. 중앙집중식 로깅

6.4.1. 중앙집중식 로깅은 쿠버네티스가 제공하지 않으므로 외부 솔루션을 사용

 

6.4.1. Stackdriver Logging -> Cloud Logging (in GCP)

Cloud Logging is a fully managed service that allows you to store, search, analyze, monitor, and alert on logging data and events from Google Cloud and Amazon Web Services. You can collect logging data from over 150 common application components, on-premises systems, and hybrid cloud systems. Logging includes storage for logs through log buckets, a user interface called the Logs Explorer, and an API to manage logs programmatically. Logging lets you read and write log entries, query your logs, and control how you route and use your logs.

https://cloud.google.com/logging/docs 

 

6.4.3. ELK Stack = Elastic Search + Logstash + Kibana

[ELK 스택이란 무엇입니까?]

ELK 스택은 Elasticsearch, Logstash, Kibana의 세 가지 인기 있는 프로젝트로 구성된 스택을 의미하는 약어입니다. Elasticsearch라고도 불리는 ELK 스택은 사용자에게 모든 시스템과 애플리케이션에서 로그를 집계하고 이를 분석하며 애플리케이션과 인프라 모니터링 시각화를 생성하고, 빠르게 문제를 해결하며 보안 분석할 수 있는 능력을 제공합니다.

E = Elasticsearch
Elasticsearch는 Apache Lucene에 구축되어 배포된 검색 및 분석 엔진입니다. 다양한 언어를 지원하고 고성능에 스키마가 없는 JSON 문서로 Elasticsearch는 다양한 로그 분석과 검색 사용 사례에 최고의 선택이 되었습니다. 2021년 1월 21일, Elastic NV는 소프트웨어 라이선스 전략을 변경하는 바, 퍼미시브 라이선스인 Apache License Version 2.0(ALv2) 라이선스 하에서 Elasticsearch 및 Kibana의 새로운 버전을 더 이상 릴리스하지 않는다고 발표했습니다. 그 대신 새로운 버전의 소프트웨어는 Elastic License 또는 SSPL 아래에서 소스 코드를 사용할 수 있는 Elastic 라이선스 하에서 제공됩니다. 해당 라이선스는 오픈 소스가 아니며 사용자에게 동일한 자유를 제공하지 않습니다. 오픈 소스 커뮤니티와 고객이 계속해서 안전하고 고품질에 완전한 오픈 소스 검색과 분석 제품군을 사용할 수 있도록 AWS는 커뮤니티 주도적이며 오픈 소스 Elasticsearch 및 Kibana의 ALv2 라이선스 갈래인 OpenSearch 프로젝트를 도입했습니다. OpenSearch 제품군은 검색 엔진인 OpenSearch와 시각화 및 사용자 인터페이스인 OpenSearch 대시보드로 구성됩니다.

L = Logstash
Logstash는 다양한 소스로부터 데이터를 수집하고 전환하여 원하는 대상에 전송할 수 있도록 하는 오픈 소스 데이터 수집 도구입니다. 사전 구축된 필터와 200개가 넘은 플러그인에 대한 지원으로 Logstash는 사용자가 데이터 원본이나 유형에 관계없이 데이터를 쉽게 수집할 수 있도록 도와줍니다.

K = Kibana
Kibana는 로그 및 이벤트 검토에 사용하는 데이터 시각화 및 탐색 도구입니다. Kibana는 사용하기 쉽고 대화형 차트와 사전 구축된 집계 및 필터, 지리 공간적 지원을 제공하고 이를 사용해 Elasticsearch에 저장된 데이터를 시각화할 때 원하는 선택을 할 수 있습니다.

ELK 스택은 로그 분석 공간에서 필요를 채워줍니다. 여러분의 IT 인프라가 점점 더 퍼블릭 클라우드로 이동할수록, 해당 인프라와 서버 로그, 애플리케이션 로그, 클릭스트림 프로세스를 모니터링하기 위해 로그 관리와 분석 솔루션이 필요합니다. ELK 스택은 개발자와 DevOps 엔지니어가 오류 진단, 애플리케이션 성능, 인프라 모니터링으로부터 값진 인사이트를 얻을 수 있도록 적은 비용으로 단순하면서도 강력한 로그 분석 솔루션을 제공합니다.

https://aws.amazon.com/ko/opensearch-service/the-elk-stack/ 

 

6.4.4. EFK Stack = Elastic Search + FluentD Logstash + Kibana

https://livebook.manning.com/book/kubernetes-in-action/chapter-17/230

6.4.4.1. 쿠버네티스 클러스터 노드는 각각 플루언트디 에이전트를 데몬셋으로 파드를 배포해 실행

6.4.4.2. 플루언트디 에이전트가 컨테이너에서 로그를 수집 후 파드 정보로 태그를 지정해 전달

6.4.4.3. 일래스틱 서치에 플루언트디 에이전트가 전달한 정보를 영구 저장

6.4.4.4. 일래스틱 서치가 클러스터 내부에 파드로 배포됨

6.4.4.5. 일래스틱 서치 데이터 시각화 목적의 웹 도구 키바나를 통해 웹 브라우저로 로그 조회 및 분석

 

** 플루언트 디 에이전트는 로그 파일 각 줄을 일래스틱서치 저장소 항목으로 저장하므로 여러 줄의 로그는 별도 항목으로 분리되는 문제가 발생. 애플리케이션이 일반 텍스트 대신 JSON 형태로 출력하도록 하여 해결하면, kubectl logs 사용이 불편해진다는 문제가 발생. 따라서 읽기 쉬운 로그를 표준 출력으로 출력하도록 유지하되, JSON 로그를 파일에 써서 플루언트디가 처리하도록 에이전트 구성. 혹은 로깅 사이드카 컨테이너를 각 파드에 추가할 수도 있음.

 

 

https://medium.com/avmconsulting-blog/how-to-deploy-an-efk-stack-to-kubernetes-ebc1b539d063

 

How to Deploy an EFK Stack to Kubernetes

One of the most popular centralized logging solution is the Elasticsearch, Fluentd, and Kibana (EFK) stack.

medium.com

 

 

 

 

 

 

개발 및 테스트 모범 사례

1. 개발 중 쿠버네티스 외부에서 애플리케이션 실행해보기

2. 개발 중 Minikube 사용

3. 버전 관리 및 자동 배포 리소스 관리

4. YAML / JSON 매니페스트 대안으로 Ksonnet 고려

5. CI/CD

 

1. 개발 중 쿠버네티스 외부에서 애플리케이션 실행

애플리케이션 빌드, 이미지 빌드, 레지스트리 푸시, 파드 재배포 등의 과정을 생략하기 위한 로컬 내 개발 및 실행

 

1.1. 백엔드 서비스를 로컬에 연결

1.1.1. 연결 가능 조건

1.1.1.1. 프로덕션 환경 상 애플리케이션이 백엔드 서비스에 연결

1.1.1.2. BACKEND_SERVICE_HOST, BACKEND_SERVICE_PORT를 환경변수로 사용해 서비스 위치를 확인

1.1.2. 서비스를 노드포트나 로드밸런서 유형으로 변경하면 서비스 외부 액세스 허용 가능

 

1.2. API 서버에 연결 : 실행 중 쿠버네티스 API 서버 액세스가 필요한 경우

1.2.1. 서비스 어카운트 토큰을 사용해 자체 인증하는 경우

1.2.1.1. kubectl cp를 통해 서비스어카운트 시크릿 파일을 로컬로 복사해 사용

1.2.2. 앰배서더 컨테이너를 사용해 인증하는 경우

1.2.2.1. 시크릿 파일이 불필요함. 로컬 상 kubectl proxy를 실행해 로컬로 실행.

1.2.2.2. 로컬 kubectl의 사용자 계정이 애플리케이션 실행 서비스어카운트와 동일 권한이어야 가능.

 

1.3. 개발 중 컨테이너 내부에서 실행

1.3.1. 바이너리를 이미지에 굽는 대신 도커 볼륨으로 로컬 파일시스템을 컨테이너에 마운트

1.3.2. 바이너리 새 버전 빌드 후 컨테이너 재시작을 통해 실행 가능 (이미지 리빌드 불필요)

 

 

2. 개발 중 Minikube 사용

2.1. 목적 : 쿠버네티스 내 애플리케이션 시험 시 사용 가능한 절충안

 

2.2. Minikube VM과 로컬 컨테이너에 로컬 파일 마운트

Minikube로 개발 후 클러스터 내 애플리케이션 변경마다 minikube mount로 로컬 파일시스템을 Minikube VM에 마운트한 뒤 hostPath로 컨테이너에 마운트

 

2.3. 로컬 파일을 Minikube VM에 마운트 후 컨테이너에 넣기

Minikube로 개발 후 Minikube VM 내부 도커 데몬을 통해 이미지를 빌드 (이미지를 레지스트리에 넣어 가상머신 데몬으로 가져오기) -> 새 파드가 이미지를 즉시 사용 가능.

** 도커 데몬 사용 위해 DOCKER_HOST 환경변수를 $ eval $(minikube docker-env) 명령어를 통해 지정하면 활용 가능

 

2.4. 로컬에서 이미지를 빌드 후 Minikube VM에 직접 복사
로컬 컴퓨터 내 이미지 빌드 후 $ docker save <image> | (eval $(minikube docker-env) && docker load) 명령어로 이미지를 가상머신에 복사

** 가상머신 내부 데몬 사용 불가 경우에도 활용 가능

 

 

3. 버전 관리 및 자동 배포 리소스 관리

3.1. 버전 관리 시스템에 매니페스트를 저장해 코드 검토 수행 및 변경사항 롤백

3.2. 각 커밋 후 kubectl apply를 통해 벼경 사항을 배포 리소스에 반영

3.3. 주기적으로 버전 관리 시스템에 매니페스트를 체크아웃하는 에이전트를 실행 후 apply 명령어를 통해 간단히 관리

3.4. kube-applier 도구 활용

kube-applier is a service that enables continuous deployment of Kubernetes objects by applying declarative configuration files from a Git repository to a Kubernetes cluster. kube-applier runs as a Pod in your cluster and watches the Git repo to ensure that the cluster objects are up-to-date with their associated spec files (JSON or YAML) in the repo. At a specified interval, kube-applier performs a "full run", issuing kubectl apply commands for all JSON and YAML files within the repo. When a new commit to the repo occurs, kube-applier performs a "quick run", issuing apply commands only for files that have changed since the last run. Quick runs and full runs are handled separately and concurrently. kube-applier serves a status page and provides metrics for monitoring.

https://github.com/box/kube-applier 

 

 

4. YAML / JSON 매니페스트 대안으로 Ksonnet 고려

4.1. Ksonnet이란 JSON 데이터 구조 구축을 위한 데이터 템플릿 언어 Jsonnet 기반 라이브러리

4.1.1. JSON 직접 작성 대신 매개변수화된 JSON을 정의 후 이름을 지정해 여러 위치에서 동일 코드를 참조해 빌드

$ cat kubia.ksonnet
local k = import "../ksonnet-lib/ksonnet.beta.1/k.libsonnet";

local container = k.core.v1.container;
local deployment = k.apps.v1beta1.deployment;

local kubiaContainer =
  container.default("kubia", "luksa/kubia:v1") +
  container.helpers.namedPort("http", 8080);

deployment.default("kubia", kubiaContainer) +
deployment.mixin.spec.replicas(3)
[ksonnet]

The team behind ksonnet is stepping back from the project. As a result, work on ksonnet will end and the GitHub repositories will be archived.

ksonnet is a framework for writing, sharing, and deploying Kubernetes application manifests. With its CLI, you can generate a complete application from scratch in only a few commands, or manage a complex system at scale. Specifically, ksonnet allows you to:
Reuse common manifest patterns (within your app or from external libraries)
Customize manifests directly with powerful object concatenation syntax
Deploy app manifests to multiple environments
Diff across environments to compare two running versions of your app
Track the entire state of your app configuration in version controllable files

All of this results in a more iterative process for developing manifests, one that can be supplemented by continuous integration (CI).

https://github.com/ksonnet/ksonnet 
The next significant change relates to the ksonnet community project. From the earliest days of Heptio, co-founders Craig McLuckie and Joe Beda wanted to streamline the developer experience of configuring and deploying applications on Kubernetes. ksonnet, a tool to simplify how users configure applications they deploy to Kubernetes clusters, was built in collaboration between Heptio, Box, Microsoft, and Bitnami.

Early efforts with ksonnet were focused around creating patterns to help organize configurations across many applications for large deployments of Kubernetes. Feedback from the community was that the purpose of ksonnet was meaningful, but the language and concepts could be intimidating for new and casual users. We worked to streamline the user experience through a Visual Studio Code extension and a new command line tool, ks, but despite our efforts, ksonnet has not yet resonated with its intended audience.

Prior to the acquisition, Heptio had been shifting focus and resources away from ksonnet; with the acquisition, we felt it was the right time to rethink our investment in ksonnet. As a result, work on ksonnet will end and the GitHub repositories will be archived. It’s extremely difficult to step back from a project we have worked so hard on, but we’re excited about our new ideas and vision for changing how developers experience the Kubernetes and cloud native ecosystems. The problems that ksonnet aimed to solve are still challenges for Kubernetes users and we will be putting our energy into opportunities to contribute to existing or new projects in this space.

https://tanzu.vmware.com/content/blog/welcoming-heptio-open-source-projects-to-vmware 

 

 

5. CI/CD

https://aws.amazon.com/ko/codepipeline/

 

AWS CodePipeline | 지속적 통합 및 지속적 전달

AWS CodePipeline은 특정한 요구에 맞게 손쉽게 확장할 수 있습니다. 사전 구축된 플러그인 또는 자체 사용자 지정 플러그인을 릴리스 프로세스 중 원하는 단계에 사용할 수 있습니다. 예를 들면 GitHu

aws.amazon.com

https://aws.amazon.com/ko/devops/continuous-integration/

 

지속적 통합이란 무엇입니까? – Amazon Web Services

지속적 통합은 자동화된 빌드 및 테스트가 수행된 후, 개발자가 코드 변경 사항을 중앙 리포지토리에 정기적으로 병합하는 데브옵스 소프트웨어 개발 방식입니다. 지속적 통합은 소프트웨어 릴

aws.amazon.com

https://aws.amazon.com/ko/devops/continuous-delivery/

 

지속적 전달이란 무엇입니까? - Amazon Web Services

지속적 전달은 전체 소프트웨어 릴리스 프로세스를 자동화합니다. 수정 버전이 커밋될 때마다, 업데이트를 빌드 및 테스트한 후, 스테이징하는 자동화된 흐름이 트리거됩니다. 라이브 프로덕션

aws.amazon.com