Dockerfile.cnb 6.13 KB
# syntax=docker/dockerfile:1
# ================================================================
# Multi-stage build for minimal container image
# Uses COPY technique: builder stage downloads + extracts,
# final stage only copies runtime artifacts.
# ================================================================

# ---- Stage 1: Builder (downloads + extracts) ----
FROM debian:13.4-slim AS builder

RUN apt-get update && \
    apt-get install -y --no-install-recommends \
        ca-certificates curl unzip && \
    rm -rf /var/lib/apt/lists/*

# Python (Miniconda)
RUN curl -sSLk https://mirrors.tuna.tsinghua.edu.cn/anaconda/miniconda/Miniconda3-py312_26.3.2-2-Linux-x86_64.sh \
        -o /tmp/miniconda.sh && \
    bash /tmp/miniconda.sh -b -p /usr/local/miniconda3 && \
    rm /tmp/miniconda.sh && \
    /usr/local/miniconda3/bin/conda clean -a -y

# Node.js (prebuilt binary, no build tools needed)
RUN curl -sSLk https://unofficial-builds.nodejs.org/download/release/v22.22.2/node-v22.22.2-linux-x64-glibc-217.tar.gz \
        -o /tmp/node.tar.gz && \
    tar -xzf /tmp/node.tar.gz -C /usr/local/ && \
    rm /tmp/node.tar.gz && \
    ln -sf /usr/local/node-v22.22.2-linux-x64-glibc-217/bin/node /usr/local/bin/node && \
    ln -sf /usr/local/node-v22.22.2-linux-x64-glibc-217/bin/npm /usr/local/bin/npm

# Bun
RUN curl -fsSL https://bun.sh/install | BUN_INSTALL=/usr/local/bun bash

# opencode-ai + strip unnecessary platform binaries
RUN npm i -g opencode-ai --registry https://mirrors.cloud.tencent.com/npm/ && \
    rm -rf /usr/local/node-v22.22.2-linux-x64-glibc-217/lib/node_modules/opencode-ai/node_modules/opencode-linux-x64-musl && \
    rm -rf /usr/local/node-v22.22.2-linux-x64-glibc-217/lib/node_modules/opencode-ai/node_modules/opencode-linux-x64-baseline && \
    rm -rf /usr/local/node-v22.22.2-linux-x64-glibc-217/lib/node_modules/opencode-ai/node_modules/opencode-linux-x64-baseline-musl && \
    npm cache clean --force

# ---- Stage 2: Minimal final image ----
FROM debian:13.4-slim

# Mirror (China mainland)
RUN sed -i 's/deb.debian.org/mirrors.tencent.com/g' /etc/apt/sources.list.d/debian.sources

# System packages + Claude Code (single RUN layer for minimal size)
RUN apt-get update && \
    apt-get install -y --no-install-recommends \
        ca-certificates curl wget unzip \
        git git-lfs \
        zsh tmux \
        ripgrep jq sudo \
        vim \
        tzdata locales \
        lsof nload htop net-tools dnsutils \
        openssh-server && \
    # Claude Code official apt repo
    install -d -m 0755 /etc/apt/keyrings && \
    curl -fsSL https://downloads.claude.ai/keys/claude-code.asc \
        -o /etc/apt/keyrings/claude-code.asc && \
    chmod a+r /etc/apt/keyrings/claude-code.asc && \
    echo "deb [signed-by=/etc/apt/keyrings/claude-code.asc] https://downloads.claude.ai/claude-code/apt/stable stable main" \
        > /etc/apt/sources.list.d/claude-code.list && \
    apt-get update && \
    apt-get install -y --no-install-recommends claude-code && \
    apt-get clean && \
    rm -rf /var/lib/apt/lists/*

# Create non-root user
RUN useradd -m -s /bin/bash user && \
    echo "user:123456" | chpasswd && \
    adduser user sudo && \
    echo "user ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers

# Copy Python/Node/Bun/opencode from builder (COPY technique)
COPY --from=builder /usr/local/miniconda3 /usr/local/miniconda3
COPY --from=builder /usr/local/node-v22.22.2-linux-x64-glibc-217 /usr/local/node-v22.22.2-linux-x64-glibc-217
COPY --from=builder /usr/local/bun /usr/local/bun

RUN ln -sf /usr/local/node-v22.22.2-linux-x64-glibc-217/bin/node /usr/local/bin/node && \
    ln -sf /usr/local/node-v22.22.2-linux-x64-glibc-217/bin/npm /usr/local/bin/npm && \
    ln -sf /usr/local/bun/bin/bun /usr/local/bin/bun

ENV PATH="/usr/local/miniconda3/bin:/usr/local/node-v22.22.2-linux-x64-glibc-217/bin:/usr/local/bun/bin:${PATH}"

# Helix: pre-built binary + config from context (COPY technique)
COPY helix_config/ /opt/helix_config/
RUN mkdir -p /home/user/.config && \
    ln -sf /opt/helix_config /home/user/.config/helix && \
    chown -R user:user /home/user/.config
ENV PATH="/opt/helix_config/bin:${PATH}"
ENV HELIX_RUNTIME=/opt/helix_config

# Scripts for runtime use
COPY scripts/ /home/user/scripts/
RUN chown -R user:user /home/user/scripts && \
    chmod +x /home/user/scripts/*.sh

# code-server
RUN curl -fsSL https://code-server.dev/install.sh | sh

# code-server extensions (run as user so they install to ~/.local)
USER user
RUN code-server --install-extension golang.go \
    && code-server --install-extension cnbcool.cnb-welcome \
    && code-server --install-extension formulahendry.code-runner \
    && code-server --install-extension ms-kubernetes-tools.vscode-kubernetes-tools \
    && code-server --install-extension tencent-cloud.coding-copilot \
    && code-server --install-extension github.github-vscode-theme \
    && code-server --install-extension ms-ceintl.vscode-language-pack-zh-hans \
    && code-server --install-extension eddieposey.vscode-icons-mac \
    && code-server --install-extension oderwat.indent-rainbow \
    && code-server --install-extension yzhang.markdown-all-in-one

USER root

# oh-my-zsh (install as user so config lands in /home/user/)
USER user
RUN RUNZSH=no CHSH=no sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)"
USER root
RUN chsh -s $(which zsh) user

# Neovim
RUN curl -fsSL https://github.com/neovim/neovim/releases/download/v0.12.2/nvim-linux-x86_64.tar.gz \
        -o /tmp/nvim.tar.gz && \
    tar xf /tmp/nvim.tar.gz -C /usr/local && \
    ln -sf /usr/local/nvim-linux-x86_64/bin/nvim /usr/bin/nvim && \
    rm /tmp/nvim.tar.gz

# tmux config (user's home)
RUN cd /home/user && \
    git clone --single-branch https://github.com/gpakosz/.tmux.git && \
    ln -s -f .tmux/.tmux.conf && \
    cp .tmux/.tmux.conf.local . && \
    chown -R user:user /home/user

# Locale (Chinese + English)
RUN sed -i '/en_US.UTF-8/s/^# //g' /etc/locale.gen && \
    localedef -i zh_CN -c -f UTF-8 -A /usr/share/locale/locale.alias zh_CN.UTF-8 && \
    dpkg-reconfigure --frontend=noninteractive locales

ENV TZ=Asia/Shanghai
ENV GIT_TERMINAL_PROMPT=0
ENV LANG=zh_CN.UTF-8
ENV LANGUAGE=zh_CN:zh

WORKDIR /home/user
USER user