vscode-remote-release icon indicating copy to clipboard operation
vscode-remote-release copied to clipboard

Support --project-directory for Docker Compose

Open davidpcaldwell opened this issue 2 years ago • 4 comments

Conceivably this is a bug in the nascent devcontainers spec; I don't know.

I am pretty sure -- or somewhat sure -- that, for projects that use Docker Compose to specify their devcontainers, there is no way to get the devcontainers working if the Docker Compose file is not specified in the root directory of the project.

This is a regression, in the sense that my project had a working devcontainer setup at one time, with its existing configuration.

But as of the commit linked below, choosing Reopen in Container simply fails silently; in the logs there's something about a command exiting with status 1.

I installed the devcontainer CLI in the hopes it might provide more information, and it did. It spit out various generated files that made it clear it was relying heavily on the directory in which the docker-compose.yaml file was specified. I tried using the generated files to reverse-engineer how it was using the files, so that I could add additional overrides to my devcontainer-specific Docker Compose overrides files, but eventually I could find no way to override the project name; it seemed to use the basename of the directory containing docker-compose.yaml, no matter what I did.

When using the Docker Compose CLI directly, I was able to get things working properly by using the --project-directory command line argument to Docker Compose. There does not appear to be an equivalent in the available devcontainer configuration properties.

When I moved my docker-compose.yaml to the project root, I was able to get the devcontainer working -- so my challenges seem specifically related to not having docker-compose.yaml at the root.

  • VSCode Version: 1.78.1
  • Local OS Version: macOS 13.4
  • Remote OS Version: debian Docker image
  • Remote Extension/Connection Type: Containers

Steps to Reproduce:

  1. See this commit of a project with a devcontainer.
  2. Attempt to configure it to get it working with "Reopen in Container"

davidpcaldwell avatar Jun 12 '23 02:06 davidpcaldwell

Please append the Dev Containers log from when this happens. (F1 > Dev Containers: Show Container Log)

chrmarti avatar Jun 12 '23 13:06 chrmarti

OK, updating this report a little bit.

Currently I can't reproduce the symptom I had above -- failing silently in the UI, with an incomprehensible (to me) node invocation of the devcontainer CLI somewhere in an output screen somewhere. I am guessing (this is a bit of a wild guess) that this is because I didn't discover the "Rebuild without cache" option until partway through my attempts to diagnose this, and so maybe the silent failure with the exit status 1 required a particular cache state, and I busted it by rebuilding without cache, so that now the symptoms are a bit more straightforward.

So currently, when I try this, it actually does open the window in container mode (or whatever the proper terminology is), but then the container fails on startup.

It's for a straightforward reason -- it can't find the Dockerfile, because the docker-compose.yaml in contributor/ references it as . -- because the docker-compose.yaml expects the --project-directory to point to the root of the project.

So I would like to be able to coax this to work, by having the ability to specify the equivalent of the --project-directory argument to docker compose when setting up the devcontainer.

Here is the log:

[52 ms] Dev Containers 0.295.0 in VS Code 1.78.1 (6a995c4f4cc2ced6e3237749973982e751cb0bf9).
[51 ms] Start: Resolving Remote
[69 ms] Setting up container for folder or workspace: /Users/inonit/src/inonit/slime
[69 ms] Context: desktop-linux
[70 ms] Start: Check Docker is running
[70 ms] Start: Run: docker version --format {{.Server.APIVersion}}
[163 ms] Server API version: 1.43
[163 ms] Start: Run: docker volume ls -q
[214 ms] Start: Run: docker ps -q -a --filter label=vsch.local.folder=/Users/inonit/src/inonit/slime --filter label=vsch.quality=stable
[268 ms] Start: Run: docker ps -q -a --filter label=devcontainer.local_folder=/Users/inonit/src/inonit/slime --filter label=devcontainer.config_file=/Users/inonit/src/inonit/slime/.devcontainer/devcontainer.json
[322 ms] Start: Run: docker inspect --type container 72ed273c8ac6
[379 ms] Start: Run: docker ps -q -a --filter label=devcontainer.local_folder=/Users/inonit/src/inonit/slime
[428 ms] Start: Run: docker inspect --type container 72ed273c8ac6
[467 ms] Start: Run: /Users/inonit/Applications/Visual Studio Code.app/Contents/Frameworks/Code Helper (Plugin).app/Contents/MacOS/Code Helper (Plugin) --ms-enable-electron-run-as-node /Users/inonit/.vscode/extensions/ms-vscode-remote.remote-containers-0.295.0/dist/spec-node/devContainersSpecCLI.js read-configuration --workspace-folder /Users/inonit/src/inonit/slime --id-label devcontainer.local_folder=/Users/inonit/src/inonit/slime --id-label devcontainer.config_file=/Users/inonit/src/inonit/slime/.devcontainer/devcontainer.json --log-level debug --log-format json --config /Users/inonit/src/inonit/slime/.devcontainer/devcontainer.json --mount-workspace-git-root true
[619 ms] @devcontainers/cli 0.42.0. Node.js v16.17.1. darwin 22.5.0 arm64.
[619 ms] Start: Run: docker ps -q -a --filter label=devcontainer.local_folder=/Users/inonit/src/inonit/slime --filter label=devcontainer.config_file=/Users/inonit/src/inonit/slime/.devcontainer/devcontainer.json
[676 ms] Start: Run: docker inspect --type container 72ed273c8ac6
[730 ms] Start: Run: /Users/inonit/Applications/Visual Studio Code.app/Contents/Frameworks/Code Helper (Plugin).app/Contents/MacOS/Code Helper (Plugin) --ms-enable-electron-run-as-node /Users/inonit/.vscode/extensions/ms-vscode-remote.remote-containers-0.295.0/dist/spec-node/devContainersSpecCLI.js up --user-data-folder /Users/inonit/Library/Application Support/Code/User/globalStorage/ms-vscode-remote.remote-containers/data --container-session-data-folder /tmp/devcontainers-222a5323-8081-45a4-8082-6a1b624843681686696850477 --workspace-folder /Users/inonit/src/inonit/slime --workspace-mount-consistency cached --id-label devcontainer.local_folder=/Users/inonit/src/inonit/slime --id-label devcontainer.config_file=/Users/inonit/src/inonit/slime/.devcontainer/devcontainer.json --log-level debug --log-format json --config /Users/inonit/src/inonit/slime/.devcontainer/devcontainer.json --default-user-env-probe loginInteractiveShell --mount type=volume,source=vscode,target=/vscode,external=true --skip-post-create --update-remote-user-uid-default on --mount-workspace-git-root true
[884 ms] @devcontainers/cli 0.42.0. Node.js v16.17.1. darwin 22.5.0 arm64.
[884 ms] Start: Run: docker buildx version
[1048 ms] github.com/docker/buildx v0.10.5 86bdced7766639d56baa4c7c449a4f6468490f87
[1048 ms] 
[1048 ms] Start: Resolving Remote
[1122 ms] Start: Run: docker-compose version --short
[1202 ms] Docker Compose version: 2.18.1
[1202 ms] Start: Run: docker ps -q -a --filter label=com.docker.compose.project=contributor --filter label=com.docker.compose.service=local
[1255 ms] Start: Run: docker-compose -f /Users/inonit/src/inonit/slime/contributor/docker-compose.yaml -f /Users/inonit/src/inonit/slime/.devcontainer/docker-compose.extend.yaml --profile * config
[1342 ms] name: contributor
services:
  box:
    build:
      context: /Users/inonit/src/inonit/slime/contributor
      dockerfile: Dockerfile
    depends_on:
      chrome:
        condition: service_started
      firefox:
        condition: service_started
    environment:
      DOCKER_HOST_UNAME: ""
      SLIME_WF_SKIP_GIT_IDENTITY_REQUIREMENT: "1"
    networks:
      default: null
    working_dir: /slime
  chrome:
    image: seleniarm/standalone-chromium
    networks:
      default: null
    ports:
    - mode: ingress
      target: 7900
      published: "7900"
      protocol: tcp
  firefox:
    image: seleniarm/standalone-firefox
    networks:
      default: null
    ports:
    - mode: ingress
      target: 7900
      published: "7901"
      protocol: tcp
  local:
    build:
      context: /Users/inonit/src/inonit/slime/contributor
      dockerfile: Dockerfile
    command:
    - sleep
    - infinity
    depends_on:
      chrome:
        condition: service_started
      firefox:
        condition: service_started
    environment:
      DOCKER_HOST_UNAME: ""
      SLIME_WF_SKIP_GIT_IDENTITY_REQUIREMENT: "1"
    networks:
      default: null
    volumes:
    - type: bind
      source: /Users/inonit/src/inonit/slime/contributor
      target: /slime
    - type: volume
      source: local
      target: /slime/local
    working_dir: /slime
  test8:
    build:
      context: /Users/inonit/src/inonit/slime/contributor
      dockerfile: Dockerfile
    command:
    - /bin/bash
    - /slime/wf
    - check
    - --docker
    depends_on:
      chrome:
        condition: service_started
      firefox:
        condition: service_started
    environment:
      DOCKER_HOST_UNAME: ""
      SLIME_WF_JDK_VERSION: "8"
      SLIME_WF_SKIP_GIT_IDENTITY_REQUIREMENT: "1"
    networks:
      default: null
    working_dir: /slime
  test11:
    build:
      context: /Users/inonit/src/inonit/slime/contributor
      dockerfile: Dockerfile
    command:
    - /bin/bash
    - /slime/wf
    - check
    - --docker
    depends_on:
      chrome:
        condition: service_started
      firefox:
        condition: service_started
    environment:
      DOCKER_HOST_UNAME: ""
      SLIME_WF_JDK_VERSION: "11"
      SLIME_WF_SKIP_GIT_IDENTITY_REQUIREMENT: "1"
    networks:
      default: null
    working_dir: /slime
  test17:
    build:
      context: /Users/inonit/src/inonit/slime/contributor
      dockerfile: Dockerfile
    command:
    - /bin/bash
    - /slime/wf
    - check
    - --docker
    depends_on:
      chrome:
        condition: service_started
      firefox:
        condition: service_started
    environment:
      DOCKER_HOST_UNAME: ""
      SLIME_WF_JDK_VERSION: "17"
      SLIME_WF_SKIP_GIT_IDENTITY_REQUIREMENT: "1"
    networks:
      default: null
    working_dir: /slime
networks:
  default:
    name: contributor_default
volumes:
  local:
    name: contributor_local
x-base-box:
  build: .
  depends_on:
  - chrome
  - firefox
  environment:
    DOCKER_HOST_UNAME: ""
    SLIME_WF_SKIP_GIT_IDENTITY_REQUIREMENT: 1
  working_dir: /slime
x-base-test:
  build: .
  command: /bin/bash /slime/wf check --docker
  depends_on:
  - chrome
  - firefox
  environment:
    DOCKER_HOST_UNAME: ""
    SLIME_WF_SKIP_GIT_IDENTITY_REQUIREMENT: 1
  working_dir: /slime
[1344 ms] Start: Run: docker events --format {{json .}} --filter event=start
[1345 ms] PersistedPath=/Users/inonit/Library/Application Support/Code/User/globalStorage/ms-vscode-remote.remote-containers/data, ContainerHasLabels=false
[1346 ms] Start: Run: docker-compose -f /Users/inonit/src/inonit/slime/contributor/docker-compose.yaml -f /Users/inonit/src/inonit/slime/.devcontainer/docker-compose.extend.yaml --profile * config
[1436 ms] name: contributor
services:
  box:
    build:
      context: /Users/inonit/src/inonit/slime/contributor
      dockerfile: Dockerfile
    depends_on:
      chrome:
        condition: service_started
      firefox:
        condition: service_started
    environment:
      DOCKER_HOST_UNAME: ""
      SLIME_WF_SKIP_GIT_IDENTITY_REQUIREMENT: "1"
    networks:
      default: null
    working_dir: /slime
  chrome:
    image: seleniarm/standalone-chromium
    networks:
      default: null
    ports:
    - mode: ingress
      target: 7900
      published: "7900"
      protocol: tcp
  firefox:
    image: seleniarm/standalone-firefox
    networks:
      default: null
    ports:
    - mode: ingress
      target: 7900
      published: "7901"
      protocol: tcp
  local:
    build:
      context: /Users/inonit/src/inonit/slime/contributor
      dockerfile: Dockerfile
    command:
    - sleep
    - infinity
    depends_on:
      chrome:
        condition: service_started
      firefox:
        condition: service_started
    environment:
      DOCKER_HOST_UNAME: ""
      SLIME_WF_SKIP_GIT_IDENTITY_REQUIREMENT: "1"
    networks:
      default: null
    volumes:
    - type: bind
      source: /Users/inonit/src/inonit/slime/contributor
      target: /slime
    - type: volume
      source: local
      target: /slime/local
    working_dir: /slime
  test8:
    build:
      context: /Users/inonit/src/inonit/slime/contributor
      dockerfile: Dockerfile
    command:
    - /bin/bash
    - /slime/wf
    - check
    - --docker
    depends_on:
      chrome:
        condition: service_started
      firefox:
        condition: service_started
    environment:
      DOCKER_HOST_UNAME: ""
      SLIME_WF_JDK_VERSION: "8"
      SLIME_WF_SKIP_GIT_IDENTITY_REQUIREMENT: "1"
    networks:
      default: null
    working_dir: /slime
  test11:
    build:
      context: /Users/inonit/src/inonit/slime/contributor
      dockerfile: Dockerfile
    command:
    - /bin/bash
    - /slime/wf
    - check
    - --docker
    depends_on:
      chrome:
        condition: service_started
      firefox:
        condition: service_started
    environment:
      DOCKER_HOST_UNAME: ""
      SLIME_WF_JDK_VERSION: "11"
      SLIME_WF_SKIP_GIT_IDENTITY_REQUIREMENT: "1"
    networks:
      default: null
    working_dir: /slime
  test17:
    build:
      context: /Users/inonit/src/inonit/slime/contributor
      dockerfile: Dockerfile
    command:
    - /bin/bash
    - /slime/wf
    - check
    - --docker
    depends_on:
      chrome:
        condition: service_started
      firefox:
        condition: service_started
    environment:
      DOCKER_HOST_UNAME: ""
      SLIME_WF_JDK_VERSION: "17"
      SLIME_WF_SKIP_GIT_IDENTITY_REQUIREMENT: "1"
    networks:
      default: null
    working_dir: /slime
networks:
  default:
    name: contributor_default
volumes:
  local:
    name: contributor_local
x-base-box:
  build: .
  depends_on:
  - chrome
  - firefox
  environment:
    DOCKER_HOST_UNAME: ""
    SLIME_WF_SKIP_GIT_IDENTITY_REQUIREMENT: 1
  working_dir: /slime
x-base-test:
  build: .
  command: /bin/bash /slime/wf check --docker
  depends_on:
  - chrome
  - firefox
  environment:
    DOCKER_HOST_UNAME: ""
    SLIME_WF_SKIP_GIT_IDENTITY_REQUIREMENT: 1
  working_dir: /slime
[1438 ms] Error: ENOENT: no such file or directory, open '/Users/inonit/src/inonit/slime/contributor/Dockerfile'
[1441 ms] Exit code 1
[1443 ms] Command failed: /Users/inonit/Applications/Visual Studio Code.app/Contents/Frameworks/Code Helper (Plugin).app/Contents/MacOS/Code Helper (Plugin) --ms-enable-electron-run-as-node /Users/inonit/.vscode/extensions/ms-vscode-remote.remote-containers-0.295.0/dist/spec-node/devContainersSpecCLI.js up --user-data-folder /Users/inonit/Library/Application Support/Code/User/globalStorage/ms-vscode-remote.remote-containers/data --container-session-data-folder /tmp/devcontainers-222a5323-8081-45a4-8082-6a1b624843681686696850477 --workspace-folder /Users/inonit/src/inonit/slime --workspace-mount-consistency cached --id-label devcontainer.local_folder=/Users/inonit/src/inonit/slime --id-label devcontainer.config_file=/Users/inonit/src/inonit/slime/.devcontainer/devcontainer.json --log-level debug --log-format json --config /Users/inonit/src/inonit/slime/.devcontainer/devcontainer.json --default-user-env-probe loginInteractiveShell --mount type=volume,source=vscode,target=/vscode,external=true --skip-post-create --update-remote-user-uid-default on --mount-workspace-git-root true
[1443 ms] Exit code 1

davidpcaldwell avatar Jun 13 '23 22:06 davidpcaldwell

By the way, in looking at the log myself, I think the "incomprehensible invocation" I talked about in my report was probably the command on the second-to-last line of the file. So, for whatever reason, the UI was not relaunching the window for the devcontainer, and rather spitting out just the command and the fact that it exited with status 1 in some output window somewhere.

But it looks like the underlying problem is the same, and not too complicated (the issue being the directory layout of the project and no equivalent of Docker Compose --project-directory that I could find).

davidpcaldwell avatar Jun 13 '23 23:06 davidpcaldwell

The workaround I'm using is to have an "empty" docker-compose.yml file in the project root:

version: '3.9'

services:
  api: {}

I haven't checked if api (or your service name) even needed, it might work without it.

Then, add to the devcontainer the path to it as the first docker-compose:

"dockerComposeFile": [
    "../docker-compose.yml",  // <== this is the docker-compose above
    "../deploy/docker-compose.yml",
    "../deploy/docker-compose.dev.yml",
    "docker-compose.yml"
],

source: https://docs.docker.com/reference/cli/docker/compose/?highlight=projectdirectory#specifying-multiple-compose-files

When you use multiple Compose files, all paths in the files are relative to the first configuration file specified with -f. You can use the --project-directory option to override this base path.

elazarcoh avatar Jun 17 '24 05:06 elazarcoh