Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature request: Allow dynamic "runArgs" for docker #3972

Open
dslijepcevic opened this issue Nov 7, 2020 · 21 comments
Open

Feature request: Allow dynamic "runArgs" for docker #3972

dslijepcevic opened this issue Nov 7, 2020 · 21 comments
Assignees
Labels
containers Issue in vscode-remote containers feature-request Request for new features or functionality under-discussion Issue is under discussion for relevance, priority, approach
Milestone

Comments

@dslijepcevic
Copy link

Could you somehow support a way of building and passing dynamic arguments to the docker run command? We currently only have runArgs array in devcontainer.json that is static in nature and not suitable for any sort of scripting. One use case could be, for example, to mount some extra volumes conditionally while keeping all the nice automatic devcontainer infrastructure that the remote extension has to offer. It'd be enough just to include a shell call somewhere. For example, you could introduce a string version of runArgs that would be included verbatim in the default docker run command and then the entire command would be executed by the shell. Or you could introduce a runCommand override with some pre-defined variables that users would then include in the command they specify. You could also support variables like ${workspaceFolder} in remote.containers.dockerPath so that we can hack our way through :) Thanks

@github-actions github-actions bot added the containers Issue in vscode-remote containers label Nov 7, 2020
@chrmarti
Copy link
Contributor

chrmarti commented Nov 9, 2020

There is "initializeCommand", we would then have to reread the devcontainer.json to pick up any changes (we currently don't).

@chrmarti chrmarti self-assigned this Nov 9, 2020
@chrmarti chrmarti added the feature-request Request for new features or functionality label Nov 9, 2020
@dslijepcevic
Copy link
Author

dslijepcevic commented Nov 9, 2020

There is "initializeCommand", we would then have to reread the devcontainer.json to pick up any changes (we currently don't).

If I understood you correctly, you mean to have a self-modifying .devcontainer.json? That would probably not be the best practice since this file is usually stored in a repo, and besides, current initializeCommand already has a major design flaw that requires hacking around. Maybe something like this:

"linux": {
    "runArgsGeneratorCommand": "echo -e '--arg\nvalue'"
}

where the generator would then write run args to stdout, each one on a separate line if you don't want to deal with the quotes. Or even better, you could introduce a similar dynamic envFileGenerator that would produce VAR=VALUE pairs for the container and standard runArgs (and even docker-compose) to consume.

Currently the whole system is pretty much locked down for any non-static content. Even with docker-compose.yml where you can specify multiple compose files, you are not able to generate the dynamic ones in a temporary directory via initializeCommand rather than poluting the source/repo folder because it is not possible to reference /tmp/$TMPDIR/%TEMP%/workspaceHash in a portable way.

@chrmarti
Copy link
Contributor

chrmarti commented Nov 9, 2020

You could add --env-file to runArgs for a file you generate in initializeCommand. Would that work? (It sounds like you mainly need environment variables.)

@dslijepcevic
Copy link
Author

No, that would not work for mounting an extra volume based on user's environment, for example. This information needs to be passed directly to docker run.

Also, currently there is no clean way for initializeCommand to generate a file in platform's temporary directory and then to actually refer to that file path in a portable way in runArgs or docker-compose.yml. VSCode lacks some pre-defined variables like ${hostOS}, ${tmpDir}, ${workspaceHash}, etc. You can only leave a mess in the project directory which is what I'd like to avoid if possible.

@chrmarti
Copy link
Contributor

You could add that file to .gitignore. What is the extra volume being used for?

@dslijepcevic
Copy link
Author

dslijepcevic commented Nov 10, 2020 via email

@chrmarti
Copy link
Contributor

You can specify additional mounts with the "mounts" property and there are a few variables (${var}) you can use to make this more dynamic: https://code.visualstudio.com/docs/remote/devcontainerjson-reference#_variables-in-devcontainerjson

@dslijepcevic
Copy link
Author

dslijepcevic commented Nov 10, 2020

Unfortunately, that's not going to work as we need more complex logic for this than a simple variable replacement. Also, mounts cannot reference any newly calculated dynamic value from the environment and there is no way to specify a "null" volume mount in more complex cases -- docker will report an error. Another issue with this approach is that VSCode cannot provide a default value (e.g. ${localEnv:VARIABLE:-defaultValue}) if user's environment variable is not set! To me this seems like a really useful feature and if you do a google search you'll see than an astounding number of people is asking for the same thing.

@chrmarti
Copy link
Contributor

What if we added a "createCommand" property with which you can implement your own docker run call? I haven't thought it through entirely, but it would likely need to handle the case where the container already exists (and might be stopped) and would have to print the container id to its stdout as the result.

@dslijepcevic
Copy link
Author

Hmm, I think that approach would be an overly complicated way to pass a few dynamic args to docker run. Beside making most of the content of .devcontainer.json irrelevant, for automatic start/stop of a container to work seamlessly like before the user would probably need to pass all of these manually:

docker run -a STDOUT -a STDERR -l vsch.quality=stable -l vsch.remote.devPort=0 -l vsch.local.folder=\\wsl$\Ubuntu\proj\test ...

I believe that just making runArgs dynamic in a way similar to what I previously proposed would be simpler. E.g. if runArgs is given as a string, it specifies a shell command to run to get the arguments on stdout, one argument per line. As simple as that. And you add windows, linux and osx overrides for it, like VSCode tasks do so container can be created portably.

@dslijepcevic
Copy link
Author

dslijepcevic commented Nov 19, 2020

@chrmarti How about something like this?

{
    "initializeCommand": [ "${localWorkspaceFolder}/generateArgsFile.sh" ],
    "linux": { // override
        "initializeCommand": "echo -e '--network\nhost' >${localWorkspaceFolder}/.args",
    }

    // either static or from file
    // "runArgs": [ "--arg", "value" ],
    "runArgsFile": "${localWorkspaceFolder}/.args",
    ...
}

It's using existing initializeCommand (albeit with new platform overloads) and seems more elegant than previous proposals. Input file format can be whatever, e.g. json array, yaml, shell-style quoted args, one arg per line, etc.

@dslijepcevic
Copy link
Author

What if we added a "createCommand" property with which you can implement your own docker run call? I haven't thought it through entirely, but it would likely need to handle the case where the container already exists (and might be stopped) and would have to print the container id to its stdout as the result.

@chrmarti Actually, on second thought, I like your idea. However, I'd expect once the container is created for extension to pick it up and run the exact same commands on it like it would normally do. Extension would perform all checks and call this method only if container does not already exist. Also, since Docker does not allow setting of metadata after container creation, there would have to be a way to pass metadata that the extension itself requires for operation to createCommand and, ultimately, to docker run. To keep things simple, if createCommand is defined only a subset of devcontainer.json properties would be available to the user (e.g. no need for build or runArgs, but workspaceFolder or containerUser can be specified, etc.).

@chrmarti
Copy link
Contributor

Related: #12 (comment)

@chrmarti chrmarti modified the milestones: Backlog Candidates, Backlog Nov 20, 2020
@chrmarti chrmarti added the under-discussion Issue is under discussion for relevance, priority, approach label Nov 20, 2020
@richbai90
Copy link

Where was this left? I could really use this feature. My specific use case is developing for a USB peripheral in a dev container. Right now my only 2 options are to update the --device option every time I reconnect the device, or to use --privileged. Privileged is not preferred for a variety of well documented reasons. I have a command shell script that can look up a device by its name and returns the absolute path to the device. I only need a way to use it through vscode now.

@osemmler
Copy link

+1

Any progress?
We would also like to see the ability to dynamically generate runArgs

@rubensa
Copy link

rubensa commented Sep 1, 2022

Any news on this feature request? Is something been done?

Should It be possible, at least, that VSCode interpolates the environment variables in runArgs before passing the args to docker run?

For example, I want to use:

  "runArgs": [
    // GPU support (Direct Rendering Manager)
    "--device",
    "${DRI_DEVICE:-/dev/null}:/dev/dri"
  ],

that generates:

docker run --device ${DRI_DEVICE:-/dev/null}:/dev/dri ...

that ends with error:

docker: bad mode specified: /dev/dri.

as ${DRI_DEVICE:-/dev/null} is not interpolated (to DRI_DEVICE value or /dev/null if DRI_DEVICE env variable is not defined).

@rubensa
Copy link

rubensa commented Sep 5, 2022

I also tried with

  "runArgs": [
    // GPU support (Direct Rendering Manager)
    "--device",
    "$(echo ${DRI_DEVICE:-/dev/null}):/dev/dri"
  ],

hopping that it is sent directly to the command line but no luck, the '$(echo ${DRI_DEVICE:-/dev/null})' is not evaluated.

Looks like this is related to the way the runArgs are passed as the generated command works as expected if manually run:

docker run --device $(echo ${DRI_DEVICE:-/dev/null}):/dev/dri ...

@chrmarti
Copy link
Contributor

chrmarti commented Sep 9, 2022

@rubensa You can use ${localEnv: DRI_DEVICE:/dev/null}.

@bhack
Copy link

bhack commented Oct 19, 2022

It is quite annoying to request to devs to comment-uncomment multiple sections every time they need to switch from CPU to GPU:

keras-team/keras-cv#946
airo-ugent/airo-ros#17

@joezappie
Copy link

joezappie commented Dec 5, 2022

I'm looking to dynamically enable a passthrough serial device if its plugged in. Since docker will fail to run if you specify a device that doesnt exist, I need to check if the device first exists, then add the device to the runsArgs if it does. Sounds like this would be required for something like that.

In our case, for development a serial device is only needed if dealing with hardware. Might not always have a serial USB plugged in or even need one, so to have to have one plugged in just for the container to boot is not preferred.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
containers Issue in vscode-remote containers feature-request Request for new features or functionality under-discussion Issue is under discussion for relevance, priority, approach
Projects
None yet
Development

No branches or pull requests

8 participants
@rubensa @bhack @dslijepcevic @joezappie @richbai90 @chrmarti @osemmler and others