matobaの学んだこと

とあるPythonエンジニアのブログ。ソフトウェア開発、執筆活動、ライフログ。

Docker初心者のはじめの一歩

Dockerを使うことになりました。Docker初心者&Dockerを実際に触った経験が少ない、というのがあって、不安が多いです。

こういう不安は、とりあえず触ってみると解消されることが多いので、簡単にDockerを触りつつ、不安を解消しました。

環境

僕の手元の環境はmacOSです。Sierraです。

予備知識

以下のあたりが参考になります。

用語

  • Docker
  • Dockerイメージ
  • Dockerコンテナ
  • DockerFile
    • Dockerイメージを使って、Dockerイメージを作る設計ファイルです。Dockerイメージは、公式のものを使って、DockerFileでファイルを読み込みつつ、自分が使うDockerイメージを作ったりできます。

Dockerのインストール

Dockerを使うために、Dockerをインストールします。

繰り返しになりますが、Dockerは、仮想マシンを管理する仕組みなので、まずは管理するヤツをインストールする必要あります。

公式から、Docker for MacをDLして、適当にインストールします。dmgでした。

docs.docker.com

バージョンも確認できました。

$ docker -v
Docker version 18.03.1-ce, build 9ee9f40

手元のDockerイメージの一覧を確認

また、繰り返しになりますが、Dockerには、仮想マシンを作る元になるDockerイメージというものがあります。

docker images を打つと、手元にあるDockerイメージの一覧が見れます。

$ docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE

まあ、今は何もないんですが。

Dockerイメージを検索

DockerイメージはDockerのリポジトリで多数公開されているらしいです。

で、Dockerのリポジトリにどんなイメージがあるかは、 docker search コマンドで確認することができます。

今回は、Pythonに関係するDockerイメージを探して見ます。

$ docker search python
NAME                               DESCRIPTION                                     STARS               OFFICIAL            AUTOMATED
python                             Python is an interpreted, interactive, objec…   2762                [OK]
django                             Django is a free web application framework, …   656                 [OK]
pypy                               PyPy is a fast, compliant alternative implem…   134                 [OK]
kaggle/python                      Docker image for Python scripts run on Kaggle   91                                      [OK]
centos/python-35-centos7           Platform for building and running Python 3.5…   20
amazon/aws-eb-python               AWS Elastic Beanstalk Python Image              19
resin/raspberrypi3-python          The Python buildpack image for Python apps f…   17
arm32v7/python                     Python is an interpreted, interactive, objec…   15
iron/python                        Tiny Python Microcontainer                      8
centos/python-27-centos7           Platform for building and running Python 2.7…   8
joyzoursky/python-chromedriver     Python with Chromedriver, for running automa…   8                                       [OK]
resin/raspberrypi3-alpine-python   The Python buildpack image for Python apps. …   6
circleci/python                    Python is an interpreted, interactive, objec…   5
centos/python-36-centos7           Platform for building and running Python 3.6…   4
resin/beaglebone-black-python      The Python buildpack image for Python apps f…   3
centos/python-34-centos7           Platform for building and running Python 3.4…   2
komand/python-plugin               Komand Python SDK                               2                                       [OK]
qbtrade/python                     python 3.5.0 with requirements                  0
resin/qemux86-alpine-python        The Python buildpack image for Python apps. …   0
resin/artik5-python                The Python buildpack image for Python apps f…   0
resin/qemux86-64-python            The Python buildpack image for Python apps f…   0
resin/artik10-python               The Python buildpack image for Python apps f…   0
openshift/python-33-centos7        DEPRECATED: A Centos7 based Python v3.3 imag…   0
resin/qemux86-python               The Python buildpack image for Python apps f…   0
publicisworldwide/python-conda     Basic Python environments with Conda.           0                                       [OK]

結構たくさん出てきました。一番上のやつでいいかな・・・。 Descriptionがもう少しみたいので、ヘルプ見て、データを削らずにアウトプットするオプションを指定して確認しました。

$ docker search --no-trunc python
NAME                               DESCRIPTION                                                                                 STARS               OFFICIAL            AUTOMATED
python                             Python is an interpreted, interactive, object-oriented, open-source programming language.   2762                [OK]
...

あ、はい。という感じの説明です。

OFFICIAL OKと書いてるからなんとなくよさげな雰囲気を感じつつ、pythonというイメージを使うことにします。

Dockerイメージをダウンロード

Dockerイメージは、docker pull でダウンロードすることができるようです。

$ docker pull python
Using default tag: latest
latest: Pulling from library/python
f2b6b4884fc8: Pull complete
4fb899b4df21: Pull complete
...略
Status: Downloaded newer image for python:latest

ここでいう、python:latestってなんだろ?という疑問はありますが、まあとりあえず、スルーします。

docker images で確認すると以下のようになってます。

$ docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
python              latest              6bf7a4fa2d45        6 days ago          691MB

CREATEDが6 days agoなので、かなり新しそう。

Dockerイメージでコンテナ作成

次は、Dockerイメージを使ってコンテナを作ってみます。

docker run に対話型のオプション -it をつけて、Dockerイメージ pythonを指定してを実行します。

$ docker run -it python
Python 3.6.5 (default, Mar 31 2018, 01:15:58)
[GCC 4.9.2] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>>

すると新しいDockerイメージが起動して、Pythonインタラクティブシェルが起動しました。

Dockerイメージがあることを確認します。 docker ps -a を実行します。このコマンドで、起動中のコンテナの一覧が見れます。

$ docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED              STATUS              PORTS               NAMES
ca7d38f97899        python              "python3"           About a minute ago   Up About a minute                       nervous_snyder

STATUSが Up About a minute になっています。 はい。

最初のPythonインタラクティブで、 exit() を実行します。

$ docker run -it python
Python 3.6.5 (default, Mar 31 2018, 01:15:58)
[GCC 4.9.2] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> exit()

するとSTATUSが変わります。

$ docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                     PORTS               NAMES
ca7d38f97899        python              "python3"           3 minutes ago       Exited (0) 9 seconds ago                       nervous_snyder

まあ、ステータスコード0で終わったよ。という話。

この後、dockerコンテナは削除しましょう。消えます。

$ docker rm ca7d38f97899
ca7d38f97899
$ docker ps -al
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES

要するに、Dockerというのは、簡単に使い捨ての実行環境を作る仕組みです。

Pythonインタラクティブシェルだけだと面白くないし、何が嬉しいのかわからないです。

で、いろいろ調べてると、Dockerコンテナの中で、サーバーを起動するのが、よくあるパターンのようです。

というわけでやってみます。

DockerコンテナでWebアプリを起動する

Pythonで動くWebアプリを用意する

まずは、Python3.6で動くhttpserverを用意します。

$ echo Flask > requirements.txt
$ cat requirements.txt
Flask
$ python3 -m venv venv --prompt flask
$ . venv/bin/activate
(flask) $ pip install -r requirements.txt
(flask) $ vim app.py

app.py

from flask import Flask

app = Flask(__name__)

@app.route("/")
def hello():
    return "<h1>Hello Flask in Docker!</h1>" \

if __name__ == "__main__":
    app.run(host='0.0.0.0', port=8000)
(flask) $ python app.py
 * Serving Flask app "app" (lazy loading)
 * Environment: production
   WARNING: Do not use the development server in a production environment.
   Use a production WSGI server instead.
 * Debug mode: off
 * Running on http://0.0.0.0:8000/ (Press CTRL+C to quit)
$ curl http://localhost:8000/
<h1>Hello Flask in Docker!</h1>

はい。とりあえず、できました。

これを、Dockerコンテナの中で動かしていきます。

Dockerコンテナの中で、指定したコマンドを実行

Dockerコンテナの中で、指定したコマンドを実行するのは、以下ではダメです。

(flask) $ docker run python app.py
docker: Error response from daemon: OCI runtime create failed: container_linux.go:348: starting container process caused "exec: \"app.py\": executable file not found in $PATH": unknown.
ERRO[0000] error waiting for container: context canceled

まあ、当たり前なんですが。

で、それを実現するために出てくるのが、DockerFileです。 DockerFileにいろいろ書くと、実現できます。

というわけで、以下のDockerFileを用意します。

Dockerfile

FROM python

# 作業ディレクトリを /myapp に設定
WORKDIR /myapp

# 必要なファイルをコンテナ内の /myapp にコピー
ADD requirements.txt /myapp
ADD app.py /myapp

# requirements.txt でインストール
RUN pip install -r requirements.txt

# 8000ポートを外に見せる
EXPOSE 8000

CMD ["python", "app.py"]

そして、以下を実行すると hello_myapp というDockerイメージが作成されます。

$docker build -t hello_myapp .

以下を実行して、きちんとできていることを確認します。

$ docker images | grep hello_myapp
hello_myapp         latest              f87e05b52f04        About a minute ago   701MB

次は、dockerコンテナを作ってみます。-p でホストOSの8010ポートをDocker上のコンテナの8000にポートフォワーディングしています。

$ docker run -p 8010:8000 hello_myapp
 * Serving Flask app "app" (lazy loading)
 * Environment: production
   WARNING: Do not use the development server in a production environment.
   Use a production WSGI server instead.
 * Debug mode: off
 * Running on http://0.0.0.0:8000/ (Press CTRL+C to quit)

httpでアクセスできます。

$ curl http://0.0.0.0:8010/
<h1>Hello Flask in Docker!</h1>

はい。ここまできたら、大体のことはできそうな予感がしてきました。 次は、docker-composeを触ってみたいですね。

皆様も、よいDockerライフを。