Dev Containerについて基礎を学習する

Azureで動作するPythonアプリを開発するにあたって、Web AppsはPython 3.12までサポートしているが、Azure FunctionsはPython 3.11までしかサポートしていなかった。メンバーから3.11で統一して開発したいといわれたが、仮想化を使えばなんかもっとよくできるんじゃないかと思いつつ具体的な案を出せず悔しい思いをしたので、以前から気になっていたDev Containerを調査してみる。

# 環境構築
まずは何はともあれGetting Startedの動画を見る。

https://www.youtube.com/watch?v=b1RavPr_878

Dev Containerを解説している動画に「IT業界に35年いるが、これはまるで魔法のようだ」というコメントがあったが、魔法を使うには魔法の杖の振り方を学ばなくてはならない。環境構築を簡単にするためにはその環境構築が必要ということで。Docker DesktopとWSLだけインストールしてやったら「stream is closed」というエラーになった。

こちらに近いようだが、手間取ったのでまとめる。

https://pancokeiba.hatenablog.com/entry/2024/08/19/232336


## ローカル環境設定
以下を諸々インストール。
- VSCode
- Devc Container Extension
- WSL
- Docker Desktop

### WSL
WSLの基本的な使い方はこちら。

https://www.tohoho-web.com/ex/wsl.html

WSLからUbuntuのDistroをインストール

https://zenn.dev/minato86/scraps/6d12fb526f6648

Ubuntuを規定にしておく。
```
PS C:\Work\Python\DevContainer\vscode-remote-try-python> wsl -l
Linux 用 Windows サブシステム ディストリビューション:
Ubuntu (既定)
docker-desktop
```

### Docker Desktop
Docker Desktopの設定から、WSLのUbuntuと統合を使うように設定。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/654538/ec8c694e-77b4-61c9-a51b-b989eec04882.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/654538/dcc26614-56f2-fe68-56e9-81bf2172d39f.png)

### VSCodeの設定
VSCodeの設定でDevcontainerで検索して、以下の項目をこうする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/654538/a215fc5d-f5ce-5294-532c-de75ac0fb595.png)


# Devcontainerを設定

Microsoft LearnのModuleがあったので、これに沿って進めていく。

https://learn.microsoft.com/ja-jp/training/modules/use-docker-container-dev-env-vs-code/

こちらもわかりやすくまとまっていたので、参考にさせていただきました。

https://qiita.com/im-dev/items/a2eb4ebba6b6df1e0521


Moduleでは、既存のプロジェクトに対してDev Containerを設定していく形で進めているが、新規で作る場合もそんなに変わらない。まずはプロジェクトをgit clone。新規で開発する場合は空のフォルダを開いた状態で始める。

Add Dev Container Configuration Files。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/654538/ecc13ed5-ec02-1368-474c-a38474fbe4b5.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/654538/35b1ada4-bbc5-f07c-eb60-b144a05e12c9.png)
このTemplateはかなり幅広く、Python＋PostgreSQL、.Net＋Azure SQL、Azure Functionsなどもある。Azure FunctionsをDev Containerで開発する用のイメージもあり、しばやんさんが作ってくれたポイ。

https://blog.shibayan.jp/entry/20210628/1624845958

Pythonイメージはこちらに詳細があった。

https://github.com/devcontainers/images/tree/main/src/python

Pythonのバージョンを選ぶ。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/654538/04537050-ab4d-dade-56b5-5cc79546af25.png)

.devcontainerのフォルダができた。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/654538/2514dd3d-7163-9a98-6b39-f067602006d1.png)

devcontainer.jsonでベースコンテナイメージ、コンテナ作成後のコマンド実行、Dev Container内のVSCodeを開いた時の拡張機能等を設定できる。

```devcontainer.json
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
// README at: https://github.com/devcontainers/templates/tree/main/src/python
{
	"name": "Python 3",
	// Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile
	"image": "mcr.microsoft.com/devcontainers/python:1-3.12-bullseye"

	// Features to add to the dev container. More info: https://containers.dev/features.
	// "features": {},

	// Use 'forwardPorts' to make a list of ports inside the container available locally.
	// "forwardPorts": [],

	// Use 'postCreateCommand' to run commands after the container is created.
	// "postCreateCommand": "pip3 install --user -r requirements.txt",

	// Configure tool-specific properties.
	// "customizations": {},

	// Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
	// "remoteUser": "root"
}
```

Reopen in containerでコンテナを起動する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/654538/33cdf505-48cf-1166-2a84-f1a4d8abcd4b.png)

ちなみに最近はGithubのリポジトリでも.devcontainerフォルダを見かけることが多くなったが、そういうプロジェクトは基本的にGit cloneした後にReopenすれば環境を気にすることなくコンテナ上で開くことができる。その際に諸々の依存関係はLocalではなくDev Container上にインストールされるので、ローカルの環境を汚すこともない。

左下がDev Containerになり、コンテナ内で起動できていることがわかる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/654538/f7fc4a53-664a-30da-7057-15f4981594ed.png)

Dev ContainerをVSCodeから開いた状態では、VSCodeの拡張機能も別にインストールする必要がある。確かに考えてみれば、Python開発とC#開発で必要な拡張機能を全部入れてしまったせいで、ローカルのVSCodeの起動が遅くなってしまうような問題がある。Dev Containerを使えば、これは●●開発専用という環境が手に入る。ローカルでインストールされている拡張機能は右クリックからAdd to devcontainer.jsonでDev Container側にもインストールできる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/654538/897bd70a-3820-fecb-84f9-339001a5001c.png)
、、、はずなのだが、なんかうまく反映されないときがあった。その場合は右にあるIdentifierをdevcontaier.jsonにペーストするといい。
```devcontainer.json
"customizations": {
    "vscode": {
        "extensions": [
            "wholroyd.jinja",
        ]
    }
},
```

その他Dev Containerにツールを入れたい場合はFeature機能が便利。Azure CLIやNodeなども入れることができる。
```	devcontainer.json
// Features to add to the dev container. More info: https://containers.dev/features.
"features": {
    "ghcr.io/devcontainers/features/azure-cli:1": {},
    "ghcr.io/devcontainers/features/node:1": {
        "version": "18"
    }
},
```

devcontainer.jsonを更新したら、それを反映させるために最後にRebuildを実行。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/654538/4a065539-bdcc-92d4-dcb3-0ecf118408cb.png)

Jupyterを使用するPyhon環境は一旦こんな感じになりました。
```devcontainer.json
{
  "name": "Python 3",

  "image": "mcr.microsoft.com/devcontainers/python:1-3.12-bullseye",

  "runArgs": ["--env-file", ".env"],

  "features": {
    "ghcr.io/devcontainers/features/python:1": {
      "installTools": true,
      "installJupyterlab": true,
      "version": "latest"
    }
  },

  "mounts": [
    "source=vscode-extensions,target=/vscode/.vscode-server/extensions,type=volume",
    {
      "type": "volume",
      "source": "myprj-cache-vscode",
      "target": "/home/vscode/.cache"
    },
    {
      "type": "volume",
      "source": "myprj-venv",
      "target": "${containerWorkspaceFolder}/.venv"
    }
  ],

  "customizations": {
    "vscode": {
      "extensions": [
        "ms-python.python",
        "charliermarsh.ruff",
        "ms-toolsai.jupyter"
      ]
    },
    "settings": {
      "python.defaultInterpreterPath": "/usr/local/bin/python",
      "python.pythonPath": "/usr/local/bin/python"
    }
  },

  "remoteUser": "vscode",

  "postAttachCommand": "sudo chown -R vscode ${containerWorkspaceFolder}/.venv"
}
```


# Dev ContainerからGitに接続

VSCodeの設定がONになっていることを確認。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/654538/c3e42e9d-d354-ef6c-520e-200e58ded71a.png)

これをONにしているだけでローカルのGitの認証情報を引き継げるので、Dev container内からGit Pushなどを行う。

# 参考情報
- Dev Containerの読み込み処理が激遅な場合（2025/02/16 追記）

「Dev Containerディスク遅い」とかで検索すると出てくるけど、色んな人がいろんなことを言っていて、ちょっとわかりづらかったので。

https://learn.microsoft.com/ja-jp/windows/wsl/tutorials/wsl-vscode#open-a-wsl-project-in-visual-studio-code

要はプロジェクトファイルをいつも通りにC\Workなんかに置くと、WSLからの読み取りが遅くなるということらしい。なので、プロジェクトファイルはwsl配下のフォルダの置きましょう。

\\wsl.localhost\Ubuntu\home\simari\Project
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/654538/117189f9-e07b-459c-a5ea-cd70c0cb0c91.png)

Explorerで\\wsl$と入力すればwsl配下が見れる。
ここから右クリックでCodeで開くを実施すればよい。
　

- Rebuild containerすると毎回pip installが必要になる
→ venvをマウントすることで解決。

```devcontainer.json
  "mounts": [
    "source=vscode-extensions,target=/root/.vscode-server/extensions,type=volume",
    {
      "type": "volume",
      "source": "myprj-cache-vscode",
      "target": "/home/vscode/.cache"
    },
    {
      "type": "volume",
      "source": "myprj-venv",
      "target": "${containerWorkspaceFolder}/.venv"
    }
  ],
```

https://zenn.dev/naas/articles/dev-container-python-best-practice#poetry%E3%81%AE%E3%82%AD%E3%83%A3%E3%83%83%E3%82%B7%E3%83%A5%E3%82%82%E3%83%9C%E3%83%AA%E3%83%A5%E3%83%BC%E3%83%A0%E3%81%AB%E9%80%80%E9%81%BF%E3%81%99%E3%82%8B%EF%BC%88%E3%82%AA%E3%83%97%E3%82%B7%E3%83%A7%E3%83%B3%EF%BC%89

- Rebuildするとapt-getなどのツールの再インストールが必要になる
→ Dockerfileを使う。

https://code.visualstudio.com/docs/devcontainers/create-dev-container#_dockerfile

> When you make changes like installing new software, changes made in the Dockerfile will persist even upon a rebuild of the dev container.

- 環境変数
これは通常のPython開発と同じで.envファイルを使える。これはチェックインしちゃダメなので、gitignoreに追加して管理する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/654538/80b9c84d-3d74-6c26-6a73-b87ef55f6ed7.png)

```
 "runArgs": ["--env-file", ".env"],
```

https://code.visualstudio.com/remote/advancedcontainers/environment-variables#_option-2-use-an-env-file