-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathDockerfile
More file actions
136 lines (125 loc) · 7.87 KB
/
Copy pathDockerfile
File metadata and controls
136 lines (125 loc) · 7.87 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
# syntax=docker/dockerfile:1
# ---- Rust daemon ----------------------------------------------------------
# These manifest-list digests fix the selected base-image identity while
# retaining the upstream images' supported platforms. They do not make the
# whole build byte-for-byte reproducible; see docs/release/SUPPLY_CHAIN.md.
FROM rust:1.88-slim-trixie@sha256:9a7159329166b45f453351a077367f501aa3e98378f7e327530e7966a139d05f AS rust-builder
WORKDIR /src
RUN apt-get update && apt-get install -y --no-install-recommends pkg-config libssl-dev \
&& rm -rf /var/lib/apt/lists/*
COPY crates ./crates
COPY VERSION ./VERSION
COPY rust-toolchain.toml ./
RUN cargo build --release --manifest-path crates/Cargo.toml \
-p dockermap-daemon -p dockermap-docker-gateway
RUN cargo build --release --manifest-path crates/Cargo.toml \
-p dockermap-core --bin generate-contract-schemas
# ---- Node API + React web app ---------------------------------------------
FROM node:22-trixie-slim@sha256:7b8a0c89c54499bee567618f96578e1a12a800f062fbdbfd1fb6a443fa6f6284 AS js-builder
WORKDIR /src
ARG VITE_ENABLE_ATLAS_OVERVIEW=false
COPY package.json package-lock.json ./
COPY apps/api/package.json apps/api/package.json
COPY apps/web/package.json apps/web/package.json
COPY packages/contracts/package.json packages/contracts/package.json
RUN npm ci
COPY VERSION ./VERSION
COPY scripts/check-version-authority.mjs scripts/check-version-authority.mjs
COPY scripts/check-rust-contract-schemas.mjs scripts/generate-rust-contract-types.mjs scripts/generate-rust-contract-types.test.mjs ./scripts/
# The version checker validates every Rust package mirror too. These sources
# remain builder-only and never reach the runtime image.
COPY crates ./crates
COPY tsconfig.base.json ./
COPY apps ./apps
COPY packages ./packages
COPY tests/fixtures ./tests/fixtures
COPY --from=rust-builder /src/crates/target/release/generate-contract-schemas /usr/local/bin/generate-contract-schemas
# The single-container image serves the SPA and the API from the SAME origin
# (nginx proxies /api/* to the Node API on 4000), so the bundle must call
# relative /api/... URLs. The default in api.ts points at the user's
# localhost:4000, which never exists inside this container — an empty string
# is not nullish, so apiUrl() yields same-origin paths the proxy can serve.
ENV VITE_API_BASE_URL=""
ENV VITE_ENABLE_ATLAS_OVERVIEW=${VITE_ENABLE_ATLAS_OVERVIEW}
ENV DOCKERMAP_CONTRACT_SCHEMA_GENERATOR=/usr/local/bin/generate-contract-schemas
RUN npm run check:version && npm run check:contracts && npm run build
# The runtime image needs the compiled artifacts and production dependency
# closure only. Remove root/workspace development dependencies before copying
# node_modules so scanners and the image do not retain build tooling.
RUN npm prune --omit=dev --workspaces --include-workspace-root
# `@dockermap/contracts` is a real runtime dependency of the compiled API.
# Build and assert the entire package artifact, rather than relying on a
# source-tree module that happened to be copied into the image.
RUN test -f packages/contracts/dist/index.js && test -f packages/contracts/dist/nodeSchemas.js
# ---- API runtime dependency closure ----------------------------------------
# Resolve the runtime dependency tree separately from the full monorepo build.
# The API deliberately needs only itself and @dockermap/contracts; web runtime
# packages must not cross this boundary merely because npm hoisted them during
# the builder install.
FROM node:22-trixie-slim@sha256:7b8a0c89c54499bee567618f96578e1a12a800f062fbdbfd1fb6a443fa6f6284 AS api-runtime-deps
WORKDIR /runtime
COPY package.json package-lock.json ./
COPY apps/api/package.json apps/api/package.json
COPY packages/contracts/package.json packages/contracts/package.json
RUN npm ci --omit=dev --workspace @dockermap/api --include-workspace-root=false \
&& test ! -e node_modules/.bin/tsx && test ! -e node_modules/.bin/vite \
&& test ! -d node_modules/typescript && test ! -e node_modules/@playwright/test/package.json \
&& test ! -e node_modules/react/package.json \
&& test ! -e node_modules/react-dom/package.json \
&& test ! -e node_modules/react-router-dom/package.json
# ---- Runtime image ----------------------------------------------------------
FROM node:22-trixie-slim@sha256:7b8a0c89c54499bee567618f96578e1a12a800f062fbdbfd1fb6a443fa6f6284 AS runtime
# The pinned base fixes image identity, while this upgrade applies the current
# distribution security fixes before adding the runtime-only packages.
RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get upgrade -y --no-install-recommends \
&& apt-get install -y --no-install-recommends nginx procps curl \
&& rm -rf /var/lib/apt/lists/*
# npm is used only by the builder. Removing its global installation prevents
# unused bundled packages from remaining in the production attack surface.
RUN rm -rf /usr/local/lib/node_modules/npm /usr/local/bin/npm /usr/local/bin/npx
# The split deployment uses one shared non-root group for the filtered Unix
# socket. The gateway receives the host Docker-socket GID as a supplemental
# group at runtime; neither frontend nor collector does.
RUN groupadd --gid 10003 dockermap && \
useradd --uid 10001 --gid 10003 --create-home --home-dir /nonexistent --shell /usr/sbin/nologin dockermap-frontend && \
useradd --uid 10002 --gid 10003 --create-home --home-dir /nonexistent --shell /usr/sbin/nologin dockermap-gateway && \
useradd --uid 10003 --gid 10003 --create-home --home-dir /nonexistent --shell /usr/sbin/nologin dockermap-collector && \
mkdir -p /run/dockermap && chown 10002:10003 /run/dockermap && chmod 0770 /run/dockermap
WORKDIR /opt/dockermap
COPY --from=api-runtime-deps /runtime/node_modules ./node_modules
COPY --from=js-builder /src/package.json ./package.json
COPY --from=js-builder /src/apps/api/dist ./apps/api/dist
COPY --from=js-builder /src/apps/api/package.json ./apps/api/package.json
COPY --from=js-builder /src/apps/web/dist ./apps/web/dist
COPY --from=js-builder /src/packages/contracts/package.json ./packages/contracts/package.json
COPY --from=js-builder /src/packages/contracts/dist ./packages/contracts/dist
COPY --from=rust-builder /src/crates/target/release/dockermap-daemon /usr/local/bin/dockermap-daemon
COPY --from=rust-builder /src/crates/target/release/dockermap-docker-gateway /usr/local/bin/dockermap-docker-gateway
COPY deploy/docker/nginx.conf /etc/nginx/sites-enabled/default
COPY deploy/docker/nginx-main.conf /etc/nginx/nginx.conf
COPY deploy/docker/entrypoint.sh /entrypoint.sh
COPY deploy/docker/frontend-entrypoint.sh /frontend-entrypoint.sh
COPY deploy/docker/healthcheck.sh /usr/local/bin/dockermap-healthcheck
RUN chmod +x /entrypoint.sh /frontend-entrypoint.sh /usr/local/bin/dockermap-healthcheck
# The Node base image includes package-manager CLIs that DockerMap never uses
# at runtime. Remove them after staging the already-pruned closure; `node`
# remains available for the compiled API, while npm/npx cannot become an
# in-container mutation surface.
RUN rm -rf /usr/local/lib/node_modules/npm \
&& rm -f /usr/local/bin/npm /usr/local/bin/npx /usr/local/bin/corepack \
&& ! command -v npm && ! command -v npx \
&& test ! -e node_modules/.bin/tsx && test ! -e node_modules/.bin/vite \
&& test ! -d node_modules/typescript && test ! -e node_modules/@playwright/test/package.json \
&& test ! -e node_modules/react/package.json \
&& test ! -e node_modules/react-dom/package.json \
&& test ! -e node_modules/react-router-dom/package.json
ENV NODE_ENV=production \
PORT=4000 \
DOCKERMAP_DAEMON_HOST=127.0.0.1 \
DOCKERMAP_DAEMON_PORT=4100 \
DOCKERMAP_DAEMON_URL=http://127.0.0.1:4100 \
DOCKERMAP_PROJECT_ROOT=/opt/dockermap/project \
DOCKERMAP_ALLOWED_ORIGINS=http://127.0.0.1:3233,http://localhost:3233
EXPOSE 3233
HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 CMD ["/usr/local/bin/dockermap-healthcheck"]
ENTRYPOINT ["/entrypoint.sh"]