作ったツール類をコンテナにまとめてしまえばいろいろ便利と耳にしたので、以前から気になっていたDockerを使い始めることにしました。
今回は、pythonのflaskで作ったwebサーバをコンテナ化し、コンテナの起動・停止だけでwebサーバを管理できるようにしてみようと思います。
使用した環境はこちら
$ cat /etc/redhat-release
Red Hat Enterprise Linux release 8.2 (Ootpa)
$ docker --version
Docker version 19.03.12, build 48a66213fe
※ 余談ですが、CentOS 8でDockerをインストールしようとすると containerd.io
が無いぞって言われることがあるようです。私の場合はこちらで無事解決できましたので参考までに。
Dockerおさらい
まずはDockerの使い方(コンテナの作り方)について簡単に整理します。Dockerコンテナの作り方は次の4ステップ。
- ベースとなるイメージをpull
- Dockerfile作成
- Dockerイメージのビルド
- イメージからDockerコンテナの生成・起動
個人的に、最初はDockerfileを作成するところが一番よくわからないところだと思います。なので、まずは第一段階としてpythonの簡単なスクリプトをコンテナ内で動かすところまで作り、第二段階としてflask製webサーバを動かすところまで改良していきます。
コンテナ内でpythonスクリプトの実行
第一段階として、コンテナ内で次の myapp.py
を実行するところまで作ります。
print("hello Docker!")
ベースとなるイメージをpull
最初にpython3系の実行環境となるイメージを用意します。Docker Hubに登録されているpython3系のイメージを検索。
$ sudo docker search python3
NAME DESCRIPTION STARS OFFICIAL AUTOMATED
rackspacedot/python37 11
sellpy/python3-jupyter-sklearn python3-jupyter-sklearn 5 [OK]
openwhisk/python3action Apache OpenWhisk runtime for Python 3 Actions 5
sellpy/python3-jupyter-sklearn-java python3-jupyter-sklearn-java 2 [OK]
quoinedev/python3.6-pandas-alpine Python 3.7 on alpine with numpy and pandas i… 2
(略)
今回はSTARSが最も多い rackspacedot/python37
を使用します。これをpullしましょう。
$ sudo docker pull rackspacedot/python37
rackspacedot/python37
もDockerイメージなので、pullした後は docker images
で確認できます。
$ sudo docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
rackspacedot/python37 latest 3d51361ee118 7 weeks ago 1.06GB
このイメージがあればコンテナ内でpythonが使えるようになるので、これをベースとしてその他の必要な部分(スクリプトの配置など)を追加すればOKという感じです。
Dockerfile作成
次に、 Dockerfile
という名前のファイルを作成します。
FROM rackspacedot/python37
WORKDIR /usr/local/script
COPY myapp.py .
CMD python myapp.py
簡単に説明しますと、
-
FROM rackspacedot/python37
- ベースとなるイメージを指定する部分です。先ほどpullしたイメージを指定します。
-
WORKDIR /usr/local/script
- コンテナ内での作業ディレクトリを指定します。今自分がいるディレクトリと違っていても問題ありません。
-
COPY myapp.py .
- myapp.pyをコンテナ内の第二引数で指定したディレクトリにコピーします。今回は
.
で指定しているので、WORKDIR
で指定したディレクトリにコピーされます。
- myapp.pyをコンテナ内の第二引数で指定したディレクトリにコピーします。今回は
-
CMD python myapp.py
- コンテナ起動時に実行するコマンドです。
ここまでで用意したファイルは次の通り。
$ ls -l
total 8
-rw-r--r--. 1 user developer 146 Sep 11 16:39 Dockerfile
-rw-r--r--. 1 user developer 173 Sep 11 17:04 myapp.py
Dockerイメージのビルド・コンテナ起動
Dockerfileを作成したので、イメージのビルド→コンテナ起動をしていきます。
まずはイメージのビルドから。
$ sudo docker build -t myapp:test .
-t 名前:タグ
はイメージの名前とタグを設定します(スクリプト名と違っていてもOKです)。 .
はDockerfileがあるディレクトリのパスを指定します。
Successfully built ハッシュ値
と出ればイメージが生成されたので、 docker images
で確認できるようになります。
$ sudo docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
myapp test e577339515a7 10 seconds ago 1.06GB
rackspacedot/python37 latest 3d51361ee118 7 weeks ago 1.06GB
イメージができたので、コンテナを作成・起動します。
$ sudo docker run myapp:test
hello Docker!
無事コンテナでpythonスクリプトを実行できました。
ここで起動したコンテナは残るので、再度同じコマンドで実行することができます。また、 docker ps -a
で作成したコンテナを確認することができます。
コンテナ内でflask製サーバの実行
さて、コンテナ内でpythonスクリプトを実行できるようになったので、第二段階としてflaskでサーバを作成していきましょう。
myapp.py
を次のように書き換えます。
from flask import Flask
app = Flask("myapp")
@app.route("/")
def main():
return "hello Docker!!"
if __name__ == "__main__":
app.run(host="0.0.0.0", port=8080)
一応先ほどと変化がわかるように !
の数を2個にしました。
これをコンテナ内でwebサーバとして使える状態にしましょう。
Dockerファイル修正
flaskを使用するので、コンテナ内にflaskをインストールする必要があります。 rackspacedot/python37
にはデフォルトでpipが入っていますので、イメージのビルド時に pip install
する部分をDockerfileに追加します。
FROM rackspacedot/python37
RUN pip install flask
RUN useradd docker
USER docker
WORKDIR /usr/local/script
COPY myapp.py .
CMD python myapp.py
追加した分を説明すると、
-
RUN pip install flask
- コンテナ内にflaskをインストールします。
-
RUN useradd docker / USER docker
-
docker
というユーザーを追加し、その後の操作をdocker
ユーザーとして実行します。 - 今回は無くても動作しますが、セキュリティ上の理由で追加しています。
-
Dockerイメージのビルド・コンテナ起動
ファイルを書き換えたので、イメージを再ビルド→コンテナ起動します。
まずは再ビルドから。
$ sudo docker build -t myapp .
今回はタグを省略したので、自動的に latest
というタグが割り当てられます。 docker images
で確認してみましょう。
$ sudo docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
myapp latest 6c747be5d597 3 seconds ago 1.06GB
myapp test e577339515a7 50 minutes ago 1.06GB
rackspacedot/python37 latest 3d51361ee118 7 weeks ago 1.06GB
それではコンテナを起動しましょう。webサーバなので、オプションを追加しています。
$ sudo docker run -d -p 8080:8080 myapp
ポート番号ですが、 -p 受付ポート番号:コンテナ側の番号
の書き方になります。受付ポート番号は何番でも良いのですが、コンテナ側の番号はコンテナ内の myapp.py
で指定した番号(今回の場合は8080)にします。
問題なく起動していれば、 docker ps
で起動中のコンテナを確認することができます。
$ sudo docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
00d1ab6fc24a myapp "/bin/sh -c 'python …" 3 seconds ago Up 2 seconds 0.0.0.0:8080->8080/tcp thirsty_mccarthy
実際にアクセスしてみましょう。
$ curl http://localhost:8080
hello Docker!!
いいですね。これでwebサーバのコンテナ化完了です。
コンテナを停止したい場合は
$ sudo docker stop thirsty_mccarthy
停止後に再度起動したい場合は
$ sudo docker start thirsty_mccarthy
thirsty_mccarthy
の部分はコンテナ名( docker ps
実行時の NAME
に表示されるもの)を指定してください。docker start
で起動すると、自動的に docker run
の時に指定したポートで実行してくれます。
また、コンテナ化しておくと作ったものを他の環境で実行する時もイメージのビルド→コンテナ起動ですぐに動かせるので、非常に便利ですね。
今回は以上になります。Docker Composeで複数コンテナをコマンド一つで実行できるようになればさらに幅が広がるので、そのうちこれも勉強しようかなと思います。