VSCode+Docker+Dev Containerを使って開発環境をコンテナに作ってみた
今回やったこと
開発環境をコンテナに構築しホストのVisual Studio Codeからイジイジできるようにした。
動作検証環境は Mac mini 2020(Apple M1), MacBook Pro 2019(Intel Core)で検証しています。Windows, Linux では試せていません。
メリット
開発環境の再現性が高いため以下のようなメリットが得られます。
- 同じ開発環境をすぐに提供できる[1]
- ツール・ライブラリのバージョンをプロジェクト毎に決められる
- ホストの環境を汚さずにちょっとお試しができる
- Dockerの設定によっては構築時の最新バージョンのツールを構築することもできる
デメリット
そうはいってもデメリットやできないこともあります。
- Docker Desktopの企業利用は有料になる場合がある[2]
- Dockerを動作させる為、それなりのPCスペックが必要
- 構築するコンテナ環境によってはビルドが遅い
- Dockerで管理できないツール(VSCodeを除くGUIツール)は対応不可
- コンテナ環境の準備にはある程度の知識が必要
動作に必要なもの
- Dockerを動かせるPC(Docker Desktopのインストール)
- Visual Studio Code(以下 VSCode)
- Dev Containers拡張のインストール
Dev Containerのおさらい
Dev ContainerはVSCode(Local OS)からコンテナ(Container)へアクセスしてコンテナ上でビルドやアプリの実行を行い、あたかもホストで動かしているかのように振る舞います。
またこのコンテナ毎にVSCode拡張をインストールできるのでコンテナそれぞれで最適な環境を構築することが可能です。
より詳細を知りたい方はDev Containerをご覧ください。
またVSCodeがなくてもCLIからDev Containerの実行も可能となっています。Dev Container CLI
作ったものの紹介
以下の環境を作ってみました
リモートユーザはvsocde
、ディレクトリは/workspace
をホストとゲストで共有しています。
実行確認用のプログラムも入れてあります。
また独断と偏見でVSCodeの拡張もインストールしています。何が入っているかは書くリポジトリのREADME.md
をご確認ください。
起動方法
Dockerは立ち上げておいてください。
好きなリポジトリをgit
でclone
します。
clone
したフォルダをしてVSCodeで開いてください。
Dev Containerがインストールされていれば右下にReopen in Container
が出てきますのでそれを押してください。
押し損なった場合でもコマンドパレットからDev Containers: Open Folder In Container
で起動できます。
workspace
ディレクトリがVSCodeで開いた状態になり完成です。
リポジトリの基本構成
今回作成したリポジトリは複数あります。だいたい同じ構成で作っていますので代表でPythonのリポジトリで説明します。
+- .devconainer
| +- Dockerfile
| +- devcontainer.json
| +- docker-compose.yml
+- workspace
| +- .vscode
| | +- settings.json
| +- hello-server.py
| +- hello-world.py
+- .gitignore
+- LICENSE.md
+- README.md
.devcontainer ディレクトリ
dev containerの設定ファイルやDocker用の設定ファイルを保持するディレクトリ。
devcontainer.json
, docker-compose.yml
, Dockerfile
の3つファイルがあります
devcontainer.json ファイル
dev containerの設定ファイル。今回はdocker-compose.yml
を利用していますのそのファイル名とサービス名を指定しています。
なおdocker-compose.yml
を使わずにDockerfile
を直接設定する方法もあります。
{
// dev container名(どこに使われてるかよくわかってない)
"name": "docker-playground - python",
// 今回は docker-compose.ymlを利用する。全リポジトリ共通にしてます。
"dockerComposeFile": "docker-compose.yml",
// docker-compose.yml内のサービス名を指定。全リポジトリ共通にしてます。
"service": "playground",
// コンテナのどこにワークスペースを配置するかの指定。全リポジトリ共通にしてます。
"workspaceFolder": "/workspace",
// ゲストOSでの実行ユーザ。全リポジトリ共通にしてます。
"remoteUser": "vscode",
// ゲストOSの設定を変更する場合に利用する設定
"customizations": {
// VSCodeのデフォルトの設定を変更します
// 'settings'を指定すればここでVSCodeの設定変更も可能
// 今回のポリシーとして拡張はこのファイルに記載
// VSCodeの動作変更は'workspace/.vscode/settings.json'に記載としています
"vscode": {
// 事前にゲストOS上のVSCodeで利用する拡張をインストールします
"extensions": [
// 全リポジトリにインストール
"EditorConfig.EditorConfig",
// 以下 python用の拡張
"ms-python.python",
"ms-python.flake8",
"ms-python.autopep8",
"njpwerner.autodocstring"
]
}
}
}
docker-compose.yml ファイル
docker compose
で利用するようにdocker-compse.yml
を設定します。
version: '3'
services:
playground: # `devcontainer.json`の'service'と一致させる
container_name: 'python' # コンテナ名
hostname: 'python' # ホスト名.ゲストOSのシェルに表示されるので指定している
# 以下は他のリポジトリも全て同じ設定にしています
build: . # Dockerfileがあるディレクトリ
restart: always # 常に再起動
working_dir: '/workspace' # デフォルトの作業ディレクトリ
tty: true # コンテナを終了させずに待たせる
volumes: # ホストとゲストのディレクトリを紐づける
- type: bind # ホストのディレクトリをゲストにマウントさせる
source: ../workspace # ホストの`workspace`ディレクトリを指定
target: /workspace # ゲストの`/workspace`にマウントさせる
Dockefile ファイル
コンテナのイメージ設定。基本的には言語やツールの最新版のslimがあればをそれを選択しています。Apple シリコンで動作しない場合は別途設定やインストールで実行できるようにしています。
# ベースとなるイメージ。Python 3系の安定版のスリム版。
FROM python:3-slim
# ユーザ'vscode'を作成する
# 他のリポジトリではUSER_UIDがベースのイメージですでに使われている場合は別の値を使っています。
ARG USERNAME=vscode
ARG USER_UID=1000
ARG USER_GID=$USER_UID
# ユーザの作成と`sudo`の利用設定
# 言語・場所設定
RUN apt-get update \
&& groupadd --gid $USER_GID $USERNAME \
&& useradd -s /bin/bash --uid $USER_UID --gid $USER_GID -m $USERNAME \
&& apt-get install -y sudo \
&& echo $USERNAME ALL=\(root\) NOPASSWD:ALL > /etc/sudoers.d/$USERNAME \
&& chmod 0440 /etc/sudoers.d/$USERNAME \
&& apt-get -y install locales \
&& localedef -f UTF-8 -i ja_JP ja_JP.UTF-8
# curlとgitは利用頻度が高いので他のリポジトリでもインストールしています。
RUN apt-get -y install curl git
# その他環境変数など
ENV LANG ja_JP.UTF-8
ENV LANGUAGE ja_JP:ja
ENV LC_ALL ja_JP.UTF-8
ENV TZ JST-9
ENV TERM xterm
# vim, less, gccのインストール
RUN apt-get install -y vim less gcc
# 以下 pip
# VSCodeで自動フォーマットやリントの動作をさせるため事前にインストール
RUN pip install --upgrade pip
RUN pip install --upgrade setuptools
RUN pip install flake8 autopep8
# サンプルソースで利用しているパッケージとこの後利用しそうなものを追加
RUN pip install python-dotenv fastapi uvicorn
workspace ディレクトリ
このホストのディレクトリがコンテナのゲストOS上ではルートのディレクトリとしてバインドされる。
ソースコードやビルドの設定情報。gitなどもこのフォルダを起点に設定可能。
/workspace
+- .vscode
| +- settings.json
+- hello-server.py
+- hello-world.py
.vscode ディレクトリ
VSCodeの設定を保存するディレクトリ。このディレクトリをgitなどSCMで管理するかは議論の分かれるところだと思います。
とりあえずPythonのフォーマットやリンターの設定をしてあります。細かい説明は割愛。
リンターの設定や保存した時に自動フォーマットしてます。
settings.json ファイル
{
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.fixAll": true,
},
"autoDocstring.docstringFormat": "google",
"python.linting.lintOnSave": true,
"python.linting.pylintEnabled": false,
"python.linting.flake8Enabled": true,
"python.formatting.provider": "autopep8",
"python.formatting.autopep8Args": [
"--aggressive",
"--aggressive"
],
"[python]": {
"editor.defaultFormatter": "ms-python.autopep8"
}
}
hello-world.py ファイル
開発環境ができたらまずこれ。hello, world!
を表示します。[3]
ゲストOSで上./hello-world.py
を入力して実行できます。
#!/usr/local/bin/python3
print('hello, world!')
hello-server.py ファイル
メッセージとして'hello, world'を返すサーバです。
ゲストOSで上./hello-server.py
を入力して実行できます。
実行されるとVSCode拡張のDev Containerが自動的にポートをホストとマッピングします。ホスト上のブラウザからアクセスしてゲスト上のサーバにアクセスできます。
#!/usr/local/bin/python3
import uvicorn
from fastapi import FastAPI
app = FastAPI()
@app.get('/')
async def root():
return {'message': 'hello, world'}
if __name__ == '__main__':
uvicorn.run(app)
.gitignore ファイル
gitで追跡対象外にするファイル・フォルダを指定します。
ここにはworkspace
ディレクトリの設定については指定しないこととしています。
workspace
では別途git
を初期化して利用することを想定しているためです。
.DS_Store
LICENSE.md ファイル
ライセンスファイル。docker-playground-...は全てMITライセンスにしています。
README.md ファイル
github用のREADMEファイル。リポジトリごとにどんな設定にしているかを記載しています。
その他注意事項
denoについて
denoは正確にはlinuxのArmアーキテクチャのビルドイメージがありません。
そのため--platform=linux/amd64
でコンテナを動作させて代用しています。
haskellについて
armアーキテクチャのイメージにはstack
が入っていません。
なのでIntel macとAppleシリコン macでできることが違います。
「同じ開発環境をすぐに提供できる」と言ったな。あれは嘘だ!
失敗談
最初はworkspace
フォルダではなくopt
フォルダを利用して作成していました。
python
の時とかは良かったのですがhaskell
の時に問題になりました。
haskell
のツールghci
などは/opt/ghc/
にインストールされています。
これを後からホストのopt
ディレクトリでbind
してしまうためツール類がゴッソリなくなりコンテナの立ち上げでエラーが起きてました。これで2日無駄にしました。😂
-
CPUアーキテクチャの差異で異なる場合があります ↩︎
-
Rancher Desktopで代用できる? ↩︎
-
今気がついた、、、他の言語では
!
付けてないかも。 ↩︎
Discussion