쿠버네티스에서 Windows 컨테이너 실행 가이드
쿠버네티스에서 Windows 컨테이너 실행 가이드 (Guide for Running Windows Containers in Kubernetes)
이 페이지는 쿠버네티스를 사용해 Windows 컨테이너를 실행하기 위해 따를 수 있는 몇 가지 단계에 대한 워크스루를 제공해요. 이 페이지는 또한 쿠버네티스 내 Windows 특정 기능도 강조해요.
쿠버네티스에서 서비스와 워크로드를 만들고 배포하는 것은 Linux와 Windows 컨테이너에서 대체로 같은 방식으로 동작한다는 점을 기억하는 것이 중요해요. 클러스터와 상호 작용하는 kubectl 명령은 동일해요. 이 페이지의 예시는 Windows 컨테이너 경험을 시작하는 데 제공돼요.
출처: 문서
본문
목표 (Objectives)
Windows 노드에서 Windows 컨테이너를 실행하도록 예시 deployment를 구성해요.
시작하기 전에 (Before you begin)
Windows Server를 실행하는 워커 노드를 포함하는 쿠버네티스 클러스터에 이미 접근할 수 있어야 해요.
시작하기: Windows 워크로드 배포하기
아래 예시 YAML 파일은 Windows 컨테이너 안에서 실행되는 간단한 웹서버 애플리케이션을 배포해요.
win-webserver.yaml 이라는 매니페스트를 아래 내용으로 만들어요:
---
apiVersion: v1
kind: Service
metadata:
name: win-webserver
labels:
app: win-webserver
spec:
ports:
# the port that this service should serve on
- port: 80
targetPort: 80
selector:
app: win-webserver
type: NodePort
---
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: win-webserver
name: win-webserver
spec:
replicas: 2
selector:
matchLabels:
app: win-webserver
template:
metadata:
labels:
app: win-webserver
name: win-webserver
spec:
containers:
- name: windowswebserver
image: mcr.microsoft.com/windows/servercore:ltsc2019
command:
- powershell.exe
- -command
- "<#code used from https://gist.github.com/19WAS85/5424431#> ; $$listener = New-Object System.Net.HttpListener ; $$listener.Prefixes.Add('http://*:80/') ; $$listener.Start() ; $$callerCounts = @{} ; Write-Host('Listening at http://*:80/') ; while ($$listener.IsListening) { ;$$context = $$listener.GetContext() ;$$requestUrl = $$context.Request.Url ;$$clientIP = $$context.Request.RemoteEndPoint.Address ;$$response = $$context.Response ;Write-Host '' ;Write-Host('> {0}' -f $$requestUrl) ; ;$$count = 1 ;$$k=$$callerCounts.Get_Item($$clientIP) ;if ($$k -ne $$null) { $$count += $$k } ;$$callerCounts.Set_Item($$clientIP, $$count) ;$$ip=(Get-NetAdapter | Get-NetIpAddress); $$header='<html><body><H1>Windows Container Web Server</H1>' ;$$callerCountsString='' ;$$callerCounts.Keys | % { $$callerCountsString+='<p>IP {0} callerCount {1} ' -f $$ip[1].IPAddress,$$callerCounts.Item($$_) } ;$$footer='</body></html>' ;$$content='{0}{1}{2}' -f $$header,$$callerCountsString,$$footer ;Write-Output $$content ;$$buffer = [System.Text.Encoding]::UTF8.GetBytes($$content) ;$$response.ContentLength64 = $$buffer.Length ;$$response.OutputStream.Write($$buffer, 0, $$buffer.Length) ;$$response.Close() ;$$responseStatus = $$response.StatusCode ;Write-Host('< {0}' -f $$responseStatus) } ; "
nodeSelector:
kubernetes.io/os: windows
참고:
참고:
관찰 가능성 (Observability)
워크로드에서 로그 캡처하기
로그는 관찰 가능성의 중요한 요소예요. 사용자가 워크로드의 운영 측면에 대한 통찰을 얻을 수 있게 하고 문제를 해결하는 핵심 요소예요. Windows 컨테이너와 Windows 컨테이너 안의 워크로드는 Linux 컨테이너와 다르게 동작하기 때문에, 사용자는 로그 수집에 어려움을 겪어 운영 가시성이 제한됐어요. 예를 들어 Windows 워크로드는 보통 ETW(Event Tracing for Windows)로 로깅하거나 애플리케이션 이벤트 로그에 항목을 푸시하도록 구성돼 있어요.
Microsoft의 오픈 소스 도구인 LogMonitor는 Windows 컨테이너 안의 구성된 로그 소스를 모니터링하는 권장 방법이에요. LogMonitor는 이벤트 로그, ETW 제공자, 커스텀 애플리케이션 로그 모니터링을 지원하며, 이를 STDOUT으로 파이프해 kubectl logs <pod> 가 사용할 수 있게 해요.
LogMonitor GitHub 페이지의 지침에 따라 그 바이너리와 구성 파일을 모든 컨테이너에 복사하고 LogMonitor가 로그를 STDOUT으로 푸시하도록 필요한 엔트리포인트를 추가해요.
컨테이너 사용자 구성하기
구성 가능한 컨테이너 사용자 이름 사용하기
Windows 컨테이너는 이미지 기본값과 다른 사용자 이름으로 엔트리포인트와 프로세스를 실행하도록 구성할 수 있어요. 자세한 내용은 여기에서 알아보세요.
GMSA로 워크로드 아이덴티티 관리하기
Windows 컨테이너 워크로드는 GMSA(Group Managed Service Accounts)를 사용하도록 구성할 수 있어요. GMSA는 자동 비밀번호 관리, 단순화된 서비스 주체 이름(SPN) 관리, 여러 서버에 걸쳐 다른 관리자에게 관리를 위임할 수 있는 능력을 제공하는 특별한 유형의 Active Directory 계정이에요. GMSA로 구성된 컨테이너는 GMSA로 구성된 아이덴티티를 지니면서 외부 Active Directory 도메인 리소스에 접근할 수 있어요.
Windows 컨테이너용 GMSA 구성·사용에 대해 여기에서 더 알아보세요.
Taint와 toleration
사용자는 Linux와 Windows 워크로드를 각 OS별 노드에 스케줄링하기 위해 taint와 node selector의 어떤 조합을 사용해야 해요. 권장 접근 방식은 아래에 개략 설명돼 있으며, 그 주요 목표 중 하나는 이 접근 방식이 기존 Linux 워크로드의 호환성을 깨뜨리지 않아야 한다는 것이에요.
각 Pod에 .spec.os.name 을 설정해 그 Pod의 컨테이너가 설계된 운영 체제를 나타낼 수 있습니다(그리고 해야 해요). Linux 컨테이너를 실행하는 Pod는 .spec.os.name 을 linux 로 설정해요. Windows 컨테이너를 실행하는 Pod는 .spec.os.name 을 windows 로 설정해요.
스케줄러는 Pod를 노드에 배정할 때 .spec.os.name 값을 사용하지 않아요. 클러스터의 제어 플레인이 파드를 적절한 운영 체제를 실행하는 노드에 배치하도록 보장하려면 일반적인 쿠버네티스 [파드를 노드에 배정] 메커니즘(](/docs/concepts/scheduling-eviction/assign-pod-node/)을 사용해야 해요.
.spec.os.name 값은 Windows 파드의 스케줄링에 아무런 영향을 미치지 않으므로, Windows 파드가 적절한 Windows 노드에 도달하도록 보장하려면 여전히 taint·toleration(또는 node selector)이 필요해요.
OS별 워크로드가 적절한 컨테이너 호스트에 도달하도록 보장하기
사용자는 taint와 toleration을 사용해 Windows 컨테이너가 적절한 호스트에 스케줄링되도록 보장할 수 있어요. Kubernetes 1.37을 실행하는 모든 쿠버네티스 노드는 다음 기본 라벨을 가져요:
- kubernetes.io/os = [windows|linux]
- kubernetes.io/arch = [amd64|arm64|...]
Pod 스펙이 "kubernetes.io/os": windows 같은 nodeSelector 를 지정하지 않으면, Pod는 Windows든 Linux든 모든 호스트에 스케줄링될 수 있어요. Windows 컨테이너는 Windows에서만 실행될 수 있고 Linux 컨테이너는 Linux에서만 실행될 수 있으므로 이는 문제가 될 수 있어요. Kubernetes 1.37의 모범 사례는 nodeSelector 를 사용하는 것이에요.
하지만 많은 경우 사용자는 Linux 컨테이너용으로 이미 많은 수의 deployment를 보유하고 있으며, 커뮤니티 Helm 차트 같은 기성 구성과 operator 같은 프로그래밍적 Pod 생성 사례의 생태계도 있어요. 그런 상황에서 모든 Pod와 Pod 템플릿에 nodeSelector 필드를 추가하는 구성 변경을 망설일 수 있어요.
대안은 taint를 사용하는 것이에요. kubelet은 등록 중에 taint를 설정할 수 있으므로, Windows에서만 실행될 때 자동으로 taint를 추가하도록 쉽게 수정할 수 있어요.
예: --register-with-taints='os=windows:NoSchedule'
모든 Windows 노드에 taint를 추가하면 그 위에 아무것도 스케줄링되지 않게 돼요(기존 Linux Pod 포함). Windows Pod가 Windows 노드에 스케줄링되려면 Windows를 선택하기 위해 nodeSelector 와 적절한 일치 toleration이 모두 필요해요.
nodeSelector:
kubernetes.io/os: windows
node.kubernetes.io/windows-build: '10.0.20348'
tolerations:
- key: "os"
operator: "Equal"
value: "windows"
effect: "NoSchedule"
같은 클러스터에서 여러 Windows 버전 처리하기
각 Pod가 사용하는 Windows Server 버전은 그 노드의 버전과 일치해야 해요. 같은 클러스터에서 여러 Windows Server 버전을 사용하려면 추가 노드 라벨과 nodeSelector 필드를 설정해야 해요.
쿠버네티스는 이를 단순화하기 위해 node.kubernetes.io/windows-build 라벨을 자동으로 추가해요.
이 라벨은 호환성을 위해 일치해야 하는 Windows major, minor, build 번호를 반영해요. 각 Windows Server 버전에 사용되는 값은 다음과 같아요:
| 제품 이름 | 버전 |
|---|---|
| Windows Server 2022 | 10.0.20348 |
| Windows Server 2025 | 10.0.26100 |
RuntimeClass로 단순화하기
RuntimeClass를 사용해 taint와 toleration 사용 과정을 단순화할 수 있어요. 클러스터 관리자는 이 taint와 toleration을 캡슐화하는 데 사용되는 RuntimeClass 객체를 만들 수 있어요.