研究会

機械学習、データベース、分散システム、その他技術的なことを書く研究会です

Win10 の WSL2 に Ubuntu をインストールして Docker 上の minikube で Flask アプリを Hello World

Kubernetes を勉強しようと思って手元の Windows に minikube の環境を構築したら、その過程でいろいろなエラーに遭遇したので解決方法を添えて手順をまとめた。

構築した環境は手元のノート PC (Windows 10 Home 64bit) に WSL2 をインストールし、それで Ubuntu を動かして、その上の Docker で minikube を動かすというもの。試しに簡単な Flask アプリをデプロイしてみた。

WSL2 の有効化と Ubuntu のインストール

Windows 上で Ubuntu を動かすために、WSL2 を有効にする。

手順は Microsoft 公式のドキュメント に従えばできた。

ただし最後、Windows Store から Ubuntu 20.04 をインストールしていざ起動してみたところ、ターミナルが立ち上がってエラーコード 0xc03a001a のエラーが発生した。これは WSL2 にしたいのにエラーが出る問題 - Qiita に従い、フォルダーのプロパティから圧縮設定を解除したら回避できた (後で気づいたが、上に挙げた Microsoft のドキュメントにもエラーコードこそなかったが対処方法は書いてあった)。

これで Windows10 の WSL2 で Ubuntu が起動できるようになった。

Ubuntu に Docker をインストール

続いて Ubuntu に Docker をインストールする。

これも Docker 公式のドキュメント に従ってインストールした。

ただし動作確認のために適当な Dockerfile をビルドしようとしたところ、cannot find cgroup mount destination: unknown というエラーが出た。このエラーは WSL2 時の Dockerコンテナの起動について – すらりん日記 に従って次のコマンドを打って回避した。

sudo mkdir /sys/fs/cgroup/systemd
sudo mount -t cgroup -o none,name=systemd cgroup /sys/fs/cgroup/systemd

これで WSL2 上の Ubuntu で Docker が動くようになった。

Ubuntu に minikube をインストール

これも基本は Kubernetes の公式ドキュメント に従ってインストールする。

今回は Docker で minikube を動かすので CPU の仮想化支援機構は必須ではない。ので grep -E --color 'vmx|svm' /proc/cpuinfo の結果が空でも OK. 手順にある「ハイパーバイザーのインストール」も必要なし。

今回は 直接ダウンロードによるMinikubeのインストール の手順を実行した。

そして minikube の起動。Docker コンテナとして minikube を動かすので

minikube start --driver=docker

で起動する。

動作確認として minikube status を打ってみる。

$ minikube status
minikube
type: Control Plane
host: Running
kubelet: Running
apiserver: Running
kubeconfig: Configured

ここまでで WSL2 上の Ubuntu で Docker コンテナとして minikube を動かせた。

Flask アプリを用意

minikube で簡単な Flask アプリを動かしてみる。Flask の公式ドキュメント にある次のサンプルコードを使う。ファイル名は app.py とする。

from flask import Flask, escape, request

app = Flask(__name__)

@app.route('/')
def hello():
    name = request.args.get("name", "World")
    return f'Hello, {escape(name)}!'

またこのアプリを動かすコンテナをビルドするための Dockerfile を用意する。

FROM python:3

RUN pip install flask

COPY ./app.py /app.py

ENV FLASK_ENV=/app.py

CMD ["flask", "run", "--host", "0.0.0.0"]

これらのファイルを

~/flast-test/
  +- app.py
  +- Dockerfile

というように配置する。

Flask アプリをビルド

このコンテナイメージをビルドしたいが、単に docker build しても後の手順がうまくいかない。いくつかポイントがあるので一つずつ説明していく。

Docker ホストの向き先の切り替え

まず、minikube は組み込みの Docker エンジンを持っていて、Kubernetes の各種デーモンやデプロイされるコンテナはこの minikube 組み込みの Docker エンジンが利用される。この組み込みの Docker エンジンは先に Ubuntu 自体にインストールした Docker とは別のものである。

この後の手順ではコンテナレジストリを使わずに、ローカルに保存されているコンテナイメージを使いたいので、minikube 組み込みの Docker エンジンの方にデプロイしたいコンテナイメージを登録する。

そのために docker コマンドで参照する Docker ホストを minikube のものに変更したい。それは次のコマンドで行う。

eval $(minikube -p minikube docker-env)

このコマンドを実行すると環境変数 DOCKER_HOST や他の必要な変数がセットされ、docker コマンドの向き先が minikube のものになる。

minikube の DNS サーバーの変更

そして docker build を行おうとすると、以下のようなエラーが出る。IP アドレスは変わり得る。

Get https://registry-1.docker.io/v2/: dial tcp: lookup registry-1.docker.io on 192.168.49.1:53: read udp 192.168.49.2:37dd860911922e: Download complete

これは minikube 内の DNS サーバーの設定がまずいので、minikube コンテナに入って /etc/resolv.conf を書き換える。それには kubernetes - Error response from daemon: Get https://registry-1.docker.io/v2/: dial tcp: lookup registry-1.docker.io...i/o timeout - Stack Overflow を参考に次の手順で行う。

minikube ssh

# 以下は minikube コンテナ内での作業
sed -E 's/nameserver .*/nameserver 8.8.8.8/' /etc/resolv.conf > resolv.conf
sudo cp resolv.conf /etc/resolv.conf
exit

これでコンテナのビルドができるようになる。

ビルド

Flask アプリを動かすコンテナをビルドしてイメージを minikube 内の Docker エンジンに登録する。

docker build ~/flask-test -t flask-test

Flask アプリを minikube にデプロイ

ようやくビルドしたコンテナを Kubernetes にデプロイできる。

まずは次のような Deployment を定義する yaml ファイルを用意する。これを ~/flask-test/deployment.yaml として保存する。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: flask-test
  labels:
    app: flask
spec:
  replicas: 3
  selector:
    matchLabels:
      app: flask
  template:
    metadata:
      labels:
        app: flask
    spec:
      containers:
        - name: app
          image: flask-test:latest
          imagePullPolicy: Never
          ports:
            - containerPort: 5000

コンテナイメージは先ほどビルドしたものを使いたいので imagePullPolicy: Never としている。こうするとリモートのレジストリから Pull せずに常にローカルのイメージを使うようになる。

またレプリカ数は 3 にしている。

これを次のようにして Kubernetes に適用する。

kubectl apply -f ~/flask-test/deployment.yaml

うまくデプロイできていれば次のような結果が得られる。

$ kubectl get deployments flask-test
NAME         READY   UP-TO-DATE   AVAILABLE   AGE
flask-test   3/3     3            3           10s

$ kubectl get pods -l app=flask
NAME                         READY   STATUS    RESTARTS   AGE
flask-test-7d5c9c88b-2thh4   1/1     Running   0          10s
flask-test-7d5c9c88b-52j79   1/1     Running   0          10s
flask-test-7d5c9c88b-j6rpl   1/1     Running   0          10s

さらにこれらのコンテナに HTTP でアクセスできるように Service を定義する。

kubectl expose deployment flask-test --type NodePort

サービスが登録されていることを確認する。

$ k get services flask-test
NAME         TYPE       CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGE
flask-test   NodePort   10.103.56.173   <none>        5000:31859/TCP   10s

Flask アプリへアクセス

ここまで来ればデプロイした Flask アプリにアクセスできる。まずは URL を調べるために次のコマンドを実行する。

minikube service list

|-------------|------------|--------------|---------------------------|
|  NAMESPACE  |    NAME    | TARGET PORT  |            URL            |
|-------------|------------|--------------|---------------------------|
| default     | flask-test |         5000 | http://192.168.49.2:31859 |
| default     | kubernetes | No node port |
| kube-system | kube-dns   | No node port |
|-------------|------------|--------------|---------------------------|

http://192.168.49.2:31859 でサービスが公開されていることが分かるので次のようにして Flask アプリにアクセスできる。

curl  http://192.168.49.2:31859

Hello, World!

めでたしめでたし。

Ubuntu とか Docker いらなかったかもしれない

と、手順をまとめてみて思ったが、Ubuntu とか Docker とかいらなかったかもしれない。

手元の Windows 環境を汚したくなかったので独立した Linux 環境上で Kubernetes を試したかったのだが、Docker コンテナとして minikube が動くなら Docker Desktop for Windows でもよかったかも。それか Ubuntu で直接 minikube を動かすか。

これは次回ということで。

まとめ

  • WSL2 と Docker を駆使して minikube で Flask アプリを動かした
  • いろいろエラー出たがエラーメッセージでググったら全部解決した
  • もうちょっとシンプルな構成ができたかもしれない

参考