🐳

Dockerコンテナ内でDjangoの開発をする

に公開

経緯

Pythonの開発環境では、venvやpyenvやらで仮想環境を作り、パッケージをプロジェクトごとに分けて開発します。
しかし、これでは問題がありました。

  1. VScodeの拡張機能を動かすためにコンテナ内部とホストOS側の両方でPythonのパッケージをインストールしなければいけない
  2. aptはほかのプロジェクトと全部共通になってしまう
  3. venvやpyenvのインストールや管理が大変(個人の感想です)

じゃあ、どうせ動かしているし、Dockerコンテナ内で開発しちゃおうと思ったわけです。

ただし、これがいいやり方かといわれると自身はありません。

前半はuvでのDjangoプロジェクトの立ち上げの記事ですので、わかる人はコンテナ内で開発するときに発生する問題とその解決方法から読んでください。

要件

環境

  1. Windows 11
  2. Docker Desktop
  3. WSL

今回の目標

Djangoのサーバーを立ち上げ、ロケットを飛ばす

Dockerコンテナを立ち上げる

今回はパッケージを管理するためにuvを使います。

Pythonパッケージをインストール

以下のDockerfileを作業ディレクトリに作成します。

Dockerfile
FROM python:3.13-slim

ENV PYTHONUNBUFFERED=1
# uvをインストール
COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/

# uvで仮想環境を作らない設定
ENV UV_PROJECT_ENVIRONMENT=/usr/local

RUN apt-get update && apt-get install -y \
    # Pythonイメージではlessなどがなく、作業がしにくいので入れる(なくても動く)
    less \
    vim \
    && apt-get clean \
    && rm -rf /var/lib/apt/lists/*

# コードをコンテナ内に移動
WORKDIR /apps
COPY . /apps

※uvはpipでインストールすることもできますが、pipを使わないという一貫性がなくなってしまうため、このようにインストールしています。

まずはbuildします。

docker build . -t django-dev

次にuvの初期化コマンドをたたき、pyproject.tomlファイルを作ります。

 docker run -v .:/apps --rm django-dev uv init --app .
  • django-dev:buildの時に指定したイメージ名
  • -v .:/apps:これがないとコンテナ内の変更がホストOS側に反映されない
  • --rm:runをすると動き終わったコンテナが大量にごみとして出るので実行後に削除するためのオプション
  • --app:今回の例ではアプリケーションとして作成(任意)
  • .:最後のドットは平たく言うと、pyproject.tomlを今のディレクトリに作成するというオプション

結果は以下のようになります。

$ ls -a
. .. .python-version Dockerfile  README.md  main.py  pyproject.toml

Djangoをはじめとするパッケージをインストールしていきます。

docker run -v .:/apps --rm django-dev uv add django

ロケットを飛ばす(Djangoの設定)

Djangoのプロジェクトを作成します。

docker run -v .:/apps --rm django-dev uv run django-admin startproject django_dev .

今回のプロジェクト名はdjango_devです。Djangoのプロジェクト名には「-」が使えないので注意してください。
最後の「.」はmanage.py.(現在のディレクトリ)に置きます。というオプションです。

uv initで作成されたmain.pyはいらないので消してしまいましょう。

rm main.py

DockerfileにDjangoの設定を追加していきます。

Dockerfile
FROM python:3.13-slim

ENV PYTHONUNBUFFERED=1
# uvをインストール
COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/

# uvで仮想環境を作らない設定
ENV UV_PROJECT_ENVIRONMENT=/usr/local

RUN apt-get update && apt-get install -y \
    # Pythonイメージではlessなどがなく、作業がしにくいので入れる(なくても動く)
    less \
    vim \
    && apt-get clean \
    && rm -rf /var/lib/apt/lists/*

# コードをコンテナ内に移動
WORKDIR /apps
COPY . /apps
+
+ # 依存関係をインストール
+ RUN uv sync --frozen
+
+ # アプリケーションを実行
+ CMD ["uv", "run", "python", "manage.py", "runserver", "0.0.0.0:8000"]

いよいよDockerコンテナを動かします。
Dockerfileを更新したのでbuildをし直しましょう。

docker build . -t django-dev

その後にコンテナを立ち上げます。

docker run --rm -v .:/apps -p 8000:8000 django-dev

おめでとうございます。ロケットが飛びました。

コンテナ内で開発する

開発にはVSCodeを使います。

コンテナ内部に入る

初めにDockerコンテナの拡張機能を入れましょう。

下の画像のようにCONTAINERSからdjango-devを探し、右クリックをして項目を開きます。
Visual Studio Codeをアタッチするを選択します。


※画像ではCtrl+'が割り当てられていますが、これは私が割り当てたものです。

その後、一番上にこのようなセレクタが出てくるのでdjango-devを選択します。

新しくVSCodeが立ち上がります。これはすでにコンテナの中です。

後は、「フォルダーを開く」から/appsを選択して作業してください。
また、VSCodeのターミナルからコマンドを打つことができます。
例えば、python manage.py --helpなどのように普通にpythonのコマンドが使えます。
これで最低限の環境は整いましたが、何個か問題があります。

コンテナ内で開発するときに発生する問題とその解決方法

Gitを使おうとすると問題が出てきますのでその解消方法を示したいと思います。

まずはgitをDockerfileに追加してbuildし直してください。

Dockerfile
...

RUN apt-get update && apt-get install -y \
    less \
    vim \
+     # GitHub
+     git \
+     ssh \
    && apt-get clean \
    && rm -rf /var/lib/apt/lists/*

# プロジェクトをコピー
WORKDIR /apps
COPY . /apps

+ # gitの設定
+ RUN git config --global --add safe.directory /apps

# 依存関係をインストール
RUN uv sync --frozen

...

git commitで日本語が入力できない

コンテナ内
git commit -m '初期化'

とやろうとすると日本語が表示されません。
これはaptでパッケージを入れて、環境変数を設定すると解決できます。

Dockerfile
RUN apt-get update && apt-get install -y \
    less \
    vim \
+     # 日本語対応
+     locales \
+     locales-all \
    # GitHub
    git \
    ssh \
    && apt-get clean \
    && rm -rf /var/lib/apt/lists/*

+ # 日本語の設定
+ RUN locale-gen ja_JP.UTF-8
+ ENV LANG=ja_JP.UTF-8

buildし直してください。
これでコミットメッセージに日本語が使えるようになりました。

git pullなどGitHubへつなげられない

コンテナ内
# git pull
git@github.com: Permission denied (publickey).
fatal: Could not read from remote repository.

Please make sure you have the correct access rights
and the repository exists.

GitHubへのSSHをしてpullなどをしているのですが、GitHub側からはこれが誰かわからないわけです。
これをHostOSと同じ設定でpullをしたいと思うわけです。
そこでssh-agentを使います。

ホストOS
# ssh-agentを起動する
eval "$(ssh-agent -s)"

# 秘密鍵を追加
ssh-add ~/.ssh/id_ed25519

そして、Volumeで鍵情報をホストOSと共有するようにしましょう。
これにより、ホストOS側のSSH認証情報をそのままコンテナで利用できるようになります。

ホストOS
docker run --rm -v .:/apps -v ${SSH_AUTH_SOCK}:/ssh-agent -v ${HOME}/.gitconfig:/root/.gitconfig:ro -e SSH_AUTH_SOCK=/ssh-agent -p 8000:8000 django-dev

これでコンテナ内でgit pullができるようになります。

コンテナ内で開発するときの注意

コンテナ内ではroot権限になる

特に設定をしていない場合はコンテナ内部にいるときはrootになりますので、コンテナ内部でファイルを作成するとホストOS(WSL上)では編集できない場合があります。また、権限がないとホストOS側でgit addなどもできません。
なので、ファイルの操作をするときはコンテナ内部に入るか、

ホストOS
docker run -v .:/apps --rm django-dev git add .

のようにdocker runを使ってコンテナ内部で行うようにしましょう。

まとめ

最終的なDockerfileは以下のようになりました。

Dockerfile
FROM python:3.13-slim

ENV PYTHONUNBUFFERED=1
# uvをインストール
COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/

# uvで仮想環境を作らない設定
ENV UV_PROJECT_ENVIRONMENT=/usr/local

RUN apt-get update && apt-get install -y \
    less \
    vim \
    # 日本語対応
    locales \
    locales-all \
    # GitHub
    git \
    ssh \
    && apt-get clean \
    && rm -rf /var/lib/apt/lists/*

# 日本語の設定
RUN locale-gen ja_JP.UTF-8
ENV LANG=ja_JP.UTF-8

# プロジェクトをコピー
WORKDIR /apps
COPY . /apps

# gitの設定
RUN git config --global --add safe.directory /apps

# 依存関係をインストール
RUN uv sync --frozen

# アプリケーションを実行
CMD ["uv", "run", "python", "manage.py", "runserver", "0.0.0.0:8000"]

そして、一日の初めに

ホストOS
eval "$(ssh-agent -s)"
ssh-add ~/.ssh/id_ed25519

を打ち、コンテナを起動するときは

ホストOS
docker run --rm -v .:/apps -v ${SSH_AUTH_SOCK}:/ssh-agent -v ${HOME}/.gitconfig:/root/.gitconfig:ro -e SSH_AUTH_SOCK=/ssh-agent -p 8000:8000 django-dev

を使います。

これでコンテナ内での開発ができるようになりました。

毎日たたくコマンドをシェルスクリプトにまとめたり、docker-compose.ymlを使ったりとまだまだ改善できるところはたくさんあると思います。記事を読んだ人が理想の開発環境づくりの手助けになれたら幸いです。

Discussion