From 24551948b549a8130b695022eb10db946213414f Mon Sep 17 00:00:00 2001 From: Matthias Loibl Date: Wed, 21 Oct 2020 19:22:39 +0200 Subject: [PATCH] Rewrite the thanos-receive component without ksonnet There were some changes in places were the receive component hasn't been consistent with the other components. Additionally, I also added PodDisruptionBudget to the examples/all/ Signed-off-by: Matthias Loibl --- all.jsonnet | 1 + .../thanos-receive-podDisruptionBudget.yaml | 12 + .../all/manifests/thanos-receive-service.yaml | 6 +- .../kube-thanos/kube-thanos-receive.libsonnet | 232 +++++++++--------- 4 files changed, 135 insertions(+), 116 deletions(-) create mode 100644 examples/all/manifests/thanos-receive-podDisruptionBudget.yaml diff --git a/all.jsonnet b/all.jsonnet index b227a34e..e80fb2aa 100644 --- a/all.jsonnet +++ b/all.jsonnet @@ -53,6 +53,7 @@ local re = t.receive + t.receive.withVolumeClaimTemplate + t.receive.withServiceMonitor + + t.receive.withPodDisruptionBudget + commonConfig + { config+:: { name: 'thanos-receive', diff --git a/examples/all/manifests/thanos-receive-podDisruptionBudget.yaml b/examples/all/manifests/thanos-receive-podDisruptionBudget.yaml new file mode 100644 index 00000000..f9a0619e --- /dev/null +++ b/examples/all/manifests/thanos-receive-podDisruptionBudget.yaml @@ -0,0 +1,12 @@ +apiVersion: policy/v1beta1 +kind: PodDisruptionBudget +metadata: + name: thanos-receive + namespace: thanos +spec: + maxUnavailable: 0 + selector: + matchLabels: + app.kubernetes.io/component: database-write-hashring + app.kubernetes.io/instance: thanos-receive + app.kubernetes.io/name: thanos-receive diff --git a/examples/all/manifests/thanos-receive-service.yaml b/examples/all/manifests/thanos-receive-service.yaml index 59842327..e7a4bd58 100644 --- a/examples/all/manifests/thanos-receive-service.yaml +++ b/examples/all/manifests/thanos-receive-service.yaml @@ -13,13 +13,13 @@ spec: ports: - name: grpc port: 10901 - targetPort: 10901 + targetPort: grpc - name: http port: 10902 - targetPort: 10902 + targetPort: http - name: remote-write port: 19291 - targetPort: 19291 + targetPort: remote-write selector: app.kubernetes.io/component: database-write-hashring app.kubernetes.io/instance: thanos-receive diff --git a/jsonnet/kube-thanos/kube-thanos-receive.libsonnet b/jsonnet/kube-thanos/kube-thanos-receive.libsonnet index 1404b3fa..e2e4314a 100644 --- a/jsonnet/kube-thanos/kube-thanos-receive.libsonnet +++ b/jsonnet/kube-thanos/kube-thanos-receive.libsonnet @@ -1,5 +1,3 @@ -local k = import 'ksonnet/ksonnet.beta.4/k.libsonnet'; - { local tr = self, @@ -28,122 +26,125 @@ local k = import 'ksonnet/ksonnet.beta.4/k.libsonnet'; }, service: - local service = k.core.v1.service; - local ports = service.mixin.spec.portsType; - - service.new( - tr.config.name, - tr.config.podLabelSelector, - [ - ports.newNamed('grpc', 10901, 10901), - ports.newNamed('http', 10902, 10902), - ports.newNamed('remote-write', 19291, 19291), - ] - ) + - service.mixin.metadata.withNamespace(tr.config.namespace) + - service.mixin.metadata.withLabels(tr.config.commonLabels) + - service.mixin.spec.withClusterIp('None'), + { + apiVersion: 'v1', + kind: 'Service', + metadata: { + name: tr.config.name, + namespace: tr.config.namespace, + labels: tr.config.commonLabels, + }, + spec: { + clusterIP: 'None', + ports: [ + { name: 'grpc', targetPort: 'grpc', port: 10901 }, + { name: 'http', targetPort: 'http', port: 10902 }, + { name: 'remote-write', targetPort: 'remote-write', port: 19291 }, + ], + selector: tr.config.podLabelSelector, + }, + }, statefulSet: - local sts = k.apps.v1.statefulSet; - local affinity = sts.mixin.spec.template.spec.affinity.podAntiAffinity.preferredDuringSchedulingIgnoredDuringExecutionType; - local matchExpression = affinity.mixin.podAffinityTerm.labelSelector.matchExpressionsType; - local volume = sts.mixin.spec.template.spec.volumesType; - local container = sts.mixin.spec.template.spec.containersType; - local containerEnv = container.envType; - local containerVolumeMount = container.volumeMountsType; - - local replicationFactor = tr.config.replicationFactor; local localEndpointFlag = '--receive.local-endpoint=$(NAME).%s.$(NAMESPACE).svc.cluster.local:%d' % [tr.config.name, tr.service.spec.ports[0].port]; - local c = - container.new('thanos-receive', tr.config.image) + - container.withTerminationMessagePolicy('FallbackToLogsOnError') + - container.withArgs([ + local c = { + name: 'thanos-receive', + image: tr.config.image, + args: [ 'receive', '--log.level=' + tr.config.logLevel, '--grpc-address=0.0.0.0:%d' % tr.service.spec.ports[0].port, '--http-address=0.0.0.0:%d' % tr.service.spec.ports[1].port, '--remote-write.address=0.0.0.0:%d' % tr.service.spec.ports[2].port, - '--receive.replication-factor=%d' % replicationFactor, + '--receive.replication-factor=%d' % tr.config.replicationFactor, '--objstore.config=$(OBJSTORE_CONFIG)', '--tsdb.path=/var/thanos/receive', '--label=replica="$(NAME)"', '--label=receive="true"', localEndpointFlag, - ]) + - container.withEnv([ - containerEnv.fromFieldPath('NAME', 'metadata.name'), - containerEnv.fromFieldPath('NAMESPACE', 'metadata.namespace'), - containerEnv.fromSecretRef( - 'OBJSTORE_CONFIG', - tr.config.objectStorageConfig.name, - tr.config.objectStorageConfig.key, - ), - ]) + - container.withPorts([ - { name: 'grpc', containerPort: tr.service.spec.ports[0].port }, - { name: 'http', containerPort: tr.service.spec.ports[1].port }, - { name: 'remote-write', containerPort: tr.service.spec.ports[2].port }, - ]) + - container.withVolumeMounts([ - containerVolumeMount.new('data', '/var/thanos/receive', false), - ]) + - container.mixin.livenessProbe + - container.mixin.livenessProbe.withPeriodSeconds(30) + - container.mixin.livenessProbe.withFailureThreshold(8) + - container.mixin.livenessProbe.httpGet.withPort(tr.service.spec.ports[1].port) + - container.mixin.livenessProbe.httpGet.withScheme('HTTP') + - container.mixin.livenessProbe.httpGet.withPath('/-/healthy') + - container.mixin.readinessProbe + - container.mixin.readinessProbe.withPeriodSeconds(5) + - container.mixin.readinessProbe.withFailureThreshold(20) + - container.mixin.readinessProbe.httpGet.withPort(tr.service.spec.ports[1].port) + - container.mixin.readinessProbe.httpGet.withScheme('HTTP') + - container.mixin.readinessProbe.httpGet.withPath('/-/ready'); + ], + env: [ + { name: 'NAME', valueFrom: { fieldRef: { fieldPath: 'metadata.name' } } }, + { name: 'NAMESPACE', valueFrom: { fieldRef: { fieldPath: 'metadata.namespace' } } }, + { name: 'OBJSTORE_CONFIG', valueFrom: { secretKeyRef: { + key: tr.config.objectStorageConfig.key, + name: tr.config.objectStorageConfig.name, + } } }, + ], + ports: [ + { name: port.name, containerPort: port.port } + for port in tr.service.spec.ports + ], + volumeMounts: [{ + name: 'data', + mountPath: '/var/thanos/receive', + readOnly: false, + }], + livenessProbe: { failureThreshold: 8, periodSeconds: 30, httpGet: { + scheme: 'HTTP', + port: tr.service.spec.ports[1].port, + path: '/-/healthy', + } }, + readinessProbe: { failureThreshold: 20, periodSeconds: 5, httpGet: { + scheme: 'HTTP', + port: tr.service.spec.ports[1].port, + path: '/-/ready', + } }, + terminationMessagePolicy: 'FallbackToLogsOnError', + }; - sts.new(tr.config.name, tr.config.replicas, c, [], tr.config.commonLabels) + - sts.mixin.metadata.withNamespace(tr.config.namespace) + - sts.mixin.metadata.withLabels(tr.config.commonLabels) + - sts.mixin.spec.withServiceName(tr.service.metadata.name) + - sts.mixin.spec.template.spec.withTerminationGracePeriodSeconds(900) + - sts.mixin.spec.template.spec.withVolumes([ - volume.fromEmptyDir('data'), - ]) + - sts.mixin.spec.template.spec.affinity.podAntiAffinity.withPreferredDuringSchedulingIgnoredDuringExecution([ - affinity.new() + - affinity.withWeight(100) + - affinity.mixin.podAffinityTerm.withNamespaces(tr.config.namespace) + - affinity.mixin.podAffinityTerm.withTopologyKey('kubernetes.io/hostname') + - affinity.mixin.podAffinityTerm.labelSelector.withMatchExpressions([ - matchExpression.new() + - matchExpression.withKey('app.kubernetes.io/name') + - matchExpression.withOperator('In') + - matchExpression.withValues([tr.statefulSet.metadata.labels['app.kubernetes.io/name']]), - matchExpression.new() + - matchExpression.withKey('app.kubernetes.io/instance') + - matchExpression.withOperator('In') + - matchExpression.withValues([tr.statefulSet.metadata.labels['app.kubernetes.io/instance']]), - ]), - affinity.new() + - affinity.withWeight(100) + - affinity.mixin.podAffinityTerm.withNamespaces(tr.config.namespace) + - affinity.mixin.podAffinityTerm.withTopologyKey('topology.kubernetes.io/zone') + - affinity.mixin.podAffinityTerm.labelSelector.withMatchExpressions([ - matchExpression.new() + - matchExpression.withKey('app.kubernetes.io/name') + - matchExpression.withOperator('In') + - matchExpression.withValues([tr.statefulSet.metadata.labels['app.kubernetes.io/name']]), - matchExpression.new() + - matchExpression.withKey('app.kubernetes.io/instance') + - matchExpression.withOperator('In') + - matchExpression.withValues([tr.statefulSet.metadata.labels['app.kubernetes.io/instance']]), - ]), - ]) + - sts.mixin.spec.selector.withMatchLabels(tr.config.podLabelSelector) + { - spec+: { - volumeClaimTemplates: null, + apiVersion: 'apps/v1', + kind: 'StatefulSet', + metadata: { + name: tr.config.name, + namespace: tr.config.namespace, + labels: tr.config.commonLabels, + }, + spec: { + replicas: tr.config.replicas, + selector: { matchLabels: tr.config.podLabelSelector }, + serviceName: tr.service.metadata.name, + template: { + metadata: { + labels: tr.config.commonLabels, + }, + spec: { + containers: [c], + volumes: [], + terminationGracePeriodSeconds: 900, + affinity: { podAntiAffinity: { + local labelSelector = { matchExpressions: [{ + key: 'app.kubernetes.io/name', + operator: 'In', + values: [tr.statefulSet.metadata.labels['app.kubernetes.io/name']], + }, { + key: 'app.kubernetes.io/instance', + operator: 'In', + values: [tr.statefulSet.metadata.labels['app.kubernetes.io/instance']], + }] }, + preferredDuringSchedulingIgnoredDuringExecution: [ + { + podAffinityTerm: { + namespaces: [tr.config.namespace], + topologyKey: 'kubernetes.io/hostname', + labelSelector: labelSelector, + }, + weight: 100, + }, + { + podAffinityTerm: { + namespaces: [tr.config.namespace], + topologyKey: 'topology.kubernetes.io/zone', + labelSelector: labelSelector, + }, + weight: 100, + }, + ], + } }, + }, + }, }, }, @@ -182,12 +183,18 @@ local k = import 'ksonnet/ksonnet.beta.4/k.libsonnet'; }, podDisruptionBudget: - local pdb = k.policy.v1beta1.podDisruptionBudget; - pdb.new() + - pdb.mixin.spec.withMaxUnavailable(tr.config.podDisruptionBudgetMaxUnavailable) + - pdb.mixin.spec.selector.withMatchLabels(tr.config.podLabelSelector) + - pdb.mixin.metadata.withName(tr.config.name) + - pdb.mixin.metadata.withNamespace(tr.config.namespace), + { + apiVersion: 'policy/v1beta1', + kind: 'PodDisruptionBudget', + metadata: { + name: tr.config.name, + namespace: tr.config.namespace, + }, + spec: { + maxUnavailable: 0, + selector: { matchLabels: tr.config.podLabelSelector }, + }, + }, }, withVolumeClaimTemplate:: { @@ -259,11 +266,10 @@ local k = import 'ksonnet/ksonnet.beta.4/k.libsonnet'; for c in super.containers ], - local volume = k.apps.v1.statefulSet.mixin.spec.template.spec.volumesType, - volumes+: [ - volume.withName('hashring-config') + - volume.mixin.configMap.withName(tr.config.hashringConfigMapName), - ], + volumes+: [{ + name: 'hashring-config', + configMap: { name: tr.config.hashringConfigMapName }, + }], }, }, },