Support tcp/http liveness/readiness probe (#1449)

This commit is contained in:
ichx 2021-11-03 23:30:38 +08:00 committed by GitHub
parent ce46a5ba01
commit d55071e9d6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 1529 additions and 221 deletions

View File

@ -167,13 +167,18 @@ The currently supported options are:
| kompose.controller.type | deployment / daemonset / replicationcontroller |
| kompose.image-pull-policy | kubernetes pods imagePullPolicy |
| kompose.image-pull-secret | kubernetes secret name for imagePullSecrets |
| kompose.service.healthcheck.readiness.disable | kubernetes readiness disable |
| kompose.service.healthcheck.readiness.test | kubernetes readiness exec command |
| kompose.service.healthcheck.readiness.http_get_path | kubernetes readiness httpGet path |
| kompose.service.healthcheck.readiness.http_get_port | kubernetes readiness httpGet port |
| kompose.service.healthcheck.readiness.tcp_port | kubernetes readiness tcpSocket port |
| kompose.service.healthcheck.readiness.interval | kubernetes readiness interval value |
| kompose.service.healthcheck.readiness.timeout | kubernetes readiness timeout value |
| kompose.service.healthcheck.readiness.retries | kubernetes readiness retries value |
| kompose.service.healthcheck.readiness.start_period | kubernetes readiness start_period |
| kompose.service.healthcheck.liveness.http_get_path | kubernetes liveness httpGet path |
| kompose.service.healthcheck.liveness.http_get_port | kubernetes liveness httpGet port |
| kompose.service.healthcheck.liveness.tcp_port | kubernetes liveness tcpSocket port |
**Note**: `kompose.service.type` label should be defined with `ports` only (except for headless service), otherwise `kompose` will fail.

View File

@ -165,7 +165,7 @@ type HealthChecks struct {
}
// HealthCheck the healthcheck configuration for a service
// "StartPeriod" is not yet added to compose, see:
// "StartPeriod" was added to v3.4 of the compose, see:
// https://github.com/docker/cli/issues/116
type HealthCheck struct {
Test []string
@ -176,6 +176,7 @@ type HealthCheck struct {
Disable bool
HTTPPath string
HTTPPort int32
TCPPort int32
}
// EnvVar holds the environment variable struct of a container

View File

@ -41,61 +41,157 @@ func durationTypesPtr(value time.Duration) *types.Duration {
func TestParseHealthCheck(t *testing.T) {
helperValue := uint64(2)
check := types.HealthCheckConfig{
Test: []string{"CMD-SHELL", "echo", "foobar"},
Timeout: durationTypesPtr(1 * time.Second),
Interval: durationTypesPtr(2 * time.Second),
Retries: &helperValue,
StartPeriod: durationTypesPtr(3 * time.Second),
type input struct {
healthCheck types.HealthCheckConfig
labels types.Labels
}
testCases := map[string]struct {
input input
expected kobject.HealthCheck
}{
"Exec": {
input: input{
healthCheck: types.HealthCheckConfig{
Test: []string{"CMD-SHELL", "echo", "foobar"},
Timeout: durationTypesPtr(1 * time.Second),
Interval: durationTypesPtr(2 * time.Second),
Retries: &helperValue,
StartPeriod: durationTypesPtr(3 * time.Second),
},
},
// CMD-SHELL or SHELL is included Test within docker/cli, thus we remove the first value in Test
expected: kobject.HealthCheck{
Test: []string{"echo", "foobar"},
Timeout: 1,
Interval: 2,
Retries: 2,
StartPeriod: 3,
},
},
"HTTPGet": {
input: input{
healthCheck: types.HealthCheckConfig{
Timeout: durationTypesPtr(1 * time.Second),
Interval: durationTypesPtr(2 * time.Second),
Retries: &helperValue,
StartPeriod: durationTypesPtr(3 * time.Second),
},
labels: types.Labels{
"kompose.service.healthcheck.liveness.http_get_path": "/health",
"kompose.service.healthcheck.liveness.http_get_port": "8080",
},
},
expected: kobject.HealthCheck{
HTTPPath: "/health",
HTTPPort: 8080,
Timeout: 1,
Interval: 2,
Retries: 2,
StartPeriod: 3,
},
},
"TCPSocket": {
input: input{
healthCheck: types.HealthCheckConfig{
Timeout: durationTypesPtr(1 * time.Second),
Interval: durationTypesPtr(2 * time.Second),
Retries: &helperValue,
StartPeriod: durationTypesPtr(3 * time.Second),
},
labels: types.Labels{
"kompose.service.healthcheck.liveness.tcp_port": "8080",
},
},
expected: kobject.HealthCheck{
TCPPort: 8080,
Timeout: 1,
Interval: 2,
Retries: 2,
StartPeriod: 3,
},
},
}
// CMD-SHELL or SHELL is included Test within docker/cli, thus we remove the first value in Test
expected := kobject.HealthCheck{
Test: []string{"echo", "foobar"},
Timeout: 1,
Interval: 2,
Retries: 2,
StartPeriod: 3,
}
output, err := parseHealthCheck(check, nil)
if err != nil {
t.Errorf("Unable to convert HealthCheckConfig: %s", err)
}
for name, testCase := range testCases {
t.Log("Test case:", name)
output, err := parseHealthCheck(testCase.input.healthCheck, testCase.input.labels)
if err != nil {
t.Errorf("Unable to convert HealthCheckConfig: %s", err)
}
if !reflect.DeepEqual(output, expected) {
t.Errorf("Structs are not equal, expected: %v, output: %v", expected, output)
if !reflect.DeepEqual(output, testCase.expected) {
t.Errorf("Structs are not equal, expected: %v, output: %v", testCase.expected, output)
}
}
}
func TestParseHttpHealthCheck(t *testing.T) {
helperValue := uint64(2)
check := types.HealthCheckConfig{
Timeout: durationTypesPtr(1 * time.Second),
Interval: durationTypesPtr(2 * time.Second),
Retries: &helperValue,
StartPeriod: durationTypesPtr(3 * time.Second),
}
label := types.Labels{
HealthCheckLivenessHTTPGetPath: "ping",
HealthCheckLivenessHTTPGetPort: "80",
func TestParseHealthCheckReadiness(t *testing.T) {
testCases := map[string]struct {
input types.Labels
expected kobject.HealthCheck
}{
"Exec": {
input: types.Labels{
"kompose.service.healthcheck.readiness.test": "echo foobar",
"kompose.service.healthcheck.readiness.timeout": "1s",
"kompose.service.healthcheck.readiness.interval": "2s",
"kompose.service.healthcheck.readiness.retries": "2",
"kompose.service.healthcheck.readiness.start_period": "3s",
},
expected: kobject.HealthCheck{
Test: []string{"echo", "foobar"},
Timeout: 1,
Interval: 2,
Retries: 2,
StartPeriod: 3,
},
},
"HTTPGet": {
input: types.Labels{
"kompose.service.healthcheck.readiness.http_get_path": "/ready",
"kompose.service.healthcheck.readiness.http_get_port": "8080",
"kompose.service.healthcheck.readiness.timeout": "1s",
"kompose.service.healthcheck.readiness.interval": "2s",
"kompose.service.healthcheck.readiness.retries": "2",
"kompose.service.healthcheck.readiness.start_period": "3s",
},
expected: kobject.HealthCheck{
HTTPPath: "/ready",
HTTPPort: 8080,
Timeout: 1,
Interval: 2,
Retries: 2,
StartPeriod: 3,
},
},
"TCPSocket": {
input: types.Labels{
"kompose.service.healthcheck.readiness.tcp_port": "8080",
"kompose.service.healthcheck.readiness.timeout": "1s",
"kompose.service.healthcheck.readiness.interval": "2s",
"kompose.service.healthcheck.readiness.retries": "2",
"kompose.service.healthcheck.readiness.start_period": "3s",
},
expected: kobject.HealthCheck{
TCPPort: 8080,
Timeout: 1,
Interval: 2,
Retries: 2,
StartPeriod: 3,
},
},
}
// CMD-SHELL or SHELL is included Test within docker/cli, thus we remove the first value in Test
expected := kobject.HealthCheck{
HTTPPath: "ping",
HTTPPort: 80,
Timeout: 1,
Interval: 2,
Retries: 2,
StartPeriod: 3,
}
output, err := parseHealthCheck(check, label)
if err != nil {
t.Errorf("Unable to convert HealthCheckConfig: %s", err)
}
for name, testCase := range testCases {
t.Log("Test case:", name)
output, err := parseHealthCheckReadiness(testCase.input)
if err != nil {
t.Errorf("Unable to convert HealthCheckConfig: %s", err)
}
if !reflect.DeepEqual(output, expected) {
t.Errorf("Structs are not equal, expected: %v, output: %v", expected, output)
if !reflect.DeepEqual(output, testCase.expected) {
t.Errorf("Structs are not equal, expected: %v, output: %v", testCase.expected, output)
}
}
}

View File

@ -60,10 +60,18 @@ const (
HealthCheckReadinessRetries = "kompose.service.healthcheck.readiness.retries"
// HealthCheckReadinessStartPeriod defines readiness health check start period
HealthCheckReadinessStartPeriod = "kompose.service.healthcheck.readiness.start_period"
// HealthCheckReadinessHTTPGetPath defines readiness health check HttpGet path
HealthCheckReadinessHTTPGetPath = "kompose.service.healthcheck.readiness.http_get_path"
// HealthCheckReadinessHTTPGetPort defines readiness health check HttpGet port
HealthCheckReadinessHTTPGetPort = "kompose.service.healthcheck.readiness.http_get_port"
// HealthCheckReadinessTCPPort defines readiness health check tcp port
HealthCheckReadinessTCPPort = "kompose.service.healthcheck.readiness.tcp_port"
// HealthCheckLivenessHTTPGetPath defines liveness health check HttpGet path
HealthCheckLivenessHTTPGetPath = "kompose.service.healthcheck.liveness.http_get_path"
// HealthCheckLivenessHTTPGetPort defines liveness health check HttpGet port
HealthCheckLivenessHTTPGetPort = "kompose.service.healthcheck.liveness.http_get_port"
// HealthCheckLivenessTCPPort defines liveness health check tcp port
HealthCheckLivenessTCPPort = "kompose.service.healthcheck.liveness.tcp_port"
// ServiceTypeHeadless ...
ServiceTypeHeadless = "Headless"

View File

@ -245,9 +245,9 @@ func loadV3Ports(ports []types.ServicePortConfig, expose []string) []kobject.Por
a Kubernetes-compatible format.
*/
func parseHealthCheckReadiness(labels types.Labels) (kobject.HealthCheck, error) {
// initialize with CMD as default to not break at return (will be ignored if no test is informed)
test := []string{"CMD"}
var timeout, interval, retries, startPeriod int32
var test []string
var httpPath string
var httpPort, tcpPort, timeout, interval, retries, startPeriod int32
var disable bool
for key, value := range labels {
@ -258,6 +258,12 @@ func parseHealthCheckReadiness(labels types.Labels) (kobject.HealthCheck, error)
if len(value) > 0 {
test, _ = shlex.Split(value)
}
case HealthCheckReadinessHTTPGetPath:
httpPath = value
case HealthCheckReadinessHTTPGetPort:
httpPort = cast.ToInt32(value)
case HealthCheckReadinessTCPPort:
tcpPort = cast.ToInt32(value)
case HealthCheckReadinessInterval:
parse, err := time.ParseDuration(value)
if err != nil {
@ -281,17 +287,22 @@ func parseHealthCheckReadiness(labels types.Labels) (kobject.HealthCheck, error)
}
}
if test[0] == "NONE" {
disable = true
test = test[1:]
}
if test[0] == "CMD" || test[0] == "CMD-SHELL" {
test = test[1:]
if len(test) > 0 {
if test[0] == "NONE" {
disable = true
test = test[1:]
}
// Due to docker/cli adding "CMD-SHELL" to the struct, we remove the first element of composeHealthCheck.Test
if test[0] == "CMD" || test[0] == "CMD-SHELL" {
test = test[1:]
}
}
// Due to docker/cli adding "CMD-SHELL" to the struct, we remove the first element of composeHealthCheck.Test
return kobject.HealthCheck{
Test: test,
HTTPPath: httpPath,
HTTPPort: httpPort,
TCPPort: tcpPort,
Timeout: timeout,
Interval: interval,
Retries: retries,
@ -304,9 +315,8 @@ func parseHealthCheckReadiness(labels types.Labels) (kobject.HealthCheck, error)
a Kubernetes-compatible format.
*/
func parseHealthCheck(composeHealthCheck types.HealthCheckConfig, labels types.Labels) (kobject.HealthCheck, error) {
var timeout, interval, retries, startPeriod int32
var httpPort, tcpPort, timeout, interval, retries, startPeriod int32
var test []string
var httpPort int32
var httpPath string
// Here we convert the timeout from 1h30s (example) to 36030 seconds.
@ -348,12 +358,15 @@ func parseHealthCheck(composeHealthCheck types.HealthCheckConfig, labels types.L
httpPath = value
case HealthCheckLivenessHTTPGetPort:
httpPort = cast.ToInt32(value)
case HealthCheckLivenessTCPPort:
tcpPort = cast.ToInt32(value)
}
}
// Due to docker/cli adding "CMD-SHELL" to the struct, we remove the first element of composeHealthCheck.Test
return kobject.HealthCheck{
Test: test,
TCPPort: tcpPort,
HTTPPath: httpPath,
HTTPPort: httpPort,
Timeout: timeout,
@ -426,7 +439,7 @@ func dockerComposeToKomposeMapping(composeObject *types.Config) (kobject.Kompose
// HealthCheck Readiness
var readiness, errReadiness = parseHealthCheckReadiness(*&composeServiceConfig.Labels)
if readiness.Test != nil && len(readiness.Test) > 0 && len(readiness.Test[0]) > 0 && !readiness.Disable {
if !readiness.Disable {
serviceConfig.HealthChecks.Readiness = readiness
if errReadiness != nil {
return kobject.KomposeObject{}, errors.Wrap(errReadiness, "Unable to parse health check")

View File

@ -45,7 +45,6 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/util/intstr"
)
/**
@ -534,62 +533,8 @@ func (k *Kubernetes) UpdateKubernetesObjects(name string, service kobject.Servic
template.Spec.Volumes = append(template.Spec.Volumes, volumes...)
template.Spec.Affinity = ConfigAffinity(service)
// Configure the HealthCheck
// We check to see if it's blank
if !reflect.DeepEqual(service.HealthChecks.Liveness, kobject.HealthCheck{}) {
probe := api.Probe{}
if len(service.HealthChecks.Liveness.Test) > 0 {
probe.Handler = api.Handler{
Exec: &api.ExecAction{
Command: service.HealthChecks.Liveness.Test,
},
}
} else if !reflect.ValueOf(service.HealthChecks.Liveness.HTTPPath).IsZero() &&
!reflect.ValueOf(service.HealthChecks.Liveness.HTTPPort).IsZero() {
probe.Handler = api.Handler{
HTTPGet: &api.HTTPGetAction{
Path: service.HealthChecks.Liveness.HTTPPath,
Port: intstr.FromInt(int(service.HealthChecks.Liveness.HTTPPort)),
},
}
} else {
return errors.New("Health check must contain a command")
}
probe.TimeoutSeconds = service.HealthChecks.Liveness.Timeout
probe.PeriodSeconds = service.HealthChecks.Liveness.Interval
probe.FailureThreshold = service.HealthChecks.Liveness.Retries
// See issue: https://github.com/docker/cli/issues/116
// StartPeriod has been added to docker/cli however, it is not yet added
// to compose. Once the feature has been implemented, this will automatically work
probe.InitialDelaySeconds = service.HealthChecks.Liveness.StartPeriod
template.Spec.Containers[0].LivenessProbe = &probe
}
if !reflect.DeepEqual(service.HealthChecks.Readiness, kobject.HealthCheck{}) {
probeHealthCheckReadiness := api.Probe{}
if len(service.HealthChecks.Readiness.Test) > 0 {
probeHealthCheckReadiness.Handler = api.Handler{
Exec: &api.ExecAction{
Command: service.HealthChecks.Readiness.Test,
},
}
} else {
return errors.New("Health check must contain a command")
}
probeHealthCheckReadiness.TimeoutSeconds = service.HealthChecks.Readiness.Timeout
probeHealthCheckReadiness.PeriodSeconds = service.HealthChecks.Readiness.Interval
probeHealthCheckReadiness.FailureThreshold = service.HealthChecks.Readiness.Retries
// See issue: https://github.com/docker/cli/issues/116
// StartPeriod has been added to docker/cli however, it is not yet added
// to compose. Once the feature has been implemented, this will automatically work
probeHealthCheckReadiness.InitialDelaySeconds = service.HealthChecks.Readiness.StartPeriod
template.Spec.Containers[0].ReadinessProbe = &probeHealthCheckReadiness
}
template.Spec.Containers[0].LivenessProbe = configProbe(service.HealthChecks.Liveness)
template.Spec.Containers[0].ReadinessProbe = configProbe(service.HealthChecks.Readiness)
if service.StopGracePeriod != "" {
template.Spec.TerminationGracePeriodSeconds, err = DurationStrToSecondsInt(service.StopGracePeriod)

View File

@ -352,41 +352,96 @@ func TestIsDir(t *testing.T) {
}
}
// TestServiceWithoutPort this tests if Headless Service is created for services without Port.
// TestServiceWithHealthCheck this tests if Headless Service is created for services with HealthCheck.
func TestServiceWithHealthCheck(t *testing.T) {
service := kobject.ServiceConfig{
ContainerName: "name",
Image: "image",
ServiceType: "Headless",
HealthChecks: kobject.HealthChecks{
Readiness: kobject.HealthCheck{
Test: []string{"arg1", "arg2"},
Timeout: 10,
Interval: 5,
Retries: 3,
StartPeriod: 60,
testCases := map[string]struct {
service kobject.ServiceConfig
}{
"Exec": {
service: kobject.ServiceConfig{
ContainerName: "name",
Image: "image",
ServiceType: "Headless",
HealthChecks: kobject.HealthChecks{
Readiness: kobject.HealthCheck{
Test: []string{"arg1", "arg2"},
Timeout: 10,
Interval: 5,
Retries: 3,
StartPeriod: 60,
},
Liveness: kobject.HealthCheck{
Test: []string{"arg1", "arg2"},
Timeout: 11,
Interval: 6,
Retries: 4,
StartPeriod: 61,
},
},
},
Liveness: kobject.HealthCheck{
Test: []string{"arg1", "arg2"},
Timeout: 11,
Interval: 6,
Retries: 4,
StartPeriod: 61,
},
"HTTPGet": {
service: kobject.ServiceConfig{
ContainerName: "name",
Image: "image",
ServiceType: "Headless",
HealthChecks: kobject.HealthChecks{
Readiness: kobject.HealthCheck{
HTTPPath: "/health",
HTTPPort: 8080,
Timeout: 10,
Interval: 5,
Retries: 3,
StartPeriod: 60,
},
Liveness: kobject.HealthCheck{
HTTPPath: "/ready",
HTTPPort: 8080,
Timeout: 11,
Interval: 6,
Retries: 4,
StartPeriod: 61,
},
},
},
},
"TCPSocket": {
service: kobject.ServiceConfig{
ContainerName: "name",
Image: "image",
ServiceType: "Headless",
HealthChecks: kobject.HealthChecks{
Readiness: kobject.HealthCheck{
TCPPort: 8080,
Timeout: 10,
Interval: 5,
Retries: 3,
StartPeriod: 60,
},
Liveness: kobject.HealthCheck{
TCPPort: 8080,
Timeout: 11,
Interval: 6,
Retries: 4,
StartPeriod: 61,
},
},
},
},
}
komposeObject := kobject.KomposeObject{
ServiceConfigs: map[string]kobject.ServiceConfig{"app": service},
}
k := Kubernetes{}
objects, err := k.Transform(komposeObject, kobject.ConvertOptions{CreateD: true, Replicas: 1})
if err != nil {
t.Error(errors.Wrap(err, "k.Transform failed"))
}
if err := testutils.CheckForHealthCheckLivenessAndReadiness(objects); err != nil {
t.Error(err)
for _, testCase := range testCases {
k := Kubernetes{}
komposeObject := kobject.KomposeObject{
ServiceConfigs: map[string]kobject.ServiceConfig{"app": testCase.service},
}
objects, err := k.Transform(komposeObject, kobject.ConvertOptions{CreateD: true, Replicas: 1})
if err != nil {
t.Error(errors.Wrap(err, "k.Transform failed"))
}
if err := testutils.CheckForHealthCheckLivenessAndReadiness(objects); err != nil {
t.Error(err)
}
}
}

View File

@ -1363,8 +1363,6 @@ func (k *Kubernetes) Transform(komposeObject kobject.KomposeObject, opt kobject.
ImagePullPolicy(name, service),
RestartPolicy(name, service),
SecurityContext(name, service),
LivenessProbe(service),
ReadinessProbe(service),
HostName(service),
DomainName(service),
ResourcesLimits(service),

View File

@ -744,6 +744,84 @@ func TestServiceAccountNameOnMultipleContainers(t *testing.T) {
}
}
func TestHealthCheckOnMultipleContainers(t *testing.T) {
groupName := "pod_group"
createHealthCheck := func(TCPPort int32) kobject.HealthCheck {
return kobject.HealthCheck{
TCPPort: TCPPort,
}
}
createConfig := func(name string, livenessTCPPort, readinessTCPPort int32) kobject.ServiceConfig {
config := newSimpleServiceConfig()
config.Labels = map[string]string{compose.LabelServiceGroup: groupName}
config.Name = name
config.ContainerName = name
config.HealthChecks.Liveness = createHealthCheck(livenessTCPPort)
config.HealthChecks.Readiness = createHealthCheck(readinessTCPPort)
return config
}
testCases := map[string]struct {
komposeObject kobject.KomposeObject
opt kobject.ConvertOptions
expectedContainers map[string]api.Container
}{
"Converted multiple containers to Deployments": {
kobject.KomposeObject{
ServiceConfigs: map[string]kobject.ServiceConfig{
"app1": createConfig("app1", 8081, 9091),
"app2": createConfig("app2", 8082, 9092),
},
},
kobject.ConvertOptions{ServiceGroupMode: "label", CreateD: true},
map[string]api.Container{
"app1": {
LivenessProbe: configProbe(createHealthCheck(8081)),
ReadinessProbe: configProbe(createHealthCheck(9091)),
},
"app2": {
LivenessProbe: configProbe(createHealthCheck(8082)),
ReadinessProbe: configProbe(createHealthCheck(9092)),
},
},
},
}
for name, test := range testCases {
t.Log("Test case:", name)
k := Kubernetes{}
// Run Transform
objs, err := k.Transform(test.komposeObject, test.opt)
if err != nil {
t.Error(errors.Wrap(err, "k.Transform failed"))
}
// Check results
for _, obj := range objs {
if deployment, ok := obj.(*appsv1.Deployment); ok {
if len(deployment.Spec.Template.Spec.Containers) != len(test.expectedContainers) {
t.Errorf("Containers len is not equal, expected %d, got %d",
len(deployment.Spec.Template.Spec.Containers), len(test.expectedContainers))
}
for _, result := range deployment.Spec.Template.Spec.Containers {
expected, ok := test.expectedContainers[result.Name]
if !ok {
t.Errorf("Container %s doesn't expected", result.Name)
}
if !reflect.DeepEqual(result.LivenessProbe, expected.LivenessProbe) {
t.Errorf("Container %s: LivenessProbe expected %v returned, got %v", result.Name, expected.LivenessProbe, result.LivenessProbe)
}
if !reflect.DeepEqual(result.ReadinessProbe, expected.ReadinessProbe) {
t.Errorf("Container %s: ReadinessProbe expected %v returned, got %v", result.Name, expected.ReadinessProbe, result.ReadinessProbe)
}
}
}
}
}
}
func TestCreatePVC(t *testing.T) {
storageClassName := "custom-storage-class-name"
k := Kubernetes{}

View File

@ -34,14 +34,16 @@ func AddContainer(service kobject.ServiceConfig, opt kobject.ConvertOptions) Pod
}
podSpec.Containers = append(podSpec.Containers, api.Container{
Name: name,
Image: image,
Env: envs,
Command: service.Command,
Args: service.Args,
WorkingDir: service.WorkingDir,
Stdin: service.Stdin,
TTY: service.Tty,
Name: name,
Image: image,
Env: envs,
Command: service.Command,
Args: service.Args,
WorkingDir: service.WorkingDir,
Stdin: service.Stdin,
TTY: service.Tty,
LivenessProbe: configProbe(service.HealthChecks.Liveness),
ReadinessProbe: configProbe(service.HealthChecks.Readiness),
})
podSpec.Affinity = ConfigAffinity(service)
@ -258,75 +260,44 @@ func DomainName(service kobject.ServiceConfig) PodSpecOption {
}
}
func LivenessProbe(service kobject.ServiceConfig) PodSpecOption {
return func(podSpec *PodSpec) {
// Configure the HealthCheck
// We check to see if it's blank
if !reflect.DeepEqual(service.HealthChecks.Liveness, kobject.HealthCheck{}) {
probe := api.Probe{}
if len(service.HealthChecks.Liveness.Test) > 0 {
probe.Handler = api.Handler{
Exec: &api.ExecAction{
Command: service.HealthChecks.Liveness.Test,
},
}
} else if !reflect.ValueOf(service.HealthChecks.Liveness.HTTPPath).IsZero() &&
!reflect.ValueOf(service.HealthChecks.Liveness.HTTPPort).IsZero() {
probe.Handler = api.Handler{
HTTPGet: &api.HTTPGetAction{
Path: service.HealthChecks.Liveness.HTTPPath,
Port: intstr.FromInt(int(service.HealthChecks.Liveness.HTTPPort)),
},
}
} else {
panic(errors.New("Health check must contain a command"))
}
probe.TimeoutSeconds = service.HealthChecks.Liveness.Timeout
probe.PeriodSeconds = service.HealthChecks.Liveness.Interval
probe.FailureThreshold = service.HealthChecks.Liveness.Retries
// See issue: https://github.com/docker/cli/issues/116
// StartPeriod has been added to docker/cli however, it is not yet added
// to compose. Once the feature has been implemented, this will automatically work
probe.InitialDelaySeconds = service.HealthChecks.Liveness.StartPeriod
for i := range podSpec.Containers {
podSpec.Containers[i].LivenessProbe = &probe
}
}
func configProbe(healthCheck kobject.HealthCheck) *api.Probe {
probe := api.Probe{}
// We check to see if it's blank or disable
if reflect.DeepEqual(healthCheck, kobject.HealthCheck{}) || healthCheck.Disable {
return nil
}
}
func ReadinessProbe(service kobject.ServiceConfig) PodSpecOption {
return func(podSpec *PodSpec) {
if !reflect.DeepEqual(service.HealthChecks.Readiness, kobject.HealthCheck{}) {
probeHealthCheckReadiness := api.Probe{}
if len(service.HealthChecks.Readiness.Test) > 0 {
probeHealthCheckReadiness.Handler = api.Handler{
Exec: &api.ExecAction{
Command: service.HealthChecks.Readiness.Test,
},
}
} else {
panic(errors.New("Health check must contain a command"))
}
probeHealthCheckReadiness.TimeoutSeconds = service.HealthChecks.Readiness.Timeout
probeHealthCheckReadiness.PeriodSeconds = service.HealthChecks.Readiness.Interval
probeHealthCheckReadiness.FailureThreshold = service.HealthChecks.Readiness.Retries
// See issue: https://github.com/docker/cli/issues/116
// StartPeriod has been added to docker/cli however, it is not yet added
// to compose. Once the feature has been implemented, this will automatically work
probeHealthCheckReadiness.InitialDelaySeconds = service.HealthChecks.Readiness.StartPeriod
for i := range podSpec.Containers {
podSpec.Containers[i].ReadinessProbe = &probeHealthCheckReadiness
}
if len(healthCheck.Test) > 0 {
probe.Handler = api.Handler{
Exec: &api.ExecAction{
Command: healthCheck.Test,
},
}
} else if !reflect.ValueOf(healthCheck.HTTPPath).IsZero() && !reflect.ValueOf(healthCheck.HTTPPort).IsZero() {
probe.Handler = api.Handler{
HTTPGet: &api.HTTPGetAction{
Path: healthCheck.HTTPPath,
Port: intstr.FromInt(int(healthCheck.HTTPPort)),
},
}
} else if !reflect.ValueOf(healthCheck.TCPPort).IsZero() {
probe.Handler = api.Handler{
TCPSocket: &api.TCPSocketAction{
Port: intstr.FromInt(int(healthCheck.TCPPort)),
},
}
} else {
panic(errors.New("Health check must contain a command"))
}
probe.TimeoutSeconds = healthCheck.Timeout
probe.PeriodSeconds = healthCheck.Interval
probe.FailureThreshold = healthCheck.Retries
// See issue: https://github.com/docker/cli/issues/116
// StartPeriod has been added to v3.4 of the compose
probe.InitialDelaySeconds = healthCheck.StartPeriod
return &probe
}
func ServiceAccountName(serviceAccountName string) PodSpecOption {

View File

@ -171,3 +171,11 @@ k8s_output="$KOMPOSE_ROOT/script/test/fixtures/multiple-files/output-k8s.json"
ocp_output="$KOMPOSE_ROOT/script/test/fixtures/multiple-files/output-ocp.json"
convert::expect_success_and_warning "$k8s_cmd" "$k8s_output"
convert::expect_success "$ocp_cmd" "$ocp_output"
# test health check
k8s_cmd="kompose -f $KOMPOSE_ROOT/script/test/fixtures/healthcheck/docker-compose-healthcheck.yaml convert --stdout -j --service-group-mode=label --with-kompose-annotation=false"
os_cmd="kompose --provider=openshift -f $KOMPOSE_ROOT/script/test/fixtures/healthcheck/docker-compose-healthcheck.yaml convert --stdout -j --service-group-mode=label --with-kompose-annotation=false"
k8s_output="$KOMPOSE_ROOT/script/test/fixtures/healthcheck/output-healthcheck-k8s.json"
os_output="$KOMPOSE_ROOT/script/test/fixtures/healthcheck/output-healthcheck-os.json"
convert::expect_success "$k8s_cmd" "$k8s_output"
convert::expect_success "$os_cmd" "$os_output"

View File

@ -0,0 +1,69 @@
version: "3.3"
services:
# test exec
redis:
image: redis
ports:
- "6379"
healthcheck:
test: echo "liveness"
interval: 10s
timeout: 1s
retries: 5
labels:
kompose.service.healthcheck.readiness.test: echo "liveness"
kompose.service.healthcheck.readiness.interval: 10s
kompose.service.healthcheck.readiness.timeout: 1s
kompose.service.healthcheck.readiness.retries: 5
# test http get
postgresql:
image: postgresql
ports:
- "5432"
healthcheck:
interval: 10s
timeout: 1s
retries: 5
labels:
kompose.service.healthcheck.liveness.http_get_path: /health
kompose.service.healthcheck.liveness.http_get_port: 8080
kompose.service.healthcheck.readiness.http_get_path: /ready
kompose.service.healthcheck.readiness.http_get_port: 8080
kompose.service.healthcheck.readiness.interval: 10s
kompose.service.healthcheck.readiness.timeout: 1s
kompose.service.healthcheck.readiness.retries: 5
# test tcp socket
mongo:
image: mongo
ports:
- "27017"
healthcheck:
interval: 10s
timeout: 1s
retries: 5
labels:
kompose.service.group: "my-group"
kompose.service.healthcheck.liveness.tcp_port: 8080
kompose.service.healthcheck.readiness.tcp_port: 9090
kompose.service.healthcheck.readiness.interval: 10s
kompose.service.healthcheck.readiness.timeout: 1s
kompose.service.healthcheck.readiness.retries: 5
# test multiple service merge
mysql:
image: mysql
ports:
- "3306"
healthcheck:
interval: 11s
timeout: 2s
retries: 6
labels:
kompose.service.group: "my-group"
kompose.service.healthcheck.liveness.tcp_port: 8081
kompose.service.healthcheck.readiness.tcp_port: 9091
kompose.service.healthcheck.readiness.interval: 11s
kompose.service.healthcheck.readiness.timeout: 2s
kompose.service.healthcheck.readiness.retries: 6

View File

@ -0,0 +1,401 @@
{
"kind": "List",
"apiVersion": "v1",
"metadata": {},
"items": [
{
"kind": "Service",
"apiVersion": "v1",
"metadata": {
"name": "mongo",
"creationTimestamp": null,
"labels": {
"io.kompose.service": "my-group"
},
"annotations": {
"kompose.service.group": "my-group",
"kompose.service.healthcheck.liveness.tcp_port": "8080",
"kompose.service.healthcheck.readiness.interval": "10s",
"kompose.service.healthcheck.readiness.retries": "5",
"kompose.service.healthcheck.readiness.tcp_port": "9090",
"kompose.service.healthcheck.readiness.timeout": "1s"
}
},
"spec": {
"ports": [
{
"name": "27017",
"port": 27017,
"targetPort": 27017
}
],
"selector": {
"io.kompose.service": "my-group"
}
},
"status": {
"loadBalancer": {}
}
},
{
"kind": "Service",
"apiVersion": "v1",
"metadata": {
"name": "mysql",
"creationTimestamp": null,
"labels": {
"io.kompose.service": "my-group"
},
"annotations": {
"kompose.service.group": "my-group",
"kompose.service.healthcheck.liveness.tcp_port": "8081",
"kompose.service.healthcheck.readiness.interval": "11s",
"kompose.service.healthcheck.readiness.retries": "6",
"kompose.service.healthcheck.readiness.tcp_port": "9091",
"kompose.service.healthcheck.readiness.timeout": "2s"
}
},
"spec": {
"ports": [
{
"name": "3306",
"port": 3306,
"targetPort": 3306
}
],
"selector": {
"io.kompose.service": "my-group"
}
},
"status": {
"loadBalancer": {}
}
},
{
"kind": "Service",
"apiVersion": "v1",
"metadata": {
"name": "postgresql",
"creationTimestamp": null,
"labels": {
"io.kompose.service": "postgresql"
},
"annotations": {
"kompose.service.healthcheck.liveness.http_get_path": "/health",
"kompose.service.healthcheck.liveness.http_get_port": "8080",
"kompose.service.healthcheck.readiness.http_get_path": "/ready",
"kompose.service.healthcheck.readiness.http_get_port": "8080",
"kompose.service.healthcheck.readiness.interval": "10s",
"kompose.service.healthcheck.readiness.retries": "5",
"kompose.service.healthcheck.readiness.timeout": "1s"
}
},
"spec": {
"ports": [
{
"name": "5432",
"port": 5432,
"targetPort": 5432
}
],
"selector": {
"io.kompose.service": "postgresql"
}
},
"status": {
"loadBalancer": {}
}
},
{
"kind": "Service",
"apiVersion": "v1",
"metadata": {
"name": "redis",
"creationTimestamp": null,
"labels": {
"io.kompose.service": "redis"
},
"annotations": {
"kompose.service.healthcheck.readiness.interval": "10s",
"kompose.service.healthcheck.readiness.retries": "5",
"kompose.service.healthcheck.readiness.test": "echo \"liveness\"",
"kompose.service.healthcheck.readiness.timeout": "1s"
}
},
"spec": {
"ports": [
{
"name": "6379",
"port": 6379,
"targetPort": 6379
}
],
"selector": {
"io.kompose.service": "redis"
}
},
"status": {
"loadBalancer": {}
}
},
{
"kind": "Deployment",
"apiVersion": "apps/v1",
"metadata": {
"name": "my-group",
"creationTimestamp": null,
"labels": {
"io.kompose.service": "my-group"
},
"annotations": {
"kompose.service.group": "my-group",
"kompose.service.healthcheck.liveness.tcp_port": "8081",
"kompose.service.healthcheck.readiness.interval": "11s",
"kompose.service.healthcheck.readiness.retries": "6",
"kompose.service.healthcheck.readiness.tcp_port": "9091",
"kompose.service.healthcheck.readiness.timeout": "2s"
}
},
"spec": {
"replicas": 1,
"selector": {
"matchLabels": {
"io.kompose.service": "my-group"
}
},
"template": {
"metadata": {
"creationTimestamp": null,
"labels": {
"io.kompose.service": "my-group"
},
"annotations": {
"kompose.service.group": "my-group",
"kompose.service.healthcheck.liveness.tcp_port": "8080",
"kompose.service.healthcheck.readiness.interval": "10s",
"kompose.service.healthcheck.readiness.retries": "5",
"kompose.service.healthcheck.readiness.tcp_port": "9090",
"kompose.service.healthcheck.readiness.timeout": "1s"
}
},
"spec": {
"containers": [
{
"name": "mongo",
"image": "mongo",
"ports": [
{
"containerPort": 27017
}
],
"resources": {},
"livenessProbe": {
"tcpSocket": {
"port": 8080
},
"timeoutSeconds": 1,
"periodSeconds": 10,
"failureThreshold": 5
},
"readinessProbe": {
"tcpSocket": {
"port": 9090
},
"timeoutSeconds": 1,
"periodSeconds": 10,
"failureThreshold": 5
}
},
{
"name": "mysql",
"image": "mysql",
"ports": [
{
"containerPort": 3306
}
],
"resources": {},
"livenessProbe": {
"tcpSocket": {
"port": 8081
},
"timeoutSeconds": 2,
"periodSeconds": 11,
"failureThreshold": 6
},
"readinessProbe": {
"tcpSocket": {
"port": 9091
},
"timeoutSeconds": 2,
"periodSeconds": 11,
"failureThreshold": 6
}
}
],
"restartPolicy": "Always"
}
},
"strategy": {}
},
"status": {}
},
{
"kind": "Deployment",
"apiVersion": "apps/v1",
"metadata": {
"name": "postgresql",
"creationTimestamp": null,
"labels": {
"io.kompose.service": "postgresql"
},
"annotations": {
"kompose.service.healthcheck.liveness.http_get_path": "/health",
"kompose.service.healthcheck.liveness.http_get_port": "8080",
"kompose.service.healthcheck.readiness.http_get_path": "/ready",
"kompose.service.healthcheck.readiness.http_get_port": "8080",
"kompose.service.healthcheck.readiness.interval": "10s",
"kompose.service.healthcheck.readiness.retries": "5",
"kompose.service.healthcheck.readiness.timeout": "1s"
}
},
"spec": {
"replicas": 1,
"selector": {
"matchLabels": {
"io.kompose.service": "postgresql"
}
},
"template": {
"metadata": {
"creationTimestamp": null,
"labels": {
"io.kompose.service": "postgresql"
},
"annotations": {
"kompose.service.healthcheck.liveness.http_get_path": "/health",
"kompose.service.healthcheck.liveness.http_get_port": "8080",
"kompose.service.healthcheck.readiness.http_get_path": "/ready",
"kompose.service.healthcheck.readiness.http_get_port": "8080",
"kompose.service.healthcheck.readiness.interval": "10s",
"kompose.service.healthcheck.readiness.retries": "5",
"kompose.service.healthcheck.readiness.timeout": "1s"
}
},
"spec": {
"containers": [
{
"name": "postgresql",
"image": "postgresql",
"ports": [
{
"containerPort": 5432
}
],
"resources": {},
"livenessProbe": {
"httpGet": {
"path": "/health",
"port": 8080
},
"timeoutSeconds": 1,
"periodSeconds": 10,
"failureThreshold": 5
},
"readinessProbe": {
"httpGet": {
"path": "/ready",
"port": 8080
},
"timeoutSeconds": 1,
"periodSeconds": 10,
"failureThreshold": 5
}
}
],
"restartPolicy": "Always"
}
},
"strategy": {}
},
"status": {}
},
{
"kind": "Deployment",
"apiVersion": "apps/v1",
"metadata": {
"name": "redis",
"creationTimestamp": null,
"labels": {
"io.kompose.service": "redis"
},
"annotations": {
"kompose.service.healthcheck.readiness.interval": "10s",
"kompose.service.healthcheck.readiness.retries": "5",
"kompose.service.healthcheck.readiness.test": "echo \"liveness\"",
"kompose.service.healthcheck.readiness.timeout": "1s"
}
},
"spec": {
"replicas": 1,
"selector": {
"matchLabels": {
"io.kompose.service": "redis"
}
},
"template": {
"metadata": {
"creationTimestamp": null,
"labels": {
"io.kompose.service": "redis"
},
"annotations": {
"kompose.service.healthcheck.readiness.interval": "10s",
"kompose.service.healthcheck.readiness.retries": "5",
"kompose.service.healthcheck.readiness.test": "echo \"liveness\"",
"kompose.service.healthcheck.readiness.timeout": "1s"
}
},
"spec": {
"containers": [
{
"name": "redis",
"image": "redis",
"ports": [
{
"containerPort": 6379
}
],
"resources": {},
"livenessProbe": {
"exec": {
"command": [
"echo \"liveness\""
]
},
"timeoutSeconds": 1,
"periodSeconds": 10,
"failureThreshold": 5
},
"readinessProbe": {
"exec": {
"command": [
"echo",
"liveness"
]
},
"timeoutSeconds": 1,
"periodSeconds": 10,
"failureThreshold": 5
}
}
],
"restartPolicy": "Always"
}
},
"strategy": {}
},
"status": {}
}
]
}

View File

@ -0,0 +1,660 @@
{
"kind": "List",
"apiVersion": "v1",
"metadata": {},
"items": [
{
"kind": "Service",
"apiVersion": "v1",
"metadata": {
"name": "mongo",
"creationTimestamp": null,
"labels": {
"io.kompose.service": "mongo"
},
"annotations": {
"kompose.service.group": "my-group",
"kompose.service.healthcheck.liveness.tcp_port": "8080",
"kompose.service.healthcheck.readiness.interval": "10s",
"kompose.service.healthcheck.readiness.retries": "5",
"kompose.service.healthcheck.readiness.tcp_port": "9090",
"kompose.service.healthcheck.readiness.timeout": "1s"
}
},
"spec": {
"ports": [
{
"name": "27017",
"port": 27017,
"targetPort": 27017
}
],
"selector": {
"io.kompose.service": "mongo"
}
},
"status": {
"loadBalancer": {}
}
},
{
"kind": "Service",
"apiVersion": "v1",
"metadata": {
"name": "mysql",
"creationTimestamp": null,
"labels": {
"io.kompose.service": "mysql"
},
"annotations": {
"kompose.service.group": "my-group",
"kompose.service.healthcheck.liveness.tcp_port": "8081",
"kompose.service.healthcheck.readiness.interval": "11s",
"kompose.service.healthcheck.readiness.retries": "6",
"kompose.service.healthcheck.readiness.tcp_port": "9091",
"kompose.service.healthcheck.readiness.timeout": "2s"
}
},
"spec": {
"ports": [
{
"name": "3306",
"port": 3306,
"targetPort": 3306
}
],
"selector": {
"io.kompose.service": "mysql"
}
},
"status": {
"loadBalancer": {}
}
},
{
"kind": "Service",
"apiVersion": "v1",
"metadata": {
"name": "postgresql",
"creationTimestamp": null,
"labels": {
"io.kompose.service": "postgresql"
},
"annotations": {
"kompose.service.healthcheck.liveness.http_get_path": "/health",
"kompose.service.healthcheck.liveness.http_get_port": "8080",
"kompose.service.healthcheck.readiness.http_get_path": "/ready",
"kompose.service.healthcheck.readiness.http_get_port": "8080",
"kompose.service.healthcheck.readiness.interval": "10s",
"kompose.service.healthcheck.readiness.retries": "5",
"kompose.service.healthcheck.readiness.timeout": "1s"
}
},
"spec": {
"ports": [
{
"name": "5432",
"port": 5432,
"targetPort": 5432
}
],
"selector": {
"io.kompose.service": "postgresql"
}
},
"status": {
"loadBalancer": {}
}
},
{
"kind": "Service",
"apiVersion": "v1",
"metadata": {
"name": "redis",
"creationTimestamp": null,
"labels": {
"io.kompose.service": "redis"
},
"annotations": {
"kompose.service.healthcheck.readiness.interval": "10s",
"kompose.service.healthcheck.readiness.retries": "5",
"kompose.service.healthcheck.readiness.test": "echo \"liveness\"",
"kompose.service.healthcheck.readiness.timeout": "1s"
}
},
"spec": {
"ports": [
{
"name": "6379",
"port": 6379,
"targetPort": 6379
}
],
"selector": {
"io.kompose.service": "redis"
}
},
"status": {
"loadBalancer": {}
}
},
{
"kind": "DeploymentConfig",
"apiVersion": "v1",
"metadata": {
"name": "mongo",
"creationTimestamp": null,
"labels": {
"io.kompose.service": "mongo"
},
"annotations": {
"kompose.service.group": "my-group",
"kompose.service.healthcheck.liveness.tcp_port": "8080",
"kompose.service.healthcheck.readiness.interval": "10s",
"kompose.service.healthcheck.readiness.retries": "5",
"kompose.service.healthcheck.readiness.tcp_port": "9090",
"kompose.service.healthcheck.readiness.timeout": "1s"
}
},
"spec": {
"strategy": {
"resources": {}
},
"triggers": [
{
"type": "ConfigChange"
},
{
"type": "ImageChange",
"imageChangeParams": {
"automatic": true,
"containerNames": [
"mongo"
],
"from": {
"kind": "ImageStreamTag",
"name": "mongo:latest"
}
}
}
],
"replicas": 1,
"test": false,
"selector": {
"io.kompose.service": "mongo"
},
"template": {
"metadata": {
"creationTimestamp": null,
"labels": {
"io.kompose.service": "mongo"
}
},
"spec": {
"containers": [
{
"name": "mongo",
"image": " ",
"ports": [
{
"containerPort": 27017
}
],
"resources": {},
"livenessProbe": {
"tcpSocket": {
"port": 8080
},
"timeoutSeconds": 1,
"periodSeconds": 10,
"failureThreshold": 5
},
"readinessProbe": {
"tcpSocket": {
"port": 9090
},
"timeoutSeconds": 1,
"periodSeconds": 10,
"failureThreshold": 5
}
}
],
"restartPolicy": "Always"
}
}
},
"status": {
"latestVersion": 0,
"observedGeneration": 0,
"replicas": 0,
"updatedReplicas": 0,
"availableReplicas": 0,
"unavailableReplicas": 0
}
},
{
"kind": "ImageStream",
"apiVersion": "v1",
"metadata": {
"name": "mongo",
"creationTimestamp": null,
"labels": {
"io.kompose.service": "mongo"
}
},
"spec": {
"lookupPolicy": {
"local": false
},
"tags": [
{
"name": "",
"annotations": null,
"from": {
"kind": "DockerImage",
"name": "mongo"
},
"generation": null,
"importPolicy": {},
"referencePolicy": {
"type": ""
}
}
]
},
"status": {
"dockerImageRepository": ""
}
},
{
"kind": "DeploymentConfig",
"apiVersion": "v1",
"metadata": {
"name": "mysql",
"creationTimestamp": null,
"labels": {
"io.kompose.service": "mysql"
},
"annotations": {
"kompose.service.group": "my-group",
"kompose.service.healthcheck.liveness.tcp_port": "8081",
"kompose.service.healthcheck.readiness.interval": "11s",
"kompose.service.healthcheck.readiness.retries": "6",
"kompose.service.healthcheck.readiness.tcp_port": "9091",
"kompose.service.healthcheck.readiness.timeout": "2s"
}
},
"spec": {
"strategy": {
"resources": {}
},
"triggers": [
{
"type": "ConfigChange"
},
{
"type": "ImageChange",
"imageChangeParams": {
"automatic": true,
"containerNames": [
"mysql"
],
"from": {
"kind": "ImageStreamTag",
"name": "mysql:latest"
}
}
}
],
"replicas": 1,
"test": false,
"selector": {
"io.kompose.service": "mysql"
},
"template": {
"metadata": {
"creationTimestamp": null,
"labels": {
"io.kompose.service": "mysql"
}
},
"spec": {
"containers": [
{
"name": "mysql",
"image": " ",
"ports": [
{
"containerPort": 3306
}
],
"resources": {},
"livenessProbe": {
"tcpSocket": {
"port": 8081
},
"timeoutSeconds": 2,
"periodSeconds": 11,
"failureThreshold": 6
},
"readinessProbe": {
"tcpSocket": {
"port": 9091
},
"timeoutSeconds": 2,
"periodSeconds": 11,
"failureThreshold": 6
}
}
],
"restartPolicy": "Always"
}
}
},
"status": {
"latestVersion": 0,
"observedGeneration": 0,
"replicas": 0,
"updatedReplicas": 0,
"availableReplicas": 0,
"unavailableReplicas": 0
}
},
{
"kind": "ImageStream",
"apiVersion": "v1",
"metadata": {
"name": "mysql",
"creationTimestamp": null,
"labels": {
"io.kompose.service": "mysql"
}
},
"spec": {
"lookupPolicy": {
"local": false
},
"tags": [
{
"name": "",
"annotations": null,
"from": {
"kind": "DockerImage",
"name": "mysql"
},
"generation": null,
"importPolicy": {},
"referencePolicy": {
"type": ""
}
}
]
},
"status": {
"dockerImageRepository": ""
}
},
{
"kind": "DeploymentConfig",
"apiVersion": "v1",
"metadata": {
"name": "postgresql",
"creationTimestamp": null,
"labels": {
"io.kompose.service": "postgresql"
},
"annotations": {
"kompose.service.healthcheck.liveness.http_get_path": "/health",
"kompose.service.healthcheck.liveness.http_get_port": "8080",
"kompose.service.healthcheck.readiness.http_get_path": "/ready",
"kompose.service.healthcheck.readiness.http_get_port": "8080",
"kompose.service.healthcheck.readiness.interval": "10s",
"kompose.service.healthcheck.readiness.retries": "5",
"kompose.service.healthcheck.readiness.timeout": "1s"
}
},
"spec": {
"strategy": {
"resources": {}
},
"triggers": [
{
"type": "ConfigChange"
},
{
"type": "ImageChange",
"imageChangeParams": {
"automatic": true,
"containerNames": [
"postgresql"
],
"from": {
"kind": "ImageStreamTag",
"name": "postgresql:latest"
}
}
}
],
"replicas": 1,
"test": false,
"selector": {
"io.kompose.service": "postgresql"
},
"template": {
"metadata": {
"creationTimestamp": null,
"labels": {
"io.kompose.service": "postgresql"
}
},
"spec": {
"containers": [
{
"name": "postgresql",
"image": " ",
"ports": [
{
"containerPort": 5432
}
],
"resources": {},
"livenessProbe": {
"httpGet": {
"path": "/health",
"port": 8080
},
"timeoutSeconds": 1,
"periodSeconds": 10,
"failureThreshold": 5
},
"readinessProbe": {
"httpGet": {
"path": "/ready",
"port": 8080
},
"timeoutSeconds": 1,
"periodSeconds": 10,
"failureThreshold": 5
}
}
],
"restartPolicy": "Always"
}
}
},
"status": {
"latestVersion": 0,
"observedGeneration": 0,
"replicas": 0,
"updatedReplicas": 0,
"availableReplicas": 0,
"unavailableReplicas": 0
}
},
{
"kind": "ImageStream",
"apiVersion": "v1",
"metadata": {
"name": "postgresql",
"creationTimestamp": null,
"labels": {
"io.kompose.service": "postgresql"
}
},
"spec": {
"lookupPolicy": {
"local": false
},
"tags": [
{
"name": "",
"annotations": null,
"from": {
"kind": "DockerImage",
"name": "postgresql"
},
"generation": null,
"importPolicy": {},
"referencePolicy": {
"type": ""
}
}
]
},
"status": {
"dockerImageRepository": ""
}
},
{
"kind": "DeploymentConfig",
"apiVersion": "v1",
"metadata": {
"name": "redis",
"creationTimestamp": null,
"labels": {
"io.kompose.service": "redis"
},
"annotations": {
"kompose.service.healthcheck.readiness.interval": "10s",
"kompose.service.healthcheck.readiness.retries": "5",
"kompose.service.healthcheck.readiness.test": "echo \"liveness\"",
"kompose.service.healthcheck.readiness.timeout": "1s"
}
},
"spec": {
"strategy": {
"resources": {}
},
"triggers": [
{
"type": "ConfigChange"
},
{
"type": "ImageChange",
"imageChangeParams": {
"automatic": true,
"containerNames": [
"redis"
],
"from": {
"kind": "ImageStreamTag",
"name": "redis:latest"
}
}
}
],
"replicas": 1,
"test": false,
"selector": {
"io.kompose.service": "redis"
},
"template": {
"metadata": {
"creationTimestamp": null,
"labels": {
"io.kompose.service": "redis"
}
},
"spec": {
"containers": [
{
"name": "redis",
"image": " ",
"ports": [
{
"containerPort": 6379
}
],
"resources": {},
"livenessProbe": {
"exec": {
"command": [
"echo \"liveness\""
]
},
"timeoutSeconds": 1,
"periodSeconds": 10,
"failureThreshold": 5
},
"readinessProbe": {
"exec": {
"command": [
"echo",
"liveness"
]
},
"timeoutSeconds": 1,
"periodSeconds": 10,
"failureThreshold": 5
}
}
],
"restartPolicy": "Always"
}
}
},
"status": {
"latestVersion": 0,
"observedGeneration": 0,
"replicas": 0,
"updatedReplicas": 0,
"availableReplicas": 0,
"unavailableReplicas": 0
}
},
{
"kind": "ImageStream",
"apiVersion": "v1",
"metadata": {
"name": "redis",
"creationTimestamp": null,
"labels": {
"io.kompose.service": "redis"
}
},
"spec": {
"lookupPolicy": {
"local": false
},
"tags": [
{
"name": "",
"annotations": null,
"from": {
"kind": "DockerImage",
"name": "redis"
},
"generation": null,
"importPolicy": {},
"referencePolicy": {
"type": ""
}
}
]
},
"status": {
"dockerImageRepository": ""
}
}
]
}