microsoft / vscode-remote-release

Visual Studio Code Remote Development: Open any folder in WSL, in a Docker container, or on a remote machine using SSH and take advantage of VS Code's full feature set.
https://aka.ms/vscode-remote
Other
3.67k stars 289 forks source link

[Feature request] User-specific features, mounts, extensions and settings for devcontainers #8436

Closed jamiekt closed 1 year ago

jamiekt commented 1 year ago

My team are using devcontainers in a repo that many of us use. We put a lot into the devcontainer, in fact here is our .devcontainer.json which I'm happy to share:

{
  "name": "Innovation Hours - Publish dbt docs",
  "build": {
    "dockerfile": "./Dockerfile"
  },
  "extensions": [
    "github.vscode-github-actions",
    "snowflake.snowflake-vsc",
    "ms-azuretools.vscode-docker",
    "ms-python.vscode-pylance"
],
  "mounts": [
    "source=/var/run/docker.sock,target=/var/run/docker.sock,type=bind",
    "source=${localEnv:HOME}/.aws,target=/root/.aws,type=bind,consistency=cached",
    "source=${localWorkspaceFolder}/.devcontainer/starship.toml,target=/root/.config/starship.toml,type=bind,consistency=cached",
    "source=innovationhours-bashhistory,target=/commandhistory,type=volume"
  ],
  "settings": {
    "terminal.integrated.shell.linux": "/bin/bash",
    "editor.tabSize": 4
  },
  "containerEnv": {
    "USER": "${localEnv:USER}"
  },
  "features": {
    "ghcr.io/devcontainers/features/aws-cli:1": {},
    "ghcr.io/devcontainers/features/github-cli:1": {},
    "ghcr.io/mikaello/devcontainer-features/modern-shell-utils:1": {},
    "ghcr.io/devcontainers/features/docker-outside-of-docker:1": {},
    "ghcr.io/guiyomh/features/vim": {}
  },
  "postCreateCommand": "./.devcontainer/postCreateCommand.sh"
}

and here is the Dockerfile

# Start with a base image of your choice
FROM python:3.10-slim

# Install any necessary dependencies
RUN apt-get update && \
    apt-get install -y curl && \
    apt-get clean

# Install dbt using pip
RUN pip install dbt-snowflake

# Used to persist bash history as per https://code.visualstudio.com/remote/advancedcontainers/persist-bash-history
RUN SNIPPET="export PROMPT_COMMAND='history -a' && export HISTFILE=/commandhistory/.bash_history" \
    && echo "$SNIPPET" >> "/root/.bashrc"

# starship prompt
RUN curl -sS https://starship.rs/install.sh | sh -s -- -f && echo 'eval "$(starship init bash)"' >> ~/.bashrc

# # Copy any necessary files into the container
COPY profiles.yml /root/.dbt/

The postCreateCommand calls a script postCreateCommand.sh that adds some aliases to .bashrc:

# Create aliases in here that you may want to use in the devcontainer
echo alias gd=\'git diff\' >> ~/.bashrc
echo alias gst=\'git status\' >> ~/.bashrc
echo alias gco=\'git checkout\' >> ~/.bashrc
echo alias gcb=\'git checkout -b\' >> ~/.bashrc
echo alias gbD=\'git branch --delete --force\' >> ~/.bashrc
echo alias glo=\'git log --oneline --decorate\' >> ~/.bashrc
echo alias gp=\'git push\' >> ~/.bashrc
echo alias gpf=\'git push --force-with-lease --force-if-includes\' >> ~/.bashrc
echo alias l=\'exa\' >> ~/.bashrc 
echo alias la=\'exa -a\' >> ~/.bashrc 
echo alias ll=\'exa -lah\' >> ~/.bashrc 
echo alias ls=\'exa --color=auto\' >> ~/.bashrc

Here's the problem. Some people want/need to make customisations that are specific to them. Some examples:

  1. In ~/.gitconfig on my host I have
    [commit]
     template = ~/.gitmessage

    (read https://thoughtbot.com/blog/better-commit-messages-with-a-gitmessage-template to understand why)

~/.gitconfig automatically gets mounted in into the devcontainer as I'm sure you know, but of course there is no such file inside the devcontainer. This means every time I issue git commit -a I get an error telling me that .gitmessage doesn't exist. My workaround is to issue git commit -am dummy && git commit --amend which works but is cumbersome.

  1. Some people may want to create aliases that others do not. We could put them in postCreateCommand.sh as mentioned above but that means that file will eventually get littered with different people's aliases.

  2. People may want extensions or features that others do not

I feel there should be better ways of solving these problem. I'd like to see support for user-specific config for devcontainers. For example, to solve the .gitmessage problem I could define a mount that only gets mounted for me. To solve aliases problem I could define a postCreateCommand that is only run for me.

I suggest these could be accomplished by allowing us to define ./.vscode/userdevcontainer.json that might look something like this:

{
  "mounts": [
    "source=${localEnv:HOME}/.gitmessage,target=/root/.gitmessage,type=bind,consistency=cached"
  ],
  "customizations": {
    "vscode": {
      "extensions": [],
      "settings": {
        "terminal.integrated.shell.linux": "/bin/bash",
        "editor.tabSize": 2
      }
    }
  }
  "containerEnv": {
  },
  "features": {
    "ghcr.io/eitsupi/devcontainer-features/jq-likes:1": {}
  },
  "postCreateCommand": "./.vscode/postCreateCommand.sh"
}

./.vscode/userdevcontainer.json would of course not get committed to source control, therefore allowing each user to specify their own customisations. This is just an idea, I suspect other folks could come up with other, better, ways of achieving this.

Bottom-line, I'd like there to be a way to specify user specific features, mounts, extensions and settings for devcontainers.

jamiekt commented 1 year ago

Another use case that has popped up up today...

As you can see in devcontainer.json above we mount the ~/.aws directory:

"source=${localEnv:HOME}/.aws,target=/root/.aws,type=bind,consistency=cached",

this is so that people can continue to interact with AWS via the aws cli tool without having to to re-authenticate.

There are many ways to modify behaviour of aws cli and one such way is to set environment variable $AWS_DEFAULT_PROFILE. I set this on my host machine and it is very useful and I'd like to do the same in the container like so:

"containerEnv": {
    "AWS_DEFAULT_PROFILE": "${localEnv:AWS_DEFAULT_PROFILE}"
}

however that shouldn't be the case for everyone that uses the devcontainer because their ways-of-working may be different. In this case I'd like there be an option for each user of the devcontainer to specify their own env vars that they'd like to use inside the container.

vscodenpa commented 1 year ago

This feature request is now a candidate for our backlog. The community has 60 days to upvote the issue. If it receives 10 upvotes we will move it to our backlog. If not, we will close it. To learn more about how we handle feature requests, please see our documentation.

Happy Coding!

chrmarti commented 1 year ago

Some of what you want to do can be achieved by configuring a dotfiles repository in your user settings. E.g., if the dotfiles repository creates a ~/.gitconfig, the Dev Containers extension will not copy the local ~/.gitconfig to the dev container. A dotfiles install script can also add aliases and environment variables to ~/.bashrc.

chrmarti commented 1 year ago

There is documentation on using dotfiles repositories with Dev Containers here: https://code.visualstudio.com/docs/devcontainers/containers#_personalizing-with-dotfile-repositories. HTH

jamiekt commented 1 year ago

Thank you @chrmarti , that definitely looks very promising indeed. I'll check it out.

jamiekt commented 1 year ago

ok, this seems to work great. I can pretty much do everything I need to using install.sh. Thank you @chrmarti

jamiekt commented 1 year ago

I blogged about using the dotfiles capability at https://medium.com/@jamiekt/vscode-devcontainer-with-zsh-oh-my-zsh-and-agnoster-theme-8adf884ad9f6