こんにちは、金融ソリューション事業部の孫です。
記事の前編では、Kubernetes上に必要なDockerイメージを作成しました。
今回は、EKSの構築に取り組み、KubernetesホスティングのUEアプリケーションを配信します。
- はじめに
- 実施手順
- 開発環境
- インフラ構造図
- 1. EKS環境の構築
- 2. Kubernetes Device Plugins for DirectXのインストールとテスト
- 3. AWS ALB Ingress Controllerのインストール
- 4. UEアプリケーションリリース用のyamlファイルの作成
- 5. プロジェクトのデプロイとデモンストレーション
- おわりに
- 参考文献
はじめに
前編で述べたように、KubernetesでGPUを必要とするサービスの実行が容易なことではなく、特にWindowsノードではさらに難しいです。
この記事では、Kubernetes Device Plugins for DirectXプラグインを使用してGPUサポート問題を解決します。
執筆時点で、WindowsノードでGPUを必要とするサービスを実行する記事はほとんど見つかりませんでした。
この記事が同様の解決策を求めている読者に役立つことを願っています。
このブログを理解するために必要な前提知識は、前編の記事を参照してください。
実施手順
- EKS環境の構築
- Kubernetes Device Plugins for DirectXのインストールとテスト
- AWS ALB Ingress Controllerのインストール
- UEアプリケーションリリース用のyamlファイルの作成
- プロジェクトのデプロイとデモンストレーション
開発環境
- eksctl: 0.176.0
- kubectl: v1.27.3
- AWS CLI: version 2
- helm: v3.14.4
- Helm chart version: 1.7.2
- wddm-device-plugin: 0.0.1
- AWS ALB Ingress Controller version: v2.7.2
インフラ構造図
以下のEKSサービスを構築します:
1. EKS環境の構築
ClusterとNodeGroupの作成
eksctl
コマンドを使用して、EKSクラスターとNodeGroupを迅速に構築します。
このクラスターには、WindowsNodeとLinuxNodeの2つのNodeGroupが含まれています。
※Tips:EKSサービスの一部プラグイン、例えばネットワークプラグイン(VPC-CNI)はLinuxノードでのみ動作するため、Windowsノードのみのクラスターを作成することはできません。
前回の記事で、NVIDIA GPUドライバを含むWindowsNodeに必要なAMIが既に作成されています。
以下のyamlファイルで設定します:
# test_windows_node_eksctl.yamlの内容 --- apiVersion: eksctl.io/v1alpha5 kind: ClusterConfig metadata: name: test-windows-node-cluster region: ap-northeast-1 version: '1.28' nodeGroups: - name: windows-ng instanceType: g4dn.2xlarge ami: ami-0ffxxxxxxx amiFamily: WindowsServer2022FullContainer volumeSize: 120 minSize: 1 maxSize: 1 - name: linux-ng amiFamily: AmazonLinux2 minSize: 1 maxSize: 1
以下のコマンドでクラスターを作成します:
$ eksctl create cluster -f test_windows_node_eksctl.yaml
作成後、CloudFormationで作成されたリソースを確認できます。
ECRアクセス権の追加
CloudFormationを開き、作成されたクラスターのStackで NodeInstanceRole
を見つけます。
クラスターがECRからイメージを引き出せるように、そのRoleページでAmazonEC2ContainerRegistryReadOnly
ポリシーをアタッチします。
これにより、ClusterとNodeGroupの作成が完了しました。
2. Kubernetes Device Plugins for DirectXのインストールとテスト
Kubernetes Device Plugins for DirectXは、GPUサービスを実行するための重要なプラグインです。
次に、このプラグインをインストールします。
インストールされたことを確認するために、まずWindowsNodeの状態情報を確認します。
割り当て可能なリソースにGPU関連のリソースはないことがわかります。
次に、プラグインのインストールを行います。
以下はインストールに使用するYamlファイルの内容です。
リソースタイプは DaemonSet
で、これにより追加する各WindowsNodeに自動的にこのプラグインがインストールされます。
また、WDDM_DEVICE_PLUGIN_MULTITENANCY
パラメータを通じて、各WindowsNodeはGPUリソースの数を設定できます。
# _DirectX-Device-DaemonSet.yamlの内容 apiVersion: apps/v1 kind: DaemonSet metadata: name: device-plugin-wddm spec: selector: matchLabels: app: device-plugin-wddm template: metadata: labels: app: device-plugin-wddm spec: nodeSelector: kubernetes.io/os: 'windows' kubernetes.io/arch: 'amd64' node.kubernetes.io/windows-build: '10.0.20348' securityContext: windowsOptions: hostProcess: true runAsUserName: "NT AUTHORITY\\SYSTEM" hostNetwork: true containers: - name: device-plugin-wddm image: "index.docker.io/tensorworks/wddm-device-plugin:0.0.1" imagePullPolicy: Always # Configure the WDDM device plugin to allow 4 containers to mount each display device simultaneously env: - name: WDDM_DEVICE_PLUGIN_MULTITENANCY value: "4"
以下のコマンドでプラグインをインストール:
$ kubectl apply -f ./DirectX-Device-DaemonSet.yaml
インストール結果の確認:
Nodeの状態情報の確認
- インストール前と比較して
directx.microsoft.com/display:
リソースが4つあります
- インストール前と比較して
GPUが正しく取得できているかの確認
GPUリソースが正常に取得できたかを確認するため、_device-discovery-wddm.yml.yaml
という確認用のyamlファイルを実行します。
# _device-discovery-wddm.yml.yamlの内容 apiVersion: batch/v1 kind: Job metadata: name: example-device-discovery-wddm spec: template: spec: containers: - name: example-device-discovery-wddm image: "index.docker.io/tensorworks/example-device-discovery:0.0.1" resources: limits: directx.microsoft.com/display: 1 nodeSelector: "kubernetes.io/os": windows restartPolicy: Never backoffLimit: 0
以下のコマンドでYamlファイルを実行:
$ kubectl apply -f ./_device-discovery-wddm.yml.yaml
これにより、ホストマシンにインストールされているNvidiaビデオカード情報を取得できるかを確認します。
# _nvidia-smi-wddm.ymlの内容 apiVersion: batch/v1 kind: Job metadata: name: example-nvidia-smi spec: template: spec: containers: - name: example-nvidia-smi image: "mcr.microsoft.com/windows/servercore:ltsc2022" command: ["nvidia-smi.exe"] resources: limits: directx.microsoft.com/display: 1 nodeSelector: "kubernetes.io/os": windows restartPolicy: Never backoffLimit: 0
以下のコマンドでyamlファイルを実行:
$ kubectl apply -f ./_nvidia-smi-wddm.yml
これにより、Nvidia GPUの状態を確認し、結果を得られます。
3. AWS ALB Ingress Controllerのインストール
PixelStreamingサービスが外部からアクセス可能になるように、AWS ALB Ingress Controllerプラグインをインストールします。
このプラグインを使って、アプリケーションロードバランサー(以下はALB)を作成します。
ALB Ingress Controller用のIAMの構築
# OIDC Create $ eksctl utils associate-iam-oidc-provider --region ap-northeast-1 --cluster test-windows-node-cluster --approve # AWS Load Balancer ControllerにIAMポリシーを作成し、AWS APIへの呼び出しを代行させる。 $ curl -o iam_policy_latest.json https://raw.githubusercontent.com/kubernetes-sigs/aws-load-balancer-controller/main/docs/install/iam_policy.json # Create Policy $ aws iam create-policy \ > --policy-name AWSLoadBalancerControllerIAMPolicy \ > --policy-document file://iam_policy_latest.json $ eksctl create iamserviceaccount \ > --cluster=test-windows-node-cluster \ > --namespace=kube-system \ > --name=aws-load-balancer-controller \ > --attach-policy-arn=arn:aws:iam::236960927670:policy/AWSLoadBalancerControllerIAMPolicy \ > --override-existing-serviceaccounts \ > --approve # iamserviceaccountの確認 $ eksctl get iamserviceaccount --cluster test-windows-node-cluster NAMESPACE NAME ROLE ARN kube-system aws-load-balancer-controller arn:aws:iam:: $ kubectl get sa aws-load-balancer-controller -n kube-system NAME SECRETS AGE aws-load-balancer-controller 0 32s
aws-load-balancer-controller インストール
# 参考:https://github.com/aws/eks-charts/tree/master/stable/aws-load-balancer-controller helm repo add eks https://aws.github.io/eks-charts $ helm install aws-load-balancer-controller eks/aws-load-balancer-controller -n kube-system --set clusterName=test-windows-node-cluster --set serviceAccount.create=false --set serviceAccount.name=aws-load-balancer-controller # インストールされていることを確認。 kubectl -n kube-system get deployment NAME READY UP-TO-DATE AVAILABLE AGE aws-load-balancer-controller 0/2 2 0 10s # Webhook-svcが作成されていることを確認。 $ kubectl -n kube-system get svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE aws-load-balancer-webhook-service ClusterIP xx.xxx.xx.x <none> 443/TCP 102m kube-dns ClusterIP xx.xxx.xx.x <none> 53/UDP,53/TCP,9153/TCP 3m9s
4. UEアプリケーションリリース用のyamlファイルの作成
TURNサービスリリース用yaml
以下はTURNサービスへの接続用のアカウント名とパスワードを設定するyamlの内容です。
今回はDemoのため、アカウント名とパスワードは平文で処理されています。
ただし、実際の本番環境では、KubernetesのSecretリソースタイプを使用してこれらの情報を安全に作成するべきです。
# _turn-demo-deployment.yamlの内容 --- apiVersion: apps/v1 kind: DaemonSet metadata: name: turn-demo labels: app: turn-demo spec: selector: matchLabels: app: turn-demo template: metadata: labels: app: turn-demo spec: restartPolicy: Always terminationGracePeriodSeconds: 30 hostNetwork: true nodeSelector: kubernetes.io/os: linux containers: - name: turn-server image: [aws accound id].dkr.ecr.ap-northeast-1.amazonaws.com/turn-windows-demo:latest imagePullPolicy: Always ports: - name: turn-udp containerPort: 3478 hostPort: 3478 protocol: UDP - name: turn-tcp containerPort: 3478 hostPort: 3478 protocol: TCP env: - name: INTERNAL_IP valueFrom: fieldRef: fieldPath: status.podIP # Firewall rules on the node pool instances must be created for these port ranges - name: TURN_PORT value: "3478" - name: TLS_PORT value: "443" - name: TURN_MIN_PORT value: "49152" - name: TURN_MAX_PORT value: "65535" - name: TURN_REALM value: turnserver - name: TURN_USER value: [turn username] - name: TURN_PASS value: [turn password]
PixelStreamingサービス用yamlファイル
ネットワーク遅延を低減するため、SignallingサーバーとUnrealEngineのデモゲームを同一のPodに配置しています。
以下のパラメータ設定に注意してください:
--peerConnectionOptions
中のSTUN/TURNサービスのIPアドレスは、LinuxNodeのPublicIPであるべきです。--peerConnectionOptions
中のSTUN/TURNサービスのアカウント名とパスワードは、_turn-demo-deployment.yaml
で設定された値と一致する必要があります。- GPUリソースの割り当てについては、
directx.microsoft.com/display
値を指定することで設定します。
# _demo-deployment.yamlの内容 apiVersion: apps/v1 kind: Deployment metadata: name: ue-demo-deployment labels: app: ue-demo-app spec: replicas: 1 selector: matchLabels: app: ue-demo-app template: metadata: labels: app: ue-demo-app spec: nodeSelector: "kubernetes.io/os": "windows" containers: - name: signalling-server image: [aws accound id].dkr.ecr.ap-northeast-1.amazonaws.com/signalling-windows-demo:latest ports: - name: http containerPort: 80 - name: stream containerPort: 8888 command: ["cmd", "/C"] args: - "node" - "cirrus.js" - '--peerConnectionOptions={"iceServers":[{"urls":["stun:[linuxNode Public IP]:3478","turn:[linuxNode Public IP]:3478?transport=udp"],"username":"[turn username]","credential":"[turn password]"}]}' - name: ue-project-demo image: [aws accound id].dkr.ecr.ap-northeast-1.amazonaws.com/unreal-engine-windows-demo:latest imagePullPolicy: Always resources: limits: directx.microsoft.com/display: 1
ALB作成用のyamlファイル
httpサービス用のALBを作成します。ユーザーがこのALBのDNSアドレスにアクセスすることで、デモUEアプリケーションにアクセスできます。
# _demo-ingress.yamlの内容 # Service apiVersion: v1 kind: Service metadata: name: demo-web-service labels: app: ue-demo-app spec: type: ClusterIP selector: app: ue-demo-app ports: - name: http protocol: TCP port: 80 targetPort: 80 --- apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: demo-web annotations: alb.ingress.kubernetes.io/load-balancer-name: demo-alb alb.ingress.kubernetes.io/scheme: internet-facing alb.ingress.kubernetes.io/target-type: ip spec: ingressClassName: alb rules: - http: paths: - path: / pathType: Prefix backend: service: name: demo-web-service port: number: 80
5. プロジェクトのデプロイとデモンストレーション
以下のコマンドでyamlファイルをデプロイします::
$ kubectl apply -f _turn-demo-deployment.yaml $ kubectl apply -f _demo-deployment.yaml $ kubectl apply -f _demo-ingress.yaml
ユーザーとPixelStreamingサーバー間のメディアストリーミング転送は、主にTURNサーバーを通じてリレーされます。
そのため、LinuxNodeのセキュリティグループで以下のインバウンドポートを開放する必要があります。
セキュリティグループ編集
以下のポートを開放します:
TCP 32355-65535 0.0.0.0/0 UDP 32355-65535 0.0.0.0/0 TCP 3478 0.0.0.0/0 UDP 3478 0.0.0.0/0
UEアプリケーションへのアクセス
以下のコマンドでALBのDNSアドレスを確認します:
$ kubectl get ingress
ブラウザで ADDRESS
列に表示されたアドレスを入力すると、UEアプリケーションにアクセスできます!
おわりに
Amazon EKSのWindowsノードでUEアプリケーションの配信に成功しました!
通常、ゲーム開発はWindowsシステムで行われることが多いです、特にUnreal Engineなどの開発エンジンを使用する開発者にとってはそうです。
ゲーム製品とOSの互換性を確保するために、通常はWindows Server環境でゲームをリリースすることが推奨されます。
以前は、KubernetesにはWindowsコンテナ内のGPUアプリケーションのサポートが限られていました。
そのため、ゲーム開発者は従来のEC2インスタンスに依存してゲームサーバーをデプロイおよび運用する必要があり、運用の柔軟性と拡張性を制限していました。
今回のブログを通じて、Kubernetes上でのWindowsコンテナのGPUサポート問題は解決されたことが確認できました。
これにより、将来的にWindowsコンテナがKubernetes領域で広く利用される可能性が示されました!
現在、電通総研はweb3領域のグループ横断組織を立ち上げ、Web3およびメタバース領域のR&Dを行っております(カテゴリー「3DCG」の記事はこちら)。 もし本領域にご興味のある方や、一緒にチャレンジしていきたい方は、ぜひお気軽にご連絡ください!
私たちと同じチームで働いてくれる仲間をお待ちしております!
電通総研の採用ページ
参考文献
- PixelStreamingInfrastructure
- Offscreen rendering in Windows containers
- Kubernetes Secrets
- DirectX-Device-Plugins
- Containers Quick Start
- epicgame packages
- Application load balancing on Amazon EKS
- Amazon EKS optimized Windows AMIs
- eksctl Config file Schema
執筆:@chen.sun、レビュー:@miyazawa.hibiki
(Shodoで執筆されました)