Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ jobs:
deploy_target: test-compat-e2e-olm
- name: supported-clickhouse-compatibility
k8s_image: v1.30.13
clickhouse_version: "26.3,26.2,26.1,25.8"
clickhouse_version: "26.3,26.3-distroless,26.2,26.1,25.8"
deploy_target: test-compat-e2e-manifest
steps:
- name: Checkout code
Expand Down
2 changes: 1 addition & 1 deletion internal/controller/clickhouse/sync.go
Original file line number Diff line number Diff line change
Expand Up @@ -399,11 +399,11 @@ func (r *clickhouseReconciler) reconcileExternalSecret(ctx context.Context, log

func (r *clickhouseReconciler) reconcileVersionProbe(ctx context.Context, log ctrlutil.Logger) (chctrl.StepResult, error) {
probeResult, err := r.VersionProbe(ctx, log, chctrl.VersionProbeConfig{
Binary: "clickhouse-server",
Labels: r.Cluster.Spec.Labels,
Annotations: r.Cluster.Spec.Annotations,
PodTemplate: r.Cluster.Spec.PodTemplate,
ContainerTemplate: r.Cluster.Spec.ContainerTemplate,
Binary: "clickhouse-server",
VersionProbe: r.Cluster.Spec.VersionProbeTemplate,
CachedVersion: r.Cluster.Status.Version,
CachedRevision: r.Cluster.Status.VersionProbeRevision,
Expand Down
2 changes: 1 addition & 1 deletion internal/controller/keeper/sync.go
Original file line number Diff line number Diff line change
Expand Up @@ -204,11 +204,11 @@ func (r *keeperReconciler) reconcileClusterRevisions(ctx context.Context, log ct
}

probeResult, err := r.VersionProbe(ctx, log, chctrl.VersionProbeConfig{
Binary: "clickhouse-keeper",
Labels: r.Cluster.Spec.Labels,
Annotations: r.Cluster.Spec.Annotations,
PodTemplate: r.Cluster.Spec.PodTemplate,
ContainerTemplate: r.Cluster.Spec.ContainerTemplate,
Binary: "clickhouse-keeper",
VersionProbe: r.Cluster.Spec.VersionProbeTemplate,
CachedVersion: r.Cluster.Status.Version,
CachedRevision: r.Cluster.Status.VersionProbeRevision,
Expand Down
26 changes: 23 additions & 3 deletions internal/controller/versionprobe.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,13 @@ const (
DefaultProbeCPURequest = "250m"
DefaultProbeMemoryLimit = "1Gi"
DefaultProbeMemoryRequest = "256Mi"
versionProbeBinary = "/usr/bin/clickhouse"
versionProbeQuery = "INSERT INTO FUNCTION file('/dev/termination-log', 'RawBLOB', 'version String') SELECT version()"
versionProbeShell = "sh"
)

// VersionProbeConfig holds parameters for the version probe Job.
type VersionProbeConfig struct {
// Name of the binary to run.
Binary string
// Labels to apply to the Job, inherited from the cluster spec.
Labels map[string]string
// Annotations to apply to the Job, inherited from the cluster spec.
Expand All @@ -40,6 +41,8 @@ type VersionProbeConfig struct {
PodTemplate v1.PodTemplateSpec
// ContainerTemplate to apply to the Job, inherited from the cluster spec.
ContainerTemplate v1.ContainerTemplateSpec
// Binary is the legacy image binary used for non-distroless version probes.
Binary string
// VersionProbe is the user-provided override for the version probe Job.
VersionProbe *v1.VersionProbeTemplate
// CachedVersion is the previously detected version stored in CR Status.
Expand Down Expand Up @@ -250,7 +253,23 @@ func imageRevision(cfg VersionProbeConfig) (string, error) {
return hash, nil
}

func versionProbeCommand(cfg VersionProbeConfig) ([]string, []string) {
if !isDistrolessImage(cfg.ContainerTemplate.Image.String()) {
return []string{versionProbeShell, "-c"}, []string{
fmt.Sprintf("%s --version > %s 2>&1", cfg.Binary, corev1.TerminationMessagePathDefault),
}
}

return []string{versionProbeBinary}, []string{"local", "--query", versionProbeQuery}
}

func isDistrolessImage(image string) bool {
return strings.Contains(image, "distroless")
}

func (rm *ResourceManager) buildVersionProbeJob(cfg VersionProbeConfig, revision string) (batchv1.Job, error) {
command, args := versionProbeCommand(cfg)

job := batchv1.Job{
ObjectMeta: metav1.ObjectMeta{
Namespace: rm.owner.GetNamespace(),
Expand Down Expand Up @@ -280,7 +299,8 @@ func (rm *ResourceManager) buildVersionProbeJob(cfg VersionProbeConfig, revision
SecurityContext: DefaultContainerSecurityContext(),
TerminationMessagePolicy: corev1.TerminationMessageReadFile,
TerminationMessagePath: corev1.TerminationMessagePathDefault,
Command: []string{"sh", "-c", fmt.Sprintf("%s --version > %s 2>&1", cfg.Binary, corev1.TerminationMessagePathDefault)},
Command: command,
Args: args,
Resources: corev1.ResourceRequirements{
Requests: corev1.ResourceList{
corev1.ResourceCPU: resource.MustParse(DefaultProbeCPURequest),
Expand Down
48 changes: 45 additions & 3 deletions internal/controller/versionprobe_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,8 @@ func baseJob() batchv1.Job {
{
Name: v1.VersionProbeContainerName,
Image: "clickhouse/clickhouse-server:latest",
Command: []string{"sh", "-c", "clickhouse-server --version"},
Command: []string{versionProbeShell, "-c"},
Args: []string{"clickhouse-server --version > /dev/termination-log 2>&1"},
SecurityContext: &corev1.SecurityContext{
RunAsNonRoot: new(true),
},
Expand Down Expand Up @@ -189,7 +190,8 @@ var _ = Describe("patchResource with jobSchema (version probe overrides)", func(

By("verifying container command is preserved")
Expect(container.Image).To(Equal("clickhouse/clickhouse-server:latest"))
Expect(container.Command).To(Equal([]string{"sh", "-c", "clickhouse-server --version"}))
Expect(container.Command).To(Equal([]string{versionProbeShell, "-c"}))
Expect(container.Args).To(Equal([]string{"clickhouse-server --version > /dev/termination-log 2>&1"}))
})

It("should deep-merge securityContext via SMP", func() {
Expand Down Expand Up @@ -311,15 +313,55 @@ func (f *fakeController) GetRecorder() events.EventRecorder { return f.recorder
// probeCfg returns a VersionProbeConfig with the given image and cache values.
func probeCfg(image, cachedVersion, cachedRevision string) VersionProbeConfig {
return VersionProbeConfig{
Binary: "clickhouse-server",
ContainerTemplate: v1.ContainerTemplateSpec{
Image: v1.ContainerImage{Repository: image, Tag: "latest"},
},
Binary: "clickhouse-server",
CachedVersion: cachedVersion,
CachedRevision: cachedRevision,
}
}

var _ = Describe("buildVersionProbeJob", func() {
It("should use a shell-free ClickHouse local command for distroless images", func() {
rm, _ := setupProbeTest()
cfg := probeCfg("clickhouse/clickhouse-keeper", "", "")
cfg.ContainerTemplate.Image.Tag = "latest-distroless"

revision, err := imageRevision(cfg)
Expect(err).NotTo(HaveOccurred())

job, err := rm.buildVersionProbeJob(cfg, revision)
Expect(err).NotTo(HaveOccurred())

container := job.Spec.Template.Spec.Containers[0]

Expect(container.Command).To(Equal([]string{versionProbeBinary}))
Expect(container.Args).To(Equal([]string{"local", "--query", versionProbeQuery}))
Expect(versionProbeQuery).To(ContainSubstring(corev1.TerminationMessagePathDefault))
Expect(container.TerminationMessagePath).To(Equal(corev1.TerminationMessagePathDefault))
Expect(container.TerminationMessagePolicy).To(Equal(corev1.TerminationMessageReadFile))
})

It("should use a shell command for regular images", func() {
rm, _ := setupProbeTest()
cfg := probeCfg("clickhouse/clickhouse-server", "", "")

revision, err := imageRevision(cfg)
Expect(err).NotTo(HaveOccurred())

job, err := rm.buildVersionProbeJob(cfg, revision)
Expect(err).NotTo(HaveOccurred())

container := job.Spec.Template.Spec.Containers[0]

Expect(container.Command).To(Equal([]string{versionProbeShell, "-c"}))
Expect(container.Args).To(Equal([]string{"clickhouse-server --version > /dev/termination-log 2>&1"}))
Expect(container.TerminationMessagePath).To(Equal(corev1.TerminationMessagePathDefault))
Expect(container.TerminationMessagePolicy).To(Equal(corev1.TerminationMessageReadFile))
})
})

var _ = Describe("VersionProbe caching", func() {
It("should return cached version on cache hit without creating a Job", func(ctx context.Context) {
rm, log := setupProbeTest()
Expand Down
Loading