feat(tools): unified container dev setup (#65589)

This commit is contained in:
Mrugesh Mohapatra
2026-02-08 12:20:52 +05:30
committed by GitHub
parent b321f075fd
commit 46b607d84a
10 changed files with 337 additions and 148 deletions
+97
View File
@@ -0,0 +1,97 @@
# =============================================================================
# BASE - System dependencies, pnpm, mongosh
# =============================================================================
FROM node:24-bookworm AS base
RUN apt-get update && apt-get install -y --no-install-recommends \
git \
curl \
jq \
gnupg \
sudo \
rsync \
&& rm -rf /var/lib/apt/lists/* \
&& echo "node ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers.d/node
RUN curl -fsSL https://www.mongodb.org/static/pgp/server-8.0.asc | gpg --dearmor -o /usr/share/keyrings/mongodb-archive-keyring.gpg \
&& echo "deb [signed-by=/usr/share/keyrings/mongodb-archive-keyring.gpg] https://repo.mongodb.org/apt/debian bookworm/mongodb-org/8.0 main" > /etc/apt/sources.list.d/mongodb-org-8.0.list \
&& apt-get update \
&& apt-get install -y --no-install-recommends mongodb-mongosh \
&& rm -rf /var/lib/apt/lists/*
# renovate: datasource=npm depName=pnpm
RUN npm install -g pnpm@10.28.1
ENV PLAYWRIGHT_BROWSERS_PATH=/home/node/.cache/ms-playwright
ENV npm_config_store_dir=/home/node/.local/share/pnpm/store
# =============================================================================
# BUILDER - Install dependencies and build to populate caches (disposable)
# =============================================================================
FROM base AS builder
USER node
WORKDIR /home/node/.cache/fcc
# Package manifests only (for pnpm install caching)
COPY --chown=node:node pnpm-lock.yaml pnpm-workspace.yaml package.json turbo.json tsconfig-base.json ./
COPY --chown=node:node api/package.json api/
COPY --chown=node:node client/package.json client/turbo.json client/
COPY --chown=node:node curriculum/package.json curriculum/turbo.json curriculum/
COPY --chown=node:node e2e/package.json e2e/
COPY --chown=node:node tools/challenge-helper-scripts/package.json tools/challenge-helper-scripts/
COPY --chown=node:node tools/challenge-parser/package.json tools/challenge-parser/
COPY --chown=node:node tools/client-plugins/browser-scripts/package.json tools/client-plugins/browser-scripts/
COPY --chown=node:node tools/client-plugins/gatsby-remark-node-identity/package.json tools/client-plugins/gatsby-remark-node-identity/
COPY --chown=node:node tools/client-plugins/gatsby-source-challenges/package.json tools/client-plugins/gatsby-source-challenges/
COPY --chown=node:node tools/daily-challenges/package.json tools/daily-challenges/
COPY --chown=node:node tools/scripts/seed/package.json tools/scripts/seed/
COPY --chown=node:node tools/scripts/seed-exams/package.json tools/scripts/seed-exams/
COPY --chown=node:node packages/challenge-builder/package.json packages/challenge-builder/
COPY --chown=node:node packages/challenge-linter/package.json packages/challenge-linter/
COPY --chown=node:node packages/eslint-config/package.json packages/eslint-config/
COPY --chown=node:node packages/shared/package.json packages/shared/
# Prisma schema needed for api postinstall script (prisma generate)
COPY --chown=node:node api/prisma/ api/prisma/
COPY --chown=node:node api/prisma.config.ts api/
# Install dependencies (populates pnpm store)
ENV PUPPETEER_SKIP_DOWNLOAD=true
RUN pnpm install --frozen-lockfile
# Source files for builds
COPY --chown=node:node packages/ packages/
COPY --chown=node:node tools/ tools/
COPY --chown=node:node curriculum/ curriculum/
# Build shared packages and curriculum (populates Turbo cache)
# Source .env so turbo hashes env vars (e.g. FCC_*) identically to runtime
COPY --chown=node:node sample.env .env
RUN set -a && . ./.env && set +a && \
pnpm turbo build --filter=@freecodecamp/shared && \
pnpm turbo build --filter=@freecodecamp/curriculum
# =============================================================================
# DEVCONTAINER - Clean image with only pre-populated caches
# Used by: GitHub Codespaces, local VS Code devcontainers
# =============================================================================
FROM base AS devcontainer
LABEL org.opencontainers.image.source=https://github.com/freeCodeCamp/freeCodeCamp \
org.opencontainers.image.description="Development container for freeCodeCamp with pre-populated caches" \
org.opencontainers.image.licenses=BSD-3-Clause
USER node
# Copy pre-populated pnpm store (for fast pnpm install --prefer-offline)
COPY --from=builder --chown=node:node /home/node/.local/share/pnpm/store /home/node/.local/share/pnpm/store
# Copy turbo cache only (preserving directory structure for rsync at runtime)
WORKDIR /home/node/.cache/fcc
RUN --mount=type=bind,from=builder,source=/home/node/.cache/fcc,target=/tmp/fcc-build \
rsync -a --include='*/' --include='.turbo/***' --exclude='*' /tmp/fcc-build/ ./
WORKDIR /workspaces/freeCodeCamp
+50
View File
@@ -0,0 +1,50 @@
// Docker Bake configuration for freeCodeCamp devcontainer images
//
// Usage (from repo root):
// docker buildx bake -f docker/devcontainer/docker-bake.hcl # Local build (native platform)
// docker buildx bake -f docker/devcontainer/docker-bake.hcl devcontainer --push # Push multi-arch to GHCR
//
// With custom tag:
// TAG=v1.0.0 docker buildx bake -f docker/devcontainer/docker-bake.hcl devcontainer --push
variable "REGISTRY" {
default = "ghcr.io/freecodecamp"
}
variable "TAG" {
default = "latest"
}
variable "TAG_LATEST" {
default = "true"
}
group "default" {
targets = ["local-devcontainer"]
}
target "_common" {
context = "."
dockerfile = "docker/devcontainer/Dockerfile"
}
// Multi-arch image for pushing to registry (CI and local --push)
target "devcontainer" {
inherits = ["_common"]
target = "devcontainer"
platforms = ["linux/amd64", "linux/arm64"]
cache-from = ["type=gha"]
cache-to = ["type=gha,mode=max"]
tags = concat(
["${REGISTRY}/devcontainer:${TAG}"],
TAG_LATEST == "true" ? ["${REGISTRY}/devcontainer:latest"] : []
)
}
// Native platform only (fast local builds)
target "local-devcontainer" {
inherits = ["_common"]
target = "devcontainer"
output = ["type=docker"]
tags = ["ghcr.io/freecodecamp/devcontainer:latest"]
}
-13
View File
@@ -1,13 +0,0 @@
FROM gitpod/workspace-mongodb:latest
LABEL org.opencontainers.image.source=https://github.com/freecodecamp/freecodecamp \
org.opencontainers.image.description="A Gitpod image for the main freeCodeCamp repository" \
org.opencontainers.image.licenses=BSD-3-Clause
# from https://www.gitpod.io/docs/introduction/languages/javascript#node-versions
RUN bash -c 'VERSION="24" \
&& source $HOME/.nvm/nvm.sh && nvm install $VERSION \
&& nvm use $VERSION && nvm alias default $VERSION \
&& npm i -g pnpm@10 \
&& echo "nvm use default &>/dev/null" >> ~/.bashrc.d/51-nvm-fix \
&& pnpm dlx playwright@1.47.1 install --with-deps chromium'