9
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

APIとフロントのアプリ両方が含まれたdocker-composeプロジェクトに VSCode Remote Containersを導入する方法

Last updated at Posted at 2020-11-15

背景

  • 社内で新規プロジェクトを立ち上げる上で、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とかもあったけどこの記事の趣旨には関係ないから除外した

docker-compose.yml(一部省略)
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.jsondocker-compose.extend.yml の2つの設定ファイルを作成するのが目標になります。

前提

  • VScodeおよびdockerはインストール済み
  • VScodeの拡張機能ペインから、Remote - Containers をインストール済み
    • インストールすると、VScodeの画面左下にRemote - Containersのアイコンが追加されます

手順

api側を例に解説します。front側は同じことをやり直してください。

1. .devcontainer を自動作成する

  1. 「file(ファイル)」の「open workspace(ワークスペースを開く)」から、 project-docker を開く
  2. 画面左下にRemote - Containersのアイコンをクリックし、Reopen in Container を選択
  3. From docker-compose.yml を 選択
  4. select a service で backend を選択
  5. project-docker 直下に、 .devcontainer ディレクトリと、 その下に devcontainer.jsondocker-compose.yml の2つの設定ファイルが作成されるので、これを project-api の下に移動させる

2. .devcontainer/devcontainer.json の修正

自動的に作られた直後の .devcontainer/devcontainer.json は以下です。

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"
}

これを以下に書き換えます。

devcontainer.json(修正部分のみ)
{
	"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 は以下です。

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 の中身を以下に書き換えます。

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.ymlbackendcommand (今回の場合はrailsのサーバー起動コマンド) を上書きしているので、サーバーが起動しません。 元の記述を持ってきて、最後に while sleep 1000; do :; done を加えます。
  • circleci系のコンテナなど、 コンテナ側のユーザがrootではないコンテナを使っている場合は、"environment" で環境変数 HOME の指定が必要だそうです。詳しくはこっちの記事を参照してください。

4. Remote - Containers で開く

  1. 設定が完了したので、「file(ファイル)」の「open workspace(ワークスペースを開く)」から、このリポジトリの直下にcloneした api-okapi (or front-okapi) を開きます。
  2. 左下のアイコンをクリックし、 Remote-Containers: Reopen in Container を選択します。
  3. 自動的にcontainerが起動し、コンテナ内でVSCodeが開きます。(ビルドが必要な場合、長い時間がかかります)

front側の相違点

  • front側を設定するときは、 runServices の中を frontend のみにしてください。
devcontainer.json(修正部分のみ)
{
	"runServices": [
		"frontend"
		// "db",
		// "backend",
	],
}
  • このように、backend側とfrontend側で起動するserviceを振り分けることで、同時にbackend側とfrontend側をRemote - Containersで起動しても、それぞれのレポジトリで起動するserviceが衝突しないので安心。(必要ないかもしれない。誰か詳しい人教えてください)
  • 親の docker-compose.yml の方で depends_on を指定していると、 runServices の設定から外しても起動するのでご注意ください。

導入後の設定

VScodeのエディタ設定の変更

  • 例: .tsファイルを保存する度に、ESLintでフォーマットが走るようにする
  • 各レポジトリの .devcontainer/devcontainer.jsonsettings の中を修正してください。
    • ここが .vscode/settings.json の代わりになります。
.devcontainer/devcontainer.json
{
	"settings": {
		"editor.codeActionsOnSave": {
			"source.fixAll.eslint": true // ファイル保存時にESLintでフォーマット
		}
		...
	},
}

VScodeのプラグイン設定の変更

  • 例: eslint の VScodeプラグインを入れる
  • 各レポジトリの .devcontainer/devcontainer.jsonextensions の中を修正してください。
    • 各プラグインのIDは、VScodeの拡張機能ペインにて、該当のプラグインを右クリックして「拡張機能IDをコピーする」で取得できます。
  • 通常通り、VScodeの拡張機能ペインからプラグインを追加することもできますが、この場合、他の開発者の環境には追加されないっぽい?。
.devcontainer/devcontainer.json
{
	"extensions": [
		"dbaeumer.vscode-eslint",
		...
	],
}

bash設定の変更

  • 例: gitコマンドの補完スクリプトを入れる
  • .bashrc などのファイルを準備した上で、docker-compose.ymlvolume を修正して、container側のホームディレクトリ(この場合は/root)直下にマウントしてください。
    • 以下では、 project-docker の 下に bash-config フォルダを用意して、親玉の方の docker-compose.yml でマウントの設定をしてます。
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関連

導入後の設定関連

9
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?