Python の学習がてら、SDKs for Docker Engine API を触ってみた

2017.05.15

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

はじめに

Python の学習を始めるにあたり、手頃なお題を探していました。 Docker Engine API を利用すると、各種コードからコンテナが起動出来るということを docker docs - SDKs for Docker Engine API で知り 試しに動かしてみようと思いました。

なお、筆者は Python 初心者であるため 記述内容に不備などあれば、ご指摘頂けますと幸いです。

事前作業

Docker SDK for Python は、Python Package Index (PyPI) で パッケージとして提供されているため、pip でインストール出来ます。 以下のコマンドにて、予めインストールしておいてください。 なお、筆者の環境は macOS Sierra(10.12.4) です。

$ sudo pip install docker

はじめてみよう

以下のドキュメントに記載されたサンプルを動かしてみながら、Docker API を試してみましょう。

Run a container

まずは、コンテナを起動するコードを記述します。 ファイル名は、run_container.py としました。

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import docker
client = docker.from_env()
print client.containers.run("alpine", ["echo", "hello", "world"])

実行してみます。

~/local/sample $ ./run_container.py 
hello world

"hello world"は、echo されましたが、 コンテナ内で実行されたかどうか分からないので プログラムコードをループ処理に変更(daemonize)し、 docker コマンドにて、確認してみます。

コードの変更点は、以下のとおりです。

~/local/sample $ git diff ^HEAD
diff --git a/run_container.py b/run_container.py
index 2b3e547..7dcbd9d 100755
--- a/run_container.py
+++ b/run_container.py
@@ -3,4 +3,4 @@

import docker
client = docker.from_env()
-print client.containers.run("alpine", ["echo", "hello", "world"])
+print client.containers.run("alpine", ["sh", "-c", 'while true; do echo hello world; sleep 1; done'])
~/local/sample $

バックグラウンドで実行し、docker コマンドで確認してみましょう。

~/local/sample $ ./run_container.py > /dev/null &
[1] 3598
~/local/sample $ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS               NAMES
08f51295d34c        alpine              "sh -c 'while true..."   15 seconds ago      Up 14 seconds                           jovial_wescoff
~/local/sample $ docker top 08f51295d34c
PID                 USER                TIME                COMMAND
4452                root                0:00                sh -c while true; do echo hello world; sleep 1; done
4500                root                0:00                sleep 1
~/local/sample $ docker logs 08f51295d34c | tail
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world

確かに、alpine イメージのコンテナが起動され延々と "hello world" が出力されているようです。

Run a container in the background

次に、バックグラウンドでコンテナを起動してみます。

コードの変更点は、以下のとおりです。

~/local/sample $ git diff ^HEAD
diff --git a/run_container.py b/run_container.py
index 7dcbd9d..185d72a 100755
--- a/run_container.py
+++ b/run_container.py
@@ -3,4 +3,5 @@

import docker
client = docker.from_env()
-print client.containers.run("alpine", ["sh", "-c", 'while true; do echo hello world; sleep 1; done'])
+container = client.containers.run("alpine", ["sh", "-c", 'while true; do echo hello world; sleep 1; done'], detach=True)
+print container.id

実行してみる。

~/local/sample $ ./run_container.py 
12f106941293c254064d51d414ad2b446522bb7313b3dc27430898865d729c51
~/local/sample $ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS               NAMES
12f106941293        alpine              "sh -c 'while true..."   3 seconds ago       Up 2 seconds                            clever_tesla

docker run -d で実行した場合と同様、バックグラウンドでコンテナが起動しました。

List and manage containers

次に、起動済みのコンテナ の ID をリストします。

ファイル名は、list_container.py とします。

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import docker
client = docker.from_env()
for container in client.containers.list():
    print container.id

実行してみる

~/local/sample $ ./list_container.py 
12f106941293c254064d51d414ad2b446522bb7313b3dc27430898865d729c51

さすがに少し味気ないですが、 起動済みコンテナの ID が表示されていますね。

Stop all running containers

次は、起動済みのコンテナを全停止します。

ファイル名は、stop_container.py とします。

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import docker
client = docker.from_env()
for container in client.containers.list():
    container.stop()

実行してみる

~/local/sample $ docker run -d -p 8080:80 nginx
4709ed26d564e52e41121c9ba98ebc4de07a395a9c262c4ed7b123ac23803927
~/local/sample $ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                  NAMES
4709ed26d564        nginx               "nginx -g 'daemon ..."   3 seconds ago       Up 2 seconds        0.0.0.0:8080->80/tcp   goofy_bartik
~/local/sample $ ./stop_container.py 
~/local/sample $ docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
~/local/sample $

検証用に起動した、nginx コンテナが stop_container.py の実行により 停止していることが確認できます。

Print the logs of a specific container

次に、コンテナのログを表示します。

先程、作成した list_container.py に少し手を入れます。 以下のコードを実行することにより、全てのコンテナの log が表示されます。

~/local/sample $ git diff ^HEAD
diff --git a/list_container.py b/list_container.py
index 1e51937..eeead74 100755
--- a/list_container.py
+++ b/list_container.py
@@ -4,4 +4,4 @@
import docker
client = docker.from_env()
for container in client.containers.list():
-    print container.id
+    print container.logs()
~/local/sample $

nginx コンテナが起動した状態で、実行してみます。

~/local/sample $ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED              STATUS              PORTS                  NAMES
0988e51e1c74        nginx               "nginx -g 'daemon ..."   About a minute ago   Up About a minute   0.0.0.0:8080->80/tcp   laughing_heisenberg
~/local/sample $ ./list_container.py 
172.17.0.1 - - [15/May/2017:13:35:02 +0000] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36" "-"

docker logs コマンド同様、コンテナのログが表示されました。

List all images

docker images コマンド同様、コンテナイメージをリストします。 ファイル名は、list_images.py とします。

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import docker
client = docker.from_env()
for image in client.images.list():
    print image.id

実行してみる。

~/local/sample $ ./list_images.py 
sha256:02674b9cb179d57c68b526733adf38b458bd31ba0abff0c2bf5ceca5bad72cd9
sha256:3448f27c273f3122fc554d7acf33796efb4df2ad9886efc092c3bfe716e897b7
sha256:6a2f32de169d14e6f8a84538eaa28f2629872d7d4f580a303b296c60db36fbd7
sha256:766ebb052d4f44d2708c5808691644afc0de1263b22cd30464fd85556afb93c3
~/local/sample $ docker images --all --digests | awk '{print $1 ,"\t",$4, "\t", $3}'
REPOSITORY   IMAGE   DIGEST
alpine   02674b9cb179    sha256:c0537ff6a5218ef531ece93d4984efc99bbf3f7497c0a7726c88e2bb7584dc96
nginx    3448f27c273f    sha256:12d30ce421ad530494d588f87b2328ddc3cae666e77ea1ae5ac3a6661e52cde6
ubuntu   6a2f32de169d    sha256:c2bbf50d276508d73dd865cda7b4ee9b5243f2648647d21e3a471dd3cc4209a0
amazonlinux      766ebb052d4f    sha256:7c781c9234e712f135ee402a13ffd5dbf342a9ff1394c73bc5ae4d9b9078e0f8

確かに、イメージID をリストしていますね。

Pull images

次は、イメージを pull します。 ファイル名は、pull_images.py とします。

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import docker
client = docker.from_env()
image = client.images.pull("alpine")
print image.id

実行してみる。

~/local/sample $ docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
nginx               latest              3448f27c273f        5 days ago          109 MB
ubuntu              latest              6a2f32de169d        4 weeks ago         117 MB
amazonlinux         latest              766ebb052d4f        5 weeks ago         162 MB
~/local/sample $ ./pull_images.py 
sha256:02674b9cb179d57c68b526733adf38b458bd31ba0abff0c2bf5ceca5bad72cd9
~/local/sample $ docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
alpine              edge                e020ea09df00        4 days ago          3.97 MB
alpine              3.5                 02674b9cb179        4 days ago          3.99 MB
alpine              latest              02674b9cb179        4 days ago          3.99 MB
alpine              3.4                 016182cd451a        4 days ago          4.81 MB
alpine              3.3                 c8ea6694a9aa        4 days ago          4.81 MB
alpine              3.2                 87ab25c5a2f0        4 days ago          5.26 MB
alpine              3.1                 765e3ac9a905        4 days ago          5.05 MB
nginx               latest              3448f27c273f        5 days ago          109 MB
ubuntu              latest              6a2f32de169d        4 weeks ago         117 MB
amazonlinux         latest              766ebb052d4f        5 weeks ago         162 MB
alpine              2.7                 93f518ec2c41        16 months ago       4.71 MB
alpine              2.6                 e738dfbe7a10        16 months ago       4.5 MB
~/local/sample $

Commit containers

最後に、commit を実行しイメージを作成します。 ファイル名は、commit_containers.py とします。

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import docker
client = docker.from_env()
container = client.containers.run("alpine", ["touch", "/helloworld"], detach=True)
container.wait()
image = container.commit("helloworld")
print image.id

公式ドキュメントのソースコードに不備がありましたが、修正されました。(docker/docker.github.io - Pull requests #3267)

実行してみる

~/local/sample $ ./commit_containers.py 
sha256:ac09116c6e675fded1427d33dccdd43be4ce7276298efa0f6ef983097b7a0a24
~/local/sample $ docker images | grep hello
helloworld          latest              ac09116c6e67        26 seconds ago      3.99 MB
~/local/sample $ docker run helloworld sh -c 'ls -l /helloworld'
-rw-r--r--    1 root     root             0 May 15 14:13 /helloworld

イメージが作成されました。

なお、API の特定バージョンを使用する場合、環境変数 DOCKER_API_VERSION に指定します。 例えば、以下のように Docker API のバージョンを確認し、DOCKER_API_VERSION 環境変数にセットします。

$ docker version
$ export DOCKER_API_VERSION='1.27'

Python SDK の詳細については、以下のドキュメントを参照します。

最後に

Python の学習題材として、Docker SDK for Python を選択するのも ありなんじゃないかなと思いました。

ではでは