Files
code-tools/.devcontainer/Dockerfile
2025-09-29 14:14:30 +00:00

320 lines
11 KiB
Docker

# Start from the universal devcontainer base image
FROM mcr.microsoft.com/devcontainers/universal:2-linux
ARG LAZYGIT_VERSION=0.55.1
ARG LAZYGIT_SHA256=6385a699dde302b7fdcd1cc8910ae225ed0c19a230285569c586051576f0d6a3
ARG LAZYDOCKER_VERSION=0.24.1
ARG LAZYDOCKER_SHA256=461cacf618e1020dff1d7896248c1c1f2267d5c25fb529755e4b9c43c5d1d4a5
ARG SUPERFILE_VERSION=1.3.3
ARG SUPERFILE_SHA256=b74dffa446bdbeaef38cae0815e1714f78d5bffc0b39aafd1bd9f26ef191210a
ARG BTOP_VERSION=1.4.5
ARG BTOP_SHA256=206b0f9334e93c06de9025eaf90676c374ca79815b41dadff1b36ef4e4e6d1d4
ARG CODE_SERVER_VERSION=4.104.2
ARG CODE_SERVER_SHA256=bc650b57fd8d0bcee952c97308dd43ae37ad8dc11b83a713d8eca8ce823fefd9
ARG UV_VERSION=0.8.22
ARG UV_PYTHON_VERSION=3.12.5
ARG GO_VERSION=1.25.1
ARG GO_SHA256=7716a0d940a0f6ae8e1f3b3f4f36299dc53e31b16840dbd171254312c41ca12e
# Switch to root for installations
USER root
# Change codespace user to coder for Coder compatibility
RUN usermod -l coder codespace && \
groupmod -n coder codespace && \
usermod -d /home/coder -m coder
# Install additional development tools not included in features
RUN apt-get update && export DEBIAN_FRONTEND=noninteractive && \
apt-get install -y \
# Terminal tools
ripgrep \
fd-find \
bat \
htop \
ncdu \
ranger \
tmux \
neovim \
tree \
curl \
wget \
unzip \
xz-utils \
# Development tools
jq \
httpie \
software-properties-common \
# Build tools
build-essential \
cmake \
pkg-config \
# Database clients
postgresql-client \
redis-tools \
# Networking tools for port forwarding
socat \
psmisc \
# Additional utilities for scripts
git \
&& apt-get clean && rm -rf /var/lib/apt/lists/*
# Install the Go toolchain from upstream tarball to guarantee a fresh version
RUN set -eux; \
curl -fsSL "https://go.dev/dl/go${GO_VERSION}.linux-amd64.tar.gz" -o /tmp/go.tar.gz; \
echo "${GO_SHA256} /tmp/go.tar.gz" | sha256sum -c -; \
rm -rf /usr/local/go; \
tar -C /usr/local -xzf /tmp/go.tar.gz; \
rm -f /tmp/go.tar.gz
# Install Python 3.12 system-wide and set as default
RUN set -eux; \
add-apt-repository ppa:deadsnakes/ppa -y; \
apt-get update; \
apt-get install -y python3.12 python3.12-venv python3.12-dev; \
python3.12 -m ensurepip --upgrade; \
python3.12 -m pip install --upgrade pip; \
update-alternatives --install /usr/bin/python3 python3 /usr/bin/python3.12 2; \
update-alternatives --set python3 /usr/bin/python3.12; \
update-alternatives --install /usr/bin/python python /usr/bin/python3.12 2; \
update-alternatives --set python /usr/bin/python3.12; \
if command -v pip3.12 >/dev/null 2>&1; then \
ln -sf "$(command -v pip3.12)" /usr/local/bin/pip3; \
ln -sf "$(command -v pip3.12)" /usr/local/bin/pip; \
fi; \
apt-get clean && rm -rf /var/lib/apt/lists/*
# Install pinned CLI utilities that workspaces depend on
RUN set -eux; \
tmpdir=$(mktemp -d); \
cd "$tmpdir"; \
curl -fsSL "https://github.com/yorukot/superfile/releases/download/v${SUPERFILE_VERSION}/superfile-linux-v${SUPERFILE_VERSION}-amd64.tar.gz" -o superfile.tar.gz; \
echo "${SUPERFILE_SHA256} superfile.tar.gz" | sha256sum -c -; \
tar -xzf superfile.tar.gz; \
install -Dm755 "dist/superfile-linux-v${SUPERFILE_VERSION}-amd64/spf" /usr/local/bin/spf; \
curl -fsSL "https://github.com/jesseduffield/lazygit/releases/download/v${LAZYGIT_VERSION}/lazygit_${LAZYGIT_VERSION}_Linux_x86_64.tar.gz" -o lazygit.tar.gz; \
echo "${LAZYGIT_SHA256} lazygit.tar.gz" | sha256sum -c -; \
tar -xzf lazygit.tar.gz lazygit; \
install -Dm755 lazygit /usr/local/bin/lazygit; \
curl -fsSL "https://github.com/jesseduffield/lazydocker/releases/download/v${LAZYDOCKER_VERSION}/lazydocker_${LAZYDOCKER_VERSION}_Linux_x86_64.tar.gz" -o lazydocker.tar.gz; \
echo "${LAZYDOCKER_SHA256} lazydocker.tar.gz" | sha256sum -c -; \
tar -xzf lazydocker.tar.gz lazydocker; \
install -Dm755 lazydocker /usr/local/bin/lazydocker; \
curl -fsSL "https://github.com/aristocratos/btop/releases/download/v${BTOP_VERSION}/btop-x86_64-linux-musl.tbz" -o btop.tbz; \
echo "${BTOP_SHA256} btop.tbz" | sha256sum -c -; \
tar -xjf btop.tbz; \
install -Dm755 btop/bin/btop /usr/local/bin/btop; \
cd /; \
rm -rf "$tmpdir"
# Install code-server into a fixed prefix so the module can run in offline mode
RUN set -eux; \
curl -fsSL "https://github.com/coder/code-server/releases/download/v${CODE_SERVER_VERSION}/code-server-${CODE_SERVER_VERSION}-linux-amd64.tar.gz" -o /tmp/code-server.tar.gz; \
echo "${CODE_SERVER_SHA256} /tmp/code-server.tar.gz" | sha256sum -c -; \
rm -rf /opt/code-server; \
mkdir -p /opt; \
tar -xzf /tmp/code-server.tar.gz -C /opt; \
mv /opt/code-server-${CODE_SERVER_VERSION}-linux-amd64 /opt/code-server; \
ln -sf /opt/code-server/bin/code-server /usr/local/bin/code-server; \
rm -f /tmp/code-server.tar.gz; \
chown -R coder:coder /opt/code-server
# Install the uv Python toolchain manager system-wide
RUN set -eux; \
curl -LsSf https://astral.sh/uv/install.sh | UV_INSTALL_DIR=/usr/local/bin UV_VERSION=${UV_VERSION} sh
# Preinstall JavaScript tooling for all users
RUN set -eux; \
npm install -g --silent \
pnpm@latest \
yarn@latest \
turbo@latest \
@anthropic-ai/claude-code@latest \
vercel@latest \
netlify-cli@latest \
tsx@latest \
nodemon@latest \
tldr@latest \
fkill-cli@latest \
repomix@latest
# Switch to coder user for user-specific installations
USER coder
# Ensure user-local bin directories and system installs are on PATH
ENV PATH="/home/coder/.venv/bin:/usr/local/go/bin:/usr/local/bin:/home/coder/.local/bin:/home/coder/bin:${PATH}"
# Install Rust-based tools using cargo (check if available first)
RUN if [ -f ~/.cargo/env ]; then \
/bin/bash -c "source ~/.cargo/env && cargo install starship zoxide tokei git-delta --locked"; \
elif command -v cargo >/dev/null 2>&1; then \
cargo install starship zoxide tokei git-delta --locked; \
else \
echo "Rust/cargo not available, skipping Rust tools"; \
fi
# Install Python tooling for coder user
RUN echo "Installing Python packages..." && \
uv tool install poetry && \
uv tool install black && \
uv tool install ruff && \
uv tool install mypy && \
uv tool install pytest && \
pip install --user --quiet pipenv httpx rich && \
echo "Python packages installed successfully"
# Preinstall Python 3.12 virtual environment and Marimo environment expected by the template
RUN set -eux; \
uv python install ${UV_PYTHON_VERSION}; \
uv venv --python ${UV_PYTHON_VERSION} /home/coder/.venv; \
/home/coder/.venv/bin/python -m ensurepip --upgrade; \
/home/coder/.venv/bin/python -m pip install --upgrade pip; \
/home/coder/.venv/bin/python -m pip install --upgrade marimo; \
mkdir -p /home/coder/workspaces/notebooks; \
cat <<MARIMO_APP > /home/coder/workspaces/notebooks/welcome.py
import marimo
__generated_with = "0.16.0"
app = marimo.App()
@app.cell
def __():
import marimo as mo
return mo,
@app.cell
def __(mo):
mo.md("# Welcome to Marimo!")
return
@app.cell
def __(mo):
mo.md("This is your interactive notebook environment.")
return
if __name__ == "__main__":
app.run()
MARIMO_APP
# Seed code-server configuration matching the Terraform defaults
RUN set -eux; \
mkdir -p /home/coder/.config/code-server; \
cat <<CONFIG > /home/coder/.config/code-server/config.yaml
bind-addr: 127.0.0.1:13337
auth: none
cert: false
CONFIG
# Create necessary directories and stage workspace helper scripts (if present)
USER root
COPY . /tmp/devcontainer-src
RUN if [ -d /tmp/devcontainer-src/terraform/scripts ]; then \
cp -r /tmp/devcontainer-src/terraform/scripts/*.sh /usr/local/bin/; \
if [ -d /tmp/devcontainer-src/terraform/scripts/agentapi ]; then \
rm -rf /usr/local/bin/agentapi; \
cp -r /tmp/devcontainer-src/terraform/scripts/agentapi /usr/local/bin/agentapi; \
fi; \
elif [ -d /tmp/devcontainer-src/scripts ]; then \
cp -r /tmp/devcontainer-src/scripts/*.sh /usr/local/bin/; \
if [ -d /tmp/devcontainer-src/scripts/agentapi ]; then \
rm -rf /usr/local/bin/agentapi; \
cp -r /tmp/devcontainer-src/scripts/agentapi /usr/local/bin/agentapi; \
fi; \
else \
echo "No workspace helper scripts found; skipping copy"; \
fi && \
find /usr/local/bin -maxdepth 1 -type f -name *.sh -exec chmod +x {} \; && \
rm -rf /tmp/devcontainer-src
# Switch to coder user
USER coder
RUN mkdir -p ~/bin ~/.config
WORKDIR /workspaces
# Set up shell configuration with enhanced aliases and tools
RUN echo 'export PATH="$HOME/.local/bin:$HOME/bin:$PATH"' >> ~/.zshrc && \
echo 'alias ll="ls -la"' >> ~/.zshrc && \
echo 'alias cat="bat"' >> ~/.zshrc && \
echo 'alias find="fd"' >> ~/.zshrc && \
echo '# Rust tools (if available)' >> ~/.zshrc && \
echo 'command -v starship >/dev/null 2>&1 && eval "$(starship init zsh)"' >> ~/.zshrc && \
echo 'command -v zoxide >/dev/null 2>&1 && eval "$(zoxide init zsh)"' >> ~/.zshrc
# Set up IDE configurations if the helper scripts are present
RUN if [ -f /usr/local/bin/cursor-setup.sh ]; then \
/usr/local/bin/cursor-setup.sh; \
else \
echo "cursor-setup.sh not found; skipping"; \
fi && \
if [ -f /usr/local/bin/windsurf-setup.sh ]; then \
/usr/local/bin/windsurf-setup.sh; \
else \
echo "windsurf-setup.sh not found; skipping"; \
fi
# Create devinfo utility
RUN cat <<'EOF' > "$HOME/bin/devinfo" \
&& chmod +x "$HOME/bin/devinfo"
#!/usr/bin/env bash
set -euo pipefail
echo "Workspace diagnostics"
echo "----------------------"
echo "User: $(whoami)"
echo "Home: ${HOME}"
echo "Workspace: /workspaces"
if command -v node >/dev/null 2>&1; then
echo "Node: $(node --version)"
fi
if command -v npm >/dev/null 2>&1; then
echo "npm: $(npm --version)"
fi
if command -v python3 >/dev/null 2>&1; then
echo "Python: $(python3 --version | awk '{print $2}')"
fi
if command -v rustc >/dev/null 2>&1; then
echo "Rust: $(rustc --version | awk '{print $2}')"
fi
if command -v cargo >/dev/null 2>&1; then
echo "Cargo: $(cargo --version | awk '{print $2}')"
fi
if [[ -n "${POSTGRES_URL:-}" ]]; then
echo "PostgreSQL: ${POSTGRES_URL}"
fi
if [[ -n "${REDIS_URL:-}" ]]; then
echo "Redis: ${REDIS_URL}"
fi
if [[ -n "${QDRANT_URL:-}" ]]; then
echo "Qdrant: ${QDRANT_URL}"
fi
EOF
# Create Claude CLI helper
RUN cat <<'EOF' > "$HOME/bin/claude-help" \
&& chmod +x "$HOME/bin/claude-help"
#!/usr/bin/env bash
cat <<'TXT'
Claude CLI quick start
----------------------
claude auth login # authenticate
claude chat # open an interactive chat
claude edit <file> # AI assisted editing
claude analyze . # Review the current directory
TXT
EOF
# Set environment variables for consistent operation
ENV USER_NAME=coder
ENV HOME_DIR=/home/coder
ENV WORKSPACES_DIR=/workspaces
ENV BIN_DIR=/home/coder/bin
ENV META_DIR=/tmp/git-metadata
# Expose common development ports
EXPOSE 3000 5000 8000 8080 8888 5050 6333
# Default command
CMD ["/bin/zsh"]