Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ This repository contains example images for use with [Coder](https://coder.com/d
- `example-java`: Contains Java development tools.
- `example-node`: Contains Node.js development tools.
- `example-desktop`: Contains a desktop environment accessible via web browser.
- `example-podman`: Contains rootless Podman for building and running
containers without a privileged runtime.

## Images on Docker Hub

Expand Down
9 changes: 5 additions & 4 deletions images/node/ubuntu.Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,11 @@ RUN curl -sL https://deb.nodesource.com/setup_lts.x | bash - && \
DEBIAN_FRONTEND="noninteractive" apt-get update -y && \
apt-get install -y nodejs

# Install Yarn
RUN curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add -
RUN echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list
RUN DEBIAN_FRONTEND="noninteractive" apt-get update && apt-get install -y yarn
# Install Yarn. apt-key was removed from modern Ubuntu releases, so trust
# the Yarn repository via a signed-by keyring instead.
RUN curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | gpg --dearmor -o /usr/share/keyrings/yarnkey.gpg && \
echo "deb [signed-by=/usr/share/keyrings/yarnkey.gpg] https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list && \
DEBIAN_FRONTEND="noninteractive" apt-get update && apt-get install -y yarn
Comment on lines +11 to +15

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unrelated to the Podman image (Yarn keyring fix). It's correct and probably necessary now that apt-key is gone on resolute — but it's invisible in the PR title/body. Worth splitting into its own small PR (would unblock main on its own) or at least calling it out in the description.

From Coder Agents 🤖

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Called it out in the description instead of splitting — main is red either way and this unblocks it in one go.

(posted via Coder Agents on my behalf)


# Set back to coder user
USER coder
31 changes: 31 additions & 0 deletions images/podman/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Podman

[![DockerPulls](https://img.shields.io/docker/pulls/codercom/enterprise-podman)](https://hub.docker.com/r/codercom/enterprise-podman)

## Description

Wraps [enterprise-base](../base/README.md) with rootless
[Podman](https://podman.io), so workspaces can build and run containers
without a privileged container runtime or custom RuntimeClass. `docker` is
aliased to `podman`.

This image was previously published as `ghcr.io/coder/podman` from the
now-archived
[community-templates](https://github.com/coder/community-templates/tree/main/kubernetes-podman)
repository.

## How To Use

Visit
[Docker in Workspaces: Rootless Podman](https://coder.com/docs/admin/templates/extending-templates/docker-in-workspaces#rootless-podman)
for the template changes this image pairs with: an AppArmor `unconfined`
profile for the workspace container and a FUSE device exposed via
smarter-device-manager.

Rootless container storage lives under `~/.local/share/containers/storage`,
so it lands on the workspace home volume with no extra mounts required.

Nodes must have Linux user namespaces enabled
(`sysctl user.max_user_namespaces` greater than 0). Notably,
[Bottlerocket](https://github.com/bottlerocket-os/bottlerocket) disables them
by default, and EKS Auto Mode nodes cannot enable them at all.
16 changes: 16 additions & 0 deletions images/podman/containers.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
[containers]
netns="host"
userns="host"
ipcns="host"
utsns="host"
cgroupns="host"
cgroups="disabled"
log_driver = "k8s-file"
volumes = [
"/proc:/proc",
]
default_sysctls = []
[engine]
cgroup_manager = "cgroupfs"
events_logger="file"
runtime="crun"
36 changes: 36 additions & 0 deletions images/podman/storage.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Storage configuration for rootless Podman inside a Kubernetes pod.
# See man 5 containers-storage.conf for all options.
#
# Note: runroot and graphroot below only apply when Podman runs as root.
# Rootless Podman (the expected mode for this image, running as the coder
# user) stores containers under ~/.local/share/containers/storage instead,
# so no extra volume mounts are required for those paths.

[storage]
# Default storage driver. fuse-overlayfs (set as the mount program below)
# lets the overlay driver work for unprivileged users.
driver = "overlay"

# Temporary storage location (rootful only; see note above)
runroot = "/run/containers/storage"

# Primary read/write location of container storage (rootful only; see note
# above)
graphroot = "/var/lib/containers/storage"
Comment on lines +15 to +19

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Non-blocking question: runroot (/run/containers/storage) and graphroot (/var/lib/containers/storage) sit under root-owned paths, and the image ends as USER coder (uid 1000) without creating/chowning them. Does rootless Podman here rely on the workspace mounting writable volumes at those paths (as the coder/coder#28100 template does)? If so, a one-line note in the README would help anyone using the image on its own. The /var/lib/shared read-only stores look correctly handled.

From Coder Agents 🤖

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good question — neither, actually: rootless Podman ignores runroot/graphroot (those are rootful paths) and stores under ~/.local/share/containers/storage, which lands on the workspace home volume. That's why the verified runs worked with no extra mounts. Added a note to both storage.conf and the README.

(posted via Coder Agents on my behalf)


[storage.options]
# Read-only image stores shared into the image at build time.
additionalimagestores = [
"/var/lib/shared",
]

pull_options = {enable_partial_images = "false", use_hard_links = "false", ostree_repos=""}

[storage.options.overlay]
# Mount via fuse-overlayfs instead of mounting overlayfs directly, which
# unprivileged users cannot do. Pairs with a FUSE device exposed to the pod
# (e.g. via smarter-device-manager).
mount_program = "/usr/bin/fuse-overlayfs"

# Extra mount options
mountopt = "nodev,fsync=0"
43 changes: 43 additions & 0 deletions images/podman/ubuntu.Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
FROM codercom/enterprise-base:ubuntu

# Run everything as root
USER root

# Install Podman and rootless dependencies from Ubuntu's own repositories.
# uidmap provides newuidmap/newgidmap, which rootless Podman requires.
RUN apt-get update && \
DEBIAN_FRONTEND="noninteractive" apt-get install -y --no-install-recommends \
podman \
crun \
fuse-overlayfs \
slirp4netns \
uidmap && \
rm -rf /var/lib/apt/lists/*

# Allow the unprivileged coder user to map subordinate UID/GID ranges for
# rootless containers.
RUN setcap cap_setuid+ep /usr/bin/newuidmap && \
setcap cap_setgid+ep /usr/bin/newgidmap && \
chmod 0755 /usr/bin/newuidmap /usr/bin/newgidmap && \
echo "coder:100000:65536" >/etc/subuid && \
echo "coder:100000:65536" >/etc/subgid

COPY containers.conf /etc/containers/containers.conf
COPY storage.conf /etc/containers/storage.conf
RUN chmod 644 /etc/containers/containers.conf /etc/containers/storage.conf

# Read-only shared image stores referenced by storage.conf.
RUN mkdir -p /var/lib/shared/overlay-images \
/var/lib/shared/overlay-layers \
/var/lib/shared/vfs-images \
/var/lib/shared/vfs-layers && \
touch /var/lib/shared/overlay-images/images.lock \
/var/lib/shared/overlay-layers/layers.lock \
/var/lib/shared/vfs-images/images.lock \
/var/lib/shared/vfs-layers/layers.lock

# Alias "docker" to "podman"
RUN [ -e /usr/bin/docker ] || ln -s /usr/bin/podman /usr/bin/docker

# Set back to coder user
USER coder
1 change: 1 addition & 0 deletions scripts/images.sh
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,5 @@ IMAGES=(
"desktop"
"universal"
"kitchensink"
"podman"
)