BLOG

最終更新日:
公開日:

WEB制作

DockerでPythonを実行するコンテナを作る

DockerでPythonの実行環境を構築する方法について解説します。

この記事のポイント

  • 開発向けPHP実行環境のコンテナを作成する
  • Docker Hubからコンテナの設計が書かれた「イメージ」をダウンロードする
  • ローカル環境とDockerコンテナ内のディレクトリを接続する

目次

Pythonを実行するコンテナに必要なもの

開発向けのPythonを実行することができるコンテナを作っていきます。
次の3つのファイル(1つはcgi-binディレクトリ内に設置)が必要になります。

  • Dockerfile
  • index.html
  • cgi-bin/index.py

コンテナイメージの設計図となるDockerfileの他に、Webサーバーの挙動を確認するためにindex.htmlとPythonのコードを書いたファイルindex.pyを用意します。
今回はPython3の標準モジュール「http.server」を使ってWebサーバーを動かしながら、Pythonの実行環境を構築します。

今回は以下の流れでコンテナを作成、実行していきます。

  1. Docker Hubにあるコンテナイメージを確認にする
  2. Dockerfileを作成する
  3. index.htmlを作成する
  4. cgi-binディレクトリとindex.pyを作成する
  5. Dockerコンテナイメージをビルドする
  6. Dockerコンテナを起動
  7. ブラウザからコンテナにアクセス

なお、Dockerはすでにインストールされていることを前提としています。
これからインストールする場合は、「Dockerをインストールする」よりインストールを行なってください。

コンテナのイメージを確認する

まずは今回使用するPythonのコンテナイメージをDocker Hubより確認しておきましょう。
以下のリンクから開いてください。
Docker Hub

Docker Hubのページ上部にある検索スペースに、「python」と入力してみてください。

pythonのコンテナイメージを検索
pythonのコンテナイメージを検索

入力すると下に検索候補が表示されます。
この中から一番上にある「python」を選択してください。
(検索候補から選択せずに検索を実行して、一番上に表示される「python」を選択する形でも大丈夫です)

python」を選択すると、Pythonの公式コンテナイメージのページが表示されます。
公式のコンテナイメージはタイトルのすぐ下に青い文字で「Docker Official Images」と記載されています。

Pythonの公式コンテナイメージ
Pythonの公式コンテナイメージ

ページを少し下へ移動すると、「Description」「Reviews」「Tags」の3つのタブがあります。
最初から表示されている「Description」は使用できるアプリケーションのバージョンや基本的な使い方が記載されています。

この中の「Supported tags and respective Dockerfile links」は使用できるコンテナイメージのタグが記載されています。
ここにあるコンテナイメージは全て使用できますが、今回は軽量なAlpine LinuxをベースとしたPythonの最新安定板である「alpine」のタグを使ってコンテナを作成します。

今回使用するイメージのタグを確認する
今回使用するイメージのタグを確認する

2021年4月現在、「alpine」はPython3.9.4を使ったコンテナイメージになります。
同じ行に記載されている「3.9.4-alpine3.13」や「3-alpine」は別名のタグが付いていますが、コンテナイメージ自体は全く同じものです。
常に最新バージョンのPythonを使った環境のコンテナを作りたいときは、今回のようにバージョンが明記されていない「alpine」を使用します。

もし、「今後しばらく同じバージョンで開発を行いたい」、「以前の環境を再現したい」など明確な理由があるときは、今回とは対照的にバージョンが明記されたタグを使用します。

Dockerfileを作成する

使用するコンテナイメージを確認したところで、コンテナの設計図にあたる「Dockerfile」というテキストファイルを作成します。

今回はローカル環境の「/Users/test/docker/python/」というパスにファイルを配置していきます。
ディレクトリ名は任意のもので大丈夫なので、パスはご自身の環境に置き換えて進めてください。

/Users/test/docker/python/」の中に「Dockerfile」というファイルを作成して、以下のコードを書いてください。

Dockerfile

FROM python:alpine

WORKDIR /app

COPY . /app

CMD ["python","-m","http.server","--cgi"]

1行目の「FROM python:alpine」は「FROM」を使ってベースになるコンテナイメージを指定します。
先ほどDocker Hubで確認したコンテナイメージ「python」とタグ「alpine」を「:」で区切って指定します。
(もし使うタグが「3.9.4-alpine3.13」のときは「FROM python:3.9.4-alpine3.13」のようになります。)

2行目の「WORKDIR」はコンテナの作業ディレクトリを指定します。
今回はコンテナ内の「/app」を作業ディレクトリとして指定します。

3行目の「COPY」はコンテナを起動したときに、ローカル環境からコンテナ内にファイルをコピーして設置するための指定です。
COPY」の1つ目にはコピー元のホストディレクトリ(ローカル環境のディレクトリ)、2つ目にはコピー先のコンテナのディレクトリを指定します。

今回の例であれば、1つ目のホストディレクトリには現在のディレクトリ「.」を指定するため、ローカル環境「/Users/test/docker/python/」にある全てのファイルがコンテナの「/app」に複製されて設置されます。

最後の行の「CMD」は起動したタイミングでコンテナ内で実行するコマンドを指定することができます。
上記の設定はLinuxのCUIで「python -m http.server –cgi」を実行する指定になっています。
CMDではCUIのコマンド入力で使う半角スペースを「,(コンマ)」に置き換え、それぞれのコマンドやパラメータを「(ダブルクォート)」で囲みます。

http.serverはポート番号を指定しない場合は「8000」を使用します。
もし他のポート番号を指定したいときは以下のように指定します。

Dockerfile(ポート番号を指定)

FROM python:alpine

WORKDIR /app

COPY . /app

CMD ["python","-m","http.server","4040","--cgi"]

HTMLファイルを作成する

使用するコンテナイメージを確認したところで、続いてコンテナで使用するHTMLファイルを作成します。

今回はローカル環境の「/Users/test/docker/python/」というパスにファイルを配置していきます。
ディレクトリ名は任意のもので大丈夫なので、パスはご自身の環境に置き換えて進めてください。

Pythonの実行環境を構築することを目的にしているため、HTMLコードだけが書かれたファイルは不要に思われるかもしれません。
こちらはモジュール「http.server」で立ち上げるWebサーバーの動作確認をする目的で作成します。

まずは「index.html」というHTMLファイルを作成して、以下のコードを入力してください。

index.html

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="utf-8">
  <title>Test Page</title>
</head>
<body>
  <h1>Welcome to Python!</h1>
  <p>This is test page.</p>
</body>
</html>

コードを記述したら保存してください。

Pythonファイルを作成する

続いて、Pythonコードを書いたファイルを作成します。

モジュール「http.server」で立ち上げるWebサーバーは、標準設定で「/app/cgi-bin/」にある拡張子「.py」のファイルに書かれたコードをCGI(Common Gateway Interface)という仕組みで実行します。

今回の例ではローカル環境の「/Users/test/docker/python/」と、Dockerコンテナ内のパス「/app」と同期させます。
そのため、「/Users/test/docker/python/」の中に「cgi-bin」というディレクトリを作って、さらにその中に「index.py」というファイルを作成してください。
するとローカル環境とコンテナ内のファイルを同期したときに、コンテナ内の「/app」の中に作成したcgi-binディレクトリごとファイルが同期されます。
同期の設定は後ほど行います。

index.pyを開いて、以下のコードを書いてください。

index.py

#!/usr/bin/env python3

print("Content-type: text/plain\n")
print("Hello! Python on Docker!")

シンプルに「Hello! Python on Docker!」とメッセージを出力するだけのコードです。
こちらのファイルもコードを書いたら保存してください。

Dockerコンテナイメージをビルドする

コンテナに必要なファイルが全て揃いました。
続いて、コンテナイメージを作成しましょう。

まずはコマンドを入力して実行するためにプロンプトを起動します。
Windowsで実行するなら「PowerShell」、Macの場合は「ターミナル」などを開いてください。
(コマンドの入力、実行ができるなら他のアプリケーションでも大丈夫です)

cdコマンドを使って、ローカル環境の「/Users/test/docker/python/」に移動します。

cdコマンド 入力例

$ cd /Users/test/docker/python/

念のため、ファイルが揃っているかlsコマンドで確認しておきましょう。
以下のように2つのファイルとcgi-binフォルダが表示されればOKです。

lsコマンド 入力&出力例

$ ls
Dockerfile  cgi-bin  index.html

cgi-binフォルダの中もindex.pyがあるか確認してください。

lsコマンド 入力&出力例

$ ls cgi-bin
index.py

続いて、Dockerの「docker image build」コマンドを実行します。
新しく作成するコンテナイメージ名は「py」としていますが、自由な名前に変えても大丈夫です。

コマンド 入力&出力例

$ docker image build -t py .
Sending build context to Docker daemon  11.78kB
Step 1/4 : FROM python:alpine
 ---> ef8f54a21dcd
Step 2/4 : WORKDIR /app
 ---> Using cache
 ---> 2f44d7638591
Step 3/4 : COPY . /app
 ---> 3fdc2fc8eec8
Step 4/4 : CMD ["python","-m","http.server","--cgi"]
 ---> Running in 30f8b373abd6
Removing intermediate container 30f8b373abd6
 ---> 26f00ba29fc5
Successfully built 26f00ba29fc5
Successfully tagged py:latest

コンテナイメージのビルドが無事成功すると、上記の最後の2行のように「Successfully」が表示されます。
Stepなどの表示は実行環境によってダウンロードなどが発生するため異なります。

-tオプションは作成するコンテナイメージ名とタグ名を指定することができます。
今回のようにタグ名を省略すると自動的に「latest」になります。

末尾には現在のディレクトリである「.(ドット)」を指定します。

作成したコンテナイメージを「docker image ls」コマンドで確認してみましょう。

lsコマンド 入力&出力例

$ docker image ls
REPOSITORY  TAG      IMAGE ID       CREATED          SIZE
py          latest   26f00ba29fc5   44 seconds ago   44.7MB

コンテナイメージが新しい順に表示されます。
正常に作成できていたら「py」が表示されます。
(コンテナイメージ名を変えている場合は指定したイメージ名が表示されます)

コンテナを起動する

作成したコンテナイメージを使って、早速コンテナを起動してみましょう。
以下の「docker run」コマンドを入力して、実行してください。
実行に成功すると、2行目のようにランダムの英数字からなるコンテナIDが表示されます。

コマンド入力例

$ docker run -p 5000:8000 -v ${PWD}:/app -d py
8b4e058bd0ff0bbcc872c594bfba1a5489673e8da7324545ac40ca8190aae883

コンテナの起動はdockerコマンドで「container run」、もしくは「run」を使います(どちらも同じです)。
今回のコマンドはオプションの指定が多いため、先頭から解説していきます。

ポート番号を指定する-pオプション

1つ目の「-p 5000:8000」はサーバーのポート番号を指定します。
-p」は「publish」の頭文字です。

ポート番号は「:」で区切って、「開くポート番号:コンテナ内のポート番号」の形式で指定します。

先述の通り、http.serverはポート番号を指定しない場合は「8000」になります。
ただしこのポート番号はコンテナ内のもので、ブラウザなど外部からアクセスするためには-pオプションで外部のポート番号を別途指定する必要があります。

ここではコンテナ内のポート番号「8000」を「5000」から外部アクセスできるようにしています。
そのため、ブラウザからアクセスするときは「localhost:5000」を使います。

また、ポート番号はすでに他のDockerコンテナやサーバーが使用していると同じ番号は使うことができないため、以下のようなエラーができます。

コマンド入力例

$ docker run -p 5000:8000 -v ${PWD}:/app -d py
55d443f62f7268b72739ab2a0130c1cfa59f7cf6978fa76997b887
docker: Error response from daemon: driver failed programming external connectivity on endpoint zen_mahavira
(1a7aa82afdd184c42a4218b2861df841b6d3d4a3d52d556ce8): Bind for 0.0.0.0:5000 failed: port is already allocated.

その場合は上記の-pオプションで指定するポート番号を「5001」など重複しない番号を指定してください。

ファイルを同期する-vオプション

2つ目の「-v ${PWD}:/app」はローカル環境とコンテナのディレクトリを同期するオプションです。
-v」は「volume」の頭文字です。

このオプションを指定すると、ローカル環境の特定のディレクトリをコンテナ内と同期させて、ファイルの修正をすぐに反映することができるようになります。

同期するディレクトリのパスは「:」で区切って、「ホスト(ローカル環境)ディレクトリ:コンテナ内のディレクトリ」の形式で指定します。

上記のように「${PWD}」を使うと、現在のディレクトリのパスが自動的に入ります。
もちろん絶対パスや相対パスで指定しても大丈夫です。

コンテナをバックグランド処理にする-dオプション

3つ目の「-d」は起動したコンテナをバックグラウンド処理で実行するオプションです。
-d」は「detach」の頭文字です。

-dオプションを指定しない場合、「docker run」コマンドでコンテナを起動するとコンテナが終了するまではカーソルが入力状態になりません。
もし挙動が気になる方は、後述するコンテナ終了コマンドを実行してから改めて-dオプションを指定しないで実行してみてください。

以上でPythonを実行するコンテナが起動しました。
起動中のコンテナは「docker container ls」コマンドより確認することができます。

コマンド入力例

$ docker container ls
CONTAINER ID  IMAGE  COMMAND       CREATED        STATUS        PORTS                   NAMES
8b4e058bd0ff  py     "python -m…"  4 seconds ago  Up 4 seconds  0.0.0.0:5000->8000/tcp  modest_kho

「CONTAINER ID」は「docker run」コマンドで実行した後に表示されたコンテナIDを短くしたものが表示されます。

もしここで先ほど起動したコンテナが表示されていない場合は、起動後にエラーなどですぐに終了してしまった恐れがあります。
そのときは「docker container ls」に-aオプションをつけて実行してみてください。

コマンド入力例

$ docker container ls
CONTAINER ID  IMAGE  COMMAND       CREATED        STATUS        PORTS                   NAMES
8b4e058bd0ff  py     "python -m…"  4 seconds ago  Exited (137) 8 seconds ago   modest_kho

「STATUS」カラムに「Exited」と表示されていたら、コンテナはすでに実行を終了しています。
そのときは上記のDockerfileの記述、パスやコマンドのパラメーターなどを改めて確認してみてください。

ブラウザからコンテナにアクセス

コンテナを起動したら、ブラウザからコンテナ内のWebサーバーにアクセスしてみましょう。

Chromeなどのブラウザを開いて、URLに「localhost:5000」と入力してアクセスしてみてください。
もし上記「docker run」コマンドの-pで「5000」以外のポート番号を指定している場合は、指定した番号に置き換えてください。

ブラウザの表示例
ブラウザの表示例

ブラウザに「index.html」の内容が表示されたでしょうか。
無事に表示されていたら、コンテナ内の「/app」にindex.htmlが設置されていると確認できたことになります。

ここで、-vオプションの挙動を確認してみましょう。
-vオプションが正常に設定されていると、ローカル環境の「/Users/test/docker/python/」にあるindex.htmlを編集するとコンテナ内の「/app」にあるindex.htmlも編集が反映されます。
ローカル環境のindex.htmlを開いて、以下の赤字の箇所のようにコードを編集して上書き保存してください。

index.html

<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>Test Page</title>
</head>
<body>
  <h1>Welcome to Python!</h1>
  <p>This is test page.<br>Edited.</p>
</body>
</html>

ブラウザに戻って、再読み込み(リロード)してください。
以下のように編集内容がすぐに反映されたら、ファイルの同期が成功しています。

ブラウザの表示例
ブラウザの表示例

続いて、Pythonファイルにアクセスしてみましょう。
先ほど入力したURLの後ろに「/cgi-bin/index.py」を入力して、「localhost:5000/cgi-bin/index.py」にアクセスしてみてください。
以下のようにメッセージが出力されたら成功です。

ブラウザの表示例
ブラウザの表示例

ここでもしブラウザに「#!/usr/bin/env python3」から続くindex.pyの内容がそのまま出力されてしまうときは、WebサーバーがCGIを実行できていません。
そのときはDockerfileの内容(特にWORKDIRCMD)、またはindex.pyの1行目の「#!/usr/bin/env python3」を確認してみてください。

PythonコードのファイルもHTMLと同様に、ローカル環境でファイルを修正したらすぐにコンテナ内に反映されます。
ローカル環境のcgi-binディレクトリにあるindex.pyを開いて、以下の赤字の箇所を追記してください。

index.py

#!/usr/bin/env python3

print("Content-type: text/plain\n")
print("Hello! Python on Docker!")
print( (1+4)*100 )

コードを追記したら上書き保存して、もう一度ブラウザに戻って再読み込み(リロード)してください。
以下のように計算結果が出力されたら成功です。

計算結果が出力される
計算結果が出力される

ここまでで、DockerでPythonを実行できるコンテナを作成することができました。
もしコンテナが不要になったら、「docker stop」コマンドか「docker container stop」コマンドでコンテナを停止します(どちらも停止する動作は同じです)

コマンド入力例

$ docker stop 8b4e058bd0ff
8b4e058bd0ff

正常に停止すると、停止したコンテナのIDを出力します。
コンテナIDは「docker container ls」コマンドで表示された短いID、起動したときに表示されるフルIDのどちらでも大丈夫です。

また、停止したコンテナは削除したわけはないため、「docker start」コマンドで再度起動することができます。

コマンド入力例

$ docker start 8b4e058bd0ff
8b4e058bd0ff

こちらの記事は役に立ちましたか?

ありがとうございます。
もしよろしければ、あわせてフィードバックや要望などをご入力ください。

コメントありがとうございます!
運営の参考にさせていただきます。

前のページへ 一覧に戻る 次のページへ