When do_chown is false (running as uid 101, non-root), createDirectoryAndChown
was delegating to 'clickhouse su UID:GID mkdir -p DIR'. The distroless image
has no mkdir binary, so this always failed, silently leaving coordination
subdirectories and server runtime paths uncreated.
Since we are already running as the target user, fs::create_directories works
directly — no user-switch or external binary is needed. The NFS root-squash
concern that motivated the clickhouse-su-mkdir approach does not apply when
the process is already non-root.
The docker-library `override-cmd` test runs:
docker run "$image" echo "Hello $random"
With the ENTRYPOINT `["/usr/bin/clickhouse", "docker-init"]`, docker-init
receives `["echo", "Hello ..."]` as extra_args. Previously, `echo` was not
in the explicit passthrough list, so docker-init started the full server,
which ran indefinitely — causing a ~4.5-hour timeout in CI.
Fix: mirror `entrypoint.sh` behaviour: if the first extra argument does not
start with `--`, exec it directly without server startup. For recognized
ClickHouse tool names (client, local, etc.) the bin_dir path is used for
correct argv[0]-based dispatch; for generic commands (echo, date, bash, …)
PATH resolution via execvp handles it.
Two bugs addressed:
1. `Dockerfile.distroless` — `cp -r` without `-p` preserves mode bits but
resets ownership to root:root. `clickhouse install` sets `config.xml` to
mode 0400 owned by `clickhouse:clickhouse`; after the copy the file becomes
`root:root 0400`, which uid 101 cannot read (errno 13 EACCES). Fix: expand
the `chown -R clickhouse:clickhouse` target from just `users.d` to the
entire `/output/etc/clickhouse-server` tree.
2. `docker-init.cpp` — the official Docker-library test suite runs client
queries by spawning a second container from the same image:
`docker run "$image" clickhouse-client --host ... --query ...`
Because the distroless ENTRYPOINT is `clickhouse docker-init`, the
client tool name and its arguments land in `extra_args` and were being
forwarded to `clickhouse-server`, causing "Unknown option specified" errors.
Fix: before any server-startup logic, detect a recognised client-side
subcommand as the first extra arg (`clickhouse-client`, `clickhouse-local`,
`clickhouse-keeper-client`, and their short forms) and exec it directly
via its `/usr/bin/` symlink, bypassing server initialisation entirely.
- Replace `#include <signal.h>` with `#include <csignal>` (deprecated C header)
- Remove `#include <sstream>`; replace `std::istringstream` with manual newline split
- Wrap all `close()`/`dup2()` calls with `(void)` (return value must be acknowledged)
- Split `int lhs_status = 0, rhs_status = 0;` into two declarations
(readability-isolate-declaration)
- Replace loop-runs-once `has_init_files` detection with iterator comparison
(clang-diagnostic-unreachable-code-loop-increment)
- Add `// NOLINT(concurrency-mt-unsafe)` to `strerror` and `sleep` call sites
- Rename `initClickHouseDb` → `initClickHouseDB` (abbreviations must be all-caps)
- Add `clickhouse docker-init` C++ subcommand that replaces `entrypoint.sh`
for shell-free distroless environments (fork/exec, POSIX-only, no shell deps)
- Add `docker/server/Dockerfile.distroless` and `docker/keeper/Dockerfile.distroless`
as parallel build targets alongside existing ubuntu/alpine variants
- Add `--no-distroless` CI flag and fix package selector to use `.deb` for distroless
- Add structural smoke-test harness under `docker/tests/distroless/`
The distroless images use `gcr.io/distroless/cc-debian12:nonroot` as base,
expose the same ports as ubuntu, run as uid/gid 101, and include a debug
variant (`distroless-debug`) with a busybox shell for troubleshooting.