mizzsugar’s blog

日々感じていることや学んだことを書きます。エンジニアリング以外にも書くかもしれません。

【Python】Poetryでパッケージ管理 on Docker Container

DockerでPython開発する時、パッケージ管理はpip install -r requirement.txtで行なっていましたが、

requirement.txtのみではパッケージ同士の依存関係まで管理できないことが問題でした。

そこで、Poetryを使ってみることにしました。

github.com

使用技術

- Python 3.7.3
- Docker 19.03.1
- poetry 0.12.17

ディレクトリ構成です。 今回は、Djangoプロジェクトをappというコンテナに、DBをdbというコンテナで管理することにしました。

poetry.lockとpyproject.tomlをどこに入れるか迷いましたが、Pythonのコードを管理しているapp配下に。


環境関連は全てdocker以下に!ということでdocker/appに入れてみたのですが、新しいパッケージを導入したいと思うたびに

appからdockerに移動しないといけないのが面倒だと気づいてしまいました汗

Dockerコンテナに入って開発する際にworkdirがapp以下になるだろうということで、 app以下にこの2つを置いてpoetryの操作をしやすいようにしました。

ディレクトリ構成

├── app
│   ├── poetry.lock
│   ├── project
│   │   ├── config
│   │   │   ├── __init__.py
│   │   │   ├── manage.py
│   │   │   ├── settings
│   │   │   │   ├── __init__.py
│   │   │   │   └── base.py
│   │   │   ├── urls.py
│   │   │   └── wsgi.py
│   │   ├── manage.py
│   │   ├── sample_app
│   │   │   ├── __init__.py
│   │   │   ├── admin.py
│   │   │   ├── apps.py
│   │   │   ├── migrations
│   │   │   │   ├── __init__.py
│   │   │   ├── models.py
│   │   │   ├── urls.py
│   │   │   └── views.py
│   │   └── tests
│   │       └── __init__.py
│   └── pyproject.toml
├── docker
│   ├── app
│   │   ├── Dockerfile
│   │   └── start-server.sh
│   ├── etc
│   │   └── gunicorn.conf
│   ├── db
│   │   └── Dockerfile
│   └── var
│       └── log
│           └── gunicorn
└── docker-compose.yaml


PythonコンテナのDockerfileです。

poetryのインストールのみにとどめ、 poetry installアプリケーションサーバーの立ち上げは 独自にシェルスクリプトを作成して、そちらに実行させることにしました。

Dockerfile

FROM python:latest
ENV PYTHONUNBUFFERED 1
LABEL maintainer "sample_name <hogehoge@example.com>"
RUN pip install --upgrade pip
RUN pip install poetry


シェルスクリプトの中身をみましょう。

Dockerコンテナを立ち上げる際に下記のコマンドが実行されるようにしました。 serverも立ち上がるようにし、コンテナが立ち上がった後にlocalhost:8080にアクセスするとDjangoで作成した画面が見れ流ようにしました。

本番環境と開発環境で別コマンドが実行されるようにします。

#!/bin/bash
cd /home/app

# /home/app下にpoetry.lockとpyproject.tomlがあるのでインストールします。
poetry install
cd project


# poetry run [実行したいコマンド]でpipenvで作成される仮想環境でコマンドを実行します。
if [ "${DJANGO_ENV}" = 'production' ]; then
    # 本番環境
    poetry run python manage.py migrate --settings config.settings
    poetry run python manage.py collectstatic --noinput
    poetry run gunicorn config.wsgi:application -c /home/docker/etc/gunicorn.conf -b :8080
else
 # 開発環境
    poetry run python manage.py migrate
    poetry run python manage.py runserver 0.0.0.0:8000
fi


docker-compose.yaml

version: "3"
services:
  app:
    build:
      context: ./docker/app
      dockerfile: Dockerfile
    env_file: .env
    environment:
      - POSTGRESQL_HOST=db
      - POSTGRESQL_PORT=5432
    volumes:
      - ./app:/home/app
      - ./docker/app:/home/docker
      - ./docker/etc/gunicorn.conf:/etc/gunicorn.conf
      - ./docker/var/log/gunicorn:/var/log/gunicorn
    working_dir: /home/app
    entrypoint: "/bin/sh"
    command: "/home/docker/start-server.sh"
    ports:
      - "8080:8080"
    tty: true
    depends_on:
      - db
  db:
    build:
      context: ./docker/postgres
      dockerfile: Dockerfile
    env_file: .env
    ports:
      - 5432:5432
    volumes:
      - ./docker/db/pgsql-data:/var/lib/postgresql/data


つづいて、操作方法について。

なんかしらPythonの操作したい

まずコンテナに入ります。

docker-compose exec app bash

poetryの仮想環境下で操作する必要があるので、 まずpoetry shellでpoetryが作成する仮想環境に入ってからコマンドを実行

poetry shell

[実行したいコマンド]

またはこちらで。 poetry runを頭につけると、poetryの仮想環境に入った状態でコマンドが実行される動きになります。

poetry run [実行したいコマンド]

新しくパッケージを導入したい

docker-compose exec app bash
# poetryにてインストール
poetry add [パッケージ名]

パッケージのバージョンをあげたい

docker-compose exec app bash
# 全部のパッケージをアップデートしたい時
poetry update

# 特定のパッケージのみアップデートしたい時
poetry update [パッケージ名]


リポジトリはこちら。

github.com


おまけ。Pipenv編リポジトリ

(やることはあまり変わらなかった)

GitHub - mizzsugar/pipenv_on_docker