-
-
Save nivekuil/05f507d9e53cf53da6918728ece54b40 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(defn enable-traefik [m port] | |
(into {} | |
(map (fn [[k v]] | |
{k (update-in v [:deploy :labels] assoc | |
(format "traefik.http.services.%s.loadbalancer.server.port" (name k)) port | |
"traefik.enable" "true" | |
"traefik.docker.network" :net/traefik)})) | |
m)) | |
(defn enable-prometheus [m port] | |
(into {} | |
(map (fn [[k v]] | |
{k (update-in v [:deploy :labels] assoc | |
"prometheus.job" k | |
"prometheus.port" port)})) | |
m)) | |
(defn bind-docker-socket [m] | |
(into {} | |
(map (fn [[k v]] | |
{k (update v :volumes conj "/var/run/docker.sock:/var/run/docker.sock:ro")})) | |
m)) | |
(defn flags [& pairs] | |
(mapv (fn [[k v]] (str "--" k "=" v)) (partition 2 pairs))) | |
(defn traefik-with-cloudflare | |
"Use traefik with cloudflare. | |
If .tls=true on routers, then full mode ssl must be used. Otherwise | |
if Cloudflare is proxying unencrypted traffic, the Traefik router | |
must leave off .tls=true. TODO enforce that somehow; rules engine?" | |
[m] | |
(into {} | |
(map (fn [[k v]] | |
{k (-> v | |
(update :command concat | |
(flags | |
"certificatesResolvers.myresolver.acme.dnsChallenge" "true" | |
"certificatesResolvers.myresolver.acme.dnsChallenge.provider" "cloudflare")) | |
(assoc :environment {"CLOUDFLARE_EMAIL" cloudflare-email | |
"CLOUDFLARE_API_KEY" cloudflare-global-api-key}))})) | |
m)) | |
(defn traefik-access-log | |
"" | |
[m] | |
(into {} | |
(map (fn [[k v]] | |
{k (-> v | |
(update :command concat | |
(flags | |
"accesslog" true | |
"accesslog.format" "json" | |
"accesslog.bufferingsize" 10)))})) | |
m)) | |
(def traefik-stack | |
{:stack/name "traefik" | |
:stack/compose | |
{:networks {:net/traefik {:external true}} | |
:services | |
(-> | |
{:ser/traefik | |
{:image "traefik:2.3.2" | |
:command (flags | |
"api.dashboard" true | |
"log.format" "json" | |
"providers.docker" true | |
"providers.docker.swarmMode" true | |
"providers.docker.exposedByDefault" false | |
"providers.docker.endpoint" "unix:///var/run/docker.sock" | |
"entrypoints.web.address" ":80" | |
"entrypoints.websecure.address" ":443" | |
"metrics.prometheus" true) | |
:networks #{:net/traefik} | |
:ports #{;; bind to host, not through swarm, to log the real client IP | |
{:target 80 | |
:published 80 | |
:mode :host} | |
{:target 443 | |
:published 443 | |
:mode :host}} | |
:deploy | |
{:labels | |
{"traefik.http.routers.api.rule" (-> "Host(`%s`) && (PathPrefix(`/api`) || PathPrefix(`/dashboard`))" | |
(format hostname)) | |
"traefik.http.routers.api.service" "api@internal" | |
"traefik.http.routers.api.middlewares" "auth" | |
"traefik.http.routers.api.tls" "true" | |
"traefik.enable" "true" | |
"traefik.http.services.swarm-dummy.loadbalancer.server.port" 42069 | |
"traefik.http.middlewares.auth.basicauth.users" traefik-basicauth-credentials | |
"traefik.http.middlewares.auth.basicauth.headerField" "X-WebAuth-User" ; passed to grafana | |
"traefik.http.middlewares.auth.basicauth.removeheader" "true" ; avoid conflict with grafana | |
} | |
:placement {:constraints ["node.role == manager"]}}}} | |
traefik-access-log | |
traefik-with-cloudflare | |
(enable-prometheus 8080) | |
bind-docker-socket)}}) | |
(def monitoring-stack | |
{:stack/name "monitoring" | |
:stack/compose | |
{:networks {:net/traefik {:external true}} | |
:volumes {:vol/grafana {:external true} | |
:vol/prometheus {:external true}} | |
:services | |
(merge | |
(-> | |
{:ser/prometheus | |
{:image "prom/prometheus:latest" | |
:user "root" ;TODO this is sad https://github.com/prometheus/prometheus/pull/7420 | |
:volumes #{"./prometheus/prometheus.yml:/prometheus.yml" | |
{:type :volume | |
:source :vol/prometheus | |
:target "/prometheus"}} | |
:command ["--config.file=/prometheus.yml"] | |
:networks #{:net/traefik :net/default}}} | |
bind-docker-socket) | |
(-> | |
{:ser/grafana | |
{:image "grafana/grafana:latest" | |
:environment {"GF_SERVER_ROOT_URL" (str "http://" hostname "/grafana") | |
"GF_SERVER_SERVE_FROM_SUB_PATH" 1 | |
"GF_AUTH_PROXY_ENABLED" 1 | |
"GF_AUTH_PROXY_HEADER_NAME" "X-WEBAUTH-USER" | |
"GF_AUTH_PROXY_AUTO_SIGN_UP" 1} | |
:volumes #{{:type :volume | |
:source :vol/grafana | |
:target "/var/lib/grafana"}} | |
:networks #{:net/traefik :net/default} | |
:deploy | |
{:labels {"traefik.http.routers.grafana.rule" (-> "Host(`%s`) && PathPrefix(`/grafana`)" | |
(format hostname)) | |
"traefik.http.routers.grafana.service" :ser/grafana | |
"traefik.http.routers.grafana.tls" "true" | |
"traefik.http.routers.grafana.middlewares" "auth"}}}} | |
(enable-traefik 3000)) | |
(-> | |
{:ser/node-exporter | |
{:image "prom/node-exporter:v1.0.1" | |
:volumes #{"/proc:/host/proc:ro" | |
"/sys:/host/sys:ro" | |
"/:/rootfs:ro"} | |
:command (flags "path.procfs" "/host/proc" | |
"path.sysfs" "/host/sys" | |
"collector.filesystem.ignored-mount-points" "^/(sys|proc|dev|host|etc|rootfs/var/lib/docker/containers|rootfs/var/lib/docker/overlay2|rootfs/run/docker/netns|rootfs/var/lib/docker/aufs)($$|/)") | |
:networks #{:net/default} | |
:deploy {:mode :global}}} | |
(enable-prometheus 9100)) | |
(-> | |
{:ser/cadvisor | |
{:image "gcr.io/google-containers/cadvisor:latest" | |
:volumes #{"/:/rootfs:ro" | |
"/var/run:/var/run:rw" | |
"/sys:/sys:ro" | |
"/var/lib/docker/:/var/lib/docker:ro"} | |
:command ["--docker_only=true"] | |
:networks #{:net/default} | |
:deploy {:mode :global}}} | |
(enable-prometheus 8080)) | |
{:ser/loki | |
{:image "grafana/loki:2.0.0" | |
:command ["-config.file=/etc/loki/loki.yaml"] | |
:networks #{:net/default} | |
:volumes #{"./loki:/etc/loki"}}} | |
(-> {:ser/vector | |
{:image "timberio/vector:latest-alpine" | |
:command ["--watch-config"] | |
:networks #{:net/default} | |
:volumes #{"./vector:/etc/vector:ro"}}} | |
bind-docker-socket))}}) | |
(defn replace-ns [m] | |
(update m :stack/compose | |
(fn [compose] | |
(walk/postwalk #(if (qualified-keyword? %) (name %) %) compose)))) | |
(defn add-version [m] | |
(update m :stack/compose assoc :version compose-file-version)) | |
(def stack-transforms (comp replace-ns add-version)) | |
(def stacks (->> [traefik-stack monitoring-stack] | |
(mapv stack-transforms))) | |
(defn deploy [{:stack/keys [name compose]}] | |
(str "docker stack deploy --compose-file - " name " <<< '" (json/generate-string compose) "'")) | |
(doseq [stack stacks] | |
(spit (str "stack-" (:stack/name stack)) (deploy stack))) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment