5
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Kubernetes2Advent Calendar 2019

Day 22

0からはじめる Windows on Kubernetes

Last updated at Posted at 2019-12-22

はじめに

Kubernetes の Windows 対応は v.1.14 でGAとなりました。
本記事では、既存の Kubernetes クラスタに0から Windows ワーカーノードを追加する方法をご紹介します。

実行環境

今回は実行環境として Azure を使用しています。

  • Kubernetes クラスタ(hard way on azure で作成)
    • Linux VM(ubuntu 18.04)×6
  • Windows ノード
    • Windows VM(Windows Server 2019 Datacenter)×1
# クラスタには3台の Linux ワーカーノード
$ kubectl get no
NAME       STATUS   ROLES    AGE     VERSION
worker-0   Ready    <none>   12m     v1.15.0
worker-1   Ready    <none>   7m26s   v1.15.0
worker-2   Ready    <none>   5m59s   v1.15.0

クラスタ側の修正

hard way で作成したクラスタですが、kube-controller-manager の起動オプションが足りていません。

kube-controller-manager.service
[Unit]
Description=Kubernetes Controller Manager
Documentation=https://github.com/kubernetes/kubernetes

[Service]
ExecStart=/usr/local/bin/kube-controller-manager \
  --address=0.0.0.0 \
+ --allocate-node-cidrs=true \
  --cluster-cidr=10.200.0.0/16 \
  --cluster-name=kubernetes \
  --cluster-signing-cert-file=/var/lib/kubernetes/ca.pem \
  --cluster-signing-key-file=/var/lib/kubernetes/ca-key.pem \
  --kubeconfig=/var/lib/kubernetes/kube-controller-manager.kubeconfig \
  --leader-elect=true \
  --root-ca-file=/var/lib/kubernetes/ca.pem \
  --service-account-private-key-file=/var/lib/kubernetes/service-account-key.pem \
  --service-cluster-ip-range=10.32.0.0/24 \
  --use-service-account-credentials=true \
  --v=2
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target

このオプションがないとcluster-cidrが適用されず、ノードのpodCIDRが未設定になってしまいます。
以降で使用するスクリプトでpodCIDRが必要になるので、事前に修正しておきましょう。

Windows ノードの追加

途中までMSのドキュメントを参考に進めていきます。

Docker のインストール

手順に従って Docker をインストールし、マシンを再起動します。

Install-Module -Name DockerMsftProvider -Repository PSGallery -Force
Install-Package -Name Docker -ProviderName DockerMsftProvider
Restart-Computer -Force

再起動後、docker pullでコンテナイメージを取得します。
ここで取得するイメージは Pod 内のインフラ用コンテナの作成に使用します。
Dockerfile に記載されているイメージはタグが未指定なので、取得したイメージに latest タグを付加してください。

docker pull mcr.microsoft.com/windows/nanoserver:1809
docker tag mcr.microsoft.com/windows/nanoserver:1809 mcr.microsoft.com/windows/nanoserver:latest

ちなみにインストールが完了すると、Get-HNSNetworkなど HNS の操作が可能になります。

実行ファイルの用意

Kubernetes のファイルを配置するディレクトリを作成します。

mkdir c:\k

ディレクトリを作成したら以下のファイルを配置してください。

  • クラスタに接続できる kubeconfig(ファイル名は config)
  • kubernetes ノード用バイナリ
    • kubectl.exe
    • kubelet.exe
    • kube-proxy.exe

バイナリは Kubernetes のリリースページにアクセスし、CHANGE LOGから取得できます。
次のような構成になっていればOKです。

ls config,*exe

    Directory: C:\k

Mode                LastWriteTime         Length Name
----                -------------         ------ ----
-a----       12/22/2019  11:49 AM           6254 config
-a----       12/11/2019   1:14 PM       40086016 kube-proxy.exe
-a----       12/11/2019   1:20 PM       47195136 kubectl.exe
-a----       12/11/2019   1:20 PM      119127552 kubelet.exe

スクリプトの実行

ではいよいよ、各種設定とバイナリの起動を行う powershell スクリプトを実行していきます。
github からスクリプトをダウンロードしてください。

cd c:\k
Start-BitsTransfer https://github.com/microsoft/SDN/raw/master/Kubernetes/windows/start.ps1

ここではMSのドキュメントの手順とは異なるスクリプトをダウンロードしています。
MSのドキュメントでは CNI プラグインとして flannel を使用し、vxlan overlay ネットワークを構成しています。
flannel はクラスタに事前にインストールする必要がありますが、hard way のクラスタでは別の CNI プラグインを使用しているため、今回は flannel を使用しない方法を取りました。
ダウンロードしたスクリプトでは wincni.exe を使用し、L2 ブリッジネットワークを構成します。(overlay も選択可)

start.ps1 は以下の処理を順番に行います。

  1. 必要なバイナリ、スクリプト、Dockerfile をダウンロード
  2. コンテナイメージを作成(InstallImages.ps1)
  3. HNS ネットワークを初期化
  4. kubelet を起動(start-kubelet.ps1)
  5. kube-proxy を起動(start-kubeproxy.ps1)
  6. ルーティングテーブルに追加(AddRoutes.ps1)

スクリプト1つで必要な処理をすべて行ってくれるようです。
またスクリプトの中を見てみると、2つの param を設定できることがわかります。

start.ps1
Param(
    [parameter(Mandatory = $true)] [string] $masterIp,
    [parameter(Mandatory = $false)] $clusterCIDR="192.168.0.0/16"
)

masterIpは VM のプライベートIP(10.240.0.4)、clusterCIDRは上述の kube-controller-manager で設定した値(10.200.0.0/16)を使用します。

.\start.ps1 -masterIp 10.240.0.4 -clusterCIDR 10.200.0.0/16

これでノードの追加完了!…とはいきませんでした。

動かない…

案の定そのままでは動きませんでした。
powershell ウィンドウにはWaiting for the Network to be createdが延々と出力され続けていると思います。
一度実行すると必要なファイル等はダウンロードされるので、start.ps1は捨てて個別のスクリプトを修正&実行していきます。

スクリプトの修正&実行

helper.psm1

helper.psm1
function Get-PodCIDR()
{
-   return c:\k\kubectl.exe --kubeconfig=c:\k\config get nodes/$($(hostname).ToLower()) -o custom-columns=podCidr:.spec.podCIDR --no-headers
+   return "10.200.3.0/24"
}

まずはモジュールの修正から。
これは本当に疑問なのですが、ノードの追加前なのにクラスタから自身のノード情報を取得しようとしているのはどうしてでしょうか…?(間違っていたらご指摘ください)
当然取得はできないので、自分で決めた podCIDR を返すように修正します。
モジュールをインポート済みの場合は一度削除しておいてください。

Remove-Module helper

InstallImages.ps1

問題なく実行できているので、修正・再実行は行いません。
事前に取得した Docker イメージから、pause コンテナを作成しています。

docker image ls | Out-String -Stream | Select-String pause
kubeletwin/pause                       latest              14d3bdf2f5cb        5 hours ago         251MB

start-kubelet.ps1

start-kubelet.ps1
Param(
+   $clusterCIDR="10.200.0.0/16",
-   $clusterCIDR="192.168.0.0/16",
    $NetworkMode = "L2Bridge",
    $NetworkName = "l2bridge",
    [ValidateSet("process", "hyperv")]
    $IsolationType = "process"
)

# Todo : Get these values using kubectl
$KubeDnsSuffix ="svc.cluster.local"
+$KubeDnsServiceIp="10.32.0.10"
-$KubeDnsServiceIp="11.0.0.10"
+$serviceCIDR="10.32.0.0/24"
-$serviceCIDR="11.0.0.0/8"

Todo と記載された変数は外から設定できないようです。なぜこんなところに?
$KubeDnsServiceIpには kube-dns サービスのクラスタIP、$serviceCIDRには kube-controller-manager で設定したservice-cluster-ip-rangeを使用します。
ついでに param の$clusterCIDRも修正しておきました。これでオプションなしでスクリプトを実行できるはずです。

.\start-kubelet.ps1

成功するとフォアグラウンドで kubelet.exe が実行中になるので、別の powershell ウィンドウを起動してください。
start powershellで別ウィンドウで起動しても良いです)

kubelet を無事に起動できると、クラスタにノードが追加されていることが確認できます。

$ kubectl get no
NAME         STATUS   ROLES    AGE    VERSION
win-server   Ready    <none>   173m   v1.16.4
worker-0     Ready    <none>   28h    v1.15.0
worker-1     Ready    <none>   28h    v1.15.0
worker-2     Ready    <none>   28h    v1.15.0

start-kubelet.ps1

start-kubelet.ps1
Param(
    [parameter(Mandatory = $false)] $LogDir = "C:\k",    
    $NetworkName = "cbr0"
)

特に修正の必要はありません。
初回起動時にはここまで到達していないので、スクリプトを実行します。
他の箇所とは違い$NetworkNameの初期値がなぜかcbr0になっていますが、惑わされずにl2bridgeを指定しましょう。(私は惑わされました)

.\start-Kubeproxy.ps1 -NetworkName l2bridge

成功するとフォアグラウンドで kube-proxy.exe が実行中になります。

AddRoutes.ps1

最後にこのスクリプトを実行します。
こちらも修正は不要です。
初回起動時と同様、$masterIpには VM のプライベートIPをしていてください。

.\AddRoutes.ps1 -masterIp 10.240.0.4

これでノードの追加完了です!

動作確認

Windows コンテナのデプロイを試したり、Linux ノード上のコンテナから Windows ノード上のコンテナにアクセスしてみたり、色々と試してみてください。

$ kubectl get po,svc -o wide
NAME                                 READY   STATUS    RESTARTS   AGE   IP             NODE        NOMINATED NODE   READINESS GATES
pod/busybox                          1/1     Running   13         13h   10.200.2.4     worker-2    <none>           <none>
pod/nginx                            1/1     Running   0          38h   10.200.1.3     worker-1    <none>           <none>
pod/ubuntu                           1/1     Running   0          20h   10.200.1.4     worker-1    <none>           <none>
pod/win-webserver-784d66c84f-bqh9l   1/1     Running   0          10h   10.200.3.159   win-server  <none>           <none>
pod/win-webserver-784d66c84f-ssxfr   1/1     Running   0          10h   10.200.3.39    win-server  <none>           <none>

NAME                    TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)        AGE   SELECTOR
service/kubernetes      ClusterIP   10.32.0.1    <none>        443/TCP        38h   <none>
service/nginx           NodePort    10.32.0.52   <none>        80:32121/TCP   37h   run=nginx
service/win-webserver   NodePort    10.32.0.65   <none>        80:31663/TCP   10h   app=win-webserver

サービスとして起動する

今回は powershell 上で kubelet.exe と kube-proxy.exe を起動しましたが、これらを Windows のサービスとして起動する方法もあります。
詳細はこちらをご参照ください。

感想

最後までたどり着いて本当に良かった…
色々と悩んで調べまわった結果、ネットワーク周りと powershell の知識が身についてきたのは良かったです。
Issue はあまり確認する時間がなかったので、きちんと調べたら別の方法があったかもしれません。何かご存知の方は教えてくださいm(_ _)m

実際に Windows ノードを使用する場合は、やはりマネージドサービスがおススメです。AKS であれば Windows ノードプールを指定するだけで簡単に始められます。
オンプレの場合は kubeadm + flannel を使用した方法が kubernetes.io で紹介されています。その他の方法についてもサイト下部に記載があるので、興味のある方は読んでみてください。

参考

Joining Windows Server Nodes to a Cluster
github: microsoft/SDN/Kubernetes/Windows
KubernetesとFlannelでWindows上にPod間VXLAN Overlayネットワークを構成
Kubernetes Networking: Behind the scenes
Troubleshooting Kubernetes Networking on Windows: Part 1

5
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?