Kubernetes SD: Add node name and host IP to pod discovery

This commit is contained in:
Jimmi Dyson 2016-07-20 12:00:54 +01:00
parent 40f8da699e
commit 6c8080607f
No known key found for this signature in database
GPG key ID: 978CD4AF4C1E87F5
4 changed files with 28 additions and 0 deletions

View file

@ -62,6 +62,10 @@ const (
podLabelPrefix = metaLabelPrefix + "pod_label_" podLabelPrefix = metaLabelPrefix + "pod_label_"
// podAnnotationPrefix is the prefix for prom label names corresponding to k8s annotations for a target pod // podAnnotationPrefix is the prefix for prom label names corresponding to k8s annotations for a target pod
podAnnotationPrefix = metaLabelPrefix + "pod_annotation_" podAnnotationPrefix = metaLabelPrefix + "pod_annotation_"
// podNodeLabel is the name for the label containing the name of the node that a pod is scheduled on to
podNodeNameLabel = metaLabelPrefix + "pod_node_name"
// podHostIPLabel is the name for the label containing the IP of the node that a pod is scheduled on to
podHostIPLabel = metaLabelPrefix + "pod_host_ip"
sourceServicePrefix = "services" sourceServicePrefix = "services"
// serviceNamespaceLabel is the name for the label containing a target's service namespace. // serviceNamespaceLabel is the name for the label containing a target's service namespace.

View file

@ -117,9 +117,11 @@ func pod(name string, containers []Container) *Pod {
Status: "True", Status: "True",
}, },
}, },
HostIP: "2.2.2.2",
}, },
PodSpec: PodSpec{ PodSpec: PodSpec{
Containers: c, Containers: c,
NodeName: "test-node",
}, },
} }
} }
@ -147,6 +149,12 @@ func TestUpdatePodTargets(t *testing.T) {
t.Fatalf("expected 0 targets, received %d", len(result)) t.Fatalf("expected 0 targets, received %d", len(result))
} }
// Return no targets for a pod that has no HostIP
result = updatePodTargets(&Pod{PodStatus: PodStatus{PodIP: "1.1.1.1", Phase: "Running"}}, true)
if len(result) > 0 {
t.Fatalf("expected 0 targets, received %d", len(result))
}
// A pod with all valid containers should return one target per container with allContainers=true // A pod with all valid containers should return one target per container with allContainers=true
result = updatePodTargets(pod("easy", []Container{container("a", portsA), container("b", portsB)}), true) result = updatePodTargets(pod("easy", []Container{container("a", portsA), container("b", portsB)}), true)
if len(result) != 2 { if len(result) != 2 {
@ -167,6 +175,12 @@ func TestUpdatePodTargets(t *testing.T) {
if result[1][podContainerPortMapPrefix+"https"] != "443" { if result[1][podContainerPortMapPrefix+"https"] != "443" {
t.Fatalf("expected result[1][podContainerPortMapPrefix + 'https'] to be '443', but was %s", result[1][podContainerPortMapPrefix+"https"]) t.Fatalf("expected result[1][podContainerPortMapPrefix + 'https'] to be '443', but was %s", result[1][podContainerPortMapPrefix+"https"])
} }
if result[0][podNodeNameLabel] != "test-node" {
t.Fatalf("expected result[0] podNodeNameLabel 'test-node', received '%s'", result[0][podNodeNameLabel])
}
if result[0][podHostIPLabel] != "2.2.2.2" {
t.Fatalf("expected result[0] podHostIPLabel '2.2.2.2', received '%s'", result[0][podHostIPLabel])
}
// A pod with all valid containers should return one target with allContainers=false, and it should be the alphabetically first container // A pod with all valid containers should return one target with allContainers=false, and it should be the alphabetically first container
result = updatePodTargets(pod("easy", []Container{container("a", portsA), container("b", portsB)}), false) result = updatePodTargets(pod("easy", []Container{container("a", portsA), container("b", portsB)}), false)

View file

@ -255,6 +255,12 @@ func updatePodTargets(pod *Pod, allContainers bool) []model.LabelSet {
return targets return targets
} }
// Should never hit this (running pods should always have this set), but better to be defensive.
if pod.PodStatus.HostIP == "" {
log.Debugf("skipping pod %s -- PodStatus.HostIP is empty", pod.ObjectMeta.Name)
return targets
}
ready := "unknown" ready := "unknown"
for _, cond := range pod.PodStatus.Conditions { for _, cond := range pod.PodStatus.Conditions {
if strings.ToLower(cond.Type) == "ready" { if strings.ToLower(cond.Type) == "ready" {
@ -293,6 +299,8 @@ func updatePodTargets(pod *Pod, allContainers bool) []model.LabelSet {
podContainerNameLabel: model.LabelValue(container.Name), podContainerNameLabel: model.LabelValue(container.Name),
podContainerPortNameLabel: model.LabelValue(tcpPorts[0].Name), podContainerPortNameLabel: model.LabelValue(tcpPorts[0].Name),
podReadyLabel: model.LabelValue(ready), podReadyLabel: model.LabelValue(ready),
podNodeNameLabel: model.LabelValue(pod.PodSpec.NodeName),
podHostIPLabel: model.LabelValue(pod.PodStatus.HostIP),
} }
for _, port := range tcpPorts { for _, port := range tcpPorts {

View file

@ -285,10 +285,12 @@ type PodStatus struct {
Phase string `json:"phase" description:"Current condition of the pod. More info: http://kubernetes.io/v1.1/docs/user-guide/pod-states.html#pod-phase"` Phase string `json:"phase" description:"Current condition of the pod. More info: http://kubernetes.io/v1.1/docs/user-guide/pod-states.html#pod-phase"`
PodIP string `json:"podIP" description:"IP address allocated to the pod. Routable at least within the cluster. Empty if not yet allocated."` PodIP string `json:"podIP" description:"IP address allocated to the pod. Routable at least within the cluster. Empty if not yet allocated."`
Conditions []PodCondition `json:"conditions" description:"Current service state of pod."` Conditions []PodCondition `json:"conditions" description:"Current service state of pod."`
HostIP string `json:"hostIP,omitempty" description:"IP address of the host to which the pod is assigned. Empty if not yet scheduled."`
} }
type PodSpec struct { type PodSpec struct {
Containers []Container `json:"containers" description:"list of containers, see http://kubernetes.io/v1.1/docs/api-reference/v1/definitions.html#_v1_container"` Containers []Container `json:"containers" description:"list of containers, see http://kubernetes.io/v1.1/docs/api-reference/v1/definitions.html#_v1_container"`
NodeName string `json:"nodeName,omitempty" description:"NodeName is a request to schedule this pod onto a specific node. If it is non-empty, the scheduler simply schedules this pod onto that node, assuming that it fits resource requirements."`
} }
type PodCondition struct { type PodCondition struct {