まえおき
2016年ごろからずっとローカルDockerd&K8sにはminikubeを使ってきました。
minikubeでローカルKubernetesクラスタを5分でつくる方法 - Qiita
が、minikubeが最近重い。Minikube自身が原因かどうか深追いはしてないものの、気軽に乗り換えられそうならやってみるか、程度の軽い気持ちでmultipassを試してみました。
// minikubeの重さについて定量的な検証はとくにしていないので、必要な形はこの手順で構築したVMとminikubeVMのCPU・メモリ利用量などを実際に比較してみることをおすすめします
TL;DR;
multipass
というシングルバイナリのツールで、Ubuntuの入ったhyperkit VMを簡単に操作できる。
- UbuntuでDocker/ローカルK8sを利用する標準的な構成(docker & microk8s)をセットアップするだけの構成。
minikube同様な点
- ホストOS側のディレクトリマウントにも対応している。
minikubeよりよいと思われる点
- microk8sのアドオンにローカルdocker registryがあり、高速にdocker build -> push -> K8sへデプロイするサイクルがまわせる
- microk8sとk3dによるK8sクラスタを共存させることもできる。Namespacedでないリソース(CRDなど)を複数バージョン作って平行でE2Eテストを走らせるような使い方をする場合、microk8sだとバッティングしてしまうので、k3dで高速に使い捨てのクラスタをつくれるのは便利。
そのほかにやってみたこと
- k3dでmultipass VM上に軽量K8sを構築。microk8sのk8sクラスタと共存
- kanikoでmacOS上のファイルをクラスタに転送してコンテナイメージをビルド(dockerd依存なしで)してローカルレジストリに高速にpush
手順
multipassのインストール
0.7.0のRC版を使います(後述の primary
マシンが使えるようになり便利になったので
VM の作成
multipass launch
の引数にVMに割り当てる最大メモリ、ストレージサイズ、CPUコア数とVM名(名前を変えればVMを複数つくることができます)を指定する。
名前を primary
にすると、multipass
の各コマンドでVM名を省略したときのデフォルトとして扱ってくれるため、よく使うVMまたは最初の一台とりあえず primary
にしておくことをおすすめします。
mac$ multipass launch --mem 8G --disk 40G --cpus 2 --name primary
multipass ls
コマンドでVM一覧を確認できます。StateがRunningとなっていればひとまず問題ありません。また、IPv4
欄に表示されるIPアドレスは macOS 側からVMで起動しているサービスにアクセスする場合によく使うことになるので、覚えておきましょう。
mac$ multipass ls
Name State IPv4 Release
primary Running 192.168.64.8 Ubuntu 18.04 LTS
K8sクラスタの構築
最小構成としてK8s自身とクラスタDNS、そしてローカル開発に便利なクラスタ内コンテナイメージレジストリを構築する。
K8s自身は、Ubuntuのパッケージマネージャである snap
で microk8s
というsnapをインストールして、IPフォワードの許可をするだけでOK。
multipass@primary:~$ sudo snap install microk8s --classic
multipass@primary:~$ sudo iptables -P FORWARD ACCEPT
次に、クラスタDNSとコンテナイメージレジストリをmicrok8s.enable
コマンドでインストールする。
multipass@primary:~$ microk8s.enable registry
Enabling the private registry
Enabling default storage class
deployment.extensions/hostpath-provisioner created
storageclass.storage.k8s.io/microk8s-hostpath created
Storage will be available soon
Applying registry manifest
namespace/container-registry created
persistentvolumeclaim/registry-claim created
deployment.extensions/registry created
service/registry created
The registry is enabled
multipass@primary:~$ microk8s.enable dns
Enabling DNS
Applying manifest
service/kube-dns created
serviceaccount/kube-dns created
configmap/kube-dns created
deployment.extensions/kube-dns created
Restarting kubelet
DNS is enabled
microk8s
をインストールすると、同梱された containerd
が起動した状態になる。
multipass@primary:~$ ls /var/snap/microk8s/current/args/
cni-network/ containerd-env containerd.toml etcd kube-controller-manager kube-scheduler kubelet
containerd containerd-template.toml ctr kube-apiserver kube-proxy kubectl
multipass@primary:~$ cat /var/snap/microk8s/current/args/containerd
--config ${SNAP_DATA}/args/containerd.toml
--root ${SNAP_COMMON}/var/lib/containerd
--state ${SNAP_COMMON}/run/containerd
--address ${SNAP_COMMON}/run/containerd.sock
これだけだと docker
コマンドの接続先となる、containerd
のフロントエンドとなる dockerd
が存在しないため、別途 docker のみインストールする。
multipass@primary:~$ sudo apt-get install docker.io
Reading package lists... Done
Building dependency tree
Reading state information... Done
The following package was automatically installed and is no longer required:
grub-pc-bin
Use 'sudo apt autoremove' to remove it.
Suggested packages:
aufs-tools debootstrap docker-doc rinse zfs-fuse | zfsutils
The following NEW packages will be installed:
docker.io
0 upgraded, 1 newly installed, 0 to remove and 48 not upgraded.
Need to get 0 B/46.4 MB of archives.
After this operation, 234 MB of additional disk space will be used.
Preconfiguring packages ...
Selecting previously unselected package docker.io.
(Reading database ... 60225 files and directories currently installed.)
Preparing to unpack .../docker.io_18.09.2-0ubuntu1~18.04.1_amd64.deb ...
Unpacking docker.io (18.09.2-0ubuntu1~18.04.1) ...
Setting up docker.io (18.09.2-0ubuntu1~18.04.1) ...
Processing triggers for ureadahead (0.100.0-21) ...
Processing triggers for systemd (237-3ubuntu10.21) ...
Processing triggers for man-db (2.8.3-2ubuntu0.1) ...
systemctl status
で dockerd
が起動していることを確認しておく。 Active: active (running)
になっていれば一旦は問題なし。
multipass@primary:~$ systemctl status docker
● docker.service - Docker Application Container Engine
Loaded: loaded (/lib/systemd/system/docker.service; disabled; vendor preset: enabled)
Active: active (running) since Wed 2019-05-22 17:47:16 JST; 25min ago
Docs: https://docs.docker.com
Main PID: 7660 (dockerd)
Tasks: 25
CGroup: /system.slice/docker.service
├─7660 /usr/bin/dockerd -H fd://
└─7687 docker-containerd --config /var/run/docker/containerd/containerd.toml --log-level info
May 22 17:47:15 primary dockerd[7660]: time="2019-05-22T17:47:15.888067580+09:00" level=info msg="Loading containers: done."
May 22 17:47:16 primary dockerd[7660]: time="2019-05-22T17:47:16.055035350+09:00" level=info msg="Docker daemon" commit=6247962 graphdriver(s)=overlay2 version=18.09.2
May 22 17:47:16 primary dockerd[7660]: time="2019-05-22T17:47:16.055151889+09:00" level=info msg="Daemon has completed initialization"
May 22 17:47:16 primary dockerd[7660]: time="2019-05-22T17:47:16.065357823+09:00" level=info msg="API listen on /var/run/docker.sock"
May 22 17:47:16 primary systemd[1]: Started Docker Application Container Engine.
May 22 17:49:11 primary dockerd[7660]: time="2019-05-22T17:49:11.615281919+09:00" level=info msg="Attempting next endpoint for push after error: Get https://localhost:32000/v2/: http: server gave HTTP response to HTTPS client"
May 22 17:49:54 primary dockerd[7660]: time="2019-05-22T17:49:54.981556940+09:00" level=info msg="Pull session cancelled"
May 22 17:49:55 primary dockerd[7660]: time="2019-05-22T17:49:55.748494759+09:00" level=info msg="shim docker-containerd-shim started" address="/containerd-shim/moby/c7265d99a9070c43c41bc7f6a298b669a4c87354a22599174dd0d37a82acd483/shim.
May 22 17:50:20 primary dockerd[7660]: time="2019-05-22T17:50:20.647918693+09:00" level=info msg="shim reaped" id=c7265d99a9070c43c41bc7f6a298b669a4c87354a22599174dd0d37a82acd483
May 22 17:50:20 primary dockerd[7660]: time="2019-05-22T17:50:20.657969019+09:00" level=info msg="ignoring event" module=libcontainerd namespace=moby topic=/tasks/delete type="*events.TaskDelete"
このままだと /var/run/docker.sock
への権限が原因で sudo
をつけないと docker
コマンド経由の通信が失敗するため、docker.help
コマンドの出力に従ってLinuxユーザ・グループをセットアップする。
multipass@primary:~$ docker.help
Docker snap: Docker Linux container runtime.
Due to the confinement issues on snappy, it requires some manual setup to make docker-snap works on your machine.
We'll take you through the steps needed to set up docker snap work for you on ubuntu core and ubuntu classic.
On Ubuntu classic, before installing the docker snap,
please run the following command to add the login user into docker group.
sudo addgroup --system docker
sudo adduser $USER docker
newgrp docker
On Ubuntu Core 16, after installing the docker snap from store,
you need to connect the home interface as it's not auto-connected by default.
sudo snap connect docker:home :home
Then have fun with docker in snappy.
$ sudo addgroup --system docker
$ sudo adduser $USER docker
$ newgrp docker
実際に docker
コマンドをいくつか実行してみて、動作確認しておく。
multipass@primary:~$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
multipass@primary:~$ docker version
Client:
Version: 18.09.2
API version: 1.39
Go version: go1.10.4
Git commit: 6247962
Built: Tue Feb 26 23:52:23 2019
OS/Arch: linux/amd64
Experimental: false
Server:
Engine:
Version: 18.09.2
API version: 1.39 (minimum version 1.12)
Go version: go1.10.4
Git commit: 6247962
Built: Wed Feb 13 00:24:14 2019
OS/Arch: linux/amd64
Experimental: false
docker build
もできる。
multipass@primary:~/work$ cat >Dockerfile
FROM nginx:alpine
^C
multipass@primary:~/work$ docker build . -t mynginx:local
Sending build context to Docker daemon 2.048kB
Step 1/1 : FROM nginx:alpine
alpine: Pulling from library/nginx
e7c96db7181b: Pull complete
264026bbe255: Pull complete
最高のクラスタ内コンテナイメージレジストリを用意する
少し手間をかけると、docker pushだけでなくkanikoにも対応できます。
microk8s デフォルトの状態
microk8s.enable registry
でインストールした docker registry は VM の 32000番でアクセスできるようになっている。また、apt-get
でインストールした dockerd
はデフォルトでローカルレジストリを信頼するようになっている。したがって、以下のように localhost:32000
をDockerレジストリとして docker push
などが可能。
docker build . -t localhost:32000/mynginx:registry
docker push localhost:32000/mynginx
dockerd, K8sの両方からローカルレジストリにアクセス可能にする
レジストリ名にはlocalhostではなくIPアドレスを使うことがポイント。
イメージ名に含まれるレジストリのアドレスに「localhost:32000」を使うより、IPアドレス:ポートを使うようにする、ということ。
localhostの場合multipass VM上のUbuntuから起動しているdockerdがアクセスすることはもちろん可能だが、例えばkanikoでin-cluster buildをしてkanikoからpushをするような場合にアクセスできないから(kanikoにとってのlocalhostはkaniko自身のPodになるため)。
したがって、multipass ls
で確認できるVMのIPアドレスが 192.168.64.8 だとしたら、192.168.64.8:32000
をイメージレジストリのアドレスとして利用する。そうすれば、macOSやUbuntuからdocker push
する場合、kanikoからin-cluster build/pushする場合で同じレジストリのアドレスを利用することができ、混乱が少ない。
dockerdのinsecure registry設定
基本的には docker
コマンドを使う場合は docker tag 192.168.64.8:32000/MYIMAGE
のようにタグを打てばよいが、dockerd側の設定をしないと以下のエラーになる。
multipass@primary:~$ docker push 192.168.64.8:32000/alpine
The push refers to repository [192.168.64.8:32000/alpine]
Get https://192.168.64.8:32000/v2/: http: server gave HTTP response to HTTPS client
これは、microk8sで導入したレジストリがHTTPモードになっているため。dockerdはlocalhost:32000
のようなレジストリが指定された場合はHTTPモードのレジストリとして通信をするが、IPアドレス:32000
のようにIPアドレスを明示した場合はHTTPSをデフォルトとして利用するようで、このようなエラーになってしまう。
そこで、dockerd に該当アドレスにいるレジストリはHTTPを話すということを伝える必要がある。具体的には、/etc/docker/daemon.json
を以下の通り作成する。
multipass$ sudo sh -c 'cat > /etc/docker/daemon.json'
{
"insecure-registries" : ["192.168.64.8:32000"]
}
参考: https://docs.docker.com/registry/insecure/
この設定をdockerdに読み込ませるために、dockerdを再起動する。
multipass@primary:~$ sudo systemctl restart docker
先程エラーになったdocker pushコマンドを再度実行してみると、今度はうまくいく。
multipass@primary:~$ docker push 192.168.64.8:32000/alpine
The push refers to repository [192.168.64.8:32000/alpine]
f1b5933fe4b5: Pushed
3.9: digest: sha256:bf1684a6e3676389ec861c602e97f27b03f14178e5bc3f70dce198f9f160cce9 size: 528
kanikoのinsecureレジストリ設定
kaniko
の場合は、--insecure
というフラグをつけるとpush先のレジストリをHTTPサーバとみなす。
kaniko
のREADMEによれば、kaniko
を試すときは docker runやkubectlから実行するのが常のようだが、手元から試しにビルドする場合には手順が煩雑なので、ここではskaffoldを使うことにする。skaffoldにはkanikoビルダがあり、kaniko
を直接使うよりは簡単にビルドができる。
skaffoldはkaniko
の--insecure
フラグを自動で付与したりはしてくれない(しようもない)ので、それは自分で skaffold
の設定ファイルに記述する。
skaffoldの設定ファイルであるskaffold.yaml
のリファレンスのとおり、build.artifacts[].kaniko
にkaniko関連の設定を記述する。
flags
に前述の--insecure
フラグを追加すればよい。
apiVersion: skaffold/v1beta11
kind: Config
build:
artifacts:
- image: 192.168.64.8:32000/mumoshu/skaffoldtest
context: .
kaniko:
flags:
# Required in order to avoid the following error when pusing to a local, insecure registry:
# error pushing image: failed to push to destination 192.168.64.8:32000/mumoshu/skaffoldtest:6383d2f-dirty: Get https://192.168.64.8:32000/v2/: http: server gave HTTP response to HTTPS client
- --insecure
buildContext:
localDir: {}
# If omitted, `local` builder is selected by default even though the `kaniko` settings is provided
cluster:
pullSecret: /Users/YOU/.docker/config.json
この内容で skaffold build
を実行すると、skaffoldがkanikoを使ってクラスタ内(のPodを使って)イメージビルドしてくれる。
$ skaffold build
Generating tags...
- 192.168.64.8:32000/mumoshu/skaffoldtest -> 192.168.64.8:32000/mumoshu/skaffoldtest:6383d2f-dirty
Tags generated in 49.780056ms
Starting build...
Creating kaniko secret [kaniko-secret]...
Building [192.168.64.8:32000/mumoshu/skaffoldtest]...
Storing build context at /var/folders/_w/3lwtgvv51tl_fgxkdvcmtm340000gp/T/context-c2cb37afc85a7037bdbf94e9502fcbd7.tar.gz
WARN[0000] The additionalFlags field in kaniko is deprecated, please consult the current schema at skaffold.dev to update your skaffold.yaml.
INFO[0000] Downloading base image nginx:alpine
2019/05/24 06:22:47 No matching credentials were found, falling back on anonymous
INFO[0002] Taking snapshot of full filesystem...
INFO[0002] Skipping paths under /kaniko, as it is a whitelisted directory
INFO[0002] Skipping paths under /secret, as it is a whitelisted directory
INFO[0002] Skipping paths under /dev, as it is a whitelisted directory
INFO[0002] Skipping paths under /sys, as it is a whitelisted directory
INFO[0002] Skipping paths under /proc, as it is a whitelisted directory
INFO[0002] Skipping paths under /var/run, as it is a whitelisted directory
2019/05/24 06:22:50 existing blob: sha256:5595887beb811004cfb48cd5bb3eb9a9602fb1fd47d93117b92ef97e22859c00
2019/05/24 06:22:50 existing blob: sha256:264026bbe25598d28ce74f288ce0b4ef93dc4123bb793bf655780e0455453f4c
2019/05/24 06:22:50 existing blob: sha256:a71634c55d292856f6a48a5984ff4aa7e244f2e82083e1279aa5af8a7da5819f
2019/05/24 06:22:50 existing blob: sha256:e7c96db7181be991f19a9fb6975cdbbd73c65f4a2681348e63a141a2192a5f10
2019/05/24 06:22:50 pushed blob sha256:a0c491e91aadbd72d0375bc0d186ebede44c5e9e2f2377a035de37baf5b1d878
2019/05/24 06:22:50 192.168.64.8:32000/mumoshu/skaffoldtest:6383d2f-dirty: digest: sha256:ac66fceb3d272c21e54450bfa7c18e7235baea1b5924c2ac2d2e029eae8b78fb size: 912
Build complete in 14.884723143s
Starting test...
Test complete in 7.838µs
Complete in 14.9516144s
kanikoをPod内で実行する場合、ローカルマシンからkanikoのPodへビルドコンテキスト(DockerfileからADDやCOPYできるファイルがある場所。docker build .
だとカレントディレクトリがそれ)を渡すのが面倒だが、skaffoldはそれも面倒を見てくれる。具体的には、skaffold.yamlに記述した場所にあるディレクトリをtarballにアーカイブして、kubectl execでkaniko podに転送する、ということを自動的にやってくれる。素のkanikoより便利ですね。
kanikoがローカルレジストリにpushしたことを確認するため、dockerコマンドを使ってdockerdにpullしてみる。
まず、pullする前はイメージがdockerdには見えない状態。これは、kanikoがdocker/dockerdを経由しないで自前でイメージをビルドしてローカルレジストリにpushしたため。
$ docker images
以下のようにpullすれば、イメージが見えるようになるはず。
$ docker pull 192.168.64.8:32000/mumoshu/skaffoldtest:6383d2f-dirty
6383d2f-dirty: Pulling from mumoshu/skaffoldtest
e7c96db7181b: Already exists
264026bbe255: Already exists
a71634c55d29: Already exists
5595887beb81: Already exists
Digest: sha256:3132ea39b2e91e2d76f45adbdf0921f394a5793fd9ab4a4b7c895da46ecdd033
Status: Downloaded newer image for 192.168.64.8:32000/mumoshu/skaffoldtest:6383d2f-dirty
docker images
コマンドで dockerd から見えているイメージを見てみると、無事にkanikoがpushしたイメージがある。
macos$ docker images | grep mumoshu
192.168.64.8:32000/mumoshu/skaffoldtest 6383d2f-dirty f39da67d6567 39 seconds ago 16.1MB
macOS側からdockerdにアクセスできるようにする
このままだと /var/run/docker.sock
経由によるdockerdとの通信しかできない。macOS側の docker
コマンドからは tcp 経由の通信をしたいので、 dockerd
の設定を変更する。
方法はいろいろあるが、今回は dockerd
のコマンドラインオプションに -H プロトコル://アドレス:ポート
の記述を追加することで対応する。ポート2376番で、どのネットワークインターフェースでも待ち受けてほしい場合は、 -H tcp://0.0.0.0:2376
のように書けばよい。
参考: Docker - How do I enable the remote API for dockerd
multipass@primary:~$ sudo mkdir /etc/systemd/system/docker.service.d/
multipass@primary:~$ sudo sh -c 'cat > /etc/systemd/system/docker.service.d/startup_options.conf'
# /etc/systemd/system/docker.service.d/override.conf
[Service]
ExecStart=
ExecStart=/usr/bin/dockerd -H fd:// -H tcp://0.0.0.0:2376
^C
multipass@primary:~$ sudo systemctl daemon-reload
multipass@primary:~$ sudo systemctl restart docker.service
以下のように dockerd
のコマンドライン引数に -H tcp://0.0.0.0:2376
が追加されていればOK
multipass@primary:~$ systemctl status docker
● docker.service - Docker Application Container Engine
Loaded: loaded (/lib/systemd/system/docker.service; disabled; vendor preset: enabled)
Drop-In: /etc/systemd/system/docker.service.d
└─startup_options.conf
Active: active (running) since Wed 2019-05-22 18:14:13 JST; 1s ago
Docs: https://docs.docker.com
Main PID: 17395 (dockerd)
Tasks: 22
CGroup: /system.slice/docker.service
├─17395 /usr/bin/dockerd -H fd:// -H tcp://0.0.0.0:2376
└─17432 docker-containerd --config /var/run/docker/containerd/containerd.toml --log-level info
May 22 18:14:13 primary dockerd[17395]: time="2019-05-22T18:14:13.122806400+09:00" level=warning msg="Your kernel does not support cgroup rt period"
May 22 18:14:13 primary dockerd[17395]: time="2019-05-22T18:14:13.122820048+09:00" level=warning msg="Your kernel does not support cgroup rt runtime"
May 22 18:14:13 primary dockerd[17395]: time="2019-05-22T18:14:13.123708656+09:00" level=info msg="Loading containers: start."
May 22 18:14:13 primary dockerd[17395]: time="2019-05-22T18:14:13.217868247+09:00" level=info msg="Default bridge (docker0) is assigned with an IP address 172.17.0.0/16. Daemon option --bip can be used to set a preferred IP address"
May 22 18:14:13 primary dockerd[17395]: time="2019-05-22T18:14:13.254483709+09:00" level=info msg="Loading containers: done."
May 22 18:14:13 primary dockerd[17395]: time="2019-05-22T18:14:13.305465422+09:00" level=info msg="Docker daemon" commit=6247962 graphdriver(s)=overlay2 version=18.09.2
May 22 18:14:13 primary dockerd[17395]: time="2019-05-22T18:14:13.305581627+09:00" level=info msg="Daemon has completed initialization"
May 22 18:14:13 primary dockerd[17395]: time="2019-05-22T18:14:13.311982639+09:00" level=info msg="API listen on [::]:2376"
May 22 18:14:13 primary dockerd[17395]: time="2019-05-22T18:14:13.312016834+09:00" level=info msg="API listen on /var/run/docker.sock"
May 22 18:14:13 primary systemd[1]: Started Docker Application Container Engine.
macOS側
Dockerの接続先設定
まだ入ってなければ docker
コマンドをインストールする。
mac$ brew install docker
multipass ls
コマンドで VMのIPアドレスを調べて、
$ multipass ls
Name State IPv4 Release
primary Running 192.168.64.8 Ubuntu 18.04 LTS
docker
コマンドであれば -H
フラグでそのIPアドレスの2376(前述の設定のとおり)をDocker APIのエンドポイントとして使うようにします。
mac$ docker -H 192.168.64.8:2376 ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
いちいち -H
を設定するのが面倒な場合や、docker
コマンド以外の方法(例えば各プログラミング言語向けの Docker APIクライアントやそれを内部的に使っているようなツール)で dockerd と通信したいような場合は、DOCKER_HOST
環境変数を設定してください。
mac$ export DOCKER_HOST=tcp://192.168.64.8:2376
mac$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
VM上のK8s APIにアクセスする
microk8s
をインストールすると作られる microk8s.config
コマンドで、kubeconfig
の内容を標準出力に出すことができます。
multipass@primary:~$ microk8s.config
設定内容に含まれるK8s APIエンドポイントURLのホスト名部分には VMのプライベートIPアドレスが書かれており、VMのIPアドレスはmacOS側から特に何もせずともアクセスすることができるため、これを単にmacOS側に保存してkubectl
などに読ませればOKです。
$ multipass exec primary -- /snap/bin/microk8s.config > microk8s.kubeconfig
$ export KUBECONFIG=$(pwd)/microk8s.kubeconfig
実際に kubectl
を実行してアクセスできるか確認してみます。
$ kubectl version
$ kubectl get no
NAME STATUS ROLES AGE VERSION
primary Ready <none> 9h v1.14.1
ホームディレクトリのマウント
TL;DR;
mac$ multipass mount $HOME primary:$HOME
説明
macOSの場合 $HOME
= /Users/$USER
がホームディレクトリになっていると思います。minikube
や docker-machine
はデフォルトで macOS 側のホームディレクトリを VM 上の同じパスにマウントしてくれるため、ホームディレクトリ以下のディレクトリであれば docker run -v $SRC:$DST
でマウントするソースディレクトリのパスに macOS 側のパスをそのまま利用できて便利です。
たとえば docker run --rm -it -v $(pwd):$(pwd) myimage /bin/bash
のようにカレントディレクトリをマウントしたコンテナを起動するというようなことができるのは、macOS側の$(PWD)が示すパスがVM上にもあるから、ですよね。
multipass mount
で明示的にホームディレクトリをマウントすれば、同じ状態を再現することができます。
mac$ multipass mount $HOME primary:$HOME
これまで通り、macOS側のパスとVM上のパスの読み替えをすることなく、macOSにあるファイルをコンテナ内から参照することができます。
mac$ docker run --rm -it -v $HOME:$HOME alpine:3.9 sh
上級編
k3d on multipass VM
multipass VM上にmicrok8sとは別の、k3dによるK8sクラスタを相乗りさせることもできる。
ただし、k3dの実装上の都合により、k3dが作成したK8sクラスタへのアクセスはVM側から行ったほうが良い。例えばkubectlを使うなら、macOS側からではなくUbuntu側からkubectlを実行したほうがよい。これは、macOS側からk3dのK8sにアクセスしようとすると、CA証明書の検証エラーとなってしまうため。
$ KUBECONFIG=~/.config/k3d/k3s-default/kubeconfig.yaml k get no
Unable to connect to the server: x509: certificate signed by unknown authority
エラー内容から察するに、k3dはUbuntu側のローカルルートCAで署名されたCA証明書をK8s APIとの通信に利用するようになっており、Ubuntu側のローカルルートCAはmacOS側で信頼されていないから、ということではないかと思う。(macOS側でそのルートCAを信頼するようにすればよいが、面倒なのでやっていない。)
そのときに利用するKUBECONFIGはk3dコマンドが生成したものを使うことになるため、最初からmacOS側ではなくUbuntu側でk3dコマンドを実行してkubeconfigがmacOS側ではなくUbuntu側に用意された状態にすると混乱がない。
以上を踏まえて、Ubuntu側に kubectl
と k3d
をインストールし、Ubuntu上で k3d
によるK8sクラスタの作成と、kubectl
による接続確認を行う。
multipass@primary:~$ sudo snap install kubectl --classic
multipass@primary:~$ k3d create
2019/05/24 11:06:10 Created cluster network with ID baee312bc080400e2625b2097f886fef96b7c41a8afb1f9fb40c0826380495b2
2019/05/24 11:06:10 Creating cluster [k3s-default]
2019/05/24 11:06:10 Creating server using docker.io/rancher/k3s:v0.5.0...
2019/05/24 11:06:12 SUCCESS: created cluster [k3s-default]
2019/05/24 11:06:12 You can now use the cluster with:
export KUBECONFIG="$(k3d get-kubeconfig --name='k3s-default')"
kubectl cluster-info
KUBECONFIGを指定しない場合は microk8s で作られたほうの K8s に向いている。
multipass@primary:~$ kubectl cluster-info
Kubernetes master is running at http://localhost:8080
KubeDNS is running at http://localhost:8080/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy
To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.
k3d create
コマンドの出力で指示されたとおりKUBECONFIGを設定すると、k3d で作られたほうのK8sに向く。
multipass@primary:~$ export KUBECONFIG="$(k3d get-kubeconfig --name='k3s-default')"
multipass@primary:~$ kubectl cluster-info
Kubernetes master is running at https://localhost:6443
CoreDNS is running at https://localhost:6443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy
To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.
注意点
再起動するたびに下記コマンドを実行すること。
multipass@primary:~$ sudo iptables -P FORWARD ACCEPT
実行しないと、クラスタ外のIPアドレス(例えばインターネット上のAlpine Package Registryやコンテナイメージレジストリ含めて)にあらゆるPod内からアクセスできない。kube-dnsもUpstreamである 8.8.8.8 などにアクセスできないので、kube-dnsが起動しているにもかかわらず、あらゆるPodからクラスタ外の名前解決ができない、という状態になってしまう。
動かないときは
とりあえず microk8s.inspect を実行して、なにかエラーや注意が出ていないか確認する。例えば前述のiptablesの件は、microk8s.inspectにも出てくる。(WARNING
の部分)
multipass@primary:~$ microk8s.inspec
microk8s.inspec: command not found
multipass@primary:~$ microk8s.inspect
Inspecting services
Service snap.microk8s.daemon-containerd is running
Service snap.microk8s.daemon-apiserver is running
Service snap.microk8s.daemon-proxy is running
Service snap.microk8s.daemon-kubelet is running
Service snap.microk8s.daemon-scheduler is running
Service snap.microk8s.daemon-controller-manager is running
Service snap.microk8s.daemon-etcd is running
Copy service arguments to the final report tarball
Inspecting AppArmor configuration
Gathering system info
Copy network configuration to the final report tarball
Copy processes list to the final report tarball
Copy snap list to the final report tarball
Inspect kubernetes cluster
WARNING: IPtables FORWARD policy is DROP. Consider enabling traffic forwarding with: sudo iptables -P FORWARD ACCEPT
Building the report tarball
Report tarball is at /var/snap/microk8s/522/inspection-report-20190524_145809.tar.gz
所感
- (個人的には)ブラックボックス感が少なくて、問題が起きたときに対処しやすそう
- minikubeでよく行っていた
docker build && kubectl apply
のようなワークフローも問題なく流せそうなので、移行したい