python + vscode + devcontainer で開発したい！

## はじめに
python で開発を行って行くにあたりモジュールやデプロイ先の環境との差異が生じてしまい、いちいち合わせていくのが面倒だったので docker container 上で開発を行えるようにしたいと思いました。
docker container 環境で開発を行うことができればサーバなどにデプロイする際にも楽だと思うので、そのような開発環境を行いたい場合には本記事を参照していただけると幸いです。

## やりたいこと
python + vscode + devcontainer の環境構築をしたい！

## 結論
以下のリポジトリを clone するなり Fork するなりして使ってください。(使い方などは後述)

https://github.com/akin0ri/python3-devcontainer

## 動作確認環境
- windows10
- vscode  (1.86.1)
- docker for windows (4.26.1)
- wsl2

## 使い方
### 前提条件
- `wsl` は `v2` にして `docker` をインストール
- `vscode` に `Dev Containers (Remote Development でも可)` をインストール
- `docker for windows` をインストール

※ wsl1の場合は以下のサイトなどを参照してwsl2にしてください

https://qiita.com/ryamamoto0406/items/d43f19e8821d3e28f1cb

### 手順
1. [github リポジトリ](https://github.com/akin0ri/python3-devcontainer) を `Fork` する
1. `Fork` したリポジトリを wsl上で `clone` する
1. Docker for windows を起動する
1. wsl 上で `code .` を使ってvscodeを立ち上げる
1. 以下の画像の様に Reopen... と出るので押してコンテナの立ち上げをする
1. vscode上でコンテナに接続した状態になるので開発を行ってください！


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/543125/754e3167-90c7-fcc7-aada-bb900c6b6daa.png)

## 仕組み

### `.devcontainer/Dockerfile`
``` Dockerfile:.devcontainer/Dockerfile
# select python image
FROM python:3.10

# Add non-root user
ARG USERNAME=vscode
ARG USER_UID=1000
ARG USER_GID=$USER_UID

RUN groupadd --gid $USER_GID $USERNAME \
    && useradd -s /bin/bash --uid $USER_UID --gid $USER_GID -m $USERNAME \
    && apt-get update \
    && apt-get install -y sudo \
    && echo $USERNAME ALL=\(root\) NOPASSWD:ALL > /etc/sudoers.d/$USERNAME\
    && chmod 0440 /etc/sudoers.d/$USERNAME \
    && apt-get clean

# Update package lists
RUN apt-get update && \
    apt-get -y upgrade && \
    apt-get -y install --no-install-recommends \
        curl \
        git \
        vim \
        less \
        gcc && \
    apt-get clean && \
    rm -rf /var/lib/apt/lists/*

# setup git branch in console
RUN echo "source /usr/share/bash-completion/completions/git" >> /home/${USERNAME}/.bashrc

WORKDIR /usr/share/bash-completion/completions

RUN curl -O https://raw.githubusercontent.com/git/git/master/contrib/completion/git-prompt.sh
RUN curl -O https://raw.githubusercontent.com/git/git/master/contrib/completion/git-completion.bash

RUN chmod a+x git*.*

RUN ls -l $PWD/git*.* | awk '{print "source "$9}' >> /home/${USERNAME}/.bashrc

RUN echo "GIT_PS1_SHOWUNTRACKEDFILES=true" >> /home/${USERNAME}/.bashrc
RUN echo 'export PS1="\[\033[01;32m\]\u@\h\[\033[01;33m\] \w \[\033[01;31m\]\$(__git_ps1 \"(%s)\") \\n\[\033[01;34m\]\\$ \[\033[00m\]"' >> /home/${USERNAME}/.bashrc

# Set the working directory in the container
WORKDIR /workspace

# Copy requirements file
COPY requirements.txt requirements.txt

# Install any needed packages specified in requirements.txt
RUN pip install --no-cache-dir --upgrade pip && \
    pip install --no-cache-dir -r requirements.txt

# Run any command to initialize the container
CMD ["bash"]
```

Dockerfile に関して少し解説します

- `FROM python:3.10` : docker hub から持ってくるコンテナの tag を指定しています
- `ARG USERNAME=vscode` : vscode でコンテナに接続するため、root ユーザとは別に別のユーザを作成する必要があります(名前は何でも可)
- `RUN apt-get update && ...` : コンテナ自体のapt update & upgrade を行っています。また、`curl` や `git` などの必要なモジュールもインストールしています
- `# setup git branch in console ...` : この部分では以下の様に `vscode` のターミナル上に現在利用している `git branch` を表示する設定を行っています(扶養であれば `RUN echo 'export PS1="\[\033[0 ...` の行まで削除してください)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/543125/c20813ac-c345-ffb4-8bab-4d8f98d35efd.png)

- `WORKDIR /workspace` : コンテナ内で作業する際のディレクトリ指定を行っています(指定した名前のディレクトリがない場合には新規作成してくれます)
- `COPY requirements.txt requirements.txt` : コンテナ内に `requirements.txt` というテキストファイルをコピーしています。後述しますが、このファイル内には開発に必要な python モジュールが含まれていて、これを元にコンテナ内へ python モジュールをインストールします
- `RUN pip install --no-cache-dir ...` : コンテナ内の `pip upgrade` と前述した `requirements.txt` 内のモジュールインストールを行っています

### .devcontainer/docker-compose.yml
``` Dockerfile:docker-compose.yml
version: '3'

services:
  # sync devcontainer.json 'service'
  python3:
    # original container naame
    container_name: python3.10-development
    build:
      context: .
      dockerfile: Dockerfile
    tty: true
    # working dir
    working_dir: /workspace
    # setting volume (host:container)
    volumes:
      - ..:/workspace
```
docker-composeファイルは、複数のコンテナを管理するための内容を記述するファイルです。
今回は、立ち上げるコンテナが1つしかないのでDockerfileのみで十分なのですが、今後、複数のコンテナを利用する可能性を考慮して作成しました。
基本的には先ほどの `Dockerfile` を用いてコンテナを立ち上げる処理が記述されていて、`volumes` という項目内でホストとコンテナでストレージのマウントを行う場所の指定を行っています。

### .devcontainer/requirements.txt
ex.)
``` text:.devcontainer/requirements.txt
Flask==2.3.3
python-dotenv==1.0.0
line-bot-sdk==3.9.0
```
github上では記述されていませんが例として記述しました。上記のように必要なモジュールとバージョンを指定することによってコンテナが立ち上がると同時にモジュールのインストールも行ってくれます。

:::note info
バージョンの指定を行わない場合、最新のバージョンがインストールされます。
バージョンによって動作が若干異なる場合もあるのでバージョンを指定することをおすすめします。
:::

### .devcontainer/devcontainer.json
``` json:devcontainer.json
{
  "name": "Python Development",
  "dockerComposeFile": "docker-compose.yml",
  "workspaceFolder": "/workspace",
  "remoteUser": "vscode",
  "service": "python3",
  "customizations": {
    "vscode": {
      "settings": {
        "terminal.integrated.shell.linux": "/bin/bash"
      },
      "extensions": [
        "ms-python.python",
        "ms-python.vscode-pylance",
        "ms-toolsai.jupyter",
        "ms-azuretools.vscode-docker",
        "mhutchie.git-graph",
        "codezombiech.gitignore",
        "eamodio.gitlens"
      ]
    }
  }
}
```
`devcontainer.json` ファイル内では vscode 上でコンテナを立ち上げ、接続する設定を行っています。
- `dockerComposeFile` : 作成したdocker-composeファイルを指定します
- `workspaceFolder` : Dockerfileなどで指定した作業ディレクトリを選択します
- `remoteUser` : Dockerfile で作成したユーザ名を指定します
- `extensions` : vscode で開発を行う際に必要な vscode の拡張機能を追加することができます。(不要な拡張機能があれば削除してしまってください)

## おわりに
今回は `python + vscode + devcontainer` で開発環境を構築するための Dockerfile などを作成しました。
github 上で公開しているのでご自身の環境に合わせてカスタマイズして、ご自由にお使いください。
誤りや不明点がある際にはコメントいただけるとありがたいです。