Paketo BuildpackでPython Docker Imageをビルドする

こんにちは。最近立派なApple信者と化しているアソビュー!SREチームのkirimaruです。写真エモいの選べていいですね。

アソビュー!ではJavaをメインで使っているのですが、一部でPythonを使った開発も行われています。
今回は備忘を兼ねて、簡単なPythonのスクリプトを実行するDocker ImageをPaketo Buildpackでビルドする方法について書こうと思います。

Cloud Native Buildpacks

今回利用するPaketo BuildpacksはCloud Native Buildpacksの基本的なBuildpackの1つです。実行環境を問わない所がいいです。これ以外の基本的なものだとHerokuやGoogleの提供しているBuildpackなどがあります。

 

paketo.io

Cloud Native Buildpacks(CNB)は雑に説明するとDockerfileなしでめっちゃ簡単にいい感じのDocker Image作れるよ!ってやつです。

 

buildpacks.io

導入も簡単で、以下の2ステップで完了です。

  1. Dockerのインストール
  2. packコマンドのインストール

コマンド1つでビルドもできるので、今回のような小さいイメージの作成からwebサービス用のイメージの作成まで、本当に簡単かつ最適なイメージが作れます。

前述の通りアソビュー!ではJavaをメインで開発しているので、Spring Bootを使ったwebアプリケーションでもこれを利用しています。

Python Paketo Buildpack

今回使うBuildpackは paketobuildpacks/builder:base です。これはJava, .NET Core, NodeJS, Go, Python, Ruby, NGINXの言語等に対応するBuildpackが含まれています。
それぞれにはBuildpackが選択されるトリガーがあります。Pythonであればプロジェクトのルートディレクトリに__init__.pyやsetup.pyといったものを配置することでコードアナライズに引っかかるようにします。(必要ない場合もあります。)

Python用のBuildpackはこちら。中身を軽く見てみます。

CPython CNBはPythonのリファレンス実装です。実行環境やビルド環境としてのPythonを提供してくれます。バージョン指定も可能なので、pyenvを利用している場合はビルド時に下記のようにバージョンを指定できます。念の為ですが、Python 2系は非対応のようです。

$ pack build ${IMAGE名} --builder paketobuildpacks/builder:base \
--env BP_CPYTHON_VERSION=$(cat .python-version)

Python Paketo Buildpackはパッケージマネージャーとして、Pip, Pipenv, Condaに対応しています。Pipenv CNBやPipenv install CNBなどはそれぞれのパッケージマネージャーのインストールや、パッケージマネージャー経由の依存ライブラリのインストール等を行ってくれます。installのCNBにもトリガーが存在し、例えばPipenvであればPipfileが、Pipであればrequirements.txtがプロジェクトのルートディレクトリにある場合にのみ作動します。
ちなみにPipenvの場合、実行時にはPipenvがいないのでscript機能などは使えません。余計なものは残さないぞ、という強い意志を感じますね。

最後にPython Start CNBProcfile CNBです。これらはどちらもコンテナを起動させたときの起動プロセスを制御します。
起動プロセスは下記のように指定します。

<type>: <command>

Python Start CNBは起動プロセスに「web: python」を設定します。webはデフォルトで起動するプロセスで、ここではコマンドの通り、対話型ウィンドウ (REPL)を起動します。
このデフォルトの起動プロセスを変更するためにはProcfile CNBを利用する必要があります。

Procfile CNBはProcfileを用意するか、ビルド時にバインドすることで利用することができます。指定方法は上記と同じです。
サンプルでは「web」のプロセスを上書きしていますが、全く別のプロセスを定義することもできます。この場合、下記のようにoptionを使ってデフォルトで起動するプロセスを変更できます。

$ echo "hello: echo hello world" > Procfile
$ pack build ${IMAGE名} --builder paketobuildpacks/builder:base \
--default-process hello

どこかで見たことのあるような指定方法とファイル名です。Herokuの開発思想が反映されている結果でしょうか。

実際に作ってみる

ここからがタイトルの内容なのですが、ここからは秒です。

今回の構成はこんな感じです。
Slackに適当な文章を送るスクリプトで試してみます。
packのバージョンは「0.21.1+git-e09e397.build-2823」でした。

- cnbtestpy
|- .python-version
|- Procfile
|- requirement.txt
|- test.py

それぞれの中身です。

■ .python-version

3.9.7

■ Procfile

script: python test.py

■ requirement.txt

slack-sdk==3.11.2

■ test.py

 
 
channel nameは適当に変えてください。

後はこのプロジェクトのルートディレクトリに移動して、packコマンドを打つだけです。

$ cd cnbtestpy
$ pack build cnbtestpy \
--builder paketobuildpacks/builder:base \
--env BP_CPYTHON_VERSION=$(cat .python-version) \
--default-process script

できたらrunしてみましょう。

docker run -e SLACK_BOT_TOKEN="xoxb-hogehoge" cnbtestpy

簡単ですね。

「PythonでもCNB使えるやん!使おう!」…から色々調べる時間が長かったので、自分でも体系的にまとまってる資料が欲しくて書きました。いかがだったでしょうか。

最後やっつけみたいになってますが、使うのはめちゃめちゃ簡単なんですよ、使うのは。中どうなってるのかな〜っていうのが1個こうしてがっつり触るとよく分かるようになってくるので、みなさんもCNBを雑に導入してみると良いと思います。Dockerfileから開放されるのは思ったより快適ですよ。

アソビュー!SREでは一緒に働くメンバーを積極的に募集しています!
EKSの導入やCICDの改善など、日々より良い技術を取り入れていき、より良いサービスを提供していく、非常にやりがいのある仕事です!
興味がありましたらお気軽にご応募いただければと思います。

 

www.wantedly.com