devcontainers / spec

Development Containers: Use a container as a full-featured development environment.
https://containers.dev
Creative Commons Attribution 4.0 International
3.49k stars 217 forks source link

[proposal] Support more lifecycle scripts #229

Open rubensa opened 1 year ago

rubensa commented 1 year ago

comes from https://github.com/microsoft/vscode-remote-release/issues/8308

Support new container's lifecycle commands.

Property Type Description
preDetachCommand string,
array,
object
A command to run each time a tool is going to be detached from the container.
Note that the array syntax will execute the command without a shell. You can learn more about formatting string vs array vs object properties.
postDetachCommand string,
array,
object
A command string or list of command arguments to run on the host machine after a tool has been detached from the container.

:warning: The command is run wherever the source code is located on the host. For cloud services, this is in the cloud.
Note that the array syntax will execute the command without a shell. You can learn more about formatting string vs array vs object properties.
preShutdownCommand string,
array,
object
A command to run before the container is shutdown.
Note that the array syntax will execute the command without a shell. You can learn more about formatting string vs array vs object properties.
postShutdownCommand string,
array,
object
A command string or list of command arguments to run on the host machine after the container is shutdown.

:warning: The command is run wherever the source code is located on the host. For cloud services, this is in the cloud.
Note that the array syntax will execute the command without a shell. You can learn more about formatting string vs array vs object properties.
joshspicer commented 1 year ago

Thanks for posting! I'd be very curious to know if you currently have any potential use-cases for these hooks, or if you just think these would be generally useful to folks.

rubensa commented 1 year ago

I think these would be generally useful but I also, currently, have a use case for the preDetachCommand (or preShutdownCommand).

I'm using the LTeX – LanguageTool grammar/spell checking extension in some projects using the Dev Containers extension.

This extension downloads the ltex-ls library if necessary.

In order for the ltext-ls library to be "cached" among different projects, I have a volume to keep a copy of it.

Currently I have a postAttachCommand that copies the content from the lib folder inside the extension folder (under .vscode-server/extensions) to the volume folder (mounter under the user HOME directory inside the container) and back from the volume folder to the extension folder (to keep it in sync).

The problem with this solution is that, for the first time, when there is no content neither in the volume folder (not used yet by any container) nor in the extension lib folder (the container has just been built), the extension downloads the ltex-ls from the internet.

If the user, then rebuilds (for any reason) the devcontainer then, the same happens again (as the folders could not been synced before disconnecting from the container).

If the user does not rebuild the container but simply closes it, the next time he opens it, the content from extension lib is synced to the volume (so it can be reused by other containers created afterwards -as the same volume is mounted-).

The ideal would be to be able to synchronize the folders just before the container disconnection (preDetachCommand or postShutdownCommand) so the folders could be kept in sync in any case.

@joshspicer If it is not clear and you need more info about my use-case, please just ask.

jkeech commented 1 year ago

Currently I have a postAttachCommand that copies the content from the lib folder inside the extension folder (under .vscode-server/extensions) to the volume folder (mounter under the user HOME directory inside the container) and back from the volume folder to the extension folder (to keep it in sync).

@rubensa, for this use case, instead of trying to copy the files back and forth on startup and shutdown, would be it easier to add a volume mount (or bind mount) into the final destination location under the HOME directory? That way the file edits and reads are directly against the shared copy in the volume and you don't have to worry about the files getting out of sync or needing extra lifecycle hooks to perform synchronization.

rubensa commented 1 year ago

@jkeech The problem with your proposal is that the lib folder is inside the extension folder whose name depends on the extension version which, in my solution, is dynamically resolved but, in your proposal, needs to be determined beforehand (so, with each extension version, the mount point should be "manually" specified).

jkeech commented 1 year ago

Really this case sounds like something that the extension should provide as a configuration option to select the download path for the large asset, which you can then point to whatever volume mount path you want. But I think you could also just put the entire extensions folder in a volume mount to share across containers as long as you don't mind having the same extensions installed in each one.

jkeech commented 1 year ago

Actually it looks like that extension does provide a setting (ltex.ltex-ls.path) to control the path where that file is loaded from. That seems cleaner to me than tweaking the inside of the extensions install directory: https://valentjn.github.io/ltex/settings.html#ltexltex-lspath

rubensa commented 1 year ago

@jkeech Despite it not been relevant for this issue (I was just spotting my particular use case), I want to let you know that, as already specified in the LTeX – LanguageTool grammar/spell checking extension documentation, the problem with manually download ltex-ls:

Each version of LTEX has been tested with exactly one version of ltex-ls, which is the version that LTEX automatically downloads. If you download ltex-ls manually, be sure to use this version of ltex-ls. An older or a newer version of ltex-ls might work, or it might not.

For this reason, this approach is not recommended as automatically updated versions of LTEX (by Visual Studio Code) might not be compatible anymore with your manually downloaded version of ltex-ls. If you choose this approach, remember to update ltex-ls if LTEX doesn’t work anymore.

so you end with the same problem I already told (to have to do thing "manually" specific for the extension version).

MikeJansenNextira commented 9 months ago

A good use case for detach/shutdown commands:

Generally:

Cleanup of temporary files that have security implications.

Specifically:

A development process requires an unencrypted key file. The user is prompted to enter the passphrase (which should be stored in a password manager) in order to decrypt the encrypted key file for use. Normal operation will be that when the session is done, the unencrypted key file is deleted. If the user stops the dev container before ending the session, the unencrypted key file remains. Currently, postStartCommand is used to check for the existence of this file and delete it, which protects from someone starting the dev container and having the key file. It does not protect from someone accessing the key file via the docker volume.

Every additional opportunity to clean up security related files on detach/shutdown will decrease any attack surface.

rubensa commented 4 months ago

Any advance on this topic?

I currently have another use case:

I'm using docker-from-docker and I have a VSCode task to start some containers using docker compose. I also have a task to stop the containers using docker compose but I would like to make sure that the containers are down before closing the connection despite I forgot to manually run the task to stop them.

jenkin commented 2 months ago

Another use case: I need to run two dev containers from two different vscode windows and in the initializeCommand hook I can create a shared network (if it not exists) so they can communicate. But I want to remove the network when both containers are removed on windows close.

...
  "initializeCommand": "docker network inspect my-awesome-network >/dev/null 2>&1 || docker network create --driver bridge my-awesome-network",
  "postShutdownCommand": "docker network inspect -f '{{len .Containers}}' my-awesome-network | grep -q 0 && docker network rm my-awesome-network",
...