Files
2026-07-13 13:12:00 +08:00

177 lines
6.5 KiB
Docker

# Omnigent UBI images: server (default target) + host (`--target host`).
#
# Red Hat Universal Base Image (UBI 9) variant of the standard Dockerfile,
# for RHEL/OpenShift environments that require UBI-compliant containers.
# Same two-target structure: `runtime` (server) and `host` (sandbox).
#
# Build (from repo root):
#
# docker build -t omnigent-server:ubi \
# -f deploy/docker/Dockerfile.ubi .
#
# docker build -t omnigent-host:ubi --target host \
# -f deploy/docker/Dockerfile.ubi .
ARG PYTHON_VERSION=3.12
ARG NODE_VERSION=20
# ── Web UI builder ──────────────────────────────────────
FROM registry.access.redhat.com/ubi9/nodejs-${NODE_VERSION} AS web-builder
ARG NPM_CONFIG_REGISTRY=
ENV NPM_CONFIG_REGISTRY=${NPM_CONFIG_REGISTRY}
USER 0
WORKDIR /web/web
COPY web/package.json web/package-lock.json ./
RUN npm install --no-audit --no-fund
COPY web/ ./
RUN npm run build
# ── Python builder (shared: server + host) ──────────────
FROM registry.access.redhat.com/ubi9/python-312 AS builder
ARG PYPI_INDEX_URL=https://pypi.org/simple
ENV PYTHONDONTWRITEBYTECODE=1 \
PIP_DISABLE_PIP_VERSION_CHECK=1
USER 0
RUN dnf install -y --nodocs gcc gcc-c++ make python3-devel \
&& dnf clean all
RUN pip install --index-url ${PYPI_INDEX_URL} --no-cache-dir uv
WORKDIR /build
COPY pyproject.toml setup.py ./
COPY LICENSE NOTICE ./
COPY sdks/ ./sdks/
COPY omnigent/ ./omnigent/
COPY examples/ ./examples/
RUN python -m venv /opt/venv
ENV VIRTUAL_ENV=/opt/venv \
PATH="/opt/venv/bin:${PATH}"
RUN uv pip install --no-cache-dir --index-url ${PYPI_INDEX_URL} -e .
# ── Server builder ──────────────────────────────────────
FROM builder AS server-builder
ARG PYPI_INDEX_URL=https://pypi.org/simple
COPY --from=web-builder /web/omnigent/server/static/web-ui ./omnigent/server/static/web-ui
RUN test -f ./omnigent/server/static/web-ui/index.html \
|| (echo "ERROR: SPA bundle missing after web-builder stage — check the web build." && exit 1)
RUN uv pip install --no-cache-dir --index-url ${PYPI_INDEX_URL} 'psycopg[binary]>=3.1,<4'
# ── Node alias stage ─────────────────────────────────────
FROM registry.access.redhat.com/ubi9/nodejs-${NODE_VERSION} AS node-runtime
# ── Host runtime (`--target host`) ──────────────────────
FROM registry.access.redhat.com/ubi9/python-312 AS host
ARG NPM_CONFIG_REGISTRY=
ENV NPM_CONFIG_REGISTRY=${NPM_CONFIG_REGISTRY}
ENV PYTHONUNBUFFERED=1 \
PYTHONDONTWRITEBYTECODE=1 \
PATH="/opt/venv/bin:${PATH}" \
IS_SANDBOX=1
USER 0
# curl-minimal and ca-certificates are preinstalled in UBI9.
RUN dnf install -y --nodocs git tmux unzip \
&& dnf clean all
RUN git config --system credential.helper \
'!f() { [ "$1" = get ] || return 0; [ -n "$GIT_TOKEN" ] || return 0; printf "username=%s\npassword=%s\n" "${GIT_USERNAME:-x-access-token}" "$GIT_TOKEN"; }; f'
# Node runtime from the UBI Node image.
COPY --from=node-runtime /usr/bin/node /usr/local/bin/node
COPY --from=node-runtime /usr/lib/node_modules /usr/local/lib/node_modules
RUN ln -sf /usr/local/lib/node_modules/npm/bin/npm-cli.js /usr/local/bin/npm \
&& ln -sf /usr/local/lib/node_modules/npm/bin/npx-cli.js /usr/local/bin/npx
RUN npm install -g --no-audit --no-fund \
@anthropic-ai/claude-code \
@openai/codex \
@earendil-works/pi-coding-agent \
&& npm cache clean --force
# Kiro CLI is not published as an npm package and its installer has no version
# flag (always fetches `latest`). Pin it by fetching the immutable per-arch zip
# from the versioned CDN path + verifying sha256, then running the package's own
# install.sh and copying the binaries onto the global PATH. The `--version` check
# asserts the binary is the pinned version (a sanity guard atop the sha256). See
# the fuller rationale in deploy/docker/Dockerfile — keep KIRO_CLI_VERSION + both
# SHA256s in sync.
ARG KIRO_CLI_VERSION=2.10.0
ARG KIRO_CLI_SHA256_AMD64=be9d8b6d7c44f93a83ca22466043d98ad058e6ed3c12fffd068f3fb8a60b3b70
ARG KIRO_CLI_SHA256_ARM64=0afb37399b9e2847c2f2e3f5d9052c8bc52bbf1e30401ea284a602661bce34bc
RUN set -eu; \
case "$(uname -m)" in \
x86_64) asset="kirocli-x86_64-linux.zip"; sha="$KIRO_CLI_SHA256_AMD64" ;; \
aarch64) asset="kirocli-aarch64-linux.zip"; sha="$KIRO_CLI_SHA256_ARM64" ;; \
*) echo "ERROR: unsupported arch '$(uname -m)' for kiro-cli" >&2; exit 1 ;; \
esac; \
curl -fsSL -o /tmp/kiro.zip "https://prod.download.cli.kiro.dev/stable/${KIRO_CLI_VERSION}/${asset}"; \
echo "${sha} /tmp/kiro.zip" | sha256sum -c -; \
unzip -q /tmp/kiro.zip -d /tmp/kiro; \
KIRO_CLI_SKIP_SETUP=1 sh /tmp/kiro/kirocli/install.sh; \
install -m 0755 /root/.local/bin/kiro-cli /usr/local/bin/kiro-cli; \
if [ -f /root/.local/bin/kiro-cli-chat ]; then \
install -m 0755 /root/.local/bin/kiro-cli-chat /usr/local/bin/kiro-cli-chat; \
fi; \
rm -rf /tmp/kiro /tmp/kiro.zip; \
installed="$(/usr/local/bin/kiro-cli --version 2>&1 | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -n1)"; \
[ "$installed" = "$KIRO_CLI_VERSION" ] || { \
echo "ERROR: kiro-cli reports '${installed:-<none>}', expected '$KIRO_CLI_VERSION'." >&2; exit 1; }; \
echo "kiro-cli ${KIRO_CLI_VERSION} pinned (sha256 verified)"
COPY --from=builder /opt/venv /opt/venv
COPY --from=builder /build /build
RUN echo 'export PATH="/opt/venv/bin:${PATH}"' > /etc/profile.d/omnigent-venv.sh
WORKDIR /root
CMD ["sleep", "infinity"]
# ── Server runtime (default target) ─────────────────────
FROM registry.access.redhat.com/ubi9/python-312 AS runtime
ENV PYTHONUNBUFFERED=1 \
PYTHONDONTWRITEBYTECODE=1 \
PATH="/opt/venv/bin:${PATH}"
USER 0
# curl-minimal and ca-certificates are preinstalled in UBI9;
# installing full curl would conflict with curl-minimal.
COPY --from=server-builder /opt/venv /opt/venv
COPY --from=server-builder /build /build
COPY deploy/docker/entrypoint.py /app/entrypoint.py
WORKDIR /app
RUN mkdir -p /data/artifacts \
&& chown -R 1001:0 /data \
&& chmod -R g=u /data
ENV PORT=8000 \
HOST=0.0.0.0 \
ARTIFACT_DIR=/data/artifacts
EXPOSE 8000
USER 1001
HEALTHCHECK --interval=30s --timeout=5s --start-period=20s --retries=3 \
CMD curl -fsS "http://127.0.0.1:${PORT}/health" || exit 1
CMD ["python", "/app/entrypoint.py"]