1
0
Fork 0
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:
Frederic Branczyk 2017-05-23 12:35:02 +02:00
parent 6e664fdd78
commit a0761a3079
No known key found for this signature in database
GPG key ID: CA14788B1E48B256
10 changed files with 73 additions and 42 deletions
Documentation
contrib/kube-prometheus/manifests/alertmanager
pkg
alertmanager
client/monitoring/v1alpha1
prometheus
test/e2e

View file

@ -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 |

View file

@ -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`.

View file

@ -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:

View file

@ -6,4 +6,4 @@ metadata:
alertmanager: "main"
spec:
replicas: 3
version: v0.6.2
version: v0.7.0

View file

@ -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")
}

View file

@ -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 {

View file

@ -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"`

View file

@ -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

View file

@ -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)
}
}

View file

@ -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 {