blob: ea89e9f4af6d0bb56ac446eed4e773e16cfb316b [file] [log] [blame]
Radek Pietruszewskif5844312023-10-27 22:41:18 +02001local kube = import "../../../kube/hscloud.libsonnet";
Serge Bazanski363bf4f2020-08-24 21:00:56 +02002
3{
4 // Global sets up a global tier instance of the hscloud monitoring infrastructure.
5 //
6 // This currently consists of Victoria Metrics, to which the agent tier sends metrics data via
7 // the prometheus remote_write protocol.
8 // Victoria Metrics is here used as a long-term storage solution. However, right now, it
9 // just keeps data locally on disk. In the future, S3 snapshots/backups should be introduced.
10 Global(name):: {
11 local global = self,
12 local cfg = global.cfg,
13
14 cfg:: {
15 name: name,
16 namespace: "monitoring-global-%s" % [cfg.name],
17
18 images: {
19 victoria: "victoriametrics/victoria-metrics:v1.40.0",
20 vmauth: "victoriametrics/vmauth:v1.40.0",
Serge Bazanski4f7caf82020-10-10 17:58:09 +020021 grafana: "grafana/grafana:7.2.1",
Serge Bazanski363bf4f2020-08-24 21:00:56 +020022 },
23
24 hosts: {
25 // DNS hostname that this global tier will use. Ingress will run under it.
26 globalAPI: error "hosts.globalAPI must be set",
Serge Bazanski4f7caf82020-10-10 17:58:09 +020027 globalDashboard: error "hosts.globalDashboard must be set",
Serge Bazanski363bf4f2020-08-24 21:00:56 +020028 },
29
30 storageClasses: {
31 // Storage class used for main data retention.
32 victoria: error "storageClasses.victoria must be set",
33 },
34
Serge Bazanski4f7caf82020-10-10 17:58:09 +020035 oauth: {
36 clientId: error "oauth.clientId must be set",
37 clientSecret: error "oauth.clientSecret must be set",
38 },
39
Serge Bazanski363bf4f2020-08-24 21:00:56 +020040 // A list of agents that will push metrics to this instance.
41 // List of:
42 // {
43 // username: the username that the agent will authenticate with
44 // password: the password that the agent will authenticate with
45 // }
46 agents: [],
47 },
48
49 // Generated URLs that agents should use to ship metrics over. Both require HTTP basic
50 // auth, configured via cfg.agents.
Serge Bazanski4f7caf82020-10-10 17:58:09 +020051 // The internal URL that should be used for agents colocated in the same Kubernetes cluster.
Serge Bazanski363bf4f2020-08-24 21:00:56 +020052 internalIngestURL:: "http://%s/api/v1/write" % [global.victoria.serviceAPI.host_colon_port],
Serge Bazanski4f7caf82020-10-10 17:58:09 +020053 // The internal URL that should be used for readers colocated in the same Kubernetes cluster.
54 internalReadURL:: "http://%s/" % [global.victoria.serviceAPI.host_colon_port],
55 // The global URL that should be used for agents sending data over the internet.
Serge Bazanski363bf4f2020-08-24 21:00:56 +020056 globalIngestURL:: "https://%s/api/v1/write" % [cfg.hosts.globalAPI],
Serge Bazanski4f7caf82020-10-10 17:58:09 +020057 // The global URL that should be used for readers over the internet.
58 globalReadURL:: "https://%s" % [cfg.hosts.globalAPI],
Serge Bazanski363bf4f2020-08-24 21:00:56 +020059
60 namespace: kube.Namespace(cfg.namespace),
61 local ns = global.namespace,
62
63 victoria: {
64 local victoria = self,
65
66 pvc: ns.Contain(kube.PersistentVolumeClaim("victoria-data")) {
Radek Pietruszewskif28cd622023-11-03 17:30:10 +010067 storage: "64Gi",
68 storageClass: cfg.storageClasses.victoria,
Serge Bazanski363bf4f2020-08-24 21:00:56 +020069 },
70
71 authSecret: ns.Contain(kube.Secret("vmauth")) {
72 data+: {
73 "config.yaml": std.base64(std.manifestJson({
74 users: [
75 {
76 username: a.username,
77 password: a.password,
78 url_prefix: "http://localhost:8428",
79 }
Serge Bazanski4f7caf82020-10-10 17:58:09 +020080 for a in (cfg.agents + [cfg.loopbackGrafanaUser])
Serge Bazanski363bf4f2020-08-24 21:00:56 +020081 ],
82 }) + "\n")
83 },
84 },
85
86 deploy: ns.Contain(kube.Deployment("victoria")) {
87 spec+: {
88 template+: {
89 spec+: {
90 containers_: {
91 default: kube.Container("default") {
92 image: cfg.images.victoria,
93 volumeMounts_: {
94 data: { mountPath: "/victoria-metrics-data", },
95 },
96 },
97 vmauth: kube.Container("vmauth") {
98 image: cfg.images.vmauth,
99 command: [
100 "/vmauth-prod",
101 "-auth.config", "/mnt/secret/config.yaml",
102 ],
103 volumeMounts_: {
104 secret: { mountPath: "/mnt/secret", },
105 },
106 ports_: {
107 api: { containerPort: 8427 }
108 },
109 }
110 },
111 volumes_: {
112 data: kube.PersistentVolumeClaimVolume(victoria.pvc),
113 secret: kube.SecretVolume(victoria.authSecret),
114 },
115 },
116 },
117 },
118 },
119
120 serviceAPI: ns.Contain(kube.Service("victoria-api")) {
121 target_pod: victoria.deploy.spec.template,
122 spec+: {
123 ports: [
124 { name: "api", port: 8427, targetPort: 8427, protocol: "TCP" },
125 ],
126 type: "ClusterIP",
127 },
128 },
129
Radek Pietruszewskif5844312023-10-27 22:41:18 +0200130 ingressAPI: ns.Contain(kube.SimpleIngress("victoria-api")) {
131 hosts:: [cfg.hosts.globalAPI],
132 target_service:: victoria.serviceAPI,
Serge Bazanski363bf4f2020-08-24 21:00:56 +0200133 },
134 },
Serge Bazanski4f7caf82020-10-10 17:58:09 +0200135
136 grafana: {
137 local grafana = self,
138
139 // grafana.ini, serialized to secret.
140 ini:: {
141 sections: {
142 "auth": {
143 "disable_login_form": true,
144 "oauth_auto_login": true,
145 },
146 "security": {
147 # We do not disable basic auth, as we want to use builtin
148 # users as API users (eg for config reload), but we want
149 # to disable the default admin:admin user.
150 "disable_initial_admin_creation": true,
151 },
152 "auth.generic_oauth": {
153 enabled: true,
154 client_id: cfg.oauth.clientId,
155 client_secret: cfg.oauth.clientSecret,
Serge Bazanskicc2ff792021-01-30 17:26:47 +0100156 auth_url: "https://sso.hackerspace.pl/oauth/authorize",
157 token_url: "https://sso.hackerspace.pl/oauth/token",
158 api_url: "https://sso.hackerspace.pl/api/1/userinfo",
Serge Bazanski4f7caf82020-10-10 17:58:09 +0200159 scopes: "openid",
160 email_attribute_path: "email",
161 allow_sign_up: true,
162 role_attribute_path: "contains(groups, 'grafana-admin')",
163 },
164 "server": {
165 domain: cfg.hosts.globalDashboard,
166 root_url: "https://%s/" % [ cfg.hosts.globalDashboard ],
167 },
168 },
169 },
170
171 datasources:: {
172 apiVersion: 1,
173 datasources: [
174 {
175 name: "victoria-global",
176 type: "prometheus",
177 uid: "victoria-global",
178 isDefault: true,
179 url: global.internalReadURL,
180 basicAuth: true,
181 basicAuthUser: cfg.loopbackGrafanaUser.username,
182 secureJsonData: {
183 basicAuthPassword: cfg.loopbackGrafanaUser.password,
184 },
185 },
186 ],
187 },
188
189 config: ns.Contain(kube.Secret("grafana-config")) {
190 data+: {
191 "grafana.ini": std.base64(std.manifestIni(grafana.ini)),
192 "datasources.yaml": std.base64(std.manifestYamlDoc(grafana.datasources)),
193 },
194 },
195
196 pvc: ns.Contain(kube.PersistentVolumeClaim("grafana-data")) {
Radek Pietruszewskif28cd622023-11-03 17:30:10 +0100197 storage: "8Gi",
Serge Bazanski4f7caf82020-10-10 17:58:09 +0200198 spec+: {
199 storageClassName: cfg.storageClasses.grafana,
Serge Bazanski4f7caf82020-10-10 17:58:09 +0200200 },
201 },
202
203 deploy: ns.Contain(kube.Deployment("grafana")) {
204 spec+: {
205 template+: {
206 spec+: {
207 containers_: {
208 default: kube.Container("default") {
209 image: cfg.images.grafana,
210 ports_: {
211 public: { containerPort: 3000 },
212 },
213 env_: {
214 GF_PATHS_CONFIG: "/etc/hscloud-config/grafana.ini",
215 GF_PATHS_PROVISIONING: "/etc/hscloud-config/provisioning",
216 GF_PATHS_DATA: "/var/lib/grafana",
217 },
218 volumeMounts_: {
219 config: { mountPath: "/etc/hscloud-config", },
220 data: { mountPath: "/var/lib/grafana", },
221 },
222 resources: {
223 requests: { cpu: "100m", memory: "256M", },
224 limits: { cpu: "200m", memory: "512M", },
225 },
226 },
227 },
228 volumes_: {
229 data: kube.PersistentVolumeClaimVolume(grafana.pvc),
230 config: kube.SecretVolume(grafana.config) {
231 secret+: {
232 items: [
233 { key: "grafana.ini", path: "grafana.ini", },
234 { key: "datasources.yaml", path: "provisioning/datasources/datasources.yaml", },
235 ],
236 },
237 },
238 },
239 },
240 },
241 },
242 },
243
244 service: ns.Contain(kube.Service("grafana-public")) {
245 target_pod: grafana.deploy.spec.template,
246 spec+: {
247 ports: [
248 { name: "public", port: 3000, targetPort: 3000, protocol: "TCP" },
249 ],
250 },
251 },
252
Radek Pietruszewskif5844312023-10-27 22:41:18 +0200253 ingress: ns.Contain(kube.SimpleIngress("grafana-public")) {
254 hosts:: [cfg.hosts.globalDashboard],
255 target_service:: grafana.service,
Serge Bazanski4f7caf82020-10-10 17:58:09 +0200256 },
257 },
Serge Bazanski363bf4f2020-08-24 21:00:56 +0200258 }
259}