320 lines
11 KiB
Docker
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"]
|