本ページはプロモーションが含まれています

Docker

DockerでPython環境構築!3つのメリットと手順

トム

・都内自社開発IT企業勤務/javaのバックエンドエンジニア
/java歴10年以上 ・首都圏在住30代
・資格:基本情報技術者/応用情報技術者/Java Silver/Python3エンジニア認定基礎

「自分のPCでは動いたのに、サーバーだと動かない…」

「新しいプロジェクトのたびにPythonのバージョン管理で混乱する」

「チームメンバーと開発環境をそろえるのが面倒」

こんにちは。これまで多くのPythonプロジェクトに携わってきましたが、開発初期の「環境構築」はいつも悩みのタネでした。venvやpyenvを駆使しても、OSの違いやライブラリの依存関係でエラーが起きることは日常茶飯事でした。

しかし、Dockerと出会ってから、私のPython開発は劇的に変わりました。

この記事は、過去の私と同じように「DockerでPython環境を構築したいけれど、何から手をつければいいか分からない」という方に向けて書いています。

この記事を読めば、なぜDockerを使うべきなのか、そして具体的にどうやってPython環境を構築し、開発を進めていくのか、その手順とよくある疑問点まで、網羅的に理解できます。

DockerでPython環境を構築するメリット

Dockerは、コンテナという技術を使ってアプリケーションを動かすためのプラットフォームです。Python開発にDockerを導入すると、開発効率と安定性が飛躍的に向上します。主なメリットを3つ紹介します。

ローカル環境を汚さずに開発できる

Dockerコンテナは、あなたのPCとは隔離された空間です。

Python本体や、pandas Flask といったライブラリはすべてコンテナの中にインストールされます。PC本体には何もインストールしないため、ローカル環境は常にクリーンな状態に保てます。

プロジェクトが終わればコンテナを削除するだけ。PCに不要なファイルが残る心配もありません。

環境差異によるエラーを防げる

開発で最も避けたい「環境差異」の問題を根本から解決できます。

「AさんのWindows PCでは動くのに、BさんのMacでは動かない」

「開発PCでは動いたのに、本番サーバーでエラーが出る」

これらは、OSやPythonのバージョン、ライブラリのわずかな違いが原因で発生します。

DockerではDockerfileという設定ファイルに、「どのOSを使い、どのバージョンのPythonを入れ、どのライブラリをインストールするか」をすべて記述します。

このファイルさえ共有すれば、誰でも、どこでも、まったく同じ環境を100%再現できるのです。

複数プロジェクトの切り替えが簡単

開発者は複数のプロジェクトを同時に担当することも多いです。

  • プロジェクトA:Python 3.8 + Django 3.2
  • プロジェクトB:Python 3.10 + FastAPI 0.88
  • プロジェクトC:Python 3.7 + 古いライブラリ (事情があって更新できない)

従来のvenv (仮想環境) では、これらを切り替えるたびに activatedeactivate を実行する必要があり、非常に手間がかかりました。

Dockerなら、プロジェクトごとにコンテナが独立しています。プロジェクトAのコンテナとプロジェクトBのコンテナを同時に起動することも可能です。環境が互いに干渉しないため、プロジェクトの切り替えがストレスなく行えます。

DockerでPython環境を作るための準備

メリットを理解したところで、早速準備を始めましょう。必要なものは多くありません。

Docker Desktop のインストール

まずはDockerを動かすためのソフトウェア「Docker Desktop」をインストールします。

公式サイトから、お使いのOS (Windows, Mac, Linux) に合わせたインストーラーをダウンロードし、画面の指示に従ってインストールしてください。

インストールが完了したら、ターミナルを開き、docker --version と入力してバージョン情報が表示されれば準備OKです。

Python公式イメージの種類を理解する

Dockerでは「イメージ」と呼ばれるひな形を基にコンテナを作ります。Pythonには幸いなことに公式イメージが用意されています。

ただし、公式イメージにはいくつか種類(タグと呼ばれます)があり、特徴が異なります。

  • python:3.10 (full版)
    • Debianベースの標準的なイメージ。
    • ビルドに必要なライブラリなどが一通り含まれており、多くのPythonパッケージが問題なく動きます。
    • ただし、イメージのサイズは大きめです (約900MB)。
  • python:3.10-slim
    • full 版から不要なファイルを削減した軽量版。
    • イメージサイズが小さい (約120MB) ため、ビルド時間の短縮やディスク容量の節約になります。
    • 開発環境では、まず slim 版を試すのがおすすめです。
  • python:3.10-alpine
    • Alpine Linuxという非常に軽量なOSをベースにしたイメージ。
    • サイズは驚異的に小さい (約50MB) です。
    • ただし、標準のLinux (Debian系) と仕組みが異なる部分があり、特定のPythonライブラリ (pandas など) のインストールでエラーが起きやすい「罠」があります (後述)。

特別な理由がなければ python:3.10-slim (バージョン数字は適宜変更) を選ぶと良いでしょう。

作業ディレクトリの構成例

Dockerを使った開発では、特定のファイル構成がよく用いられます。

PC上にプロジェクト用のフォルダ (例: my_project) を作り、以下のようなファイルを配置するのが一般的です。

my_project/
├── .dockerignore         # Dockerにコピーしないファイルを指定
├── .env                  # 環境変数 (APIキーなど)
├── Dockerfile            # コンテナの設計図
├── docker-compose.yml    # 複数のコンテナを管理する設定
├── requirements.txt      # Pythonライブラリ一覧
└── src/                  # Pythonコード置き場
    └── main.py

Dockerfileを使ったPython環境の作り方

いよいよコンテナの設計図である Dockerfile を書いていきます。

最小構成のDockerfileを書く

Dockerfile は、コンテナをどう作るかを上から順に記述するテキストファイルです。

先ほどの my_project フォルダ直下に、Dockerfile という名前で以下のファイルを作成します。

# 1. ベースにするイメージを指定
FROM python:3.10-slim

# 2. 環境変数を設定 (バッファリング無効化など)
ENV PYTHONUNBUFFERED=1

# 3. コンテナ内の作業ディレクトリを指定
WORKDIR /app

# 4. 必要なファイルをコンテナにコピー
COPY ./requirements.txt /app/requirements.txt

# 5. ライブラリをインストール
RUN pip install -r requirements.txt

# 6. アプリケーションのコードをコピー
COPY ./src /app/src

# 7. コンテナ起動時に実行するコマンド
CMD ["python", "src/main.py"]

このDockerfileは、以下の処理を行います。

  1. python:3.10-slim イメージを土台にします。
  2. Pythonのログがすぐに見られるように設定します。
  3. コンテナ内の /app というフォルダを基準に作業します。
  4. まず requirements.txt だけをコピーします。
  5. ライブラリをインストールします。
  6. src フォルダ以下のPythonコードをコンテナにコピーします。
  7. コンテナが起動したら python src/main.py を実行します。

requirements.txtを使った依存パッケージ管理

requirements.txt は、プロジェクトで使うPythonライブラリとそのバージョンを記載するファイルです。

my_project フォルダ直下に、requirements.txt を作成します。

例えばFlaskを使う場合は、以下のように記述します。

Flask==2.2.2

ローカル環境ですでに開発を進めている場合は、ターミナルで pip freeze > requirements.txt を実行すると、現在インストールされているライブラリ一覧を生成できます。

Dockerfileでは、このファイルを RUN pip install -r requirements.txt コマンドで読み込み、ライブラリをまとめてインストールします。

仮想環境(venv)が不要になる理由

「Dockerを使うとき、コンテナの中で venv を作る必要はありますか?」

これは非常によくある質問です。

結論から言うと、venv は不要です。

venv の目的は、「プロジェクトごとにPythonライブラリの環境を分離すること」でした。

しかし、Dockerコンテナ自体が、OSレベルで隔離された「独立した環境」です。

コンテナAとコンテナBは互いに干渉しません。コンテナAでインストールしたライブラリが、コンテナBに影響することはありません。

Dockerコンテナそのものが、venv よりも強力な仮想環境の役割を果たしているため、コンテナ内でさらに venv を使うのは二重の手間であり、不要なのです。

docker-composeで開発環境を自動化する

Dockerfileはコンテナの「設計図」ですが、実際にビルドして起動するにはターミナルで docker builddocker run といった長いコマンドを打つ必要があります。

docker-compose は、この作業を自動化し、複数のコンテナ (例: Pythonアプリとデータベース) をまとめて管理するためのツールです。

docker-compose.yml の基本構造

docker-compose.yml という設定ファイルに、コンテナの起動設定を記述します。

my_project フォルダ直下に、docker-compose.yml を作成します。

services:
  app:
    build: .
    ports:
      - "8000:8000"
    volumes:
      - ./src:/app/src
    env_file:
      - .env

この設定の意味は以下の通りです。

  • services:: 起動するコンテナ群を定義します。
  • app:: app という名前のサービス (コンテナ) を定義します。
  • build: .: カレントディレクトリにある Dockerfile を使ってビルドします。
  • ports:: PCの8000番ポートと、コンテナの8000番ポートをつなぎます。
  • volumes:: PCの src フォルダと、コンテナの /app/src フォルダを同期します。
  • env_file:: .env ファイルを読み込んで環境変数として使います。

ボリュームでコードをホットリロードする

docker-compose.yml に記述した volumes が、開発効率を劇的に上げる鍵となります。

volumes: ['./src:/app/src']

この設定により、PC (ホスト) の src フォルダと、コンテナ内の /app/src フォルダが「同期」されます。

PC側で src/main.py を編集して保存すると、コンテナを再ビルドしなくても、その変更が即座にコンテナ内のファイルに反映されます。

FlaskやFastAPIの「リロードモード」と組み合わせれば、コードを保存するたびにWebサーバーが自動で再起動し、変更内容をすぐにブラウザで確認できます。

環境変数を.envで管理する方法

データベースのパスワードやAPIキーといった機密情報を、Dockerfiledocker-compose.yml に直接書き込むのは非常に危険です。

これらの情報は .env ファイルに分離して管理するのが定石です。

my_project フォルダ直下に .env ファイルを作成します。

# .env ファイル
API_KEY=abcdefg123456
DATABASE_URL=postgres://user:pass@db:5432/mydb

そして、.gitignore ファイルに .env を追加し、Gitリポジトリに含まれないように設定します。

docker-compose.ymlenv_file: .env 設定により、.env の内容がコンテナ内の環境変数として読み込まれます。Pythonコードからは os.environ.get('API_KEY') のようにして値を取得できます。

PythonアプリをDocker上で実行する方法

docker-compose.yml ができたら、ターミナルで以下のコマンドを実行するだけです。

docker-compose up --build

これで Dockerfile がビルドされ、コンテナが起動します。

Flask/Djangoの開発環境を立ち上げる

FlaskやDjangoのようなWebフレームワークを動かす際は、コンテナ外部からアクセスできるように設定する必要があります。

DockerfileのCMD命令:

CMD で指定する開発サーバーのホストを 0.0.0.0 に設定します。

# Flaskの場合
CMD ["flask", "run", "--host=0.0.0.0", "--port=8000"]

# Djangoの場合
CMD ["python", "manage.py", "runserver", "0.0.0.0:8000"]

127.0.0.1 (localhost) ではなく 0.0.0.0 を指定する理由は、127.0.0.1 がコンテナ内部からのアクセスのみを許可するのに対し、0.0.0.0 はコンテナ外部 (つまり、あなたのPCのブラウザ) からのアクセスを許可するためです。

FastAPI を uvicorn で動かす構成例

FastAPIを uvicorn サーバーで動かす場合も同様です。

開発中は --reload オプションを付けると、前述のボリュームマウントと合わせて最強のホットリロード環境が完成します。

DockerfileのCMD命令:

CMD ["uvicorn", "src.main:app", "--host", "0.0.0.0", "--port", "8000", "--reload"]

src.main:app の部分は、FastAPIのインスタンス ( app ) が src/main.py 内で定義されていることを示します。

ログ出力とエラーハンドリングのポイント

Dockerで動かすアプリケーションのログは、ファイルに書き出すのではなく、標準出力 (STDOUT) または 標準エラー出力 (STDERR) に出すのが原則です。

Pythonの print() 関数や logging モジュール (標準設定) は、標準出力にログを出します。

Dockerはこれらの出力を自動的に収集するため、何か問題が起きたときは docker logs コマンド (または docker-compose logs) で、コンテナが出力したログをすぐに確認できます。

# appサービス (コンテナ) のログを表示する
docker-compose logs app

# ログを監視し続ける (tail -f と同じ)
docker-compose logs -f app

よくあるエラーと対処法

Docker環境構築は、特有の「ハマりどころ」があります。よくあるエラーと対処法を知っておけば、時間を無駄にせずに済みます。

Permission denied が出るとき

コンテナ内でファイルに書き込もうとしたら Permission denied (権限がありません) と怒られることがあります。

これは、コンテナ内ではデフォルトで root (管理者) ユーザーでプロセスが動くのに対し、ホストPC (特にMacやLinux) のファイルは一般ユーザーの所有物であるため、権限のズレが生じるのが原因です。

対処法:

Dockerfile 内で root ではない一般ユーザーを作成し、そのユーザーでプロセスを実行するように USER 命令を追加します。

FROM python:3.10-slim
# ... (中略) ...

# 1. 権限問題を避けるため、一般ユーザー (appuser) を作成
RUN useradd -m -u 1000 appuser

# 2. 作業ディレクトリの所有者を変更
RUN chown -R appuser:appuser /app

# 3. 以降の命令を実行するユーザーを指定
USER appuser

# ... (COPY や CMD) ...

pip install が遅すぎるときの改善

docker build を実行するたびに pip install が走り、ライブラリのダウンロードに時間がかかってイライラすることがあります。

対処法1: Dockerfileの命令順を工夫する (キャッシュの活用)

(詳細は次のセクションで説明します)

対処法2: pipのキャッシュをマウントする (BuildKit)

Dockerの新しいビルド機能 (BuildKit) を使うと、pip のキャッシュをビルド間で共有できます。

RUN 命令を以下のように書き換えます。

# Dockerfile
RUN --mount=type=cache,target=/root/.cache/pip \
    pip install -r requirements.txt

これにより、2回目以降のビルドではキャッシュが使われ、pip install が劇的に速くなります。

コンテナがすぐ落ちるときのデバッグ方法

docker-compose up を実行した直後、コンテナが起動したように見えてすぐに Exited with code 1 (エラーで終了) となり、落ちる場合があります。

これは、CMD で指定したPythonスクリプトが起動時にエラー (文法エラーやインポートエラーなど) を起こしている可能性が高いです。

対処法:

docker-compose logs でエラー内容を確認するのが基本です。

それでも原因が分からない場合は、コンテナに入って中を調査します。

docker-compose.ymlCMD を一時的に「何もしないで待機する」コマンドに変更します。

services:
  app:
    build: .
    # ... (中略) ...
    # CMDを上書きして、コンテナを起動し続ける
    command: tail -f /dev/null

この状態で docker-compose up -d を実行し、コンテナを起動させたままにします。

次に、docker-compose exec コマンドで、起動中のコンテナの内部 (シェル) に入ります。

Bash

# appコンテナに入り、bashを起動する
docker-compose exec app bash

コンテナ内部に入れたら、そこで初めて python src/main.py を手動で実行してみます。

すると、画面に直接エラーメッセージが表示されるため、デバッグが容易になります。

Docker × Python 開発を効率化するTips

基本をマスターしたら、さらに開発を快適にするテクニックも見てみましょう。

キャッシュを活用してビルド時間を短縮する

Dockerは、Dockerfile の各命令 ( FROM, RUN, COPY ) をレイヤーとしてキャッシュします。

ファイルに変更がなければ、前回のキャッシュを使ってビルド時間を短縮します。

この仕組みを最大限に活かすには、変更頻度の低いものを先に実行するのが鉄則です。

悪い例:

COPY . .  # コードもライブラリ一覧も全部コピー
RUN pip install -r requirements.txt

これでは、src/main.py を1行修正しただけでも、COPY が実行され、キャッシュが破棄されます。

その結果、変更がない requirements.txt の pip install も毎回実行されてしまいます。

良い例 (最小構成で示した例):

# 1. 変更頻度の低いライブラリ一覧だけ先にコピー
COPY ./requirements.txt /app/requirements.txt

# 2. ライブラリをインストール (ここがキャッシュされる)
RUN pip install -r requirements.txt

# 3. 変更頻度の高いコードをコピー
COPY ./src /app/src

この順番なら、Pythonコード (src) を変更しても、requirements.txt に変更がなければ pip install はキャッシュが使われ、ビルドが一瞬で終わります。

POETRY・pipenv をコンテナ内で使う方法

requirements.txt の代わりに、Poetrypipenv といったモダンなパッケージ管理ツールを使いたい場合もあるでしょう。

基本的な考え方は同じです。

Dockerfile 内で poetry (または pipenv) をインストールし、ライブラリをインストールします。

FROM python:3.10-slim

# Poetryをインストール
RUN pip install poetry

WORKDIR /app

# 依存ファイルだけ先にコピー
COPY poetry.lock pyproject.toml /app/

# 仮想環境を作らず、システムにインストールする設定
RUN poetry config virtualenvs.create false \
    && poetry install --no-dev --no-interaction --no-ansi

# コードをコピー
COPY . .

CMD ["poetry", "run", "python", "src/main.py"]

VSCode Dev Containers と組み合わせる

Visual Studio Code (VSCode) をお使いの場合、Dev Containers (Remote - Containers) 拡張機能は必須です。

これは、VSCodeの編集画面ごとDockerコンテナの中に入り込んでしまうような機能です。

.devcontainer という設定フォルダを用意するだけで、以下のことが可能になります。

  • PC本体にPythonやVSCode拡張機能を一切インストールする必要がなくなる。
  • Gitリポジトリをクローンして「コンテナで開く」を押すだけで、開発環境が自動構築される。
  • ターミナルもデバッガーも、すべてコンテナ内で完結する。

チーム開発において、全員のVSCode設定まで含めて環境を統一できる、非常に強力な手法です。

DockerでPython環境を構築する際の注意点

最後に、Dockerを使う上で知っておきたい注意点 (罠) を共有します。

Alpineベースの罠(ビルドエラー・musl問題)

イメージサイズが最小の python:3.10-alpine は魅力的ですが、安易に手を出すと痛い目を見ることがあります。

Alpine Linuxは、多くのLinux (Debian, Ubuntu) が使う標準ライブラリ glibc ではなく、musl libc という軽量なライブラリを採用しています。

多くのPythonパッケージ (特に pandas, numpy, scipy など) は、glibc がある前提で高速化されたバイナリ (wheel) が提供されています。

musl 環境ではこのバイナリが使えないため、pip install 時にC言語のソースコードからコンパイル (ビルド) が始まってしまいます。

結果、ビルドに必要なツール (gcc, build-base など) がコンテナにないため、インストールが失敗します。

対処法:

初心者は alpine を避け、slim 版 (Debianベース) を使いましょう。

どうしても alpine を使う必要がある場合は、必要なビルドツールを追加でインストールする必要がありますが、非常に手間がかかります。

コンテナとホストでファイル権限がズレるとき

「よくあるエラー」でも触れましたが、権限問題はDockerでよく遭遇する問題です。

特にLinuxホストでDockerを動かしている場合、コンテナが root 権限で作成したファイル (ログファイルなど) を、ホスト側で編集・削除できなくなることがあります。

DockerfileUSER 命令を使い、一般ユーザーでプロセスを実行する習慣をつけるのが、最も堅実な対策です。

不要なイメージ・ボリュームの掃除方法

Dockerを使っていると、ビルドに失敗した中間イメージや、使わなくなったコンテナ、ボリュームがPCのディスク容量を圧迫していきます。

「DockerのせいでPCの空き容量がなくなった」とならないよう、定期的な掃除が必要です。

  • 停止中のコンテナをすべて削除:docker container prune
  • 使われていない (ぶら下がり) イメージをすべて削除:docker image prune
  • 使われていないボリュームをすべて削除:docker volume prune
  • 上記すべて+ビルドキャッシュも削除 (強力):docker system prune

docker system prune は非常に強力ですが、必要なキャッシュまで消してしまうこともあるため、実行タイミングには注意してください。

まとめ:DockerならPython環境構築が圧倒的に楽になる

Dockerは、現代のPython開発において欠かせないツールです。最初は Dockerfiledocker-compose.yml の書き方に戸惑うかもしれませんが、一度その恩恵を知ると、もうDockerなしの開発には戻れなくなります。

再現性の高い開発環境を作れる

Dockerfileという「環境の設計図」があるおかげで、「誰がやっても」「いつやっても」同じ環境が手に入ります。これは、バグの特定や安定した運用に絶大な効果を発揮します。

チーム開発・学習用でも扱いやすい

新しいメンバーがプロジェクトに参加したとき、以前は環境構築マニュアルを渡して半日かかることもありました。

Dockerなら、Gitリポジトリをクローンして docker-compose up を実行するだけ。わずか数分で開発を開始できます。これはPythonを学習する初学者が、環境構築で挫折するのを防ぐためにも役立ちます。

  • この記事を書いた人
  • 最新記事

トム

・都内自社開発IT企業勤務/javaのバックエンドエンジニア
/java歴10年以上 ・首都圏在住30代
・資格:基本情報技術者/応用情報技術者/Java Silver/Python3エンジニア認定基礎

-Docker