Compare commits

...

7 Commits
0.1.1 ... 0.1.2

Author SHA1 Message Date
Stefan Prodan
71137ba3bb Release 0.1.2 2018-12-06 14:00:12 +07:00
Stefan Prodan
6372c7dfcc Merge pull request #14 from stefanprodan/slack
Add details to Slack messages
2018-12-06 13:53:20 +07:00
Stefan Prodan
4584733f6f Change coverage threshold 2018-12-06 13:48:06 +07:00
Stefan Prodan
03408683c0 Add details to Slack messages
- attach canary analysis metadata to init/start messages
- add rollback reason to failed canary messages
2018-12-06 12:51:02 +07:00
Stefan Prodan
29137ae75b Add Alermanager example 2018-12-06 12:49:41 +07:00
Stefan Prodan
6bf85526d0 Add Slack screens with successful and failed canaries 2018-12-06 12:49:15 +07:00
stefanprodan
9f6a30f43e Bump dev version 2018-11-28 15:08:24 +02:00
17 changed files with 114 additions and 31 deletions

View File

@@ -3,6 +3,6 @@ coverage:
project:
default:
target: auto
threshold: 0.50
threshold: 50
base: auto
patch: off
patch: off

View File

@@ -13,7 +13,8 @@ build:
docker build -t stefanprodan/flagger:$(TAG) . -f Dockerfile
push:
docker push stefanprodan/flagger:$(TAG)
docker tag stefanprodan/flagger:$(TAG) quay.io/stefanprodan/flagger:$(VERSION)
docker push quay.io/stefanprodan/flagger:$(VERSION)
fmt:
gofmt -l -s -w $(SOURCE_DIRS)

View File

@@ -367,7 +367,25 @@ helm upgrade -i flagger flagger/flagger \
Once configured with a Slack incoming webhook, Flagger will post messages when a canary deployment has been initialized,
when a new revision has been detected and if the canary analysis failed or succeeded.
![flagger-slack](https://raw.githubusercontent.com/stefanprodan/flagger/master/docs/screens/slack-notifications.png)
![flagger-slack](https://raw.githubusercontent.com/stefanprodan/flagger/master/docs/screens/slack-canary-success.png)
A canary deployment will be rolled back if the progress deadline exceeded or if the analysis
reached the maximum number of failed checks:
![flagger-slack-errors](https://raw.githubusercontent.com/stefanprodan/flagger/master/docs/screens/slack-canary-failed.png)
Besides Slack, you can use Alertmanager to trigger alerts when a canary deployment failed:
```yaml
- alert: canary_rollback
expr: flagger_canary_status > 1
for: 1m
labels:
severity: warning
annotations:
summary: "Canary failed"
description: "Workload {{ $labels.name }} namespace {{ $labels.namespace }}"
```
### Roadmap

View File

@@ -22,7 +22,7 @@ spec:
serviceAccountName: flagger
containers:
- name: flagger
image: quay.io/stefanprodan/flagger:0.1.1
image: quay.io/stefanprodan/flagger:0.1.2
imagePullPolicy: Always
ports:
- name: http

View File

@@ -1,6 +1,6 @@
apiVersion: v1
name: flagger
version: 0.1.1
appVersion: 0.1.1
version: 0.1.2
appVersion: 0.1.2
description: Flagger is a Kubernetes operator that automates the promotion of canary deployments using Istio routing for traffic shifting and Prometheus metrics for canary analysis.
home: https://github.com/stefanprodan/flagger

View File

@@ -2,7 +2,7 @@
image:
repository: quay.io/stefanprodan/flagger
tag: 0.1.1
tag: 0.1.2
pullPolicy: IfNotPresent
controlLoopInterval: "10s"

View File

@@ -367,7 +367,25 @@ helm upgrade -i flagger flagger/flagger \
Once configured with a Slack incoming webhook, Flagger will post messages when a canary deployment has been initialized,
when a new revision has been detected and if the canary analysis failed or succeeded.
![flagger-slack](https://raw.githubusercontent.com/stefanprodan/flagger/master/docs/screens/slack-notifications.png)
![flagger-slack](https://raw.githubusercontent.com/stefanprodan/flagger/master/docs/screens/slack-canary-success.png)
A canary deployment will be rolled back if the progress deadline exceeded or if the analysis
reached the maximum number of failed checks:
![flagger-slack-errors](https://raw.githubusercontent.com/stefanprodan/flagger/master/docs/screens/slack-canary-failed.png)
Besides Slack, you can use Alertmanager to trigger alerts when a canary deployment failed:
```yaml
- alert: canary_rollback
expr: flagger_canary_status > 1
for: 1m
labels:
severity: warning
annotations:
summary: "Canary failed"
description: "Workload {{ $labels.name }} namespace {{ $labels.namespace }}"
```
### Roadmap

BIN
docs/flagger-0.1.2.tgz Normal file

Binary file not shown.

Binary file not shown.

View File

@@ -1,9 +1,21 @@
apiVersion: v1
entries:
flagger:
- apiVersion: v1
appVersion: 0.1.2
created: 2018-12-06T13:57:50.322474+07:00
description: Flagger is a Kubernetes operator that automates the promotion of
canary deployments using Istio routing for traffic shifting and Prometheus metrics
for canary analysis.
digest: a52bf1bf797d60d3d92f46f84805edbd1ffb7d87504727266f08543532ff5e08
home: https://github.com/stefanprodan/flagger
name: flagger
urls:
- https://stefanprodan.github.io/flagger/flagger-0.1.2.tgz
version: 0.1.2
- apiVersion: v1
appVersion: 0.1.1
created: 2018-11-28T14:53:55.671596+02:00
created: 2018-12-06T13:57:50.322115+07:00
description: Flagger is a Kubernetes operator that automates the promotion of
canary deployments using Istio routing for traffic shifting and Prometheus metrics
for canary analysis.
@@ -15,7 +27,7 @@ entries:
version: 0.1.1
- apiVersion: v1
appVersion: 0.1.0
created: 2018-11-28T14:53:55.670949+02:00
created: 2018-12-06T13:57:50.321509+07:00
description: Flagger is a Kubernetes operator that automates the promotion of
canary deployments using Istio routing for traffic shifting and Prometheus metrics
for canary analysis.
@@ -28,13 +40,13 @@ entries:
grafana:
- apiVersion: v1
appVersion: 5.3.1
created: 2018-11-28T14:53:55.67202+02:00
created: 2018-12-06T13:57:50.323051+07:00
description: A Grafana Helm chart for monitoring progressive deployments powered
by Istio and Flagger
digest: 1ab2d0297f11def3787294d277180742f8a62dabfe577795d1867d5b001cbcd1
digest: 692b7c545214b652374249cc814d37decd8df4f915530e82dff4d9dfa25e8762
home: https://github.com/stefanprodan/flagger
name: grafana
urls:
- https://stefanprodan.github.io/flagger/grafana-0.1.0.tgz
version: 0.1.0
generated: 2018-11-28T14:53:55.670112+02:00
generated: 2018-12-06T13:57:50.320726+07:00

Binary file not shown.

After

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 113 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 114 KiB

View File

@@ -260,12 +260,36 @@ func (c *Controller) recordEventWarningf(r *flaggerv1.Canary, template string, a
c.eventRecorder.Event(r, corev1.EventTypeWarning, "Synced", fmt.Sprintf(template, args...))
}
func (c *Controller) sendNotification(workload string, namespace string, message string, warn bool) {
func (c *Controller) sendNotification(cd *flaggerv1.Canary, message string, metadata bool, warn bool) {
if c.notifier == nil {
return
}
err := c.notifier.Post(workload, namespace, message, warn)
var fields []notifier.SlackField
if metadata {
fields = append(fields,
notifier.SlackField{
Title: "Target",
Value: fmt.Sprintf("%s/%s.%s", cd.Spec.TargetRef.Kind, cd.Spec.TargetRef.Name, cd.Namespace),
},
notifier.SlackField{
Title: "Traffic routing",
Value: fmt.Sprintf("Weight step: %v max: %v",
cd.Spec.CanaryAnalysis.StepWeight,
cd.Spec.CanaryAnalysis.MaxWeight),
},
notifier.SlackField{
Title: "Failed checks threshold",
Value: fmt.Sprintf("%v", cd.Spec.CanaryAnalysis.Threshold),
},
notifier.SlackField{
Title: "Progress deadline",
Value: fmt.Sprintf("%vs", cd.GetProgressDeadlineSeconds()),
},
)
}
err := c.notifier.Post(cd.Name, cd.Namespace, message, fields, warn)
if err != nil {
c.logger.Error(err)
}

View File

@@ -95,11 +95,15 @@ func (c *Controller) advanceCanary(name string, namespace string) {
if cd.Status.FailedChecks >= cd.Spec.CanaryAnalysis.Threshold {
c.recordEventWarningf(cd, "Rolling back %s.%s failed checks threshold reached %v",
cd.Name, cd.Namespace, cd.Status.FailedChecks)
c.sendNotification(cd, fmt.Sprintf("Failed checks threshold reached %v", cd.Status.FailedChecks),
false, true)
}
if !retriable {
c.recordEventWarningf(cd, "Rolling back %s.%s progress deadline exceeded %v",
cd.Name, cd.Namespace, err)
c.sendNotification(cd, fmt.Sprintf("Progress deadline exceeded %v", err),
false, true)
}
// route all traffic back to primary
@@ -112,7 +116,7 @@ func (c *Controller) advanceCanary(name string, namespace string) {
c.recorder.SetWeight(cd, primaryRoute.Weight, canaryRoute.Weight)
c.recordEventWarningf(cd, "Canary failed! Scaling down %s.%s",
cd.Spec.TargetRef.Name, cd.Namespace)
cd.Name, cd.Namespace)
// shutdown canary
if err := c.deployer.Scale(cd, 0); err != nil {
@@ -127,8 +131,6 @@ func (c *Controller) advanceCanary(name string, namespace string) {
}
c.recorder.SetStatus(cd)
c.sendNotification(cd.Spec.TargetRef.Name, cd.Namespace,
"Canary analysis failed, rollback finished.", true)
return
}
@@ -199,8 +201,8 @@ func (c *Controller) advanceCanary(name string, namespace string) {
return
}
c.recorder.SetStatus(cd)
c.sendNotification(cd.Spec.TargetRef.Name, cd.Namespace,
"Canary analysis completed successfully, promotion finished.", false)
c.sendNotification(cd, "Canary analysis completed successfully, promotion finished.",
false, false)
}
}
@@ -217,15 +219,15 @@ func (c *Controller) checkCanaryStatus(cd *flaggerv1.Canary, deployer CanaryDepl
}
c.recorder.SetStatus(cd)
c.recordEventInfof(cd, "Initialization done! %s.%s", cd.Name, cd.Namespace)
c.sendNotification(cd.Spec.TargetRef.Name, cd.Namespace,
"New deployment detected, initialization completed.", false)
c.sendNotification(cd, "New deployment detected, initialization completed.",
true, false)
return false
}
if diff, err := deployer.IsNewSpec(cd); diff {
c.recordEventInfof(cd, "New revision detected! Scaling up %s.%s", cd.Spec.TargetRef.Name, cd.Namespace)
c.sendNotification(cd.Spec.TargetRef.Name, cd.Namespace,
"New revision detected, starting canary analysis.", false)
c.sendNotification(cd, "New revision detected, starting canary analysis.",
true, false)
if err = deployer.Scale(cd, 1); err != nil {
c.recordEventErrorf(cd, "%v", err)
return false

View File

@@ -30,10 +30,17 @@ type SlackPayload struct {
// SlackAttachment holds the markdown message body
type SlackAttachment struct {
Color string `json:"color"`
AuthorName string `json:"author_name"`
Text string `json:"text"`
MrkdwnIn []string `json:"mrkdwn_in"`
Color string `json:"color"`
AuthorName string `json:"author_name"`
Text string `json:"text"`
MrkdwnIn []string `json:"mrkdwn_in"`
Fields []SlackField `json:"fields"`
}
type SlackField struct {
Title string `json:"title"`
Value string `json:"value"`
Short bool `json:"short"`
}
// NewSlack validates the Slack URL and returns a Slack object
@@ -60,7 +67,7 @@ func NewSlack(hookURL string, username string, channel string) (*Slack, error) {
}
// Post Slack message
func (s *Slack) Post(workload string, namespace string, message string, warn bool) error {
func (s *Slack) Post(workload string, namespace string, message string, fields []SlackField, warn bool) error {
payload := SlackPayload{
Channel: s.Channel,
Username: s.Username,
@@ -76,6 +83,7 @@ func (s *Slack) Post(workload string, namespace string, message string, warn boo
AuthorName: fmt.Sprintf("%s.%s", workload, namespace),
Text: message,
MrkdwnIn: []string{"text"},
Fields: fields,
}
payload.Attachments = []SlackAttachment{a}

View File

@@ -1,4 +1,4 @@
package version
var VERSION = "0.1.1"
var VERSION = "0.1.2"
var REVISION = "unknown"