背景
- 社内で新規プロジェクトを立ち上げる上で、Visual Studio Code(以下 VSCode)のプラグインであるRemote - Containersを使用して開発したかった。
- docker利用で、アプリケーションの動作環境はチーム内で共通化できるが、エディタの動作環境の構築は各メンバーに任されたままである。今回のプロジェクトでは、eslintやrubocopなどの構文チェックやコード補完ツールを複数個入れることが序盤から決まっていたので、Remote - Containersを入れることで、エディタの動作環境もまとめてdockerでメンバーと共有して効率化したかった。
- 今回のプロジェクトでは、同一プロジェクトの中で、APIとフロントを別々のレポジトリとしてgit管理しており、それらを同一のdocker-compose.ymlで管理しているという条件だった。この場合のRemote - Container設定の書き方でかなり悩んだ。
想定読者
- すでに
docker-compose.yml
で管理しているプロジェクトがあり、そのプロジェクトの中に複数のアプリケーション(例:APIとフロント)が含まれている - それぞれのアプリケーションを Remote - Containersで開発できるようにしたい
修正前のプロジェクト構成
フォルダ構成
project-docker
┣ project-api (railsのレポジトリ)
┃ ┣ app
┃ ┣ ...
┃ ┗ Gemfile
┣ project-front (Next.jsのレポジトリ)
┃ ┣ .next
┃ ┣ ...
┃ ┗ package.json
┣ docker-compose.yml
┣ Dockerfile.backend
┗ Dockerfile.frontend
project-docker
直下で docker-compose up
を叩くと、APIとフロント(とDB)が同時に起動してハッピー、という構成。
docker-compose.yml
docker-compose.yml
が 以下。ひとまずservices
が少なくとも以下の3つがある。
- db
- backend
- frontend
※本当はredisとかsmtpとかもあったけどこの記事の趣旨には関係ないから除外した
services:
db:
image: postgres:11.5
ports:
- "5432:5432"
backend:
build:
context: .
dockerfile: Dockerfile.backend
volumes:
- ./project-api:/project-api
command: /bin/sh -c "rm -f /api-okapi/tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
ports:
- "3000:3000"
depends_on:
- db
frontend:
build:
context: .
dockerfile: Dockerfile.frontend
command: npm run dev
volumes:
- ./project-front:/project-front
ports:
- "8080:8080"
Remote - Containers の導入手順
- 基本的には、各レポジトリ(project-api, project-front)の下に Remote - Containers の設定ファイルを入れるディレクトリ
.devcontainer
を作成し、その下にdevcontainer.json
とdocker-compose.extend.yml
の2つの設定ファイルを作成するのが目標になります。
前提
- VScodeおよびdockerはインストール済み
- VScodeの拡張機能ペインから、Remote - Containers をインストール済み
- インストールすると、VScodeの画面左下にRemote - Containersのアイコンが追加されます
手順
api側を例に解説します。front側は同じことをやり直してください。
1. .devcontainer
を自動作成する
- 「file(ファイル)」の「open workspace(ワークスペースを開く)」から、
project-docker
を開く - 画面左下にRemote - Containersのアイコンをクリックし、
Reopen in Container
を選択 -
From docker-compose.yml
を 選択 - select a service で
backend
を選択 -
project-docker
直下に、.devcontainer
ディレクトリと、 その下にdevcontainer.json
とdocker-compose.yml
の2つの設定ファイルが作成されるので、これをproject-api
の下に移動させる
2. .devcontainer/devcontainer.json
の修正
自動的に作られた直後の .devcontainer/devcontainer.json
は以下です。
// If you want to run as a non-root user in the container, see .devcontainer/docker-compose.yml.
// If you want to run as a non-root user in the container, see .devcontainer/docker-compose.yml.
{
"name": "Existing Docker Compose (Extend)",
// Update the 'dockerComposeFile' list if you have more compose files or use different names.
// The .devcontainer/docker-compose.yml file contains any overrides you need/want to make.
"dockerComposeFile": [
"../docker-compose.yml",
"docker-compose.yml"
],
// The 'service' property is the name of the service for the container that VS Code should
// use. Update this value and .devcontainer/docker-compose.yml to the real service name.
"service": "backend",
// The optional 'workspaceFolder' property is the path VS Code should open by default when
// connected. This is typically a file mount in .devcontainer/docker-compose.yml
"workspaceFolder": "/workspace",
// Set *default* container specific settings.json values on container create.
"settings": {
"terminal.integrated.shell.linux": null
},
// Add the IDs of extensions you want installed when the container is created.
"extensions": []
// Use 'forwardPorts' to make a list of ports inside the container available locally.
// "forwardPorts": [],
// Uncomment the next line if you want start specific services in your Docker Compose config.
// "runServices": [],
// Uncomment the next line if you want to keep your containers running after VS Code shuts down.
// "shutdownAction": "none",
// Uncomment the next line to run commands after the container is created - for example installing curl.
// "postCreateCommand": "apt-get update && apt-get install -y curl",
// Uncomment to connect as a non-root user if you've added one. See https://aka.ms/vscode-remote/containers/non-root.
// "remoteUser": "vscode"
}
これを以下に書き換えます。
{
"name": "project-api-docker", // 適当にナイスな名前にする
"dockerComposeFile": [
"../../docker-compose.yml", // フォルダ移動したのでパスを修正
"docker-compose.extend.yml" // .extend をつける (動作するだけなら不要だけど私はわかりやすさを重視して名前を変えました)
],
"runServices": [
"db",
"backend",
// stmpなど他のサービスがあれば追加。 "frontend" を 含めないのが重要。空だと、デフォルトで全てのserviceを起動する。
],
"workspaceFolder": "/workspace/project-api/", // workspaceを project-api にする
}
3. docker-compose.yml
の修正
自動的に作られた直後の .devcontainer/docker-compose.yml
は以下です。
version: '3'
services:
# Update this to the name of the service you want to work with in your docker-compose.yml file
backend:
# If you want add a non-root user to your Dockerfile, you can use the "remoteUser"
# property in devcontainer.json to cause VS Code its sub-processes (terminals, tasks,
# debugging) to execute as the user. Uncomment the next line if you want the entire
# container to run as this user instead. Note that, on Linux, you may need to
# ensure the UID and GID of the container user you create matches your local user.
# See https://aka.ms/vscode-remote/containers/non-root for details.
#
# user: vscode
# Uncomment if you want to override the service's Dockerfile to one in the .devcontainer
# folder. Note that the path of the Dockerfile and context is relative to the *primary*
# docker-compose.yml file (the first in the devcontainer.json "dockerComposeFile"
# array). The sample below assumes your primary file is in the root of your project.
#
# build:
# context: .
# dockerfile: .devcontainer/Dockerfile
volumes:
# Update this to wherever you want VS Code to mount the folder of your project
- .:/workspace:cached
# Uncomment the next line to use Docker from inside the container. See https://aka.ms/vscode-remote/samples/docker-from-docker-compose for details.
# - /var/run/docker.sock:/var/run/docker.sock
# Uncomment the next four lines if you will use a ptrace-based debugger like C++, Go, and Rust.
# cap_add:
# - SYS_PTRACE
# security_opt:
# - seccomp:unconfined
# Overrides default command so things don't shut down after the process ends.
command: /bin/sh -c "while sleep 1000; do :; done"
まず、ファイル名を .devcontainer/docker-compose.extend.yml
に変更しておきます。
これは、.devcontainer/docker-compose.extend.yml
は、project-docker
直下の docker-compose.yml
の一部要素を上書きしているだけの存在であることをわかりやすくするためです。
そして、.devcontainer/docker-compose.extend.yml
の中身を以下に書き換えます。
services:
backend:
volumes:
- .:/workspace:cached
- ~/.gitconfig:/root/.gitconfig # ローカルの.gitconfig設定をコンテナ内に共有するため、コンテナ側のホームディレクトリ(この場合は/root)にマウントします。
- ~/.ssh:/root/.ssh # ローカルの.ssh 設定ををコンテナ内に共有するため(以下略)
- /var/run/docker.sock:/var/run/docker.sock # 一応アンコメントしてるけど必要性がよくわかってない。誰か教えてください・・・
command: /bin/sh -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0' ; while sleep 1000; do :; done"
- 特に
command
の修正が重要。元の記述のままだと、親玉のdocker-compose.yml
のbackend
のcommand
(今回の場合はrailsのサーバー起動コマンド) を上書きしているので、サーバーが起動しません。 元の記述を持ってきて、最後にwhile sleep 1000; do :; done
を加えます。 - circleci系のコンテナなど、 コンテナ側のユーザがrootではないコンテナを使っている場合は、"environment" で環境変数 HOME の指定が必要だそうです。詳しくはこっちの記事を参照してください。
4. Remote - Containers で開く
- 設定が完了したので、「file(ファイル)」の「open workspace(ワークスペースを開く)」から、このリポジトリの直下にcloneした api-okapi (or front-okapi) を開きます。
- 左下のアイコンをクリックし、
Remote-Containers: Reopen in Container
を選択します。 - 自動的にcontainerが起動し、コンテナ内でVSCodeが開きます。(ビルドが必要な場合、長い時間がかかります)
front側の相違点
- front側を設定するときは、
runServices
の中をfrontend
のみにしてください。
{
"runServices": [
"frontend"
// "db",
// "backend",
],
}
- このように、backend側とfrontend側で起動するserviceを振り分けることで、同時にbackend側とfrontend側をRemote - Containersで起動しても、それぞれのレポジトリで起動するserviceが衝突しないので安心。(必要ないかもしれない。誰か詳しい人教えてください)
- 親の
docker-compose.yml
の方でdepends_on
を指定していると、runServices
の設定から外しても起動するのでご注意ください。
導入後の設定
VScodeのエディタ設定の変更
- 例: .tsファイルを保存する度に、ESLintでフォーマットが走るようにする
- 各レポジトリの
.devcontainer/devcontainer.json
のsettings
の中を修正してください。- ここが
.vscode/settings.json
の代わりになります。
- ここが
{
"settings": {
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true // ファイル保存時にESLintでフォーマット
}
...
},
}
VScodeのプラグイン設定の変更
- 例: eslint の VScodeプラグインを入れる
- 各レポジトリの
.devcontainer/devcontainer.json
のextensions
の中を修正してください。- 各プラグインのIDは、VScodeの拡張機能ペインにて、該当のプラグインを右クリックして「拡張機能IDをコピーする」で取得できます。
- 通常通り、VScodeの拡張機能ペインからプラグインを追加することもできますが、この場合、他の開発者の環境には追加されないっぽい?。
{
"extensions": [
"dbaeumer.vscode-eslint",
...
],
}
bash設定の変更
- 例: gitコマンドの補完スクリプトを入れる
-
.bashrc
などのファイルを準備した上で、docker-compose.yml
のvolume
を修正して、container側のホームディレクトリ(この場合は/root
)直下にマウントしてください。- 以下では、
project-docker
の 下にbash-config
フォルダを用意して、親玉の方のdocker-compose.yml
でマウントの設定をしてます。
- 以下では、
frontend:
volumes:
- ./bash-config/.bashrc:/root/.bashrc
- ./bash-config/.git-completion.bash:/root/.git-completion.bash
- ./bash-config/.git-prompt.sh:/root/.git-prompt.sh
...
- 各レポジトリでbashの設定を変えたい場合は、 各レポジトリ以下に
bash-config
フォルダを用意してdocker-compose.extend.yml
の設定を変えるといいでしょう。
参考
VSCode Remote Container関連
- VSCode Remote Containerが良い
- Dockerで立ち上げた開発環境をVS Codeで開く!
- VS Code Remote Development で Docker 開発環境を利用する