fix(docker): run runtime image under tini (#78777)

Run the Docker runtime image under tini so long-lived containers reap orphaned child processes and forward signals correctly.

Thanks @VintageAyu!
This commit is contained in:
Ayu
2026-05-08 13:19:55 +05:30
committed by GitHub
parent fb66a101e2
commit e63e4f9551
5 changed files with 11 additions and 5 deletions

View File

@@ -6,6 +6,7 @@ Docs: https://docs.openclaw.ai
### Changes
- Docker: run the runtime image under `tini` so long-lived containers reap orphaned child processes and forward signals correctly. (#77885) Thanks @VintageAyu.
- Google/Gemini: normalize retired `google/gemini-3-pro-preview` and `google-gemini-cli/gemini-3-pro-preview` selections to `google/gemini-3.1-pro-preview` before they are written to model config.
- Amazon Bedrock: support `serviceTier` parameter for Bedrock models, configurable via `agents.defaults.params.serviceTier` or per-model in `agents.defaults.models`. Valid values: `default`, `flex`, `priority`, `reserved`. (#64512) Thanks @mobilinkd.
- Control UI: read the Quick Settings exec policy badge from `tools.exec.security` instead of the non-schema `agents.defaults.exec.security` path, so configured `full`/`deny` values render accurately. Fixes #78311. Thanks @FriedBack.

View File

@@ -160,7 +160,7 @@ RUN --mount=type=cache,id=openclaw-bookworm-apt-cache,target=/var/cache/apt,shar
--mount=type=cache,id=openclaw-bookworm-apt-lists,target=/var/lib/apt,sharing=locked \
apt-get update && \
DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
ca-certificates procps hostname curl git lsof openssl python3 && \
ca-certificates procps hostname curl git lsof openssl python3 tini && \
update-ca-certificates
RUN chown node:node /app
@@ -287,4 +287,5 @@ USER node
# For external access from host/ingress, override bind to "lan" and set auth.
HEALTHCHECK --interval=3m --timeout=10s --start-period=15s --retries=3 \
CMD node -e "fetch('http://127.0.0.1:18789/healthz').then((r)=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))"
ENTRYPOINT ["tini", "-s", "--"]
CMD ["node", "openclaw.mjs", "gateway", "--allow-unconfigured"]

View File

@@ -427,8 +427,7 @@ See [ClawDock](/install/clawdock) for the full helper guide.
</Accordion>
<Accordion title="Base image metadata">
The main Docker runtime image uses `node:24-bookworm-slim` and publishes OCI
base-image annotations including `org.opencontainers.image.base.name`,
The main Docker runtime image uses `node:24-bookworm-slim` and includes `tini` as the entrypoint init process (PID 1) to ensure zombie processes are reaped and signals are handled correctly in long-running containers. It publishes OCI base-image annotations including `org.opencontainers.image.base.name`,
`org.opencontainers.image.source`, and others. The Node base digest is
refreshed through Dependabot Docker base-image PRs; release builds do not run
a distro upgrade layer. See

View File

@@ -78,6 +78,8 @@ read_when:
destination = "/data"
```
The OpenClaw Docker image uses `tini` as its entrypoint. Fly process commands replace Docker `CMD` without replacing `ENTRYPOINT`, so the process still runs under `tini`.
**Key settings:**
| Setting | Why |

View File

@@ -47,7 +47,7 @@ describe("Dockerfile", () => {
expect(collapsed).toContain("update-ca-certificates");
});
it("installs python3 in the slim runtime stage for workspace scripts", async () => {
it("installs python3 and tini in the slim runtime stage", async () => {
const dockerfile = collapseDockerContinuations(await readFile(dockerfilePath, "utf8"));
const runtimeIndex = dockerfile.indexOf(
"FROM ${OPENCLAW_NODE_BOOKWORM_SLIM_IMAGE} AS base-runtime",
@@ -59,7 +59,10 @@ describe("Dockerfile", () => {
expect(runtimeIndex).toBeGreaterThan(-1);
expect(pythonInstallIndex).toBeGreaterThan(runtimeIndex);
expect(pythonInstallIndex).toBeLessThan(dockerfile.indexOf("RUN chown node:node /app"));
expect(dockerfile).toContain("ca-certificates procps hostname curl git lsof openssl python3");
expect(dockerfile).toContain(
"ca-certificates procps hostname curl git lsof openssl python3 tini",
);
expect(dockerfile).toContain('ENTRYPOINT ["tini", "-s", "--"]');
});
it("installs optional browser dependencies after pnpm install", async () => {