Support custom entrypoint and command script hooks in the main Workspace container
The current editor injector implementation specifies an entrypoint for the main container. This entrypoint starts the VS Code server.
In the future, we would like to support custom entrypoints and commands in the main Workspace containers
Vishal's description of the problem and suggested solution
make a local docker container work with local WebIDE server. (I'll use yours as an example, could you please post here a link?)
I'm not sure what you mean here. Are you referring to registry.gitlab.com/gitlab-com/create-stage/editor-poc/remote-development/gitlab-rd-web-ide-docker:0.1-alpha
?
have a look if I can find some editor injector example code that's licensed favourably
This is what we have to do, as I think -
Build a multi-architecture container image of our vscode-fork. This image would contain the package for that architecture and a script which will
- copy the contents of the said package to a location
- inject running the editor into the workspace's main container's entrypoint/command
e.g. We build multi-architecture container image for gitlab-web-ide-vscode-fork
with the command
docker buildx build \
--push \
--platform linux/arm64/v8,linux/amd64 \
--tag registry.gitlab.com/gitlab-org/gitlab-web-ide-vscode-fork \
.
To recap -
- The
ENTRYPOINT
specifies a command that will always be executed when the container starts. - The
CMD
specifies arguments that will be fed to theENTRYPOINT
.
Now imagine the user wants to run the docker/getting-started
container image. When we inspect the image, we get the following
docker inspect docker/getting-started
[
{
...
"ContainerConfig": {
"Hostname": "",
"Domainname": "",
"User": "",
"AttachStdin": false,
"AttachStdout": false,
"AttachStderr": false,
"Tty": false,
"OpenStdin": false,
"StdinOnce": false,
"Env": null,
"Cmd": null,
"Image": "",
"Volumes": null,
"WorkingDir": "",
"Entrypoint": null,
"OnBuild": null,
"Labels": null
},
"DockerVersion": "",
"Author": "",
"Config": {
"Hostname": "",
"Domainname": "",
"User": "",
"AttachStdin": false,
"AttachStdout": false,
"AttachStderr": false,
"ExposedPorts": {
"80/tcp": {}
},
"Tty": false,
"OpenStdin": false,
"StdinOnce": false,
"Env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
"NGINX_VERSION=1.23.3",
"PKG_RELEASE=1",
"NJS_VERSION=0.7.9"
],
"Cmd": [
"nginx",
"-g",
"daemon off;"
],
"Image": "",
"Volumes": null,
"WorkingDir": "",
"Entrypoint": [
"/docker-entrypoint.sh"
],
"OnBuild": null,
"Labels": {
"maintainer": "NGINX Docker Maintainers <docker-maint@nginx.com>"
},
"StopSignal": "SIGQUIT"
},
"Architecture": "arm64",
"Os": "linux",
...
}
]
Calculate the final Entrypoint
and Cmd
of the main container by inspecting it are
Entrypoint = first-not-null-value-of( .Config.Entrypoint, ["/bin/sh","-c"] )
Cmd = .Config.Cmd
In the case of running docker/getting-started
container image, the values we would from inspection are get are
Entrypoint = first-not-null-value-of( ["/docker-entrypoint.sh"], ["/bin/sh","-c"] ) = ["/docker-entrypoint.sh"]
Cmd = ["nginx","-g","daemon off;"]
Now create a script which copies the content binaries for running the editor, runs the editor and then runs the container's entrypoint/cmd. Example would be
# Let's call this script init.sh
# copy the editor to the mounted volume location
cp source destination
# run the editor
"./${VSCODE_REH_DIR}/bin/code-server-oss" --host "0.0.0.0"
# run the container's entrypoint/command
# "$Entrypoint" "$Command"
"/docker-entrypoint.sh" "nginx" "-g" "daemon off;"
The script would be available in the multi-architecture docker image we built earlier.
Now, we will set the workspace's ContainerConfig.Entrypoint
= ["/bin/sh","-c"]
and ContainerConfig.Cmd
= init.sh
try to create a file like this for the new docker image
Let's keep this on hold for now
P.S. - I feel like this now after writing this comment. I haven't tested it out. So let's pair on it if you'd like
After having slept on it, I think we should do the following
- Create multi-arch image which also has a script to copy the editor to a volume mount( say
init.sh
- We can use this image by setting the command of the main container of the workspace to this script (
init.sh
)
Once we have done that, let's figure out how Eclipse Che and DWO are taking of such scenarios - when docker image has a entrypoint and command and when that is overriden through pod-overrides
and container-overrides
in the devfile. Then decide how we want to do further improve it.
WDYT?
Chad's follow-up suggestion to support a `pre` and `post` hook (from this comment)
Add support in Remote Development to not completely override the default entrypoint/arg of the container (which are called command/args in Kuberntes) by doing something like this
This looks like a promising approach.
We could even make this more generic, by allowing an optional "pre" and "post" script to be run if they exist.
The script could look something like this:
# Run the pre-command hook only if it exists and is executable
if [ -f "${volume_path}/pre_command_hook.sh" ] && [ -x "${volume_path}/pre_command_hook.sh" ]; then
"${volume_path}/pre_command_hook.sh"
fi
# Run the default command, if any
if [ -n "$*" ]; then
exec "$@"
fi
# Run the post-command hook only if it exists and is executable
if [ -f "${volume_path}/post_command_hook.sh" ] && [ -x "${volume_path}/post_command_hook.sh" ]; then
"${volume_path}/post_command_hook.sh"
fi
We could also optionally make the names/locations of these scripts configurable somehow.
TASKS
-
Address the following suggestion from review (!105783 (comment 1374894393)): "I suggest looking into creating children of Config::Entry::Root to define the structure of the devfile in code. This is how CI yml config files are loaded and it provides a framework for parsing config files in a standardized and understandable way." -
Ideally, support a pre
andpost
script hook, with configurable paths for each.