mirror of
https://github.com/prometheus-operator/prometheus-operator.git
synced 2025-04-21 11:48:53 +00:00
*: default -route-prefix to root
Whenever serving Prometheus or Alertmanager through non root ExternalURLs we require the reverse proxy to trim the URL to be to the root Prometheus/Alertmanager.
This commit is contained in:
parent
6e664fdd78
commit
a0761a3079
10 changed files with 73 additions and 42 deletions
Documentation
contrib/kube-prometheus/manifests/alertmanager
pkg
test/e2e
|
@ -53,7 +53,8 @@ Specification of the desired behavior of the Alertmanager cluster. More info: ht
|
|||
| imagePullSecrets | An optional list of references to secrets in the same namespace to use for pulling prometheus and alertmanager images from registries see http://kubernetes.io/docs/user-guide/images#specifying-imagepullsecrets-on-a-pod | [][v1.LocalObjectReference](https://kubernetes.io/docs/api-reference/v1.6/#localobjectreference-v1-core) | false |
|
||||
| replicas | Size is the expected size of the alertmanager cluster. The controller will eventually make the size of the running cluster equal to the expected size. | *int32 | false |
|
||||
| storage | Storage is the definition of how storage will be used by the Alertmanager instances. | *[StorageSpec](#storagespec) | false |
|
||||
| externalUrl | ExternalURL is the URL under which Alertmanager is externally reachable (for example, if Alertmanager is served via a reverse proxy). Used for generating relative and absolute links back to Alertmanager itself. If the URL has a path portion, it will be used to prefix all HTTP endpoints served by Alertmanager. If omitted, relevant URL components will be derived automatically. | string | false |
|
||||
| externalUrl | The external URL the Alertmanager instances will be available under. This is necessary to generate correct URLs. This is necessary if Alertmanager is not served from root of a DNS name. | string | false |
|
||||
| routePrefix | The route prefix Alertmanager registers HTTP handlers for. This is useful, if using ExternalURL and a proxy is rewriting HTTP routes of a request, and the actual ExternalURL is still true, but the server serves requests under a different route prefix. For example for use with `kubectl proxy`. | string | false |
|
||||
| paused | If set to true all actions on the underlaying managed objects are not goint to be performed, except for delete actions. | bool | false |
|
||||
| nodeSelector | Define which Nodes the Pods are scheduled on. | map[string]string | false |
|
||||
| resources | Define resources requests and limits for single Pods. | [v1.ResourceRequirements](https://kubernetes.io/docs/api-reference/v1.6/#resourcerequirements-v1-core) | false |
|
||||
|
|
|
@ -432,7 +432,7 @@ metadata:
|
|||
alertmanager: "main"
|
||||
spec:
|
||||
replicas: 3
|
||||
version: v0.6.2
|
||||
version: v0.7.0
|
||||
```
|
||||
|
||||
Read more in the [alerting guide](alerting.md) on how to configure the Alertmanager as it will not spin up unless it has a valid configuration mounted through a `Secret`. Note that the `Secret` has to be in the same namespace as the `Alertmanager` resource as well as have the name `alertmanager-<name-of-alertmanager-object` and the key of the configuration is `alertmanager.yaml`.
|
||||
|
|
|
@ -15,7 +15,7 @@ metadata:
|
|||
name: "main"
|
||||
spec:
|
||||
replicas: 1
|
||||
version: v1.5.0
|
||||
version: v1.7.0
|
||||
resources:
|
||||
requests:
|
||||
memory: 400Mi
|
||||
|
@ -51,7 +51,7 @@ metadata:
|
|||
name: "main"
|
||||
spec:
|
||||
replicas: 3
|
||||
version: v0.6.2
|
||||
version: v0.7.0
|
||||
resources:
|
||||
requests:
|
||||
memory: 400Mi
|
||||
|
@ -115,9 +115,8 @@ metadata:
|
|||
name: "main"
|
||||
spec:
|
||||
replicas: 1
|
||||
version: v1.5.0
|
||||
version: v1.7.0
|
||||
externalUrl: http://127.0.0.1:8001/api/v1/proxy/namespaces/default/services/prometheus-main:web/
|
||||
routePrefix: /
|
||||
resources:
|
||||
requests:
|
||||
memory: 400Mi
|
||||
|
@ -127,7 +126,7 @@ spec:
|
|||
|
||||
Once the Prometheus `Pod`s are running they are reachable under the specified `externalUrl`.
|
||||
|
||||
In contrast, the Alertmanager is able to perform all requests relative to its root when using this approach so the manifest for the `Alertmanager` object is simply the following:
|
||||
The Alertmanager works with the same approach so the manifest for the `Alertmanager` object is simply the following:
|
||||
|
||||
```yaml
|
||||
apiVersion: "monitoring.coreos.com/v1alpha1"
|
||||
|
@ -136,7 +135,8 @@ metadata:
|
|||
name: "main"
|
||||
spec:
|
||||
replicas: 3
|
||||
version: v0.6.2
|
||||
version: v0.7.0
|
||||
externalUrl: http://127.0.0.1:8001/api/v1/proxy/namespaces/default/services/alertmanager-main:web/
|
||||
resources:
|
||||
requests:
|
||||
memory: 400Mi
|
||||
|
@ -219,6 +219,7 @@ metadata:
|
|||
name: monitoring
|
||||
annotations:
|
||||
ingress.kubernetes.io/whitelist-source-range: 10.0.0.0/16 # change this range to admin ips
|
||||
ingress.kubernetes.io/rewrite-target: "/"
|
||||
spec:
|
||||
rules:
|
||||
- http:
|
||||
|
@ -242,7 +243,7 @@ metadata:
|
|||
name: "main"
|
||||
spec:
|
||||
replicas: 1
|
||||
version: v1.5.0
|
||||
version: v1.7.0
|
||||
externalUrl: http://monitoring.my.systems/prometheus
|
||||
resources:
|
||||
requests:
|
||||
|
@ -254,7 +255,7 @@ metadata:
|
|||
name: "main"
|
||||
spec:
|
||||
replicas: 3
|
||||
version: v0.6.2
|
||||
version: v0.7.0
|
||||
externalUrl: http://monitoring.my.systems/alertmanager
|
||||
resources:
|
||||
requests:
|
||||
|
|
|
@ -6,4 +6,4 @@ metadata:
|
|||
alertmanager: "main"
|
||||
spec:
|
||||
replicas: 3
|
||||
version: v0.6.2
|
||||
version: v0.7.0
|
||||
|
|
|
@ -370,12 +370,21 @@ func (c *Operator) sync(key string) error {
|
|||
}
|
||||
|
||||
if !exists {
|
||||
if _, err := ssetClient.Create(makeStatefulSet(am, nil, c.config)); err != nil {
|
||||
sset, err := makeStatefulSet(am, nil, c.config)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "making the statefulset, to create, failed")
|
||||
}
|
||||
if _, err := ssetClient.Create(sset); err != nil {
|
||||
return errors.Wrap(err, "creating statefulset failed")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
if _, err := ssetClient.Update(makeStatefulSet(am, obj.(*v1beta1.StatefulSet), c.config)); err != nil {
|
||||
|
||||
sset, err := makeStatefulSet(am, obj.(*v1beta1.StatefulSet), c.config)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "making the statefulset, to update, failed")
|
||||
}
|
||||
if _, err := ssetClient.Update(sset); err != nil {
|
||||
return errors.Wrap(err, "updating statefulset failed")
|
||||
}
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@ import (
|
|||
"fmt"
|
||||
"net/url"
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/resource"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
@ -25,13 +26,15 @@ import (
|
|||
"k8s.io/client-go/pkg/api/v1"
|
||||
"k8s.io/client-go/pkg/apis/apps/v1beta1"
|
||||
|
||||
"github.com/blang/semver"
|
||||
"github.com/coreos/prometheus-operator/pkg/client/monitoring/v1alpha1"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
const (
|
||||
governingServiceName = "alertmanager-operated"
|
||||
defaultBaseImage = "quay.io/prometheus/alertmanager"
|
||||
defaultVersion = "v0.6.2"
|
||||
defaultVersion = "v0.7.0"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -39,7 +42,7 @@ var (
|
|||
probeTimeoutSeconds int32 = 3
|
||||
)
|
||||
|
||||
func makeStatefulSet(am *v1alpha1.Alertmanager, old *v1beta1.StatefulSet, config Config) *v1beta1.StatefulSet {
|
||||
func makeStatefulSet(am *v1alpha1.Alertmanager, old *v1beta1.StatefulSet, config Config) (*v1beta1.StatefulSet, error) {
|
||||
// TODO(fabxc): is this the right point to inject defaults?
|
||||
// Ideally we would do it before storing but that's currently not possible.
|
||||
// Potentially an update handler on first insertion.
|
||||
|
@ -60,13 +63,17 @@ func makeStatefulSet(am *v1alpha1.Alertmanager, old *v1beta1.StatefulSet, config
|
|||
am.Spec.Resources.Requests[v1.ResourceMemory] = resource.MustParse("200Mi")
|
||||
}
|
||||
|
||||
spec, err := makeStatefulSetSpec(am, config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
statefulset := &v1beta1.StatefulSet{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: prefixedName(am.Name),
|
||||
Labels: am.ObjectMeta.Labels,
|
||||
Annotations: am.ObjectMeta.Annotations,
|
||||
},
|
||||
Spec: makeStatefulSetSpec(am, config),
|
||||
Spec: *spec,
|
||||
}
|
||||
|
||||
if am.Spec.ImagePullSecrets != nil && len(am.Spec.ImagePullSecrets) > 0 {
|
||||
|
@ -102,7 +109,7 @@ func makeStatefulSet(am *v1alpha1.Alertmanager, old *v1beta1.StatefulSet, config
|
|||
if old != nil {
|
||||
statefulset.Annotations = old.Annotations
|
||||
}
|
||||
return statefulset
|
||||
return statefulset, nil
|
||||
}
|
||||
|
||||
func makeStatefulSetService(p *v1alpha1.Alertmanager) *v1.Service {
|
||||
|
@ -137,8 +144,14 @@ func makeStatefulSetService(p *v1alpha1.Alertmanager) *v1.Service {
|
|||
return svc
|
||||
}
|
||||
|
||||
func makeStatefulSetSpec(a *v1alpha1.Alertmanager, config Config) v1beta1.StatefulSetSpec {
|
||||
func makeStatefulSetSpec(a *v1alpha1.Alertmanager, config Config) (*v1beta1.StatefulSetSpec, error) {
|
||||
image := fmt.Sprintf("%s:%s", a.Spec.BaseImage, a.Spec.Version)
|
||||
versionStr := strings.TrimLeft(a.Spec.Version, "v")
|
||||
|
||||
version, err := semver.Parse(versionStr)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "parse version")
|
||||
}
|
||||
|
||||
commands := []string{
|
||||
"/bin/alertmanager",
|
||||
|
@ -148,13 +161,22 @@ func makeStatefulSetSpec(a *v1alpha1.Alertmanager, config Config) v1beta1.Statef
|
|||
fmt.Sprintf("-storage.path=%s", "/etc/alertmanager/data"),
|
||||
}
|
||||
|
||||
webRoutePrefix := ""
|
||||
if a.Spec.ExternalURL != "" {
|
||||
commands = append(commands, "-web.external-url="+a.Spec.ExternalURL)
|
||||
extUrl, err := url.Parse(a.Spec.ExternalURL)
|
||||
if err == nil {
|
||||
webRoutePrefix = extUrl.Path
|
||||
}
|
||||
|
||||
webRoutePrefix := "/"
|
||||
if a.Spec.RoutePrefix != "" {
|
||||
webRoutePrefix = a.Spec.RoutePrefix
|
||||
}
|
||||
|
||||
switch version.Major {
|
||||
case 0:
|
||||
if version.Minor >= 7 {
|
||||
commands = append(commands, "-web.route-prefix="+webRoutePrefix)
|
||||
}
|
||||
default:
|
||||
return nil, errors.Errorf("unsupported Alertmanager major version %s", version)
|
||||
}
|
||||
|
||||
localReloadURL := &url.URL{
|
||||
|
@ -175,7 +197,7 @@ func makeStatefulSetSpec(a *v1alpha1.Alertmanager, config Config) v1beta1.Statef
|
|||
}
|
||||
|
||||
terminationGracePeriod := int64(0)
|
||||
return v1beta1.StatefulSetSpec{
|
||||
return &v1beta1.StatefulSetSpec{
|
||||
ServiceName: governingServiceName,
|
||||
Replicas: a.Spec.Replicas,
|
||||
Template: v1.PodTemplateSpec{
|
||||
|
@ -263,7 +285,7 @@ func makeStatefulSetSpec(a *v1alpha1.Alertmanager, config Config) v1beta1.Statef
|
|||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}, nil
|
||||
}
|
||||
|
||||
func configSecretName(name string) string {
|
||||
|
|
|
@ -269,13 +269,15 @@ type AlertmanagerSpec struct {
|
|||
// Storage is the definition of how storage will be used by the Alertmanager
|
||||
// instances.
|
||||
Storage *StorageSpec `json:"storage,omitempty"`
|
||||
// ExternalURL is the URL under which Alertmanager is externally reachable
|
||||
// (for example, if Alertmanager is served via a reverse proxy). Used for
|
||||
// generating relative and absolute links back to Alertmanager itself. If the
|
||||
// URL has a path portion, it will be used to prefix all HTTP endpoints
|
||||
// served by Alertmanager. If omitted, relevant URL components will be
|
||||
// derived automatically.
|
||||
// The external URL the Alertmanager instances will be available under. This is
|
||||
// necessary to generate correct URLs. This is necessary if Alertmanager is not
|
||||
// served from root of a DNS name.
|
||||
ExternalURL string `json:"externalUrl,omitempty"`
|
||||
// The route prefix Alertmanager registers HTTP handlers for. This is useful,
|
||||
// if using ExternalURL and a proxy is rewriting HTTP routes of a request,
|
||||
// and the actual ExternalURL is still true, but the server serves requests
|
||||
// under a different route prefix. For example for use with `kubectl proxy`.
|
||||
RoutePrefix string `json:"routePrefix,omitempty"`
|
||||
// If set to true all actions on the underlaying managed objects are not
|
||||
// goint to be performed, except for delete actions.
|
||||
Paused bool `json:"paused,omitempty"`
|
||||
|
|
|
@ -319,17 +319,11 @@ func makeStatefulSetSpec(p v1alpha1.Prometheus, c *Config, ruleConfigMaps []*v1.
|
|||
return nil, errors.Errorf("unsupported Prometheus major version %s", version)
|
||||
}
|
||||
|
||||
webRoutePrefix := ""
|
||||
|
||||
if p.Spec.ExternalURL != "" {
|
||||
extUrl, err := url.Parse(p.Spec.ExternalURL)
|
||||
if err != nil {
|
||||
return nil, errors.Errorf("invalid external URL %s", p.Spec.ExternalURL)
|
||||
}
|
||||
webRoutePrefix = extUrl.Path
|
||||
promArgs = append(promArgs, "-web.external-url="+p.Spec.ExternalURL)
|
||||
}
|
||||
|
||||
webRoutePrefix := "/"
|
||||
if p.Spec.RoutePrefix != "" {
|
||||
promArgs = append(promArgs, "-web.route-prefix="+p.Spec.RoutePrefix)
|
||||
webRoutePrefix = p.Spec.RoutePrefix
|
||||
|
|
|
@ -198,7 +198,7 @@ func TestMeshInitialization(t *testing.T) {
|
|||
},
|
||||
Spec: v1alpha1.AlertmanagerSpec{
|
||||
Replicas: &amountAlertmanagers,
|
||||
Version: "master",
|
||||
Version: "v0.7.0",
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -275,7 +275,8 @@ receivers:
|
|||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := framework.WaitForSpecificAlertmanagerConfig(ns, alertmanager.Name, firstConfig); err != nil {
|
||||
firstExpectedConfig := "global:\n resolve_timeout: 6m\n smtp_from: \"\"\n smtp_smarthost: \"\"\n smtp_auth_username: \"\"\n smtp_auth_password: null\n smtp_auth_secret: null\n smtp_auth_identity: \"\"\n smtp_require_tls: true\n slack_api_url: null\n pagerduty_url: https://events.pagerduty.com/generic/2010-04-15/create_event.json\n hipchat_url: https://api.hipchat.com/\n hipchat_auth_token: null\n opsgenie_api_host: https://api.opsgenie.com/\n victorops_api_url: https://alert.victorops.com/integrations/generic/20131114/alert/\nroute:\n receiver: webhook\n group_by:\n - job\n group_wait: 30s\n group_interval: 5m\n repeat_interval: 12h\nreceivers:\n- name: webhook\n webhook_configs:\n - send_resolved: true\n url: http://alertmanagerwh:30500/\ntemplates: []\n"
|
||||
if err := framework.WaitForSpecificAlertmanagerConfig(ns, alertmanager.Name, firstExpectedConfig); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
|
@ -285,7 +286,8 @@ receivers:
|
|||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := framework.WaitForSpecificAlertmanagerConfig(ns, alertmanager.Name, secondConfig); err != nil {
|
||||
secondExpectedConfig := "global:\n resolve_timeout: 5m\n smtp_from: \"\"\n smtp_smarthost: \"\"\n smtp_auth_username: \"\"\n smtp_auth_password: null\n smtp_auth_secret: null\n smtp_auth_identity: \"\"\n smtp_require_tls: true\n slack_api_url: null\n pagerduty_url: https://events.pagerduty.com/generic/2010-04-15/create_event.json\n hipchat_url: https://api.hipchat.com/\n hipchat_auth_token: null\n opsgenie_api_host: https://api.opsgenie.com/\n victorops_api_url: https://alert.victorops.com/integrations/generic/20131114/alert/\nroute:\n receiver: webhook\n group_by:\n - job\n group_wait: 30s\n group_interval: 5m\n repeat_interval: 12h\nreceivers:\n- name: webhook\n webhook_configs:\n - send_resolved: true\n url: http://alertmanagerwh:30500/\ntemplates: []\n"
|
||||
if err := framework.WaitForSpecificAlertmanagerConfig(ns, alertmanager.Name, secondExpectedConfig); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -225,7 +225,7 @@ func (f *Framework) WaitForSpecificAlertmanagerConfig(ns, amName string, expecte
|
|||
return false, err
|
||||
}
|
||||
|
||||
if config.Data.Config == expectedConfig {
|
||||
if config.Data.ConfigYAML == expectedConfig {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
|
@ -239,7 +239,7 @@ type alertmanagerStatus struct {
|
|||
|
||||
type alertmanagerStatusData struct {
|
||||
MeshStatus meshStatus `json:"meshStatus"`
|
||||
Config string `json:"config"`
|
||||
ConfigYAML string `json:"configYAML"`
|
||||
}
|
||||
|
||||
type meshStatus struct {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue