본문 바로가기

Infrastructure/Kubernetes

[Windows] 쿠버네티스에서의 Windows

쿠버네티스에서의 Windows

쿠버네티스 공식문서를 확인하며 Windows에 대해서 기억해야 하는 부분을 기록한다.

  • Windows 애플리케이션은 많은 조직에서 실행되는 서비스 및 애플리케이션의 상당 부분을 구성한다.
  • Windows 컨테이너는 프로세스와 패키지 종속성을 캡슐화하는 현대적인 방법을 제공하고, 데브옵스(DevOps) 사례를 더욱 쉽게 사용하고 Windows 애플리케이션의 클라우드 네이티브 패턴을 따르도록 한다.
  • Windows 기반 애플리케이션과 리눅스 기반 애플리케이션에 투자한 조직은 워크로드를 관리하기 위해 별도의 오케스트레이터를 찾을 필요가 없으므로, 운영 체제와 관계없이 배포 전반에 걸쳐 운영 효율성이 향상된다.

쿠버네티스에서의 Windows 노드

  • 쿠버네티스에서 Windows 컨테이너 오케스트레이션을 활성화하려면, 기존 리눅스 클러스터에 Windows 노드를 추가한다.
  • 쿠버네티스에서 파드 내의 Windows 컨테이너를 스케줄링하는 것은 리눅스 기반 컨테이너를 스케줄링하는 것과 유사하다.
  • Windows 컨테이너를 실행하려면, 쿠버네티스 클러스터가 여러 운영 체제를 포함하고 있어야 한다. 컨트롤 플레인은 리눅스에서만 실행할 수 있는 반면, 워커 노드는 Windows 또는 리눅스를 실행할 수 있다.
  • Windows Server 2019인 경우에만 Windows 노드로써 사용할 수 있다.
  • 본 문서에서 “Windows 컨테이너”라는 용어는 프로세스 격리 기반의 Windows 컨테이너를 의미하며, 쿠버네티스는 Hyper-V 격리 기반의 Windows 컨테이너를 지원하지 않는다.

[정리]

쿠버네티스를 사용하는 경우 “Windows 컨테이너”와 “Linux 컨테이너”의 구분 없이 운영이 가능하기 때문에 운영 효율성을 높일 수 있다. Windows 컨테이너를 사용하기 위해서는 단순히 기존에 사용하던 리눅스 클러스터에 Windows 노드만 추가하면 된다. 단, 쿠버네티스 클러스터가 여러 운영 체제를 포함하고 있어야 한다.


호환성 및 제한

  • 일부 노드 기능은 특정 컨테이너 런타임을 사용할 때에만 이용 가능하며, Windows 노드에서 사용할 수 없는 기능도 있다.
    • HugePages: Windows 컨테이너에서 지원되지 않음
    • 특권을 가진(Privileged) 컨테이너: Windows 컨테이너에서 지원되지 않으며 HostProcess 컨테이너가 비슷한 기능을 제공한다.
    • TerminationGracePeriod: containerD를 필요로 한다.
  • 공유 네임스페이스(shared namespaces)의 모든 기능이 지원되는 것은 아니다.
  • API 및 kubectl 관점에서, Windows 컨테이너는 리눅스 기반 컨테이너와 거의 같은 방식으로 작동하지만 주요 기능에서 몇 가지 주목할 만한 차이점이 있다.

리눅스와의 비교

  • Windows에서 주요 쿠버네티스 요소는 리눅스와 동일한 방식으로 작동한다. 몇 가지 주요 워크로드 추상화 및 Windows에서 어떻게 매핑되는지 확인해본다.
    • 파드: 파드는 쿠버네티스의 기본 빌딩 블록이며, 이는 쿠버네티스 오브젝트 모델에서 생성하고 배포하는 가장 작고 간단한 단위이다. 동일한 파드에 Windows 컨테이너와 리눅스 컨테이너를 배포할 수 없다. 파드의 모든 컨테이너는 단일 노드로 스케줄되며 이 때 각 노드는 특정 플랫폼 및 아키텍처를 갖는다.
      아래와 같은 기능, 속성 및 이벤트가 Windows 컨테이너에서 지원된다.
      • 프로세스 격리 및 볼륨 공유 기능을 갖춘 파드 당 하나 또는 여러 개의 컨테이너
      • 파드의 status 필드
      • 준비성 프로브(readiness probe), 활성 프로브(liveness probe) 및 시작 프로브(startup probe)
      • postStart 및 preStop 컨테이너 라이프사이클
      • 컨피그맵(ConfigMap), 시크릿(Secrets): 환경 변수 또는 볼륨 형태
      • emptyDir 볼륨
      • 명명된 파이프 호스트 마운트
      • 리소스 제한
      • OS 필드: 특정 파드가 윈도우 컨테이너를 사용하고 있다는 것을 나타내려면 .spec.os.name 필드를 windows로 설정해야 한다. 해당 필드가 인식되기 위해서는 IdentifyPodOS 기능 게이트를 활성화하면 된다.
      • IdentifyPodOS를 활성화하고, .spec.os.name 필드를 windows로 설정했다면, 사용해서는 안되는 필드가 있으며 “참고 자료”를 통해 공식 문서에서 확인해야 한다.
    • 워크로드 리소스
      • 레플리카셋(ReplicaSet)
      • 디플로이먼트(Deployment)
      • 스테이트풀셋(StatefulSet)
      • 데몬셋(DaemonSet)
      • 잡(Job)
      • 크론잡(Job)
      • 레플리케이션 컨트롤러(Replication Controller)
  • 파드, 워크로드 리소스 및 서비스는 쿠버네티스에서 Windows 워크로드를 관리하는 데 중요한 요소이다. 그러나 그 자체만으로는 동적인 클라우드 네이티브 환경에서 Windows 워크로드의 적절한 라이프사이클 관리를 수행하기에 충분하지 않다.
    • kubectl exec
    • 파드 및 컨테이너 메트릭
    • Horizontal pod autoscaling
    • 리소스 쿼터(Resource quota)
    • 스케쥴러 선점(preemption)

kubelet을 위한 명령줄 옵션

  • Windows에서는 일부 kubelet 명령줄 옵션이 아래와 같이 다르게 동작한다.
    • --windows-priorityclass를 사용하여 kubelet 프로세스의 스케줄링 우선 순위를 설정할 수 있다.
    • --kube-reserved, --system-reserved--eviction-hard 플래그는 NodeAllocatable을 업데이트한다.
    • --enforce-node-allocable을 이용한 축출은 구현되어 있지 않다.
    • --eviction-hard--eviction-soft를 이용한 축출은 구현되어 있지 않다.
    • Windows 노드에서 실행되는 kubelet은 메모리 및 CPU 제한을 받지 않는다. NodeAllocatable 에서 --kube-reserved--system-reserved가 차감될 뿐이며 워크로드에 제공될 리소스는 보장되지 않는다.
    • MemoryPressure 컨디션은 구현되어 있지 않다.
    • kubelet은 메모리 부족(OOM) 축출 동작을 수행하지 않는다.

API 호환성

  • 운영 체제와 컨테이너 런타임의 차이로 인해, Windows에 대해 쿠버네티스 API가 동작하는 미묘한 차이가 있다. 일부 워크로드 속성은 리눅스에 맞게 설계되어 있기 때문에 Windows에서 실행되지 않는다.
  • 고수준에서, OS 개념에 대한 아래와 같은 차이점이 존재한다.
    • ID: 리눅스는 정수형으로 표시되는 userID(UID) 및 groupID(GID)를 사용한다. 사용자와 그룹 이름은 정식 이름이 아니며 UID + GID에 대한 /etc/groups 또는 /etc/passwd의 별칭일 뿐이다.
      Windows는 Windows 보안 관리자(Security Account Manager, SAM) 데이터베이스에 저장된 더 큰 이진 보안 식별자(SID)를 사용하며 이 데이터베이스는 호스트와 컨테이너, 컨테이너들 간에 공유되지 않는다.
    • 파일 퍼미션: Windows는 SID 기반 접근 제어 목록을 사용하는 반면, 리눅스와 같은 POSIX 시스템은 오브젝트 권한 및 UID+GID 기반의 비트마스크(bitmask)를 사용하며, 접근 제어 목록도 선택적으로 사용한다.
    • 파일 경로: Windows의 규칙은 / 대신 \ 을 사용하는 것이다. Go IO 라이브러리는 두 가지 파일 경로 분리자를 모두 허용한다. 하지만, 컨테이너 내부에서 해석되는 경로 또는 커맨드 라인을 설정할 때 \가 필요할 수 있다.
    • 신호(Signals): Windows 대화형(interactive) 앱은 종료를 다르게 처리하며, 아래 목록 중 하나 이상을 구현할 수 있다.
      • UI 스레드는 WM_CLOSE 등의 잘 정의된(well-defined) 메시지를 처리한다.
      • 콘솔 앱은 컨트롤 핸들러(Control Handler)를 사용하여 Ctrl-c 또는 Ctrl-break를 처리한다.
      • 서비스는 SERVICE_CONTROL_STOP 제어 코드를 수용할 수 있는 Service Control Handler 함수를 등록한다.
  • 컨테이너 종료 코드는 리눅스와 동일하게 성공이면 0, 실패면 0이 아닌 다른 수이다. 상세 오류 코드는 Windows와 리눅스 간에 다를 수 있지만, 쿠버네티스 컴포넌트(kubelet, kube-proxy)에 전달된 종료 코드는 변경되지 않는다.

컨테이너 명세의 필드 호환성

  • 아래의 목록은 Windows와 리눅스에서 파드 컨테이너 명세가 어떻게 다르가 작동하는지 정리되어 있다.
    • Huge page는 Windows 컨테이너 런타임에서 구현되지 않았기 때문에 사용할 수 없다. 컨테이너에 대해 구성할 수 없는사용자 권한(user privilege) 어설트(assert)가 필요하다.
    • requests.cpurequests.memory: 요청이 노드의 사용 가능한 리소스에서 차감되며, 이는 노드 오버프로비저닝을 방지하기 위해 사용될 수 있다. 그러나 오버프로비저닝된 노드 내에서 리소스를 보장하기 위해서는 사용될 수 없다. 운영자가 오버프로비저닝을 완전히 피하려는 경우 모범 사례로 모든 컨테이너에 적용해야 한다.
    • securityContext.allowPrivilegeEscalation: 어떠한 기능도 연결되지 않아서, Windows에서는 사용할 수 없다.
    • securityContext.capabilities: POSIX 기능은 Windows에서 구현되지 않았다.
    • securityContext.privileged: Windows는 특권을 가진(Privileged) 컨테이너를 지원하지 않는다.
    • securityContext.procMount: Windows에는 /proc 파일시스템이 없다.
    • securityContext.readOnlyRootFilesystem: Windows에서는 사용할 수 없으며, 이는 레지스트리 및 시스템 프로세스가 컨테이너 내부에서 실행될 때 쓰기 권한이 필요하기 때문이다.
    • securityContext.runAsGroup: 컨테이너가 ContainerAdministrator 사용자로 실행되는 것을 방지하는 설정이며, 이는 리눅스의 root 사용자와 가장 가까운 Windows의 역할이다.
    • securityContext.runAsUser: 설정 대신 .runAsUserName을 사용해야 한다.
    • securityContext.seLinuxOptions: SELinux는 리눅스 전용이므로 Windows에서는 사용할 수 없다.
    • terminationMessagePath: Windows가 단일 팡리 매핑을 지원하지 않음으로 인하여 몇 가지 제한이 있다. 기본값은 /dev/termination-log이며, 이 경로가 기본적으로 윈도우에 존재하지 않기 때문에 정상적으로 작동한다.

파드 명세의 필드 호환성

  • 아래의 목록은 Windows와 리눅스에서 파드 명세가 어떻게 다르게 동작하는지 정리되어 있다.
    • hostIPChostpid: 호스트 네임스페이스 공유 기능은 Windows에서 사용할 수 없다.
    • hostNetwork: Windows 운영 체제에서 호스트 네트워크 공유 기능을 지원하지 않는다.
    • dnsPolicy: Windows에서 호스트 네트워킹이 지원되지 않기 때문에 dnsPolicyClusterFirstWithHostNet으로 설정할 수 없다. 파드는 항상 컨테이너 네트워크와 함께 동작한다.
    • podSecurityContext
    • terminationGracePeriodSeconds: Windows용 도커에 완전히 구현되지 않았다. 현재 동작은 ENTRYPOINT 프로세스가 CTRL_SHUTDOWN_EVENT로 전송된 다음, Windows가 기본적으로 5초를 기다린 후, 마지막으로 정상적인 윈도우 종료 동작을 사용하여 모든 프로세스를 종료하는 것이다.
      기본값인 5초는, 실제로는 컨테이너 내부 Windows 레지스트르에 있으므로 컨테이너를 빌드할 때 재정의할 수 있다.
    • volumeDevices: 베타 기능이며, Windows에서 구현되지 않았다. Windows는 원시 블록 장치(raw block device)를 파드에 연결할 수 없다.
    • volumes: emptyDir 볼륨을 정의한 경우, 볼륨의 소스(source)를 memory로 설정할 수는 없다.
    • mountPropagation: 마운트 전파(propagation)는 Windows에서 지원되지 않으므로 이 필드는 활성화할 수 없다.

파드 시큐리티 컨텍스트의 필드 호환성

  • 파드 securityContext의 모든 필드는 Windows에서 작동하지 않는다.

[정리]

Windows 컨테이너의 경우 대부분의 기능이 Linux 컨테이너 유사하지만 특정 기능은 사용하지 못하거나 사용법이 다른 기능들이 있다. 사용법이 다르다는 것은 kubectl 커맨드를 사용할 때도 다른 점이 있다는 것을 의미한다.

Windows 컨테이너와 리눅스 컨테이너가 종료되었을 때의 오류 코드는 다를 수 있다. 하지만 쿠버네티스 컴포넌트에 전달되는 코드는 동일하다.


노드 문제 감지기

  • 노드 문제 감지기는 기초적은 Windows 지원을 포함한다.

퍼즈(pause) 컨테이너

  • 쿠버네티스 파드에서, 컨테이너를 호스팅하기 위해 먼저 “퍼즈” 컨테이너라는 인프라 컨테이너가 생성된다.
  • 리눅스에서, 파드를 구성하는 cgroup과 네임스페이스가 계속 유지되기 위해서는 프로세스가 필요하며, 퍼즈 프로세스가 이를 담당한다.
  • 동일한 파드에 속한 (인프라 및 워커) 컨테이너는 공통의 네트워크 엔드포인트(공통 IPv4.IPv6주소, 공통 네트워크 포트 공간)를 공유한다.
  • 쿠버네티스는 퍼즈 컨테이너를 사용하여 워커 컨테이너가 충돌하거나 재시작하여도 네트워킹 구성을 잃지 않도록 한다.
  • 쿠버네티스는 Windows 지원을 포함하는 다중 아키텍처 이미지를 유지보수한다. v1.25 버전의 경우 권장 퍼즈 이미지는 k8s.gcr.io/pause:3.6 에서 유지보수하고 있다. 이 이미지는 쿠버네티스가 유지 관리하는 이미지와 동일한 소스코드에서 생성되었지만, 모든 Windows 바이너리가 Microsoft에 의해 인증 코드(authenticode)로 서명되었다.
  • 서명된 바이너리를 필요로 하는 프로덕션 또는 프로덕션에 준하는 환경에 파드를 배포하는 경우, Microsoft가 유지 관리하는 이미지를 사용하는 것이 권장된다.

[정리]

쿠버네티스는 컨테이너를 호스팅하기 위해 가장 먼저 퍼즈 컨테이너를 생성한다. 퍼즈 컨테이너를 사용하여 워커 컨테이너가 재시작하여도 네트워크 구성을 잃지 않도록 한다. 모든 Windows 바이너리가 Microsoft에 의해 서명되어 있으며 프로덕션 환경에는 Microsoft 공식 이미지를 사용하는 것이 권장된다.


컨테이너 런타임

  • 파드가 각 노드에서 실행될 수 있도록, 클러스터의 각 노드에 컨테이너 런타임을 설치해야 한다.
  • 쿠버네티스에 필요한 기능을 제공하는 써드파티 프로젝트와 관련이 있지만 쿠버네티스 프로젝트 작성자는 써드파티 프로젝트에 대한 책임이 없다.
  • 아래는 Windows에서 지원하는 컨테이너 런타임이다.
    • ContainerD
    • Mirantis Container Runtime

윈도우 운영 체제 버전 호환성

  • Windows에는 호스트 OS 버전이 컨테이너 베이스 이미지 OS 버전과 일치해야 한다는 엄격한 호환성 규칙이 있다.
  • 컨테이너 운영 체제가 Windows Server 2019인 Windows 컨테이너만 완전히 지원된다.
  • v1.25에서, Windows 노드 및 파드에 대한 운영 체제 호환성은 아래와 같다.
    • Windows Server LTSC릴리즈
      • Windows Server 2019
      • Windows Server 2022
    • Windows Server SAC 릴리즈
      • Windows Server 버전 20H2

배포 도구

  • kubeadm 도구는 클러스터를 관리할 컨트롤 플레인과 워크로드를 실행할 노드를 제공함으로써 쿠버네티스 클러스터를 배포할 수 있게 해준다.
  • 쿠버네티스 클러스터 API 프로젝트는 Windows 노드 배포를 자동화하는 수단을 제공한다.

참고 자료