From 6a4ad0b464fa957211b752cda0fb320659e1de7d Mon Sep 17 00:00:00 2001 From: Devesh B <98201065+DeveshB-1@users.noreply.github.com> Date: Mon, 30 Mar 2026 21:57:29 +0530 Subject: [PATCH 1/2] fix(kube): export container healthcheck as LivenessProbe in generate kube Signed-off-by: Devesh B <98201065+DeveshB-1@users.noreply.github.com> --- libpod/kube.go | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/libpod/kube.go b/libpod/kube.go index 5de8fd33d35..8634d485ce7 100644 --- a/libpod/kube.go +++ b/libpod/kube.go @@ -31,6 +31,7 @@ import ( "github.com/sirupsen/logrus" "go.podman.io/common/libnetwork/types" "go.podman.io/common/pkg/config" + "go.podman.io/image/v5/manifest" ) // GenerateForKube takes a slice of libpod containers and generates @@ -1073,9 +1074,35 @@ func containerToV1Container(ctx context.Context, c *Container, getService bool) } dns.Options = dnsOptions } + if hc := c.config.HealthCheckConfig; hc != nil { + kubeContainer.LivenessProbe = healthConfigToProbe(hc) + } + return kubeContainer, kubeVolumes, &dns, annotations, nil } +// healthConfigToProbe converts a container's Schema2HealthConfig into a +// Kubernetes Probe for use as a LivenessProbe in generated kube YAML. +func healthConfigToProbe(hc *manifest.Schema2HealthConfig) *v1.Probe { + if hc == nil || len(hc.Test) == 0 { + return nil + } + // Test[0] is the type: NONE, CMD, or CMD-SHELL. NONE means disabled. + if hc.Test[0] == define.HealthConfigTestNone { + return nil + } + probe := &v1.Probe{ + Handler: v1.Handler{ + Exec: &v1.ExecAction{Command: hc.Test[1:]}, + }, + InitialDelaySeconds: int32(hc.StartPeriod.Seconds()), + TimeoutSeconds: int32(hc.Timeout.Seconds()), + PeriodSeconds: int32(hc.Interval.Seconds()), + FailureThreshold: int32(hc.Retries), + } + return probe +} + // portMappingToContainerPort takes a portmapping and converts // it to a v1.ContainerPort format for kube output func portMappingToContainerPort(portMappings []types.PortMapping, getService bool) ([]v1.ContainerPort, error) { From 1f366e606aeb6fc56eb1ab4c09e8832d1b092e07 Mon Sep 17 00:00:00 2001 From: Devesh B <98201065+DeveshB-1@users.noreply.github.com> Date: Mon, 30 Mar 2026 21:58:03 +0530 Subject: [PATCH 2/2] test(kube): verify healthcheck is exported as LivenessProbe Signed-off-by: Devesh B <98201065+DeveshB-1@users.noreply.github.com> --- test/e2e/generate_kube_test.go | 36 +++++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/test/e2e/generate_kube_test.go b/test/e2e/generate_kube_test.go index 76f0efb73fe..a1e5baf66f3 100644 --- a/test/e2e/generate_kube_test.go +++ b/test/e2e/generate_kube_test.go @@ -2001,4 +2001,38 @@ EXPOSE 2004-2005/tcp`, CITEST_IMAGE) kube.WaitWithDefaultTimeout() Expect(kube).Should(ExitWithError(125, "k8s DaemonSets can only have restartPolicy set to Always")) }) -}) + + It("on container with healthcheck exports LivenessProbe", func() { + ctrName := "test-hc-ctr" + session := podmanTest.Podman([]string{ + "create", "--name", ctrName, + "--health-cmd", "CMD /bin/true", + "--health-interval", "10s", + "--health-timeout", "5s", + "--health-retries", "3", + "--health-start-period", "2s", + CITEST_IMAGE, "top", + }) + session.WaitWithDefaultTimeout() + Expect(session).Should(ExitCleanly()) + + kube := podmanTest.Podman([]string{"kube", "generate", ctrName}) + kube.WaitWithDefaultTimeout() + Expect(kube).Should(ExitCleanly()) + + pod := new(v1.Pod) + err := yaml.Unmarshal(kube.Out.Contents(), pod) + Expect(err).ToNot(HaveOccurred()) + Expect(pod.Spec.Containers).To(HaveLen(1)) + + probe := pod.Spec.Containers[0].LivenessProbe + Expect(probe).ToNot(BeNil(), "LivenessProbe should be set when container has a healthcheck") + Expect(probe.Exec).ToNot(BeNil()) + Expect(probe.Exec.Command).To(ContainElement("/bin/true")) + Expect(probe.PeriodSeconds).To(Equal(int32(10))) + Expect(probe.TimeoutSeconds).To(Equal(int32(5))) + Expect(probe.FailureThreshold).To(Equal(int32(3))) + Expect(probe.InitialDelaySeconds).To(Equal(int32(2))) + }) + +}) \ No newline at end of file