forked from hashicorp/consul
-
Notifications
You must be signed in to change notification settings - Fork 0
/
container_init.go
150 lines (131 loc) · 3.84 KB
/
container_init.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
package connectinject
import (
"bytes"
"strings"
"text/template"
corev1 "k8s.io/api/core/v1"
)
type initContainerCommandData struct {
PodName string
ServiceName string
ServicePort int32
Upstreams []initContainerCommandUpstreamData
}
type initContainerCommandUpstreamData struct {
Name string
LocalPort int32
}
// containerInit returns the init container spec for registering the Consul
// service, setting up the Envoy bootstrap, etc.
func (h *Handler) containerInit(pod *corev1.Pod) (corev1.Container, error) {
data := initContainerCommandData{
PodName: pod.Name,
ServiceName: pod.Annotations[annotationService],
}
if data.ServiceName == "" {
// Assertion, since we call defaultAnnotations above and do
// not mutate pods without a service specified.
panic("No service found. This should be impossible since we default it.")
}
// If a port is specified, then we determine the value of that port
// and register that port for the host service.
if raw, ok := pod.Annotations[annotationPort]; ok && raw != "" {
if port, _ := portValue(pod, raw); port > 0 {
data.ServicePort = port
}
}
// If upstreams are specified, configure those
if raw, ok := pod.Annotations[annotationUpstreams]; ok && raw != "" {
for _, raw := range strings.Split(raw, ",") {
parts := strings.SplitN(raw, ":", 2)
port, _ := portValue(pod, strings.TrimSpace(parts[1]))
if port > 0 {
data.Upstreams = append(data.Upstreams, initContainerCommandUpstreamData{
Name: strings.TrimSpace(parts[0]),
LocalPort: port,
})
}
}
}
// Render the command
var buf bytes.Buffer
tpl := template.Must(template.New("root").Parse(strings.TrimSpace(
initContainerCommandTpl)))
err := tpl.Execute(&buf, &data)
if err != nil {
return corev1.Container{}, err
}
return corev1.Container{
Name: "consul-connect-inject-init",
Image: h.ImageConsul,
Env: []corev1.EnvVar{
{
Name: "HOST_IP",
ValueFrom: &corev1.EnvVarSource{
FieldRef: &corev1.ObjectFieldSelector{FieldPath: "status.hostIP"},
},
},
{
Name: "POD_IP",
ValueFrom: &corev1.EnvVarSource{
FieldRef: &corev1.ObjectFieldSelector{FieldPath: "status.podIP"},
},
},
},
VolumeMounts: []corev1.VolumeMount{
corev1.VolumeMount{
Name: volumeName,
MountPath: "/consul/connect-inject",
},
},
Command: []string{"/bin/sh", "-ec", buf.String()},
}, nil
}
// initContainerCommandTpl is the template for the command executed by
// the init container.
const initContainerCommandTpl = `
export CONSUL_HTTP_ADDR="${HOST_IP}:8500"
export CONSUL_GRPC_ADDR="${HOST_IP}:8502"
# Register the service. The HCL is stored in the volume so that
# the preStop hook can access it to deregister the service.
cat <<EOF >/consul/connect-inject/service.hcl
services {
id = "{{ .PodName }}-{{ .ServiceName }}-proxy"
name = "{{ .ServiceName }}-proxy"
kind = "connect-proxy"
address = "${POD_IP}"
port = 20000
proxy {
destination_service_name = "{{ .ServiceName }}"
destination_service_id = "{{ .ServiceName}}"
{{ if (gt .ServicePort 0) -}}
local_service_address = "127.0.0.1"
local_service_port = {{ .ServicePort }}
{{ end -}}
{{ range .Upstreams -}}
upstreams {
destination_name = "{{ .Name }}"
local_bind_port = {{ .LocalPort }}
}
{{ end }}
}
checks {
name = "Proxy Public Listener"
tcp = "${POD_IP}:20000"
interval = "10s"
deregister_critical_service_after = "10m"
}
checks {
name = "Destination Alias"
alias_service = "{{ .ServiceName }}"
}
}
EOF
/bin/consul services register /consul/connect-inject/service.hcl
# Generate the envoy bootstrap code
/bin/consul connect envoy \
-proxy-id="{{ .PodName }}-{{ .ServiceName }}-proxy" \
-bootstrap > /consul/connect-inject/envoy-bootstrap.yaml
# Copy the Consul binary
cp /bin/consul /consul/connect-inject/consul
`