Files
team/Dockerfile
T
zeekayandHanzo Dev 61fefb7b8d track go.work, and build the shipped binary as a shipped binary
The gate failed on `[build failed]` for symbols that are in this tree. Upstream
publishes server/public and pins v0.4.0 of it; we changed server/public, so
anything that reads the pin compiles against a release with no HanzoSettings, no
ServiceHanzo, no UserAuthServiceHanzo. The workspace is what makes ./public mean
this tree, and it was ignored — so `go build`, `go test`, the gate and the image
each had to arrange it privately, and the one that did not simply failed.

Tracking it states the fact once. The image build no longer arranges anything.

Also:

  -tags production. Without it server/public/model selects the DEV service
  environment through a build constraint, and a shipped binary points at dev
  telemetry and licensing while looking entirely normal.

  The runtime tree — data, logs, config, plugins, client/plugins — is made in a
  stage that has a shell, because distroless does not and the server has nowhere
  to write without them.

  The document-extraction binaries are dropped rather than carried. pdftotext
  wants GLIBC_2.38 and libstdc++ on a 2.36 base that has no libstdc++ at all;
  wvText is a shell script and there is no shell. The library COPYs beside them
  read /usr/lib while Ubuntu keeps those under /usr/lib/x86_64-linux-gnu, and a
  --from glob matching nothing is a silent no-op — so upstream's image ships five
  binaries with no libraries and reports success. Restoring extraction needs a
  base that can run it; that is its own decision.

  .dockerignore, because .git alone is 1.2 GiB of context and node_modules is a
  working tree's results standing in for the build's.

Co-authored-by: Hanzo Dev <[email protected]>
2026-08-13 23:48:07 -07:00

82 lines
4.2 KiB
Docker

# Hanzo Team — server + web app, built from this tree.
#
# Upstream's server/build/Dockerfile downloads a released tarball, which cannot
# work for a fork: the thing we changed is the source. This builds both halves
# and assembles the same runtime layout the binary looks for.
FROM node:24.11-bookworm AS webapp
WORKDIR /src/webapp
# The whole tree BEFORE the install, not the manifests alone. `npm ci` runs the
# root postinstall, which is `patch-package` followed by a BUILD of the platform
# workspaces — so an install staged on package.json files has nothing to compile
# and dies there. The dependency layer a manifests-only copy would have cached is
# not available at this shape, and a cache that breaks the build is not a cache.
COPY webapp .
# `npm run build` is the repo's own build (scripts/build.mjs): subpackages first,
# then channels. Naming the channels workspace directly would skip the first half.
RUN npm ci --no-audit --no-fund && npm run build
FROM golang:1.26.4-bookworm AS server
# Declared, or the expansion below is unset on every build and the server reports
# its version as the fallback for the life of the image.
ARG BUILD_NUMBER=dev
WORKDIR /src/server
# go.work comes with this copy and is tracked (see server/.gitignore), so ./public
# resolves to this tree rather than the published v0.4.0, which carries none of
# the Hanzo model. Nothing is arranged here — the tree already states it.
COPY server .
# `production` is not decoration: without the tag the !production file in
# server/public/model selects the DEV service environment, and a shipped binary
# then points at dev telemetry and licensing.
RUN CGO_ENABLED=0 go build -trimpath -tags production \
-ldflags "-X github.com/mattermost/mattermost/server/public/model.BuildNumber=${BUILD_NUMBER}" \
-o /out/ ./cmd/mattermost ./cmd/mmctl
# The writable tree and the mime table. Distroless has no shell, so directories
# the server creates files in cannot be made in the final stage — and unmade, the
# server has nowhere to write its config or its log and does not start.
FROM ubuntu:noble AS tools
RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install --no-install-recommends -y \
ca-certificates media-types tzdata \
&& rm -rf /var/lib/apt/lists/*
RUN mkdir -p /hanzo/data /hanzo/logs /hanzo/config /hanzo/plugins /hanzo/client/plugins \
&& chown -R 2000:2000 /hanzo
# Upstream also lifts pdftotext, wvText, wvWare, unrtf and tidy in here for
# attachment text extraction. They are NOT carried, because on this base they
# cannot run and shipping a binary that cannot run is not a feature:
# pdftotext needs GLIBC_2.38 and libstdc++; debian12 is 2.36 and distroless
# `base` has no libstdc++ at any version.
# wvText is a /bin/sh script, and there is no shell here.
# The library COPYs beside them read /usr/lib/libpoppler.so*, while Ubuntu puts
# every one of those under /usr/lib/x86_64-linux-gnu — and a --from glob that
# matches nothing is a silent no-op in BuildKit, so upstream's image has been
# carrying five binaries with no libraries and reporting success. Restoring
# extraction means a base that can run it, which is a different decision than
# this one and should be made on its own.
FROM gcr.io/distroless/base-debian12
ENV PATH="/hanzo/bin:${PATH}"
ENV MM_SERVICESETTINGS_ENABLELOCALMODE="true"
COPY --from=tools /etc/mime.types /etc/
COPY --from=tools --chown=2000:2000 /etc/ssl/certs /etc/ssl/certs
# The writable tree first, then the read-only content into it.
COPY --from=tools --chown=2000:2000 /hanzo /hanzo
COPY --from=server --chown=2000:2000 /out/ /hanzo/bin/
COPY --from=webapp --chown=2000:2000 /src/webapp/channels/dist /hanzo/client
COPY --chown=2000:2000 server/i18n /hanzo/i18n
COPY --chown=2000:2000 server/templates /hanzo/templates
COPY --chown=2000:2000 server/fonts /hanzo/fonts
# NOT chowned: this is the account database, and the account it names must not be
# able to rewrite it.
COPY server/build/passwd /etc/passwd
USER 2000
WORKDIR /hanzo
EXPOSE 8065 8067 8074
VOLUME ["/hanzo/data", "/hanzo/logs", "/hanzo/config", "/hanzo/plugins", "/hanzo/client/plugins"]
HEALTHCHECK --interval=30s --timeout=10s CMD ["/hanzo/bin/mmctl", "system", "status", "--local"]
CMD ["/hanzo/bin/mattermost"]