Repository navigation
Expand file tree
/
Copy pathDockerfile
More file actions
138 lines (110 loc) · 5.81 KB
/
Copy pathDockerfile
File metadata and controls
138 lines (110 loc) · 5.81 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
137
138
# Build stage - Backend
# Base images are overridable so CI can fall back to docker.io mirrors
# (same digests) when public.ecr.aws returns 429 Too Many Requests.
ARG GOLANG_BASE=public.ecr.aws/docker/library/golang:1.27.1-alpine@sha256:8a5910f31396cd4d89662f56c68b3ae31d374308270a1c3bd96672ee5ed43414
ARG ALPINE_BASE=public.ecr.aws/docker/library/alpine:3.24@sha256:294b683cb724975bec92580e1e685676bd4b50bda910ddb8c51d4cabeaec77e6
ARG NODE_BASE=public.ecr.aws/docker/library/node:26-alpine@sha256:0b36e8c136b94cd4fcf02188228e76c31ad5872eef3fec8cbd2eee500cfd9e80
FROM ${GOLANG_BASE} AS backend-builder
WORKDIR /app
# Copy go mod files
COPY go.mod go.sum ./
RUN go mod download
# Copy source
COPY . .
# Build args for version and target architecture
ARG APP_VERSION=dev
ARG TARGETARCH
# Build for the target platform (TARGETARCH is set automatically by buildx)
RUN CGO_ENABLED=0 GOOS=linux GOARCH=${TARGETARCH} go build -ldflags="-s -w -X github.com/kubestellar/console/pkg/api.Version=${APP_VERSION}" -o console ./cmd/console
RUN CGO_ENABLED=0 GOOS=linux GOARCH=${TARGETARCH} go build -ldflags="-s -w -X main.version=${APP_VERSION}" -o kc-watcher ./cmd/watcher
# Build stage - MCP binaries
FROM ${ALPINE_BASE} AS mcp-binaries
ARG TARGETARCH
ARG KUBESTELLAR_MCP_RELEASE_TAG=v0.8.18-nightly.20260509
# SHA256 checksums for linux/amd64 tarballs (update when bumping KUBESTELLAR_MCP_RELEASE_TAG)
ARG OPS_SHA256_AMD64="ee199aed870a074d056045e18ea0efb89af0dd817b502e8b1e2157608bd0efd2"
ARG DEPLOY_SHA256_AMD64="f49e94bce3157bd7ed450fabcc6bff8a72bc41f19735740f6b89717a3f0dc225"
# SHA256 checksums for linux/arm64 tarballs
ARG OPS_SHA256_ARM64="264678618b30a178eed02488b3c74afd49b4a85f68b474d9ae9aae2b19ba0b23"
ARG DEPLOY_SHA256_ARM64="65d4ca235e494a1a29345d28b65c8e46c66bd65c5101f1ca0a4c1bf8b83880a8"
RUN set -eux; \
apk add --no-cache ca-certificates curl tar; \
case "${TARGETARCH}" in \
amd64) mcp_arch="amd64"; ops_sha="${OPS_SHA256_AMD64}"; deploy_sha="${DEPLOY_SHA256_AMD64}" ;; \
arm64) mcp_arch="arm64"; ops_sha="${OPS_SHA256_ARM64}"; deploy_sha="${DEPLOY_SHA256_ARM64}" ;; \
*) echo "unsupported TARGETARCH: ${TARGETARCH}" >&2; exit 1 ;; \
esac; \
release_version="${KUBESTELLAR_MCP_RELEASE_TAG#v}"; \
base_url="https://github.com/kubestellar/kubestellar-mcp/releases/download/${KUBESTELLAR_MCP_RELEASE_TAG}"; \
mkdir -p /out; \
curl -fsSL "${base_url}/kubestellar-ops_${release_version}_linux_${mcp_arch}.tar.gz" -o /out/kubestellar-ops.tar.gz; \
echo "${ops_sha} /out/kubestellar-ops.tar.gz" | sha256sum -c -; \
tar -xzf /out/kubestellar-ops.tar.gz -C /out kubestellar-ops; \
curl -fsSL "${base_url}/kubestellar-deploy_${release_version}_linux_${mcp_arch}.tar.gz" -o /out/kubestellar-deploy.tar.gz; \
echo "${deploy_sha} /out/kubestellar-deploy.tar.gz" | sha256sum -c -; \
tar -xzf /out/kubestellar-deploy.tar.gz -C /out kubestellar-deploy; \
rm /out/kubestellar-ops.tar.gz /out/kubestellar-deploy.tar.gz; \
chmod +x /out/kubestellar-ops /out/kubestellar-deploy
# Build stage - Frontend
FROM ${NODE_BASE} AS frontend-builder
WORKDIR /app
# Build args for version and commit hash
ARG APP_VERSION=0.0.0
ARG COMMIT_HASH=unknown
# Copy all frontend source first so we can detect a pre-built dist/.
# WARNING (local builds): if web/dist/ is present in your working tree from a
# previous build it will be copied here and the conditional below will skip
# npm ci + Vite, silently shipping stale assets. Remove web/dist/ before
# building locally if you want a fresh frontend build.
# In CI this is intentional: the build-frontend job pre-builds on amd64 and
# uploads the artifact; the docker-build job downloads it into web/dist/ so
# that QEMU arm64 never needs to run Node at all, avoiding the
# "Illegal instruction" crash caused by Node 22 using ARMv8.2+ instructions
# not supported by the default QEMU cpu model.
COPY web/ ./
# If dist/ is already present (CI pre-built path), skip npm ci and Vite
# entirely — no Node execution under QEMU arm64. Otherwise install
# dependencies and build from source (local / amd64 scratch builds).
RUN if [ -d dist ] && [ -n "$(ls -A dist 2>/dev/null)" ]; then \
echo "Using pre-built frontend dist/ — skipping npm ci and build"; \
else \
for attempt in 1 2 3; do \
npm ci --legacy-peer-deps && break; \
echo "npm ci failed on attempt ${attempt}; retrying..." >&2; \
sleep $((attempt * 5)); \
[ "${attempt}" = "3" ] && { echo "npm ci failed after 3 attempts" >&2; exit 1; }; \
done; \
VITE_APP_VERSION=${APP_VERSION} VITE_COMMIT_HASH=${COMMIT_HASH} npm run build; \
fi
# Final stage
FROM ${ALPINE_BASE}
WORKDIR /app
# Install runtime dependencies
RUN apk add --no-cache ca-certificates tzdata sqlite
# Copy backend and watcher binaries
COPY --from=backend-builder /app/console .
COPY --from=backend-builder /app/kc-watcher .
# Copy MCP helper binaries used by the in-cluster bridge
COPY --from=mcp-binaries /out/kubestellar-ops /usr/local/bin/kubestellar-ops
COPY --from=mcp-binaries /out/kubestellar-deploy /usr/local/bin/kubestellar-deploy
# Copy frontend build
COPY --from=frontend-builder /app/dist ./web/dist
# Create non-root user for container security
RUN addgroup -g 1001 -S appgroup && adduser -u 1001 -S appuser -G appgroup
# Create data and settings directories
RUN mkdir -p /app/data /app/.kc && chown -R appuser:appgroup /app/data /app/.kc
# Copy entrypoint script for watchdog + backend
COPY entrypoint.sh .
RUN chmod +x entrypoint.sh
# Environment variables
ENV PORT=8080
ENV BACKEND_PORT=8081
ENV DATABASE_PATH=/app/data/console.db
ENV HOME=/app
EXPOSE 8080
# Health check hits the watchdog, which always responds
HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
CMD wget -qO- http://localhost:8080/watchdog/health || exit 1
# Run as non-root user
USER appuser
ENTRYPOINT ["./entrypoint.sh"]