Dockerでのpythonモジュールの管理

背景

前回pythonのモジュール管理をRubyと比較しながら学びました。pythonにはvenvというモジュールでプロジェクトごとにモジュールを分離できるということを学びました。

しかし、ローカルPCではなくDockerを使う場合はそもそもモジュールの分離を検討しなくてもよいのではないか?と思ったので、Dockerでのモジュール管理について考えていきたいと思います。

現在のDockerfile

以前利用していたDockerfileはこんな感じでした

1
2
3
4
5
6
7
8
FROM python:3.9.5-alpine
ENV PYTHONUNBUFFERED 1
RUN apk update && apk add mysql-client mysql-dev gcc libc-dev
RUN mkdir /code
WORKDIR /code
ADD requirements.txt /code/
RUN pip install -r requirements.txt
ADD . /code/

モジュールのインストールに関しては7行目の

RUN pip install -r requirements.txt

で行なっています。

requirements.txtは

1
2
Django==3.2.4
mysqlclient

でした。イメージのビルド時にDjango3.2.4とmysqlclientとそれに依存したパッケージがインストールされます。

インストールされたパッケージの確認

現在インストールされているパッケージの確認を行います。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
$ docker run -it image_name /bin/sh
/code #
/code # which pip
/usr/local/bin/pip
/code # pip list
Package Version
----------- -------
asgiref 3.3.4
Django 3.2.4
mysqlclient 2.0.3
pip 21.1.2
pytz 2021.1
setuptools 57.0.0
sqlparse 0.4.1
wheel 0.36.2
WARNING: You are using pip version 21.1.2; however, version 21.1.3 is available.
You should consider upgrading via the '/usr/local/bin/python -m pip install --upgrade pip' command.

指定したのはDjangoとmysqlclientのみでしたが、依存関係でその他のパッケージがいくつかインストールされていることがわかります。

現在のdocker-compose.yml

現在のdocker-compose.ymlは以下のようになっています。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
version: '3'

services:
db:
image: mysql:5.7
environment:
MYSQL_ROOT_PASSWORD: root
MYSQL_USER: django
MYSQL_PASSWORD: django
MYSQL_DATABASE: django
ports:
- 33060:3306
volumes:
- mysql:/var/lib/mysql
web:
build: .
command: python3 manage.py runserver 0.0.0.0:8000
volumes:
- .:/code
ports:
- "8000:8000"
links:
- db

volumes:
mysql:
driver: local

volumesはmysqlのストレージをDocker内に持っているのみです。

モジュールのインストール、アップデート時の動作

なんとなく予想できますが、モジュールのインストール、アップデートを試してみます。

モジュールのインストール

モジュールのインストールを行なってみます。今回はhttpクライアントライブラリのRequestsをインストールしてみます。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
$ docker-compose run --rm web python -m pip install requests
Creating django_web_run ... done
Collecting requests
Downloading requests-2.26.0-py2.py3-none-any.whl (62 kB)
|████████████████████████████████| 62 kB 741 kB/s
Collecting idna<4,>=2.5
Downloading idna-3.2-py3-none-any.whl (59 kB)
|████████████████████████████████| 59 kB 2.6 MB/s
Collecting certifi>=2017.4.17
Downloading certifi-2021.5.30-py2.py3-none-any.whl (145 kB)
|████████████████████████████████| 145 kB 7.9 MB/s
Collecting urllib3<1.27,>=1.21.1
Downloading urllib3-1.26.6-py2.py3-none-any.whl (138 kB)
|████████████████████████████████| 138 kB 7.0 MB/s
Collecting charset-normalizer~=2.0.0
Downloading charset_normalizer-2.0.3-py3-none-any.whl (35 kB)
Installing collected packages: urllib3, idna, charset-normalizer, certifi, requests
Successfully installed certifi-2021.5.30 charset-normalizer-2.0.3 idna-3.2 requests-2.26.0 urllib3-1.26.6
WARNING: Running pip as root will break packages and permissions. You should install packages reliably by using venv: https://pip.pypa.io/warnings/venv
WARNING: You are using pip version 21.1.2; however, version 21.1.3 is available.
You should consider upgrading via the '/usr/local/bin/python -m pip install --upgrade pip' command.

警告が出ていますが、無事インストールできたようです。ではpip listで一覧を表示してみましょう。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
$ docker-compose run --rm web pip list
Creating django_web_run ... done
Package Version
----------- -------
asgiref 3.3.4
Django 3.2.4
mysqlclient 2.0.3
pip 21.1.2
pytz 2021.1
setuptools 57.0.0
sqlparse 0.4.1
wheel 0.36.2
WARNING: You are using pip version 21.1.2; however, version 21.1.3 is available.
You should consider upgrading via the '/usr/local/bin/python -m pip install --upgrade pip' command.

インストールしたパッケージは消えてなくなっています。

モジュールのアップデート

結果はなんとなくわかりますが、警告が出ていたpipをアップデートしてみます。

1
2
3
4
5
6
7
8
9
10
11
12
13
$ docker-compose run --rm web python -m pip install --upgrade pip
Creating django_web_run ... done
Requirement already satisfied: pip in /usr/local/lib/python3.9/site-packages (21.1.2)
Collecting pip
Downloading pip-21.1.3-py3-none-any.whl (1.5 MB)
|████████████████████████████████| 1.5 MB 5.9 MB/s
Installing collected packages: pip
Attempting uninstall: pip
Found existing installation: pip 21.1.2
Uninstalling pip-21.1.2:
Successfully uninstalled pip-21.1.2
Successfully installed pip-21.1.3
WARNING: Running pip as root will break packages and permissions. You should install packages reliably by using venv: https://pip.pypa.io/warnings/venv

無事21.1.3にアップデートされたように見えます。

pip listで確認します。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
$ docker-compose run --rm web python -m pip list
Creating django_web_run ... done
Package Version
----------- -------
asgiref 3.3.4
Django 3.2.4
mysqlclient 2.0.3
pip 21.1.2
pytz 2021.1
setuptools 57.0.0
sqlparse 0.4.1
wheel 0.36.2
WARNING: You are using pip version 21.1.2; however, version 21.1.3 is available.
You should consider upgrading via the '/usr/local/bin/python -m pip install --upgrade pip' command.

予想通り21.1.2に戻っています。

Docker Volumeの利用

モジュールのインストール、アップデートを行なったところで、保存しておくストレージがないため、コンテナを停止すると次回起動時はイメージをビルドした時の状態になっています。

その対応としてDocker Volumeを利用します。

モジュールインストールディレクトリの確認

まずはじめにモジュールがどこにインストールされているかを確認します。

モジュールのインストール先を確認するにはpip showコマンドを利用します。Djangoのパッケージがどこにインストールされているのかをみてみます。

1
2
3
4
5
6
7
8
9
10
11
12
$ docker-compose run --rm web pip show django
Creating django_web_run ... done
Name: Django
Version: 3.2.4
Summary: A high-level Python Web framework that encourages rapid development and clean, pragmatic design.
Home-page: https://www.djangoproject.com/
Author: Django Software Foundation
Author-email: foundation@djangoproject.com
License: BSD-3-Clause
Location: /usr/local/lib/python3.9/site-packages
Requires: asgiref, pytz, sqlparse
Required-by:

Locationにインストールディレクトリが表示されています。その他依存関係なども表示されていて便利ですね!

念のため別のパッケージでも試してみます。

1
2
3
4
5
6
7
8
9
10
11
12
$ docker-compose run --rm web pip show mysqlclient
Creating django_web_run ... done
Name: mysqlclient
Version: 2.0.3
Summary: Python interface to MySQL
Home-page: https://github.com/PyMySQL/mysqlclient
Author: Inada Naoki
Author-email: songofacandy@gmail.com
License: GPL
Location: /usr/local/lib/python3.9/site-packages
Requires:
Required-by:

Djangoと同じパスでした。ということはこのディレクトリにボリュームを割り当てれば良さそうです。

Volumeを利用するようdocker-compose.ymlを変更

/usr/local/lib/python3.9/site-packagesにvolumeを割り当ててみます。

docker-compose.ymlのwebの箇所

1
2
3
4
5
6
7
8
9
web:
build: .
command: python3 manage.py runserver 0.0.0.0:8000
volumes:
- .:/code
ports:
- "8000:8000"
links:
- db

1
2
3
4
5
6
7
8
9
10
web:
build: .
command: python3 manage.py runserver 0.0.0.0:8000
volumes:
- .:/code
- site-packages:/usr/local/lib/python3.9/site-packages
ports:
- "8000:8000"
links:
- db

とし、volumeにも追加します

1
2
3
4
5
volumes:
mysql:
driver: local
site-packages:
driver: local

この設定で試してみます。

動作確認

さきほどと同様にpip listから始めます

1
2
3
4
5
6
7
8
9
10
11
12
13
14
$ docker-compose run --rm web python -m pip list
Creating django_web_run ... done
Package Version
----------- -------
asgiref 3.3.4
Django 3.2.4
mysqlclient 2.0.3
pip 21.1.2
pytz 2021.1
setuptools 57.0.0
sqlparse 0.4.1
wheel 0.36.2
WARNING: You are using pip version 21.1.2; however, version 21.1.3 is available.
You should consider upgrading via the '/usr/local/bin/python -m pip install --upgrade pip' command.

pipをアップデートしてみます。

1
2
3
4
5
6
7
8
9
10
11
12
13
$ docker-compose run --rm web python -m pip install --upgrade pip
Creating django_web_run ... done
Requirement already satisfied: pip in /usr/local/lib/python3.9/site-packages (21.1.2)
Collecting pip
Downloading pip-21.1.3-py3-none-any.whl (1.5 MB)
|████████████████████████████████| 1.5 MB 3.3 MB/s
Installing collected packages: pip
Attempting uninstall: pip
Found existing installation: pip 21.1.2
Uninstalling pip-21.1.2:
Successfully uninstalled pip-21.1.2
Successfully installed pip-21.1.3
WARNING: Running pip as root will break packages and permissions. You should install packages reliably by using venv: https://pip.pypa.io/warnings/venv

無事できました。

pip listでアップデートされたままかどうか確認します。

1
2
3
4
5
6
7
8
9
10
11
12
$ docker-compose run --rm web python -m pip list
Creating django_web_run ... done
Package Version
----------- -------
asgiref 3.3.4
Django 3.2.4
mysqlclient 2.0.3
pip 21.1.3
pytz 2021.1
setuptools 57.0.0
sqlparse 0.4.1
wheel 0.36.2

アップデートされたままになっていました!無事volumeが利用できています!

まとめ

Dockerを利用する場合、パッケージのインストールディレクトリはvolumeを利用しないと変更が保存されないので、volumeを利用します。

開発の途中でパッケージのインストールが必要になった場合はインストールし、pip freezerequirements.txtを更新し、コミットします。

他のメンバーはそれをチェックアウトして、pip install -r requirements.txtを行います。

このフローで開発を回していくことができるようになりました。

次回は、今回よく表示されていた警告

1
WARNING: Running pip as root will break packages and permissions. You should install packages reliably by using venv: https://pip.pypa.io/warnings/venv

について調べてみようと思います。rootで実行するのはパーミッションを壊してしまうのでよくないということだと思いますが、venvとの関連がいまいちわかっていません…前回venvについて調べておいてよかったですが、次回はこの問題を解決していこうと思います。