Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Jsonnet: Add Grafana Enterprise Logs library #4165

Merged
merged 16 commits into from
Aug 17, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions production/ksonnet/enterprise-logs/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.eval
lib
vendor
50 changes: 50 additions & 0 deletions production/ksonnet/enterprise-logs/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
include variables.mk

.ONESHELL:
.DELETE_ON_ERROR:
export SHELL := bash
export SHELLOPTS := pipefail:errexit
MAKEFLAGS += --warn-undefined-variables
MAKEFLAGS += --no-builtin-rule

# Adapted from https://suva.sh/posts/well-documented-makefiles/
.PHONY: help
help: ## Display this help.
help:
@awk 'BEGIN {FS = ": ##"; printf "Usage:\n make <target>\n\nTargets:\n"} /^[a-zA-Z0-9_\.\-\/% ]+: ##/ { printf " %-45s %s\n", $$1, $$2 }' $(MAKEFILE_LIST)

jsonnetfile.lock.json: ## Update the locked dependency versions for the library.
jsonnetfile.lock.json: jsonnetfile.json
jb update

test: ## Evaluate the library Jsonnet.
test: test/.eval
:

test/.eval: # Cache testing results.
test/.eval: test/eval.jsonnet main.libsonnet test/lib/k.libsonnet test/vendor
cd $(@D); tmp=$$(mktemp); if tk eval $(<F) | tee $${tmp}; then mv $${tmp} $(@F); fi

test/lib:
mkdir -p $@

test/lib/k.libsonnet: # Install implicit k.libsonnet dependency used in testing.
test/lib/k.libsonnet: test/lib
printf "(import 'github.com/jsonnet-libs/k8s-libsonnet/%s/main.libsonnet')" $(K8S_VERSION) > $@

test/jsonnetfile.json: ## Update the jsonnetfile used in testing.
test/jsonnetfile.json: test/jsonnetfile.jsonnet variables.mk jsonnetfile.json
jsonnet --tla-str k8sVersion=$(K8S_VERSION) $< > $@

test/jsonnetfile.lock.json test/vendor: ## Update the locked dependency versions used in testing.
test/jsonnetfile.lock.json test/vendor: test/jsonnetfile.json
cd $(@D); jb update

.PHONY: k3d-cluster-create
k3d-cluster-create: ## Create a development k3d cluster.
./scripts/k3d-cluster create

.PHONY: k3d-cluster-create
k3d-cluster-delete: ## Delete a development k3d cluster.
k3d-cluster-delete:
./scripts/k3d-cluster delete
24 changes: 24 additions & 0 deletions production/ksonnet/enterprise-logs/jsonnetfile.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"version": 1,
"dependencies": [
{
"source": {
"git": {
"remote": "https://github.com/grafana/loki.git",
"subdir": "production/ksonnet/loki"
}
},
"version": "main"
},
{
"source": {
"git": {
"remote": "https://github.com/grafana/jsonnet-libs",
"subdir": "ksonnet-util"
}
},
"version": "master"
}
],
"legacyImports": true
}
66 changes: 66 additions & 0 deletions production/ksonnet/enterprise-logs/jsonnetfile.lock.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
{
"version": 1,
"dependencies": [
{
"source": {
"git": {
"remote": "https://github.com/grafana/jsonnet-libs.git",
"subdir": "consul"
}
},
"version": "00795013f5975f518a0a3de99253f9d5590271c8",
"sum": "Po3c1Ic96ngrJCtOazic/7OsLkoILOKZWXWyZWl+od8="
},
{
"source": {
"git": {
"remote": "https://github.com/grafana/jsonnet-libs.git",
"subdir": "jaeger-agent-mixin"
}
},
"version": "00795013f5975f518a0a3de99253f9d5590271c8",
"sum": "DsdBoqgx5kE3zc6fMYnfiGjW2+9Mx2OXFieWm1oFHgY="
},
{
"source": {
"git": {
"remote": "https://github.com/grafana/jsonnet-libs.git",
"subdir": "ksonnet-util"
}
},
"version": "00795013f5975f518a0a3de99253f9d5590271c8",
"sum": "OxgtIWL4hjvG0xkMwUzZ7Yjs52zUhLhaVQpwHCbqf8A="
},
{
"source": {
"git": {
"remote": "https://github.com/grafana/jsonnet-libs.git",
"subdir": "memcached"
}
},
"version": "00795013f5975f518a0a3de99253f9d5590271c8",
"sum": "dTOeEux3t9bYSqP2L/uCuLo/wUDpCKH4w+4OD9fePUk="
},
{
"source": {
"git": {
"remote": "https://github.com/grafana/loki.git",
"subdir": "production/ksonnet/loki"
}
},
"version": "9ea59f2062016d91398387ee2231e2e840af6a06",
"sum": "i27fS9sssvYd9Ywyq6uoB52EUWTaOPxo9DczCBVBuaM="
},
{
"source": {
"git": {
"remote": "https://github.com/jsonnet-libs/k8s-libsonnet.git",
"subdir": "1.18"
}
},
"version": "91008dbd2ea5734288467d6dcafef7c285c3f7e6",
"sum": "x881PM+6ARMsa9OSJcxO6L+4GOBy91clZipjeYbbzpw="
}
],
"legacyImports": false
}
220 changes: 220 additions & 0 deletions production/ksonnet/enterprise-logs/main.libsonnet
Original file line number Diff line number Diff line change
@@ -0,0 +1,220 @@
// TODO(jdb): Use cluster_dns_suffix to configure absolute domain names so as to avoid excessive lookups.
// TODO(jdb): Introduce utility functions for mapping over all containers, all microservices (modules), all apps, etc..
local k = import 'github.com/grafana/jsonnet-libs/ksonnet-util/kausal.libsonnet',
clusterRole = k.rbac.v1.clusterRole,
clusterRoleBinding = k.rbac.v1.clusterRoleBinding,
container = k.core.v1.container,
configMap = k.core.v1.configMap,
deployment = k.apps.v1.deployment,
job = k.batch.v1.job,
policyRule = k.rbac.v1.policyRule,
pvc = k.core.v1.persistentVolumeClaim,
service = k.core.v1.service,
serviceAccount = k.core.v1.serviceAccount,
subject = k.rbac.v1.subject,
statefulSet = k.apps.v1.statefulSet;
local loki = import 'github.com/grafana/loki/production/ksonnet/loki/loki.libsonnet';
local util = (import 'github.com/grafana/jsonnet-libs/ksonnet-util/util.libsonnet').withK(k) {
withNonRootSecurityContext(uid, fsGroup=null)::
{ spec+: { template+: { spec+: { securityContext: {
fsGroup: if fsGroup == null then uid else fsGroup,
runAsNonRoot: true,
runAsUser: uid,
} } } } },
};

loki {
_config+:: {
commonArgs+:: {
'auth.enabled': 'true',
'auth.type': 'enterprise',
'cluster-name':
if self['auth.type'] == 'enterprise' then
error 'must set _config.commonArgs.cluster-name'
else null,
},

loki+: {
distributor+: {
ring: {
kvstore: {
store: 'memberlist',
},
},
},
ingester+: {
lifecycler+: {
ring: {
kvstore: {
store: 'memberlist',
},
},
},
},
memberlist: {
retransmit_factor: 2,
gossip_interval: '5s',
stream_timeout: '5s',
abort_if_cluster_join_fails: false,
bind_port: 7946,
join_members: ['gossip-ring'],
},
},

ingester_pvc_size: '50Gi',
stateful_ingesters: true,

querier_pvc_size: '50Gi',
stateful_queriers: true,

compactor_pvc_size: '50Gi',
},

_images+:: {
loki: 'grafana/enterprise-logs:v1.1.0',
kubectl: 'bitnami/kubectl',
},

admin_api_args:: self._config.commonArgs {
'bootstrap.license.path': '/etc/gel-license/license.jwt',
target: 'admin-api',
},
admin_api_container::
container.new(name='admin-api', image=self._images.loki)
+ container.withArgs(util.mapToFlags(self.admin_api_args))
+ container.withPorts(loki.util.defaultPorts)
+ container.resources.withLimits({ cpu: '2', memory: '4Gi' })
+ container.resources.withRequests({ cpu: '500m', memory: '1Gi' })
+ loki.util.readinessProbe,
admin_api_deployment:
deployment.new(name='admin-api', replicas=3, containers=[self.admin_api_container])
+ deployment.spec.selector.withMatchLabelsMixin({ name: 'admin-api' })
+ deployment.spec.template.metadata.withLabelsMixin({ name: 'admin-api', gossip_ring_member: 'true' })
+ deployment.spec.template.spec.withTerminationGracePeriodSeconds(15)
+ util.configVolumeMount('loki', '/etc/loki/config')
+ util.secretVolumeMount('gel-license', '/etc/gel-license/')
+ util.withNonRootSecurityContext(uid=10001),
admin_api_service:
util.serviceFor(self.admin_api_deployment),

compactor_data_pvc+: { spec+: { storageClassName:: null } },
compactor_statefulset+: util.withNonRootSecurityContext(10001),

// Remove consul in favor of memberlist.
consul_config_map:: {},
consul_deployment:: null,
consul_service:: null,

distributor_deployment+:
deployment.spec.template.metadata.withLabelsMixin({ gossip_ring_member: 'true' })
+ util.withNonRootSecurityContext(uid=10001),

gateway_args:: self._config.commonArgs {
'bootstrap.license.path': '/etc/gel-license/license.jwt',
'gateway.proxy.admin-api.url': 'http://admin-api:%s' % $._config.http_listen_port,
'gateway.proxy.compactor.url': 'http://compactor:%s' % $._config.http_listen_port,
'gateway.proxy.distributor.url': 'dns:///distributor:9095',
'gateway.proxy.ingester.url': 'http://ingester:%s' % $._config.http_listen_port,
'gateway.proxy.query-frontend.url': 'http://query-frontend:%s' % $._config.http_listen_port,
'gateway.proxy.ruler.url': 'http://ruler:%s' % $._config.http_listen_port,
target: 'gateway',
},
gateway_container::
container.new(name='gateway', image=self._images.loki)
+ container.withArgs(util.mapToFlags(self.gateway_args))
+ container.withPorts(loki.util.defaultPorts)
+ container.resources.withLimits({ cpu: '2', memory: '4Gi' })
+ container.resources.withRequests({ cpu: '500m', memory: '1Gi' })
+ loki.util.readinessProbe,
gateway_deployment:
deployment.new(name='gateway', replicas=3, containers=[self.gateway_container])
+ deployment.spec.template.spec.withTerminationGracePeriodSeconds(15)
+ deployment.spec.template.spec.securityContext.withFsGroup(10001)
+ deployment.spec.template.spec.securityContext.withRunAsNonRoot(true)
+ deployment.spec.template.spec.securityContext.withRunAsUser(10001)
+ util.configVolumeMount('loki', '/etc/loki/config')
+ util.withNonRootSecurityContext(uid=10001),
// Remove the htpasswd Secret used by the OSS Loki NGINX gateway.
gateway_secret:: null,
gateway_service:
util.serviceFor(self.gateway_deployment),

ingester_data_pvc+: { spec+: { storageClassName:: null } },
ingester_statefulset+:
statefulSet.spec.template.metadata.withLabelsMixin({ gossip_ring_member: 'true' })
+ util.withNonRootSecurityContext(uid=10001),

querier_data_pvc+: { spec+: { storageClassName:: null } },
querier_statefulset+:
statefulSet.spec.template.metadata.withLabelsMixin({ gossip_ring_member: 'true' })
+ util.withNonRootSecurityContext(uid=10001),

table_manager_deployment+: util.withNonRootSecurityContext(uid=10001),

tokengen_args:: self._config.commonArgs {
target: 'tokengen',
'tokengen.token-file': '/shared/admin-token',
},
tokengen_container::
container.new('tokengen', self._images.loki)
+ container.withPorts(loki.util.defaultPorts)
+ container.withArgs(util.mapToFlags(self.tokengen_args))
+ container.withVolumeMounts([
{ mountPath: '/etc/loki/config', name: 'config' },
{ mountPath: '/shared', name: 'shared' },
])
+ container.resources.withLimits({ memory: '4Gi' })
+ container.resources.withRequests({ cpu: '500m', memory: '500Mi' }),
tokengen_create_secret_container::
container.new('create-secret', self._images.kubectl)
+ container.withCommand([
'/bin/bash',
'-euc',
'kubectl create secret generic gel-admin-token --from-file=token=/shared/admin-token --from-literal=grafana-token="self.base64 <(echo :self.cat /shared/admin-token)))"',
])
+ container.withVolumeMounts([{ mountPath: '/shared', name: 'shared' }]),
tokengen_job::
job.new('tokengen')
+ job.spec.withCompletions(1)
+ job.spec.withParallelism(1)
+ job.spec.template.spec.withContainers([self.tokengen_create_secret_container])
+ job.spec.template.spec.withInitContainers([self.tokengen_container])
+ job.spec.template.spec.withRestartPolicy('Never')
+ job.spec.template.spec.withServiceAccount('tokengen')
+ job.spec.template.spec.withServiceAccountName('tokengen')
+ job.spec.template.spec.withVolumes([
{ name: 'config', configMap: { name: 'loki' } },
{ name: 'shared', emptyDir: {} },
])
+ util.withNonRootSecurityContext(uid=10001),
tokengen_service_account:
serviceAccount.new('tokengen'),
tokengen_cluster_role:
clusterRole.new('tokengen')
+ clusterRole.withRules([
policyRule.withApiGroups([''])
+ policyRule.withResources(['secrets'])
+ policyRule.withVerbs(['create']),
]),
tokengen_cluster_role_binding:
clusterRoleBinding.new()
+ clusterRoleBinding.metadata.withName('tokengen')
+ clusterRoleBinding.roleRef.withApiGroup('rbac.authorization.k8s.io')
+ clusterRoleBinding.roleRef.withKind('ClusterRole')
+ clusterRoleBinding.roleRef.withName('tokengen')
+ clusterRoleBinding.withSubjects([
subject.new()
+ subject.withName('tokengen')
+ subject.withKind('ServiceAccount')
+ { namespace: $._config.namespace },
]),

gossip_ring_service:
service.new(
name='gossip-ring',
selector={ gossip_ring_member: 'true' },
ports=[{ name: 'gossip-ring', port: 7946, protocol: 'TCP', targetPort: 7946 }],
)
+ service.spec.withClusterIp('None')
+ service.spec.withPublishNotReadyAddresses(true),
}
Loading