# syntax=docker/dockerfile:1 # ── Stage 1: Build Go gateway binary ──────────────────────────────────────── FROM golang:1.25-bookworm AS builder WORKDIR /src COPY go.mod go.sum ./ RUN go mod download COPY . . # 优化:去除符号表(-s -w)减小体积,CGO_ENABLED=0 确保静态链接 RUN CGO_ENABLED=0 GOOS=linux go build -trimpath -ldflags="-s -w" -o /out/server ./cmd/server # ── Stage 2: Build gopls ──────────────────────────────────────────────────── FROM golang:1.25-bookworm AS gopls-builder # 优化:静态编译 gopls,避免 GLIBC 版本依赖问题 RUN CGO_ENABLED=0 go install golang.org/x/tools/gopls@latest # ── Stage 3: Runtime ──────────────────────────────────────────────────────── FROM eclipse-temurin:22-jdk-noble ARG NODE_MAJOR=22 # ---- System deps ---- # 🔴 关键修复:必须安装 git,否则 gopls 无法拉取依赖 # python3: JDTLS 需要 # nodejs: TS Server 需要 RUN apt-get update && \ apt-get install -y --no-install-recommends \ ca-certificates \ curl \ python3 \ git \ gnupg && \ mkdir -p /etc/apt/keyrings && \ curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg && \ echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_${NODE_MAJOR}.x nodistro main" | tee /etc/apt/sources.list.d/nodesource.list && \ apt-get update && \ apt-get install -y --no-install-recommends nodejs && \ apt-get clean && \ rm -rf /var/lib/apt/lists/* # ---- typescript-language-server + pyright (Python LSP) ---- RUN npm install -g typescript-language-server typescript pyright && \ npm cache clean --force # ---- Go toolchain (Optimized) ---- COPY --from=golang:1.25-bookworm /usr/local/go /usr/local/go # 🟡 建议:设置 GOPROXY 加速依赖下载 (gopls 需要) ENV PATH="/usr/local/go/bin:/go/bin:${PATH}" \ GOPATH="/go" \ GOPROXY="https://goproxy.io,direct" # ---- gopls ---- COPY --from=gopls-builder /go/bin/gopls /go/bin/gopls # ---- Eclipse JDT Language Server ---- # !!! 请确保当前目录下有这个文件夹 !!! COPY jdt-language-server-1.57.0-202602111032 /opt/jdtls RUN chmod +x /opt/jdtls/bin/jdtls /opt/jdtls/bin/jdtls.py # ---- Gateway Setup ---- WORKDIR /app COPY --from=builder /out/server /app/server # ---- 默认配置 ---- COPY <<'EOF' /app/config.json { "port": "8080", "workspaceDir": "/workspace", "allowOrigin": "*", "requestTimeout": "30s", "sessionTTL": "20m", "cleanupInterval": "2m", "maxSessions": 256, "enableRedis": false, "appEnv": "prod", "logLevel": "info", "logConsoleEnabled": true, "logDir": "/app/logs", "servers": [ { "language": "go", "languageId": "go", "command": "gopls", "args": [] }, { "language": "javascript", "languageId": "javascript", "command": "typescript-language-server", "args": ["--stdio"] }, { "language": "typescript", "languageId": "typescript", "command": "typescript-language-server", "args": ["--stdio"] }, { "language": "java", "languageId": "java", "command": "/opt/jdtls/bin/jdtls", "args": [] }, { "language": "python", "languageId": "python", "command": "pyright-langserver", "args": ["--stdio"] } ] } EOF # ---- 权限与目录 ---- RUN mkdir -p /workspace /go /app/logs && \ groupadd --system app && \ useradd --system --gid app --home-dir /home/app --create-home app && \ chown -R app:app /app /workspace /go /home/app /app/logs ENV PORT=8080 \ WORKSPACE_DIR=/workspace VOLUME ["/app/logs"] EXPOSE 8080 USER app # 🔴 关键:用 entrypoint 脚本在启动时写 go.mod,避免被 volume 挂载覆盖 # 如果 /workspace 下还没有 go.mod,自动创建一个最小的 ENTRYPOINT ["sh", "-c", "test -f /workspace/go.mod || printf 'module workspace\n\ngo 1.25\n' > /workspace/go.mod; exec /app/server"]