diff --git a/docs/config.md b/docs/config.md index b85d1f0..5269b41 100644 --- a/docs/config.md +++ b/docs/config.md @@ -50,4 +50,13 @@ global: scrape_interval: 10s ``` +Nested values can be specified by separating them with `-`. For example, if environment variables `GLOBAL_EXTERNAL_LABELS-CLUSTER=swarm` and `GLOBAL_EXTERNAL_LABELS-TYPE=production` are defined, the resulting Prometheus configuration would be as follows. + +``` +global: + external_labels: + cluster: swarm + type: production +``` + Please consult [Prometheus Configuration](https://prometheus.io/docs/operating/configuration/) for more information about the available options. \ No newline at end of file diff --git a/prometheus/config.go b/prometheus/config.go index e700811..9c80ce5 100644 --- a/prometheus/config.go +++ b/prometheus/config.go @@ -5,14 +5,21 @@ import ( "text/template" "bytes" "github.com/spf13/afero" + "strings" ) func GetGlobalConfig() string { + data := getGlobalConfigData() config := ` global:` - for _, e := range os.Environ() { - if key, value := getArgFromEnv(e, "GLOBAL"); len(key) > 0 { - config = config + "\n " + key + ": " + value + for key, values := range data { + if len(values[""]) > 0 { + config += "\n " + key + ": " + values[""] + } else { + config += "\n " + key + ":" + for subKey, value := range values { + config += "\n " + subKey + ": " + value + } } } return config @@ -50,3 +57,24 @@ func WriteConfig(scrapes map[string]Scrape, alerts map[string]Alert) { LogPrintf("Writing to prometheus.yml") afero.WriteFile(FS, "/etc/prometheus/prometheus.yml", []byte(config), 0644) } + +func getGlobalConfigData() map[string]map[string]string { + data := map[string]map[string]string{} + for _, e := range os.Environ() { + if key, value := getArgFromEnv(e, "GLOBAL"); len(key) > 0 { + realKey := key + subKey := "" + if strings.Contains(key, "-") { + keys := strings.Split(key, "-") + realKey = keys[0] + subKey = keys[1] + } + if _, ok := data[realKey]; !ok { + data[realKey] = map[string]string{} + } + subData := data[realKey] + subData[subKey] = value + } + } + return data +} diff --git a/prometheus/config_test.go b/prometheus/config_test.go index 2ef5331..961e3a8 100644 --- a/prometheus/config_test.go +++ b/prometheus/config_test.go @@ -37,6 +37,27 @@ global: s.Equal(expected, actual) } +func (s *ConfigTestSuite) Test_GlobalConfig_AllowsNestedEntries() { + scrapeIntervalOrig := os.Getenv("GLOBAL_SCRAPE_INTERVAL") + defer func() { + os.Setenv("GLOBAL_SCRAPE_INTERVAL", scrapeIntervalOrig) + os.Unsetenv("GLOBAL_EXTERNAL_LABELS-CLUSTER") + os.Unsetenv("GLOBAL_EXTERNAL_LABELS-TYPE") + }() + os.Setenv("GLOBAL_SCRAPE_INTERVAL", "123s") + os.Setenv("GLOBAL_EXTERNAL_LABELS-CLUSTER", "swarm") + os.Setenv("GLOBAL_EXTERNAL_LABELS-TYPE", "production") + expected := ` +global: + scrape_interval: 123s + external_labels: + cluster: swarm + type: production` + + actual := GetGlobalConfig() + s.Equal(expected, actual) +} + // GetScrapeConfig func (s *ConfigTestSuite) Test_GetScrapeConfig_ReturnsConfigWithData() { diff --git a/scripts/dm-swarm-07.sh b/scripts/dm-swarm-07.sh index 05ac592..c16031b 100755 --- a/scripts/dm-swarm-07.sh +++ b/scripts/dm-swarm-07.sh @@ -37,5 +37,7 @@ docker stack deploy \ exporter docker stack deploy \ - -c stacks/go-demo-alert.yml \ + -c stacks/go-demo-scale.yml \ go-demo + +docker stack deploy -c stacks/jenkins.yml jenkins diff --git a/stacks/alert-manager-slack.yml b/stacks/alert-manager-slack.yml index bea20de..5883018 100644 --- a/stacks/alert-manager-slack.yml +++ b/stacks/alert-manager-slack.yml @@ -3,12 +3,19 @@ version: "3" services: alert-manager: - image: vfarcic/alert-manager:slack + image: prom/alertmanager ports: - 9093:9093 networks: - monitor + secrets: + - alert_manager_config + command: -config.file=/run/secrets/alert_manager_config -storage.path=/alertmanager networks: monitor: external: true + +secrets: + alert_manager_config: + external: true diff --git a/stacks/docker-flow-monitor-slack.yml b/stacks/docker-flow-monitor-slack.yml index a28a401..7a2922a 100644 --- a/stacks/docker-flow-monitor-slack.yml +++ b/stacks/docker-flow-monitor-slack.yml @@ -3,7 +3,7 @@ version: "3.1" services: monitor: - image: vfarcic/docker-flow-monitor:${TAG:-latest} + image: vfarcic/docker-flow-monitor environment: - LISTENER_ADDRESS=swarm-listener - GLOBAL_SCRAPE_INTERVAL=10s diff --git a/stacks/go-demo-alert-info.yml b/stacks/go-demo-alert-info.yml index 0f1e7c5..85ded50 100644 --- a/stacks/go-demo-alert-info.yml +++ b/stacks/go-demo-alert-info.yml @@ -3,7 +3,7 @@ version: '3' services: main: - image: vfarcic/go-demo${TAG} + image: vfarcic/go-demo environment: - DB=db networks: diff --git a/stacks/go-demo-alert-long.yml b/stacks/go-demo-alert-long.yml index 5813584..8b29e28 100644 --- a/stacks/go-demo-alert-long.yml +++ b/stacks/go-demo-alert-long.yml @@ -3,7 +3,7 @@ version: '3' services: main: - image: vfarcic/go-demo${TAG} + image: vfarcic/go-demo environment: - DB=db networks: diff --git a/stacks/go-demo-alert.yml b/stacks/go-demo-alert.yml index ec42ab3..842fc82 100644 --- a/stacks/go-demo-alert.yml +++ b/stacks/go-demo-alert.yml @@ -3,7 +3,7 @@ version: '3' services: main: - image: vfarcic/go-demo${TAG} + image: vfarcic/go-demo environment: - DB=db networks: diff --git a/stacks/go-demo-mem.yml b/stacks/go-demo-mem.yml index b31526f..11f1c71 100644 --- a/stacks/go-demo-mem.yml +++ b/stacks/go-demo-mem.yml @@ -3,7 +3,7 @@ version: '3' services: main: - image: vfarcic/go-demo${TAG} + image: vfarcic/go-demo environment: - DB=db networks: diff --git a/stacks/go-demo-scale.yml b/stacks/go-demo-scale.yml new file mode 100644 index 0000000..da65d5b --- /dev/null +++ b/stacks/go-demo-scale.yml @@ -0,0 +1,45 @@ +version: '3' + +services: + + main: + image: vfarcic/go-demo + environment: + - DB=db + networks: + - proxy + deploy: + replicas: 3 + update_config: + parallelism: 1 + delay: 10s + labels: + - com.df.notify=true + - com.df.distribute=true + - com.df.servicePath=/demo + - com.df.port=8080 + - com.df.alertName=memlimit + - com.df.alertIf=@service_mem_limit:0.8 + - com.df.alertFor=5s + - com.df.scaleMin=2 + - com.df.scaleMax=4 + resources: + reservations: + memory: 5M + limits: + memory: 10M + + db: + image: mongo + networks: + - proxy + deploy: + resources: + reservations: + memory: 40M + limits: + memory: 80M + +networks: + proxy: + external: true \ No newline at end of file diff --git a/stacks/go-demo.yml b/stacks/go-demo.yml index 5af76b7..1e96d36 100644 --- a/stacks/go-demo.yml +++ b/stacks/go-demo.yml @@ -3,7 +3,7 @@ version: '3' services: main: - image: vfarcic/go-demo${TAG} + image: vfarcic/go-demo environment: - DB=db networks: diff --git a/stacks/jenkins.yml b/stacks/jenkins.yml index bfee1c9..ca7a2d6 100644 --- a/stacks/jenkins.yml +++ b/stacks/jenkins.yml @@ -1,15 +1,16 @@ -version: '3' +version: '3.1' services: - main: - image: jenkinsci/jenkins:${TAG:-lts-alpine} + master: + image: vfarcic/jenkins ports: - - "50000:50000" + - 50000:50000 environment: - - JAVA_OPTS="-Djenkins.install.runSetupWizard=false" + - JENKINS_OPTS="--prefix=/jenkins" networks: - proxy + - default deploy: labels: - com.df.notify=true @@ -20,12 +21,31 @@ services: - jenkins-user - jenkins-pass + agent: + image: vfarcic/jenkins-swarm-agent + environment: + - USER_NAME_SECRET=/run/secrets/${JENKINS_USER_SECRET:-jenkins-user} + - PASSWORD_SECRET=/run/secrets/${JENKINS_PASS_SECRET:-jenkins-pass} + - COMMAND_OPTIONS=-master http://master:8080/jenkins -labels 'prod' -executors 4 + networks: + - default + volumes: + - /var/run/docker.sock:/var/run/docker.sock + secrets: + - jenkins-user + - jenkins-pass + deploy: + placement: + constraints: [node.role == manager] + networks: proxy: external: true + default: + external: false secrets: jenkins-user: external: true jenkins-pass: - external: true + external: true \ No newline at end of file