Skip to content

operator: build the runtime image on scratch - #378

Open
yuval-gr wants to merge 1 commit into
mainfrom
yuval/fix/operator-scratch-image
Open

yuval-gr wants to merge 1 commit into
mainfrom
yuval/fix/operator-scratch-image

Conversation

@yuval-gr

@yuval-gr yuval-gr commented Sep 17, 2026

Copy link
Copy Markdown
Collaborator

What does this PR do?

The operator image ran on gcr.io/distroless/static-debian13:nonroot, which already gave a non-root, shell-less base. Moving the final stage to scratch drops the remaining userland the operator never touches and removes the gcr.io base-image dependency from the build.

Nothing in the runtime needs what distroless/static supplied:

  • No outbound TLS. There is no http.Client, tls.Config or SystemCertPool in operator/ or pkg/; the apiserver client uses the projected service-account CA, not the system trust store. The CA bundle is carried over anyway so a future outbound call fails loudly rather than with a bare x509 error.
  • No tzdata use (no time.LoadLocation).
  • No writable /tmp needed. The chart sets readOnlyRootFilesystem: true, and the webhook serving cert arrives on a secret volume mounted at /tmp/k8s-webhook-server/serving-certs, a path kubelet creates.
  • USER is numeric, so no /etc/passwd entry is required; passwd is copied for tooling that resolves the UID.

Summary by CodeRabbit

  • Chores
    • Reduced the runtime container image footprint while preserving non-root execution.
    • Retained support for TLS connections and the configured runtime user.

@coderabbitai

coderabbitai Bot commented Sep 17, 2026

Copy link
Copy Markdown
Contributor

Review Change StackReview Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Enterprise

Run ID: 4a23dc45-6d3f-42b9-9533-aac35dda066e

📥 Commits

Reviewing files that changed from the base of the PR and between 2c64329 and 4a7274f.

📒 Files selected for processing (1)
  • operator/Dockerfile
💤 Files with no reviewable changes (1)
  • operator/Dockerfile

Included review availability: Your plan provides up to 12 included reviews per hour; 11 remain after this review.


📝 Walkthrough

Walkthrough

The operator runtime image changes from Distroless to scratch. The Dockerfile copies the CA certificate bundle and /etc/passwd from the build stage and retains UID/GID 65532:65532.

Changes

Operator runtime image

Layer / File(s) Summary
Scratch runtime configuration
operator/Dockerfile
The runtime base image changes to scratch. The image copies the CA certificate bundle, /etc/passwd, and the operator binary. The non-root UID/GID remains 65532:65532.

Priority: ⬇️ Low

Estimated code review effort: 2 (Simple) | ~10 minutes

Change: Refactor

Merge Risk: ⚪ Minimal · up to 4a727

The operator image retains the files and static binary needed to start under scratch, with no actionable runtime risk identified.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly identifies the main change: building the operator runtime image on scratch. It is concise and specific.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check. Docstring coverage is scoped to functions touched by this diff. Analyzed 0 functions across 0…
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR

Comment @coderabbitai help to get the list of available commands.

AviadHayumi
AviadHayumi previously approved these changes Sep 17, 2026
shaked-bouktus
shaked-bouktus previously approved these changes Sep 17, 2026
The operator image ran on gcr.io/distroless/static-debian13:nonroot, which
already gave a non-root, shell-less base. Moving the final stage to scratch
drops the remaining userland the operator never touches and removes the
gcr.io base-image dependency from the build.

Nothing in the runtime needs what distroless/static supplied:

- No outbound TLS. There is no http.Client, tls.Config or SystemCertPool in
  operator/ or pkg/; the apiserver client uses the projected service-account
  CA, not the system trust store. The CA bundle is carried over anyway so a
  future outbound call fails loudly rather than with a bare x509 error.
- No tzdata use (no time.LoadLocation).
- No writable /tmp needed. The chart sets readOnlyRootFilesystem: true, and
  the webhook serving cert arrives on a secret volume mounted at
  /tmp/k8s-webhook-server/serving-certs, a path kubelet creates.
- USER is numeric, so no /etc/passwd entry is required; passwd is copied for
  tooling that resolves the UID.

Verified by building and running the image: `--help` exits 0, and the rootfs
goes from 46 MB / 1401 files to 43 MB / 17 files, of which only the binary,
/etc/passwd and the CA bundle come from the image.
@yuval-gr
yuval-gr force-pushed the yuval/fix/operator-scratch-image branch from 4a7274f to fed066e Compare September 17, 2026 15:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants