Skip to content

Commit

Permalink
chore(*) support Service-less Pods
Browse files Browse the repository at this point in the history
Signed-off-by: Nikolay Nikolaev <nikolay.nikolaev@konghq.com>
  • Loading branch information
Nikolay Nikolaev committed Jan 25, 2021
1 parent a7d78b8 commit e48386c
Show file tree
Hide file tree
Showing 10 changed files with 187 additions and 67 deletions.
41 changes: 35 additions & 6 deletions dev/examples/k8s/example-app/example-app.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,32 +2,32 @@
apiVersion: v1
kind: Service
metadata:
name: example-app
name: example-server
spec:
ports:
- port: 80
name: http
selector:
app: example-app
app: example-server
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: example-app
name: example-server
labels:
app: example-app
app: example-server
spec:
strategy:
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
selector:
matchLabels:
app: example-app
app: example-server
template:
metadata:
labels:
app: example-app
app: example-server
spec:
containers:
- name: nginx
Expand All @@ -39,3 +39,32 @@ spec:
requests:
cpu: 10m
memory: 32Mi
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: example-client
labels:
app: example-client
spec:
strategy:
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
selector:
matchLabels:
app: example-client
template:
metadata:
labels:
app: example-client
spec:
containers:
- name: alpine
image: "alpine:latest"
imagePullPolicy: IfNotPresent
command: ["sh", "-c", "tail -f /dev/null"]
resources:
requests:
cpu: 10m
memory: 32Mi
2 changes: 0 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -337,7 +337,6 @@ github.com/elazarl/goproxy/ext v0.0.0-20190711103511-473e67f1d7d2/go.mod h1:gNh8
github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
github.com/emicklei/go-restful v2.9.6+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
github.com/emicklei/go-restful v2.14.2+incompatible h1:uyx8VgUCryEkh7qbr8rEtrA0rGDEJ73F5lOJdB5m3V8=
github.com/emicklei/go-restful v2.14.2+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
github.com/emicklei/go-restful v2.15.0+incompatible h1:8KpYO/Xl/ZudZs5RNOEhWMBY4hmzlZhhRd9cu+jrZP4=
github.com/emicklei/go-restful v2.15.0+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
Expand Down Expand Up @@ -763,7 +762,6 @@ github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.3.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.7.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/lib/pq v1.8.0 h1:9xohqzkUwzR4Ga4ivdTcawVS89YSDVxXMa3xJX3cGzg=
github.com/lib/pq v1.8.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/lib/pq v1.9.0 h1:L8nSXQQzAYByakOFMTwpjRoHsMJklur4Gi59b6VivR8=
github.com/lib/pq v1.9.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
Expand Down
2 changes: 2 additions & 0 deletions pkg/core/resources/apis/mesh/dataplane_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ const (
ProtocolHTTP2 = "http2"
ProtocolGRPC = "grpc"
ProtocolKafka = "kafka"

TCPPortReserved = 49151 // IANA Reserved
)

func ParseProtocol(tag string) Protocol {
Expand Down
77 changes: 69 additions & 8 deletions pkg/plugins/runtime/k8s/controllers/inbound_converter.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package controllers

import (
"fmt"
"strings"

"github.com/pkg/errors"
kube_core "k8s.io/api/core/v1"
Expand All @@ -26,7 +27,7 @@ func InboundInterfacesFor(zone string, pod *kube_core.Pod, services []*kube_core
continue
}

tags := InboundTagsFor(zone, pod, svc, &svcPort)
tags := InboundTagsForService(zone, pod, svc, &svcPort)
var health *mesh_proto.Dataplane_Networking_Inbound_Health

// if container is not equal nil then port is explicitly defined as containerPort so we're able
Expand Down Expand Up @@ -58,20 +59,50 @@ func InboundInterfacesFor(zone string, pod *kube_core.Pod, services []*kube_core
})
}
}

if len(ifaces) == 0 {
// Notice that here we return an error immediately
// instead of leaving Dataplane validation up to a ValidatingAdmissionWebHook.
// We do it this way in order to provide the most descriptive error message.
cause := "However, there are no Services that select this Pod."
if len(services) > 0 {
cause = "However, this Pod doesn't have any container ports that would satisfy matching Service(s)."
// Notice that here we return an error immediately
// instead of leaving Dataplane validation up to a ValidatingAdmissionWebHook.
// We do it this way in order to provide the most descriptive error message.
return nil, errors.Errorf("Kuma requires every Pod in a Mesh to be a part of at least one Service. However, this Pod doesn't have any container ports that would satisfy matching Service(s).")
}

// The Pod does not have any services associated with it, just get the data from the Pod itself
tags := InboundTagsForPod(zone, pod)
var health *mesh_proto.Dataplane_Networking_Inbound_Health

for _, container := range pod.Spec.Containers {
if container.Name != util_k8s.KumaSidecarContainerName {
if cs := util_k8s.FindContainerStatus(pod, container.Name); cs != nil {
health = &mesh_proto.Dataplane_Networking_Inbound_Health{
Ready: cs.Ready,
}
}
}
}

// also we're checking whether kuma-sidecar container is ready
if cs := util_k8s.FindContainerStatus(pod, util_k8s.KumaSidecarContainerName); cs != nil {
if health != nil {
health.Ready = health.Ready && cs.Ready
} else {
health = &mesh_proto.Dataplane_Networking_Inbound_Health{
Ready: cs.Ready,
}
}
}
return nil, errors.Errorf("Kuma requires every Pod in a Mesh to be a part of at least one Service. %s", cause)

ifaces = append(ifaces, &mesh_proto.Dataplane_Networking_Inbound{
Port: mesh_core.TCPPortReserved,
Tags: tags,
Health: health,
})
}
return ifaces, nil
}

func InboundTagsFor(zone string, pod *kube_core.Pod, svc *kube_core.Service, svcPort *kube_core.ServicePort) map[string]string {
func InboundTagsForService(zone string, pod *kube_core.Pod, svc *kube_core.Service, svcPort *kube_core.ServicePort) map[string]string {
tags := util_k8s.CopyStringMap(pod.Labels)
for key, value := range tags {
if value == "" {
Expand Down Expand Up @@ -110,3 +141,33 @@ func ProtocolTagFor(svc *kube_core.Service, svcPort *kube_core.ServicePort) stri
// to a user that at least `<port>.service.kuma.io/protocol` has an effect
return protocolValue
}

func InboundTagsForPod(zone string, pod *kube_core.Pod) map[string]string {
tags := util_k8s.CopyStringMap(pod.Labels)
for key, value := range tags {
if value == "" {
delete(tags, key)
}
}
if tags == nil {
tags = make(map[string]string)
}
tags[mesh_proto.ServiceTag] = fmt.Sprintf("%s_%s_svc", nameFromPod(pod), pod.Namespace)
if zone != "" {
tags[mesh_proto.ZoneTag] = zone
}
tags[mesh_proto.ProtocolTag] = mesh_core.ProtocolTCP
tags[mesh_proto.InstanceTag] = pod.Name

return tags
}

func nameFromPod(pod *kube_core.Pod) string {
// the name is in format <name>-<replica set id>-<pod id>
split := strings.Split(pod.Name, "-")
if len(split) > 2 {
split = split[:len(split)-2]
}

return strings.Join(split, "-")
}
54 changes: 18 additions & 36 deletions pkg/plugins/runtime/k8s/controllers/pod_converter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,25 +55,6 @@ var _ = Describe("PodToDataplane(..)", func() {
podIP: 192.168.0.1
`

gatewayPod := `
metadata:
namespace: demo
name: example
labels:
app: example
version: "0.1"
annotations:
kuma.io/gateway: enabled
spec:
containers:
- ports:
- containerPort: 7070
- containerPort: 6060
name: metrics
status:
podIP: 192.168.0.1
`

ParseServices := func(values []string) ([]*kube_core.Service, error) {
services := make([]*kube_core.Service, len(values))
for i, value := range values {
Expand Down Expand Up @@ -117,11 +98,14 @@ var _ = Describe("PodToDataplane(..)", func() {
Expect(err).ToNot(HaveOccurred())

// services for pod
bytes, err = ioutil.ReadFile(filepath.Join("testdata", given.servicesForPod))
Expect(err).ToNot(HaveOccurred())
YAMLs := util_yaml.SplitYAML(string(bytes))
services, err := ParseServices(YAMLs)
Expect(err).ToNot(HaveOccurred())
services := []*kube_core.Service{}
if given.servicesForPod != "" {
bytes, err = ioutil.ReadFile(filepath.Join("testdata", given.servicesForPod))
Expect(err).ToNot(HaveOccurred())
YAMLs := util_yaml.SplitYAML(string(bytes))
services, err = ParseServices(YAMLs)
Expect(err).ToNot(HaveOccurred())
}

// other services
var serviceGetter kube_client.Reader
Expand Down Expand Up @@ -238,6 +222,14 @@ var _ = Describe("PodToDataplane(..)", func() {
servicesForPod: "12.services-for-pod.yaml",
dataplane: "12.dataplane.yaml",
}),
Entry("13. Pod without a service", testCase{
pod: "13.pod.yaml",
dataplane: "13.dataplane.yaml",
}),
Entry("14. Gateway pod without a service", testCase{
pod: "14.pod.yaml",
dataplane: "14.dataplane.yaml",
}),
)

DescribeTable("should convert Pod into a Dataplane YAML version",
Expand Down Expand Up @@ -346,16 +338,6 @@ var _ = Describe("PodToDataplane(..)", func() {
Expect(err).To(HaveOccurred())
Expect(err.Error()).To(Equal(given.expectedErr))
},
Entry("regular Pod without Services", testCase{
pod: pod,
services: nil,
expectedErr: `Kuma requires every Pod in a Mesh to be a part of at least one Service. However, there are no Services that select this Pod.`,
}),
Entry("gateway Pod without Services", testCase{
pod: gatewayPod,
services: nil,
expectedErr: `Kuma requires every Pod in a Mesh to be a part of at least one Service. However, there are no Services that select this Pod.`,
}),
Entry("Pod with a Service but mismatching ports", testCase{
pod: pod,
services: []string{`
Expand Down Expand Up @@ -419,7 +401,7 @@ var _ = Describe("MeshFor(..)", func() {
)
})

var _ = Describe("InboundTagsFor(..)", func() {
var _ = Describe("InboundTagsForService(..)", func() {

type testCase struct {
isGateway bool
Expand Down Expand Up @@ -462,7 +444,7 @@ var _ = Describe("InboundTagsFor(..)", func() {
}

// expect
Expect(InboundTagsFor(given.zone, pod, svc, &svc.Spec.Ports[0])).To(Equal(given.expected))
Expect(InboundTagsForService(given.zone, pod, svc, &svc.Spec.Ports[0])).To(Equal(given.expected))
},
Entry("Pod without labels", testCase{
isGateway: false,
Expand Down
17 changes: 17 additions & 0 deletions pkg/plugins/runtime/k8s/controllers/testdata/13.dataplane.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
mesh: default
metadata:
creationTimestamp: null
spec:
networking:
address: 192.168.0.1
inbound:
- health:
ready: true
port: 49151
tags:
app: example
kuma.io/instance: example
kuma.io/protocol: tcp
kuma.io/service: example_demo_svc
kuma.io/zone: zone-1
version: "0.1"
16 changes: 16 additions & 0 deletions pkg/plugins/runtime/k8s/controllers/testdata/13.pod.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
metadata:
namespace: demo
name: example
labels:
app: example
version: "0.1"
spec:
containers:
- ports: []
- ports:
- containerPort: 7070
status:
podIP: 192.168.0.1
containerStatuses:
- ready: true
started: true
14 changes: 14 additions & 0 deletions pkg/plugins/runtime/k8s/controllers/testdata/14.dataplane.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
mesh: default
metadata:
creationTimestamp: null
spec:
networking:
address: 192.168.0.1
gateway:
tags:
app: example
kuma.io/instance: example
kuma.io/protocol: tcp
kuma.io/service: example_demo_svc
kuma.io/zone: zone-1
version: "0.1"
16 changes: 16 additions & 0 deletions pkg/plugins/runtime/k8s/controllers/testdata/14.pod.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
metadata:
namespace: demo
name: example
labels:
app: example
version: "0.1"
annotations:
kuma.io/gateway: enabled
spec:
containers:
- ports:
- containerPort: 7070
- containerPort: 6060
name: metrics
status:
podIP: 192.168.0.1
15 changes: 0 additions & 15 deletions test/framework/setup.go
Original file line number Diff line number Diff line change
Expand Up @@ -228,19 +228,6 @@ func IngressUniversal(mesh, token string) InstallFunc {

func DemoClientK8s(mesh string) InstallFunc {
const name = "demo-client"
service := `
apiVersion: v1
kind: Service
metadata:
name: demo-client
namespace: kuma-test
spec:
ports:
- port: 3000
name: http
selector:
app: demo-client
`
deployment := `
apiVersion: apps/v1
kind: Deployment
Expand Down Expand Up @@ -281,9 +268,7 @@ spec:
memory: 128Mi
`
return Combine(
YamlK8s(service),
YamlK8s(fmt.Sprintf(deployment, mesh)),
WaitService(TestNamespace, name),
WaitNumPods(1, name),
WaitPodsAvailable(TestNamespace, name),
)
Expand Down

0 comments on commit e48386c

Please sign in to comment.