VSCode の Remote Containers で環境変数が読み込めなくてハマった

※この記事は以下の元記事を一部修正して転載しています。
https://lanchester-tech-blog.hatenablog.com/entry/2019/09/20/161341

---

# 現象
VSCode の Remote - Containers 拡張機能を使って起動・ログインしたコンテナ内で `docker-compose.yml` の環境変数がどうしても読み込めなかった。でも普通に `docker-compose up` とかして `attach` すれば読み込めていた。

Remote - Containers 拡張機能の説明はこの辺。

Developing inside a Container using Visual Studio Code Remote Development
https://code.visualstudio.com/docs/remote/containers


# 原因
原因としては Dev Container を起動する際に `docker-compose.yml` ではなく `Dockerfile` の設定だけが読まれていた。

## ダメだったコード

```dockerfile:Dockerfile-rails
FROM ruby:2.6.4

WORKDIR /app

ENV LANG C.UTF-8 \
    BUNDLE_PATH=/bundle

COPY Gemfile .
COPY Gemfile.lock .

RUN apt-get update -qq && \
    apt-get install -y build-essential libpq-dev nodejs && \
    gem install bundler && \
    bundle install --jobs=4

COPY . /app
```

```yaml:docker-compose.yml
version: '3'
services:
  db:
    image: mysql:5.6
    environment:
      - MYSQL_USER=root
      - MYSQL_ROOT_PASSWORD=
      - MYSQL_ALLOW_EMPTY_PASSWORD=yes
    ports:
      - '3316:3306'
    volumes:
      - mysql_data:/var/lib/mysql
  api:
    build: .devcontainer
    environment:
      - DATABASE_HOST=db
      - MYSQL_USER=root
      - MYSQL_ROOT_PASSWORD=
    command: bundle exec rails s -p 80 -b '0.0.0.0'
    volumes:
      - .:/app:cached
      - bundle_data:/bundle
    ports:
      - "3000:80"
    depends_on:
      - db
    tty: true
    stdin_open: true
volumes:
  bundle_data:
    driver: local
  mysql_data:
    driver: local
```

```json:.devcontainer/devcontainer.json
{
    "name": "MyApp",
    "dockerComposeFile": ["../docker-compose.yml", "docker-compose.extend.yml"],
    "dockerFile": "../Dockerfile-rails",
    "service": "api",
    "workspaceFolder": "/app",
    "extensions": [
      "rebornix.ruby",
      "castwide.solargraph"
    ],
    "shutdownAction": "stopCompose"
}
```

```yaml:.devcontainer/docker-compose.extend.yaml
version: '3'
services:
  api:
    volumes:
      - ~/.gitconfig:/root/.gitconfig
    command: sleep infinity
```


## 修正したコード
`docker-compose.yml` と `.devcontainer/devcontainer.json` だけ修正。

```yaml:docker-compose.yml
version: '3'
services:
  db:
    image: mysql:5.6
    environment:
      - MYSQL_USER=root
      - MYSQL_ROOT_PASSWORD=
      - MYSQL_ALLOW_EMPTY_PASSWORD=yes
    ports:
      - '3316:3306'
    volumes:
      - mysql_data:/var/lib/mysql
  api:
    build:
      context: .
      dockerfile: Dockerfile-rails
    environment:
      - DATABASE_HOST=db
      - MYSQL_USER=root
      - MYSQL_ROOT_PASSWORD=
    command: bundle exec rails s -p 80 -b '0.0.0.0'
    volumes:
      - .:/app:cached
      - bundle_data:/bundle
    ports:
      - "3000:80"
    depends_on:
      - db
    tty: true
    stdin_open: true
volumes:
  bundle_data:
    driver: local
  mysql_data:
    driver: local
```

```json:.devcontainer/devcontainer.json
{
    "name": "MyApp",
    "dockerComposeFile": ["../docker-compose.yml", "docker-compose.extend.yml"],
    "service": "api",
    "workspaceFolder": "/app",
    "extensions": [
      "rebornix.ruby",
      "castwide.solargraph"
    ],
    "shutdownAction": "stopCompose"
}
```

変更したのは以下

```diff:docker-compose.yml
services:
  # …
  api:
-   build: .devcontainer
+   build:
+     context: .
+     dockerFile: Dockerfile-rails
```

```diff:.devcontainer/devcontainer.json
{
    "name": "MyApp",
    "dockerComposeFile": ["../docker-compose.yml", "docker-compose.extend.yml"],
-   "dockerFile": "../Dockerfile-rails",
    "service": "api",
    "workspaceFolder": "/app",
```

最初 `build` に `.devcontainer` を指定して `devcontainer.json` で `dockerFile` のパスを指定していたが、`.devcontainer/devcontainer.json` に `dockerFile` と `dockerComposeFile` の両方の指定がある場合、**`dockerFile` の指定が優先されて `dockerComposeFile` は無視される**。

特に指定しなくても VSCode は `.devcontainer.json`、もしくは `.devcontainer/devcontainer.json` を自動で読んでくれる。
https://code.visualstudio.com/docs/remote/containers#_creating-a-devcontainerjson-file


# 余談
ちなみに最初は `alpine` を使って `FROM ruby:2.6.4-alpine3.10` としていたが `spdlog` に関するエラーが出てすぐに切断されてしまうという状況だったためバージョンを `ruby:2.6.4-alpine3.9` にしたがそれでもダメだったので `debian` ベースにした。
Remote - Containers が比較的新しめの機能で、Alpine Linux がサポートされたのもつい最近なのでまだこなれてないのかも。また試してみる。

https://github.com/microsoft/vscode-remote-release/issues/1026