1
0
Fork 0
mirror of https://github.com/prometheus-operator/prometheus-operator.git synced 2025-04-16 01:06:27 +00:00
prometheus-operator/pkg/prometheus/statefulset.go

923 lines
28 KiB
Go
Raw Normal View History

// Copyright 2016 The prometheus-operator Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
2016-11-04 15:02:40 +01:00
package prometheus
2016-09-22 15:25:57 +02:00
import (
"fmt"
2017-06-22 14:58:01 +02:00
"net/url"
"path"
"strings"
appsv1 "k8s.io/api/apps/v1"
v1 "k8s.io/api/core/v1"
2017-05-11 14:05:39 +02:00
"k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/intstr"
2017-04-18 15:08:11 +02:00
"github.com/blang/semver"
"github.com/pkg/errors"
monitoringv1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1"
"github.com/prometheus-operator/prometheus-operator/pkg/k8sutil"
"github.com/prometheus-operator/prometheus-operator/pkg/operator"
2016-09-22 15:25:57 +02:00
)
2017-01-18 19:07:22 +01:00
const (
governingServiceName = "prometheus-operated"
defaultRetention = "24h"
defaultReplicaExternalLabelName = "prometheus_replica"
storageDir = "/prometheus"
confDir = "/etc/prometheus/config"
confOutDir = "/etc/prometheus/config_out"
pkg/prometheus: Enable users to configure bearer token from secret To configure a bearer token users could only specify a file path in the service monitor, pointing to a bearer token file in the Prometheus container. This enables hostile users, being able to configure a service monitor and controlling the scrape target, to retrieve arbitrary files in the Prometheus container. In cases where users can not be trusted, this patch adds an option to disallow the above file path specification and replaces it by a secret reference. This secret has to be in the same namespace as the service monitor, shrinking the attack vector. pkg/prometheus: Add option to deny file system access through service monitors ArbitraryFSAccessThroughSMsConfig enables users to configure, whether a service monitor selected by the Prometheus instance is allowed to use arbitrary files on the file system of the Prometheus container. This is the case when e.g. a service monitor specifies a BearerTokenFile in an endpoint. A malicious user could create a service monitor selecting arbitrary secret files in the Prometheus container. Those secrets would then be send with a scrape request by Prometheus to a malicious target. Denying the above would prevent the attack, users can instead use the BearerTokenSecret field. test/basic-auth-test-app: Add mTLS endpoint pkg/prometheus: Enable users to configure tls from secret pkg/prometheus/operator: Validate TLS configs before retrieving assets Before retrieving TLS assets from Kubernetes secrets for a given service monitor, make sure the user did not specify both file and secret reference, e.g. both `CAFile` and `CASecret`. test: Rename basic-auth-test-app to instrumented-sample-app Given that the basic-auth-test-app not only supports basic auth, but also bearer token as well as tls authentication, this patch renames the app to a more generic name. test/e2e/prometheus_test: Test ArbitraryFSAccessThroughSM option for tls The Prometheus custom resource has the option to disable arbitrary filesystem access configured through service monitors. This commit adds an end-to-end test for this option in combination with the TLS configuration via files or secret references in service monitors. pkg/prometheus/operator: Move check for arbitrary fs access into func
2019-03-18 15:56:38 +01:00
tlsAssetsDir = "/etc/prometheus/certs"
rulesDir = "/etc/prometheus/rules"
secretsDir = "/etc/prometheus/secrets/"
configmapsDir = "/etc/prometheus/configmaps/"
configFilename = "prometheus.yaml.gz"
configEnvsubstFilename = "prometheus.env.yaml"
sSetInputHashName = "prometheus-operator-input-hash"
defaultPortName = "web"
2017-01-18 19:07:22 +01:00
)
2017-02-24 13:17:07 +01:00
var (
minReplicas int32 = 1
defaultMaxConcurrency int32 = 20
managedByOperatorLabel = "managed-by"
managedByOperatorLabelValue = "prometheus-operator"
managedByOperatorLabels = map[string]string{
managedByOperatorLabel: managedByOperatorLabelValue,
}
2017-04-27 18:20:21 +03:00
probeTimeoutSeconds int32 = 3
2017-02-24 13:17:07 +01:00
)
prometheus: Introduce RuleFile Custom Resource Definition This patch introduces a new Custom Resource Definition to the Prometheus Operator - the Rule CRD. It addresses two main needs: 1. Prometheus (alerting and recording) Rule validation during creation time via Kubernetes Custom Resource Definition validation. 2. Life-cycle management of Prometheus application Rules alongside the application itself, inside the applications Kubernetes namespace, not necessarily the namespace of the scraping Prometheus instance. A user defines Prometheus alerting and recording Rules via a Kubernetes Custom Resource Definition. These Custom Resource Definitions can be fully validated by the Kubernetes API server during creation time via automatically generated OpenAPI specifications. Instead of the restriction of a Prometheus instance to only select Rule definitions inside its own namespace, the Prometheus specification is extended to also specify namespaces to look for Rule Custom Resource Definitions outside its own namespace. --- Dependent technical changes: - prometheus: Use github.com/jimmidyson/configmap-reload to reload rules - prometheus: Remove Prometheus Statefulset deletion function. Starting with K8s >=1.8 this is handled via OwnerReferences. - prometheus: Do not add rule files checksum to Prometheus configuration secret - prometheus: Update StatefulSet only on relevant changes. Instead of updating the Prometheus StatefulSet on every `sync()` run, only update it if the input parameters to `makeStatefulSet` change. Enforce this via a checksum of the parameters which is saved inside the annotations of the statefulset. - e2e/prometheus: Check how often resources (Secret, ConfigMap, Prometheus CRD, Service) are updated to enforce that Prometheus Operator only updated created resources if necessary. - contrib/prometheus-config-reloader: Remove logic to retriev K8s ConfigMaps. These are mounted into the pod right away now.
2018-05-08 09:43:45 +02:00
func makeStatefulSet(
p monitoringv1.Prometheus,
config *Config,
ruleConfigMapNames []string,
inputHash string,
prometheus: Introduce RuleFile Custom Resource Definition This patch introduces a new Custom Resource Definition to the Prometheus Operator - the Rule CRD. It addresses two main needs: 1. Prometheus (alerting and recording) Rule validation during creation time via Kubernetes Custom Resource Definition validation. 2. Life-cycle management of Prometheus application Rules alongside the application itself, inside the applications Kubernetes namespace, not necessarily the namespace of the scraping Prometheus instance. A user defines Prometheus alerting and recording Rules via a Kubernetes Custom Resource Definition. These Custom Resource Definitions can be fully validated by the Kubernetes API server during creation time via automatically generated OpenAPI specifications. Instead of the restriction of a Prometheus instance to only select Rule definitions inside its own namespace, the Prometheus specification is extended to also specify namespaces to look for Rule Custom Resource Definitions outside its own namespace. --- Dependent technical changes: - prometheus: Use github.com/jimmidyson/configmap-reload to reload rules - prometheus: Remove Prometheus Statefulset deletion function. Starting with K8s >=1.8 this is handled via OwnerReferences. - prometheus: Do not add rule files checksum to Prometheus configuration secret - prometheus: Update StatefulSet only on relevant changes. Instead of updating the Prometheus StatefulSet on every `sync()` run, only update it if the input parameters to `makeStatefulSet` change. Enforce this via a checksum of the parameters which is saved inside the annotations of the statefulset. - e2e/prometheus: Check how often resources (Secret, ConfigMap, Prometheus CRD, Service) are updated to enforce that Prometheus Operator only updated created resources if necessary. - contrib/prometheus-config-reloader: Remove logic to retriev K8s ConfigMaps. These are mounted into the pod right away now.
2018-05-08 09:43:45 +02:00
) (*appsv1.StatefulSet, error) {
pkg/*/statefulset.go: Do not mutate shared object Users have reported high CPU usage of the Prometheus Operator when adding an annotation to a Prometheus object. The Operator would update the respective StatefulSet in an infinite loop. Whether a given StatefulSet needs updating is determined by the hash of the inputs needed to generate the StatefulSet, which is calculated and then attached to the StatefulSet as an annotation. On subsequent reconciliations this hash is compared to the hash of the new inputs. The function to build the StatefulSet definition is passed the Prometheus object. This is done by value, not by reference. This does not enforce a deep copy but merely a shallow copy. In the build function the new StatefulSet would inherit the annotation map of the Prometheus object. Next the input hash would be added to this map, resulting in both the Statefulset having the hash annotation, as intended, as well as the Prometheus object (same map, shared as a reference). On subsequent reconciliations the same Prometheus object is used to calculate the input hash, this time accidentally containing the has annotation from the previous run. Even though the actual inputs never changed, this results in a new hash, thereby updating the StatefulSet, ... The solution is to deep copy the Prometheus object before using it in the StatefulSet build function, thereby never mutating the annotations of the Prometheus object. Same measure is taken for the Alertmanager StatefulSet build function.
2018-08-13 13:42:41 +02:00
// p is passed in by value, not by reference. But p contains references like
// to annotation map, that do not get copied on function invocation. Ensure to
// prevent side effects before editing p by creating a deep copy. For more
// details see https://github.com/prometheus-operator/prometheus-operator/issues/1659.
pkg/*/statefulset.go: Do not mutate shared object Users have reported high CPU usage of the Prometheus Operator when adding an annotation to a Prometheus object. The Operator would update the respective StatefulSet in an infinite loop. Whether a given StatefulSet needs updating is determined by the hash of the inputs needed to generate the StatefulSet, which is calculated and then attached to the StatefulSet as an annotation. On subsequent reconciliations this hash is compared to the hash of the new inputs. The function to build the StatefulSet definition is passed the Prometheus object. This is done by value, not by reference. This does not enforce a deep copy but merely a shallow copy. In the build function the new StatefulSet would inherit the annotation map of the Prometheus object. Next the input hash would be added to this map, resulting in both the Statefulset having the hash annotation, as intended, as well as the Prometheus object (same map, shared as a reference). On subsequent reconciliations the same Prometheus object is used to calculate the input hash, this time accidentally containing the has annotation from the previous run. Even though the actual inputs never changed, this results in a new hash, thereby updating the StatefulSet, ... The solution is to deep copy the Prometheus object before using it in the StatefulSet build function, thereby never mutating the annotations of the Prometheus object. Same measure is taken for the Alertmanager StatefulSet build function.
2018-08-13 13:42:41 +02:00
p = *p.DeepCopy()
promVersion := operator.StringValOrDefault(p.Spec.Version, operator.DefaultPrometheusVersion)
parsedVersion, err := semver.ParseTolerant(promVersion)
if err != nil {
return nil, errors.Wrap(err, "failed to parse prometheus version")
}
if p.Spec.PortName == "" {
p.Spec.PortName = defaultPortName
}
2017-09-15 15:28:16 +02:00
if p.Spec.Replicas == nil {
p.Spec.Replicas = &minReplicas
}
intZero := int32(0)
if p.Spec.Replicas != nil && *p.Spec.Replicas < 0 {
p.Spec.Replicas = &intZero
}
if p.Spec.Retention == "" {
2017-01-18 19:07:22 +01:00
p.Spec.Retention = defaultRetention
2016-11-02 11:50:36 -07:00
}
if p.Spec.Resources.Requests == nil {
p.Spec.Resources.Requests = v1.ResourceList{}
}
_, memoryRequestFound := p.Spec.Resources.Requests[v1.ResourceMemory]
memoryLimit, memoryLimitFound := p.Spec.Resources.Limits[v1.ResourceMemory]
if !memoryRequestFound && parsedVersion.Major == 1 {
defaultMemoryRequest := resource.MustParse("2Gi")
compareResult := memoryLimit.Cmp(defaultMemoryRequest)
// If limit is given and smaller or equal to 2Gi, then set memory
// request to the given limit. This is necessary as if limit < request,
// then a Pod is not schedulable.
if memoryLimitFound && compareResult <= 0 {
p.Spec.Resources.Requests[v1.ResourceMemory] = memoryLimit
} else {
p.Spec.Resources.Requests[v1.ResourceMemory] = defaultMemoryRequest
}
}
spec, err := makeStatefulSetSpec(p, config, ruleConfigMapNames, parsedVersion)
2017-04-18 15:08:11 +02:00
if err != nil {
return nil, errors.Wrap(err, "make StatefulSet spec")
}
boolTrue := true
// do not transfer kubectl annotations to the statefulset so it is not
// pruned by kubectl
annotations := make(map[string]string)
for key, value := range p.ObjectMeta.Annotations {
if !strings.HasPrefix(key, "kubectl.kubernetes.io/") {
annotations[key] = value
}
}
2018-03-09 15:12:59 +01:00
statefulset := &appsv1.StatefulSet{
2017-05-11 14:05:39 +02:00
ObjectMeta: metav1.ObjectMeta{
2017-01-18 19:07:22 +01:00
Name: prefixedName(p.Name),
Labels: config.Labels.Merge(p.ObjectMeta.Labels),
Annotations: annotations,
OwnerReferences: []metav1.OwnerReference{
{
APIVersion: p.APIVersion,
BlockOwnerDeletion: &boolTrue,
Controller: &boolTrue,
Kind: p.Kind,
Name: p.Name,
UID: p.UID,
},
},
2016-09-22 15:25:57 +02:00
},
2017-04-18 15:08:11 +02:00
Spec: *spec,
}
prometheus: Introduce RuleFile Custom Resource Definition This patch introduces a new Custom Resource Definition to the Prometheus Operator - the Rule CRD. It addresses two main needs: 1. Prometheus (alerting and recording) Rule validation during creation time via Kubernetes Custom Resource Definition validation. 2. Life-cycle management of Prometheus application Rules alongside the application itself, inside the applications Kubernetes namespace, not necessarily the namespace of the scraping Prometheus instance. A user defines Prometheus alerting and recording Rules via a Kubernetes Custom Resource Definition. These Custom Resource Definitions can be fully validated by the Kubernetes API server during creation time via automatically generated OpenAPI specifications. Instead of the restriction of a Prometheus instance to only select Rule definitions inside its own namespace, the Prometheus specification is extended to also specify namespaces to look for Rule Custom Resource Definitions outside its own namespace. --- Dependent technical changes: - prometheus: Use github.com/jimmidyson/configmap-reload to reload rules - prometheus: Remove Prometheus Statefulset deletion function. Starting with K8s >=1.8 this is handled via OwnerReferences. - prometheus: Do not add rule files checksum to Prometheus configuration secret - prometheus: Update StatefulSet only on relevant changes. Instead of updating the Prometheus StatefulSet on every `sync()` run, only update it if the input parameters to `makeStatefulSet` change. Enforce this via a checksum of the parameters which is saved inside the annotations of the statefulset. - e2e/prometheus: Check how often resources (Secret, ConfigMap, Prometheus CRD, Service) are updated to enforce that Prometheus Operator only updated created resources if necessary. - contrib/prometheus-config-reloader: Remove logic to retriev K8s ConfigMaps. These are mounted into the pod right away now.
2018-05-08 09:43:45 +02:00
if statefulset.ObjectMeta.Annotations == nil {
statefulset.ObjectMeta.Annotations = map[string]string{
sSetInputHashName: inputHash,
prometheus: Introduce RuleFile Custom Resource Definition This patch introduces a new Custom Resource Definition to the Prometheus Operator - the Rule CRD. It addresses two main needs: 1. Prometheus (alerting and recording) Rule validation during creation time via Kubernetes Custom Resource Definition validation. 2. Life-cycle management of Prometheus application Rules alongside the application itself, inside the applications Kubernetes namespace, not necessarily the namespace of the scraping Prometheus instance. A user defines Prometheus alerting and recording Rules via a Kubernetes Custom Resource Definition. These Custom Resource Definitions can be fully validated by the Kubernetes API server during creation time via automatically generated OpenAPI specifications. Instead of the restriction of a Prometheus instance to only select Rule definitions inside its own namespace, the Prometheus specification is extended to also specify namespaces to look for Rule Custom Resource Definitions outside its own namespace. --- Dependent technical changes: - prometheus: Use github.com/jimmidyson/configmap-reload to reload rules - prometheus: Remove Prometheus Statefulset deletion function. Starting with K8s >=1.8 this is handled via OwnerReferences. - prometheus: Do not add rule files checksum to Prometheus configuration secret - prometheus: Update StatefulSet only on relevant changes. Instead of updating the Prometheus StatefulSet on every `sync()` run, only update it if the input parameters to `makeStatefulSet` change. Enforce this via a checksum of the parameters which is saved inside the annotations of the statefulset. - e2e/prometheus: Check how often resources (Secret, ConfigMap, Prometheus CRD, Service) are updated to enforce that Prometheus Operator only updated created resources if necessary. - contrib/prometheus-config-reloader: Remove logic to retriev K8s ConfigMaps. These are mounted into the pod right away now.
2018-05-08 09:43:45 +02:00
}
} else {
statefulset.ObjectMeta.Annotations[sSetInputHashName] = inputHash
prometheus: Introduce RuleFile Custom Resource Definition This patch introduces a new Custom Resource Definition to the Prometheus Operator - the Rule CRD. It addresses two main needs: 1. Prometheus (alerting and recording) Rule validation during creation time via Kubernetes Custom Resource Definition validation. 2. Life-cycle management of Prometheus application Rules alongside the application itself, inside the applications Kubernetes namespace, not necessarily the namespace of the scraping Prometheus instance. A user defines Prometheus alerting and recording Rules via a Kubernetes Custom Resource Definition. These Custom Resource Definitions can be fully validated by the Kubernetes API server during creation time via automatically generated OpenAPI specifications. Instead of the restriction of a Prometheus instance to only select Rule definitions inside its own namespace, the Prometheus specification is extended to also specify namespaces to look for Rule Custom Resource Definitions outside its own namespace. --- Dependent technical changes: - prometheus: Use github.com/jimmidyson/configmap-reload to reload rules - prometheus: Remove Prometheus Statefulset deletion function. Starting with K8s >=1.8 this is handled via OwnerReferences. - prometheus: Do not add rule files checksum to Prometheus configuration secret - prometheus: Update StatefulSet only on relevant changes. Instead of updating the Prometheus StatefulSet on every `sync()` run, only update it if the input parameters to `makeStatefulSet` change. Enforce this via a checksum of the parameters which is saved inside the annotations of the statefulset. - e2e/prometheus: Check how often resources (Secret, ConfigMap, Prometheus CRD, Service) are updated to enforce that Prometheus Operator only updated created resources if necessary. - contrib/prometheus-config-reloader: Remove logic to retriev K8s ConfigMaps. These are mounted into the pod right away now.
2018-05-08 09:43:45 +02:00
}
if p.Spec.ImagePullSecrets != nil && len(p.Spec.ImagePullSecrets) > 0 {
2017-04-27 18:20:21 +03:00
statefulset.Spec.Template.Spec.ImagePullSecrets = p.Spec.ImagePullSecrets
}
storageSpec := p.Spec.Storage
if storageSpec == nil {
statefulset.Spec.Template.Spec.Volumes = append(statefulset.Spec.Template.Spec.Volumes, v1.Volume{
2017-01-18 19:07:22 +01:00
Name: volumeName(p.Name),
2016-10-28 17:42:35 +02:00
VolumeSource: v1.VolumeSource{
EmptyDir: &v1.EmptyDirVolumeSource{},
},
})
} else if storageSpec.EmptyDir != nil {
emptyDir := storageSpec.EmptyDir
statefulset.Spec.Template.Spec.Volumes = append(statefulset.Spec.Template.Spec.Volumes, v1.Volume{
Name: volumeName(p.Name),
VolumeSource: v1.VolumeSource{
EmptyDir: emptyDir,
},
})
2016-10-28 17:42:35 +02:00
} else {
pvcTemplate := operator.MakeVolumeClaimTemplate(storageSpec.VolumeClaimTemplate)
if pvcTemplate.Name == "" {
pvcTemplate.Name = volumeName(p.Name)
}
if storageSpec.VolumeClaimTemplate.Spec.AccessModes == nil {
pvcTemplate.Spec.AccessModes = []v1.PersistentVolumeAccessMode{v1.ReadWriteOnce}
} else {
pvcTemplate.Spec.AccessModes = storageSpec.VolumeClaimTemplate.Spec.AccessModes
}
pvcTemplate.Spec.Resources = storageSpec.VolumeClaimTemplate.Spec.Resources
pvcTemplate.Spec.Selector = storageSpec.VolumeClaimTemplate.Spec.Selector
statefulset.Spec.VolumeClaimTemplates = append(statefulset.Spec.VolumeClaimTemplates, *pvcTemplate)
2016-10-28 17:42:35 +02:00
}
for _, volume := range p.Spec.Volumes {
statefulset.Spec.Template.Spec.Volumes = append(statefulset.Spec.Template.Spec.Volumes, volume)
}
2017-04-18 15:08:11 +02:00
return statefulset, nil
}
prometheus: Introduce RuleFile Custom Resource Definition This patch introduces a new Custom Resource Definition to the Prometheus Operator - the Rule CRD. It addresses two main needs: 1. Prometheus (alerting and recording) Rule validation during creation time via Kubernetes Custom Resource Definition validation. 2. Life-cycle management of Prometheus application Rules alongside the application itself, inside the applications Kubernetes namespace, not necessarily the namespace of the scraping Prometheus instance. A user defines Prometheus alerting and recording Rules via a Kubernetes Custom Resource Definition. These Custom Resource Definitions can be fully validated by the Kubernetes API server during creation time via automatically generated OpenAPI specifications. Instead of the restriction of a Prometheus instance to only select Rule definitions inside its own namespace, the Prometheus specification is extended to also specify namespaces to look for Rule Custom Resource Definitions outside its own namespace. --- Dependent technical changes: - prometheus: Use github.com/jimmidyson/configmap-reload to reload rules - prometheus: Remove Prometheus Statefulset deletion function. Starting with K8s >=1.8 this is handled via OwnerReferences. - prometheus: Do not add rule files checksum to Prometheus configuration secret - prometheus: Update StatefulSet only on relevant changes. Instead of updating the Prometheus StatefulSet on every `sync()` run, only update it if the input parameters to `makeStatefulSet` change. Enforce this via a checksum of the parameters which is saved inside the annotations of the statefulset. - e2e/prometheus: Check how often resources (Secret, ConfigMap, Prometheus CRD, Service) are updated to enforce that Prometheus Operator only updated created resources if necessary. - contrib/prometheus-config-reloader: Remove logic to retriev K8s ConfigMaps. These are mounted into the pod right away now.
2018-05-08 09:43:45 +02:00
func makeEmptyConfigurationSecret(p *monitoringv1.Prometheus, config Config) (*v1.Secret, error) {
s := makeConfigSecret(p, config)
s.ObjectMeta.Annotations = map[string]string{
"empty": "true",
}
return s, nil
}
prometheus: Introduce RuleFile Custom Resource Definition This patch introduces a new Custom Resource Definition to the Prometheus Operator - the Rule CRD. It addresses two main needs: 1. Prometheus (alerting and recording) Rule validation during creation time via Kubernetes Custom Resource Definition validation. 2. Life-cycle management of Prometheus application Rules alongside the application itself, inside the applications Kubernetes namespace, not necessarily the namespace of the scraping Prometheus instance. A user defines Prometheus alerting and recording Rules via a Kubernetes Custom Resource Definition. These Custom Resource Definitions can be fully validated by the Kubernetes API server during creation time via automatically generated OpenAPI specifications. Instead of the restriction of a Prometheus instance to only select Rule definitions inside its own namespace, the Prometheus specification is extended to also specify namespaces to look for Rule Custom Resource Definitions outside its own namespace. --- Dependent technical changes: - prometheus: Use github.com/jimmidyson/configmap-reload to reload rules - prometheus: Remove Prometheus Statefulset deletion function. Starting with K8s >=1.8 this is handled via OwnerReferences. - prometheus: Do not add rule files checksum to Prometheus configuration secret - prometheus: Update StatefulSet only on relevant changes. Instead of updating the Prometheus StatefulSet on every `sync()` run, only update it if the input parameters to `makeStatefulSet` change. Enforce this via a checksum of the parameters which is saved inside the annotations of the statefulset. - e2e/prometheus: Check how often resources (Secret, ConfigMap, Prometheus CRD, Service) are updated to enforce that Prometheus Operator only updated created resources if necessary. - contrib/prometheus-config-reloader: Remove logic to retriev K8s ConfigMaps. These are mounted into the pod right away now.
2018-05-08 09:43:45 +02:00
func makeConfigSecret(p *monitoringv1.Prometheus, config Config) *v1.Secret {
boolTrue := true
return &v1.Secret{
2017-05-11 14:05:39 +02:00
ObjectMeta: metav1.ObjectMeta{
Name: configSecretName(p.Name),
Labels: config.Labels.Merge(managedByOperatorLabels),
OwnerReferences: []metav1.OwnerReference{
{
APIVersion: p.APIVersion,
BlockOwnerDeletion: &boolTrue,
Controller: &boolTrue,
Kind: p.Kind,
Name: p.Name,
UID: p.UID,
},
},
},
Data: map[string][]byte{
configFilename: {},
},
prometheus: Introduce RuleFile Custom Resource Definition This patch introduces a new Custom Resource Definition to the Prometheus Operator - the Rule CRD. It addresses two main needs: 1. Prometheus (alerting and recording) Rule validation during creation time via Kubernetes Custom Resource Definition validation. 2. Life-cycle management of Prometheus application Rules alongside the application itself, inside the applications Kubernetes namespace, not necessarily the namespace of the scraping Prometheus instance. A user defines Prometheus alerting and recording Rules via a Kubernetes Custom Resource Definition. These Custom Resource Definitions can be fully validated by the Kubernetes API server during creation time via automatically generated OpenAPI specifications. Instead of the restriction of a Prometheus instance to only select Rule definitions inside its own namespace, the Prometheus specification is extended to also specify namespaces to look for Rule Custom Resource Definitions outside its own namespace. --- Dependent technical changes: - prometheus: Use github.com/jimmidyson/configmap-reload to reload rules - prometheus: Remove Prometheus Statefulset deletion function. Starting with K8s >=1.8 this is handled via OwnerReferences. - prometheus: Do not add rule files checksum to Prometheus configuration secret - prometheus: Update StatefulSet only on relevant changes. Instead of updating the Prometheus StatefulSet on every `sync()` run, only update it if the input parameters to `makeStatefulSet` change. Enforce this via a checksum of the parameters which is saved inside the annotations of the statefulset. - e2e/prometheus: Check how often resources (Secret, ConfigMap, Prometheus CRD, Service) are updated to enforce that Prometheus Operator only updated created resources if necessary. - contrib/prometheus-config-reloader: Remove logic to retriev K8s ConfigMaps. These are mounted into the pod right away now.
2018-05-08 09:43:45 +02:00
}
}
func makeStatefulSetService(p *monitoringv1.Prometheus, config Config) *v1.Service {
p = p.DeepCopy()
if p.Spec.PortName == "" {
p.Spec.PortName = defaultPortName
}
2016-10-28 16:08:11 +02:00
svc := &v1.Service{
2017-05-11 14:05:39 +02:00
ObjectMeta: metav1.ObjectMeta{
2017-01-18 19:07:22 +01:00
Name: governingServiceName,
OwnerReferences: []metav1.OwnerReference{
metav1.OwnerReference{
Name: p.GetName(),
Kind: p.Kind,
APIVersion: p.APIVersion,
UID: p.GetUID(),
},
},
Labels: config.Labels.Merge(map[string]string{
"operated-prometheus": "true",
}),
2016-10-28 16:08:11 +02:00
},
Spec: v1.ServiceSpec{
ClusterIP: "None",
Ports: []v1.ServicePort{
{
Name: p.Spec.PortName,
2016-10-28 16:08:11 +02:00
Port: 9090,
TargetPort: intstr.FromString(p.Spec.PortName),
2016-10-28 16:08:11 +02:00
},
},
Selector: map[string]string{
2016-11-01 16:50:53 -07:00
"app": "prometheus",
},
2016-10-28 16:08:11 +02:00
},
}
if p.Spec.Thanos != nil {
svc.Spec.Ports = append(svc.Spec.Ports, v1.ServicePort{
Name: "grpc",
Port: 10901,
TargetPort: intstr.FromString("grpc"),
})
}
2016-10-28 16:08:11 +02:00
return svc
}
func makeStatefulSetSpec(p monitoringv1.Prometheus, c *Config, ruleConfigMapNames []string,
version semver.Version) (*appsv1.StatefulSetSpec, error) {
// Prometheus may take quite long to shut down to checkpoint existing data.
// Allow up to 10 minutes for clean termination.
terminationGracePeriod := int64(600)
baseImage := operator.StringValOrDefault(p.Spec.BaseImage, operator.DefaultPrometheusBaseImage)
if p.Spec.Image != nil && strings.TrimSpace(*p.Spec.Image) != "" {
baseImage = *p.Spec.Image
2017-04-18 15:08:11 +02:00
}
prometheusImagePath, err := operator.BuildImagePath(baseImage, p.Spec.Version, p.Spec.Tag, p.Spec.SHA)
if err != nil {
return nil, err
}
promArgs := []string{
"-web.console.templates=/etc/prometheus/consoles",
"-web.console.libraries=/etc/prometheus/console_libraries",
}
2017-04-18 15:08:11 +02:00
switch version.Major {
case 1:
promArgs = append(promArgs,
"-storage.local.retention="+p.Spec.Retention,
"-storage.local.num-fingerprint-mutexes=4096",
fmt.Sprintf("-storage.local.path=%s", storageDir),
2017-04-18 15:08:11 +02:00
"-storage.local.chunk-encoding-version=2",
fmt.Sprintf("-config.file=%s", path.Join(confOutDir, configEnvsubstFilename)),
)
2017-04-18 15:08:11 +02:00
// We attempt to specify decent storage tuning flags based on how much the
// requested memory can fit. The user has to specify an appropriate buffering
// in memory limits to catch increased memory usage during query bursts.
// More info: https://prometheus.io/docs/operating/storage/.
reqMem := p.Spec.Resources.Requests[v1.ResourceMemory]
if version.Minor < 6 {
// 1024 byte is the fixed chunk size. With increasing number of chunks actually
// in memory, overhead owed to their management, higher ingestion buffers, etc.
// increases.
// We are conservative for now an assume this to be 80% as the Kubernetes environment
// generally has a very high time series churn.
memChunks := reqMem.Value() / 1024 / 5
promArgs = append(promArgs,
"-storage.local.memory-chunks="+fmt.Sprintf("%d", memChunks),
"-storage.local.max-chunks-to-persist="+fmt.Sprintf("%d", memChunks/2),
)
} else {
// Leave 1/3 head room for other overhead.
promArgs = append(promArgs,
"-storage.local.target-heap-size="+fmt.Sprintf("%d", reqMem.Value()/3*2),
)
}
case 2:
retentionTimeFlag := "-storage.tsdb.retention="
if version.Minor >= 7 {
retentionTimeFlag = "-storage.tsdb.retention.time="
if p.Spec.RetentionSize != "" {
promArgs = append(promArgs,
fmt.Sprintf("-storage.tsdb.retention.size=%s", p.Spec.RetentionSize),
)
}
}
promArgs = append(promArgs,
fmt.Sprintf("-config.file=%s", path.Join(confOutDir, configEnvsubstFilename)),
fmt.Sprintf("-storage.tsdb.path=%s", storageDir),
retentionTimeFlag+p.Spec.Retention,
"-web.enable-lifecycle",
"-storage.tsdb.no-lockfile",
)
if p.Spec.Query != nil && p.Spec.Query.LookbackDelta != nil {
promArgs = append(promArgs,
fmt.Sprintf("-query.lookback-delta=%s", *p.Spec.Query.LookbackDelta),
)
}
if version.Minor >= 4 {
if p.Spec.Rules.Alert.ForOutageTolerance != "" {
promArgs = append(promArgs, "-rules.alert.for-outage-tolerance="+p.Spec.Rules.Alert.ForOutageTolerance)
}
if p.Spec.Rules.Alert.ForGracePeriod != "" {
promArgs = append(promArgs, "-rules.alert.for-grace-period="+p.Spec.Rules.Alert.ForGracePeriod)
}
if p.Spec.Rules.Alert.ResendDelay != "" {
promArgs = append(promArgs, "-rules.alert.resend-delay="+p.Spec.Rules.Alert.ResendDelay)
}
}
if version.Minor >= 5 {
if p.Spec.Query != nil && p.Spec.Query.MaxSamples != nil {
promArgs = append(promArgs,
fmt.Sprintf("-query.max-samples=%d", *p.Spec.Query.MaxSamples),
)
}
}
2017-04-18 15:08:11 +02:00
default:
return nil, errors.Errorf("unsupported Prometheus major version %s", version)
}
if p.Spec.Query != nil {
if p.Spec.Query.MaxConcurrency != nil {
if *p.Spec.Query.MaxConcurrency < 1 {
p.Spec.Query.MaxConcurrency = &defaultMaxConcurrency
}
promArgs = append(promArgs,
fmt.Sprintf("-query.max-concurrency=%d", *p.Spec.Query.MaxConcurrency),
)
}
if p.Spec.Query.Timeout != nil {
promArgs = append(promArgs,
fmt.Sprintf("-query.timeout=%s", *p.Spec.Query.Timeout),
)
}
}
2019-01-17 21:28:30 +05:30
if p.Spec.EnableAdminAPI {
promArgs = append(promArgs, "-web.enable-admin-api")
}
2018-06-22 16:28:47 -05:00
if p.Spec.ExternalURL != "" {
2017-04-18 15:08:11 +02:00
promArgs = append(promArgs, "-web.external-url="+p.Spec.ExternalURL)
}
webRoutePrefix := "/"
2017-01-27 14:38:31 +01:00
if p.Spec.RoutePrefix != "" {
webRoutePrefix = p.Spec.RoutePrefix
}
promArgs = append(promArgs, "-web.route-prefix="+webRoutePrefix)
2017-01-27 14:38:31 +01:00
if p.Spec.LogLevel != "" && p.Spec.LogLevel != "info" {
promArgs = append(promArgs, fmt.Sprintf("-log.level=%s", p.Spec.LogLevel))
}
if version.GTE(semver.MustParse("2.6.0")) {
if p.Spec.LogFormat != "" && p.Spec.LogFormat != "logfmt" {
promArgs = append(promArgs, fmt.Sprintf("-log.format=%s", p.Spec.LogFormat))
}
}
if version.GTE(semver.MustParse("2.11.0")) && p.Spec.WALCompression != nil {
if *p.Spec.WALCompression {
promArgs = append(promArgs, "-storage.tsdb.wal-compression")
} else {
promArgs = append(promArgs, "-no-storage.tsdb.wal-compression")
}
}
if version.GTE(semver.MustParse("2.8.0")) && p.Spec.AllowOverlappingBlocks {
promArgs = append(promArgs, "-storage.tsdb.allow-overlapping-blocks")
}
var ports []v1.ContainerPort
if p.Spec.ListenLocal {
promArgs = append(promArgs, "-web.listen-address=127.0.0.1:9090")
} else {
ports = []v1.ContainerPort{
{
Name: p.Spec.PortName,
ContainerPort: 9090,
Protocol: v1.ProtocolTCP,
},
}
}
2017-06-22 14:58:01 +02:00
if version.Major == 2 {
for i, a := range promArgs {
promArgs[i] = "-" + a
}
}
localReloadURL := &url.URL{
Scheme: "http",
Host: c.LocalHost + ":9090",
Path: path.Clean(webRoutePrefix + "/-/reload"),
}
volumes := []v1.Volume{
{
Name: "config",
VolumeSource: v1.VolumeSource{
Secret: &v1.SecretVolumeSource{
SecretName: configSecretName(p.Name),
},
},
},
pkg/prometheus: Enable users to configure bearer token from secret To configure a bearer token users could only specify a file path in the service monitor, pointing to a bearer token file in the Prometheus container. This enables hostile users, being able to configure a service monitor and controlling the scrape target, to retrieve arbitrary files in the Prometheus container. In cases where users can not be trusted, this patch adds an option to disallow the above file path specification and replaces it by a secret reference. This secret has to be in the same namespace as the service monitor, shrinking the attack vector. pkg/prometheus: Add option to deny file system access through service monitors ArbitraryFSAccessThroughSMsConfig enables users to configure, whether a service monitor selected by the Prometheus instance is allowed to use arbitrary files on the file system of the Prometheus container. This is the case when e.g. a service monitor specifies a BearerTokenFile in an endpoint. A malicious user could create a service monitor selecting arbitrary secret files in the Prometheus container. Those secrets would then be send with a scrape request by Prometheus to a malicious target. Denying the above would prevent the attack, users can instead use the BearerTokenSecret field. test/basic-auth-test-app: Add mTLS endpoint pkg/prometheus: Enable users to configure tls from secret pkg/prometheus/operator: Validate TLS configs before retrieving assets Before retrieving TLS assets from Kubernetes secrets for a given service monitor, make sure the user did not specify both file and secret reference, e.g. both `CAFile` and `CASecret`. test: Rename basic-auth-test-app to instrumented-sample-app Given that the basic-auth-test-app not only supports basic auth, but also bearer token as well as tls authentication, this patch renames the app to a more generic name. test/e2e/prometheus_test: Test ArbitraryFSAccessThroughSM option for tls The Prometheus custom resource has the option to disable arbitrary filesystem access configured through service monitors. This commit adds an end-to-end test for this option in combination with the TLS configuration via files or secret references in service monitors. pkg/prometheus/operator: Move check for arbitrary fs access into func
2019-03-18 15:56:38 +01:00
{
Name: "tls-assets",
VolumeSource: v1.VolumeSource{
Secret: &v1.SecretVolumeSource{
SecretName: tlsAssetsSecretName(p.Name),
},
},
},
{
Name: "config-out",
VolumeSource: v1.VolumeSource{
EmptyDir: &v1.EmptyDirVolumeSource{},
},
},
}
for _, name := range ruleConfigMapNames {
volumes = append(volumes, v1.Volume{
Name: name,
prometheus: Introduce RuleFile Custom Resource Definition This patch introduces a new Custom Resource Definition to the Prometheus Operator - the Rule CRD. It addresses two main needs: 1. Prometheus (alerting and recording) Rule validation during creation time via Kubernetes Custom Resource Definition validation. 2. Life-cycle management of Prometheus application Rules alongside the application itself, inside the applications Kubernetes namespace, not necessarily the namespace of the scraping Prometheus instance. A user defines Prometheus alerting and recording Rules via a Kubernetes Custom Resource Definition. These Custom Resource Definitions can be fully validated by the Kubernetes API server during creation time via automatically generated OpenAPI specifications. Instead of the restriction of a Prometheus instance to only select Rule definitions inside its own namespace, the Prometheus specification is extended to also specify namespaces to look for Rule Custom Resource Definitions outside its own namespace. --- Dependent technical changes: - prometheus: Use github.com/jimmidyson/configmap-reload to reload rules - prometheus: Remove Prometheus Statefulset deletion function. Starting with K8s >=1.8 this is handled via OwnerReferences. - prometheus: Do not add rule files checksum to Prometheus configuration secret - prometheus: Update StatefulSet only on relevant changes. Instead of updating the Prometheus StatefulSet on every `sync()` run, only update it if the input parameters to `makeStatefulSet` change. Enforce this via a checksum of the parameters which is saved inside the annotations of the statefulset. - e2e/prometheus: Check how often resources (Secret, ConfigMap, Prometheus CRD, Service) are updated to enforce that Prometheus Operator only updated created resources if necessary. - contrib/prometheus-config-reloader: Remove logic to retriev K8s ConfigMaps. These are mounted into the pod right away now.
2018-05-08 09:43:45 +02:00
VolumeSource: v1.VolumeSource{
ConfigMap: &v1.ConfigMapVolumeSource{
LocalObjectReference: v1.LocalObjectReference{
Name: name,
prometheus: Introduce RuleFile Custom Resource Definition This patch introduces a new Custom Resource Definition to the Prometheus Operator - the Rule CRD. It addresses two main needs: 1. Prometheus (alerting and recording) Rule validation during creation time via Kubernetes Custom Resource Definition validation. 2. Life-cycle management of Prometheus application Rules alongside the application itself, inside the applications Kubernetes namespace, not necessarily the namespace of the scraping Prometheus instance. A user defines Prometheus alerting and recording Rules via a Kubernetes Custom Resource Definition. These Custom Resource Definitions can be fully validated by the Kubernetes API server during creation time via automatically generated OpenAPI specifications. Instead of the restriction of a Prometheus instance to only select Rule definitions inside its own namespace, the Prometheus specification is extended to also specify namespaces to look for Rule Custom Resource Definitions outside its own namespace. --- Dependent technical changes: - prometheus: Use github.com/jimmidyson/configmap-reload to reload rules - prometheus: Remove Prometheus Statefulset deletion function. Starting with K8s >=1.8 this is handled via OwnerReferences. - prometheus: Do not add rule files checksum to Prometheus configuration secret - prometheus: Update StatefulSet only on relevant changes. Instead of updating the Prometheus StatefulSet on every `sync()` run, only update it if the input parameters to `makeStatefulSet` change. Enforce this via a checksum of the parameters which is saved inside the annotations of the statefulset. - e2e/prometheus: Check how often resources (Secret, ConfigMap, Prometheus CRD, Service) are updated to enforce that Prometheus Operator only updated created resources if necessary. - contrib/prometheus-config-reloader: Remove logic to retriev K8s ConfigMaps. These are mounted into the pod right away now.
2018-05-08 09:43:45 +02:00
},
},
},
})
}
volName := volumeName(p.Name)
if p.Spec.Storage != nil {
if p.Spec.Storage.VolumeClaimTemplate.Name != "" {
volName = p.Spec.Storage.VolumeClaimTemplate.Name
}
}
promVolumeMounts := []v1.VolumeMount{
{
Name: "config-out",
ReadOnly: true,
MountPath: confOutDir,
},
pkg/prometheus: Enable users to configure bearer token from secret To configure a bearer token users could only specify a file path in the service monitor, pointing to a bearer token file in the Prometheus container. This enables hostile users, being able to configure a service monitor and controlling the scrape target, to retrieve arbitrary files in the Prometheus container. In cases where users can not be trusted, this patch adds an option to disallow the above file path specification and replaces it by a secret reference. This secret has to be in the same namespace as the service monitor, shrinking the attack vector. pkg/prometheus: Add option to deny file system access through service monitors ArbitraryFSAccessThroughSMsConfig enables users to configure, whether a service monitor selected by the Prometheus instance is allowed to use arbitrary files on the file system of the Prometheus container. This is the case when e.g. a service monitor specifies a BearerTokenFile in an endpoint. A malicious user could create a service monitor selecting arbitrary secret files in the Prometheus container. Those secrets would then be send with a scrape request by Prometheus to a malicious target. Denying the above would prevent the attack, users can instead use the BearerTokenSecret field. test/basic-auth-test-app: Add mTLS endpoint pkg/prometheus: Enable users to configure tls from secret pkg/prometheus/operator: Validate TLS configs before retrieving assets Before retrieving TLS assets from Kubernetes secrets for a given service monitor, make sure the user did not specify both file and secret reference, e.g. both `CAFile` and `CASecret`. test: Rename basic-auth-test-app to instrumented-sample-app Given that the basic-auth-test-app not only supports basic auth, but also bearer token as well as tls authentication, this patch renames the app to a more generic name. test/e2e/prometheus_test: Test ArbitraryFSAccessThroughSM option for tls The Prometheus custom resource has the option to disable arbitrary filesystem access configured through service monitors. This commit adds an end-to-end test for this option in combination with the TLS configuration via files or secret references in service monitors. pkg/prometheus/operator: Move check for arbitrary fs access into func
2019-03-18 15:56:38 +01:00
{
Name: "tls-assets",
ReadOnly: true,
MountPath: tlsAssetsDir,
},
{
Name: volName,
MountPath: storageDir,
SubPath: subPathForStorage(p.Spec.Storage),
},
}
promVolumeMounts = append(promVolumeMounts, p.Spec.VolumeMounts...)
for _, name := range ruleConfigMapNames {
promVolumeMounts = append(promVolumeMounts, v1.VolumeMount{
Name: name,
MountPath: rulesDir + "/" + name,
})
}
for _, s := range p.Spec.Secrets {
volumes = append(volumes, v1.Volume{
Name: k8sutil.SanitizeVolumeName("secret-" + s),
VolumeSource: v1.VolumeSource{
Secret: &v1.SecretVolumeSource{
SecretName: s,
},
},
})
promVolumeMounts = append(promVolumeMounts, v1.VolumeMount{
Name: k8sutil.SanitizeVolumeName("secret-" + s),
ReadOnly: true,
MountPath: secretsDir + s,
})
}
for _, c := range p.Spec.ConfigMaps {
volumes = append(volumes, v1.Volume{
Name: k8sutil.SanitizeVolumeName("configmap-" + c),
VolumeSource: v1.VolumeSource{
ConfigMap: &v1.ConfigMapVolumeSource{
LocalObjectReference: v1.LocalObjectReference{
Name: c,
},
},
},
})
promVolumeMounts = append(promVolumeMounts, v1.VolumeMount{
Name: k8sutil.SanitizeVolumeName("configmap-" + c),
ReadOnly: true,
MountPath: configmapsDir + c,
})
}
configReloadVolumeMounts := []v1.VolumeMount{
{
Name: "config",
MountPath: confDir,
},
{
Name: "config-out",
MountPath: confOutDir,
},
}
configReloadArgs := []string{
fmt.Sprintf("--log-format=%s", c.LogFormat),
fmt.Sprintf("--reload-url=%s", localReloadURL),
fmt.Sprintf("--config-file=%s", path.Join(confDir, configFilename)),
fmt.Sprintf("--config-envsubst-file=%s", path.Join(confOutDir, configEnvsubstFilename)),
}
const localProbe = `if [ -x "$(command -v curl)" ]; then curl %s; elif [ -x "$(command -v wget)" ]; then wget -q -O /dev/null %s; else exit 1; fi`
2017-10-07 01:05:16 -04:00
var readinessProbeHandler v1.Handler
if (version.Major == 1 && version.Minor >= 8) || version.Major == 2 {
{
healthyPath := path.Clean(webRoutePrefix + "/-/healthy")
if p.Spec.ListenLocal {
localHealthyPath := fmt.Sprintf("http://localhost:9090%s", healthyPath)
readinessProbeHandler.Exec = &v1.ExecAction{
Command: []string{
"sh",
"-c",
fmt.Sprintf(localProbe, localHealthyPath, localHealthyPath),
},
}
} else {
readinessProbeHandler.HTTPGet = &v1.HTTPGetAction{
Path: healthyPath,
Port: intstr.FromString(p.Spec.PortName),
}
}
2017-10-07 01:05:16 -04:00
}
{
readyPath := path.Clean(webRoutePrefix + "/-/ready")
if p.Spec.ListenLocal {
localReadyPath := fmt.Sprintf("http://localhost:9090%s", readyPath)
readinessProbeHandler.Exec = &v1.ExecAction{
Command: []string{
"sh",
"-c",
fmt.Sprintf(localProbe, localReadyPath, localReadyPath),
},
}
} else {
readinessProbeHandler.HTTPGet = &v1.HTTPGetAction{
Path: readyPath,
Port: intstr.FromString(p.Spec.PortName),
}
}
2017-10-07 01:05:16 -04:00
}
2017-10-07 01:05:16 -04:00
} else {
readinessProbeHandler = v1.Handler{
2017-10-07 01:05:16 -04:00
HTTPGet: &v1.HTTPGetAction{
Path: path.Clean(webRoutePrefix + "/status"),
Port: intstr.FromString(p.Spec.PortName),
2017-10-07 01:05:16 -04:00
},
}
2017-04-24 12:45:30 +02:00
}
2017-10-07 01:05:16 -04:00
// TODO(paulfantom): Re-add livenessProbe and add startupProbe when kubernetes 1.21 is available.
// This would be a follow-up to https://github.com/prometheus-operator/prometheus-operator/pull/3502
readinessProbe := &v1.Probe{
Handler: readinessProbeHandler,
TimeoutSeconds: probeTimeoutSeconds,
PeriodSeconds: 5,
FailureThreshold: 120, // Allow up to 10m on startup for data recovery
}
podAnnotations := map[string]string{}
podLabels := map[string]string{}
podSelectorLabels := map[string]string{
"app": "prometheus",
"prometheus": p.Name,
}
2017-09-15 15:28:16 +02:00
if p.Spec.PodMetadata != nil {
if p.Spec.PodMetadata.Labels != nil {
for k, v := range p.Spec.PodMetadata.Labels {
podLabels[k] = v
}
}
if p.Spec.PodMetadata.Annotations != nil {
for k, v := range p.Spec.PodMetadata.Annotations {
podAnnotations[k] = v
}
}
}
for k, v := range podSelectorLabels {
podLabels[k] = v
}
2018-03-09 15:12:59 +01:00
finalSelectorLabels := c.Labels.Merge(podSelectorLabels)
2018-03-22 13:03:37 +01:00
finalLabels := c.Labels.Merge(podLabels)
var additionalContainers []v1.Container
2018-06-14 18:47:15 +02:00
if len(ruleConfigMapNames) != 0 {
container := v1.Container{
Name: "rules-configmap-reloader",
Image: c.ConfigReloaderImage,
Args: []string{
fmt.Sprintf("--webhook-url=%s", localReloadURL),
},
VolumeMounts: []v1.VolumeMount{},
Resources: v1.ResourceRequirements{
Limits: v1.ResourceList{}, Requests: v1.ResourceList{}},
TerminationMessagePolicy: v1.TerminationMessageFallbackToLogsOnError,
2019-04-16 15:33:21 +02:00
}
if c.ConfigReloaderCPU != "0" {
container.Resources.Limits[v1.ResourceCPU] = resource.MustParse(c.ConfigReloaderCPU)
container.Resources.Requests[v1.ResourceCPU] = resource.MustParse(c.ConfigReloaderCPU)
2019-04-16 15:33:21 +02:00
}
if c.ConfigReloaderMemory != "0" {
container.Resources.Limits[v1.ResourceMemory] = resource.MustParse(c.ConfigReloaderMemory)
container.Resources.Requests[v1.ResourceMemory] = resource.MustParse(c.ConfigReloaderMemory)
}
for _, name := range ruleConfigMapNames {
mountPath := rulesDir + "/" + name
container.VolumeMounts = append(container.VolumeMounts, v1.VolumeMount{
Name: name,
MountPath: mountPath,
})
container.Args = append(container.Args, fmt.Sprintf("--volume-dir=%s", mountPath))
}
additionalContainers = append(additionalContainers, container)
}
disableCompaction := p.Spec.DisableCompaction
2018-06-14 18:47:15 +02:00
if p.Spec.Thanos != nil {
thBaseImage := operator.StringPtrValOrDefault(p.Spec.Thanos.BaseImage, operator.DefaultThanosBaseImage)
thVersion := operator.StringPtrValOrDefault(p.Spec.Thanos.Version, operator.DefaultThanosVersion)
thTag := operator.StringPtrValOrDefault(p.Spec.Thanos.Tag, "")
thSHA := operator.StringPtrValOrDefault(p.Spec.Thanos.SHA, "")
thanosImage, err := operator.BuildImagePath(thBaseImage, thVersion, thTag, thSHA)
if err != nil {
return nil, errors.Wrap(err, "failed to build image path")
}
// If the image path is set in the custom resource, override other image settings.
if p.Spec.Thanos.Image != nil && strings.TrimSpace(*p.Spec.Thanos.Image) != "" {
thanosImage = *p.Spec.Thanos.Image
}
bindAddress := "[$(POD_IP)]"
if p.Spec.Thanos.ListenLocal {
bindAddress = "127.0.0.1"
}
thanosArgs := []string{"sidecar",
fmt.Sprintf("--prometheus.url=http://%s:9090%s", c.LocalHost, path.Clean(webRoutePrefix)),
fmt.Sprintf("--grpc-address=%s:10901", bindAddress),
fmt.Sprintf("--http-address=%s:10902", bindAddress),
}
if p.Spec.Thanos.GRPCServerTLSConfig != nil {
tls := p.Spec.Thanos.GRPCServerTLSConfig
if tls.CertFile != "" {
thanosArgs = append(thanosArgs, "--grpc-server-tls-cert="+tls.CertFile)
}
if tls.KeyFile != "" {
thanosArgs = append(thanosArgs, "--grpc-server-tls-key="+tls.KeyFile)
}
if tls.CAFile != "" {
thanosArgs = append(thanosArgs, "--grpc-server-tls-client-ca="+tls.CAFile)
}
}
container := v1.Container{
Name: "thanos-sidecar",
Image: thanosImage,
TerminationMessagePolicy: v1.TerminationMessageFallbackToLogsOnError,
Args: thanosArgs,
Env: []v1.EnvVar{
{
Name: "POD_IP",
ValueFrom: &v1.EnvVarSource{
FieldRef: &v1.ObjectFieldSelector{
FieldPath: "status.podIP",
},
},
},
},
Ports: []v1.ContainerPort{
{
Name: "http",
ContainerPort: 10902,
},
{
Name: "grpc",
ContainerPort: 10901,
},
},
Resources: p.Spec.Thanos.Resources,
}
if p.Spec.Thanos.ObjectStorageConfig != nil {
container.Args = append(container.Args, "--objstore.config=$(OBJSTORE_CONFIG)")
container.Env = append(container.Env, v1.EnvVar{
Name: "OBJSTORE_CONFIG",
ValueFrom: &v1.EnvVarSource{
SecretKeyRef: p.Spec.Thanos.ObjectStorageConfig,
},
})
container.Args = append(container.Args, fmt.Sprintf("--tsdb.path=%s", storageDir))
container.VolumeMounts = append(
container.VolumeMounts,
v1.VolumeMount{
Name: volName,
MountPath: storageDir,
SubPath: subPathForStorage(p.Spec.Storage),
},
)
// NOTE(bwplotka): As described in https://thanos.io/components/sidecar.md/ we have to turn off compaction of Prometheus
// to avoid races during upload, if the uploads are configured.
disableCompaction = true
}
if p.Spec.Thanos.TracingConfig != nil {
container.Args = append(container.Args, "--tracing.config=$(TRACING_CONFIG)")
container.Env = append(container.Env, v1.EnvVar{
Name: "TRACING_CONFIG",
ValueFrom: &v1.EnvVarSource{
SecretKeyRef: p.Spec.Thanos.TracingConfig,
},
})
}
if p.Spec.Thanos.LogLevel != "" {
container.Args = append(container.Args, "--log.level="+p.Spec.Thanos.LogLevel)
} else if p.Spec.LogLevel != "" {
container.Args = append(container.Args, "--log.level="+p.Spec.LogLevel)
2018-06-14 18:47:15 +02:00
}
if p.Spec.Thanos.LogFormat != "" {
container.Args = append(container.Args, "--log.format="+p.Spec.Thanos.LogFormat)
} else if p.Spec.LogFormat != "" {
container.Args = append(container.Args, "--log.format="+p.Spec.LogFormat)
2018-06-14 18:47:15 +02:00
}
2020-05-28 12:27:59 -07:00
if p.Spec.Thanos.MinTime != "" {
container.Args = append(container.Args, "--min-time="+p.Spec.Thanos.MinTime)
}
additionalContainers = append(additionalContainers, container)
2018-06-14 18:47:15 +02:00
}
if disableCompaction {
promArgs = append(promArgs, "--storage.tsdb.max-block-duration=2h")
}
2018-06-14 18:47:15 +02:00
prometheusConfigReloaderResources := v1.ResourceRequirements{
Limits: v1.ResourceList{}, Requests: v1.ResourceList{}}
2019-04-16 15:33:21 +02:00
if c.ConfigReloaderCPU != "0" {
prometheusConfigReloaderResources.Limits[v1.ResourceCPU] = resource.MustParse(c.ConfigReloaderCPU)
prometheusConfigReloaderResources.Requests[v1.ResourceCPU] = resource.MustParse(c.ConfigReloaderCPU)
2019-04-16 15:33:21 +02:00
}
if c.ConfigReloaderMemory != "0" {
prometheusConfigReloaderResources.Limits[v1.ResourceMemory] = resource.MustParse(c.ConfigReloaderMemory)
prometheusConfigReloaderResources.Requests[v1.ResourceMemory] = resource.MustParse(c.ConfigReloaderMemory)
2019-04-16 15:33:21 +02:00
}
operatorContainers := append([]v1.Container{
{
Name: "prometheus",
Image: prometheusImagePath,
Ports: ports,
Args: promArgs,
VolumeMounts: promVolumeMounts,
ReadinessProbe: readinessProbe,
Resources: p.Spec.Resources,
TerminationMessagePolicy: v1.TerminationMessageFallbackToLogsOnError,
}, {
Name: "prometheus-config-reloader",
Image: c.PrometheusConfigReloaderImage,
TerminationMessagePolicy: v1.TerminationMessageFallbackToLogsOnError,
Env: []v1.EnvVar{
{
Name: "POD_NAME",
ValueFrom: &v1.EnvVarSource{
FieldRef: &v1.ObjectFieldSelector{FieldPath: "metadata.name"},
},
},
},
Command: []string{"/bin/prometheus-config-reloader"},
Args: configReloadArgs,
VolumeMounts: configReloadVolumeMounts,
Resources: prometheusConfigReloaderResources,
},
}, additionalContainers...)
containers, err := k8sutil.MergePatchContainers(operatorContainers, p.Spec.Containers)
if err != nil {
return nil, errors.Wrap(err, "failed to merge containers spec")
}
// PodManagementPolicy is set to Parallel to mitigate issues in kubernetes: https://github.com/kubernetes/kubernetes/issues/60164
// This is also mentioned as one of limitations of StatefulSets: https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/#limitations
2018-03-09 15:12:59 +01:00
return &appsv1.StatefulSetSpec{
ServiceName: governingServiceName,
Replicas: p.Spec.Replicas,
2018-03-09 15:12:59 +01:00
PodManagementPolicy: appsv1.ParallelPodManagement,
UpdateStrategy: appsv1.StatefulSetUpdateStrategy{
Type: appsv1.RollingUpdateStatefulSetStrategyType,
},
2018-03-22 13:03:37 +01:00
Selector: &metav1.LabelSelector{
MatchLabels: finalSelectorLabels,
2018-03-22 13:03:37 +01:00
},
Template: v1.PodTemplateSpec{
2017-05-11 14:05:39 +02:00
ObjectMeta: metav1.ObjectMeta{
2018-03-22 13:03:37 +01:00
Labels: finalLabels,
Annotations: podAnnotations,
},
Spec: v1.PodSpec{
Containers: containers,
InitContainers: p.Spec.InitContainers,
2020-02-20 17:09:01 -06:00
SecurityContext: p.Spec.SecurityContext,
ServiceAccountName: p.Spec.ServiceAccountName,
2017-01-18 12:14:47 -06:00
NodeSelector: p.Spec.NodeSelector,
PriorityClassName: p.Spec.PriorityClassName,
TerminationGracePeriodSeconds: &terminationGracePeriod,
Volumes: volumes,
Tolerations: p.Spec.Tolerations,
Affinity: p.Spec.Affinity,
2016-09-22 15:25:57 +02:00
},
},
2017-04-18 15:08:11 +02:00
}, nil
2016-09-22 15:25:57 +02:00
}
2016-12-22 14:43:21 +01:00
func configSecretName(name string) string {
return prefixedName(name)
pkg/prometheus: Enable users to configure bearer token from secret To configure a bearer token users could only specify a file path in the service monitor, pointing to a bearer token file in the Prometheus container. This enables hostile users, being able to configure a service monitor and controlling the scrape target, to retrieve arbitrary files in the Prometheus container. In cases where users can not be trusted, this patch adds an option to disallow the above file path specification and replaces it by a secret reference. This secret has to be in the same namespace as the service monitor, shrinking the attack vector. pkg/prometheus: Add option to deny file system access through service monitors ArbitraryFSAccessThroughSMsConfig enables users to configure, whether a service monitor selected by the Prometheus instance is allowed to use arbitrary files on the file system of the Prometheus container. This is the case when e.g. a service monitor specifies a BearerTokenFile in an endpoint. A malicious user could create a service monitor selecting arbitrary secret files in the Prometheus container. Those secrets would then be send with a scrape request by Prometheus to a malicious target. Denying the above would prevent the attack, users can instead use the BearerTokenSecret field. test/basic-auth-test-app: Add mTLS endpoint pkg/prometheus: Enable users to configure tls from secret pkg/prometheus/operator: Validate TLS configs before retrieving assets Before retrieving TLS assets from Kubernetes secrets for a given service monitor, make sure the user did not specify both file and secret reference, e.g. both `CAFile` and `CASecret`. test: Rename basic-auth-test-app to instrumented-sample-app Given that the basic-auth-test-app not only supports basic auth, but also bearer token as well as tls authentication, this patch renames the app to a more generic name. test/e2e/prometheus_test: Test ArbitraryFSAccessThroughSM option for tls The Prometheus custom resource has the option to disable arbitrary filesystem access configured through service monitors. This commit adds an end-to-end test for this option in combination with the TLS configuration via files or secret references in service monitors. pkg/prometheus/operator: Move check for arbitrary fs access into func
2019-03-18 15:56:38 +01:00
}
func tlsAssetsSecretName(name string) string {
return fmt.Sprintf("%s-tls-assets", prefixedName(name))
2017-01-18 19:07:22 +01:00
}
func volumeName(name string) string {
return fmt.Sprintf("%s-db", prefixedName(name))
}
func prefixedName(name string) string {
return fmt.Sprintf("prometheus-%s", name)
}
func subPathForStorage(s *monitoringv1.StorageSpec) string {
2016-12-22 14:43:21 +01:00
if s == nil {
return ""
}
if s.DisableMountSubPath {
return ""
}
2016-12-22 14:43:21 +01:00
return "prometheus-db"
}