To Deploy k8s on WindowsServer with Rancher

# はじめに

近年、Windows のコンテナ技術が進み、ニュースの記事でも見る機会が増えているように思います。
今回はそんな Windows のコンテナ化です。
Windows 10Pro / DockerDesktop の記事が散見されていたため、今回は記事少なめな k8s / WindowsServer2019SE で構築します。

# 環境構成
いつも通りに VirtualBox 上に・・・

**Host Machine**
開発端末 : Window10 Pro
VirtualBox：6.0.16

**Guest Machine**

|#|Rancher|K8S Master|K8S Worker|
|:-----------------|------------------:|------------------:|------------------:|
|OS|CentOS 7.6.1810|CentOS 7.6.1810|WindowsServer 2019<br>StandardEvaluation|
|docker|19.03.5|19.03.5|19.03.5|
|Rancher|2.3.5|-|-|
|K8S|-|1.17.2|1.17.2|
|CPU/MEM/Disk|2P / 4GB / 8GB|2P / 4GB / 8GB|4P / 8GB / 50GB|
|IPAddress|192.168.10.70|192.168.10.71|192.168.10.72|

![qiita100.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/317159/3ad1b429-7a93-3481-6b88-8f7668f9c03d.jpeg)


# 準備

1. VirtualBox 上に予め3台のサーバを構築します<br>
※各サーバのはネットワークはブリッジアダプターで構築し、IP アドレスを静的に設定します<br>
※Windows サーバは「デスクトップ エクスペリエンス」でインストールします<br>
⇒今回は 180 日間の無料トライアル版の ISO を使ってインストールしています<br>
　[Windows Server 2019 Evaluation](https://www.microsoft.com/en-us/evalcenter/evaluate-windows-server-2019)<br>
※Windows サーバには以下の設定をしています<br>
　・WindowsDefender Firewall / Windows Firewall の無効化<br>
　・VirtualBox Guest Additions をインストール(任意)<br>
　・コンピュータ名変更(任意)<br>
※以下、K8S の基本構成のため、注意事項だけ記載しているのと「[gluster on k8s](https://qiita.com/t_ume/items/cce5f4cebf77af293b91)」を参考に
2. Rancher の構築<br>
注意事項、特になし。```docker run``` の 1 liner で起動します
3. クラスタの作成<br>
※クラスターのタイプは「**カスタム**」で構築します<br>
※今回は **Windows Worker** を登録するため、以下設定でクラスタを構築しています<br>
・ネットワークプロバイダー：**Flannel**<br>
・Windows Support：**有効**<br>
・Flannel Backend：VXLAN(Overlay)<br>
4. K8S Master の構築<br>
※Rancher の管理コンソールにある「Node Run Command」から実行用コマンドを使って構築してください<br>
※「etcd」、「Control」をチェックし、「Worker」のチェックは外してください<br>
※必要に応じて詳細オプションを指定してください(複数 NIC 指している場合は IP を指定できます)

ここまでで、VM の準備、Rancher、K8S Master の構築が完了しました。

# WindowsServer2019SE docker install

以下を参考にして構築していきます。
[MS 公式：環境をセットアップする](https://docs.microsoft.com/ja-jp/virtualization/windowscontainers/quick-start/set-up-environment?tabs=Windows-Server)

```powershell:docker_install
# 以下、1～3 を Powershell で実行
# 1. Docker-Microsoft PackageManagement プロバイダーのインストール
PS C:\Users\Administrator> Install-Module -Name DockerMsftProvider -Repository PSGallery -Force

続行するには NuGet プロバイダーが必要です
...
今すぐ PowerShellGet で NuGetプロバイダーをインストールしてインポートしますか?
[Y] はい(Y)  [N] いいえ(N)  [S] 中断(S)  [?] ヘルプ (既定値は "Y"): Y

# 2. docker install
PS C:\Users\Administrator> Install-Package -Name docker -ProviderName DockerMsftProvider

パッケージは、信頼済みとマークされていないパッケージ ソースから取得されています。
'DockerDefault' からソフトウェアをアンインストールしますか?
[Y] はい(Y)  [A] すべて続行(A)  [N] いいえ(N)  [L] すべて無視(L)  [S] 中断(S)  [?] ヘルプ (既定値は "N"): Y
警告: A restart is required to enable the containers feature. Please restart your machine.

Name                           Version          Source           Summary
----                           -------          ------           -------
Docker                         19.03.5          DockerDefault    Contains Docker EE for use with Windows Server.

# 3. OS reboot
PS C:\Users\Administrator> Restart-Computer -Force

# 4. 確認(cmd(コマンドプロンプト)で実行)
C:\Users\Administrator>docker version
Client: Docker Engine - Enterprise
 Version:           19.03.5
...

Server: Docker Engine - Enterprise
 Engine:
  Version:          19.03.5
...
```

# k8s Worker 登録

Rancher の管理コンソールからクラスターの編集画面、再下端で Windows 用のコマンドを取得します。

![qiita101.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/317159/47a2e09c-1cde-1353-3df6-ee1dc080699a.jpeg)

※ノードの「オペレーティングシステム」を「Windows」にすると自動的に「Worker」のみが選択されるようです。
青いボタンをクリックしてコマンドをコピーし、Windows サーバのPowershellで実行しましょう。

![qiita102.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/317159/d49c36ba-5d8b-b076-8742-a561fbebcc6c.jpeg)

途中、Rancherの画面でエラーが何度か表示されますが、時間経過で解消されます。
10～20分を目安で構築が完了し、クラスターに組み込まれます。

![qiita103.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/317159/c25d01f0-cc85-7ce5-d86a-00d0f1664503.jpeg)

# Windows コンテナ作成

それでは早速 Windows コンテナを作成してみましょう。
こちらも以下の公式サイトを参考にデプロイします。
[MS 公式：Kubernetes リソースのデプロイ](https://docs.microsoft.com/ja-jp/virtualization/windowscontainers/kubernetes/deploying-resources)
※今回使った K8S バージョンですと公式の yaml をそのまま使えなかったので、少し修正しています

まずはコンテナのデプロイから。

```yaml:container.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: win-webserver
  name: win-webserver
spec:
  selector:
    matchLabels:
      app: win-webserver
  replicas: 1
  template:
    metadata:
      labels:
        app: win-webserver
      name: win-webserver
    spec:
      containers:
      - name: windowswebserver
        image: mcr.microsoft.com/windows/servercore:1809
        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
```

デプロイも Rancher から実施できます。
「Default」の名前空間の「リソース」⇒「ワークロード」を選択し、右上「YAML をインポート」をクリックします。
「インポートモード」を「プロジェクト」とし、yaml コードを入力 ⇒ 「インポート」ボタンでデプロイされます。

![qiita104.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/317159/c33aeef1-5913-a02d-a59a-eae4ba28a6b2.jpeg)

次にアクセス確認用に Service をデプロイします。
こちらも Rancher からデプロイできます(デプロイ方法は上記と一緒)。

```yaml:service.yaml
apiVersion: v1
kind: Service
metadata:
  name: win-webserver
  labels:
    app: win-webserver
spec:
  ports:
  - nodePort: 30600
    port: 80
    protocol: TCP
    targetPort: 80
  selector:
    app: win-webserver
  type: NodePort
```

コンテナ、サービスがデプロイできたでしょうか。
初回起動時にコンテナイメージを pull するため、10～15分くらいかかります。
※servercore:1809 のイメージで 4.82 GB のサイズがありました。

![qiita105.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/317159/f575d1a2-eb47-d71d-9347-4ff7b39865c3.jpeg)

![qiita106.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/317159/a0fcd8af-cccc-aa3c-f88e-d2a14e77a486.jpeg)

また、NodePort で指定したポートに対して、Windows サーバにブラウザアクセスするとサンプルアプリがレスポンスします。
※今回の場合ブラウザで「 http://192.168.10.72:30600 」にアクセスすると以下の表示がされます
※コンテナの yaml ファイルに書かれている command 部のプログラムがレスポンスされます

|![qiita107.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/317159/1f0bb7ff-a683-7e71-72de-a91d9218a119.jpeg)|
|:-:|

# まとめ

Windows コンテナいかがでしたでしょうか。
意外と簡単に k8s / WindowsServer 上にも windows コンテナが作成できたのではないでしょうか。

また、作成されたコンテナについて補足を。

### プロセス分離化されている、Hyper-V 分離ではない

[ProcessExplorer](https://docs.microsoft.com/en-us/sysinternals/downloads/process-explorer) でプロセス状況を確認してみます。

![qiita108.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/317159/21b7d8c0-e4c9-0dcc-5069-b890e13ba6a6.jpeg)

Hyper-V 分離ですと「vmcompute.exe」の子プロセスとして起動しますが、
今回の場合「CExecSvc.exe」の子プロセスとして起動しているため「プロセス分離」としてコンテナが起動しています。

また、docker コマンドで確認すると、

![qiita109.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/317159/f7547753-9604-3052-4000-8caf5ce3538f.jpeg)

こちらでもプロセス分離で起動していることが確認とれます。
※ついでにイメージ情報も表示してあります

### コマンドラインにアクセスもできる

他コンテナ同様に Rancher からコンソールアクセスができます。

![qiita110.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/317159/61ec38e0-71b6-8101-1ddc-345a83174f51.jpeg)

![qiita111.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/317159/42a9e9c3-0676-1735-764a-6cd9394f9cb7.jpeg)

勿論のことですが、cmd から powershell も呼び出せます。