diff --git a/kube/charts/kubernetes/kube.go b/kube/charts/kubernetes/kube.go index 6b08d79a9..f4dd9ae89 100644 --- a/kube/charts/kubernetes/kube.go +++ b/kube/charts/kubernetes/kube.go @@ -33,6 +33,12 @@ import ( "k8s.io/apimachinery/pkg/util/intstr" ) +const ( + headlessPort = 55555 + headlessName = "headless" + clusterIPHeadless = "None" +) + //MapToKubernetesObjects maps compose project to Kubernetes objects func MapToKubernetesObjects(project *types.Project) (map[string]runtime.Object, error) { objects := map[string]runtime.Object{} @@ -70,7 +76,12 @@ func MapToKubernetesObjects(project *types.Project) (map[string]runtime.Object, func mapToService(project *types.Project, service types.ServiceConfig) *core.Service { ports := []core.ServicePort{} + serviceType := core.ServiceTypeClusterIP + clusterIP := "" for _, p := range service.Ports { + if p.Published != 0 { + serviceType = core.ServiceTypeLoadBalancer + } ports = append(ports, core.ServicePort{ Name: fmt.Sprintf("%d-%s", p.Target, strings.ToLower(p.Protocol)), @@ -79,8 +90,14 @@ func mapToService(project *types.Project, service types.ServiceConfig) *core.Ser Protocol: toProtocol(p.Protocol), }) } - if len(ports) == 0 { - return nil + if len(ports) == 0 { // headless service + clusterIP = clusterIPHeadless + ports = append(ports, core.ServicePort{ + Name: headlessName, + Port: headlessPort, + TargetPort: intstr.FromInt(headlessPort), + Protocol: core.ProtocolTCP, + }) } return &core.Service{ TypeMeta: meta.TypeMeta{ @@ -91,32 +108,14 @@ func mapToService(project *types.Project, service types.ServiceConfig) *core.Ser Name: service.Name, }, Spec: core.ServiceSpec{ - Selector: map[string]string{"com.docker.compose.service": service.Name}, - Ports: ports, - Type: mapServiceToServiceType(project, service), + ClusterIP: clusterIP, + Selector: map[string]string{"com.docker.compose.service": service.Name}, + Ports: ports, + Type: serviceType, }, } } -func mapServiceToServiceType(project *types.Project, service types.ServiceConfig) core.ServiceType { - serviceType := core.ServiceTypeClusterIP - if len(service.Networks) == 0 { - // service is implicitly attached to "default" network - serviceType = core.ServiceTypeLoadBalancer - } - for name := range service.Networks { - if !project.Networks[name].Internal { - serviceType = core.ServiceTypeLoadBalancer - } - } - for _, port := range service.Ports { - if port.Published != 0 { - serviceType = core.ServiceTypeNodePort - } - } - return serviceType -} - func mapToDeployment(project *types.Project, service types.ServiceConfig, name string) (*apps.Deployment, error) { labels := map[string]string{ "com.docker.compose.service": service.Name, diff --git a/kube/charts/kubernetes/kube_test.go b/kube/charts/kubernetes/kube_test.go new file mode 100644 index 000000000..7a1aa9173 --- /dev/null +++ b/kube/charts/kubernetes/kube_test.go @@ -0,0 +1,94 @@ +// +build kube + +/* + Copyright 2020 Docker Compose CLI authors + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package kubernetes + +import ( + "testing" + + "gotest.tools/v3/assert" + + core "k8s.io/api/core/v1" + meta "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/intstr" +) + +func TestServiceWithExposedPort(t *testing.T) { + model, err := loadYAML(` +services: + nginx: + image: nginx + ports: + - "80:80" +`) + assert.NilError(t, err) + + service := mapToService(model, model.Services[0]) + assert.DeepEqual(t, *service, core.Service{ + TypeMeta: meta.TypeMeta{ + Kind: "Service", + APIVersion: "v1", + }, + ObjectMeta: meta.ObjectMeta{ + Name: "nginx", + }, + Spec: core.ServiceSpec{ + Selector: map[string]string{"com.docker.compose.service": "nginx"}, + Ports: []core.ServicePort{ + { + Name: "80-tcp", + Port: int32(80), + TargetPort: intstr.FromInt(int(80)), + Protocol: core.ProtocolTCP, + }, + }, + Type: core.ServiceTypeLoadBalancer, + }}) +} + +func TestServiceWithoutExposedPort(t *testing.T) { + model, err := loadYAML(` +services: + nginx: + image: nginx +`) + assert.NilError(t, err) + + service := mapToService(model, model.Services[0]) + assert.DeepEqual(t, *service, core.Service{ + TypeMeta: meta.TypeMeta{ + Kind: "Service", + APIVersion: "v1", + }, + ObjectMeta: meta.ObjectMeta{ + Name: "nginx", + }, + Spec: core.ServiceSpec{ + Selector: map[string]string{"com.docker.compose.service": "nginx"}, + ClusterIP: "None", + Ports: []core.ServicePort{ + { + Name: headlessName, + Protocol: core.ProtocolTCP, + Port: headlessPort, + TargetPort: intstr.IntOrString{IntVal: 55555}, + }, + }, + Type: core.ServiceTypeClusterIP, + }}) +} diff --git a/kube/e2e/kube-simple-demo/demo_sentences.yaml b/kube/e2e/kube-simple-demo/demo_sentences.yaml new file mode 100644 index 000000000..85107558c --- /dev/null +++ b/kube/e2e/kube-simple-demo/demo_sentences.yaml @@ -0,0 +1,13 @@ +services: + db: + build: aci-demo/db + image: gtardif/sentences-db + + words: + build: aci-demo/words + image: gtardif/sentences-api + web: + build: aci-demo/web + image: gtardif/sentences-web + ports: + - "80:80"