blob: b3a5eb7b48ef906a88f7efb8f4d0e06b4c070475 [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")) {
67 spec+: {
68 storageClassName: cfg.storageClasses.victoria,
69 accessModes: ["ReadWriteOnce"],
70 resources: {
71 requests: {
72 storage: "64Gi",
73 },
74 },
75 },
76 },
77
78 authSecret: ns.Contain(kube.Secret("vmauth")) {
79 data+: {
80 "config.yaml": std.base64(std.manifestJson({
81 users: [
82 {
83 username: a.username,
84 password: a.password,
85 url_prefix: "http://localhost:8428",
86 }
Serge Bazanski4f7caf82020-10-10 17:58:09 +020087 for a in (cfg.agents + [cfg.loopbackGrafanaUser])
Serge Bazanski363bf4f2020-08-24 21:00:56 +020088 ],
89 }) + "\n")
90 },
91 },
92
93 deploy: ns.Contain(kube.Deployment("victoria")) {
94 spec+: {
95 template+: {
96 spec+: {
97 containers_: {
98 default: kube.Container("default") {
99 image: cfg.images.victoria,
100 volumeMounts_: {
101 data: { mountPath: "/victoria-metrics-data", },
102 },
103 },
104 vmauth: kube.Container("vmauth") {
105 image: cfg.images.vmauth,
106 command: [
107 "/vmauth-prod",
108 "-auth.config", "/mnt/secret/config.yaml",
109 ],
110 volumeMounts_: {
111 secret: { mountPath: "/mnt/secret", },
112 },
113 ports_: {
114 api: { containerPort: 8427 }
115 },
116 }
117 },
118 volumes_: {
119 data: kube.PersistentVolumeClaimVolume(victoria.pvc),
120 secret: kube.SecretVolume(victoria.authSecret),
121 },
122 },
123 },
124 },
125 },
126
127 serviceAPI: ns.Contain(kube.Service("victoria-api")) {
128 target_pod: victoria.deploy.spec.template,
129 spec+: {
130 ports: [
131 { name: "api", port: 8427, targetPort: 8427, protocol: "TCP" },
132 ],
133 type: "ClusterIP",
134 },
135 },
136
Radek Pietruszewskif5844312023-10-27 22:41:18 +0200137 ingressAPI: ns.Contain(kube.SimpleIngress("victoria-api")) {
138 hosts:: [cfg.hosts.globalAPI],
139 target_service:: victoria.serviceAPI,
Serge Bazanski363bf4f2020-08-24 21:00:56 +0200140 },
141 },
Serge Bazanski4f7caf82020-10-10 17:58:09 +0200142
143 grafana: {
144 local grafana = self,
145
146 // grafana.ini, serialized to secret.
147 ini:: {
148 sections: {
149 "auth": {
150 "disable_login_form": true,
151 "oauth_auto_login": true,
152 },
153 "security": {
154 # We do not disable basic auth, as we want to use builtin
155 # users as API users (eg for config reload), but we want
156 # to disable the default admin:admin user.
157 "disable_initial_admin_creation": true,
158 },
159 "auth.generic_oauth": {
160 enabled: true,
161 client_id: cfg.oauth.clientId,
162 client_secret: cfg.oauth.clientSecret,
Serge Bazanskicc2ff792021-01-30 17:26:47 +0100163 auth_url: "https://sso.hackerspace.pl/oauth/authorize",
164 token_url: "https://sso.hackerspace.pl/oauth/token",
165 api_url: "https://sso.hackerspace.pl/api/1/userinfo",
Serge Bazanski4f7caf82020-10-10 17:58:09 +0200166 scopes: "openid",
167 email_attribute_path: "email",
168 allow_sign_up: true,
169 role_attribute_path: "contains(groups, 'grafana-admin')",
170 },
171 "server": {
172 domain: cfg.hosts.globalDashboard,
173 root_url: "https://%s/" % [ cfg.hosts.globalDashboard ],
174 },
175 },
176 },
177
178 datasources:: {
179 apiVersion: 1,
180 datasources: [
181 {
182 name: "victoria-global",
183 type: "prometheus",
184 uid: "victoria-global",
185 isDefault: true,
186 url: global.internalReadURL,
187 basicAuth: true,
188 basicAuthUser: cfg.loopbackGrafanaUser.username,
189 secureJsonData: {
190 basicAuthPassword: cfg.loopbackGrafanaUser.password,
191 },
192 },
193 ],
194 },
195
196 config: ns.Contain(kube.Secret("grafana-config")) {
197 data+: {
198 "grafana.ini": std.base64(std.manifestIni(grafana.ini)),
199 "datasources.yaml": std.base64(std.manifestYamlDoc(grafana.datasources)),
200 },
201 },
202
203 pvc: ns.Contain(kube.PersistentVolumeClaim("grafana-data")) {
204 spec+: {
205 storageClassName: cfg.storageClasses.grafana,
206 accessModes: ["ReadWriteOnce"],
207 resources: {
208 requests: {
209 storage: "8Gi",
210 },
211 },
212 },
213 },
214
215 deploy: ns.Contain(kube.Deployment("grafana")) {
216 spec+: {
217 template+: {
218 spec+: {
219 containers_: {
220 default: kube.Container("default") {
221 image: cfg.images.grafana,
222 ports_: {
223 public: { containerPort: 3000 },
224 },
225 env_: {
226 GF_PATHS_CONFIG: "/etc/hscloud-config/grafana.ini",
227 GF_PATHS_PROVISIONING: "/etc/hscloud-config/provisioning",
228 GF_PATHS_DATA: "/var/lib/grafana",
229 },
230 volumeMounts_: {
231 config: { mountPath: "/etc/hscloud-config", },
232 data: { mountPath: "/var/lib/grafana", },
233 },
234 resources: {
235 requests: { cpu: "100m", memory: "256M", },
236 limits: { cpu: "200m", memory: "512M", },
237 },
238 },
239 },
240 volumes_: {
241 data: kube.PersistentVolumeClaimVolume(grafana.pvc),
242 config: kube.SecretVolume(grafana.config) {
243 secret+: {
244 items: [
245 { key: "grafana.ini", path: "grafana.ini", },
246 { key: "datasources.yaml", path: "provisioning/datasources/datasources.yaml", },
247 ],
248 },
249 },
250 },
251 },
252 },
253 },
254 },
255
256 service: ns.Contain(kube.Service("grafana-public")) {
257 target_pod: grafana.deploy.spec.template,
258 spec+: {
259 ports: [
260 { name: "public", port: 3000, targetPort: 3000, protocol: "TCP" },
261 ],
262 },
263 },
264
Radek Pietruszewskif5844312023-10-27 22:41:18 +0200265 ingress: ns.Contain(kube.SimpleIngress("grafana-public")) {
266 hosts:: [cfg.hosts.globalDashboard],
267 target_service:: grafana.service,
Serge Bazanski4f7caf82020-10-10 17:58:09 +0200268 },
269 },
Serge Bazanski363bf4f2020-08-24 21:00:56 +0200270 }
271}