refactor(code-server): install Docker CLI, plugins and gh into home

- Drop the Docker and GitHub apt repositories and the Ruby build headers
  from the image; keep build-essential, bubblewrap, zip and unzip.
- Document home installs for the Docker CLI with its Compose and Buildx
  plugins, gh, Go, Rust, Python, Node and Java, ordered so each installer
  writes to ~/.zshrc and SDKMAN stays last.
- Drop the Ruby, GitLab CLI and jq instructions.
This commit is contained in:
tiennm99 committed 2026-10-06 14:43:56 +07:00
1 parent c1ef9e7680
commit ee2f92de19
2 files changed
+79 -83

No files matched your search

-24
View File
@@ -6,30 +6,6 @@ USER root
RUN apt-get update \ RUN apt-get update \
&& apt-get install -y --no-install-recommends \ && apt-get install -y --no-install-recommends \
build-essential bubblewrap unzip zip \ build-essential bubblewrap unzip zip \
libffi-dev libssl-dev libyaml-dev zlib1g-dev \
&& rm -rf /var/lib/apt/lists/*
# Docker CLI with the Compose and Buildx plugins, from Docker's apt repository,
# and GitHub CLI, from GitHub's apt repository.
RUN install -m 0755 -d /etc/apt/keyrings \
&& curl -fsSL https://download.docker.com/linux/debian/gpg \
-o /etc/apt/keyrings/docker.asc \
&& curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg \
-o /etc/apt/keyrings/githubcli-archive-keyring.gpg \
&& chmod a+r /etc/apt/keyrings/docker.asc /etc/apt/keyrings/githubcli-archive-keyring.gpg \
&& printf '%s\n' \
'Types: deb' \
'URIs: https://download.docker.com/linux/debian' \
"Suites: $(. /etc/os-release && echo "$VERSION_CODENAME")" \
'Components: stable' \
"Architectures: $(dpkg --print-architecture)" \
'Signed-By: /etc/apt/keyrings/docker.asc' \
> /etc/apt/sources.list.d/docker.sources \
&& echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" \
> /etc/apt/sources.list.d/github-cli.list \
&& apt-get update \
&& apt-get install -y --no-install-recommends \
docker-ce-cli docker-buildx-plugin docker-compose-plugin gh \
&& rm -rf /var/lib/apt/lists/* && rm -rf /var/lib/apt/lists/*
# Workspace directory, owned by the container user. # Workspace directory, owned by the container user.
+79 -59
View File
@@ -4,17 +4,25 @@
official `codercom/code-server` image. official `codercom/code-server` image.
The image ships code-server on Debian with `git`, `zsh`, `curl`, `sudo` and a The image ships code-server on Debian with `git`, `zsh`, `curl`, `sudo` and a
few editors. The `Dockerfile` adds `build-essential`, `bubblewrap`, `zip`, few editors. The `Dockerfile` adds `build-essential`, `bubblewrap`, `zip` and
`unzip`, the headers Ruby builds against, the Docker CLI with its Compose and `unzip`, and wraps the entrypoint so it starts in `/workspace` and `coder` can
Buildx plugins, and the GitHub CLI, and wraps the entrypoint so it starts in use the Docker socket. Language toolchains and CLIs are installed into home,
`/workspace` and `coder` can use the Docker socket. Language toolchains and below.
other CLIs are installed into home, below.
## Toolchains ## Toolchains
Only `/home/coder` and `/workspace` survive a redeploy, so install toolchains Only `/home/coder` and `/workspace` survive a redeploy, so install toolchains
and CLIs into home from the editor's terminal. Each command below was tested in and CLIs into home from the editor's terminal. Each command below was tested in
the image. Open a new terminal afterwards so the `PATH` changes apply. the image, in this order. Open a new terminal afterwards so the `PATH` changes
apply.
The terminal is zsh, and the image ships no `~/.zshrc`. Create it first, with
`~/.local/bin` on `PATH` for the binaries below:
```sh
mkdir -p ~/.local/bin
echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.zshrc
```
### Official install methods ### Official install methods
@@ -43,38 +51,36 @@ curl -LsSf https://astral.sh/uv/install.sh | sh
uv python install 3.13 uv python install 3.13
``` ```
Ruby, with rbenv and its ruby-build plugin, each cloned with git as their Rust, with rustup, from the [install page](https://rustup.rs/). The toolchain
READMEs document ([rbenv](https://github.com/rbenv/rbenv#basic-git-checkout), lives in `~/.rustup`, and `cargo` with the tools it installs in `~/.cargo/bin`;
[ruby-build](https://github.com/rbenv/ruby-build#clone-as-rbenv-plugin-using-git)). rustup adds itself to `~/.zshenv`. `-y` accepts the default install:
Debian's `ruby` package is 3.3, several releases behind. Rubies are compiled into
`~/.rbenv/versions` against the headers the `Dockerfile` installs.
`rbenv init` adds itself to the login shell's startup file, `~/.zprofile`:
```sh ```sh
git clone https://github.com/rbenv/rbenv.git ~/.rbenv curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
~/.rbenv/bin/rbenv init . "$HOME/.cargo/env"
eval "$(~/.rbenv/bin/rbenv init - zsh)"
git clone https://github.com/rbenv/ruby-build.git "$(rbenv root)"/plugins/ruby-build
V=$(rbenv install -l 2>/dev/null | grep -E '^[0-9]+\.[0-9]+\.[0-9]+$' | tail -1)
rbenv install "$V" && rbenv global "$V"
``` ```
To get newer Ruby versions listed, `git -C "$(rbenv root)"/plugins/ruby-build pull`. Docker Compose and Buildx, as CLI plugins in `~/.docker/cli-plugins`, the
manual install from the
Java, with SDKMAN, from its [install guide](https://sdkman.io/install/). [Compose docs](https://docs.docker.com/compose/install/linux/#install-the-plugin-manually)
SDKMAN and every JDK it installs live in `~/.sdkman`; the installer adds itself and the [Buildx README](https://github.com/docker/buildx#manual-download). The
to `~/.bashrc` and `~/.zshrc`, and needs the `zip` and `unzip` the `Dockerfile` Docker client itself is below:
installs. `sdk install java` with no version takes SDKMAN's default, the
current Temurin LTS:
```sh ```sh
curl -s "https://get.sdkman.io" | bash DOCKER_CONFIG=${DOCKER_CONFIG:-$HOME/.docker}
. "$HOME/.sdkman/bin/sdkman-init.sh" mkdir -p "$DOCKER_CONFIG/cli-plugins"
sdk install java ARCH=$(dpkg --print-architecture)
V=$(curl -fsSLI -o /dev/null -w '%{url_effective}' https://github.com/docker/compose/releases/latest | sed 's|.*/||')
curl -fsSL "https://github.com/docker/compose/releases/download/$V/docker-compose-linux-$(uname -m)" -o "$DOCKER_CONFIG/cli-plugins/docker-compose"
V=$(curl -fsSLI -o /dev/null -w '%{url_effective}' https://github.com/docker/buildx/releases/latest | sed 's|.*/||')
curl -fsSL "https://github.com/docker/buildx/releases/download/$V/buildx-$V.linux-$ARCH" -o "$DOCKER_CONFIG/cli-plugins/docker-buildx"
chmod +x "$DOCKER_CONFIG/cli-plugins/docker-compose" "$DOCKER_CONFIG/cli-plugins/docker-buildx"
``` ```
`sdk list java` shows other vendors and versions, and `sdk install gradle` or To upgrade them, run the same commands again.
`sdk install maven` adds a build tool the same way.
### Suggested by AI, may not be the optimal way ### Suggested by AI, may not be the optimal way
@@ -90,29 +96,52 @@ puts tools in `~/go/bin`:
```sh ```sh
V=$(curl -fsSL 'https://go.dev/VERSION?m=text' | head -1) V=$(curl -fsSL 'https://go.dev/VERSION?m=text' | head -1)
mkdir -p ~/.local
curl -fsSL "https://go.dev/dl/$V.linux-$(dpkg --print-architecture).tar.gz" | tar -C ~/.local -xzf - curl -fsSL "https://go.dev/dl/$V.linux-$(dpkg --print-architecture).tar.gz" | tar -C ~/.local -xzf -
echo 'export PATH="$HOME/.local/go/bin:$HOME/go/bin:$PATH"' >> ~/.bashrc echo 'export PATH="$HOME/.local/go/bin:$HOME/go/bin:$PATH"' >> ~/.zshrc
``` ```
To upgrade Go, `rm -rf ~/.local/go` and run the same commands again, without To upgrade Go, `rm -rf ~/.local/go` and run the same commands again, without
the `echo` line. the `echo` line.
jq, the binary from its Docker CLI and GitHub CLI, as the release binaries each project publishes,
[releases page](https://github.com/jqlang/jq/releases), into `~/.local/bin`, into `~/.local/bin`:
with no documented location:
- Docker: [static binaries](https://docs.docker.com/engine/install/binaries/),
documented for `/usr/bin`. Only the client is taken; the daemon is the
host's, through the socket.
- GitHub CLI: the `.tar.gz` on [cli.github.com](https://cli.github.com/), with
no documented location.
```sh ```sh
mkdir -p ~/.local/bin
echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.bashrc
ARCH=$(dpkg --print-architecture) ARCH=$(dpkg --print-architecture)
V=$(curl -fsSLI -o /dev/null -w '%{url_effective}' https://github.com/jqlang/jq/releases/latest | sed 's|.*/||') V=$(curl -fsSL https://download.docker.com/linux/static/stable/$(uname -m)/ | grep -o 'docker-[0-9.]*\.tgz' | sort -V | tail -1)
curl -fsSL "https://github.com/jqlang/jq/releases/download/$V/jq-linux-$ARCH" -o ~/.local/bin/jq && chmod +x ~/.local/bin/jq curl -fsSL "https://download.docker.com/linux/static/stable/$(uname -m)/$V" | tar -C ~/.local/bin -xzf - --strip-components=1 docker/docker
V=$(curl -fsSLI -o /dev/null -w '%{url_effective}' https://github.com/cli/cli/releases/latest | sed 's|.*/v||')
curl -fsSL "https://github.com/cli/cli/releases/download/v$V/gh_${V}_linux_$ARCH.tar.gz" | tar -C ~/.local/bin -xzf - --strip-components=2 "gh_${V}_linux_$ARCH/bin/gh"
``` ```
To upgrade it, run the same commands again, without the `echo` line; the new To upgrade one, run the `ARCH=` line and that tool's two lines again; the
binary overwrites the old one. new binary overwrites the old one.
### Java, last
Java, with SDKMAN, from its [install guide](https://sdkman.io/install/).
SDKMAN and every JDK it installs live in `~/.sdkman`; it needs the `zip` and
`unzip` the `Dockerfile` installs. Its installer appends to `~/.zshrc` and
requires its lines to stay at the end of the file, so install it after
everything above. `sdk install java` with no version takes SDKMAN's default,
the current Temurin LTS:
```sh
curl -s "https://get.sdkman.io" | bash
. "$HOME/.sdkman/bin/sdkman-init.sh"
sdk install java
```
`sdk list java` shows other vendors and versions, and `sdk install gradle` or
`sdk install maven` adds a build tool the same way.
## Environment ## Environment
@@ -141,8 +170,8 @@ its `\h` uses the real hostname.
## Docker access ## Docker access
The host's Docker socket is bind-mounted at `/var/run/docker.sock`. The The host's Docker socket is bind-mounted at `/var/run/docker.sock`. The image
`Dockerfile` installs the client only; the daemon is the host's. Containers ships no Docker CLI; install the client into home as above. Containers
started through it are siblings on the host, not children, so bind mounts in started through it are siblings on the host, not children, so bind mounts in
them resolve against host paths. them resolve against host paths.
@@ -197,23 +226,14 @@ The home volume needs no such step, because the image already ships
`build-essential`, `bubblewrap`, `zip` and `unzip` are in the `Dockerfile` `build-essential`, `bubblewrap`, `zip` and `unzip` are in the `Dockerfile`
rather than home because their projects publish no standalone binaries; rather than home because their projects publish no standalone binaries;
Debian's packages are the install method, and they land outside home. Debian's packages are the install method, and they land outside home. The base
`build-essential` supplies the `gcc` and `make` that native builds expect: image ships none of them. `build-essential` supplies the `gcc` and `make` that
node-gyp addons, Python sdists, Rust crates using `cc`, and Ruby built by native builds expect: the linker `cargo` calls, node-gyp addons and Python
rbenv. `libffi-dev`, `libssl-dev`, `libyaml-dev` and `zlib1g-dev` are the sdists.
headers a rbenv-built Ruby needs for its `fiddle`, `openssl`, `psych` and
`zlib` extensions; without them `rbenv install` fails or leaves those out.
The Docker CLI, its Compose and Buildx plugins, and the GitHub CLI come from Everything else lives in home rather than the image, so the image build stays
Docker's and GitHub's signed apt repositories, which is each vendor's documented small and a redeploy does not reinstall or upgrade tools behind your back;
install for Debian. Neither documents an install into home, and Coolify builds upgrading is the same commands run again.
with `--pull`, so they update with each rebuild rather than by hand. The GitLab
CLI is not in the image: GitLab publishes no apt repository, only Homebrew and
a community one.
Copies of `docker`, `gh` or the plugins left in `~/.local/bin` or
`~/.docker/cli-plugins` from an older setup take precedence over the image's
and should be deleted.
## Shell ## Shell