fbpx

Docker Enterprise の Kubernetes にWindows Workerノードを追加する #docker #mirantis #kubernetes #k8s

この記事は1年以上前に投稿されました。情報が古い可能性がありますので、ご注意ください。

本ブログは Mirantis社のblog記事「Windows Worker Nodes for Docker Enterprise Kubernetes: Easily add and scale Windows workload capacity」の翻訳記事です。

Docker Enterprise 3.1 の Kubernetes 1.17 では、Windows Worker ノードを簡単にクラスタに追加できます(クラスタの Master ノードは Linux 上で動作する必要があります)。新しく結合されたWindows Workerノード は Docker Enterprise の Kubernetes によって即座に認識され、deployment YAML の spec 内の nodeSelector に従ってワークロードをスケジューリングできます。

この Windows ベースのコンテナをオーケストレーションする機能の追加によって、Windows コンテナ形式のコンポーネントを幅広く活用する事が可能となり、Windows でのアプリケーションの開発や、アプリケーションのモダナイズを効率化し推進することが可能となります。
これにより、可用性を保証しスケーリングを促進するとともに、使い慣れた Windows 環境においても、コンテナ化やミッションクリティカル(またはレガシーな)Windowsアプリケーションの運用が比較的容易になります。もちろん、Azure Stack や Windows Server の仮想およびベアメタルインフラを提供する他のクラウドプラットフォームなども利用可能です。

Windows Server Worker ノードの設定

Windows Server の Workerノードをクラスタへ追加する前に、もちろんクラスタ自体を用意しなければなりません。クラスタを構築していない場合は、Getting Started Blog日本語訳)を参照してクラスタを構築してください。

次に Windows Server ノードを作成し、そこに Docker Enterprise 3.1 のソフトウェアを設定してクラスタに追加するための準備を行います。

以下の手順では、PowerShell を管理者権限で実行して、Docker Enterprise 3.1 で Kubernetes ワーカーとして使用するための Windows Server 2019 の設定を詳細に説明します。クラウドホストを使用する場合は、コンテナ用にあらかじめ設定されたイメージではなく、Windows Server 2019 の OS イメージを選択してください。

Windows コンテナ機能を有効にしてから再起動します。改行をマークするためにバッククォートが使われていることに注意してください。

Enable-WindowsOptionalFeature `
  -All `
  -FeatureName containers `
  -Online;

その後、必要に応じてコンピュータを再起動します。

Restart-Computer;

再起動後、リモートでダウンロードしたスクリプトを現在のセッションで実行できるように実行ポリシーを設定します。

Set-ExecutionPolicy `
  -ExecutionPolicy RemoteSigned `
  -Force `
  -Scope Process;

次に、インストール用スクリプトをダウンロードします。

Invoke-WebRequest `
  -OutFile 'install.ps1' `
  -Uri 'https://get.mirantis.com/install.ps1' `
  -UseBasicParsing;

そして、ダウンロードしたスクリプトを実行します。

.\install.ps1 -Channel 'test' -dockerVersion '19.03.8';

スクリプトの実行後、パスを更新するために一度ログアウトしてから再度ログインする必要があります。

logoff

再度ログインして、インストール用スクリプトを削除します。

Remove-Item -Path 'install.ps1';

この初期設定後、UCP イメージをダウンロードしてローカルの Docker リポジトリに保存します。

PowerShell のステータスバーをオフにすると、ダウンロード速度が向上します。

$ProgressPreference = 'SilentlyContinue'

そして、UCP のイメージバンドルをダウンロードします。

Invoke-WebRequest `
  -OutFile 'ucp_images.tar.gz' `
  -Uri 'https://packages.docker.com/caas/ucp_images_win_2019_3.3.0.tar.gz' `
  -UseBasicParsing;

ダウンロード後、イメージバンドルをリポジトリにロードします。

docker load --input 'ucp_images.tar.gz';

イメージを参照して登録されているか確認します。

docker images;

最後に、ダウンロードしたイメージバンドルのアーカイブを削除します。

Remove-Item -Path 'ucp_images.tar.gz';

この時点で、クラスタにノードを追加するために必要な「 docker join 」コマンドを Docker Enterprise の UI から取得できます。 このコマンドは、Managerノードコンソールから " docker swarm join-token worker "を実行する事でも取得できます。これを新しく追加する Windows Workerノード の PowerShell コマンドラインにコピーして実行します。コマンドを実行した Worker ノードは Docker Enterprise によって Windows Worker ノードとして認識され、ノードリストに表示されます。

新しいノードを Kubernetes Worker として追加するように Docker Enterprise を設定している場合(Admin Settings の Orchestration で設定)、新しいノードは Kubernetes Worker として起動されます。デフォルトでは「 swarm 」として設定されています。 Kubernetes に切り替えるには、Manager ノードのコンソールから以下のコマンドを実行します。

docker node update <nodename> --label-add com.docker.ucp.orchestrator.kubernetes=true
docker node update <nodename> --label-rm com.docker.ucp.orchestrator.swarm

動作を確認してみましょう

簡単なテストデプロイを実行してみましょう。

この例では、ロードバランサの後ろに2つの Pod を持つ Windows ウェブサーバをデプロイしています。デプロイするには、アカウント用に Docker Enterprise の UI からダウンロードした Client Bundle の env.sh スクリプトを使って " kubectl " をマシンにインストールし、 Docker Enterprise クラスタに認証する必要があります。詳しくは Getting Started Blog日本語訳)を参照してください。

以下のコードは、Kubernetesのドキュメントで紹介されているものと同じです。

はじめに、作業用の namespace を作成します。

次の内容で demo-namespace.yaml を作成します。

# demo-namespace.yaml
apiVersion: v1
kind: Namespace
metadata:
  name: demo

作成した yaml ファイルを使って namespace を作成します。

kubectl create -f demo-namespace.yaml

次の内容で win-webserver.yaml を作成します。
この YAML にはウェブサーバを設定する組み込みコマンドが含まれており、応答するウェブサーバが実行されている Pod の IP を識別することで、リクエスト (この場合はポート 80 で起動している service の IP アドレス) に応答するアプリを作成していることに注意してください。このアプリはロードバランシングの確認に使用します。

# win-webserver.yaml
apiVersion: v1
kind: Service
metadata:
  name: win-webserver
  namespace: demo
  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
    namespace: demo
  name: win-webserver
  namespace: demo
spec:
  replicas: 2
  selector:
    matchLabels:
      app: win-webserver
  template:
    metadata:
      labels:
        app: win-webserver
      name: win-webserver
    spec:
      affinity:
        podAntiAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            - labelSelector:
                matchExpressions:
                  - key: app
                    operator: In
                    values:
                      - win-webserver
              topologyKey: "kubernetes.io/hostname"
      containers:
        - name: windowswebserver
          image: mcr.microsoft.com/windows/servercore:ltsc2019
          command:
            - powershell.exe
            - -command
            - "<#code used from https://gist.github.com/wagnerandrade/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:
        beta.kubernetes.io/os: windows

このYAMLファイルをデプロイします。

kubectl create -f win-webserver.yaml

デプロイした service の動作を確認します。

kubectl get service --namespace demo

※ コマンド出力例

NAME            TYPE       CLUSTER-IP    EXTERNAL-IP   PORT(S)        AGE
win-webserver   NodePort   10.96.29.12   <none>        80:35048/TCP   12m

コマンドの実行結果として service のIPアドレスが表示されます。ブラウザでアクセスするとアプリの画面が表示されます。

service のIPアドレスをcurlで何度か連続して呼び出して見てください。

curl 10.96.29.12

アプリが2つの異なるIPアドレスを持つ2つの Pod にデプロイされ、受信するリクエストが負荷分散されていることを確認してください。

最後に service と namespace を削除してください。

kubectl delete service win-webserver
kubectl delete namespace demo

これで Windows Worker ノードを追加してアプリをデプロイ出来ました。

新規CTA