その2は自作コンテナの第一歩!
ベースの環境は「その1」の記事内容が前提になっています。
その1で構成したコンテナオーケストレーション(minikube)環境を使って、今度は自分で作成した Pythonアプリケーションをコンテナに組み込んで動かしてみます。その1と同じく最小の手順になっており YAML も使用しません。
(本来 Kubernetes の操作で YAML の知識は必須ですが、できるだけ各コンポーネントの関係にフォーカスするため本稿では YAMLを使用しない手順としています)
Python 関連のアップデートなど
「その1」で設定した WSL Ubuntu は何もしなくても Python(Python3)が使えますが念のためアップデートを行います。
$ sudo apt update && sudo apt upgrade
$ sudo apt upgrade python3
Python の標準ライブラリに含まれていない追加のパッケージをインストールして管理するために pip をインストールします。
$ sudo apt install python3-pip
PythonでWebアプリを実行させるために Flaskライブラリをインストールします。
$ pip3 install flask
Python ソースコードの作成、編集
Ubuntu でファイル( helloweb.py )を作成します。
$ echo aaa > helloweb.py
この後 Windowsのファイルエクスプローラーから helloweb.py をメモ帳などで編集、保存してください。
もちろん "aaa" は消してください。このような事をする理由は「その1」の余談に!
よく見かける固定の文字列を返すだけのシンプルな Python の Web(Flask)アプリです。
# helloweb.py
from flask import Flask
#Flaskオブジェクトの生成
app = Flask(__name__)
#ブラウザで仮想ディレクトリルートが指定された場合の動作
@app.route('/')
def hello():
return 'hello world\n'
#Webサーバを起動
if __name__ == '__main__':
app.run(debug='true',host='0.0.0.0',port='8888')
Webアプリを Ubuntu上で直接実行します。
$ python3 helloweb.py
Windows上のブラウザーからアクセス
http://localhost:8888/
ブラウザーに hello world の文字列が表示されたら正常に動作しています。Pythonアプリは Ctrl + c で終了できます。
コンテナのビルドと実行
動作確認済みの Pythonアプリを組み込んだコンテナをビルドします。
以下内容の Dockerファイル( helloWebDockerfile.txt )を用意します。
※もし実施した際に FROM のベースコンテナが見つからないような場合は、その時々で使える Pythonの公開イメージ名に置き換えてください。
# helloWebDockerfile.txt
# 元になる Python コンテナ
FROM python:3.11-slim-bookworm
# ワークディレクトリを作成
workdir /app
# コンテナホスト側の helloweb.py をコンテナ側にコピー
copy ./helloweb.py .
run pip install flask
CMD python helloweb.py
コンテナをビルドします。
$ docker build -t helloweb:001 -f helloWebDockerfile.txt .
まずはDocker環境で動作しているか確認します。
$ docker run --rm -d -p 8888:8888 --name helloweb helloweb:001
$ docker ps
もしコンテナ状態表示で起動が確認できない場合は以下の -it で問題を確認。
$ docker run --rm -it -p 8888:8888 --name helloweb helloweb:001
curlコマンドで hello world の文字列が表示されれば正常に動作しています。
$ curl localhost:8888
hello world
Dockerコンテナを停止します。
$ docker stop helloweb
minikube クラスターでのアプリ実行
では minikube クラスター内で実行してみましょう。
まずクラスターをスタートしておきます。
$ minikube start
環境変数を変更して dockerコマンドの出力先を minikubeクラスターに設定しておきます。
$ eval $(minikube -p minikube docker-env)
※本稿執筆時には minikube image load の問題があるためコンテナイメージの作成先を環境変数で変更する手順とします。
元のDockerホスト用の環境に戻すときは次のコマンドで。
eval $(minikube -p minikube docker-env -u)
環境の確認は docker context list で。
コンテナをビルドします。先ほどのビルドと同じコマンド内容ですが、環境変数を変更しているのでこのコンテナイメージは minikube クラスター内に作成されます。
$ docker build -t helloweb:001 -f helloWebDockerfile.txt .
クラスター内にアプリの Pod をデプロイします。
$ kubectl create deployment --image helloweb:001 helloweb
Pod の状態が Running になっているのを確認します。
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
helloweb-5fdb645d4d-r24x8 1/1 Running 0 7s
Pod に繋げるためのサービスを定義、確認します。
$ kubectl expose deployment helloweb --port 8888 --type=NodePort
$ kubectl get service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
helloweb NodePort 10.109.48.35 <none> 8888:31062/TCP 39s
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 1h
このサービスを更に外部からアクセス可能にします。
$ minikube service helloweb --url
http://127.0.0.1:37843
❗ Because you are using a Docker driver on linux, the terminal needs to be open to run it.
表示された URL に Windows上のブラウザーからアクセスします。
アプリケーションを組み込んだコンテナがクラスターで正常に動作している事が確認できました。
最後に
各コンポーネントの関係を理解した上で本稿の内容(その1と併せて)の実施や、更に kubectl で色々なコマンドを試す事によってコンテナオーケストレーションの基本的な知識が得られると思います。
本稿作成前は、WSL と VSCode の連携や Python の 仮想プロジェクト管理(venv) など、開発環境や手順にも触れようとしていたのですが煩雑になるのでカットしました。VSCode などの開発環境は効率や品質を高めるために必ず利用すべきです。本稿中で触れたような改行コードのケアも不要になります。VSCode も出たばかりの頃は便利なソースコードエディターくらいの感覚でしたが、現在は拡張機能の充実により統合開発環境として広く利用されています。
WSL と VSCode の連携については Microsoft が公開しているこのようなガイド( https://learn.microsoft.com/ja-jp/windows/python/web-frameworks )で簡単に入門できると思います。
もともとは Kubernetes の経験が無いメンバーのために、Windowsローカルでコンテナアプリケーションの開発、単体テストをしてもらうためのハンズオン・オリエンテーション資料を探していたのですが、検索しても適当な内容が見つからなかったので本稿内容を作成しました。
コンテナ、Kubernetes に触れるタイミングがなかった方々の第一歩として、コンポーネントの関係や大まかな流れを理解するために本稿がその一助となれば幸いです。
おまけ:コンテナイメージのサイズを小さくしている有識者の記事を参考にしてマルチステージビルドで Distrolessコンテナ、および gunicornも使用するようDockerfileを変更
大変スマートな方法を考えている方の Dockerfile を勝手に参考にしました。m(_ _)m
このベースイメージであれば運用レベルでも大丈夫かも。。
# helloWebDockerfile2.txt
FROM python:3.11-slim-bookworm as builder
WORKDIR /app
copy ./helloweb.py .
ENV PYTHONUSERBASE=/app/__pypackages__
RUN pip install --user Flask gunicorn
FROM gcr.io/distroless/python3-debian12
WORKDIR /app
COPY --from=builder /app .
ENV PYTHONUSERBASE=/app/__pypackages__
ENTRYPOINT ["python", "-uB", "-m", "gunicorn", "helloweb:app", "-b", ":8888"]
結果:153M → 58.5M Pythonコンテナの軽量化を確認
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
helloweb 001 xxxxxxxxxxxx 58 minutes ago 153MB
helloweb 002 xxxxxxxxxxxx 24 minutes ago 58.5MB