local kube = import "../../../kube/hscloud.libsonnet"; { // Global sets up a global tier instance of the hscloud monitoring infrastructure. // // This currently consists of Victoria Metrics, to which the agent tier sends metrics data via // the prometheus remote_write protocol. // Victoria Metrics is here used as a long-term storage solution. However, right now, it // just keeps data locally on disk. In the future, S3 snapshots/backups should be introduced. Global(name):: { local global = self, local cfg = global.cfg, cfg:: { name: name, namespace: "monitoring-global-%s" % [cfg.name], images: { victoria: "victoriametrics/victoria-metrics:v1.93.9", vmauth: "victoriametrics/vmauth:v1.93.9", grafana: "grafana/grafana:10.2.3", }, hosts: { // DNS hostname that this global tier will use. Ingress will run under it. globalAPI: error "hosts.globalAPI must be set", globalDashboard: error "hosts.globalDashboard must be set", }, storageClasses: { // Storage class used for main data retention. victoria: error "storageClasses.victoria must be set", }, oauth: { clientId: error "oauth.clientId must be set", clientSecret: error "oauth.clientSecret must be set", }, // A list of agents that will push metrics to this instance. // List of: // { // username: the username that the agent will authenticate with // password: the password that the agent will authenticate with // } agents: [], }, // Generated URLs that agents should use to ship metrics over. Both require HTTP basic // auth, configured via cfg.agents. // The internal URL that should be used for agents colocated in the same Kubernetes cluster. internalIngestURL:: "http://%s/api/v1/write" % [global.victoria.serviceAPI.host_colon_port], // The internal URL that should be used for readers colocated in the same Kubernetes cluster. internalReadURL:: "http://%s/" % [global.victoria.serviceAPI.host_colon_port], // The global URL that should be used for agents sending data over the internet. globalIngestURL:: "https://%s/api/v1/write" % [cfg.hosts.globalAPI], // The global URL that should be used for readers over the internet. globalReadURL:: "https://%s" % [cfg.hosts.globalAPI], namespace: kube.Namespace(cfg.namespace), local ns = global.namespace, victoria: { local victoria = self, pvc: ns.Contain(kube.PersistentVolumeClaim("victoria-data")) { storage:: "64Gi", storageClass:: cfg.storageClasses.victoria, }, authSecret: ns.Contain(kube.Secret("vmauth")) { data+: { "config.yaml": std.base64(std.manifestJson({ users: [ { username: a.username, password: a.password, url_prefix: "http://localhost:8428", } for a in (cfg.agents + [cfg.loopbackGrafanaUser]) ], }) + "\n") }, }, deploy: ns.Contain(kube.Deployment("victoria")) { spec+: { template+: { spec+: { default_container: "vmauth", containers_: { default: kube.Container("default") { image: cfg.images.victoria, volumeMounts_: { data: { mountPath: "/victoria-metrics-data", }, }, }, vmauth: kube.Container("vmauth") { image: cfg.images.vmauth, command: [ "/vmauth-prod", "-auth.config", "/mnt/secret/config.yaml", ], volumeMounts_: { secret: { mountPath: "/mnt/secret", }, }, ports_: { api: { containerPort: 8427 } }, } }, volumes_: { data: victoria.pvc.volume, secret: kube.SecretVolume(victoria.authSecret), }, }, }, }, }, serviceAPI: ns.Contain(kube.Service("victoria-api")) { target:: victoria.deploy, }, ingressAPI: ns.Contain(kube.SimpleIngress("victoria-api")) { hosts:: [cfg.hosts.globalAPI], target:: victoria.serviceAPI, }, }, grafana: { local grafana = self, // grafana.ini, serialized to secret. ini:: { sections: { "auth": { "disable_login_form": true, "oauth_auto_login": true, }, "security": { # We do not disable basic auth, as we want to use builtin # users as API users (eg for config reload), but we want # to disable the default admin:admin user. "disable_initial_admin_creation": true, }, "auth.generic_oauth": { enabled: true, client_id: cfg.oauth.clientId, client_secret: cfg.oauth.clientSecret, auth_url: "https://sso.hackerspace.pl/oauth/authorize", token_url: "https://sso.hackerspace.pl/oauth/token", api_url: "https://sso.hackerspace.pl/api/1/userinfo", scopes: "openid", email_attribute_path: "email", allow_sign_up: true, role_attribute_path: "contains(groups, 'grafana-admin')", }, "server": { domain: cfg.hosts.globalDashboard, root_url: "https://%s/" % [ cfg.hosts.globalDashboard ], }, }, }, datasources:: { apiVersion: 1, datasources: [ { name: "victoria-global", type: "prometheus", uid: "victoria-global", isDefault: true, url: global.internalReadURL, basicAuth: true, basicAuthUser: cfg.loopbackGrafanaUser.username, secureJsonData: { basicAuthPassword: cfg.loopbackGrafanaUser.password, }, }, ], }, config: ns.Contain(kube.Secret("grafana-config")) { data+: { "grafana.ini": std.base64(std.manifestIni(grafana.ini)), "datasources.yaml": std.base64(std.manifestYamlDoc(grafana.datasources)), }, }, pvc: ns.Contain(kube.PersistentVolumeClaim("grafana-data")) { storage:: "8Gi", storageClass:: cfg.storageClasses.grafana, }, deploy: ns.Contain(kube.Deployment("grafana")) { spec+: { template+: { spec+: { containers_: { default: kube.Container("default") { image: cfg.images.grafana, ports_: { public: { containerPort: 3000 }, }, env_: { GF_PATHS_CONFIG: "/etc/hscloud-config/grafana.ini", GF_PATHS_PROVISIONING: "/etc/hscloud-config/provisioning", GF_PATHS_DATA: "/var/lib/grafana", }, volumeMounts_: { config: { mountPath: "/etc/hscloud-config", }, data: { mountPath: "/var/lib/grafana", }, }, resources: { requests: { cpu: "100m", memory: "256M", }, limits: { cpu: "200m", memory: "512M", }, }, }, }, volumes_: { data: grafana.pvc.volume, config: kube.SecretVolume(grafana.config) { secret+: { items: [ { key: "grafana.ini", path: "grafana.ini", }, { key: "datasources.yaml", path: "provisioning/datasources/datasources.yaml", }, ], }, }, }, }, }, }, }, service: ns.Contain(kube.Service("grafana-public")) { target:: grafana.deploy, }, ingress: ns.Contain(kube.SimpleIngress("grafana-public")) { hosts:: [cfg.hosts.globalDashboard], target:: grafana.service, }, }, } }