blob: 9b64f05c6f960bea61318fa9f3eb244d7bed2e66 [file] [log] [blame]
Sergiusz Bazanski2022ac22020-06-06 17:04:07 +02001local kube = import "../../../kube/kube.libsonnet";
Sergiusz Bazanskice81c392020-06-06 12:35:06 +02002
3{
Sergiusz Bazanski2022ac22020-06-06 17:04:07 +02004 // Cluster sets up all cluster-specific monitoring resources in their own namespace.
5 // Currently this consists of a prometheus server that scrapes k8s nodes for kubelet
6 // and cAdvisor metrics.
Sergiusz Bazanskice81c392020-06-06 12:35:06 +02007 Cluster(name):: {
8 local cluster = self,
9 local cfg = cluster.cfg,
10 cfg:: {
11 name: name,
12 namespace: "monitoring-cluster",
13
14 images: {
15 prometheus: "prom/prometheus:v2.18.1",
16 },
17
18 storageClasses: {
Sergiusz Bazanski2022ac22020-06-06 17:04:07 +020019 prometheus: error "storageClasses.prometheus must be set",
Sergiusz Bazanskice81c392020-06-06 12:35:06 +020020 },
21 },
22
23 namespace: kube.Namespace(cfg.namespace),
24
25 prometheus: {
26 local prometheus = self,
27
28 // Configuration that's going to be emitted as prometheus.yml and passed to the
29 // prometheus server for this cluster.
30 configuration:: {
31 global: {
32 external_labels: {
33 cluster: cluster.cfg.name,
34 },
35 },
36
37 // Constructor for a Kubernetes scrape job that uses the pod's service account and
38 // TLS configuration, selecting the given k8s scrape 'role'.
39 local kubeScrapeConfig = function(name, role) {
40 job_name: name,
41 scheme: "https",
42 scrape_interval: "30s",
43 kubernetes_sd_configs: [ { role: role }, ],
44 tls_config: {
45 ca_file: "/var/run/secrets/kubernetes.io/serviceaccount/ca.crt",
46 },
47 bearer_token_file: "/var/run/secrets/kubernetes.io/serviceaccount/token",
48 },
49
50 scrape_configs: [
51 // When scraping node-based metrics (ie. node and cadvisor metrics) we contact
52 // the metrics endpoints on the kubelet via the API server. This is done by
53 // relabeling _address__ and __metrics_path__ to point at the k8s API server,
54 // and at the API server proxy path to reach a node's metrics endpoint.
55 //
56 // This approach was lifted from the prometheus examples for Kubernetes, and
57 // while the benefits outlined there do not matter that much to us (our
58 // kubelets listen on public addresses, anyway), we still enjoy this approach
59 // for the fact that we don't have to hardcode the kubelet TLS port.
60 //
61 // https://github.com/prometheus/prometheus/blob/master/documentation/examples/prometheus-kubernetes.yml
62 //
63 // When contacting the API server, we hardcode the 'hswaw.net' DNS suffix as
64 // our API server's TLS certificate only has a CN/SAN for its full FQDN, not
65 // the .svc.cluster.local shorthand (see //cluster/clustercfg:clustercfg.py).
66
67 // Scrape Kubernetes node metrics via apiserver. This emites kube_node_* metrics.
68 kubeScrapeConfig("cluster_node_metrics", "node") {
69 relabel_configs: [
70 {
71 action: "labelmap",
72 regex: "__meta_kubernetes_node_label_(.+)",
73 },
74 {
75 action: "replace",
76 target_label: "__address__",
77 replacement: "kubernetes.default.svc.%s.hswaw.net:443" % [cluster.cfg.name],
78 },
79 {
80 target_label: "__metrics_path__",
81 source_labels: ["__meta_kubernetes_node_name"],
82 regex: "(.+)",
83 replacement: "/api/v1/nodes/${1}/proxy/metrics",
84 },
85 ],
86 },
87 // Scrape Kubernetes node cadvisor metrics via apiserver. This emits container_* metrics.
88 kubeScrapeConfig("cluster_cadvisor_metrics", "node") {
89 relabel_configs: [
90 {
91 action: "labelmap",
92 regex: "__meta_kubernetes_node_label_(.+)",
93 },
94 {
95 action: "replace",
96 target_label: "__address__",
97 replacement: "kubernetes.default.svc.%s.hswaw.net:443" % [cluster.cfg.name],
98 },
99 {
100 target_label: "__metrics_path__",
101 source_labels: ["__meta_kubernetes_node_name"],
102 regex: "(.+)",
103 replacement: "/api/v1/nodes/${1}/proxy/metrics/cadvisor",
104 },
105 ],
106 },
107 ],
108 },
109
110 configmap: kube.ConfigMap("prometheus-cluster") {
111 metadata+: {
112 namespace: cfg.namespace,
113 },
114 data: {
115 "prometheus.yml": std.manifestYamlDoc(prometheus.configuration),
116 },
117 },
118
119 sa: kube.ServiceAccount("prometheus-cluster") {
120 metadata+: {
121 namespace: cfg.namespace,
122 },
123 },
124
125 cr: kube.ClusterRole("monitoring-cluster-prometheus-server-%s" % [cfg.name]) {
126 rules: [
127 // Allow access to all metrics.
128 { nonResourceURLs: ["/metrics"], verbs: ["get"], },
129 // Allow to access node details for discovery.
130 { apiGroups: [""], resources: ["nodes"], verbs: ["list", "watch", "get"], },
131 // Allow to proxy to bare node HTTP to access per-node metrics endpoints.
132 { apiGroups: [""], resources: ["nodes/proxy"], verbs: ["get"], },
133 ],
134 },
135
136 crb: kube.ClusterRoleBinding("monitoring-cluster-prometheus-server-%s" % [cfg.name]) {
137 subjects_: [prometheus.sa],
138 roleRef_: prometheus.cr,
139 },
140
141 deploy: kube.Deployment("prometheus-cluster") {
142 metadata+: {
143 namespace: cfg.namespace,
144 },
145 spec+: {
146 template+: {
147 spec+: {
148 containers_: {
149 default: kube.Container("default") {
150 image: cfg.images.prometheus,
151 command: [
152 "/bin/prometheus",
153 "--config.file=/etc/prometheus/prometheus.yml",
154 "--storage.tsdb.path=/prometheus",
155 # TODO(q3k): reduce this once we have a long-term storage
156 # solution.
157 "--storage.tsdb.retention.time=120d",
158 "--web.console.libraries=/usr/share/prometheus/console_libraries",
159 "--web.console.templates=/usr/share/prometheus/consoles",
160 "--web.enable-lifecycle",
161 ],
162 resources: {
163 requests: {
164 memory: "256Mi",
165 cpu: "100m",
166 },
167 limits: {
168 memory: "1Gi",
169 cpu: "1",
170 },
171 },
172 volumeMounts_: {
173 data: { mountPath: "/prometheus", },
174 configmap: { mountPath: "/etc/prometheus", },
175 },
176 },
177 },
178 serviceAccountName: prometheus.sa.metadata.name,
179 tolerations: [
180 { key: "CriticalAddonsOnly", operator: "Exists" },
181 ],
182 volumes_: {
183 data: kube.PersistentVolumeClaimVolume(prometheus.pvc),
184 configmap: kube.ConfigMapVolume(prometheus.configmap),
185 },
186 },
187 },
188 },
189 },
190
191 // Kubernetes metric storage volume.
192 pvc: kube.PersistentVolumeClaim("prometheus-cluster") {
193 metadata+: {
194 namespace: cfg.namespace,
195 },
196 spec+: {
197 storageClassName: cfg.storageClasses.prometheus,
198 accessModes: ["ReadWriteOnce"],
199 resources: {
200 requests: {
201 storage: "32Gi",
202 },
203 },
204 },
205 },
206
207 // Network Policy governing access to the prometheus server.
208 np: kube.NetworkPolicy("prometheus-cluster") {
209 metadata+: {
210 namespace: cfg.namespace,
211 },
212 spec+: kube.podLabelsSelector(prometheus.deploy) {
213 ingress_: {
214 // Deny all inbound traffic to pod.
215 // This will be augmented to allow access from some other pod/namespace
216 // in the future.
217 },
218 egress_: {
219 // Allow all outbound traffic from pod.
220 outboundAll: {},
221 },
222 policyTypes: ["Ingress", "Egress"],
223 },
224 },
225 },
226 },
Sergiusz Bazanskice81c392020-06-06 12:35:06 +0200227}