github.com/yankunsam/loki/v2@v2.6.3-0.20220817130409-389df5235c27/production/ksonnet/enterprise-logs/main.libsonnet (about) 1 // TODO(jdb): Use cluster_dns_suffix to configure absolute domain names so as to avoid excessive lookups. 2 // TODO(jdb): Introduce utility functions for mapping over all containers, all microservices (modules), all apps, etc.. 3 local k = import 'github.com/grafana/jsonnet-libs/ksonnet-util/kausal.libsonnet', 4 clusterRole = k.rbac.v1.clusterRole, 5 clusterRoleBinding = k.rbac.v1.clusterRoleBinding, 6 container = k.core.v1.container, 7 configMap = k.core.v1.configMap, 8 deployment = k.apps.v1.deployment, 9 job = k.batch.v1.job, 10 policyRule = k.rbac.v1.policyRule, 11 pvc = k.core.v1.persistentVolumeClaim, 12 service = k.core.v1.service, 13 serviceAccount = k.core.v1.serviceAccount, 14 subject = k.rbac.v1.subject, 15 statefulSet = k.apps.v1.statefulSet; 16 local loki = import 'github.com/grafana/loki/production/ksonnet/loki/loki.libsonnet'; 17 local util = (import 'github.com/grafana/jsonnet-libs/ksonnet-util/util.libsonnet').withK(k) { 18 withNonRootSecurityContext(uid, fsGroup=null):: 19 { spec+: { template+: { spec+: { securityContext: { 20 fsGroup: if fsGroup == null then uid else fsGroup, 21 runAsNonRoot: true, 22 runAsUser: uid, 23 } } } } }, 24 }; 25 26 loki { 27 _config+:: { 28 commonArgs+:: { 29 'auth.enabled': 'true', 30 'auth.type': 'enterprise', 31 'cluster-name': 32 if self['auth.type'] == 'enterprise' then 33 error 'must set _config.commonArgs.cluster-name' 34 else null, 35 }, 36 37 loki+: { 38 distributor+: { 39 ring: { 40 kvstore: { 41 store: 'memberlist', 42 }, 43 }, 44 }, 45 ingester+: { 46 lifecycler+: { 47 ring: { 48 kvstore: { 49 store: 'memberlist', 50 }, 51 }, 52 }, 53 }, 54 memberlist: { 55 retransmit_factor: 2, 56 gossip_interval: '5s', 57 stream_timeout: '5s', 58 abort_if_cluster_join_fails: false, 59 bind_port: 7946, 60 join_members: ['gossip-ring'], 61 }, 62 }, 63 64 ingester_pvc_size: '50Gi', 65 stateful_ingesters: true, 66 67 querier_pvc_size: '50Gi', 68 stateful_queriers: true, 69 70 compactor_pvc_size: '50Gi', 71 }, 72 73 _images+:: { 74 loki: 'grafana/enterprise-logs:v1.1.0', 75 kubectl: 'bitnami/kubectl', 76 }, 77 78 admin_api_args:: self._config.commonArgs { 79 'license.path': '/etc/gel-license/license.jwt', 80 target: 'admin-api', 81 }, 82 admin_api_container:: 83 container.new(name='admin-api', image=self._images.loki) 84 + container.withArgs(util.mapToFlags(self.admin_api_args)) 85 + container.withPorts(loki.util.defaultPorts) 86 + container.resources.withLimits({ cpu: '2', memory: '4Gi' }) 87 + container.resources.withRequests({ cpu: '500m', memory: '1Gi' }) 88 + loki.util.readinessProbe, 89 admin_api_deployment: 90 deployment.new(name='admin-api', replicas=3, containers=[self.admin_api_container]) 91 + deployment.spec.selector.withMatchLabelsMixin({ name: 'admin-api' }) 92 + deployment.spec.template.metadata.withLabelsMixin({ name: 'admin-api', gossip_ring_member: 'true' }) 93 + deployment.spec.template.spec.withTerminationGracePeriodSeconds(15) 94 + util.configVolumeMount('loki', '/etc/loki/config') 95 + util.secretVolumeMount('gel-license', '/etc/gel-license/') 96 + util.withNonRootSecurityContext(uid=10001), 97 admin_api_service: 98 util.serviceFor(self.admin_api_deployment), 99 100 compactor_data_pvc+: { spec+: { storageClassName:: null } }, 101 compactor_statefulset+: util.withNonRootSecurityContext(10001), 102 103 // Remove consul in favor of memberlist. 104 consul_config_map:: {}, 105 consul_deployment:: null, 106 consul_service:: null, 107 108 distributor_deployment+: 109 deployment.spec.template.metadata.withLabelsMixin({ gossip_ring_member: 'true' }) 110 + util.withNonRootSecurityContext(uid=10001), 111 112 gateway_args:: self._config.commonArgs { 113 'license.path': '/etc/gel-license/license.jwt', 114 'gateway.proxy.admin-api.url': 'http://admin-api:%s' % $._config.http_listen_port, 115 'gateway.proxy.compactor.url': 'http://compactor:%s' % $._config.http_listen_port, 116 'gateway.proxy.distributor.url': 'dns:///distributor:9095', 117 'gateway.proxy.ingester.url': 'http://ingester:%s' % $._config.http_listen_port, 118 'gateway.proxy.query-frontend.url': 'http://query-frontend:%s' % $._config.http_listen_port, 119 'gateway.proxy.ruler.url': 'http://ruler:%s' % $._config.http_listen_port, 120 target: 'gateway', 121 }, 122 gateway_container:: 123 container.new(name='gateway', image=self._images.loki) 124 + container.withArgs(util.mapToFlags(self.gateway_args)) 125 + container.withPorts(loki.util.defaultPorts) 126 + container.resources.withLimits({ cpu: '2', memory: '4Gi' }) 127 + container.resources.withRequests({ cpu: '500m', memory: '1Gi' }) 128 + loki.util.readinessProbe, 129 gateway_deployment: 130 deployment.new(name='gateway', replicas=3, containers=[self.gateway_container]) 131 + deployment.spec.template.spec.withTerminationGracePeriodSeconds(15) 132 + deployment.spec.template.spec.securityContext.withFsGroup(10001) 133 + deployment.spec.template.spec.securityContext.withRunAsNonRoot(true) 134 + deployment.spec.template.spec.securityContext.withRunAsUser(10001) 135 + util.configVolumeMount('loki', '/etc/loki/config') 136 + util.withNonRootSecurityContext(uid=10001), 137 // Remove the htpasswd Secret used by the OSS Loki NGINX gateway. 138 gateway_secret:: null, 139 gateway_service: 140 util.serviceFor(self.gateway_deployment), 141 142 ingester_data_pvc+: { spec+: { storageClassName:: null } }, 143 ingester_statefulset+: 144 statefulSet.spec.template.metadata.withLabelsMixin({ gossip_ring_member: 'true' }) 145 + util.withNonRootSecurityContext(uid=10001), 146 147 querier_data_pvc+: { spec+: { storageClassName:: null } }, 148 querier_statefulset+: 149 statefulSet.spec.template.metadata.withLabelsMixin({ gossip_ring_member: 'true' }) 150 + util.withNonRootSecurityContext(uid=10001), 151 152 table_manager_deployment+: util.withNonRootSecurityContext(uid=10001), 153 154 tokengen_args:: self._config.commonArgs { 155 target: 'tokengen', 156 'tokengen.token-file': '/shared/admin-token', 157 }, 158 tokengen_container:: 159 container.new('tokengen', self._images.loki) 160 + container.withPorts(loki.util.defaultPorts) 161 + container.withArgs(util.mapToFlags(self.tokengen_args)) 162 + container.withVolumeMounts([ 163 { mountPath: '/etc/loki/config', name: 'config' }, 164 { mountPath: '/shared', name: 'shared' }, 165 ]) 166 + container.resources.withLimits({ memory: '4Gi' }) 167 + container.resources.withRequests({ cpu: '500m', memory: '500Mi' }), 168 tokengen_create_secret_container:: 169 container.new('create-secret', self._images.kubectl) 170 + container.withCommand([ 171 '/bin/bash', 172 '-euc', 173 'kubectl create secret generic gel-admin-token --from-file=token=/shared/admin-token --from-literal=grafana-token="$(base64 <(echo :$(cat /shared/admin-token)))"', 174 ]) 175 + container.withVolumeMounts([{ mountPath: '/shared', name: 'shared' }]), 176 tokengen_job:: 177 job.new('tokengen') 178 + job.spec.withCompletions(1) 179 + job.spec.withParallelism(1) 180 + job.spec.template.spec.withContainers([self.tokengen_create_secret_container]) 181 + job.spec.template.spec.withInitContainers([self.tokengen_container]) 182 + job.spec.template.spec.withRestartPolicy('Never') 183 + job.spec.template.spec.withServiceAccount('tokengen') 184 + job.spec.template.spec.withServiceAccountName('tokengen') 185 + job.spec.template.spec.withVolumes([ 186 { name: 'config', configMap: { name: 'loki' } }, 187 { name: 'shared', emptyDir: {} }, 188 ]) 189 + util.withNonRootSecurityContext(uid=10001), 190 tokengen_service_account: 191 serviceAccount.new('tokengen'), 192 tokengen_cluster_role: 193 clusterRole.new('tokengen') 194 + clusterRole.withRules([ 195 policyRule.withApiGroups(['']) 196 + policyRule.withResources(['secrets']) 197 + policyRule.withVerbs(['create']), 198 ]), 199 tokengen_cluster_role_binding: 200 clusterRoleBinding.new() 201 + clusterRoleBinding.metadata.withName('tokengen') 202 + clusterRoleBinding.roleRef.withApiGroup('rbac.authorization.k8s.io') 203 + clusterRoleBinding.roleRef.withKind('ClusterRole') 204 + clusterRoleBinding.roleRef.withName('tokengen') 205 + clusterRoleBinding.withSubjects([ 206 subject.new() 207 + subject.withName('tokengen') 208 + subject.withKind('ServiceAccount') 209 + { namespace: $._config.namespace }, 210 ]), 211 212 gossip_ring_service: 213 service.new( 214 name='gossip-ring', 215 selector={ gossip_ring_member: 'true' }, 216 ports=[{ name: 'gossip-ring', port: 7946, protocol: 'TCP', targetPort: 7946 }], 217 ) 218 + service.spec.withClusterIp('None') 219 + service.spec.withPublishNotReadyAddresses(true), 220 }