Skip to content

Latest commit

 

History

History
1535 lines (1511 loc) · 181 KB

쿠버네티스 모범 사례.md

File metadata and controls

1535 lines (1511 loc) · 181 KB

서평

  • error (10)
  • 이 책은 CKA 취득 후에 Kubernetes 환경에서 airflow와 trino 그리고 kubeflow를 활용한 MLops 프로젝트를 위해서 사전에 공부를 하게 될 겸 읽게 되었습니다. 책을 읽으면서 예제 코드를 실습할 때 CKAD를 병행하여 재밌게 읽었던 거 같습니다.
  • 이 책은 쿠버네티스에 애플리케이션을 배포하거나 쿠버네티스 기반 애플리케이션에 적용할 수 있는 패턴과 사례를 배우려는 실무자를 대상으로 하고 있습니다. 쿠버네티스를 활용한 애플리케이션 개발, 운영 환경 구축에 필요한 포괄적인 지식을 제공하며 각 패턴별로 모범 사례를 소개하고 있어 실무를 하는데 많은 도움이 될 거 같습니다.
    • 글로벌 애플리케이션 분산: 사용자 경험 향상을 위해 애플리케이션을 글로벌하게 분산 배포하는 전략을 탐구합니다. 레이턴시 최소화와 지역성 향상을 통해 더 나은 서비스 제공이 가능합니다.
    • 리소스 관리: 쿠버네티스의 리소스 관리 기능을 활용하여 파드 배치와 스케줄링을 최적화합니다. 파드 어피니티, 안티어피니티, 노드 셀렉터를 통한 세밀한 조정을 통해 클러스터 리소스 활용을 극대화합니다.
    • 네트워킹과 보안: 파드 간 통신 및 서비스 간 통신을 가능하게 하는 쿠버네티스 네트워킹과 네트워크 정책을 통한 트래픽 제어 방법을 다룹니다. 또한, 서비스 메시를 사용하여 애플리케이션 간 통신의 관리와 보안을 강화합니다.
    • 클러스터 정책과 거버넌스: 클러스터의 보안, 컴플라이언스, 리소스 사용 효율성을 관리하기 위한 파드시큐리티폴리시, 런타임클래스 등의 도구를 소개합니다. OPA와 게이트키퍼를 활용한 정책 기반 클러스터 관리 방법도 제공합니다.
  • 이 책은 쿠버네티스 클러스터의 효과적인 관리와 최적화를 위한 심도 있는 지침을 제공합니다. 다중 클러스터 관리, 외부 서비스와의 통합, 머신러닝 실행, 고수준 애플리케이션 패턴 구축, 상태 및 스테이트풀 애플리케이션 관리, 어드미션 컨트롤과 권한 관리 등 쿠버네티스를 활용한 다양한 시나리오를 포괄적으로 다룹니다. 초보자부터 고급 사용자까지 모두에게 유용한 지침서로, 클라우드 네이티브 애플리케이션의 개발과 운영을 최적화하는 데 큰 도움이 될 거 같습니다.

기본 서비스 설치

  • 설정 파일 관리
    • 쿠버네티스에서는 모든 것을 선언적(declarative)으로 표현함. 즉 클러스터 내에서 애플리케이션의 의도한 상태(desired state)를 작성하며(일반적으로 YAML이나 JSON 파일) 애플리케이션의 모든 구성 요소에 대해 상태를 정의함.
    • 클러스터의 상태를 일련의 변경의 합으로 보는 명령적(imperative) 접근방법도 있지만, 쿠버네티스는 선언적 방법을 선호함
    • 쿠버네티스는 YAML과 JSON을 지원함. 일반적으로 애플리케이션의 상태를 선언할 때는 JSON 보다 YAML을 선호함. YAML이 JSON보다 좀 더 간결하고 수정이 쉽기 때문. 대신 YAML은 들여쓰기에 민감함. YAML에서 들여쓰기를 잘못한 탓에 종종 쿠버네티스 설정 오류가 발생함
  • 디플로이먼트를 이용한 복제 서비스 생성
    • 이미지 관리 모범 사례
      • 컨테이너 이미지를 구축하고 관리하는 것. 이미지 구축 과정은 공급망 공격(supply chain attack)에 취약함. 공급망 공격이란 신뢰할 수 있는 소스의 의존 이미지에 악의적인 사용자가 코드나 바이너리를 삽입해서, 결국 독자의 애플리케이션에 이를 내장시키는 것
      • 네이밍(naming)과 관련된 모범 사례도 있음. 이론적으로는 이미지 레지스트리에 존재하는 컨테이너 이미지 버전을 변경할 수 있음. 하지만 실제로는 버전 태그를 변경하지 않는 것이 좋음. 그래서 의미론적 버전과, 이미지가 빌드된 커밋의 SHA 해시(hash)와 결합해 네이밍하는 것을 권장함(예를 들어 v1.0.1-bfeda01f). 만약 이미지 버전 태그를 명시하지 않는다면 latest를 기본으로 사용함
    • 애플리케이션 레플리카 생성
      • 쿠버네티스에서 레플리카셋(ReplicaSet)은 컨테이너화된 애플리케이션의 레플리카를 관리하는 리소스. 하지만 레플리카셋을 사용하는 대신 디플로이먼트(Deployment) 리소스를 사용하는 것을 권장함.
      • 디플로이먼트는 레플리카셋의 복제 기술과 더불어 버전 과리, 단계적 롤아웃도 지원함. 디플로이먼트를 사용하면 쿠버네티스에 내장된 도구를 이용해 애플리케이션 버전을 변경할 수 있음
      • 컨테이너의 리소스 요청(request)와 제한(limit)에도 주목해야 함.
        • 요청은 애플리케이션을 실행하는 호스트 장비가 보장해주는 리소스 크기이고 제한은 컨테이너가 사용할 수 있는 최대 리소스 크기
        • 요청과 제한을 동일한 값으로 설정하면 애플리케이션은 대부분 예상대로 동작함. 대신 리소스 이용률을 높일 수 없다는 단점이 있음
        • 애플리케이션이 과도하게 스케줄링되거나 유휴 리소스를 과소비하는 것을 방지한다는 장점은 있지만, 세밀하게 튜닝하지 않으면 리소스를 최대로 사용할 수 없음
      • 클러스터 항목과 소스 관리 항목이 정확히 일치해야 함. 가장 좋은 방안은 깃옵스(GitOps)로 지속적 통합(CI)과 지속적 배포(CD)를 자동화하여 특정 브랜치만 운영에 배포하는 것. 이 방식으로 소스 관리와 운영을 일치시킬 수 있음
  • HTTP 트래픽을 처리하는 외부 인그레스 설정
    • 외부에 노출하려면 실제로 두 개의 쿠버네티스 리소스를 사용함.
      • 첫 번째는 전송 제어 프로토콜(TCP, Transmission Control Protocol) 또는 사용자 데이터그램 프로토콜(UDP, User Datagram Protocol) 트래픽을 로드 밸런싱하는 서비스
      • 인그레스 리소스는 HTTP 경로와 호스트 기반의 요청을 지능적으로 라우팅(routing) 할 수 있는 HTTP (S) 로드 밸런싱을 지원함
  • 컨피그맵으로 애플리케이션 설정
    • 설정을 사용하면 사용자의 요구사항 변경이나 애플리케이션 코드가 실패했을 때 빠르게(그리고 동적으로) 기능을 활성화하고 비활성화할 수 있음. 하나의 기능 단위로 롤아웃이나 롤백할 수 있음
    • 쿠버네티스에서는 컨피그맵 리소스로 설정을 정의함. 컨피그맵은 설정 정보나 파일을 나타내는 다중 키/값 쌍을 가짐. 이 설정 정보는 파드 내의 컨테이너에 파일이나 환경 변수 형태로 전달됨
  • 시크릿 인증 관리
    • 볼륨은 사용자가 지정한 위치에 존재하는 하나의 파일이나 디렉터리로, 실행 중인 컨테이너에 마운트될 수 있음. 시크릿은 tmpfs 램 기반의 파일 시스템으로 볼륨을 생성해 컨테이너에 마운트됨. 따라서 장비가 물리적인 피해를 입더라도(클라우드가 아닌 데이터 센터라면 가능) 공격자가 시크릿을 취득하기 어려움
  • 간단한 스테이트풀 데이터베이스 배포
    • 쿠버네티스에서는 노드 상태, 업그레이드, 리밸런싱 등 여러 이유로 파드가 다시 스케줄링됨. 이러한 일이 발생하면 파드는 다른 서버로 옮겨짐. 이때 레디스 인스턴스와 연관된 데이터가 특정 장비나 컨테이너 자체에 존재하는 경우, 컨테이너가 이관되거나 재시작될 때 해당 데이터가 손실됨. 이를 방지하려면 스테이트풀 작업을 실행할 때, 원격 퍼시스턴트볼륨(PersistentVolume)을 사용하여 애플리케이션 상태를 처리해야 함
    • 시크릿과는 달리 퍼시스턴트볼륨은 일반적으로 원격 스토리지에 존재하며, 파일 기반의 네트워크 파일 시스템(Network File System,NFS), 서버 메시지 블록(Server Message Block, SMB), 블록 기반의 iSCSI, 클라우드 기반 디스크 등 다양한 네트워크 프로토콜을 통해 마운트됨.
    • 일반적으로 데이터베이스와 같은 애플리케이션의 경우 성능이 더 좋은 블록 기반 디스크를 선호하지만, 성능이 주요 고려 대상이 아니라면 유연성이 높은 파일 기반 디스크가 낫음
    • 퍼시스턴트볼륨클레임(PersistentVolumeClaim), 클레임은 리소스 요청을 생각하면 됨. 레디스가 50GB가 필요하다고 추상적으로 선언하면 쿠버네티스 클러스터는 적절한 퍼시스턴트볼륨을 제공할 방법을 결정함
      • 디스크 명세(specification)가 다를 수 있는 여러 클라우드나 온프레미스 사이에서 이식할 수 있도록 스테이트풀셋을 작성할 수 있음
      • 퍼시스턴트볼륨 타입은 오직 하나의 파드에 마운트될 수 있지만, 볼륨클레임을 사용해 작성한 템플릿은 복제가 가능하며 따라서 각 파드는 자신만의 퍼시스턴트볼륨을 할당받을 수 있음
  • 인그레스를 이용해 트래픽을 정적 파일 서버로 전달
    • 정적 파일 서버는 HTML, CSS, 자바스크립트, 그림 파일을 제공하는 역할을 함
  • 서비스 배포 모범 사례
    • 대부분의 서비스는 디플로이먼트 리소스로 배포되어야 함. 디플로이먼트는 중복과 확장을 위해 레플리카를 생성함
    • 디플로이먼트는 로드 밸런서인 서비스를 통해 노출됨. 서비스는 클러스터 내부(기본값) 혹은 외부에 노출될 수 있음. HTTP 애플리케이션을 노출하려면 인그레스 컨트롤러를 사용할 수 있으며 요청 라우팅과 SSL도 추가할 수 있음
    • 애플리케이션의 설정을 다양한 환경에서 재사용하려면 애플리케이션을 파라미터화해야 함. 헬름과 같은 패키징 도구는 이러한 파라미터화를 위한 최고의 선택

개발자 워크플로

  • 쿠버네티스는 소프트웨어를 안정적으로 운영하기 위해 만들어졌음. 애플리케이션 지향 API, 자체 복구 속성, 소프트웨어의 다운타임 없이 롤아웃할 수 있는 디플로이먼트 등 유용한 도구를 제공함
  • 목표
    • 개발자와 클러스터 사이의 상호작용 단계
      • 온보딩
        • 개발자에게 계정을 생성해주고 첫 배포까지 지원해줌. 개발자가 최대한 이른 시일 안에 적응하도록 돕는게 목표.
        • 핵심 성과 지표(KPI, key performance indicator)도 세워야함.
        • 빈손으로 시작한 사용자가 30분 내에 애플리케이션의 최신 버전을 실행하도록 만들기가 좋은 예
      • 개발
        • 개발자는 매일 개발을 함. 이 단계의 목표는 빠른 반복과 디버그
        • 개발자는 클러스터에 코드를 빠르고 반복적으로 푸시함. 문제가 발생했을때는 쉽게 코드를 테스트하고 디버그하길 원함
      • 테스트
        • 코드 제출과 병합 전 검증 작업을 진행함
        • 목표
          • 풀 리퀘스트를 제출하기 전에 자신의 환경에서 이를 테스트할 수 있어야 함.
          • 코드가 리포지터리에 병합되기 전에 모든 테스트가 자동으로 실행돼야 함
  • 개발 클러스터 구축
    • 쿠버네티스에서 개발을 시작할 때, 먼저 대규모 단일 개발 클러스터와 개발자별 클러스터 중 하나를 선택해야 함
    • 장단점
      • 개발자별 클러스터의 가장 치명적인 단점은 큰비용과 낮은 효율성, 관리해야 할 클러스터의 수가 많다는 것.
        • 추가로 각 클러스터의 사용률이 굉장히 저조할 가능성이 존재함
        • 리소스를 추적하여 사용하지 않는 리소스를 삭제하는 것이 어려움.
        • 개발자별 클러스터의 장점은 단순하다는 것. 각 사용자는 고립된 클러스터를 독립적으로 관리하게 되므로 서로에게 피해를 주지 않음
      • 대규모 단일 개발 클러스터는 굉장히 효율적
        • 개발자 수가 같을 때 1/3 가격 (혹은 더 적은)의 공용 클러스터로 처리가 가능함. 또한 모니터링과 로깅처럼 개발자에게 필요한 공용 클러스터 서비스를 설치하는 것이 더욱 수월함.
        • 단점은 사용자 관리 프로세스와 잠재적인 개발자 간의 간섭. 새로운 사용자와 네임스페이스를 추가하는 과정은 간단하지 않기 때문에, 새로운 개발자를 위한 온보딩 프로세스를 만들어야 함
        • 한 사용자가 너무 많은 리소스를 사용하는 경우, 개발 클러스터가 먹통이 되어 다른 애플리케이션과 개발자에게 리소스가 할당되지 않는다는 문제도 있음. 이때 쿠버네티스 리소스 관리나 역할 기반 접근 제어(RBAC, role-based access control)로 개발자 사이의 충돌을 줄일 수 있음
        • 개발자가 리소스를 생성해야 하며 누수를 일으키거나 방치되지 않았는지 신경을 써야 함. 그래도 개발자가 직접 클러스터를 생성하는 것보다 쉬움
      • 대규모 단일 클러스터를 추천함
        • 개발자들 사이의 간섭 문제가 있지만 충분히 관리가 가능함. 궁극적으로 비용 대비 효율성이 높으며 클러스터에 조직 단위 기능을 쉽게 추가할 수 있다는 것이 큰 장점
        • 그 대신 개발자 온보딩 프로세스, 리소스 관리, 가비지 컬렉션에 투자해야함. 처음에는 대규모 단일 클러스터를 시도해보고 추후 조직이 거대해지면(혹은 이미 거대하다면) 수백 명의 사용자를 가진 거대 클러스터 대신 팀이나 그룹 단위(10~20명) 클러스터를 고려해보기. 비용과 관리 측면에서 좋은 방법
  • 다중 개발자를 위한 공용 클러스터 구축
    • 네임스페이스는 서비스 배포 범위를 제한하여 특정 사용자의 프런트엔드 서비스가 다른 사용자의 프런트엔드 서비스에 피해를 주지 않도록 만듬. 또한 RBAC의 범위도 제한하기 때문에 특정 개발자가 실수로 다른 개발자의 작업 결과를 삭제하는 것을 막을 수 있음
    • 공용 클러스터에서 개발자의 작업 공간으로 네임스페이스를 사용하는 것은 좋은 생각임
    • 사용자 온보딩
      • 사용자가 네임스페이스를 할당받기 위해서는 먼저 쿠버네티스 클러스터 자체에 접근할 수 있어야 함
        • 첫 번째로 증명(certificate) 기반 인증을 사용할 수 잇음. 사용자를 위한 새로운 증명을 생성하여 로그인에 사용할 수 있는 kubeconfig 파일을 전달해주는 것
        • 두 번째로 외부 신원 시스템, 예를 들면 마이크로소프트 애저 액티브 디렉터리(Azure Active Directroy) 또는 AWS 아이덴티티 엔드 액세스 매니지먼트(IAM)를 사용해 클러스터에 접근하도록 설정할 수 있음
      • 일반적으로 신원 데이터를 한곳에서 관리할 수 있는 외부 신원 시스템을 사용하는 것이 모범 사례. 외부 신원 시스템을 사용할 수 없는 상황이라면 증명을 사용해야 함. 다행히 쿠버네티스 증명 API를 사용하여 이를 생성하고 관리할 수 있음
    • 네임스페이스 생성과 보안
      • 배포할 컴포넌트를 빌드하는 팀의 연락처와 같은 메타데이터를 네임스페이스에 추가하고는 함. 일반적으로 애너테이션(annotation) 형태
      • Jinjia 등의 템플릿을 이용해 YAML 파일로 네임스페이스를 먼저 생성하고 애너테이션을 넣을 수 있음
      • ns='my-namespace'
        kubectl create namespace ${ns}
        kubectl annotate namespace ${ns} annotation_key=annotation_value
      • 보안을 위해 특정 사용자에게만 네임스페이스 접근 권한을 부여할 수 있음. 네임스페이스 안의 사용자에게 롤바인딩을 하는 것. 이를 위해 네임스페이스 안에 롤바인딩 객체를 생성함
      • apiVersion: rbac.authorization.k8s.io/v1
        kind: RoleBinding
        metadata:
          name: example
          namespace: my-namespace
        roleRef:
          apiGroup: rbac.authorization.k8s.io
          kind: ClusterRole
          name: edit
        subjects:
        - apiGroup: rbac.authorization.k8s.io
          kind: User
          name: myuser
      • 롤바인딩을 생성하려면 kubectl create -f role-binding.yaml을 실행하면 됨. 이것은 재사용도 가능함. 네임스페이스를 변경하고 바인딩의 네임스페이스를 업데이트하면됨
      • 사용자가 다른 롤바인딩을 가지고 있지 않다면 사용자는 클러스터에서 이 네임스페이스에만 접근할 수 있음.
      • 전체 클러스터에 읽기 권한을 부여하는 것도 실용적임. 이를 통해 개발자는 자신의 작업에 영향을 미치는 다른 사람의 작업을 볼 수 있음. 하지만 클러스터의 시크릿 리소스에 접근할 수 있기 때문에 읽기 권한을 부여할 때에는 주의해야 함
      • 특정 네임스페이스의 리소스 사용량을 제한하고 싶다면 리소스쿼터를 이용함
        • 예를 들어 다음 리소스쿼터는 네임스페이스에 속한 파드의 요청과 제한 모두를 10코어와 100GB 메모리로 제한함
        • apiVersion: v1
          kind: ResourceQuota
          metadata:
            name: limit-compute
            namespace: my-namespace
          spec:
            hard:
              requests.cpu: "10"
              requests.memory: 100Gi
              limits.cpu: "10"
              limits.memory: 10Gi
    • 네임스페이스 관리
      • 개발자에게 네임스페이스를 할당하는 방법
        • 온보딩 과정의 일부로 개발자에게 네임스페이스를 부여하는 것. 그러면 온보딩 이후 자연스레 애플리케이션을 개발하고 관리할 수 있는 전용 작업 공간을 가지게 됨.
        • 영구적인 네임스페이스에서 작업한 산출물이 방치될 수 있으므로 개별 리소스를 파악하고 가비지 컬렉션하는 것이 어려울 수 있음. 대안으로 타임 투 리브(TTL, time to live)로 네임스페이스를 임시로 생성하여 할당하는 방법이 있음.
        • 개발자는 클러스터 내의 리소스를 한시적이라고 생각할 것이며 TTL이 만료되었을 때 네임스페이스 삭제의 자동화를 쉽게 구축할 수 있음
      • 쿠버네티스와 통합한다면 kubectl 도구를 이용하여 동적으로 새로운 네임스페이스를 생성하고 할당할 수 있는 사용자 리소스 정의(CRD, Custom Resource Definition)를 구현할 수 있음
        • 네임스페이스를 조사하여 TTL이 만료된 것들을 삭제하는 간단한 스크립트를 만들면 됨
  • 반복적 개발
    • 새로운 코드를 배포하는 가장 쉬운 방법은 이전 디플로이먼트 객체를 지우고 새로운 이미지를 가리키는 새로운 디플로이먼트를 생성하는 것
    • 기존 디플로이먼트를 직접 수정할 수도 있지만 이렇게 하면 디플로이먼트 리소스 롤아웃 로직이 동작하게 됨
    • kubectl delete -f ./ex.yaml
      perl -pi -e 's/${old_version}/${new_version}/' ./ex.yaml
      kubectl create -f ./ex.yaml
  • 개발 환경 설정 모범 사례
    • 개발자 경험을 온보딩, 개발, 테스팅의 세 단계로 나누어 생각해봄. 구축한 개발 환경이 이 모든 단계를 지원하는지 확인해야 함
    • 개발 클러스터를 구축할 때 대규모의 단일 클러스터와 개발자별 클러스터 중 하나를 선택할 수 있음. 각각의 장단점이 있지만 일반적으로 대규모의 단일 클러스터가 더 나은 방법
    • 클러스터에 사용자를 추가할 대, 사용자의 신원을 추가하고 자신의 네임스페이스에만 접근하도록 하세요. 사용할 수 있는 리소스의 크기는 제한해야 함
    • 네임스페이스를 관리할 때, 오랫동안 사용하지 않은 리소스를 어떻게 회수할지 고민하세요. 사용하지 않는 리소스를 삭제하지 않는 것은 개발자의 나쁜 버릇. 정리를 자동화해야 함
    • 모든 사용자를 위해 로그와 모니터링 같은 크러스터 수준의 서비스를 고민하세요. 때로는 헬름 차트와 같은 템플릿을 사용하는 모두를 위해, 데이터베이스와 같은 클러스터 수준의 의존 관계가 필요함

모니터링과 로깅

  • 메트릭 vs 로그
    • 메트릭 : 특정 기간에 측정한 일련의 숫자
    • 로그 : 시스템을 탐색적으로 분석하기 위해 사용됨
  • 모니터링 기술
    • 블랙박스 모니터링은 애플리케이션 외부에 초점을 둠. 일반적으로 CPU, 메모리, 스토리지 등의 시스템 컴포넌트를 모니터링함
    • 클러스터가 정상인지 테스트해보기 위해 수행하는 파드 스케줄링이 블랙박스 모니터링의 예시
    • 화이트박스 모니터링은 애플리케이션 상태에 초점을 둠. 예를 들면 전체 HTTP 요청, 500 오류 수, 요청 레이턴시 등. 이를 통해 시스템 상태가 왜 이런지를 이해할 수 있음
  • 모니터링 패턴
    • 브렌던 그레그의 USE 패턴
      • U(utilization): 사용률
      • S(saturation): 포화도
      • E(error): 오류율
      • 이 패턴은 애플리케이션 수준의 모니터링에 사용하기에는 한계가 있어 인프라 모니터링에만 활용됨. USE 패턴은 모든 리소스에 대해 사용률, 포화도, 오류율을 확인함.
      • 시스템의 리소스 제약과 오류율을 빠르게 파악할 수 있음. 예를 들어 클러스터 노드의 네트워크 상태를 점검하기 위해 사용률, 포화도, 오류율을 모니터링해서 네트워크 병목이나 네트워크 스택의 오류를 쉽게 알 수 있음
    • 톰 윌키의 RED 패턴
      • R(request): 요청
      • E(error): 오류율
      • D(duration): 소요 시간
    • 구글의 네 가지 황금 신호(four golden signals)
      • 레이턴시: 요청을 처리하는 데 걸리는 시간
      • 트래픽: 시스템에 존재하는 요청의 양
      • 오류율: 요청 실패율
      • 포화도: 서비스의 사용률
    • USE와 RED는 상호보완적임. USE는 인프라 컴포넌트에 초점을 맞추며 RED는 애플리케이션의 최종 UX를 모니터링하는 데 중점을 둠
  • 쿠버네티스 메트릭 개요
    • 쿠버네티스 클러스터는 컨트롤 플레인 컴포넌트와 워커 노드 컴포넌트로 구성됨.
      • 컨트롤 플레인 컴포넌트는 API 서버, etcd, 스케줄러, 컨트롤러 관리자로 이루어져 있음
      • 워커 노드는 kubelet, 컨테이너 런타임, kube-proxy, kube-dns, 파드로 이루어져 있음. 클러스터와 애플리케이션이 정상인지 확인하려면 모든 컴포넌트를 모니터링해야 함
    • cAdvisor
      • 컨테이너 어드바이저 또는 cAdvisor는 쿠버네티스 오픈 소스 프로젝트로 노드에서 실행 중인 컨테이너의 리소스와 메트릭을 수집함. cAdvisor 쿠버네티스 kubelet에 내장되어 클러스터의 모든 노드에서 실행됨
      • 리눅스 cgroups(control groups) 트리를 통해 메모리와 CPU 메트릭을 수집함. cgroups는 CPU, 디스크 IO, 네트워크 IO 리소스를 고립시킬 수 있는 리눅스 커널 기능으로 리눅스 커널에 내장된 statfs를 이용해 디스크 메트릭을 수집함
    • 메트릭 서버
      • 리소스 메트릭 API의 표준 구현체가 메트릭 서버. 메트릭 서버는 CPU와 메모리 같은 리소스 메트릭을 수집함. kubelet API로부터 수집하며 메모리에 저장함. 이 메트릭은 스케줄러, 수평 파드 오토스케일러(HPA), 수직 파드 오토스케일러(VPA)에서 사용됨
      • 사용자 정의 메트릭 API를 이용해 모니터링 시스템에서 임의의 메트릭을 수집할 수 있음. 모니터링 솔루션은 사용자 정의 어댑터를 구축해 리소스 메트릭을 확장할 수 있음
    • kube-state-metrics
      • kube-state-metrics가 해결해 줄 질문
        • 파드
          • 클러스터에 몇 개의 파드가 배포되었나요?
          • 대기 중인 파드는 몇 개인가요?
          • 파드 요청을 처리할 수 있을 만큼의 충분한 리소스가 있나요?
        • 디플로이먼트
          • 의도한 상태에서 수행 중인 파드는 몇 개인가요?
          • 몇 개의 레플리카가 가용한가요?
          • 어떤 디플로이먼트가 업데이트되었나요?
    • 톰 윌키의 RED 패턴
      • R(request): 요청
      • E(error): 오류율
      • D(duration): 소요 시간
    • 구글의 네 가지 황금 신호(four golden signals)
      • 레이턴시: 요청을 처리하는 데 걸리는 시간
      • 트래픽: 시스템에 존재하는 요청의 양
      • 오류율: 요청 실패율
      • 포화도: 서비스의 사용률
    • USE와 RED는 상호보완적임. USE는 인프라 컴포넌트에 초점을 맞추며 RED는 애플리케이션의 최종 UX를 모니터링하는 데 중점을 둠
  • 쿠버네티스 메트릭 개요
    • 쿠버네티스 클러스터는 컨트롤 플레인 컴포넌트와 워커 노드 컴포넌트로 구성됨.
      • 컨트롤 플레인 컴포넌트는 API 서버, etcd, 스케줄러, 컨트롤러 관리자로 이루어져 있음
      • 워커 노드는 kubelet, 컨테이너 런타임, kube-proxy, kube-dns, 파드로 이루어져 있음. 클러스터와 애플리케이션이 정상인지 확인하려면 모든 컴포넌트를 모니터링해야 함
    • cAdvisor
      • 컨테이너 어드바이저 또는 cAdvisor는 쿠버네티스 오픈 소스 프로젝트로 노드에서 실행 중인 컨테이너의 리소스와 메트릭을 수집함. cAdvisor 쿠버네티스 kubelet에 내장되어 클러스터의 모든 노드에서 실행됨
      • 리눅스 cgroups(control groups) 트리를 통해 메모리와 CPU 메트릭을 수집함. cgroups는 CPU, 디스크 IO, 네트워크 IO 리소스를 고립시킬 수 있는 리눅스 커널 기능으로 리눅스 커널에 내장된 statfs를 이용해 디스크 메트릭을 수집함
    • 메트릭 서버
      • 리소스 메트릭 API의 표준 구현체가 메트릭 서버. 메트릭 서버는 CPU와 메모리 같은 리소스 메트릭을 수집함. kubelet API로부터 수집하며 메모리에 저장함. 이 메트릭은 스케줄러, 수평 파드 오토스케일러(HPA), 수직 파드 오토스케일러(VPA)에서 사용됨
      • 사용자 정의 메트릭 API를 이용해 모니터링 시스템에서 임의의 메트릭을 수집할 수 있음. 모니터링 솔루션은 사용자 정의 어댑터를 구축해 리소스 메트릭을 확장할 수 있음
    • kube-state-metrics
      • kube-state-metrics가 해결해 줄 질문
        • 파드
          • 클러스터에 몇 개의 파드가 배포되었나요?
          • 대기 중인 파드는 몇 개인가요?
          • 파드 요청을 처리할 수 있을 만큼의 충분한 리소스가 있나요?
        • 디플로이먼트
          • 의도한 상태에서 수행 중인 파드는 몇 개인가요?
          • 몇 개의 레플리카가 가용한가요?
          • 어떤 디플로이먼트가 업데이트되었나요?
        • 노드
          • 워커 노드의 상태는 어떠한가요?
          • 클러스터에서 할당할 수 있는 CPU 코어는 몇 개인가요?
          • 스케줄되지 않은 노드가 있나요?
          • 잡이 언제 시작되었나요?
          • 잡이 언제 완료되었나요?
          • 몇 개의 잡이 실패했나요?
  • 모니터링할 메트릭
    • 쿠버네티스에서 모니터링할 때는 다음과 같은 계층적 방식을 취해야 함
      • 물리적 혹은 가상의 노드
      • 클러스터 컴포넌트
      • 클러스터 추가 기능
      • 최종 사용자 애플리케이션
    • 이러한 계층적 모니터링 방식으로 신호를 간단하고 정확하게 파악할 수 있음
    • 시스템에서 살펴볼 메트릭
      • 노드
        • CPU 사용률
        • 메모리 사용률
        • 네트워크 사용률
        • 디스크 사용률
      • 클러스터 컴포넌트
        • etcd 레이턴시
      • 클러스터 추가 기능
        • 클러스터 오토스케일러
        • 인그레스 컨트롤러
      • 애플리케이션
        • 컨테이너 메모리 사용률과 포화도
        • 컨테이너 CPU 사용률
        • 컨테이너 네트워크 사용률과 오류율
        • 애플리케이션 프레임워크 특정 메트릭
  • 모니터링 도구
    • 프로메테우스(Prometheus)
      • 시스템 모니터링과 알림(alert) 툴킷(toolkit) 오픈 소스로 초창기에는 사운드 클라우드(SoundCloud)에서 개발했음.
      • 2016년에 클라우드 네이티브 컴퓨팅 재단(CNCF)에 가입했음. 이 단체에서 쿠버네티스 다음으로 호스팅한 두 번째 프로젝트
    • InfluxDB
      • 높은 쓰기와 질의(query) 부하를 처리하도록 설계된 시계열 데이터베이스
      • TICK(Telegraf, InfluxDB, Chronograf, Kapacitor의 줄임말) 스택의 필수 컴포넌트
      • 대량 타임스탬프 데이터와 관련하여 다양하게 활용될 수 있는 스토리지. 예를 들면 데브옵스(DevOps) 모니터링, 애플리케이션 메트릭, IoT 센서 데이터, 실시간 분석이 있음
    • 데이터독(Datadog)
      • 클라우드 규모의 애플리케이션을 위한 모니터링 서비스.
      • SaaS 기반 데이터 분석 플랫폼을 통해 서버, 데이터베이스, 도구, 서비스를 모니터링할 수 있음
    • 시스딕(Sysdig)
      • 시스딕 모니터는 컨테이너 네이티브 앱을 위한 도커와 쿠버네티스 모니터링을 제공하는 상용 도구.
      • 쿠버네티스와 직접 통합되어 프로메테우스 메트릭을 수집하고 연동하고 질의할 수 있음
    • 클라우드 공급자 도구
      • GCP 스택드라이버(Stackdriver)
        • 스택드라이버 쿠버네티스 엔진 모니터링은 구글 쿠버네티스 엔진(GKE) 클러스터를 모니터링하도록 설계되었음.
        • 모니터링과 로깅 서비스를 관리하고, GKE 클러스터에 맞춘 대시보드 인터페이스가 있음. 이를 통해 클라우드 애플리케이션의 성능과 업타임, 전반적인 상태를 볼 수 있음
        • 구글 클라우드 플랫폼(GCP), 아마존 웹 서비스(AWS), 가동 시간 프로브, 애플리케이션 장치로부터 메트릭, 이벤트, 메타데이터를 수집함
      • 컨테이너를 위한 마이크로소프트 애저 모니터
        • 애저 컨테이너 인스턴스(ACI)나 애저 쿠버네티스 서비스(AKS)가 호스팅하는 쿠버네티스 클러스터에 배포된 것으로, 컨테이너 워크로드의 성능을 모니터링하도록 설계되었음
      • AWS 컨테이너 인사이트
        • 아마존 일래스틱 컨테이너 서비스(ECS), 아마존 일래스틱 쿠버네티스 서비스(EKS), 아마존 일래스틱 컴퓨트 클라우드(EC2)에 쿠버네티스 플랫폼을 사용한다면, 아마존 클라우드 워치 컨테이너 인사이트를 사용할 수 있음
        • 컨테이너 애플리케이션과 마이크로서비스의 메트릭과 로그를 수집, 집계, 요약할 수 있음. 메트릭에는 CPU, 메모리, 디스크, 네트워크와 같은 리소스의 사용량이 있음.
        • 컨테이너 재시작 실패와 같은 진단 정보를 제공하므로 문제의 범위를 좁혀 빠르게 해결할 수 있음
  • 프로메테우스를 사용한 모니터링
    • 프로메테우스는 쿠버네티스 레이블, 서비스 디스커버리, 메타데이터와 훌륭하게 통합되어 있음
    • 메트릭을 수집하기 위해 풀(pull) 모델을 사용함. 메트릭 엔드포인트로부터 메트릭을 수집하여 프로메테우스 서버에 메트릭을 저장함.
    • 쿠버네티스는 이미 프로메테우스 포맷으로 메트릭을 내보내는 기능을 가지고 있으므로 간단하게 메트릭을 수집할 수 있음. 다른 쿠버네티스 에코시스템 프로젝트(NGINX, Traefik, 이스티오, 링커디 등)도 이 포맷으로 내보냄. 뿐만 아니라 서비스가 내보내는 메트릭을 가져와서 프로메테우스 형태의 메트릭으로 변환할 수 있음
    • 프로메테우스 서버
      • 시스템으로부터 수집된 메트릭을 가져와 저장함
    • 프로메테우스 오퍼레이터
      • 프로메테우스 설정은 쿠버네티스 네이티브로 만듬. 프로메테우스와 알림매니저(alertmanager) 클러스터를 관리하고 운영함
      • 사용자는 쿠버네티스 네이티브 리소스 정의를 통해 프로메테우스 리소스를 생성, 제거, 설정할 수 있음
    • 노드 내보내기
      • 클러스터 안의 쿠버네티스 노드로부터 수집한 호스트 메트릭을 내보냄
    • kube-state-metrics
      • 쿠버네티스 메트릭을 수집함
    • 알림매니저
      • 알림을 설정하고 외부 시스템으로 보냄
    • 그라파나(Grafana)
      • 프로메테우스의 대시보드 시각화를 제공함
    • 프로메테우스 PromSQL이라는 질의어(query language)를 통해 쿠버네티스 메트릭을 조회해보기
      • avg(rate(node_cpu_seconds_total[5m])) : 노드의 CPU 사용률과 포화도를 수집, 전체 클러스터의 평균 CPU사용률을 반환함
      • avg(rate(node_cpu_seconds_total[5m])) by (node_name) : 노드별 CPU 사용률
    • 추적하려는 USE 기법 메트릭을 그라파나를 이용하여 대시보드로 시각화해봄. 프로메테우스 오퍼레이터를 설치할 때 그라파나 대시보드가 같이 설치됨
    • 너무 많은 대시보드를 생성하지 마세요(그래프의 장벽): 엔지니어가 문제를 해결해야 하는 상황에서 원인을 파악하기 어려워짐. 대시보드에 더 많은 정보가 있으면 모니터링하기에 더 좋을 것이라고 생각할지도 모르겠네요. 하지만 정보가 많으면 대시보드를 보는 사용자에게 혼란을 줄 수 있음. 대시보드를 설계할 때 문제 해결 시간과 결과에 중점을 두세요
  • 로깅 개요
    • 전체 환경을 보려면 쿠버네티스 클러스터와 클러스터에 배포된 애플리케이션으로부터 로그를 수집하여 중앙집중화해야 함
    • 누군가는 모든 것을 기록합시다 라고 쉽게 말할 수도 있음. 하지만 이에 따른 두 가지 문제가 발생함
      • 너무 많은 노이즈 때문에 문제를 빠르게 발견하기 어려움
      • 많은 리소스 사용으로 인한 높은 비용이 발생함
    • 최종 UX를 통해 살펴보면 30일에서 45일 사이의 로그를 보관하는 것이 좋음. 이 정도면 장기간에 걸쳐 나타나는 문제를 조사하기에 충분하고, 로그를 저장하는 데 필요한 리소스 양도 줄일 수 있음
    • 메트릭을 수집해야 할 컴포넌트의 목록
      • 노드 로그
      • 쿠버네티스 컨트롤 플레인 로그
        • API 서버
        • 컨트롤러 관리자
        • 스케줄러
      • 쿠버네티스 감사(audit) 로그
      • 애플리케이션 컨테이너 로그
  • 로깅 도구
    • 로깅 도구는 쿠버네티스 데몬셋(DaemonSet)으로 실행되어야 함. 표준 출려긍로 로그를 보낼 수 없는 애플리케이션을 위해 사이드카롭도 실행될 수 있어야 함
    • 쿠버네티스와 연동되는 대표적인 도구
      • 일래스틱 스택
      • 데이터독
      • 수모 로직(sumo logic)
      • 시스딕
      • 클라우드 공급자 서비스(GCP 스택드라이버, 애저 모니터, 아마존 클라우드워치)
    • 로그 중앙집중화를 위한 도구로는 많은 운영 비용을 절감할 수 있는 호스팅 솔루션이 좋음. 직접 로깅 솔루션을 호스팅하는 것은 며칠까지는 문제가 없을 수도 있음. 하지만 환경이 거대해진다면 유지보수를 위한 시간이 늘어날 것
  • EFK 스택을 사용한 로깅
    • 로깅 플랫폼을 관리하는 것이 정말 가치 있는일인가? 일반적으로 가치가 없음. 직접 로깅 솔루션을 호스팅하는 것은 처음에는 좋지만 시간이 지나면 굉장히 복잡해짐.
    • 자체 로깅 솔루션 호스팅은 환경의 규모가 커지면서 운영은 어려워짐
    • 모니터링 스택을 배포함
      • 일래스틱서치: 검색 엔진
      • 플루언트디: 쿠버네티스 환경에서 일래스틱서치로 로그를 전송
      • 키바나: 일래스틱서치에서 저장된 로그를 검색, 보기, 상호작용하는 시각화 도구
  • 알림
    • 쿠버네티스의 아름다움은 자동으로 컨테이너의 상태를 체크해서 재시작한느 것.
    • 사용자는 분명히 서비스 수준 목표(SLO)에 영향을 미치는 이벤트에만 집중하고 싶을 것. SLO는 가용성, 처리량, 빈도, 응답 시간 등 측정 가능한 특성으로, 서비스의 최종 사용자가 동의하는 것
    • 사용자의 기대 수준에 맞게 SLO를 설정하면 시스템이 어떻게 동작할지 명확하게 제시해야 함. SLO가 없다면 사용자는 서비스에 대한 비현실적인 기대를 가질 수 있음.
    • 쿠버네티스와 같은 시스템에서의 알림은 기존에 사용자가 경험한 방식과는 완전히 새로운 접근 방식이 필요함
    • 즉각 대응할 필요가 없는 알림을 처리하는 한 가지 방법은 문제를 자동으로 해결하는 것. 예를 들어 디스크가 가득 찼다면 디스크의 공간을 확보하기 위해 로그를 자동으로 지우는 것.
    • 앱 디플로이먼트에서 쿠버네티스의 생명성 프로브(liveness probe)를 이용하면 응답이 없는 프로세스를 자동으로 복원하는 데 도움을 얻을 수 있음
    • 알림을 구축할 때 알림 임계치(alert threshold)를 고려해야 함. 임계치가 너무 짧으면 많은 거짓 알람을 받을 수 있음. 이를 위해 일반적으로 5분 이하의 임계치를 설정할 것을 권장함.
    • 표준 임계치를 알아두면 많은 다양한 임계치를 편리하게 정리할 수 있음. 예를 들어 5분, 10분, 30분, 1시간 등의 특정 패턴을 따르는 것
    • 데이터 센터, 지역, 앱 소유자, 영향을 받는 시스템 등의 정보를 담아야 함
  • 모니터링, 로깅, 알림 모범 사례
    • 모니터링 모범 사례
      • 노드와 쿠버네티스의 모든 컴포넌트에 대한 사용률, 포화도, 오류율을 모니터링함. 그리고 애플리케이션의 속도, 오류, 시간도 모니터링함
      • 시스템의 예측하기 힘든 상태와 징후를 모니터링할 때는 블랙박스 모니터링을 사용함
      • 시스템과 내부를 조사할 때는 화이트박스 모니터링을 사용함
      • 정확도가 높은 메트릭을 얻으려면 시계열 기반 메트릭을 구현함. 애플리케이션에 대한 통찰을 얻을 수 있음
      • 프로메테우스와 같은 모니터링 시스템을 활용함. 고차원을 위한 키 레이블을 제공하고 문제의 징후에 대한 더 나은 신호를 제공함
      • 평균 메트릭을 사용하여 실제 데이터 기반의 하위 합계와 메트릭을 시각화함. 합계메트릭을 이용하여 특정 메트릭의 분포를 시각화함
    • 로깅 모범 사례
      • 전반적인 분석을 위해서는 메트릭 모니터링과 함께 로깅해야 함
      • 30일에서 45일까지만 로그를 저장하세요. 만약 그 이상의 로그가 필요하다면 장기간 보관할 수 있는 저비용 리소스를 사용하세요
      • 사이드카 패턴에서 로그 전달자를 제한적으로 사용하세요. 너무 많은 리소스를 사용할 겁니다. 데몬셋을 사용하세요
    • 알림 모범 사례
      • 알림 피로를 조심하세요. 사람과 프로세스에 악영향을 끼칠 수 있음
      • 절대로 완벽해질 수 없다는 생각을 가지고 점진적으로 개선하세요
      • 즉각적인 대응이 필요 없는 일시적인 문제는 알림하지 않고 SLO와 고객에게 영향을 미치는 징후를 알림하세요

설정, 시크릿, RBAC

  • 시크릿과 같은 민감한 데이터를 네이티브 쿠버네티스 API 객체로 전달하려면 쿠버네티스의 API 접근 보안 방식을 알아야 함. RBAC가 대표적. RBAC로 특정 사용자나 그룹의 API 이용에 대한 정교한 권한 구조를 구현할 수 있음
  • 컨피그맵과 시크릿을 통한 설정
    • 쿠버네티스는 컨피그맵과 시크릿 리소스를 이용해 애플리케이션에 설정 정보를 전달함. 둘 사이의 중요한 차이는 파드가 수신 정보를 저장하는 방식과 데이터가 etcd에 저장되는 방식
    • 컨피그맵
      • 개발자는 컨테이너를 사용해 애플리케이션과 설정 정보를 분리할 수 있으므로 애플리케이션 이식이 가능해짐. 컨피그맵 API를 이용해 전달받은 설정 정보를 주입할 수 있음
      • 컨피그맵은 유연성이 뛰어나기 때문에 애플리케이션의 다양한 요구사항을 처리할 수 있음. 키/값 쌍이나 JSON, XML과 같은 복잡한 대량 데이터, 자산 설정 데이터를 전달할 수 있음
      • 컨피그맵은 설정 정보를 파드에 전달할 뿐만 아니라 컨트롤러, CRD, 오퍼레이터 등 복잡한 시스템 서비스로도 정보를 제공할 수 있음
      • 컨피그맵 API의 대상은 민감하지 않은 문자열 데이터. 민감한 데이터를 전달할 때는 시크릿 API가 더 적합함
      • 애플리케이션에서 컨피그맵 데이터를 사용할며ㅕㄴ 파드에 볼륨을 마운트하거나 환경 변수로 전달하면 됨
    • 시크릿
      • 시크릿 데이터는 보이지 않게 저장되고 처리되어야 함. 필요시에는 환경설정을 통해 암호화된 후 저장되어야 함. 시크릿 데이터는 베이스64로 인코딩된 정보로 표현되는데, 암호화되지 않았다는 사실을 이해해야 함
      • 시크릿은 파드에 주입되자마자 일반 텍스트 형태로 보여짐. 시크릿 데이터란 베이스64로 인코딩된 데이터에 대해 기본 크기가 1MB로 제한되는 소량의 데이터를 의미함
      • 세 가지 타입
        • generic
          • 일반적인 키/값 쌍. 파일, 디렉터리로 생성되거나 다음과 같이 --from-literal= 인자를 사용해 문자열 리터럴로 생성됨
          • kubectl create secret generic mysecret --from-literal=key1=$3cr3t1 --from-literal=key2=@3cr3t2`
        • docker-registry
          • 개인 도커 레지스트리 인증에 필요한 신원. image Pullsecret에서 이 신원을 지정하면 kubelet이 파드템플릿으로 전달함
          • kubectl create secret docker-registry registryKey --docker-server myreg.azurecr.io --docker-username myreg --docker-password $up3r $3cr3tP@ssw0rd --docker-email ignore@dummy.com
        • tls
          • 공개/개인 키 쌍으로 전송 계층 보안(TLS, Transport Layer Security) 시크릿을 생성함. cert가 올바른 PEM 포맷이라면, 키 쌍은 시크릿으로 인코딩되어 SSL/TLS를 이용할 파드로 전달됨
          • kubectl create secret tls www-tls --key=./path_to_key/wwwtls.key --cert=./path_to_crt/wwwtls.crt
        • 시크릿은 자신을 사용하는 파드가 있는 노드의 tmpfs에만 마운트됨. 따라서 파드가 종료될 때 시크릿은 삭제됨. 이것은 노드의 디스크에 시크릿이 남는 상황을 방지함.
        • 보안상 안전해 보이지만, 기본적으로 시크릿은 etcd 데이터 스토리지에 평범한 텍스트로 저장됨. 그러므로 시스템 관리자나 클라우드 서비스 공급자는 etcd 노드 간의 상호 전송 계층 보안(mTLS) 및 etcd에 데이터를 저장할 때 암호화를 하는 등 etcd 환경의 보안에도 신경을 써야함
        • 쿠버네티스 최신 버전에서는 etcd3를 사용하며 네이티브 암호화를 지원함
  • 컨피그맵과 시크릿 API 모범 사례
    • 해시코프 볼트, 아쿠아 컨테이너 보안 플랫폼, 트위스트락, AWS 시크릿 관리자, 구글 클라우드 KMS, 애저 키 볼트와 같은 솔루션을 통해 쿠버네티스보다 더 높은 수준의 암호화 및 감사 기능을 제공하는 외부 스토리지 시스템을 이용할 수 있음
  • RBAC
    • 여권(사용자 계정)
      • 쿠버네티스는 사용자를 인증하기 위한 외부 권한에 의존함. 하지만 서비스 계정은 쿠버네티스가 직접 관리함
    • 비자 또는 여행 정책(권한)
      • 쿠버네티스에는 여러 권한 방식이 있지만 RBAC를 가장 많이 사용함. 여러 API 기능에 대한 세밀한 접근을 제어할 수 있음
    • 세관 또는 국격 경비대(어드미션 컨트롤러)
      • 어드미션 컨트롤러는 정의된 규칙과 정책에 기반해 API에 대한 요청을 승인, 거절, 변경함. 파드시큐리티(PodSecurity), 리소스쿼터, 서비스어카운트(ServiceAccount) 컨트롤러와 같은 내장된 어드미션 컨트롤러가 있음. 또한 검증과 변형 어드미션 컨트롤러를 이용해 동적 컨트롤러를 만들 수 있음
    • RBAC 기초
      • 쿠버네티스 RBAC 단계에서 정의해야 할 세 가지 주요 컴포넌트는 대상, 규칙, 롤바인딩
        • 대상
          • 컨포넌트는 대상. 실제로 접근을 확인해야 하는 항목. 대상은 일반적으로 사용자, 서비스 계정, 그룹
          • 기본 인증, x.509 클라이언트 증명, 오픈 아이디 연결 시스템을 사용하는 전달 토큰(bearer token)으로 분류할 수 있음
          • 쿠버네티스에서의 서비스 계정은 사용자 계정과 다름. 네임스페이스에 종속되며 쿠버네티스 내부에 저장됨. 사람이 아닌 프로세스를 나타내기 위해 만들어졌으며 네이티브 쿠버네티스 컨트롤러가 관리함
        • 규칙
          • API로 특정 개체(리소스) 또는 객체 그룹에 실행할 수 있는 기능 목록.
          • 일반적으로 CRUD(생성, 읽기, 갱신, 삭제) 동작 유형과 같지만 추가로 watch, list, exec 기능이 있음
          • 객체는 여러 API 컴포넌트와 연결되며 칸테고리로 분류되어 있음
          • 롤은 정의된 규칙을 적용할 범위
          • 쿠버네티스에는 role과 clusterRole이라는 두 가지 롤이 존재함
          • role은 하나의 네임스페이스에 적용되지만 clusterROle은 모든 네임스페이스에 걸쳐 클러스터 전체에 적용됨
          • kind: Role
            apiVersion: rbac.authorization.k8s.io/v1
            metadata:
              namespace: default
              name: pod-viewer
            rules:
            - apiGroups: [""] # ""는 핵심 API 그룹을 나타냄
              resources: ["pods"]
              verbs: ["get", "watch", "list"]
        • 롤바인딩
          • 롤바인딩은 사용자, 그룹과 같은 대상을 특정 롤에 매핑함
          • 네임스페이스에 특정된 roleBinding과 클러스터 전체에 걸친 clusterRoleBinding
          • kind: RoleBinding
            apiVersion: rbac.authorization.k8s.io/v1
            metadata:
              name: noc-helpdesk-view
              namespace: default
            subjects:
            - kind: User
              name: helpdeskuser@example.com
              apiGroup: rbac.authorization.k8s.io
            roleRef:
              kind: Role # 이것은 Role 또는 ClusterRole이어야 함
              name: pod-viewer # 이것은 바인딩된 Role 또는 ClusterRole의 이름과 일치해야 함
              apiGroup: rbac.authorization.k8s.io
    • RBAC 모범 사례
      • 쿠버네티스에서 실행되도록 개발된 애플리케이션은 대부분 RBAC나 롤바인딩을 필요로 하지 않음. 애플리케이션 코드가 실제로 쿠버네티스 API와 직접 상호작용할 때만 RBAC 설정이 필요함
      • 서비스의 엔드포인트에 따라 설정을 변경하기 위해 쿠버네티스 API에 직접 접근하거나 특정 네임스페이스의 모든 파드를 나열하고자 할 때, 새로운 서비스 계정을 생성해 파드 명세에 명시하는 것이 모범 사례. 그런 다음 목적을 달성하는 데 필요한 최소한의 권한만 가지는 롤을 생성함
      • 오픈 아이디 연결 서비스를 사용해 신원 관리를 함. 필요하다면 이중 인증을 함. 이를 통해 더 높은 수준의 신원 인증을 허용함. 작업을 수행하는 데 필요한 최소한의 권한만 가지는 롤을 사용자 그룹에 매핑함
      • JIT(just in time) 접근 시스템을 사용해 SRE와 운영자, 작업 수행을 위해 단기간 권한 상향이 필요한 사용자들이 구체적인 작업을 할 수 있도록 해야 함. 그 대신에 이러한 사용자는 접속에 대한 강도 높은 감사를 받기 위해 서로 다른 신원을 가져야 하며, 사용자 계정이나 그룹에 바인딩된 롤에 할당된 권한보다 더욱 높은 권한을 가져야 함
      • 쿠버네티스 클러스터에 배포될 CI/CD 도구를 위해 특정 서비스 계정을 사용해야 함. 이렇게 하면 클러스터에 객체를 배포하고 삭제한 사람이 누군지 감사할 수 있음
      • 헬름을 사용하여 애플리케이션을 배포할 경우, 기본 서비스 계정은 kube-system에 배포된 틸러(Tiller)임. 해당 네임스페이스에 대한 범위가 지정된 틸러 전용 서비스 계정을 사용하여 각 네임스페이스에 틸러를 배포하는 것이 좋음.
        • 사전 단계로 헬름 install, upgrade 명령을 실행하는 CI/CD 도구에서 서비스 계정과 배포 대상 네임스페이스를 사용하여 헬름 클라이언트를 초기화함. 서비스 계정 이름은 같아도 상관이 없지만 네임스페이스는 고유한 이름을 가지기를 권장함
        • 서비스 계정과 네임스페이스로 헬름을 초기화하는 예
          • kubectl create namespace myapp-prod
            
            kubectl create serviceaccount tiller --namespace myapp-prod
            
            cat <<EOF | kubectl apply -f -
            kind: Role
            apiVersion: rbac.authorization.k8s.io/v1
            metadata:
              name: tiller
              namespace: myapp-prod
            rules:
            - apiGroups: ["","batch", "extensions", "apps"]
              resources: ["*"]
              verbs: ["*"]
            EOF
            
            cat <<EOF| kubectl apply -f -
            kind: RoleBinding
            apiVersion: rbac.authorization.k8s.io/v1
            metadata:
              name: tiller-binding
              namespace: myapp-prod
            subjects:
            - kind: ServiceAccount
              name: tiller
              namespace: myapp-prod
            roleRef:
              kind: Role
              name: tiller
              apiGroup: rbac.authorization.k8s.io
              EOF
            
            helm init --service-account=tiller --tiller-namespace=myapp-prod
            
            helm install ./myChart --name myApp --namespace myapp-prod --set global. namespace=myapp-prod
      • 시크릿 API의 watch와 list를 필요로 하는 애플리케이션을 제한함. 이렇게 하면 기본적으로 애플리케이션이나 파드를 배포한 사용자가 네임스페이스 안에 존재하는 시크릿을 볼 수 있음. 만약 애플리케이션이 특정 시크릿 때문에 시크릿 API에 접근해야 한다면 직접 할당된 시크릿 이외의 것들에 대한 get 사용을 제한해야 함

지속적 통합, 테스트, 배포

  • CI/CD의 목표는 개발자의 코드 검토부터 운영 롤아웃까지 완전히 자동화된 프로세스를 갖추는 것. 쿠버네티스에 배포된 앱을 수동으로 업데이트하면 오류가 자주 발생함. 설정 표류(configuration drift)를 초래하고 배포 업데이트가 불안정해지며 전반적인 배포 속도가 둔화됨
  • 버전 관리
    • 모든 CI/CD 파이프라인은 애플리케이션 실행 이력과 설정 코드 변경을 관리하는 버전 관리로 시작됨
  • 지속적인 통합
    • CI는 코드 변경을 버전 관리 리포지터리에 지속적으로 통합하는 과정. 코드를 리포지터리에 커밋할 때는 큰 코드 변경을 가끔식 하는 것보다 작은 코드 변경을 자주 하는 것이 나음
    • 코드 변경이 커밋될 때마다 빌드가 실행됨. 이를 통해 실제로 문제가 발생했을 때 빠른 피드백을 얻을 수 있음
    • CI의 대표적인 제품으로는 젠킨스(Jenkins)가 있음
  • 테스트
    • 파이프라인에서 테스트를 실행하는 이유는 코드 변경으로 빌드가 실패할 때 빠르게 피드백을 받기 위해서. 사용 중인 언어에 따라 테스트 프레임워크가 결정됨
  • 컨테이너 빌드
    • 애플리케이션에서 가능한 한 가장 작은 이미지를 빌드하는 데 도움을 줌
    • 다중 단계 빌드
      • 애플리케이션을 실행할 때 불필요한 의존 관계를 제거함
      • 다중 단계 빌드(multistage build)를 이용하면 하나의 도커파일로 애플리케이션 실행에 필요한 정적 바이너리만 포함하는 최종 이미지를 빌드할 수 있음
    • 배포판이 없는 기본 이미지
      • 불필요한 바이너리와 셸(shell)은 이미지에서 제거함. 이미지의 크기를 눈에 띄게 줄일 수 있으며 보안을 강화할 수 있음
      • 배포판이 없는(distroless) 이미지는 셸이 없으므로 이미지에 디버거를 붙일 수 없다는 단점을 가짐
      • 패키지 관리자, 셸, 기타 일반적인 OS 패키지가 없기 때문에 일반적인 OS에서 친숙한 디버그 도구를 사용할 수 없음
    • 최적화된 기반 이미지
      • OS 계층에서 불필요한 것을 제거하고 군살을 뺀 이미지
      • 기반 이미지는 개발할 때 필요한 기능을 제공하면서 이미지 크기 최적화와 보안 위험도 낮추기 때문에 훌륭한 선택지
  • 컨테이너 이미지 태그
    • 도커 이미지를 빌드하여 배포할 이미지 산출물을 만드는 것
    • 운영에 배포한 이미지의 버전을 쉽게 분별하기 위한 이미지 태그 전략을 세우는 것이 중요함. 가장 중요한 것 중 하나는 latest를 이미지 태그로 사용하지 않는 것. 이것은 버전이 아니므로 롤아웃 이미지의 어떤 코드가 변경된 건지 파악할 수 없음
    • CI 파이프라인에서 빌드된 모든 이미지는 고유한 태그를 가져야 함.
    • 전략을 이용하면 코드 변경 및 빌드를 쉽게 파악할 수 있음
      • BuildID : CI 빌드를 시작할 때 연관된 BuildID가 생성됨. 태그의 일부로 이 값을 쓰면 어떤 빌드에서 이미지가 만들어졌는지 알 수 있음
      • 빌드 시스템-BuildID : 여러 빌드 시스템이 존재한다면 BuildID에 빌드 시스템을 추가함
      • 깃 해시 : 새로운 코드를 커밋하면 깃 해시가 생성됨. 이 값을 태그에 사용하면 이미지를 생성한 커밋을 쉽게 알 수 있음
      • 깃 해시-BuildID : 이미지를 생성한 커밋과 BuildID를 알 수 있음. 태그가 길 수 있다는 점에 유의함
  • 지속적 배포
    • 컨테이너는 변경 사항을 배포하는 데 큰 이점을 제공함. 컨테이너 이미지가 개발, 스테이지, 운영으로 옮겨갈 수 있도록 불변 객체가 되는 것.
      • 예를 들어 일관된 환경을 유지하는 것은 항상 중요한 이슈
      • 스테이지에서는 잘 동작하던 디플로먼트가 운영으로 옮겨간 후 배포에 실패하는 경우가 많음. 이는 환경 사이의 라이브러리와 컴포넌트 버전 차이, 다시 말해 설정 표류 때문. 쿠버네티스에서는 디플로이먼트 객체의 벚전과 배포일관성을 위한 선언적인 방법을 제공함
  • 배포 전략
    • 쿠버네티스는 애플리케이션의 새로운 버전을 롤아웃 하기 위한 여러 가지 전략을 제공함. 롤링 업데이트를 제공하는 기본 제공 메커니즘이 있지만 더 나은 고급 전략이 있음
      • 롤링 업데이트
        • 쿠버네티스에 내장되어 있는 롤링 업데이트를 사용하면 현재 실행 중인 애플리케이션을 다운타임 없이 업데이트 할 수 있음
        • 디플로이먼트 객체를 사용하면 한 번에 업데이트할 최대 레플리카 수와 사용할 수 없는 최대 파드 수를 롤아웃 과정에서 설정할 수 있음
        • 롤링 업데이트를 사용하면 클라이언트와 연결이 끊어질 수 있으므로 주의해야 함.이를 해결하기 위해 준비성 프로브(readiness probe)와 preStop 라이프사이클 훅을 사용할 수 있음.
          • 준비성 프로브는 배포된 새로운 버전이 트래픽을 수용할 준비가 되었는지 확인하고 preStop 훅은 현재 배포된 애플리케이션의 커넥션을 드레인(drain)함. 이 훅은 컨테이너가 종료되기 전에 동기 방식으로 호출되므로 마지막 종료 신호를 받기 전에 완료되어야만 함
      • 블루/그린 배포
        • 블루/그린 배포를 사용해 예측 가능한 방식으로 애플리케이션을 릴리스할 수 있음.
        • 블루/그린 배포는 트래픽이 새로운 환경으로 전환되는 시점을 조절할 수 있으므로 새 버전의 애플리케이션 롤아웃을 효과적으로 통제할 수 있음
        • 몇 가지 주의할 사항
          • 데이터베이스 마이그레이션이 어려울 수 있음. 진행 중인 트랜잭션과 스키마 업데이트의 호환성을 고려해야 하기 때문
          • 두 환경을 우연히 삭제할 위험이 있음
          • 두 환경을 위한 추가적인 용량이 필요함
          • 하이브리드(hybrid) 배포의 경우 레거시 앱에서 발생하는 문제를 해결해야 함
      • 카나리 배포
        • 블루/그린 배포와 상당히 유사하지만 신규 배포로 트래픽을 전환하는 것에 대해 다양한 통제권을 제공함
        • 최신 인그레스 구현은 신규 배포로 전달할 트래픽의 비율을 정할 수 있는 기능이 있음. 배포 전략 구현에 필요한 여러 기능을 제공하는 이스티오, 링커디, 해시코프의 콘솔(Consul)과 같은 서비스 메시(service mesh) 기술을 구현할 수 있음
        • 카나리 배포에서는 일부 사용자에게만 새로운 기능을 테스트할 수도 있음
        • 추가 고려 사항
          • 일부 사용자에게만 트래픽을 전환하는 기능
          • 신규 배포 상태와 비교하기 위한 안정된 상태에 대한 확고한 지식
          • 신규 배포가 좋은 또는 나쁜 상태인지 알 수 있는 메트릭
        • 카나리 배포는 동시에 여러 버전의 애플리케이션을 실행할 때 어려움을 겪음. 예를 들어 데이터베이스 스키마는 두 버전의 애프릴케이션을 동시에 지원해야 함. 그래서 이 전략을 사용할 때는 의존된 서비스를 다루는 방법과 여러 버전을 실행하는 법을 제대로 파악해야 함
  • 운영에서 테스트
    • 위험을 줄이면서 시스템을 효과적으로 테스트하려면 많은 도구를 구현해야 함. 분산 추적(distributed tracing), 인스투르먼테이션(instrumentation), 카오스 엔지니어링(chaos engineering), 트래픽 섀도(traffic shadow)가 필요함
      • 카나리 배포
      • A/B 테스트
      • 트래픽 전환
      • 기능 플래그
    • 카오스 엔지니어링은 넷플릭스에서 개발했음. 실제 생산 시스템에 실험을 배치해 그 시스템 내의 취약점을 발견하는 것. 통제된 실험 환경에서 시스템의 동작을 관찰하고 파악할 수 있음
    • 구현하고자 하는 내용
      • 가설을 세우고 안정된 상태를 파악함
      • 시스템에 영향을 미치는 현업의 다양한 이벤트를 모음
      • 통제 그룹을 구축하고 안정된 상태와 비교하는 실험을 함
      • 실험을 수행해 가설을 세움
    • 스테이지에서 테스트하면 안 되나요? 의문의 근본적인 문제
      • 리소스 배포의 불일치
      • 운영과의 설정 차이
      • 모의 트래픽과 사용자 행위
      • 현업 워크로드와 유사한 요청을 재현하지 못함
      • 모니터링이 빈약함
      • 배포된 데이터 서비스는 운영과 다른 데이터와 부하를 가짐
  • CI/CD 모범 사례
    • CI를 이용한 자동화와 빠른 빌드에 집중하세요. 빌드 속도를 최적화한다면 변경된 코드가 실패했을 때 빠른 피드백을 얻을 수 있음
    • 파이프라인에서 안정적으로 테스트하는 데 초점을 두세요. 코드에 문제가 생겼을 때 개발자에게 빠른 피드백을 줄 수 있음. 빠른 피드백 반복은 워크플로의 생산성을 향상시킴
    • CI/CD 도구를 결정했다면, 파이프라인을 코드로 정의할 수 있는지 확인하세요. 애플리케이션 코드로 파이프라인 버전 관리를 할 수 있음
    • 이미지 최적화가 되었는지 확인하세요. 이미지 크기를 줄이고, 운영에서 실행할 때 보안상 취약한 지점이 있다면 없애야 함. 다단계 도커 빌드를 사용하면 애플리케이션 실행에 불필요한 패키지를 제거할 수 있음. 예를 들어 애플리케이션을 빌드할 때는 메이븐이 필요하지만 실제로 이미지를 실행할 때는 필요하지 않음
    • latest 이미지 태그를 사용하지 마세요. BuildID와 깃 커밋을 참조할 수 있는 태그를 사용해야 함
    • CD가 익숙하지 않다면 쿠버네티스 롤링 업그레이드를 사용하세요. 사용하기 쉽고 배포가 편리함. CD에 능숙해지고 자신감이 생기면 블루/그린 배포와 카나리 배포 전략을 사용하세요
    • CD를 이용해 클라이언트 연결과 데이터베이스 스키마가 어떻게 업그레이드되며 애플리케이션에서 어떻게 처리되는지를 꼭 테스트하세요
    • 운영 테스트는 애플리케이션의 안정성에 도움을 줌. 훌륭한 모니터링이 가동 중인지 확인하세요. 또한 소규모로 시작하고 실험의 폭발 반경을 제한하세요

버전, 릴리스, 롤아웃

  • 전형적인 모놀리식 애플리케이션은 시간이 흐르면서 규모가 방대해지기 때문에 비즈니스 요구사항의 속도에 맞춰 업그레이드, 버전 관리, 변경을 하기가 어려움. 이로 인해 애자일 개발과 마이크로서비스 아키텍처가 등장하게 되었음
  • 신규 코드를 빠르게 반영하고, 새로운 문제를 해결하고, 심각한 상황이 오기 전에 잠재된 문제를 고치고, 중단 업그레이드를 보장하는 것은 끊임없이 변화하는 인터넷 세상에서 모든 개발 팀이 추구하는 목표
  • 시스템의 규모가 커지고 불안정해지면 엔지니어는 릴리스, 업그레이드, 장애 탐지할 수 있는 복잡한 자동화 프로세스를 구축해야 함. 이를 위해 아파치 메소스, 해시코프 노마드(Nomad)와 같은 서비스 오케스트레이터, 쿠버네티스와 Docker Swarm과 같은 컨테이너 기반 오케스트레이터는 각자의 런타임에 자동화 관련 기본 컴포넌트를 제공함. 즉, 애플리케이션의 버전 관리, 릴리스, 배포가 시스템의 일부로 포함되면서 시스템 엔지니어가 더 복잡한 문제를 해결할 수 있게 되었음
  • 버전
    • 시멘틱 버전은 기본적으로 세 개의 버전 숫자로 이루어짐.
    • 메이저 버전, 마이너 버전, 패치 버전이며 보통 1(메이저).2(마이너).3(패치)과 같이 점 표기로 표현함
    • 패치 버전은 버그 수정이나 API 변경이 없는 사소한 수정마다 증가함. 마이너 버전 업데이트는 API 변경이 있더라도 이전 버전과 하위 호환이 가능함
    • 메이저 버전 업그레이드는 대규모 코드 변경을 의미함. 대부분 메이저 버전 사이의 API는 호환되지 않음
  • 릴리스
    • 쿠버네티스에는 릴리스 컨트롤러가 없음. 릴리스와 관련된 기본 개념이 없는 것. 대신 보통 디플로이먼트 metadata.labels 명세나 pod.spec.template.metadata.label 명세에 릴리스 정보를 넣음. 넣는 시점이 중요하며 CD를 사용해 변경 사항을 디플로이먼트에 업데이트하는 방법에 따라 다양한 영향을 미칠 수 있음
    • 헬름이 처음으로 도입되었을 때 주요 개념 중 하나는 클러스터에서 실행 중인 인스턴스를 구별하기 위한 릴리스 개념이었음
    • 헬름 자체적으로 릴리스 내역을 추적하므로 많은 CD 도구가 헬름을 파이프라인에 통합하여 릴리스 서비스를 제공함
  • 버전, 릴리스, 롤아웃 모범사례
    • 애플리케이션 전체에 시맨틱 버전을 적용하세요. 컨테이너 버전과 파드 배포 버전은 다름. 컨테이너와 애플리케이션 자체도 독립적인 라이프사이클을 가짐
    • 디플로이먼트 메타데이터 내의 릴리스와 릴리스 버전/숫자 레이블을 사용해 CI/CD 파이프라인 릴리스를 추적하세요. 릴리스 이름과 숫자는 CI/CD 도구 레코드의 실제 릴리스와 연계되어야 함. 이를 통해 클러스터에서 CI/CD 과정을 추적할 수 있으며 롤백을 쉽게 식별할 수 있음
    • 디플로이먼트 패키지 서비스로 헬름을 사용하고 있다면, 헬름 차트와 함께 롤백이 되거나 업그레이드될 서비스를 함께 묶을 수 있도록 각별히 주의하세요. 이를 통해 애플리케이션의 모든 컴포넌트를 쉽게 롤백하여 업그레이드 이전으로 되돌리 수 있음
      • 헬름은 YAML 설정을 전달하기 전에 템플릿과 모든 헬름 지시자(directive)를 처리하기 때문에, 라이프사이클 훅을 적절하게 사용해 애플리케이션 템플릿 순서를 지정할 수 있음
      • 운영자는 헬름 라이프사이클 훅을 적절하게 사용하여 업그레이드와 롤백이 올바르게 실행되도록 보장할 수 있음. 쿠버네티스 TTL 컨트롤러의 정식 버전이 출시될 때까지는 Job을 수동으로 삭제해야 함
    • 조직의 운영 흐름에 맞는 릴리스 명명법(nomenclature)을 합의하세요. stable, canary, alpha만으로도 대부분 충분함

글로벌 애플리케이션 분산과 스테이지

  • 컨테이너와 쿠버네티스를 사용하더라도 빛의 속도를 따라갈 수 없기 때문에, 레이턴시를 최소화하기 위해서는 애플리케이션을 전 세계에 분산하여 사용자와의 물리적인 거리를 좁혀야 함
  • 글로벌 배포의 가장 흔한 이유는 지역성임. 대역폭(예를 들어 원격 감지 플랫폼)이나 데이터 프라이버시(지역적 제한)의 이유로, 애플리케이션을 가능하게 만들기 위해 특정 리전에 배치해야 하는 경우가 있음
  • 이미지 분산
  • 배포 파라미터화
  • 글로벌 트랙픽 로드 밸런스
  • 안정적 글로벌 롤아웃
    • 사전 롤아웃 검증
      • 부하 테스트 과정에서 리소스 사용량(CPU, 메모리, 네트워크, 디스크)을 살펴봐야 함
      • 과도한 리소스 사용 증가는 애플리케이션의 품질과 가용성에 영향을 줌. 상황에 따라 릴리스를 운영에 계속해서 배포할 수 있지만, 이때 리소스 사용량이 변경되는 이유를 이해해야 함
    • 카나리 리전
      • 카나리 리전은 릴리스를 검증하려는 곳으로부터 현업 트래픽을 받는 디플로이먼트
      • 트래픽을 보내는 곳은 해당 서비스에 의존하는 내부 팀이거나 서비스를 사용하는 외부 고객일 수 있음. 카나리 리전의 목적은 이러한 사람들에게 롤아웃이 장애를 일으킬 수 있다는 조기 경고를 주는 것
      • 통합 테스트와 부하 테스트가 아무리 훌륭하더라도 사용자와 고객에게 치명적인 모든 버그를 발견할 수는 없음. 하지만 모든 사람이 실패 확률이 높다는 것을 이해하는 공간에서 서비스를 사용하고 배포한다면 문제를 발견하는 것이 쉬울 것. 이러한 공간이 바로 카나리 리전
    • 글로벌 롤아웃 구축
      • 모든 리전의 특성을 파악했다면 이제 롤아웃 계획을 세움.
      • 운영에 주는 영향을 최소화하고자 하므로, 가장 먼저 카나리 리전이나 사용자 트래픽이 적은 리전을 시작점으로 고려하는 것이 좋음. 이러한 리전은 문제가 발생할 가능성이 매우 적으며 혹시 문제가 발생하더라도 트래픽이 적으니 영향도 작음
      • 첫 운영 리전으로의 롤아웃을 성공했다면 다음 리전으로 넘어가기 전까지 얼마나 오래 기다릴지 대기 시간을 정해야 함. 대기하는 이유는 일부러 릴리스에 지연을 주기 위해서가 아니라, 불에서 연기가 날 때까지 충분한 시간이 필요하기 때문
      • 대기 시간은 일반적으로 롤아웃이 완료되고 모니터링에서 문제의 징후가 보일 때까지 걸리는 시간
      • 예를 들어 메모리 누수의 경우, 모니터링에서 인지하거나 사용자에게 영향을 미칠 때까지 한 시간 이상이 걸릴 수 있음
      • 트래픽이 적은 카나리 리전에 성공적으로 롤아웃했다면 이제 트래픽이 많은 카나리 리전에 롤아웃할 시간
    • 글로벌 롤아웃 모범 사례
      • 이미지를 전 세계에 분산시키세요. 성공적인 롤아웃을 위해서는 릴리스 비트(바이너리, 이미지 등)가 사용할 위치와 가까이 존재해야 함. 이는 네트워크가 지연되거나 불규칙한 상황에 놓일 경우 롤아웃의 안정성을 보장함. 지역 분산은 일관된 보장을 위해 릴리스 자동화 파이프라인에 포함되어야 함
      • 최대한 광범위한 통합 및 재현 테스트를 수행하세요. 정상적으로 동작할 것이라는 확고한 믿음이 있는 릴리스만 롤아웃해야 함
      • 카나리 리전에서 릴리스를 시작하세요. 카나리 리전은 대규모 롤아웃을 시작하기 전에 다른 팀이나 대규모 고객이 직접 서비스를 사용하여 검증할 수 있는 사전 운영 환경임
      • 롤아웃하려는 리전의 다양한 특성을 파악하세요. 각각의 차이는 전체 혹은 일부의 중단 원인이 될 수 있음. 위험도가 낮은 리전에서부터 롤아웃을 시도해야 함
      • 발생할 수 있는 문제의 대응과 절차(예를 들어 롤백)에 대해 문서화하고 연습하세요. 긴급한 상황에서 무엇을 수행해야 하는지 제대로 기억해야 문제가 악화되는 것을 막을 수 있음

리소스 관리

  • 쿠버네티스 스케줄러
    • 쿠버네티스 스케줄러는 컨트롤 플레인에서 호스팅되는 핵심 컴포넌트. 스케줄러는 파드를 클러스터에 어떻게 배치할지를 결정함
    • 클러스터와 사용자가 정의한 제약에 따라 리소스를 최적화함. 그리고 논리 조건과 우선순위 기반의 스코어 알고리즘을 사용함
    • 논리 조건
      • 쿠버네티스가 스케줄링할 노드를 결정할 때 사용하는 첫 번째 기능은 논리 조건 함수. 이는 강한 제약을 내포하고 있으므로 참 또는 거짓을 반환함
      • 파드가 4GB 메모리를 요청할 때 특정 노드가 이 요건을 만족하지 못한다고 가정해봄. 이 노드는 거짓을 반환하고 파드 스케줄링 후보에서 제거됨. 노드가 스케줄링 불가로 설정된 상태라면 마찬가지로 후보에서 제거됨
      • 스케줄러는 제한성과 복잡성을 기반으로 논리 조건을 확인함
    • 우선 순위
      • 논리 조건에서는 참과 거짓으로 노드를 스케줄링에서 제외하지만, 우선순위에서는 상대적인 값을 기반으로 모든 유효한 노드의 순위를 매김
      • 노드가 같은 우선순위를 반환한다면 스케줄러는 selectHost() 함수를 사용하여 라운드 로빈 토너먼트(round-robin tournament) 방식으로 노드를 선정함
  • 고급 스케줄링 기술
    • 대부분의 경우, 쿠버네티스는 스스로 파드 스케줄링을 최적화함. 쿠버네티스는 넉넉한 리소스를 가진 노드에게만 파드를 배치함
    • 균등한 리소스 사용률을 유지하면서 레플리카셋의 파드를 여러 노드에 분산시켜 가용성을 높임
    • 파드어피니티와 안티어피니티
      • 파드어피니티와 안티어피니티로 파드 간의 배치 규칙을 설정할 수 있음. 이를 통해 스케줄링 방식을 변경하거나 배치 결정을 오버라이드할 수 있음
      • 예를 들어 안티어피니티 규칙으로 레플리카셋의 파드를 여러 데이터 센터 영역에 분산시킬 수 있음. 파드에 특정 키 레이블만 설정하면 됨. 동일한 노드에 파드를 스케줄링하거나 (파드어피니티) 그렇게 되지 않도록 할 수 있음(안티어피니티)
    • 노드 셀렉터
      • 노드 셀렉터는 특정 노드에 파드를 스케줄링 하는 가장 간단한 방식. 키/값 쌍이 있는 레이블 셀렉터를 사용하여 스케줄링을 결정함
      • 노드 셀렉터는 GPU가 가용한 노드를 요청할 때 사용되지만 노드 테인트는 오직 GPU 워크로드를 위한 용도로 노드를 제한할 때만 사용함. 둘을 동시에 사용하여 GPU 워크로드 전용 노드를 예약하고 노드 테인트를 사용하여 GPU가 있는 노드를 자동으로 선택할 수 있음
      • kubectl label node <node_name> disktype=ssd
      • apiVersion: v1
        kind: Pod
        metadata: 
          name: redis
          labels:
            env: prod
        spec:
          containers:
          - name: frontend
            image: nginx:alpine
            imagePullPolicy: IfNotPresent
          nodeSelector:
            disktype: ssd 
      • 테인트와 톨러레이션
        • 테인트는 파드가 스케줄링되는 것을 거절하기 위해 노드에 사용됨
        • 테인트는 다른 방식과 용도로 쓰임
          • 예를 들어 특정 노드에 특정 성능 요건을 가진 파드만 필요하고 그 외의 다른 파드는 스케줄링하지 않으려는 상황.
          • 테인트는 톨러레이션과 함께 동작함. 이는 테인트된 노드를 오버라이드함. 두 조합으로 안티어피니티 규칙을 세밀하게 조정할 수 있음
        • 테인트와 톨러레이션을 사용하는 일반적 사례
          • 특수한 하드웨어를 가진 노드
          • 전용 노드 리소스
          • 성능이 낮은 노드 회피
        • 스케줄링과 실행 중인 컨테이너와 관련해 여러 테인트 타입
          • NoSchedule : 톨러레이션이 일치하지 않는 파드가 스케줄링되는 것을 막는 강한 테인트
          • PreferNoSchedule: 다른 노드에 스케줄링될 수 없는 파드만 스케줄링
          • NoExecute: 노드에 이미 실행 중인 파드를 축출(evict)
          • NodeCondition: 특정 조건을 만족시키는 노드를 테인트
  • 파드 리소스 관리
    • 파드 리소스를 관리한다는 것은 전반적인 CPU와 메모리 사용률을 관리하여 쿠버네티스 클러스터의 활용도를 최적화하는 것을 의미함. 이 리소스를 컨테이너 수준과 네임스페이스 수준으로 관리할 수 있음
    • 스케줄러가 리소스를 최적화 하고 지능적으로 배치하려면 애플리케이션의 요구사항을 잘 파악해야 함
    • 리소스 제한과 파드 서비스 품질
    • apiVersion: v1
      kind: pod
      metadata: 
        name: cpu-demo
        namespace: cpu-example
      spec:
        containers:
        - name: frontend
          image: nginx:alpine
          resources:
            limits:
              cpu: "1"
            requests:
              cpu: "0.5"
      
      apiVersion: v1
      kind: Pod
      metadata:
        name: qos-demo
        namespace: qos-example
      spec:
        containers:
        - name: qos-demo-ctr
          image: nginx:alpine
          resources:
            limits:
              memory: "200Mi"
              cpu: "700m"
            requests:
              memory: "200Mi"
              cpu: "700m"
      • 파드가 생성되면 다음 QoS 중 하나가 할당됨
        • 보장
          • CPU와 메모리 모두 요청과 제한이 일치하면 보장 QoS이 할당됨
        • 폭발
          • 제한이 요청보다 높게 할당될 때. 컨테이너는 요청을 보장받지만 제한까지만 치솟을 수 있음
        • 최선의 노력
          • 요청 또는 한계를 설정하지 않으면 최선의 노력 QoS가 할당됨
      • 보장 QoS이고 파드에 여러 컨테이너가 존재하는 경우, 컨테이너별로 메모리 요청과 제한을 설정해야 함. 또한 CPU 요청과 제한도 설정해야 함. 모든 컨테이너에 요청과 제한이 설정되지 않으면 보장 QoS 할당되지 않음
    • PodDisruptionBudget
      • 자발적 중단과 비자발적 중단
        • 비자발적 중단은 하드웨어 장애, 네트워크 분할, 커널 패닉(panic), 리소스 부족 등으로 인해 일어남.
        • 자발적 축출은 클러스터 유지보수, 클러스터 오토스케일러의 할당해제, 파드템플릿 업데이트로 인해 발생함. 애플리케이션이 미치는 영향을 최소화하려면 PodDisruptionBudget을 설정하여 파드가 축출될 때 애플리케이션의 가동 시간을 보장하세요
        • PodDisruptionBudget으로 자발적 축출 이벤트 기간에 가용한 최소 파드와 불가용한 최대 파드 정책을 설정할 수 있음. 노드 유지보수 때문에 드레인하는 경우를 자발적 축출의 예시로 볼 수 있음
    • 네임스페이스를 사용한 리소스 관리
      • 네임스페이스는 쿠버네티스에 배포된 리소스를 논리적으로 구분할 수 있음.
      • 네임스페이스별로 리소스쿼터, RBAC, 네트워크 정책을 설정할 수 있음. 멀티테넌시기능으로 팀이나 애플리케이션에 전용 인프라를 지정하지 않고도 워크로드를 분리할 수 있음
      • 쿠버네티스 클러스터를 배포한 이후 네임스페이스
        • kube-system : coredns, kube-proxy, metrics-server와 같은 쿠버네티스 내부 컴포넌트는 여기에 배포딤
        • default : 리소스 객체 안에 네임스페이스를 지정하지 않을 때 사용되는 기본 네임스페이스
        • kube-public : 익명이나 인증되지 않은 콘텐츠, 예약된 시스템에 사용됨
    • 리소스쿼터
      • 여러 팀과 애플리케이션이 단일 클러스터를 공유할 때는 네임스페이스에 리소스쿼터를 설정해야 함.
      • 리소스쿼터는 단일 네임스페이스가 할당된 리소스 이상을 사용할 수 없도록 클러스터를 논리적인 단위로 분배함
        • 계산 리소스
          • request.cpu: CPU 요청의 합은 이 값을 초과할 수 없음
          • limits.cpu: CPU 제한의 합은 이 값을 초과할 수 없음
          • request.memory: 메모리 요청의 합은 이 값을 초과할 수 없음
          • limit.memory: 메모리 제한의 합은 이 값을 초과할 수 없음
        • 스토리지 리소스
          • requests.storage: 스토리지 요청의 합은 이 값을 초과할 수 없음
          • persistentvolumeclaims: 네임스페이스에 존재할 수 있는 퍼시스턴트볼륨클레임의 합은 이 값을 초과할 수 없음
          • storageclass.request: 특정 스토리지클래스와 연관된 볼륨클레임은 이 값을 초과할 수 없음
          • storageclass.pvc: 네임스페이스에 존재하는 퍼시스턴트볼륨클레임 합은 이 값을 초과할 수 없음
        • 객체 카운트 쿼리의 예
          • 카운트/pvc
          • 카운트/서비스
          • 카운트/디프롤이먼트
          • 카운트/레플리카셋
        • 쿠버네티스에서 네임스페이스별로 리소스쿼터를 정교하게 분할할 수 있음. 이를 통해 멀티테넌트 클러스터에서 리소스 사용을 보다 효율적으로 조절할 수 있음
        • apiVersion: v1
          kind: ResourceQuota
          metadata:
            name: mem-cpu-demo
            namespace: team-1
          spec:
            hard:
              requests.cpu: "1"
              requests.memory: 1Gi
              limits.cpu: "2"
              limits.memory: 2Gi 
              persistentvolumeclaims: "5"
              requests.storage: "10Gi"
        • 리소스쿼터가 디플로이먼트에 어떤 영향을 미치는지 보기 위해 애플리케이션을 배포함
        • kubectl run nginx-quotatest --image=nginx --restart=Never --replicas=1 --port=80 --requests='cpu=500m,memory=4Gi' --limits='cpu=500m,memory=4Gi' -n team-1
        • 디플로이먼트는 다음 오류를 출력하며 실패함. 2Gi 메모리 쿼터를 초과했기 때문
        • Error from server (Forbidden): pods "nginx-quotatest" is forbidden: exceeded qoota: mem-cpu-demo
    • 클러스터 확장
      • 클러스터 자동 확장
        • 쿠버네티스는 클러스터의 최소 가용 노드와 최대 가용 노드를 설정할 수 있는 부가 기능인 클러스터 오토스케일러를 제공함. 오토스케일러는 대기 상태의 파드가 존재할 때 확장을 결정함
          • 예를 들어 쿠버네티스 스케줄러가 4,000Mib의 메모리 요청을 가진 파드를 스케줄링하려고 할 때 클러스터는 2,000Mib만 가용한다면 파드는 대기 상태가 됨. 나중에 새로운 노드가 클러스터에 추가되는 즉시, 대기 중인 파드가 스케줄링됨
        • 클러스터 오토스케일러의 단점은 파드가 대기 상태가 되어야 새로운 노드가 추가된다는 것. 워크로드가 온라인이 되려면 결국 새로운 노드를 대기해야 함. 쿠버네티스 v1.15 이후부터는 클러스터 오토스케일러가 사용자 정의 메트릭 기반의 확장을 지원하지 않음
        • 클러스터 오토스케일러가 더는 리소스가 필요 없는 클러스터의 크기를 줄일 수도 있음. 리소스가 필용 없는 경우, 노드를 드레인하고 파드를 새로운 노드에 다시 스케줄링함. 드레인이 수행될 때 애플리케이션에 악영향을 주지 않도록 PodDisruptionBudget을 사용해야 함
    • 애플리케이션 확장
      • 디플로이먼트 안의 레플리카 수를 수동으로 변경하여 애플리케이션을 확장할 수 있음. 레플리카셋이나 복제 컨트롤러를 통해 변경할 수 있지만, 권장하지 않음
      • 수동 확장은 정적인 워크로드 또는 워크로드가 급증하는 시점을 알고 있을 때 유용함
      • 쿠버네티스는 자동으로 워크로드를 확장할 수 있는 HPA를 제공함
    • HPA를 이용한 확장
      • 쿠버네티스 HPA는 CPU, 메모리, 사용자 정의 메트릭 기반으로 디플로이먼트를 확장할 수 있음. 디플로이먼트를 감시하여 쿠버네티스 metrics-server로부터 메트릭을 풀함
      • 가용 파드의 최소 수, 최대 수를 설정함. 예를 들어 최소 수 3, 최대 수 10으로 HPA 정책을 정의한다면 디플로이먼트가 80% CPU 사용률에 도달했을 때 확장됨. 애플리케이션 버그나 이슈 때문에 HPA가 레플리카를 무한정 늘리지 않도록 하려면 최소 수와 최대 수를 설정하는 것이 중요함
      • HPA는 메트릭 동기화, 레플리카 확장과 축소를 위한 기본 설정
        • horizontal-pod-autoscaler-sync-period: 메트릭 동기화 시간은 기본 30초
        • horizontal-pod-autoscaler-upsclae-delay: 두 확장 사이의 레이턴시는 기본 3분
    • 수직 파드 오토스케일러
      • VPA는 레플리카를 확장하지 않으므로 HPA와 다름. 대신 자동으로 요청을 늘림
      • 아키텍처로 인해 확장할 수 없는 워크로드의 경우 자도응로 리소스를 확장하는 데 효과적
      • VPA는 HPA보다 더 복잡하며 세 가지 컴포넌트를 가짐
        • Recommender: 현재와 과거의 리소스 사용량을 모니터하고 컨테이너의 CPU와 메모리 요청의 추천값을 제공함
        • Updater: 파드가 정확한 리소스를 가지고 있는지 확인하고 그렇지 않으면 종료시킴. 컨트롤러는 업데이트된 요청으로 컨트롤러를 다시 생성함
        • Admission Plugin: 정확한 리소스 요청을 새로운 파드에 설정함
  • 리소스 관리 모범 사례
    • 파드안티어퍼니티를 사용해 워크로드를 여러 가용 영역으로 분산하여 애플리케이션의 고가용성을 보장함
    • GPU가 활성화된 노드와 같은 특수한 하드웨어를 사용하는 경우 ,테인트를 사용해 GPU가 필요한 워크로드만 해당 노드에 스케줄링되도록 함
    • NodeCondition 테인트를 사용하여 노드 실패나 성능 저하를 사전에 방지함
    • 파드 명세에 노드 셀렉터를 적용하여 특수한 하드웨어를 가진 노드에 파드르 스케줄링함
    • 운영으로 이동하기 전에 다양한 노드 크기를 실험하여 비용과 성능의 적절한 조합을 찾음
    • 다양한 성능 특성을 지닌 워크로드가 혼재되어 있다면 단일 클러스터에 노드 유형이 섞여 있는 노드 풀을 사용함
    • 클러스터에 배포된 모든 파드에 대해 메모리와 CPU 제한을 설정함
    • 여러 팀 또는 여러 애플리케이션이 공정한 리소스를 할당받을 수 있도록 ResourceQuata를 사용함
    • 제한과 요청이 설정되지 않은 파드 명세에 기본 제한과 요청을 설정하기 위해 LimitRange를 구현함
    • 쿠버네티스의 워크로드 프로필을 파악하기 전까지는 수동 클러스터 확장부터 시작함. 자동 확장을 사용할 수도 있지만 노드 기동 시간과 클러스터 축소에 대한 추가적인 고민이 필요함
    • 변동성이 있거나 예상치 못한 정점이 있는 워크로드의 경우에는 HPA를 사용함

네트워킹, 네트워크 보안, 서비스 메시

  • 사실상 쿠버네티스는 서로 연결된 시스템으로 구성된 클러스터의 관리자. 네트워크는 시스템이 통신할 때 핵심 역할을 함
  • 쿠버네티스 네트워크 원칙
    • 동일한 파드 내의 컨테이너 간 통신
      • 동일한 파드 내의 모든 컨테이너는 동일한 네트워크 공간을 공유함. 즉 컨테이너 사이의 localhost 통신이 가능함. 따라서 동일한 파드 내의 컨테이너는 다른 포트를 열어야 함
      • 리눅스 네임스페이스와 도커 네트워크를 통해 이루어짐. 파드의 네트워킹을 담당하는 모든 파드에서 일시 중지된(paused) 컨테이너를 사용해 파드 내의 모든 컨테이너가 동일한 로컬 네트워크에 존재하게 함
    • 파드 간의 통신
      • 모든 파드는 네트워크 주소 변환(NAT,network address translation) 없이 통신할 수 있어야 함. 즉 수신하는 파드에서 볼 수 있는 송신자의 파드 IP 주소가 실제 IP 주소.
      • 사용하는 네트워크 플러그인에 따라 처리 방식이 달라짐
    • 서비스 간의 통신
      • 쿠버네티스의 서비스는 견고한 IP 주소와 포트를 나타내며 각 노드는 서비스에 연계된 엔드포인트로 트래픽을 전달함
      • 의사계측(4pseudo-layer4) 로드 밸런서 기능을 제공하는 iptables로 구현함
  • 네트워크 플러그인
    • SIG(Special Interest Group)에서는 플러그인이 가능한 아키텍처를 지향한 네트워킹 표준을 제시했음. 이 표준을 통해 많은 서드파티 네트워킹 프로젝트가 연동되었으며 쿠버네티스 워크로드에서 향상된 기능을 사용할 수 있게 되었음.
    • 두 개의 네트워크 플러그인
      • 가장 기본적인 것은 쿠버네티스가 제공하는 플러그인인 Kubenet
        • 쿠버네티스에서 바로 사용할 수 있는 가장 기본적인 네트워크 플러그인.
        • 파드가 연결될 가상 이더넷(Ethernet) 쌍인 리눅스 브릿지 cbr0를 제공함. 파드가 연결되면 클러스터 노드에 분산되어 있는 사이더(CIDR, Classless Inter-Domain Routing) 범위 내의 IP 주소를 얻게 됨
        • IP 위장(masquerade) 플래그도 있음. 파드 CIDR 범위 외부의 IP로 전달되는 트래픽이 위장하려면 이 플래그를 설정해야 함
        • 파드 간의 통신 규칙을 따르지 않음. 파드 CIDR 외부로 전달되는 트래픽은 NAT를 거치기 때문. 패킷이 다른 노드로 전송될 때 일종의 라우팅은 이 트래픽을 올바른 노드로 전달하는 역할을 함
        • Kubenet 모범 사례
          • Kubenet으로 가장 단순한 네트워크 스택을 구축할 수 있으며 복잡한 네트워크에서 귀중한 IP 주소를 절약할 수 있음. 대표적으로 온프레미스 데이터 센터에 확장된 클라우드 네트워크
          • 파드 CIDR 범위가 각 클러스터의 파드의 잠재적인 최대 크기를 처리할 만큼 충분히 큰지 확인해야 함. kubelet에 설정된 노드당 기본 파드는 110이지만 이는 조정될 수 있음
          • 적합한 노드의 파드로 트래픽이 전송될 수 있도록 경로 규칙을 이해하고 올바른 계획을 세워야 함. 클라우드 공급자 환경에서는 일반적으로 자동화되지만 온프레미스 또는 예외적인 사례에서는 자동화와 함께 견고한 네트워크 관리가 필요함
      • 컨테이너 네트워크 인터페이스(CNI, Container Network Interface) 명세를 준수하는 플러그인으로 컨테이너를 위한 범용적인 플러그인 네트워크 솔루션
        • CNI 플러그인 명세의 몇 가지 기본적인 요구사항
          • CNI와의 인터페이스, 기본적인 API 동작, 클러스터에서 사용되는 컨테이너 런타임과의 인터페이스
          • 네트워크 관리 컴포넌트는 CNI에 의해 정의되지만, 이들은 모두 IP 주소 관리를 포함해야 하며 적어도 네트워크에 컨테이너 추가와 삭제를 허용해야 함. 이 명세는 rkt 네트워킹 제안서에서 파생되었음
          • 코어 CNI(coreCNI) 프로젝트는 CNI 플러그인 명세의 기본 요구사항을 만족하는 플러그인을 구현할 수 있는 라이브러리를 제공함. 다양한 기능을 수행하는 다른 플러그인을 호출할 수도 있음. 이러한 유연성 때문에 컨테이너 네트워크에 사용할 수 있는 수많은 CNI 플러그인이 만들어졌음
          • CNI 플러그인의 예시로는 클라우드 공급자가 제공하는 마이크로소프트 애저 네이티브 CNI, 아마존 VPC CNI 플러그인부터 전통적인 누아지(Nuage) CNI, 주니어 네트워크 콘트레일/텅스텐 패브릭(Juniper Networks Contrail/Tunsten Fabric), VM웨어(VMware) NSX가 있음
        • CNI 플러그인 모범 사례
          • 애플리케이션 통신의 신뢰성을 보장하려면 쿠버네티스 내의 가상 컴포넌트와 물리적인 네트워크 환경 간의 상호작용을 신중하게 설계해야 함
          • 인프라의 전반적인 네트워킹 목표를 달성하는 데 필요한 기능을 평가해야 함. 일부 CNI 플러그인은 고가용성, 다중 클라우드 연결성, 쿠버네티스 네트워크 정책 지원 등 다양한 기능을 제공함
          • 공개 클라우드 공급자를 통해 클러스터를 실행 중이라면 클라우드 공급자의 소프트웨어 정의 네트워크(SDN, software defined network)가 CNI 플러그인을 실제로 지원하는지 확인해야 함
          • 네트워크 보안 도구, 네트워크 관찰성, 관리 도구가 CNI 플러그인과 호환되는지 확인하고, 그렇지 않다면 대체할 수 있는 도구를 조사해야 함. 쿠버네티스와 같은 대규모 분산 시스템으로 전환할 때는 이러한 필요성이 확대되기 때문에, 관찰성이나 보안 기능에 문제가 없는지 확인해야 함
            • 위브웍스(Weaveworks)의 위브 스코프(Weave Scope), 다이나트레이스(Dynatrace), 시스딕 같은 도구를 쿠버네티스 환경에 추가할 수 있으며 각자의 장점이 있음
              • 애저 AKS, 구글 GCE 또는 아마존 EKS와 같은 클라우드 공급자가 관리하는 서비스에서 실행 중이라면 애저 컨테이너 인사이트, 네트워크 와처(Network Watcher), 스택드라이버, 아마존 클라우드워치와 같은 내장 도구를 사용함
              • 최소한 네트워크 스택과 네가지 황금 신호에 대한 통찰력을 제공하는 도구를 사용해야 함. 네 가지 황금 신호는 레이턴시, 트래픽, 오류, 포화도이며 구글 SRE 팀과 롭 에와스척에 의해 널리 알려졌음
          • SDN 네트워크 공간과 분리된 별도의 오버레이 네트워크를 제공하지 않는 CNI를 사용하는 경우, 노드 IP, 파드 IP, 내부 로드 밸런서와 클러스터 업그레이드, 프로세스 확장에 따른 오버헤드를 감당할 수 있는 적절한 네트워크 주소 공간이 존재하는지 확인해야 함
  • 쿠버네티스의 서비스
    • ClusterIP 서비스 타입
      • 서비스 타입을 명시하지 않을 때 기본값은 ClusterIP
      • ClusterIP는 지정된 서비스 CIDR 범위 내에서 IP가 할당됨을 의미함. 이 IP는 서비스 객체와 함께 오래 지속되므로 셀렉터 필드를 통해 백엔드 파드에 IP, 포트, 프로토콜을 매핑함
      • 테스트 시점에는 클러스터에 없는 데이터베이스를 사용하고 나중에 쿠버네티스에 배포되는 데이터베이스로 서비스를 변경하는 시나리오. 다른 서비스처럼 kube-proxy에 의해 관리되지 않으므로 헤드리스 서비스라고 불림. 엔드포인트를 직접 관리할 수 있음
    • NodePort 서비스 타입
      • NodePort 서비스 타입은 클러스터의 각 노드의 고수준 포트를 각 노드의 서비스 IP와 포트에 할당함. NodePort의 고수준 포트의 범위는 30,000부터 32,767 사이이며 정적으로 할당되거나 서비스 명세 안에 명시할 수 있음
      • NodePort는 일반적으로 자동 로드 밸런스 구성을 제공하지 않는 온프레미스 클러스터 또는 맞춤형 솔루션에서 사용됨. 클러스터 외부에서 서비스에 직접 접근하려면 NodeIP:NodePort를 사용하면 됨
    • ExternalName 서비스 타입
      • ExternalName 서비스 타입은 현업에서 거의 사용되지 않지만, 클러스터 수준의 내구성을 가진 DNS 이름을 외부 DNS 서비스에 전달할 때 유용함
    • 로드 밸런서 서비스 타입
      • 로드 밸런서는 특별한 서비스 타입. 클라우드 공급자나 프로그램이 가능한 클라우드 인프라 서비스를 통해 자동화할 수 있음
      • 쿠버네티스 클러스터의 인프라 공급자가 제공하는 로드 밸런싱 메커니즘을 배포할 수 있는 유일한 방법이 LoadBalancer 타입. LoadBalancer 동작 방식은 AWS, 애저, GCE, 오픈스택 등에서 거의 동일함
      • 일반적으로 공개된 로드 밸런스 서비스를 생성하지만 각 클라우드 공급자의 내부 전용 로드 밸런서, AWS 일래스틱 로드 밸런싱 설정 인자 등과 같은 기능을 활성화하는 특별한 애너테이션이 존재함
      • 서비스 명세에 실제로 사용하는 로드 밸런서 IP와 허용할 소스 범위를 정의할 수 있음
    • 인그레스와 인그레스 컨트롤러
      • 서비스 API로 정의된 서비스는 기본적인 수준인 계층 3/4 로드 밸런싱을 제공함. 실제로 쿠버네티스에 배포된 대부분의 무상태 서비스는 높은 수준의 트래픽 관리가 필요함
      • 일반적으로 애플리케이션 수준의 제어, 특히 HTTP 프로토콜을 관리해야 함
      • 인그레스 API는 HTTP 수준의 라우터로, 호스트와 경로 기반 규칙으로 특정 백엔드 서비스에게 트래픽을 전달함
      • 인그레스 API는 호스트 기반 라우팅을 허용해 단일 인그레스에서 여러 호스트를 지원함. 추가 기능으로 포트 433에서 TLS 종료에 대한 인증서 정보를 가진 쿠버네티스 시크릿을 선언할 수 있음.
      • 경로를 지정하지 않은 경우, 표준 404 오류보다 더 나은 UX를 제공하는 기본 백엔드가 있음
      • 특정 TLS와 기본 백엔드 구성에 대한 세부 사항은 인그레스 컨트롤러가 처리함. 인그레스 컨트롤러는 인그레스 API와 분리되어 있으며 운영자는 NGINX, Traefik, HAProxy 등과 같은 인그레스 컨트롤러를 선택해 배포할 수 있음
      • 이름에서 알 수 있듯이 인그레스 컨트롤러는 다른 쿠버네티스 컨트롤러와 마찬가지로 컨트롤러지만 시스템의 일부가 아니며, 동적 구성을 위한 쿠버네티스 인그레스 API와 인터페이스하는 서드파티 컨트롤러.
      • 가장 대중적인 인그레스 컨트롤러는 NGINX이며 쿠버네티스 프로젝트에서 부분적으로 관리됨
    • 서비스와 인그레스 컨트롤러 모범 사례
      • 클러스터 외부에서 접근하는 서비스의 수를 제한해야 함. 대부분의 서비스는 ClusterIP로 두고 외부 접근 서비스만 노출하는 것이 이상적임
      • 노출해야 하는 서비스가 주로 HTTP/HTTPS 기반이라면 인그레스 API와 컨트롤러를 사용하여 TLS 종료와 함께 트래픽을 서비스로 라우팅하는 것이 가장 좋음. 사용되는 인그레스 컨트롤러 타입에 따라 속도 제한, 헤더 재작성, OAuth 인증, 관찰 가능성 등의 기능을 애플리케이션 자체에 빌드하지 않고도 사용할 수 있음
      • 웹 기반 워크로드의 안전한 수신에 필요한 기능을 가진 인그레스 컨트롤러를 선택해야 함. 하나로 표준화하여 전사적으로 사용하세요. 컨트롤러 구현마다 설정 애너테이션이 다르므로 배포 코드가 쿠버네티스 구현 간에 이식되는 것을 방지해야 함
      • 인프라 관리와 인그레스 부하를 클러스터 외부로 옮길 수 있는 기능이 클라우드 서비스 공급자의 인그레스 컨틀로러에 있는지 평가해야 함. 당연히 쿠버네티스 API 설정도 가능해야 함
      • API를 외부에 주로 제공한다면 API 기반 워크로드를 세부적으로 조절할 수 있는 Kong 또는 앰버서더(Ambassador)와 같은 인그레스 컨트롤러를 평가함. NGINX, Traefik 등도 일부 API 튜닝을 제공하지만 특정 API 프록시 시스템만큼 세밀하지 않음
      • 인그레스 컨트롤러를 쿠버네티스에 파드 기반 워크로드로 배포할 때 고가용성이 설계되었는지 확인하고 처리량의 성능을 집계해야 함. 메트릭을 관찰해 인그레스 규모를 적절하게 확장하고, 워크로드가 확장되는 동안 클라이언트 중단을 막을 수 있는 충분한 대비책이 있어야 함
  • 네트워크 보안 정책
    • 쿠버네티스에 내장된 네트워크폴리시(NetworkPolicy) API를 사용해 워크로드에 정의된 네트워크 수준의 인그레스와 이그레스 접근을 제어할 수 있음
    • 네트워크 정책을 통해 파드 그룹 간 또는 다른 엔드포인트로 통신하는 것을 제어할 수 있음. 네트워크폴리시 명세를 자세히 알아보려면 (쿠버네티스 API로 정의되어 있어서 혼란스러울 수 있지만) 네트워크폴리시 API를 지원하는 네트워크 플러그인이 필요함
    • 네트워크 정책은 단순한 YAML 구조이며 데이터 센터 내의 간단한 트래픽 방화벽으로 볼 수 있음. 정책 명세에는 podSelector, ingress, egress, policyType 필드가 있음. 유일한 필수 필드는 podSelector이며 matchLabels를 가진 쿠버네티스 셀렉터와 동일한 규약을 따름
    • 여러 네트워크폴리시 정의를 파드에 적용하면 효과가 가중됨
    • 네트워크폴리시 객체는 네임스페이스 수준의 객체이므로 podSelector에 셀렉터가 없으면 네임스페이스의 모든 파드에 정책이 적용됨. 인그레스 또는 이그레스 규칙이 정의되어 있으면 파드에 인그레스 또는 이그레스가 허용되는 화이트리스트(whitelist)가 생성됨. 즉 셀렉터와 일치하는 파드에 정책이 적용되면 인그레스 또는 이그레스 규칙에 명시되지 않은 모든 트래픽은 차단됨
    • 셀렉터와 일치하지 않는 파드는 아무런 정책에 속하지 않기 때문에 모든 인그레스와 이그레스가 허용됨. 아무 것도 차단하지 않는 새로운 워크로드를 쿠버네티스에 간단히 배포할 수 있음
    • ingress와 egress 필드는 기본적으로 소스 또는 대상에 대한 규칙 목록으로 특정 CIDR 범위, podSelector, namespaceSelector. 인그레스 필드를 비워두면 모든 인바운드(inbound)는 차단됨. 이그레스를 비워두면 모든 아웃바운드(outbound)는 차단됨. 포트와 프로토콜 목록을 지정하면 허용할 통신 범위를 좁힐 수 있음
    • policyTypes 필드에는 정책 객체와 연관된 네트워크 정책 규칙 타입을 지정함. 해당 필드가 없으면 ingress와 egress 목록 필드를 참조함. 차이점이 있다면 이그레스는 PolicyTypes에 반드시 이그레스를 명시하고 이그레스 규칙 목록도 존재해야 동작한다는 것. 인그레스는 명시적으로 정의할 필요가 없음
    • 단일 네임스페이스에 배포된 세 개의 애플리케이션 계층의 프로토타입 예제를 사용
      • 계체 레이블은 tier: "web", tier: "db", tier: "api". 네트워크폴리시 매니페스트는 각 계층의 트래픽을 적절히 제한함
    • 네트워크 정책 모범 사례
      • 천천히 진행하면서 파드로 인그레스되는 트래픽에 집중하세요. 인그레스와 이그레스 규칙을 복잡하게 만들면 네트워크 추적이 어려워짐. 트래픽이 예상대로 흐르기 시작하면 중요한 워크로드의 흐름을 제어하기 위해 이그레스 규칙을 살펴보세요. 인그레스 명세는 인그레스 규칙 목록이 비어있더라도 많은 옵션을 기본값으로 설정함
      • 사용 중인 네트워크 플러그인에 네트워크폴리시 API에 대한 자체 인터페이스가 있거나 잘 알려진 다른 플러그인을 지원하는지 확인하세요. 플러그인의 예로 캘리코(Calico), 실리움(Clium), Kube-router, 로마나(Romana), 위브넷(Weave Net)이 있음
      • 네트워크 팀이 기본 거부 정책을 자주 사용한다면 보안이 필요한 워크로드를 가진 클러스터의 각 네임스페이스에 다음과 같은 네트워크 정책을 만듬. 이렇게 하면 다른 네트워크 정책을 삭제하더라도 실수로 파드가 노출되지 않음
        • apiVersion: networking.k8s.io/v1
          kind: NetworkPolicy
          metadata:
            name: default-deny-all
          spec:
            podSelector: {}
            policyTypes:
            - Ingress
      • 인터넷에 접근해야 하는 파드가 있는 경우, 레이블을 사용해 수신을 허용하는 네트워크 정책을 명시적으로 적용함. 패킷이 들어오는 실제 IP가 인터넷이 아니라 로드 밸런서, 방화벽, 그 외 네트워크 장치의 내부 IP라면 전체 흐름을 알아야 함. 예를 들어 allow-internet=true 레이블이 있는 파드로 모든 (외부를 포함한) 트래픽을 허용하려면 다음을 수행해야 함
        • apiVersion: networking.k8s.io/v1
          kind: NetworkPolicy
          metadata:
            name: internet-access
          spec:
            podSelector:
              matchLabels:
                allow-internet: "true"
            policyTypes:
            - Ingress
            ingress:
            - {}
      • 정책을 간단하게 만들기 위해 애플리케이션 워크로드를 단일 네임스페이스에 배치하세요. 네임스페이스 간 통신이 필요할 때는 흐름을 식별하기 위해 최대한 명시적인 이름과 구체적인 레이블을 사용하세요
      • apiVersion: networking.k8s.io/v1
        kind: NetworkPolicy
        metadata:
          name: namespace-foo-2-namespace-bar
          namespace: bar
        spec:
          podSelector:
            matchLabels:
              app: bar-app
          policyTypes:
          - Ingress
          ingress:
          - from:
            - namespaceSelector:
                matchLabels:
                  networking/namespace: foo
              podSelector:
                matchLabels:
                  app: foo-app
      • 제한 정책 수가 적은 테스트 네임스페이스를 만들어 정확한 트래픽 패턴을 조사하세요
  • 서비스 메시
    • 서비스 전용 데이터 플레인과 컨트롤 플레인으로 연결하고 보호할수 있는 법을 제어하는 것. 서비스 메시마다 기능이 다르지만 공통적으로 다음 기능들을 제공함
      • 메시에 분산되는 세밀한 트래픽 조절 정책을 통해 트래픽 로드 밸런싱이 가능함
      • 메시 소속 서비스의 디스커버리가 존재함. 서비스에는 클러스터 또는 외부 클러스터의 서비스와 메시 소속의 외부 시스템이 있음
      • 트래픽과 서비스를 관찰할 수 있음. 오픈트레이싱(OpenTracing) 표준을 따르는 예거(Jaeger) 또는 집킨(Zipkin)과 같은 추적 시스템을 사용한 분산 서비스 추적이 있음
      • 상호 인증을 사용한 메시 트래픽 보안이 가능함. 파드 대 파드, 데이터 센터 내의 트래픽 보안, 데이터 센터 보안과 제어를 모두 제공하는 인그레스 컨트롤러가 있음
      • 서킷 브레이커, 재시도, 데드라인 등과 같은 패턴을 이용한 복원력, 상태, 장애 방지 기능을 가짐
    • 모든 기능이 애플리케이션 변경 없이 메시에 속한 애플리케이션에 통합된다는 것
    • 사이드 프록시를 사용함. 현재 가용한 서비스 메시 대부분은 메시 소속인 각 파드에 데이터 플레인의 일부인 프록시를 주입함. 이 프록시를 통해 컨트롤 플레인 컴포넌트는 정책과 보안을 메시 전체에 동기화함
    • 대표적인 서비스 메시는 이스티오. 구글, 리프트(Lyft), IBM의 프젝트이며 엔보이를 데이터 플레인 프록시로 사용하고 독점적인 컨트롤 플레인 컴포넌트인 믹서, 파이롯트, 갤리, 시타델을 사용함. 다양한 수준의 기능을 제공하는 링커디 2도 있음. 링커디 2는 러스트로 구축한 자체적인 데이터 플레인 프록시를 사용함.
    • 해시코프는 최근에 많은 쿠버네티스 중심 서비스 메시 기능을 콘솔에 추가했음. 콘솔 사용자는 콘솔 자체 프록시와 엔보이 중에서 선택할 수 있으며, 서비스 메시에 대한 상업적 지원도 받을 수 있음
    • 서비스 메시 인터페이스(SMI)와 관련해 마이크로소프트, 링커디, 해시코프, 솔로닷아이오, 킨보크, 위브웍스는 의미 있는 노력을 하고 있음. SMI는 서비스 메시 기본 기능에 대해 표준 인터페이스. SMI 명세에는 신원, 전송 수준 암호화, 메시 내의 서비스 간 메트릭을 수집하는 트래픽 원격 분석, 서비스 간 트래픽을 조절하거나 가중치를 변경하는 트래픽 관리와 같은 트래픽 정책을 다룸
    • 서비스 메시 모범 사례
      • 서비스 메시가 제공하는 주요 기능의 중요도를 평가하고, 가장 중요한 기능에서 오버헤드가 가장 적은 서비스 메시를 선택함. 여기서 오버헤드는 인적 기술 부채와 인프라 자원 부채. 특정 파드 사이의 TLS가 필수라면 플러그인에 TLS가 통합된 CNI가 나음
      • 다중 클라우드 또는 하이브리드 시나리오같이 여러 시스템 간 메시가 필수 요건일까요? 모든 서비스 메시가 이 기능을 제공하는 것은 아니며, 기능을 제공한다고 하더라도 환경이 불안정해질 수 있는 복잡한 프로세스
      • 많은 서비스 메시는 오픈 소스 커뮤니티 기반 프로젝트. 환경을 관리할 팀이 서비스 메시에 익숙하지 않다면 상업적 지원이 되는 제품이 더 나음. 이스티오를 기반으로 상업적으로 지원되고 관리되는 서비스 메시를 제공하는 회사도 있음. 이스티오는 관리가 복잡하기 때문에 도움이 될 수 있음

파드와 컨테이너 보안

  • 파드시큐리티폴리시 API
    • 클러스터 수준 리소스인 파드시큐리티폴리시는 파드 명세에서 보안에 민감한 모든 필드를 정의하고 관리할 수 있는 유일한 곳. 파드시큐리티폴리시 리소스를 생성하기 전, 클러스터 관리자와 사용자는 SecurityContext 설정을 워크로드마다 개별적으로 정의해야 함.
    • 클러스터에서 맞춤형 어드미션 컨트롤러를 활성화해 파드 보안을 시행해야 함
    • 파드시큐리티폴리시 모범 사례
      • 모든 것이 RBAC에 달려있음. 파드시큐리티폴리시는 RBAC에 의해 결정됨. RBAC 정책 설계의 결점은 바로 이 관계에서 비롯됨. RBAC와 파드시큐리티폴리시 생성, 유지, 관리의 자동화가 굉장히 중요함. 특히 서비스 계정의 접근을 막는 것이 정책의 핵심
      • 정책의 범위를 파악하세요. 정책을 클러스터의 어디에 적용할지 결정하는 것은 매우 중요함. 클러스터 전체나 네임스페이스, 특정 워크로드가 될 수 있음. 쿠버네티스 클러스터 동작과 관련한 워코르드는 항상 존재함. 이 워크로드는 더 많은 보안 권한이 필요함. 그러므로 허용 정책으로 원치 않는 워크로드를 중지할 수 있는 적절한 RBAC가 있어야 함
      • 기존 클러스터에서 파드시큐리티폴리시를 활성화하고 싶은가요? 편리한 오픈 소스 도구를 사용하여 현재 리소스에 기반한 정책을 생성하세요. 훌륭한 출발.
  • 워크로드 격리와 런타임클래스
    • 런타임클래스는 쿠버네티스 컨테이너 런타임 선택을 가능하게 하는 API. 즉 클러스터 관리자가 구성한 컨테이너 런타임 중 하나를 선택하는 것
    • 쿠버네티스 사용자는 파드 명세의 RuntimeClassName을 사용해 워크로드에 특정 런타임 클래스를 정의할 수 있음
    • 실제로 구현되는 방법은 런타임클래스가 구현할 컨테이너 런타임 인터페이스(CRI)로 전달되는 RuntimeHandler를 지정하는 것. 노드 라벨링 또는 노드 테인트가 노드 셀렉터 또는 톨러레이션과 함께 사용되어 워크로드가 원하는 런타임클래스를 지원하는 노드에 배치됨
    • 런타임 구현
      • 다양한 수준의 보안과 격리를 제공하는 오픈 소스 컨테이너 런타임 구현
        • CRI containerd : 단순화, 견고성, 이식성을 강조한 컨테이너 런타임을 위한 API 퍼샤드(facade)
        • cri-o : 특수한 목적으로 제작된 경량 오픈 컨테이너 이니셔티브(OCI) 기반의 쿠버네티스 컨테이너 런타임 구현
        • 파이어크래커 : 커널 기반 VM 위에 구축되었으며, 이 가상화 기술로 전통적인 VM의 보안과 격리를 사용하여 가상화되지 않은 환경에서 격리된 가상환경인 microVM을 매우 빠르게 시작할 수 있음
        • gVisor : 새로운 사용자 공간 커널로 컨테이너를 실행하는 OCI 호환 샌드박스 런타임으로, 오버헤드가 적고 안전하며 격리된 컨테이너 런타임을 제공함
        • 카타 컨테이너 : 컨테이너와 흡사하게 동작하는 경량 VM을 실행하여 VM과 유사한 보안과 격리를 제공하는 안전한 컨테이너 런타임을 구축하는 커뮤니티
    • 워크로드 격리와 런타임클래스 모범 사례
      • 런타임클래스를 사용하여 다양한 워크로드 격리 환경을 구현하면 운영 환경이 복잡해짐. 컨테이너 런타임마다 격리의 근본적인 특성이 다르기 때문에 워크로드 이식이 어려울 수 있음. 다양한 런타임에 대한 지원 기능 메트릭스를 이해하는 것은 어려우며 UX 저하를 초래할 수 있음. 혼동을 방지하기 위해서는 가급적 단일 런타임을 갖는 개별 클러스터를 보유하는 것이 좋음
      • 워크로드 격리로 멀티테넌시 보안이 유지되는 것은 아님. 안전한 컨테이너 런타임을 구현한다고 해도 쿠버네티스 클러스터와 API까지 동일하게 안전하다는 뜻은 아님. 쿠버네티스의 시작부터 끝까지 전체 영역을 살펴봐야 함. 워크로드가 격리되었다고해서 쿠버네티스 API를 통한 악의적 수정이 불가능한 것은 아님
      • 런타임마다 도구가 다름. 디버깅과 내부 검사에 컨테이너 런타임 도구를 사용하는 사례가 있음. 만약 런타임이 바뀌면 더는 docker ps로 실행 중인 컨테이너를 볼 수 없으므로 문제 해결에 혼란을 줄 수 있음

클러스터 정책과 거버넌스

  • 다른 정책과의 차이
    • 쿠버네티스 리소스 명세에 선언된 모든 것은 해당 정책 정의에 따라 구현되어야 함. 네트워크 정책과 파드 보안 정책은 런타임에 구현됨
    • 거버넌스 맥락에서의 정책은 런타임에 정책을 구현하는 대신 쿠버네티스 리소스 명세 자체의 필드와 값을 제어하는 것을 의미함
  • 클라우드 네이티브 정책 엔진
    • 개방형 정책 에이전트(OPA,open policy agent)는 클라우드 네이티브 생태계에서 대중화되고 있는 유연하고 가벼운 오픈 소스 정책 엔진
    • OPA를 통해 생태계에 다양한 쿠버네티스 거버넌스 도구가 구현되었음. 예를 들면 쿠버네티스 정책과 거버넌스 프로젝트 중 커뮤니티가 형성되고 있는 게이트키퍼(Gatekeeper)가 있음
  • 게이트키퍼 소개
    • 게이트키퍼는 클러스터 정책과 거버넌스 오픈 소스로 사용자 정의가 가능한 쿠버네티스 어드미션 웹훅. 게이트키퍼는 OPA 제약 프레임워크를 활용해 CRD 기반 정책을 시행함으로써 정책 작성과 구현을 분리하는 통합된 쿠버네티스 경험을 제공함
    • 정책 템플릿을 제약 템플릿이라고 하며 여러 클러스터에서 공유하고 재사용할 수 있음. 게이트키퍼는 리소스 검증과 감사 기능을 제공하며 이식성이 뛰어남. 모든 쿠버네티스 클러스터에서 구현할 수 있으며 이미 사용중인 OPA의 정책을 게이트키퍼로 이식할 수도 있음
    • 정책 예제
      • 서비스가 인터넷에 공개적으로 노출되면 안 됨
      • 신뢰할 수 있는 컨테이너 레지스트리의 컨테이너만 허용해야 함
      • 모든 컨테이너에는 리소스 제한이 있어야 함
      • 인그레스 호스트 이름은 겹치지 않아야 함
      • 인그레스는 HTTPS만 사용해야 함
    • 게이트키퍼 용어
      • 제약
        • 제약을 쿠버네티스 리소스 명세의 특정 필드와 값에 적용되는 제한 사항으로 이해하면 쉬움
        • 정책을 길게 풀어 쓴 것. 제약을 정의하는 것은 무언가 허용하지 않을 것임을 효과적으로 명시하는 것
        • 제약이 없는 경우, 리소스가 암묵적으로 허용됨
      • Rego
        • OPA 네이티브 질의어. Rego 질의는 OPA에 저장된 데이터에 대한 조건문임. 게이트키퍼는 Rego를 제약 템플릿에 저장함
      • 제약 템플릿
        • 제약 템플릿은 정책 템플릿으로 볼 수 있음. 이식과 재사용이 가능함.
        • 제약 템플릿은 타입을 가진 매개변수와 재사용을 위한 파라미터화된 대상 Rego로 이루어짐
    • 제약 템플릿 정의
      • 제약 템플릿이란 정책을 공유하거나 재사용할 수 있는 정책 템플릿을 만들 수 있는 CRD. 제약 템플릿으로 정책의 매개변수를 검증할 수 있음
      • 신뢰할 수 있는 컨테이너 레지스트리의 컨테이너만 허용하는 정책에 관한 제약 템플릿
      • apiVersion: templates.gatekeeper.sh/v1alpha1
        kind: ConstraintTemplate
        metadata:
          name: k8sallowedrepos
        spec:
          crd:
            spec:
              name:
                kind: K8sAllowedRepos
                listKind: K8sAllowedReposList
                plural: k8sallowedrepos
                singular: k8sallowedrepos
              validation:
                # '매개변수' 필드를 위한 스키마
                openAPI3Schema:
                  properties:
                    repos:
                      type: array
                      items:
                        type: string
            targets:
              - target: admission.k8s.gatekeeper.sh
                rego: |
                  package k8sallowedrepos
                  
                  deny[{"msg": msg}] {
                    container := input.review.object.spec.containers[_]
                    satisfied := [good | repo = input.constraint.spec.parameters.repos[_] ;
                    good = startswith(container.image, repo)]
                    not any(satisfied)
                    msg := sprintf("container <%v> has an invalid image repo <%v>, allowed repos are %v", [container.name, container.image, input.constraint.spec.parameters.repos])
                }
    • 제약 정의
      • 제약의 운영 특성
        • 논리적 AND : 동일한 필드를 검증하는 여러 정책 중에 하나만 위반해도 전체 요청 거절
        • 빠른 오류 발견을 위한 스키마 검증
        • 셀렉션 기준
          • 레이블 셀렉터를 사용할 수 있음
          • 특정 종류만 제약
          • 특정 네임스페이스만 제약
  • 감사
    • 감사를 사용하면 게이트 키퍼는 주기적으로 정의된 제약에 대해 리소스를 평가함. 이를 통해 정책에 따라 잘못 설정된 리소스를 감지하고 교정할 수 있음
    • 감사 결과는 제약의 상태 필드에 저장되므로 kubectl을 사용하여 쉽게 찾을 수 있음. 감사를 사용하려면 감사할 리소스를 복제해야 함
    • 게이트키퍼 다음 단계
      • 변경(정책 기반 리소스 변경, 레이블 추가)
      • 외부 데이터 소스(정책 검색을 위해 경량 디렉터리 접근 프로토콜 또는 액티브 디렉터리와 통합)
      • 권한(게이트키퍼를 쿠버네티스 인증 모듈로 사용)
      • 드라이 런(dry run, 클러스터에서 정책을 활성화하기 전에 사용자가 정책을 테스트)
  • 정책과 거버넌스 모범 사례
    • 파드의 특정 필드에 정책을 시행하려면 검사하고 시행할 쿠버네티스 리소스 명세를 결정해야 함.
      • 예를 들어 디플로이먼트는 레플라카셋을 관리하고, 레플리카셋은 파드를 관리함. 세 가지 수준에서 모두 시행할 수 있지만 가장 좋은 선택은 런타임과 가장 근접한 파드
      • 사용자는 kubectl describe을 실행해 디플로이먼트와 관련된 현재 레플리카셋에서 리소스가 규정을 따르는지 확인해야 함. 번거롭게 느껴질 수 있지만, 파드 보안 정책과 같은 쿠버네티스 기능과 일관된 행동
    • 유형, 네임스페이스, 레이블 셀렉터의 기준에 따라 쿠버네티스 리소스 제약 조건을 적용할 수 있음. 제약을 적용하려는 리소스로만 범위를 최대한 좁혀야 함. 이렇게 하면 클러스터 리소스가 증가하더라도 일관된 정책이 보장됨. 그리고 평가할 필요가 없는 리소스는 OPA로 전달되지 않으므로 효율적
    • 쿠버네티스 시크릿과 같이 민감한 데이터에 정책을 동기화하고 시행하는 것은 권하지 않음. OPA가 시크릿을 캐시에 보관한 후에(데이터를 복제하도록 구성되었다면) 리소스가 게이트키퍼에게 전달되는 경우, 이 구간은 잠재적으로 보안 공격을 받을 수 있음
    • 많은 제약 조건이 정의되어 있을 때 하나의 제약 조건이 거부되면 전체 요청이 거부됨. 이를 논리적 OR로 만드는 방법은 없음

다중 클러스터 관리

  • 쿠버네티스는 많은 워크로드를 단일 클러스터로 통합하기 위해 만들어진 것이 아닌가요? 옳으 말. 하지만 여러 리전에 걸친 워크로드, 폭발 반경 문제, 규정 준수, 특수한 워크로드와 같은 시나리오가 존재함
  • 다중 클러스터의 필요성
    • 쿠버네티스를 도입할 때 이미 두 개 이상의 클러스터가 존재할 수 있으며 스테이징, 사용자 승인 테스트, 개발 등의 클러스터와 운영 클러스터를 분리하려는 단계일 수 있음
    • 쿠버네티스는 네임스페이스를 통한 멀티테넌시 기능을 제ㅔ공함. 네임스페이스는 클러스터를 작은 논리적 단위로 나누는 방법.
    • 네임스페이스에 RBAC, 쿼터, 파드 보안 정책, 네트워크 정책을 정의하여 워크로드를 분리할 수 있음.
    • 네임스페이스는 여러 팀과 프로젝트를 분리하는 좋은 방법이지만 다중 클러스터 아키텍처를 구축해야 할 우려가 있음
    • 단일 클러스터 아키텍처와 다중 클러스터의 사용을 결정할 때 고려해야 할 사항
      • 폭발 반경
      • 규정
      • 보안
      • 엄격한 멀티테넌시
      • 리전별 워크로드
      • 특수한 워크로드
    • 마이크로서비스 아키텍처는 서킷 브레이커, 재시도, 벌크헤드(bulkhead), 속도 제한을 이용해 시스템의 손상 범위를 제한함. 인프라 계층에도 동일한 설계를 적용한다면 다중 클러스터로 소프트웨어 문제로 인한 계단식 장애(cascading failure)를 막을 수 있음
    • 다중 클러스터 설계가 필요한 또 다른 이유는 결제 카드 산업(PCI), 건강 보험 이식성과 책임성(HIPAA) 등의 워크로드와 같이 특별한 상황에서의 규정 때문. 쿠버네티스가 멀티테넌트 기능을 제공하고는 있지만, 이러한 워크로드가 범용 워크로드와 분리되어 있다면 더 쉽게 관리할 수 있음
    • RBAC, 네트워크 정책, 파드 보안 정책을 관리하는 것도 큰 규모의 단일 클러스터에서는 어려움. 네트워크 정책을 조금만 변경해도 클러스터의 다른 사용자에게 보안 위험을 일으킬 수 있음. 다중 클러스터를 사용하면 설정 오류로 인한 보안 영향을 제한할 수 있음
    • 대규모 쿠버네티스 클러스터가 요구사항에 적합하다고 판단되면 보안 변경을 위한 매우 훌륭한 운영 프로세스를 갖춰야 하고 RBAC, 네트워크 정책, 파드 보안 정책을 변경할 때 발생하는 폭발 반경을 파악해야 함
    • 쿠버네티스는 클러스터 내에서 실행되는 모든 워크로드가 동일한 API 경계를 공유하므로 엄격한 멀티테넌시를 제공하지 않음. 네임스페이스를 통한 약한 멀티테넌시를 제공할 수는 있지만 적대적인 워크로드로부터 보안을 유지하기에는 부족함
    • 고성능 컴퓨팅(HPC), 머신러닝, 그리고 컴퓨팅과 같은 특수한 워크로드 또한 다중 클러스터 아키텍처를 통해 해결할 수 있음. 타입의 특수한 워크로드에는 특정 타입의 하드웨어가 필요하고, 독특한 성능 프로파일이 있으며, 특수한 사용자가 있음. 다중 쿠버네티스 노드 풀을 통해 특수한 하드웨어 성능 프로파일을 제공할 수 있기 때문에 보편적으로 사용되지는 않음
    • HPC나 머신러닝을 위해 매우 큰 클러스터가 필요한 경우, 이러한 워크로드를 담당할 전용 클러스터를 고려해야 함
  • 다중 클러스터 설계 문제
    • 다음 문제 때문에 다중 클러스터 설계 과정에서 아키텍처가 지나치게 복잡해질 수 있음
      • 데이터 복제
        • 데이터 복제와 일관성은 지리적 리전과 다중 클러스터에 워크로드를 배포할 때 중요한 요소
        • 워크로드를 실행할 때 복제 전략을 어디에서 개발하고 실행할 것인지 결정해야 함. 대부분의 데이터베이스에는 복제 도구가 내장되어 있지만, 복제 전략을 처리할 수 있도록 애플리케이션을 설계해야 함
        • NoSQL 타입의 데이터베이스 서비스에서는 다중 인스턴스로의 확장을 처리할 수 있어 작업이 어렵지 않지만, 애플리케이션의 경우에는 여러 지리적 리전에 걸친 점진적인 일관성을 보장해야만 함
        • 구글 클라우드 스패너와 마이크로소프트 애저 코스모스DB와 같은 클라우드 서비스는 여러 지리적 리전에 걸쳐 존재하는 데이터 처리의 복잡성을 해결하는 데 도움을 주는 데이터베이스 서비스를 구축했음
      • 서비스 디스커버리
        • 각 쿠버네티스 클러스터는 자체 서비스 디스커버리 레지스트리를 배포하지만, 레지스트리는 여러 클러스터 간에 동기화되 않음. 이는 애플리케이션이 서로를 식별하고 검색하는 것을 복잡하게 만듬
        • 콘솔과 같은 도구를 이용하면 다중 클러스터 서비스와 쿠버네티스 외부의 서비스까지를 투명하게 동기화할 수 있음.
        • 이스티오, 링커디, 실리움과 같은 도구는 다중 클러스터 아키텍처 위에 구축되어 클러스터 간 서비스 검색이 가능하게 함
      • 네트워크 라우팅
        • 쿠버네티스는 플랫 네트워크이고 NAT를 사용하지 않으므로 클러스터 내에서 네트워킹은 매우 간단함. 하지만 클러스터 안팎으로 트래픽을 라우팅하는 것은 더욱 복잡함
        • 클러스터와 인그레스는 1:1 매핑으로 구현되기 때문에 인그레스 리소스는 다중 클러스터 위상을 지원하지 않음
        • 클러스터 간의 이그레스 트래픽과 해당 트래픽을 라우팅하는 방법도 고려해야 함. 애플리케이션이 단일 클러스터 내에 존재하는 경우라면 간단하지만, 다중클러스터를 도입할 때는 다른 클러스터의 애플리케이션에 종속된 서비스에 대한 홉 레이턴시가 추가됨
        • 밀접하게 결합된 애플리케이션이라면 동일한 클러스터 내에서 서비스를 실해앟여 레이턴시와 복잡성을 제거하는 것이 좋음
      • 운영 관리
        • 다중 클러스터 관리에서 가장 큰 오버헤드
        • 한두 개의 클러스터만 관리하고 일관성을 유지하는 대신 환경에서 관리할 클러스터가 많아지는 것. 자동화를 통해 다중 크럴스터 운영 부담을 줄여야 함
        • 인프라 배포를 고민하고 추가 기능 관리를 고려해야 함. 해시코프의 테라폼과 같은 도구를 사용하면 상태를 여러 클러스터에 일관되고 배포하고 관리할 수 있음
      • 지속적인 배포
        • 테라폼과 같은 코드형 인프라 도구를 사용하면 클러스터 배포를 재현할 수 있음. 반면에 모니터링, 로깅, 인그레스, 보안 등의 추가 기능을 지속적으로 관리해야 함
        • 보안은 운영 관리를 위해 중요하므로 클러스터 전반에서 보안 정책, RBAC, 네트워크 정책을 유지 및 보수해야 함
        • 다중 클러스터와 CD를 사용하여 단일 쿠버네티스 API 엔드포인트 대신 다중 쿠버네티스 API 엔드포인트를 처리해야 함. 이로 인해 애플리케이션 배포에 문제가 발생할 수 있음. 소수의 파이프라인은 쉽게 관리할 수 있지만 파이프라인이 100개일 경우에는 애플리케이션 배포가 매우 어려울 것
  • 다중 클러스터 배포 관리
    • 다중 클러스터 배포를 관리할 때의 첫 번째 단계는 테라폼과 같은 코드형 인프라 도구를 사용해 배포를 설정하는 것. Kubespray, Kops, 클라우드 공급자의 특정 배포 도구도 좋지만, 가장 중요한 것은 반복적으로 클러스터에 배포할 수 있는 소스 관리 방식의 도구를 사용하는 것
    • 우선순위를 매겨 클러스터 배포와 운영의 모든 측면부터 자동화해야 함
    • 클러스터 API는 선언적인 쿠버네티스 스타일의 API로 클러스터를 생성, 구성, 관리하는 프로젝트. 핵심 쿠버네티스 위에 선택적인 추가 기능을 제공함. 클러스터 API는 공통 API를 통해 선언된 클러스터 수준의 설정을 제공하므로 ,클러스터 도구를 쉽게 자동화하고 구축할 수 있음
    • 배포와 관리 패턴
      • 오퍼레이터를 사용하면 애플리케이션 배포와 쿠버네티스 클러스터의 서비스를 추상화할 수 있음
        • 예를 들어 쿠버네티스 클러스터를 모니터링하는 프로메테우스를 표준화한다고 가정함. 각 클러스터와 팀마다 다양한 객체(디플로이먼트, 서비스, 인그레스 등)를 생성하고 관리해야 함
        • 버전, 영속성, 보관 정책, 레플리카와 같은 프로메테우스의 기본 설정도 관리해야 함. 클러스터와 팀이 많아지면 이러한 솔루션은 관리하기 어려움
        • 많은 객체와 설정을 관리하는 대신 prometheus-operator를 설치하는 방법도 있음. 쿠버네티스 API에 Prometheus, ServiceMonitor, PrometheusRule, AlertManager와 같은 새로운 객체 유형이 추가됨
        • 객체 유형으로 프로메테우스 배포 관련 모든 세부사항을 명시할 수 있음. kubectl 도구를 사용해 다른 쿠버네티스 API 객체를 관리하는 것처럼 이러한 객체도 관리할 수 있음
      • 오퍼레이터 패턴으로 핵심 운영 작업을 자동화하면 전체 클러스터 관리 능력이 향상됨.
      • 오퍼레이터 패턴의 두 가지 개념
        • CRD
          • CRD를 이용해 사용자가 정의한 API를 쿠버네티스 API에 추가할 수 있음
        • 사용자 정의 컨트롤러
          • 쿠버네티스 리소스와 컨트롤러의 핵심 개념을 기반으로 함
          • 사용자정의 컨트롤러를 사용하면 네임스페이스, 디플로이먼트, 파드, CRD와 같은 쿠버네티스 API 객체의 이벤트를 관찰하는 로직을 만들 수 있음. 선언적인 방식으로 CRD를 구축할 수 있음
          • 쿠버네티스 디플로이먼트 컨트롤러가 디플로이먼트 객체의 선언적 상태를 항상 유지하기 위해 조정 루프에서 동작하는 방식을 생각해본다면, CRD에도 같은 이점을 가져오게 됨
          • 오퍼레이터 패턴을 활용하여 다중 클러스터에서 운영 자동화를 구축할 수 있음
      • 일래스틱서치 오퍼레이터의 작업 수행
        • 마스터, 클라이언트, 데이터 노드의 레플리카
        • 고가용성 배포를 위한 영역
        • 마스터와 데이터 노드의 볼륨 크기
        • 클러스터의 크기 조정
        • 일래스틱서치 클러스터의 백업을 위한 스냅샷
      • 백업을 위한 스냅샷과 클러스터 크기 조절과 같은 일래스틱서치를 관리하는 데 필요한 많은 작업을 오퍼레이터를 통해 자동화할 수 있음
  • 깃옵스를 이용한 클러스터 관리
    • 깃옵스는 소프트웨어 개발 라이프사이클의 개념을 운영에 적용함. 깃옵스를 사용하면 깃 리포지터리가 진실의 원천이 되고 클러스터는 설정된 깃 리포지터리와 동기화됨
      • 예를 들어 쿠버네티스 디플로이먼트 매니페스트를 업데이트하면 해당 설정 변경 사항이 클러스터 상태에 자동으로 반영됨
    • 깃옵스로 보다 쉽게 다중 클러스터의 일관성을 유지보수할 수 있으며 설정 표류를 방지할 수 있음
    • 깃옵스를 통해 선언적으로 다중 클러스터의 상태를 기술하고 유지할 수 있음
    • 워브웍스 플럭스는 깃옵스를 가능하게 한 최초의 도구. 인투잇의 아르고 CD와 같이 클라우드 네이티브 생태계에 출시된 많은 도구가 있음. 아르고 CD도 깃옵스 방식으로 널리 사용되고 있음
  • 다중 클러스터 관리 도구
    • 다중 클러스터를 다룰 때 가장 필요한 도구는 컨텍스트와 네임스페이스를 쉽게 변경할 수 있는 kubectx와 kubens
    • 완벽한 다중 클러스터 관리 도구가 필요한 경우, 쿠버네티스 생태계 내에 다중 클러스터를 관리하는 몇 가지 도구
      • 랜처(Rancer)는 UI를 통해 다중 쿠버네티스 클러스터를 중앙집중식으로 관리함
        • 온프레미스, 클라우드, 호스팅되는 쿠버네티스 클러스터를 모니터링, 관리, 백업, 복원할 수 있음. 여러 클러스터에 배포된 애플리케이션을 제어하는 도구와 운영 도구를 제공함
      • 퀸(KQueen)은 쿠버네티스 클러스터 프로비저닝(provisioning)을 위한 자체적인 멀티테넌트 서비스 포털을 제공하며 다중 쿠버네티스의 감사, 가시성, 보안에 중점을 둠. 퀸은 미란티스 직원들이 개발한 오픈 소스 프로젝트
      • 가드너는 쿠버네티스 프리미티브를 사용하여 최종 사용자에게 쿠버네티스를 서비스 형태로 제공함. 모든 주요 클라우드 업체를 지원하며 SAP에서 개발되었음. 가트너느 실제로 서비스형 쿠버네티스를 구축하는 사용자에게 적합한 해결책
  • 다중 클러스터 관리 모범 사례
    • 계단식 장애로 인해 애플리케이션에 큰 피해가 발생하지 않도록 클러스터의 폭발 반경을 제한해야 함
    • PCI, HIPPA, HITRUST와 같은 규제 문제가 있다면 다중 클러스터를 사용하여 이러한 워크로드와 일반 워크로드가 혼하보디어 생기는 복잡성을 줄여야함
    • 엄격한 멀티테넌시가 비즈니스 요구사항이라면 워크로드 전용 클러스터에 배포함
    • 애플리케이션이 여러 리전을 필요로 한다면 글로벌 로드 밸런서를 사용하여 클러스터 사이의 트래픽을 관리함
    • HPC와 같은 특수한 워크로드를 개별 클러스터로 분산하여 워크로드의 특별한 요구사항을 만족시킬 수 있음
    • 여러 리전의 데이터 센터에 워크로드를 분산시켜 배포하는 경우라면 먼저 워크로드에 대한 데이터 복제 전략이 있는지 확인해야 함. 여러 리전에 걸친 다중 클러스터를 두는 건 쉬울 수 있지만 여러 리전에 걸쳐 데이터를 복제하는 것 복잡할 수 있음. 비동기 및 동기 워크로드를 처리할 수 있는 적절한 전략을 세워야 함
    • prometheus-operator 또는 일래스틱서치 오퍼레이터와 같은 쿠버네티스 오퍼레이터를 활용하여 운영 업무를 자동화함
    • 다중 클러스터 전략을 설계할 때는 클러스터 간 서비스 디스커버리와 네트워킹을 수행하는 방법도 고려해야 함. 콘술과 이스티오와 같은 서비스 메시 도구는 클러스터 간 네트워킹을 지원함
    • CD 전략이 리전 또는 다중 클러스터 간의 여러 롤아웃을 처리할 수 있는지 확인하세요
    • 다중 클러스터 운영 컴포넌트를 관리할 수 있는 깃옵스를 활용하여 모든 클러스터에 일관성을 유지할 수 있는지 조사해야 함. 깃옵스가 모든 환경에서 항상 동작하는 것은 아니지만, 최소한 다중 클러스터 환경의 운영 부담을 줄이기 위해서라도 확인해야 함

외부 서비스와 쿠버네티스 통합

  • 쿠버네티스로 서비스 가져오기
    • 캐노니컬 네임 레코드(CNAME) 기반 쿠버네티스 서비스를 정의할 수 있음. DNS 레코드인 CNAME 레코드는 특정 DNS 주소가 변환될 표준 DNS 이름을 나타냄
  • 쿠버네티스 서비스 내보내기
    • 노드포트로 서비스 내보내기
      • 노드포트 유형의 서비스는 클러스터 내의 모든 노드에 리스너를 내보냄
      • 노드포트 유형의 서비스를 생성하면 쿠버네티스는 자동으로 서비스 파드를 선택함. 서비스의 spec.ports[*].nodePort 필드에서 해당 포트를 얻을 수 있음. 서비스를 생성할 때 포트를 직접 지정할 수 있지만 클러스터에서 설정된 범위 내에 있어야 함. 포트 범위의 기본값은 30000에서 30999
      • 서비스가 포트로 노출되면 쿠버네티스 작업이 완료됨. 클러스터 외부에 존재하는 기존 애플리케이션에 서비스를 내보내려면 사용자(또는 네트워크 관리자)가 서비스를 검색할 수 있도록 만들어야 함.
      • 애플리케이션 구성 방식에 따라 다르지만 ${node}:${port} 쌍 목록을 애플리케이션에 제공할 수도 있음. 애플리케이션은 클라이언트측 로드 밸런싱을 수행함.
      • 네트워크 내에 물리적 또는 가상로드 밸런서를 구성하여 가상 IP 주소에서 ${node}:${port} 백엔드 목록으로 트래픽을 보낼 수도 있음
    • 외부 서버와 쿠버네티스 통합
      • 외부 애플리케이션을 실행하는 서버를 쿠버네티스 클러스터의 서비스 디스커버리와 네트워킹 메커니즘에 직접 통합하는 것
      • 네트워킹을 위해 외부 시스템을 클러스터에 통합할 때는 파드 네트워크 라우팅과 DNS 기반 서비스 검색이 모두 올바르게 동작하는지 확인해야 함. 가장 간단한 방법은 클러스터에 통합하려는 서버에서 kubelet을 실제로 실행하지만 스케줄링은 비활성화하는 것
      • 노드가 결합되는 즉시 kubectl cordon... 명령을 사용해 스케줄링할 수 없는 상태로 표시함으로써 추가 작업이 스케줄링되지 않도록 하세요. 데몬셋이 파드를 노드에 랜딩하는 것까지 막지는 않으므로 KubeProxy와 네트워크 라우팅 관련 파드는 서버에 랜딩되고, 해당 서버에서 실행 중인 모든 애플리케이션에서 쿠버네티스 서비스를 검색할 수 있음
  • 쿠버네티스 간 서비스 공유
    • 쿠버네티스 클러스터 간 서비스 연결. 이는 다른 리전의 쿠버네티스 클러스터의 장애를 극복하거나 서로 다른 팀에서 운영하는 서비스를 연결하기 위한 것
  • 클러스터와 외부 서비스 연결 모범 사례
    • 클러스터와 온프레미스 간 네트워크 연결을 설정함. 네트워킹은 사이트, 클라우드, 클러스터 구성에 따라 다를 수 있지만 파드가 온프레미스 서버와 통신할 수 있는지를 먼저 확인해야 함
    • 클러스터 외부의 서비스에 접근하려면 셀렉터가 없는 서비스를 사용하여 통신하려는 시스템(예를 들어 데이터베이스)의 IP 주소를 직접 프로그래밍할 수 있음. 고정 IP주소가 없다면 CNAME 서비스를 사용해 DNS 이름으로 전환할 수 있음. DNS이름이나 고정 서비스조차 없는 경우, 외부 서비스 IP 주소를 주기적으로 쿠버네티스 서비스 엔드포인트와 동기화하는 동적 오퍼레이터를 작성해야 함
    • 쿠버네티스에서 서비스를 내보내려면 내부 로드 밸런서 또는 노드포트 서비스를 사용하세요. 내부 로드밸런서는 일반적으로 쿠버네티스 서비스 자체에 바인딩될 수 있는 공개 클라우드 환경에서 사용하기가 수월함. 내부 로드 밸런서를 사용할 수 없다면 노드포트 서비스로 클러스터의 모든 서버에 서비스를 노출할 수 있음
    • 이 두 가지 방법을 조합해 쿠버네티스 클러스터 사이를 연결할 수 있음. 다른 쿠버네티스 클러스터에서 셀렉터가 없는 서비스로 사용되는 쿠버네티스 클러스터 서비스를 외부에 노출할 수 있음

쿠버네티스에서 머신러닝 실행하기

  • 머신러닝에서 쿠버네티스의 장점
    • 유비쿼터스
      • 쿠버네티스는 어디에나 있음. 주요 공개 클라우드는 모두 쿠버네티스를 지원하고 있으며 개인 클라우드와 인프라를 위한 배포판도 있음
      • 사용자는 쿠버네티스 플랫폼 생태계의 도구를 이용하여 어디에서나 딥러닝 워크로드를 실행할 수 있음
    • 규모 확장성
      • 딥러닝 워크플로는 머신러닝 모델을 효율적으로 훈련시키기 위해 많은 양의 컴퓨팅 파워를 사용함
      • 데이터 과학자가 모델 훈련에 필요한 컴퓨팅 규모를 손쉽게 달성하고 세밀하게 조절할 수 있도록 쿠버네티스에는 자동 확장 기능이 내장되어 있음
    • 기능 확장성
      • 머신러닝 모델을 효율적으로 학습할며ㅕㄴ 일반적으로 특수한 하드웨어가 필요함.
      • 쿠버네티스는 클러스터 관리자가 쿠버네티스 소스 코드를 변경하지 않고도 신규 하드웨어 정보를 스케줄러에 빠르고 쉽게 알리도록 함
      • 사용자 정의 리소스와 컨트롤러를 쿠버네티스 API에 완벽하게 통합하여, 하이퍼파라미터 튜닝과 같은 특수한 워크플로를 수행할 수 있도록 함
    • 자율성
      • 데이터 과학자는 필요에 따라 쿠버네티스 자체에 대한 전문 지식 없이도 쿠버네티스를 사용하여 머신러닝 워크플로를 스스로 수행할 수 있음
    • 이식성
      • 쿠버네티스 API를 기반으로 작업하면 어디에서나 머신러닝 모델을 실행할 수 있음. 다른 쿠버네티스 공급자에게 머신러닝 워크로드를 이식할 수도 있음
  • 머신러닝 워크플로
    • 데이터셋 준비
      • 모델 훈련에 사용되는 데이터셋을 준비하려면 스토리지, 인덱스, 카탈로그, 메타데이터가 필요함
      • 일반적으로 대규모 블록과 객체 스토리지가 필요함. 쿠버네티스 네이티브 스토리지 추상화 또는 API를 통해 접근할 수 있어야 함
    • 머신러닝 알고리즘 개발
      • 데이터 과학자가 머신러닝 알고리즘을 작성, 공유, 협업하는 단계
    • 훈련
      • 이 과정의 결과물은 일반적으로 훈련된 모델 상태의 체크포인트
      • 훈련 과정에서는 쿠버네티스의 모든 기능을 활용함. 스케줄링, 특수한 하드웨어에 접근, 데이터셋 볼륨 관리, 확장, 네트워킹이 모두 함께 발휘됨
    • 서빙
      • 훈련된 모델이 클라이언트의 서비스 요청을 처리하는 단계
      • 모델은 클라이언트가 제공한 데이터를 기반으로 예측을 함
  • 쿠버네티스 클러스터 관리자를 위한 머신러닝
    • 쿠버네티스에서 모델 훈련
      • 많은 클라우드 공급자가 다중 GPU VM을 제공하므로 분산 훈련을 시도하기 전에 VM을 4~8개의 GPU로 수직 확장하는 것이 좋음. 데이터 과학자는 모델을 훈련할 때 하이퍼파라미터 튜닝을 함
    • 쿠버네티스에서 분산 훈련
      • 훈련에 8개의 GPU가 필요한 경우 GPU가 네 개인 서버 두 대보다 8-GPU 서버 하나로 훈련하는 것이 더 빠름.
      • 분산 훈련을 해야 하는 상황은 모델의 크기가 가장 큰 가용 서버에도 맞지 않을 때
    • 리소스 제약
      • 훈련 단계에세 가장 많은 리소스를 사용함
      • 머신러닝 알고리즘 훈련은 배치 워크로드라는 것을 명심해야 함. 특히 시작 시간과 종료 시각을 가짐
      • 종료 시간은 모델을 훈련할 때 필요한 리소스를 얼마나 빨리 제공할 수 있는지에 달려 있음. 확장성이 훈련을 빨리 완료할 수 있는 가장 좋은 방법이지만, 확장성 자체에 대한 병목 현상이 존재함
    • 특수한 하드웨어
      • 특수한 하드웨어에서 모델을 훈련하고 서비스하면 당연히 효율적임. 특수한 하드웨어의 전형적인 예는 상용 GPU
      • 쿠버네티스의 장치 플러그인을 통해 GPU에 접근할 수 있음
      • 장치 플러그인은 신규 GPU 리소스를 쿠버네티스 스케줄러에 알리고 스케줄링 대상으로 만듬
      • 장치 플러그인은 각 노드에서 데몬셋으로 실행되며, 특정 리소스를 쿠버네티스 API에 알리는 것을 담당하는 프로세스.
      • NVDIA GPU에 접근할 수 있는 쿠버네티스용 NVDIA 장치 플러그인
      • apiVersion: v1
        kind: Pod
        metadata:
          name: gpu-pod
        spe:
          containers:
            - name: digits-container
              image: nvidia/digits:6.0
              resources:
                limits:
                  nvidia.com/gpu: 2 # 2개의 GPU를 요구함
        • 특이성 스케줄링
          • GPU 코어 수만 나타내고 코어당 실행할 수 있는 스레드 수는 생략함. GPU 코어가 있는 버스가 무엇인지 노출하지 않으므로 서로 또는 동일한 메모리에 접근해야 하는 잡이 동일한 쿠버네티스 노드에 배치될 수 있음
          • 모든 고려사항은 향후 장치 플러그인으로 해결 가능한 문제지만, 강력한 신규 GPU 장비를 100% 활용할 수 없는 이유가 궁금할 수 있음. GPU 일부(예를 들어 0.1)를 요청할 수 없다는 점도 언급할 필요가 있음. 특정 GPU가 다중 스레드를 지원하더라도 해당 용량만큼 사용할 수 없음을 의미함
    • 라이브러리와 드라이버와, 커널 모듈
      • 특수한 하드웨어에 접근하려면 일반적으로 특수한 라이브러리와 드라이버, 커널 모듈이 필요함. 컨테이너에서 실행 중인 도구에 사용하려면 컨테이너 런타임에 마운트되어야 함
    • 스토리지
      • 스토리지는 머신러닝 워크플로에서 가장 중요함.
      • 스토리지는 다음과 같은 머신러닝 워크플로에 직접적인 영향을 미침
        • 데이터셋 스토리지 및 훈련 중 워커 노드 간 분산
          • 훈련하는 동안 모든 워커 노드는 데이터셋을 가져와야 함. 스토리지는 읽기 전용이며 일반적으로 디스크 속도가 빠를수록 좋음
          • 스토리지의 디스크 유형은 데이터셋의 크기에 달려이씅ㅁ. 수백 메가바이트 또는 기가바이트의 데이터셋은 블록 스토리지가 적합하지만, 몇 또는 수백 테라바이트 크기의 데이터셋은 오브젝트 스토리지가 더 적합함
          • 데이터셋을 저장한 디스크의 크기와 위치에 따라 네트워크 성능이 달라질 수 있음
        • 체크포인트와 모델 저장
          • 체크포인트는 모델을 훈련할 때 생성되며, 저장된 모델은 서빙에 사용됨. 두 경우 모드 데이터를 저장하려면 각 워커 노드에 스토리지를 연결해야 함
          • 데이터는 일반적으로 단일 디렉터리에 저장되며 각 워커 노드는 특정 체크포인트나 모델 파일을 저장함. 대부분의 도구는 체크포인트와 데이터가 한곳에 존재한다고 가정하며 ReadWriteMany를 요구함
          • ReadWriteMany는 많은 노드에서 읽기와 쓰기로 마운트할 수 있다는 뜻. 쿠버네티스 퍼시스턴트볼륨을 사용한다면 가장 적합한 스토리지 플랫폼을 정해야함.
          • 쿠버네티스 문서에 ReadWriteMany을 지원하는 볼륨 플러그인 목록이 있음
    • 네트워킹
      • 머신러닝 워크플로의 훈련 단계, 특히 분산 훈련을 실행하는 것은 네트워크에 큰 부하를 줌. 텐서프로의 분산 아키텍처를 고려하면 많은 네트워크 트래픽을 발생시키는 두 가지의 개별 단계가 있음
      • 각 파라미터 서버의 변수를 워커 노드로 분배하는 단계와 워커 노드에서 다시 파라미터 서버로 기울기(gradient)를 적용하는 단계
      • 교환하는 데 걸리는 시간은 모델을 훈련시키는 시간에 직접적인 영향을 줌. 따라서 단순히 빠르면 더 좋음
      • 원격 직접 메모리 접근을 사용하면 네트워크 내의 서버가 프로세서와 캐시, 운영 체제레르 통하지 않고 메인 메모리의 데이터를 전달할 수 있음. 컨테이너 네트워크 오버레이의 높은 네트워크 성능을 자랑하는 오픈 소스 프로젝트인 프리플로(Freeflow)도 있음
    • 특수한 프로토콜
      • 분산 훈련을 보다 효율적으로 확장할 수 있는 방법
        • 메시지 전달 인터페이스는 분산 프로세스 사이에 데이터를 전송하기 위해 표준화된 이식 가능한 API
        • NVIDIA 군집 통신 라이브러리는 위상 인식 다중 GPU 통신 프리미티브 라이브러리
  • 데이터 과학자 관심사
    • Kubeflow는 쿠버네티스용 머신러닝 툴킷
      • 쿠버네티스 네이티브로 머신러닝 워크플로를 수행하는 데 필요한 도구를 제공함.
      • 주피터 노트북, 파이프라인, 쿠버네티스 네이티크 컨트롤러 등은 데이터 과학자가 쿠버네티스를 머신러닝 플랫폼으로 최대한 활용할 수 있도록 도움
    • Polyaxon은 다수의 대중적인 라이브러리를 지원하고 모든 쿠버네티스 클러스터에서 실행되는 머신러닝 워크플로우 관리 도구
      • Polyaxon은 상업용 제품과 오픈 소스 제품을 모두 보유하고 있음
    • Pachyderm은 엔터프라이즈급 데이터 과학 플랫폼.
      • 머신러닝 파이프라인을 구축할 수 있는 기능과 데이터셋 준비, 라이프사이클, 버전 관리 등을 위한 다양한 도구를 제공함.
      • Pachyderm에는 모든 쿠버네티스 클러스터에 배포할 수 있는 상업용 제품이 있음
  • 쿠버네티스에서 머신러닝 모범 사례
    • 지능적 스케줄링과 자동확장을 사용하세요
      • 머신러닝 워크플로의 대부분 단계는 본질적으로 일괄 처리이므로, 클러스터 오토스케일러의 사용을 권장함. GPU 가용 하드웨어는 비싸기 때문에 사용하지 않을 때는 비용을 지불하고 싶지 않을 것
      • 테인트와 톨러레이션을 사용하거나 시간별 클러스터 오토스케일러를 통해 특정 시간에 배치 작업을 실행하는 것이 좋음. 클러스터를 머신러닝 워크로드의 요구에 맞게 확장할 수 있음
      • 테인트와 톨러레이션과 관련된 업스트림 규칙은 확장된 리소스를 키로 사용해 노드를 테인트시키는 것. 예를 들어 NVIDIA GPU를 가진 노드는 다음과 같이 테인트함. Key: nvidia.com/gpu, Effect: NoSchedule
      • ExtendedResourceToleration 어드미션 컨트롤러를 사용할 수 있음. 컨트롤러는 사용자가 수동으로 추가할 필요가 없도록 테인트에 적절한 톨러레이션을 확장된 리소스를 요청하는 파드에 자동으로 추가함
    • 실제의 모델 훈련은 매우 민감함. 한 영역의 속도가 빨라지면 다른 영역에 병목 현상이 발생함. 지속적인 관찰과 튜닝에 노력이 듬
      • 일반적으로 GPU가 가장 비용이 많이 드는 리소스이므로 GPU에 병목 현상이 생기는 것이 좋음. GPU를 포화 상태로 유지하세요
      • 병목 현상을 항상 경계하고 GPU, CPU, 네트워크, 스토리지 사용률을 추적하는 모니터링을 구성해야 함
    • 혼합 워크로드 클러스터를 사용하세요
      • 일상적인 비즈니스 서비스를 실행하는 클러스터 역시나 머신러닝 목적으로 사용될 수 있음. 머신러닝 워크로드의 고성능 요구사항을 고려할 때 머신러닝 워크로드만 허용하도록 테이트된 별도의 노드 풀을 사용하는 것을 권장함
      • 머신러닝 노드 풀에서 실행되는 머신러닝 워크로드의 영향으로부터 다른 클러스터를 보호할 수 있음
      • 워크로드 유형에 따라 각각 다른 성능 특성을 가진 여러 GPU 가용 노드 풀도 만들어야 함.
      • 머신러닝 노드 풀에서 노드 자동 확장을 활성화하는 것이 좋음. 혼합 모드 클러스터는 머신러닝 워크로드가 클러스터에 미치는 성능 영향을 확실히 파악한 후 사용해야 함
    • 분산 훈련을 통해 선형 확장을 달성하세요
      • 분산 모델 훈련의 궁극적인 목표. 불행히도 대부분의 라이브러리는 분산될 때 선형으로 확장되지 않음
      • 확장성을 개선하기 위해 많은 연구가 진행 중이지만, 이 문제는 단순히 더 많은 하드웨어를 투입하는 것으로 해결되지 않음
      • 경험상 거의 항상 모델 자체가 병목의 원인이며 모델을 지원하는 인프라 문제가 아님. 모델 자체를 지적하기 전에 GPU, CPU, 네트워크, 스토리지의 사용률을 검토해야 함. 오픈 소스 도구인 Horovod는 분산 훈련 프레임워크를 개선해 더 나은 모델 확장성을 제공함

고수준 애플리케이션 패턴 구축

  • 고수준 추상화 개발 방법
    • 쿠버네티스를 세부 구현으로 포장하는 것. 플랫폼을 사용하는 개발자들은 자신이 쿠버네티스 위에서 개발하고 있다는 사실을 인식하지 못함
    • 쿠버네티스 자체에 내장된 확장 기능을 사용하는 것. 쿠버네티스 서버 API는 매우 유연하여 쿠버네티스 API에 새로운 리소스를 동적으로 추가할 수 있음. 이 방식을 통해 사용자는 내장된 쿠버네티스 객체와 새로운 고수준 리소스 모두를 기본 도구로 사용할 수 있음
    • 사용자가 유리를 깨고 탈출할 가능성이 없고 사용 편의성이 중요하다면 완전히 격리된 통합 환경을 구축하는 첫 번째 방법이 적합함. 머신러닝 파이프라인을 건설하는 것이 좋은 사례
    • 자바 애플리케이션 배포와 같은 고수준의 개발자 추상화를 구축할 때는 쿠버네티스를 감추는 것보다 확장하는 것이 좋음
      • 애플리케이션 개발 영역은 매우 광범위함. 특히 애플리케이션과 비즈니스가 시간이 지남에 따라 반복되고 변경되기 때문에 개발자의 모든 요구사항과 사용 사례를 예상하기 어려움
      • 쿠버네티스 생태계 도구를 계속 사용할 수 있도록 하기 위함. 모니터링, 지속적인 전달 등을 위한 클라우드 네이티브 도구가 수없이 많음. 쿠버네티스 API를 대체하는 대신 그대로 확장하면 개발 과정에서 기존 도구와 새로운 도구를 함께 사용할 수 있음
  • 쿠버네티스 확장
    • 쿠버네티스 클러스터 확장
      • 쿠버네티스 클러스터를 확장하려면 쿠버네티스 리소스의 접점을 이해하는 것이 중요함
      • 사이드 컨테이너는 서비스 메시의 맥락에서 대중화되었음. 이들은 애플리케이션 컨테이너와 함께 실행되어, 주 애플리케이션과 분리되어 있으며 종종 별도의 팀에서 유지보수하는 추가 기능을 제공하는 컨테이너
        • 예를 들어 서비스 메시에서 사이드카는 컨테이너형 애플리케이션에 투명한 mTLS 인증을 제공할 수 있음
      • 사이드카를 사용하여 사용자 정의 애플리케이션에 기능을 추가할 수 있음
      • 사이드카 방식의 궁극적인 목표는 개발자를 편하게 해주는 것. 쿠버네티스를 간편하게 확장해주는 어드미션 컨트롤러가 있음. 어드미션 컨트롤러는 API 요청을 클러스터의 백업 스토리지에 저장(또는 승인)하기 전에 가로챔.
        • 어드미션 컨트롤러를 사용해 API 객체의 유효성을 검사하거나 수정할 수 있음. 클러스터에서 생성된 모든 파드에 사이드카를 자동으로 추가할 수 있으므로 개발자는 사이드카를 몰라도 사이드카의 이점을 누릴 수 있음
      • CRD를 이용하면 기존 쿠버네티스 클러스터에 새로운 리소스를 동적으로 추가할 수 있음
        • 예를 들어 쿠버네티스 클러스터에 새로운 ReplicatedService 리소스를 추가할 수 있음
        • 개발자가 ReplicatedService의 인스턴스를 만들면 쿠버네티스는 해당 디플로이먼트와 서비스 리소스를 만듬. ReplicatedService는 공통된 유형을 개발자에게 편리하도록 추상화한 것. CRD는 일반적으로 새로운 리소스 유형을 관리하기 위해 클러스터 자체에 배포되는 제어 루프로 구현됨
  • 플랫폼 구축시 설계 고려 사항
    • 컨테이너 이미지 내보내기 지원
      • 플랫폼을 구축할 때 사용자가 완전한 컨테이너 이미지 대신 코드, 예를 들어 서비스로의 함수(FaaS,Function as a service) 또는 기본 패키지(예를 들어 자바의 JAR 파일)를 공급할 수 있도록 단순하게 설계함. 이 방식은 사용자가 친숙한 도구와 개발 경험을 그대로 이용할 수 있다는 매력을 가짐. 플랫폼은 애플리케이션의 컨테이너화를 처리함
      • 개발자가 제출한 프로그래밍 환경이 한계에 직면할 때 문제가 발생함. 예를 들면 버그를 해결하기 위해 특정 버전의 언어 런타임이 필요할 수 있음. 애플리케이션의 자동 컨테이너화 구조를 구성하지 않은 추가 리소스 또는 실행 파일을 패키징해야 할 수도 있음
      • 현재 애플리케이션을 그대로 재현한 컨테이너 이미지만 있으면 됨(예를 들어 기능과 노드 런타임을 포함하는 컨테이너 이미지)
  • 애플리케이션 플랫폼 구축 모범 사례
    • 어드미션 컨트롤러를 사용하여 클러스터에 대한 API 호출을 제한하고 수정해야 함. 어드미션 컨트롤러는 쿠버네티스 리소스의 유효성을 검증하고 타당하지 않은 리소스는 거절할 수 있음. 어드미션 컨트롤러는 API 리소스를 자동으로 수정해 사용자가 몰라도 되는 새로운 사이드카나 변경 사항을 추가할 수도 있음
    • kubectl 플러그인을 사용하여 기존의 익숙한 커맨드라인 툴에 새로운 도구를 추가하여 쿠버네티스 UX를 확장하세요. 드물지만 별도의 특수한 도구가 더 적합할 수 있음
    • 쿠버네티스 위에 플랫폼을 구축할 때 플랫폼 사용자와 사용자의 요구가 어떻게 발전할 것인지를 신중하게 고민해야 함. 간단하고 사용하기 쉽게 만드는 것은 분명 좋은 목표이지만, 사용자가 플랫폼 외부의 모든 것을 다시 구현해야 한다면 결국 좌절하고 실패하게 될 것

상태와 스테이트풀 애플리케이션 관리

  • 오퍼레이터는 쿠버네티스 기본 요소를 제공하며 복잡한 데이터 관리 시스템을 쉽게 운영할 수 있는 비즈니스 도는 애플리케이션 로직을 사용자 정의 컨트롤러로 추가할 수 있음
  • 볼륨과 볼륨 마운트
    • 도커, rkt, CRI-O, 싱귤래리티(Singularity)와 같은 주요 컨테이너 런타임은 외부 스토리지 시스템과 연계된 볼륨을 컨테이너에 마운트할 수 있음. 가장 단순한 외부 스토리지로는 메모리와 컨테이너 호스트 경로, NFS, Glusterfs, CIFS, Ceph와 같은 외부 파일 시스템이 있음
    • 사이드카 컨테이너느 공유 파드 볼륨을 통해 로그를 외부 소스로 스트리밍함. 호스트 기반 로깅 도구를 이용해 호스트 로그와 컨테이너 애플리케이션 로그를 볼륨에서 읽을 수 있음
    • 볼륨 모범 사례
      • 데이터를 공유하는 여러 컨테이너가 존재하는 파드의 볼륨 사용을 제한해야 함. 예를 들면 어댑터와 앰버서더 유형 패턴. 이러한 공유 패턴은 emptyDir을 사용함
      • 노드 기반 에이전트나 서비스에서 데이터에 접근해야 한다면 hostDir을 사용함
      • 중요한 애플리케이션 로그와 이벤트를 로컬 디스크에 쓰는 서비스를 파악해야 함. 가능하다면 stdout이나 stderr로 변경하고, 볼륨 맵 대신 쿠버네티스 환경의 로그 집계 시스템을 통해 로그를 스트리밍 함
  • 쿠버네티스 스토리지
    • 퍼시스턴트볼륨
      • 퍼시스턴트 볼륨을 파드에 마운트된 모든 볼륨을 백업하는 디스크로 볼 수 있음. 퍼시스턴트볼륨은 클레임 정책을 가지고 있음
      • 클레임 정책은 볼륨을 사용하는 파드의 라이프 사이클과 독립된 볼륨의 범위를 정의함. 쿠버네티스는 동적 또는 정적으로 정의된 볼륨을 사용할 수 있음. 동적으로 볼륨을 생성하려면 쿠버네티스에 정의된 스토리지클래스(storageClass)가 필요함
      • 퍼시스턴트볼륨은 다양한 유형의 클러스터에서 생성될 수 있으며 퍼시스턴트볼륨클레임이 퍼시스턴트볼륨과 일치할 때 파드에 할당됨. 볼륨 플러그인은 볼륨을 지원함. 쿠버네티스에서 직접 지원되는 수많은 플러그인이 있으며 각각 조정하는 설정 매개변수가 다름
      • apiVersion: v1
        kind: PersistentVolume
        metadata:
          name: pv001
        labels:
          tier: "silver"
        spec:
          capactiy:
            storage: 5Gi
          accessModes:
          - ReadWriteMany
          persistentVolumeReclaimPolicy: Recycle
          storageClassName: nfs
          mountOptions:
            - hard
            - nfsvers=4.1
          nfs:
            path: /tmp
            server: 172.17.0.2
    • 퍼시스턴트볼륨클레임
      • 퍼시스턴트볼륨클레임은 파드가 사용할 스토리지에 대한 리소스 요구사항 정의로 쿠버네티스에 전달됨
      • 쿠버네티스는 클레임을 참조해서 클레임 요청과 일치하는 persistentVolume이 있으면 해당 볼륨을 특정 파드에 할당함
      • apiVersion: v1
        kind: PersistentVolumeClaim
        metadata:
          name: my-pvc
        spec:
          storageClass: nfs
            accessModes:
            - ReadWriteMany
          resources:
            requests:
              storage: 5Gi
          selector:
            matchLabels:
              tier: "silver"
      • 쿠버네티스는 퍼시스턴트볼륨을 클레임과 매치하고 바인딩함. 이제 볼륨을 사용하려면 pod.spec에서 다음과 같이 클레임 이름을 참조하면 됨
      • apiVersion: apps/v1
        kind: Deployment
        metadata:
          name: nginx-webserver
        spec:
          replicas: 3
          selector:
            matchLabels:
              app: nginx-webserver
          template:
            metadata:
              labels:
                app: nginx-webserver
            spec:
              containers:
              - name: nginx-webserver
                image: nginx:alpine
                ports:
                - containerPort: 80
                volumeMounts:
                  - name: hostvol
                    mountPath: /usr/share/nginx/html
              volumes:
                - name: hostvol
                  persistentVolumeClaim:
                      claimName: my-pvc
    • 스토리지클래스
      • 관리자는 퍼시스턴트볼륨을 수동으로 정의하는 대신 스토리지클래스 객체를 생성할 수 있음. 스토리지클래스에는 사용할 볼륨 플러그인과 해당 클래스의 모든 퍼시스턴트볼륨이 사용할 특정 마운트 옵션과 매개변수를 정의함
      • 클레임에 스토리지클래스를 정의할 수 있고, 쿠버네티스는 스토리지클래스 매개변수와 옵션을 기반으로 퍼시스턴트볼륨을 동적으로 만들 수 있음
      • kind: StorageClass
        apiVersion: storage.k8s.io/v1
        metadata:
          name: nfs
        provisioner: cluster.local/nfs-client-provisioner
        parameters:
          archiveOnDelete: True
      • 컨테이너 스토리지 인터페이스와 플렉스볼륨
        • 제정신이 아닌 볼륨 플러그인으로 불리는 컨테이너 스토리지 인터페이스(CSI)와 플렉스볼륨(FlexVolume)을 이용해 스토리지 벤더는 사용자 정의 저장 플러그인을 구현할 수 있음
  • 쿠버네티스 스토리지 모범 사례
    • 가능하면 DefaultStorageClass 어드미션 플러그인을 활성화하고 기본 스토리지클래스를 정의하세요. 퍼시스턴트볼륨이 필요한 애플리케이션의 헬름 차트는 default 스토리지클래스가 설정되므로 애플리케이션을 거의 수정하지 않고도 설치할 수 있음
    • 온프레미스나 클라우드 공급자에서 클러스터의 아키텍처를 설계할 때, 계산과 데이터 계층의 영역과 상호 연결을 고려해야 함. 노드와 퍼시스턴트볼륨에 적절한 레이블을 쓰고 어퍼니티를 사용해 데이터와 워크로드가 최대한 근접해야 함. 궁긍적으로는 A 영역의 노드에 있는 파드가 B 영역의 노드에 붙어있는 볼륨을 마운트해야 함
    • 디스크에서 상태를 유지해야 하는 워크로드는 신중하게 고려하세요. 데이터베이스 시스템과 같은 외부 서비스에서 다룰 수 있나요? 만약 클라우드 공급자에서 실행 중이라면 서비스형 몽고DB 또는 MySQL 등의 현재 사용 중인 API와 일치하는 호스팅 API 서비스에서 처리할 수 있나요?
    • 애플리케이션 코드를 스테이트리스로 수정하는 데 얼마나 많은 노력이 드는지 조사해보세요
    • 쿠버네티스 워크로드가 스케줄링될 때 볼륨을 추적하고 마운트함. 하지만 해당 볼륨에 저장된 데이터의 중복과 백업은 아직 지원하지 않음. CSI 명세에는 네이티브 스냅샷 기술을 벤더가 플러그인 할 수 있는 API가 추가되었음. 하지만 스토리지 백엔드가 이를 지원해야 함
    • 볼륨이 유지할 데이터의 적절한 라이프사이클을 검증함. 기본적으로 회수 정책은 퍼시스턴트볼륨을 동적 프로비저닝하도록 설정되어 있음. 따라서 파드가 삭제되면 백업 스토리지 공급자에게 볼륨을 삭제함. 민감한 데이터나 법의학 분석에 사용할 수 있는 데이터는 회수하도록 설정해야 함
  • 스테이트풀 애플리케이션
    • 레플리카셋이 파드를 스케줄링하고 관리하는 방법이 전통적인 스테이트풀 애플리케이션에 해를 끼칠 수 있다는 것을 이해해야 함
      • 레플리카셋의 파드는 스케줄링 때 수평 확장되고 무작위로 이름이 할당됨
      • 레플리카셋의 파드는 임의의 방식으로 규모가 축소됨
      • 레플리카셋의 파드는 절대로 이름이나 IP 주소로 직접 호출되지 않고 Service를 통해 호출됨
      • 레플리카셋의 파드는 언제든 재시작하거나 다른 노드로 이동할 수 있음
      • 퍼시스턴트볼륨이 매핑된 레플리카셋의 파드는 오직 클레임을 통해 연결되며 새로운 이름을 가진 신규 파드는 다시 스케줄링될 때 해당 클레임을 넘겨받을 수 있음
    • 스테이트풀셋
      • 스테이트풀셋을 통해 신뢰할 수 있는 노드와 파드에서 애플리케이션 시스템을 편리하게 실행할 수 있음. 레플리카셋의 전형적인 파드 특성은 스테이트풀셋과 정반대.
      • 스테이트풀셋의 초기 형태인 쿠버네티스 v1.3 명세에서 PetSets은 복잡한 데이터 관리 시스템과 같은 스테이트풀 애플리케이션이 요구하는 중요한 스케줄링과 관리를 위해 도입되었음
        • 스테이트풀셋의 파드는 수평 확장되며 순차적으로 이름이 할당됨. 확장될 때 파드는 서수 이름을 얻고 기본적으로 새 파드는 다음 파드가 추가되기 전에 완전히 온라인 상태가 되어야함(생명성 프로브 또는 준비성 프로브 통과)
        • 스테이트풀셋의 파드는 역순으로 규모가 축소됨
        • 스테이트풀셋의 파드는 헤드리스 서비스 뒤의 이름으로 개별적으로 주소를 지정할 수 있음
        • 볼륨 마운트가 필요한 스테이트풀셋의 파드는 정의된 퍼시스턴트볼륨 템플릿을 사용해야 함. 스테이트풀셋의 파드에서 클레임된 볼륨은 스테이트풀셋이 삭제될 때 함께 삭제되지 않음
      • 스테이트풀셋의 명세는 서비스 선언 및 퍼시스턴트볼륨 템플릿을 제외하고는 디플로이먼트와 매우 유사함. 파드가 개별 주소를 가지려면 먼저 헤드리스 서비스를 생성해야 함
    • 오퍼레이터
      • 백업과 장애 극복, 리더 등록, 신규 레플리카 등록, 업그레이드와 같은 복잡한 작업은 정기적으로 수행되며 스테이트풀셋으로 실행할 때 신중하게 고려해야 함
      • 배포와 확장, 업그레이드, 백업, 일반적인 유지보수 작업을 할 수 있도록 카산드라나 카프카에 스테이트풀셋 컨트롤러를 구축한다고 상상해보자.
        • 최초로 만들어진 etcd와 프로메테우스 오퍼레이터는 시계열 데이터베이스를 사용해 시간에 따른 메트릭을 보관함
        • 프로메테우스나 etcd 인스턴스의 적절한 생성, 백업, 복원 설정은 오퍼레이터가 처리할 수 있으며 기본적으로 파드나 디플로이먼트처럼 새로운 쿠버네티스 관리 객체
    • 스테이트풀셋과 오퍼레이터 모범 사례
      • 스테이트풀셋을 사용하기로 결정할 때 시중해야 함
        • 보통 스테이트풀 애플리케이션은 오케스트레이터가 아직은 잘 관리할 수 없는 높은 수준의 관리를 필요로 하기 때문
      • 스테이트풀셋의 헤드리스 서비스는 자동으로 생성되지 않음. 파드를 개별 노드처럼 차지하려면 배포 시 주소 할당을 반드시 생성해야 함
      • 애플리케이션이 서수로 이름을 짓거나 신뢰성 있는 확장을 할 때 항상 퍼시스턴트볼륨을 할당해야 하는 것은 아님
      • 클러스터의 노드가 응답하지 않는 경우 스테이트풀셋의 파드는 자동으로 삭제되지 않음
        • 대신 유예 기간이 지나면 Terminating 또는 Unknown 상태가 됨. 이 파드를 정리할 수 있는 유일한 방법은 클러스터에서 노드 객체를 제거하거나, kubelet이 다시 동작해서 파드를 직접 삭제하거나, 오퍼레이터가 강제로 파드를 삭제하는 것.
        • 강제 삭제는 최후의 수단이어야 하며, 삭제된 파드가 있는 노드가 다시 온라인 상태가 되지 않도록 주의해야 함. 클러스터에 동일한 이름을 가진 파드가 둘이 될 수 있기 때문. kubectl delete pod nginx-0 --grace-period=0 --force를 실행하면 파드를 강제로 삭제할 수 있음
      • 파드를 강제로 삭제한 후에도 여전히 Unknown 상태로 유지될 수 있음. API 서버에 대한 패치를 통해 항목을 삭제하고 스테이트풀셋 컨트롤러가 삭제된 파드의 새 인스턴스를 생성할 수 있음. kubectl patch pod nginx-0 -p '{"metadata":{"finalizers":null}}'
      • 특정 유형의 리더 선출이나 데이터 복제 확인 프로세스가 있는 복잡한 데이터 시스템을 실행 중이라면, 정상적인 종료 프로세스를 사용해 파드를 삭제하기 전에 preStop hook을 사용하세요. 모든 연결을 종료하고 강제로 리더를 선출하거나 데이터 동기화를 검증해야 함
      • 스테이트풀 데이터가 필요한 애플리케이션이 복잡한 데이터 관리 시스템이라면 애플리케이션의 복잡한 라이프사이클 구성 요소 관리에 도움이 되는 오퍼레이터가 있는지 확인해야 함. 애플리케이션이 사내에서 구축되었다면, 애플리케이션에 관리 기능을 추가할 수 있도록 애플리케이션을 오퍼레이터 형태로 패키징하는 것이 가치가 있는지 조사해야 함

어드미션 컨트롤과 권한

  • 어드미션 컨트롤
    • 어드미션 컨트롤러 정의
      • 어드미션 컨트롤러는 쿠버네티스 API 서버 요청 처리 단계 중 하나이며 인증과 권한의 다음 단계에 존재함
      • 요청 객체를 스토리지에 저장하기 전에 요청을 검증하거나 변형 (또는 둘 다)함. 변형 어드미션 컨트롤러는 요청 객체를 수정할 수 있지만 검증 어드미션 컨트롤러는 요청 객체를 수정할 수 없음
    • 어드미션 컨트롤러의 중요성
      • 정책과 거버넌스
        • 어드미션 컨트롤러를 통해 비즈니스 요구사항을 만족시키기 위해 정책을 시행할 수 있음
          • dev 네임스페이스 내에서는 내부 클라우드 로드 밸런서만 사용할 수 있음
          • 파드의 모든 컨테이너에는 리소스 제한이 존재해야 함
          • 모든 리소스에 사전 정의된 표준 레이블이나 주석을 추가하여 기존 도구에서 찾을 수 있도록 해야 함
          • 모든 인그레스 리소스는 HTTPS만 사용함.
      • 보안
        • 어드미션 컨트롤러를 사용하여 클러스터 전체 보안 상태를 일관되게 유지할 수 있음
        • 전형적인 예로 파드 명세에서 보안에 민감한 필드를 제어할 수 있는 파드시큐리티폴리시 어드미션 컨트롤러가 있음
      • 리소스 관리
        • 어드미션 컨트롤러를 사용하면 클러스터 사용자에게 모범 사례를 제공하기 위해 다음을 검증할 수 있음
          • 모든 인그레스의 전체 주소 도메인 네임은 특정 접미사를 가져야 함
          • 인그레스의 전체 주소 도메인 네임이 겹치지 않아야 함
          • 파드의 모든 컨테이너에는 리소스 제한이 존재해야 함
    • 어드미션 컨트롤러 유형
      • 표준 어드미션 컨트롤러는 API 서버와 함께 컴파일되며 각 쿠버네티스 릴리스와 함께 플러그인으로 제공됨. API 서버가 시작될 때 설정해야 함
      • 동적 어드미션 컨트롤러는 런타임 시점에 설정할 수 있으며 핵심 쿠번테시ㅡ 코드베이스 외부에서 개발됨. 동적 어드미션 컨트롤러는 HTTP 콜백을 통해 어드미션 요청을 받는 어드미션 웹훅이 유일함
    • 어드미션 컨트롤 모범 사례
      • 어드미션 플러그인의 순서는 중요하지 않음.
        • 현재 지원되는 쿠버네티스에서는 --enable-admission-plugins를 통해 API 서버 플래그로 지정된 어드미션 플러그인 순서가 더는 중요하지 않음. 하지만 어드미션 웹훅에서는 순서가 중요하기 때문에 요청 흐름을 이해해야 함
        • 요청 승인 또는 거절은 논리적 AND로 동작하며, 만약 어드미션 웹훅 중 하나가 요청을 거절하면 전체 요청이 거절되고 오류가 사용자에게 재전송됨. 변형 어드미션 컨트롤러는 항상 검증 어드미션 컨트롤러 이전에 호출됨
      • 동일한 필드를 변경하면 안됨
        • 변형 어드미션 웹훅 사이에서는 요청 처리 순서를 정할 수 없기 때문에 구성할 문제가 생김
        • 예기치 못한 결과를 초래할 수 있으니 변형 어드미션 컨트롤러가 동일한 필드를 수정하지 않도록 해야 함. 여러 개의 변형 어드미션 웹훅이 존재할 때 일반적으로 검증 어드미션 웹훅으로 변형 끝의 리소스 매니페스트에 문제가 없는지를 점검하는 것이 낫음
      • 장애 허용/장애 차단이 중요함
        • failurePolicy 필드는 변형과 검증 웹훅 설정 리소스에 모두 존재함. 이 필드는 어드미션 웹훅에 접근 문제가 있거나 인식할 수 없는 오류가 발생했을 때 API 서버의 처리 방식을 정의함. 이 필드를 Ignore 또는 Fail로 설정할 수 있음
        • Ignore이 열리지 않는 것은 기본적으로 요청 처리는 허용함을 의미하지만 Fail은 전체 요청을 거부함을 의미함
        • 중요한 어드미션 웹훅을 무시하면 사용자가 모르는 사이, 비즈니스 관련 정책이 리소스에 적용되지 않는 문제가 생길 수 있음. 이 문제를 방지하는 해결책은 API 서버가 지정된 어드미션 웹훅에 도달할 수 없다고 기록할 때 경고를 발생시키는 것.
        • 어드미션 웹훅에 문제가 있을 때 Fail은 모든 요청을 거부하기 때문에 더욱 치명적일 수 있음. 이를 방지하기 위해 특정 리소스 요청에만 어드미션 웹훅이 설정되도록 규칙의 적용 범위를 지정할 수 있음
      • 어드미션 웹훅을 직접 작성할 때, 어드미션 웹훅에서 결정하고 응답하는 시간이 사용자와 시스템 요청에 직접적인 영향을 준다는 것을 기억해야 함
        • 모든 어드미션 웹훅 호출에 30초 타임아웃을 설정하여 이 시간이 지나면 failurePolicy가 적용되도록 함
        • 어드미션 웹훅에서 승인/거절 결정을 내리는 데 단지 몇 초가 걸린다 하더라도, UX에 심각한 영향을 미칠 수 있음
      • 어드미션 웹훅의 범위를 정해야 함. NamespaceSelector 필드를 이용해 어드미션 웹훅이 동작할 네임스페이스의 범위를 정할 수 있음. 이 필드는 기본적으로 비어 있으며 모든것을 매치함. matchLabels 필드를 이용해 네임스페이스 레이블을 매치할 수 있음. 네임스페이스별로 옵트인할 수 있으므로 항상 이 필드를 사용하세요
      • kube-system 네임스페이스는 모든 쿠버네티스 클러스터에 공통으로 사용되는 예약된 네임스페이스. 모든 시스템 수준 서비스가 동작하는 곳이므로 이 네임스페이스에서는 어드미션 웹훅을 실행하지 않는 것이 좋음. 간단하게 NamespaceSelector 필드를 사용해 kube-system 네임스페이스와 매치하지 않는 방법이 있음. 클러스터 동작에 필요한 모든 시스템 수준 네임스페이스에 대해서도 고려해야 함
      • RBAC를 통해 어드미션 웹훅 설정을 잠가야 함
        • MutatingWebhookConfiguration과 ValidatingWebhookConfiguration 생성은 클러스터에서 루트 권한이 필요한 작업이므로 RBAC를 사용해 적절히 잠겨 있어야 함은 당연함. 그렇지 않으면 클러스터에 장애가 생기거나 애플리케이션 워크로드에 대한 주입 공격이 발생할 수 있음
      • 민감한 데이터를 보내지 마세요
        • 어드미션 웹훅은 근본적으로 AdmissionRequests를 입력 받아 AdmissionResponses를 출력하는 블랙박스. 어떻게 요청을 저장하고 조작하는지는 사용자에게 보이지 않음
        • 어드미션 웹훅으로 전송하는 요청 페이로드가 무엇인지 고려하는 것이 중요함. 쿠버네티스 시크릿 또는 컨피그맵의 경우 민감한 정보를 포함할 수 있음. 정보가 저장되고 공유되는 방법에 대한 강력한 보장이 필요함
        • 어드미션 웹훅과 이러한 리소스를 공유하면 민감한 정보가 유출될 수 있음. 검증과 변형에 필요한 최소한의 리소스 규칙 범위를 정해야 함
  • 권한
    • 권한 모듈
      • ABAC : 로컬 파일을 통해 권한 정책을 설정할 수 있음
        • 특성 기반 접근 제어(attribute-based access control)
        • 새로운 API 그룹인 authorization.k8s.io. 이 그룹은 API 서버 권한을 외부 서비스에 노출하며 다음 API를 가지므로 디버깅에 도움이 됨
          • SelfSubjectAccessReview: 현재 사용자에 대한 접근 검토
          • SubjectAccessReview: SelfSubjectAccessReview와 유사하며 모든 사용자에게 적용
          • LocalSubjectAccessReview: SubjectAccessReview와 유사하며 특정 네임스페이스에 한정
          • SlefSubjectRulesReview: 지정된 네임스페이스에 사용자가 수행할 수 있는 작업 목록을 반환
      • RBAC : 쿠버네티스 API를 통해 권한 정책을 설정할 수 있음
      • 웹훅 : 원격 REST 엔드포인트를 통해 요청의 권한을 처리할 수 있음
        • 클러스터 관리자는 웹훅 권한 모듈을 사용하여 권한 프로세스를 위임할 외부 REST 엔드포인트를 설정할 수 있음. 클러스터에서 실행되며 URL을 통해 접근할 수 있음
        • REST 엔드포인트 설정은 마스터 파일 시스템의 파일에서 찾을 수 있으며 --authorization-webhook-config-file=SOME_FILENAME을 통해 API 서버에 설정됨.
        • 설정한 후에는 API 서버가 SubjectAccessReview 객체를 요청 바디에 포함하여 권한 웹훅 애플리케이션에 전송함. 권한 웹훅 애플리케이션은 해당 객체를 처리하고 상태 필드에 완료를 담아 반환함
      • 노드 : kubelet의 요청에 권한을 부여하는 특수 권한 모듈
    • 모듈은 API 서버의 --authorization-mode 플래그를 통해 클러스터 관리자가 구성함. 여러 모듈을 차례대로 구성하고 점검할 수 있음. 어드미션 컨트롤러와 달리 단일 권한 모듈에서 요청을 승인하면 요청이 진행됨. 모든 모듈이 요청을 거부하는 경우에만 오류가 사용자에게 반환됨
    • 권한 모범 사례
      • 각 마스터 노드의 파일 시스템에 ABAC 정책을 배치하고 동기화함. 일반적으로 다중 마스터 클러스터에서 ABAC를 사용하지 않을 것을 권장함
        • 설정은 파일에 존재하는 관련 플래그를 따르기 때문에 이는 웹훅 모듈에 대해서도 동일함. 파일 내의 정책을 변경하고 적용하려면 API 서버를 다시 시작해야 함
        • 단일 마스터 클러스터 내의 컨트롤 플레인이 중단되거나 다중 마스터 클러스터에서 설정이 불일치하게 됨. 이러한 세부 사항을 고려할 때 규칙이 쿠버네티스 자체에 설정되고 저장되기 때문에 사용자 권한은 RBAC 모듈만 사용할 것을 권장함
      • 웹훅 모듈은 강력하지만 잠재적으로 매우 위험함. 모든 요청이 권한 절차의 대상임을 생각하면 웹훅 서비스에 생기는 문제는 클러스터 장애로 이어짐
        • 완벽하게 파악되지 않은 외부 권한 모듈을 사용하지 않기를 권장함. 웹훅 서비스가 응답이 없거나 가용하지 않은 상황에서 동작하는 클러스터의 실패 모드가 익숙하지 않을 때도 마찬가지
  • 쿠버네티스의 강점은 모듈화와 일반화. 쿠버네티스에는 거의 모든 애플리케이션을 배포할 수 있으며 시스템에 필요하다면 어떠한 변경이나 튜닝도 할 수 있음