Introduction

docker for windows が有償化されてしまったため、その代替手段の模索。
色々調べてみると、Minikube を使った方法で、docker エンジンを Windows に組み込めることがわかった。

やっていることは、docker for windows と同様、Hyper-V 仮想マシン上で docker エンジンを動かすだけで、その環境構築を Minikube 経由で行うということ。

この記事の前提は

  • Windows 10
  • VT-x または AMD-v が有効な CPU かつ BIOS で有効になっていること

How to get started?

Hyper-V と Hypervisor の有効化

既に有効ならスキップ。
管理者権限で起動した Powershell から下記を入力。

1
2
$ Enable-WindowsOptionalFeature -Online -FeatureName Microsoft-Hyper-V -All
$ Enable-WindowsOptionalFeature -Online -FeatureName HypervisorPlatform

それぞれインストール完了後、再起動を問われますが、全部終わったら再起動でいいと思います。
一度再起動。

Chocolatey のインストール

既にインストール済みならスキップ。
管理者権限で起動した Powershell から下記を入力。

1
> Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'))

インストール完了後の確認

1
2
> choco --version
1.1.0

Minikube のインストール

Chocolatey からインストール。
管理者権限で起動した Powershell から下記を入力。

1
$ choco install minikube

インストール完了後の確認

1
2
3
$ minikube version
minikube version: v1.26.0
commit: f4b412861bb746be73053c9f6d2895f12cf78565

docker-cli のインストール

Chocolatey からインストール。
管理者権限で起動した Powershell から下記を入力。

1
$ choco install docker-cli

インストール完了後の確認

1
2
3
4
5
6
7
8
9
10
11
12
$ docker version
docker version
Client:
Version: 20.10.17
API version: 1.41
Go version: go1.17.11
Git commit: 100c701
Built: Mon Jun 6 23:09:02 2022
OS/Arch: windows/amd64
Context: default
Experimental: true
error during connect: In the default daemon configuration on Windows, the docker client must be run with elevated privileges to connect.: Get "http://%2F%2F.%2Fpipe%2Fdocker_engine/v1.24/version": open //./pipe/docker_engine: The system cannot find the file specified.

Hyper-V 仮想スイッチの追加

Minikube が仮想スイッチを介して、Hyper-V の仮想マシンにアクセスするために必要。
Powershell を管理者権限付きで起動。

まず、現在のネットワークアダプタ設定を取得。

1
2
3
4
5
6
7
$ Get-NetAdapter

Name InterfaceDescription ifIndex Status MacAddress LinkSpeed
---- -------------------- ------- ------ ---------- ---------
Wi-Fi Intel(R) Wireless-N 7260 14 Up A0-A8-CD-4B-93-03 144.4 Mbps
イーサネット Realtek PCIe GbE Family Controller 9 Disconnected C0-3F-D5-6B-8F-CB 0 bps
vEthernet (Default Swi... Hyper-V Virtual Ethernet Adapter 42 Up 00-15-5D-BF-F6-25 10 Gbps

この中から、外部に繋がっているネットワークの名前を記憶。
ここでは Wi-Fi とします。

次に、先程のネットワークを使って、外部ネットワーク の仮想スイッチを作成。
引数 --name に指定する仮想スイッチの名前は自由。

一度ネットワークが切断されるかもしれないので注意。

1
2
3
4
5
$ New-VMSwitch -name "Minikube ExternalSwitch"  -NetAdapterName "Wi-Fi" -AllowManagementOS $true

Name SwitchType NetAdapterInterfaceDescription
---- ---------- ------------------------------
Minikube ExternalSwitch External Intel(R) Wireless-N 7260

成功すると、Hyper-V マネージャー仮想スイッチマネージャー に、今追加した仮想スイッチが追加されているのがわかります。

switch

なお、既に指定したネットワークアダプタが外部ネットワークとして使用されている場合はエラーになる。

Minikube の起動

コマンドプロンプトを管理者権限付きで起動。
後述しますが、PowerShell からの起動は不可です。

ここでは、仮想マシンの作成、起動を行われます。
引数 --hyperv-virtual-switch には、先程作成した仮想スイッチの名前を指定。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
$ minikube start --vm-driver=hyperv --hyperv-virtual-switch="Minikube ExternalSwitch"
* Microsoft Windows 10 Pro 10.0.19042 Build 19042 上上のの minikube v1.26.0
* ユーザーの設定に基づいて hyperv ドライバーを使用します
* VM ブートイメージをダウンロードしています...
> minikube-v1.26.0-amd64.iso....: 65 B / 65 B [----------] 100.00% ? p/s 0s
> minikube-v1.26.0-amd64.iso: 268.86 MiB / 268.86 MiB 100.00% 7.85 MiB p/s
* minikube クラスター中のコントロールプレーンの minikube ノードを起動しています
* ロード済み Kubernetes v1.24.1 をダウンロードしています...
> preloaded-images-k8s-v18-v1...: 405.83 MiB / 405.83 MiB 100.00% 7.41 MiB
* hyperv VM (CPUs=2, Memory=2200MB, Disk=20000MB) を作成しています...
* Docker 20.10.16 で Kubernetes v1.24.1 を準備しています...
- 証明書と鍵を作成しています...
- コントロールプレーンを起動しています...
- RBAC のルールを設定中です...
* Kubernetes コンポーネントを検証しています...
- gcr.io/k8s-minikube/storage-provisioner:v5 イメージを使用しています
* 有効なアドオン: default-storageclass, storage-provisioner
* 終了しました!kubectl がデフォルトで「minikube」クラスターと「default」ネームスペースを使用するよう設定されました

start コマンドのオプションは start を参照。

よくあるのが、

引数 意味
–memory メモリサイズの指定。単位 (b, k, m, g) と共に数字で指定。 –memory 2048m

起動後の確認

1
2
3
4
5
6
7
$ minikube status
minikube
type: Control Plane
host: Running
kubelet: Running
apiserver: Running
kubeconfig: Configured

注意1

重要なこととして、直接コマンドプロンプトを管理者権限で起動してください。

Windows 10 の場合、Windows メニューを右クリックして表示される一覧には Windows PowerShell (管理者) があり、そこから cmd でコマンドプロンプトに切り替えることもできますが、この方法では失敗します。

管理者権限付きの PowerShell からコマンドプロンプトを起動した場合は、

1
2
3
4
5
6
$ > minikube start --vm-driver=hyperv --hyperv-virtual-switch="Minikube ExternalSwitch"
* Microsoft Windows 10 Pro 10.0.19042 Build 19042 上の minikube v1.26.0
* ユーザーの設定に基づいて hyperv ドライバーを使用します

X PROVIDER_HYPERV_NOT_RUNNING が原因で終了します: C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -NoProfile -NonInteractive @([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator") returned ""
* 提案: Unable to determine current user's administrator privileges

注意2

プロキシ環境では、自マシンへのアクセスに対して、プロキシを経由しないようにする必要がある。
つまり

1
2
3
setx HTTP_PROXY http://xxx.xxx.xxx.xxx:xxxx
setx HTTPS_PROXY http://xxx.xxx.xxx.xxx:xxxx
setx NO_PROXY 192.168.11.18

のように、プロキシと除外設定をつけておく。

start で動かない場合は minikube logs -f で状況を把握できる。

ダッシュボードの起動

1
2
3
4
5
$ minikube dashboard
* ダッシュボードの状態を検証しています...
* プロキシーを起動しています...
* プロキシーの状態を検証しています...
* デフォルトブラウザーで http://127.0.0.1:50406/api/v1/namespaces/kubernetes-dashboard/services/http:kubernetes-dashboard:/proxy/ を開いています...

dashboard

サンプルの実行

1
2
3
4
5
6
7
8
9
$ kubectl create deployment hello-node --image=k8s.gcr.io/echoserver:1.4
$ kubectl expose deployment hello-node --type=LoadBalancer --port=8080
$ minikube service hello-node
|-----------|------------|-------------|----------------------------|
| NAMESPACE | NAME | TARGET PORT | URL |
|-----------|------------|-------------|----------------------------|
| default | hello-node | 8080 | http://192.168.11.39:31937 |
|-----------|------------|-------------|----------------------------|
* デフォルトブラウザーで default/hello-node サービスを開いています...

dashboard

service

Minikube の停止

1
$ minikube stop

docker の設定

現時点で、Hyper-V 上の仮想マシンで docker エンジンが動いているので、docker-cli にその旨を設定してあげる。

管理者権限で起動したコマンドプロンプトで下記を入力。

1
2
3
4
5
6
7
8
9
10
$ minikube docker-env
SET DOCKER_TLS_VERIFY=1
SET DOCKER_HOST=tcp://192.168.11.39:2376
SET DOCKER_CERT_PATH=C:\Users\t-takeuchi\.minikube\certs
SET MINIKUBE_EXISTING_DOCKER_TLS_VERIFY=1
SET MINIKUBE_EXISTING_DOCKER_HOST=tcp://192.168.11.18:2376
SET MINIKUBE_EXISTING_DOCKER_CERT_PATH=C:\Users\t-takeuchi\.minikube\certs
SET MINIKUBE_ACTIVE_DOCKERD=minikube
REM To point your shell to minikube's docker-daemon, run:
REM @FOR /f "tokens=*" %i IN ('minikube -p minikube docker-env --shell cmd') DO @%i

上記の値のうち、下記をホストマシンに設定する。

1
2
3
$ setx DOCKER_TLS_VERIFY 1
$ setx DOCKER_HOST tcp://192.168.11.39:2376
$ setx DOCKER_CERT_PATH %USERPROFILE%\.minikube\certs

これにより、docker-cli が docker エンジンを認識するようになる。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
$ docker version
Client:
Version: 20.10.17
API version: 1.41
Go version: go1.17.11
Git commit: 100c701
Built: Mon Jun 6 23:09:02 2022
OS/Arch: windows/amd64
Context: default
Experimental: true

Server: Docker Engine - Community
Engine:
Version: 20.10.16
API version: 1.41 (minimum version 1.12)
Go version: go1.17.10
Git commit: f756502
Built: Thu May 12 09:19:16 2022
OS/Arch: linux/amd64
Experimental: false
containerd:
Version: v1.6.4
GitCommit: 212e8b6fa2f44b9c21b2798135fc6fb7c53efc16
runc:
Version: 1.1.1
GitCommit: 52de29d7e0f8c0899bd7efb8810dd07f0073fa87
docker-init:
Version: 0.19.0
GitCommit: de40ad0

当然、コンテナも起動する。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
$ docker run hello-world
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
2db29710123e: Pull complete
Digest: sha256:53f1bbee2f52c39e41682ee1d388285290c5c8a76cc92b42687eecf38e0af3f0
Status: Downloaded newer image for hello-world:latest

Hello from Docker!
This message shows that your installation appears to be working correctly.

To generate this message, Docker took the following steps:
1. The Docker client contacted the Docker daemon.
2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
(amd64)
3. The Docker daemon created a new container from that image which runs the
executable that produces the output you are currently reading.
4. The Docker daemon streamed that output to the Docker client, which sent it
to your terminal.

To try something more ambitious, you can run an Ubuntu container with:
$ docker run -it ubuntu bash

Share images, automate workflows, and more with a free Docker ID:
https://hub.docker.com/

For more examples and ideas, visit:
https://docs.docker.com/get-started/