Docker 単純なpythonスクリプトを選択的に実行する

[docker] pythonスクリプトを入れたイメージを作成して、引数で実行内容を分岐させる

やりたいこと

単純にpythonスクリプトを実行したい。なおかつ複数の処理を選択的に実行したい。

pythonの実行というのは、python <script_name>.pyを行いたい、ということ。

複数の処理を選択的に実行というのは、引数などで分岐を発生させたいということ。

ローカルの環境をこれ以上汚したくないというのも理由の1つ。pyenvpipenvでもいいのだが、Dockerで集約した方がわかりやすいかと思って今後はこの形にしていきたい。

Dockerはこれはこれでいつの間にかストレージ容量を食っていたりと問題があるにはあるのだが。それは置いておくとしよう。

方針

dockerのイメージを作っておいて、必要に応じてコンテナを新規起動して、処理を行ったあと、クリーンにするためコンテナを削除する、という流れで行うことにした。

コンテナは都度作成して走らせるため、コマンドの入力が面倒。ミスを減らすためにもコンテナ起動用のシェルスクリプトを作成しておくことにした。

ついでにイメージビルドもシェルスクリプトを書いておくことにした。ビルドに使ったコマンド・オプションを忘れてしまうので。 ビルドにはそんなにオプションないんだけど使用頻度が低めなので念の為。

処理の分岐はコンテナ起動用のシェルスクリプトに引数(というかpythonのスクリプトファイルのパス)を与えて行うことにした。

実装

pythonファイル自体はなんてこともないので、省略。print('Hello')で十分。 いや、本当はいくつかのスクリプトのファイルに分けていて、それぞれのif __name__ == "__main__":の中に処理が1つずつ入っている。 テスト環境なら、それぞれのpythonファイルでprint(__file__)しておけばいいだろう。

またshファイルは実行権限の付与を忘れずに。chmod +x <script_name>.shなど。

Dockerfile

Dockerfileは以下のようにした。モジュールのインストールはrequirements.txtから。VSCodeのリモートコンテナのDockerfileを参考にした。

FROM python:alpine

COPY requirements.txt /tmp/pip-tmp/
RUN pip3 --disable-pip-version-check --no-cache-dir install -r /tmp/pip-tmp/requirements.txt \
   && rm -rf /tmp/pip-tmp

COPY src/ /etc/mysrc/
WORKDIR /etc/mysrc/

ENV APP_LOGLEVEL=INFO

処理を行うpythonファイルは、/etc/mysrc/内に格納しておく。そして、/etc/mysrc/を作業用ディレクトリにしておいて、pythonで使用するロギング用に環境変数も設定しておく。イメージの実行でDEBUGログは不要なため。

build.sh

イメージをビルドするためのスクリプト。

オプション付与でイメージを削除する機能も付けたら長くなってしまった。 ここでのメインは、build関数。

#! /bin/bash
# カレントディレクトリでdockerイメージをビルド。

VERSION=1.0
IMAGE_NAME=A_IMAGE_NAME

# -dオプションでコンテナ削除機能があると便利。
FLAG_D=0

while getopts d OPT
do
    case $OPT in
        d) FLAG_D=1
        ;;
    esac
done

function build () {
    echo "イメージをビルドします"
    docker build -t ${IMAGE_NAME}:${VERSION} .
}

function delete_image () {
    echo "イメージを削除します"
    docker rmi ${IMAGE_NAME}:${VERSION}
}


if [ $FLAG_D -eq 1 ]; then
    delete_image
else
    build
fi

ものすごい単純で、docker build ...をするだけ。これ1行でも実用可能。イメージさえ作れればいい。

run.sh

コンテナを実行するためのスクリプト。build.shよりは内容がある。

#! /bin/bash

if [ $# -ne 1 ]; then
    echo "引数が1つ必要です。" 1>&2
    echo "引数は、src/ディレクトリのpyファイルを指定します。" 1>&2
    exit 1
fi

# srcのなかに該当ファイルがないときは何もしないで終わり。
# あれば、それを引数として、コンテナをrunする。
# src/はつけてもなくてもいい。
# 実装しようと思えば、一旦ビルドし直してリトライもできる。

if [ -f ./src/${1} ] || [ -f ./${1} ]; then
    name=`basename ${1}`
    docker run --rm ad-python-retriever:1.0 python ${name}
else
    echo "指定されたファイルがsrcディレクトリにありません。" 1>&2
    exit 2
fi

exit 0

引数(pythonのスクリプトファイルの相対パスかファイル名)を1つ指定して、該当ファイルを引数として、pythonコマンドをコンテナ上で行う。

入力補完の都合上、src/から始まる相対パスでも、ファイル名単体でも動作するようにしている。コンテナは実行後は消去してしまって構わないので、--rmオプションを付けている。

使い方

簡単。今までやってきたことで、イメージのビルドコンテナの起動(と自動削除)イメージの削除の3点が行える。

# まずはスクリプトのあるディレクトリへ移動
$ cd /path/to/myapp
# イメージのビルド
$ ./build.sh

# pythonファイルの実行(コンテナの起動・自動削除)
$ ./run.sh hello.py

# イメージの削除
$ ./build.sh -d

シンプルなpythonファイルを環境を気にせず実行できる。やったね。

おわり

シェルスクリプト側で今回は処理を分岐させたが、pythonスクリプト側で分岐させることも簡単だ。argparsesys.argvなどを使えばできる。

getoptsを使ってみたかったので使ったみたが、オプション少ないなら使う必要はなかった。ともあれ大体の使い方はわかった。

イメージのビルドと削除は同じスクリプトで行う必要もなかった気がする…が、イメージ名やバージョンの管理は同一スクリプトの方が楽なので実装してみた方のがいいだろう。 ==> 使ってみると、同一スクリプトは楽だった。

これでどんなダメなスクリプトでもとりあえず作って実行してみることができる。GUIありソフトはやはり難しいが、簡単なツールはどんどん作れると思う。

以上です。


関連書籍(初心者向け)

Amazon.co.jp: [改訂第3版]シェルスクリプト基本リファレンス ──#!/bin/shで、ここまでできる WEB+DB PRESS plus eBook: 山森 丈範: Kindleストア
Amazon.co.jp: [改訂第3版]シェルスクリプト基本リファレンス ──#!/bin/shで、ここまでできる WEB+DB PRESS plus eBook: 山森 丈範: Kindleストア
独習Python | 山田 祥寛 |本 | 通販 | Amazon
Amazonで山田 祥寛の独習Python。アマゾンならポイント還元本が多数。山田 祥寛作品ほか、お急ぎ便対象商品は当日お届けも可能。また独習Pythonもアマゾン配送商品なら通常配送無料。
さわって学ぶクラウドインフラ docker基礎からのコンテナ構築 | 大澤 文孝, 浅居 尚 | 工学 | Kindleストア | Amazon
Amazonで大澤 文孝, 浅居 尚のさわって学ぶクラウドインフラ docker基礎からのコンテナ構築。アマゾンならポイント還元本が多数。一度購入いただいた電子書籍は、KindleおよびFire端末、スマートフォンやタブレットなど、様々な端末でもお楽しみいただけます。
タイトルとURLをコピーしました