From ab47eee47de1de559a1c7cf35202c6aa7b7ec5c1 Mon Sep 17 00:00:00 2001 From: Steven Johnson Date: Fri, 17 May 2024 19:58:03 +0700 Subject: [PATCH] feat(ci): local custer WIP --- .config/dictionaries/project.dic | 3 +- .vscode/extensions.json | 3 +- .vscode/settings.recommended.json | 5 +- docs/Earthfile | 14 +- utilities/local-cluster/.gitignore | 4 +- utilities/local-cluster/Earthfile | 42 +- utilities/local-cluster/Readme.md | 41 +- utilities/local-cluster/Vagrantfile | 50 +- .../manifests/cat-voices-docs.yml | 40 + .../scripts/check-cluster-dns.py | 57 + utilities/local-cluster/shared/.do_not_remove | 0 utilities/local-cluster/shared/extra.hosts | 10 + .../alert-manager-ingress.yaml | 24 + .../grafana-prometheus/grafana-ingress.yaml | 24 + .../prometheus-ingress.yaml | 24 + .../grafana-prometheus/prometheus-values.yaml | 53 + .../traefik-dashboard-service.yaml | 18 + .../grafana-prometheus/traefik-dashboard.yaml | 1411 +++++++++++++++++ .../traefik-service-monitor.yaml | 20 + .../local-cluster/shared/k3s/registries.yaml | 5 + .../k3s/server/manifests/registry-ui.yaml | 61 + .../traefik-dashboard-helmconfig.yml | 17 + .../manifests/traefik-dashboard-ingress.yaml | 19 + .../manifests/traefik-dashboard-service.yaml | 18 + .../manifests/traefik-dashboard.old.yml | 48 + 25 files changed, 1989 insertions(+), 22 deletions(-) create mode 100644 utilities/local-cluster/manifests/cat-voices-docs.yml create mode 100755 utilities/local-cluster/scripts/check-cluster-dns.py delete mode 100644 utilities/local-cluster/shared/.do_not_remove create mode 100644 utilities/local-cluster/shared/extra.hosts create mode 100644 utilities/local-cluster/shared/k3s/grafana-prometheus/alert-manager-ingress.yaml create mode 100644 utilities/local-cluster/shared/k3s/grafana-prometheus/grafana-ingress.yaml create mode 100644 utilities/local-cluster/shared/k3s/grafana-prometheus/prometheus-ingress.yaml create mode 100644 utilities/local-cluster/shared/k3s/grafana-prometheus/prometheus-values.yaml create mode 100644 utilities/local-cluster/shared/k3s/grafana-prometheus/traefik-dashboard-service.yaml create mode 100644 utilities/local-cluster/shared/k3s/grafana-prometheus/traefik-dashboard.yaml create mode 100644 utilities/local-cluster/shared/k3s/grafana-prometheus/traefik-service-monitor.yaml create mode 100644 utilities/local-cluster/shared/k3s/registries.yaml create mode 100644 utilities/local-cluster/shared/k3s/server/manifests/registry-ui.yaml create mode 100644 utilities/local-cluster/shared/k3s/server/manifests/traefik-dashboard-helmconfig.yml create mode 100644 utilities/local-cluster/shared/k3s/server/manifests/traefik-dashboard-ingress.yaml create mode 100644 utilities/local-cluster/shared/k3s/server/manifests/traefik-dashboard-service.yaml create mode 100644 utilities/local-cluster/shared/k3s/server/manifests/traefik-dashboard.old.yml diff --git a/.config/dictionaries/project.dic b/.config/dictionaries/project.dic index ca89d88213..0dee976188 100644 --- a/.config/dictionaries/project.dic +++ b/.config/dictionaries/project.dic @@ -165,6 +165,7 @@ toastify Toastify tojunit Traceback +traefik TXNZD Typer unmanaged @@ -189,4 +190,4 @@ xcodeproj xctest xctestrun xcworkspace -yoroi \ No newline at end of file +yoroi diff --git a/.vscode/extensions.json b/.vscode/extensions.json index ef5d365a25..ad69134d3c 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -18,6 +18,7 @@ "anweiss.cddl-languageserver", "tintinweb.graphviz-interactive-preview", "terrastruct.d2", - "bbenoist.vagrant" + "bbenoist.vagrant", + "ms-kubernetes-tools.vscode-kubernetes-tools" ] } \ No newline at end of file diff --git a/.vscode/settings.recommended.json b/.vscode/settings.recommended.json index 02dbcf7976..b0ea38a900 100644 --- a/.vscode/settings.recommended.json +++ b/.vscode/settings.recommended.json @@ -86,5 +86,8 @@ "rust-analyzer.rustfmt.extraArgs": [ "+nightly" ], - "rust-analyzer.lens.enable": true + "rust-analyzer.lens.enable": true, + "vs-kubernetes": { + "vs-kubernetes.kubeconfig": "utilities/local-cluster/shared/k3s.yaml" + } } \ No newline at end of file diff --git a/docs/Earthfile b/docs/Earthfile index e8902313bf..53892cf6df 100644 --- a/docs/Earthfile +++ b/docs/Earthfile @@ -28,8 +28,13 @@ docs: DO docs-ci+BUILD -# Make a locally runable container that can serve the docs. +# local : Make a locally runable container that can serve the docs. +# --push will cause this image to be pushed to the local development cluster +# --local_registry : Set this to the hostname of your local registry or "" to inhibit. local: + # Change this to point to another local registry, OR set to "" to disable + # pushing to a local registry even if `--push` is passed. + ARG local_registry="192.168.58.10:5000" # Build a self contained service to show built docs locally. DO docs-ci+PACKAGE @@ -37,4 +42,9 @@ local: COPY +docs/ /usr/share/nginx/html # This is a local only image, we do not publish it. - SAVE IMAGE cat-voices-docs:latest \ No newline at end of file + SAVE IMAGE cat-voices-docs:latest + + # Publish to the local development cluster + IF [ "$local_registry" != "" ] + SAVE IMAGE --push --insecure $local_registry/cat-voices-docs:latest + END diff --git a/utilities/local-cluster/.gitignore b/utilities/local-cluster/.gitignore index 20ba5c8de3..0aa0767070 100644 --- a/utilities/local-cluster/.gitignore +++ b/utilities/local-cluster/.gitignore @@ -1,4 +1,6 @@ shared/* .vagrant -!shared/.do_not_remove +# These are shared configs, need to be checked in to git. +!shared/k3s +!shared/extra.hosts diff --git a/utilities/local-cluster/Earthfile b/utilities/local-cluster/Earthfile index b1d82125cd..6eeea8a8df 100644 --- a/utilities/local-cluster/Earthfile +++ b/utilities/local-cluster/Earthfile @@ -4,7 +4,15 @@ VERSION 0.8 # Needs both Vagrant and Virtualbox installed on the local machine. start-cluster: LOCALLY + # Check if the necessary tools are present locally + RUN kubectl version --client=true + RUN helm version --short + # Check if the necessary local DNS entries exist + RUN python scripts/check-cluster-dns.py ./shared/extra.hosts + # Everything checks out so far, try and start the cluster. RUN vagrant up + # Add default services + # Add grafana/loki # stop-cluster : stops the locally running cluster stop-cluster: @@ -16,15 +24,39 @@ test-cluster: LOCALLY RUN kubectl --kubeconfig shared/k3s.yaml -o wide get nodes -# test-inside-earthly : Checks if we can see the cluster from INSIDE Earthly and not locally. -test-inside-earthly: +# kubernetes-base : base container with tooling set up for local access +kubernetes-base: FROM alpine:3.19 # Install kubectl RUN apk update && \ apk upgrade && \ - apk add kubectl + apk add kubectl \ + helm - COPY shared shared + COPY shared/k3s.yaml $HOME/.kube/config - RUN kubectl --kubeconfig shared/k3s.yaml -o wide get nodes \ No newline at end of file + COPY --dir manifests manifests + +# test targets to deploy the local documentation +deploy-docs: + FROM +kubernetes-base + + RUN kubectl apply -f manifests/docs.yml + +# test target to stop the local documentation +stop-docs: + FROM +kubernetes-base + + RUN kubectl delete deployment cat-gateway-docs + RUN kubectl delete service cat-gateway-docs + +# show-info : list important info about the running cluster +show-info: + FROM +kubernetes-base + + # RUN kubectl --kubeconfig shared/k3s.yaml -o wide get nodes + RUN --no-cache kubectl -n kube-system get all + RUN --no-cache kubectl -o wide get nodes + RUN --no-cache kubectl -o wide get pods + RUN --no-cache kubectl -o wide get service diff --git a/utilities/local-cluster/Readme.md b/utilities/local-cluster/Readme.md index a2666ea046..85795f8c67 100644 --- a/utilities/local-cluster/Readme.md +++ b/utilities/local-cluster/Readme.md @@ -5,6 +5,8 @@ To eliminate variability and simplify local deployment, we have standardized the * [VirtualBox](https://www.virtualbox.org/) * [Vagrant](https://developer.hashicorp.com/vagrant/install?product_intent=vagrant) +* [kubectl](https://kubernetes.io/docs/tasks/tools/) +* [helm](https://helm.sh/docs/intro/install/) These tools allow us to define VMs that are consistent and provide a uniform Kubernetes environment for local testing. @@ -16,14 +18,22 @@ The Cluster is based on [K3s](https://k3s.io/), which is a lightweight version o We set up 1 server node which hosts the control-plane and is the master node. Configured with: -* 2 Cores -* 2 GB of RAM +* 4 Cores +* 5 GB of RAM It has 3 Internal nodes, configured as: * 4 Cores * 4 GB of RAM +## Default Services + +### Container Registry + +### Traefik + +### Grafana/Prometheus/Loki + ## Interacting with the cluster ### Start the cluster @@ -49,3 +59,30 @@ earthly +test-cluster ```sh earthly +test-inside-earthly ``` + +## Debugging the cluster + +### SSH into a running VM + +To SSH into a VM running the cluster, use `vagrant`: + +```sh +vagrant ssh server +``` + +```sh +vagrant ssh agent1 +``` + +etc. + +### Debug the local registry + +The local registry is running inside docker, on the `server` VM. +First ssh into the VM. + +To display the registry service logs: + +```sh +docker logs registry +``` diff --git a/utilities/local-cluster/Vagrantfile b/utilities/local-cluster/Vagrantfile index b70545c8bc..fb90d6d188 100644 --- a/utilities/local-cluster/Vagrantfile +++ b/utilities/local-cluster/Vagrantfile @@ -5,11 +5,10 @@ server_ip = "192.168.58.10" # Determine the maximum number of agents, and set their IP addresses agents = { "agent1" => "192.168.58.11", - "agent2" => "192.168.58.12", - "agent3" => "192.168.58.13" } + "agent2" => "192.168.58.12" } -server_vcpu = "2" # Number of vCPUs in the VM -server_memory = "2048" # 2G of Memory +server_vcpu = "4" # Number of vCPUs in the VM +server_memory = "51292" # 5G of Memory (An extra gig because its the server node) agent_vcpu = "4" # Number of vCPUs in the VM agent_memory = "4096" # 4G of Memory @@ -20,32 +19,61 @@ is_darwin_arm64 = Vagrant::Util::Platform.architecture == "arm64" && Vagrant::Ut # K3s picking up the wrong interface when starting server and agent # https://github.com/alexellis/k3sup/issues/306 +static_ips = <<-SHELL + sudo -i + cat /vagrant_shared/extra.hosts >> /etc/hosts + SHELL + server_script = <<-SHELL sudo -i - apk add curl + # Read preconfiguration from shared directory and install it + mkdir -p /etc/rancher/k3s/ + mkdir -p /var/lib/rancher/k3s/server/manifests/ + cp /vagrant_shared/k3s/server/manifests/* /var/lib/rancher/k3s/server/manifests/ + cp /vagrant_shared/k3s/registries.yaml /etc/rancher/k3s/ + # Install and start k3s server node export INSTALL_K3S_EXEC="--bind-address=#{server_ip} --node-external-ip=#{server_ip} --flannel-iface=eth1" curl -sfL https://get.k3s.io | sh - echo "Sleeping for 5 seconds to wait for k3s to start" sleep 5 - cp /var/lib/rancher/k3s/server/token /vagrant_shared - cp /etc/rancher/k3s/k3s.yaml /vagrant_shared + # Export generated config into shared directory so we can use it outside the cluster. + cp /var/lib/rancher/k3s/server/token /vagrant_shared/ + cp /etc/rancher/k3s/k3s.yaml /vagrant_shared/ SHELL agent_script = <<-SHELL sudo -i - apk add curl + # Read preconfiguration from shared directory and install it + mkdir -p /etc/rancher/k3s/ + cp /vagrant_shared/k3s/registries.yaml /etc/rancher/k3s/ + # Install and start k3s agent/worker node export K3S_TOKEN_FILE=/vagrant_shared/token export K3S_URL=https://#{server_ip}:6443 export INSTALL_K3S_EXEC="--flannel-iface=eth1" curl -sfL https://get.k3s.io | sh - SHELL +registry_script = <<-SHELL + sudo -i + # Start local docker registry - running on the server VM + # Keeps files in the persistent shared directory + docker run -d -p 5000:5000 \ + --restart=always \ + -v /vagrant_shared/registry:/var/lib/registry \ + -e REGISTRY_HTTP_HEADERS_Access-Control-Allow-Origin='[*]' \ + -e REGISTRY_HTTP_HEADERS_Access-Control-Allow-Headers='[Authorization,Accept,Cache-Control]' \ + -e REGISTRY_HTTP_HEADERS_Access-Control-Expose-Headers='[Docker-Content-Digest]' \ + -e REGISTRY_STORAGE_DELETE_ENABLED='true' \ + --name registry registry:2 + SHELL + Vagrant.configure("2") do |config| - config.vm.box = "generic/alpine319" + config.vm.box = "generic/debian12" config.vm.define "server", primary: true do |server| server.vm.network "private_network", ip: server_ip server.vm.hostname = "server" + server.vm.network "forwarded_port", guest: 5000, host: 5000 if !is_darwin_arm64 # x86 anything should work with this @@ -62,6 +90,9 @@ Vagrant.configure("2") do |config| qe.smp = server_vcpu end end + server.vm.provision :docker + server.vm.provision "shell", inline: static_ips + server.vm.provision "shell", inline: registry_script server.vm.provision "shell", inline: server_script end @@ -82,6 +113,7 @@ Vagrant.configure("2") do |config| qe.smp = agent_vcpu end end + agent.vm.provision "shell", inline: static_ips agent.vm.provision "shell", inline: agent_script end end diff --git a/utilities/local-cluster/manifests/cat-voices-docs.yml b/utilities/local-cluster/manifests/cat-voices-docs.yml new file mode 100644 index 0000000000..0ccabc645c --- /dev/null +++ b/utilities/local-cluster/manifests/cat-voices-docs.yml @@ -0,0 +1,40 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: cat-gateway-docs +spec: + replicas: 1 + selector: + matchLabels: + app: docs-nginx + template: + metadata: + labels: + app: docs-nginx + spec: + containers: + - name: docs-nginx + image: localhost/cat-voices-docs:latest + ports: + - containerPort: 80 + name: http + protocol: TCP + resources: + limits: + cpu: "1" + memory: 500Mi + requests: + cpu: "0.1" + memory: 100Mi +--- +apiVersion: v1 +kind: Service +metadata: + name: cat-gateway-docs +spec: + type: LoadBalancer + ports: + - port: 8080 + targetPort: 80 + selector: + app: cat-gateway-docs diff --git a/utilities/local-cluster/scripts/check-cluster-dns.py b/utilities/local-cluster/scripts/check-cluster-dns.py new file mode 100755 index 0000000000..2dc1352b61 --- /dev/null +++ b/utilities/local-cluster/scripts/check-cluster-dns.py @@ -0,0 +1,57 @@ +#!/usr/bin/env python3 + +import socket +import sys + + +def parse_extra_hostnames(hostnames): + """ + This function takes a file of hostnames and returns a list of tuples containing the IP address and hostname for each entry. + The input should be a file with one hostname per line, formatted as "IP_Address Hostname". + The function will ignore any lines that start with "#" and any extra hostnames on the same line. + """ + with open(hostnames) as f: + lines = f.readlines() + lines = [line.strip() for line in lines] + lines = [line for line in lines if line != "" and not line.startswith("#")] + + result = [] + for line in lines: + split = line.split() + result.append((split[0], split[1])) + return result + + +def status(hostname, resolved_ip, ok): + print(f"{hostname:<25} : {resolved_ip:>15} : {ok}") + + +def check_hostname(hostname, ip): + # Check the hostame resolves to the expected IP + ok = "OK" + try: + resolved_ip = socket.gethostbyname(hostname) + if resolved_ip != ip: + ok = f"FAIL. Set `{ip:<15} {hostname:<25}` in /etc/hosts." + except socket.error as e: + resolved_ip = "None" + ok = f"FAIL. Add `{ip:<15} {hostname:<25}` to /etc/hosts" + + status(hostname, resolved_ip, ok) + + return ok == "OK" + + +everything_ok = True + +extra_hosts = parse_extra_hostnames(sys.argv[1]) + +status("HOSTNAME", "RESOLVED IP", "STATUS") +status("-------------------------", "---------------", "------") + +for host in extra_hosts: + everything_ok = check_hostname(host[1], host[0]) and everything_ok + +if not everything_ok: + sys.exit(1) +sys.exit(0) diff --git a/utilities/local-cluster/shared/.do_not_remove b/utilities/local-cluster/shared/.do_not_remove deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/utilities/local-cluster/shared/extra.hosts b/utilities/local-cluster/shared/extra.hosts new file mode 100644 index 0000000000..8940ceabf7 --- /dev/null +++ b/utilities/local-cluster/shared/extra.hosts @@ -0,0 +1,10 @@ +# Basic cluster Hostnames +192.168.58.10 cluster.test # The cluster default hostname +192.168.58.10 registry.cluster.test # The local container registry +192.168.58.10 traefik.cluster.test # The Traefik Ingress dashboard +192.168.58.10 grafana.cluster.test # The Grafana dashboard + +# Catalyst Voices specific Hostnames +192.168.58.10 voices.cluster.test # cat voices - Front end +192.168.58.10 docs.voices.cluster.test # local docs server for cat voices (port 80) +192.168.59.10 db.voices.cluster.test # cat-voices exposed DB. UI on 80, DB itself on 5432 diff --git a/utilities/local-cluster/shared/k3s/grafana-prometheus/alert-manager-ingress.yaml b/utilities/local-cluster/shared/k3s/grafana-prometheus/alert-manager-ingress.yaml new file mode 100644 index 0000000000..a18ed732dc --- /dev/null +++ b/utilities/local-cluster/shared/k3s/grafana-prometheus/alert-manager-ingress.yaml @@ -0,0 +1,24 @@ +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: alert-manager-ingress + annotations: + spec.ingressClassName: traefik + cert-manager.io/cluster-issuer: letsencrypt-prod + traefik.ingress.kubernetes.io/router.middlewares: default-my-basic-auth@kubernetescrd +spec: + rules: + - host: alert-manager.cluster.local + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: prometheus-stack-kube-prom-alertmanager + port: + number: 9093 + tls: + - secretName: alert-manager-tls + hosts: + - alert-manager.cluster.local \ No newline at end of file diff --git a/utilities/local-cluster/shared/k3s/grafana-prometheus/grafana-ingress.yaml b/utilities/local-cluster/shared/k3s/grafana-prometheus/grafana-ingress.yaml new file mode 100644 index 0000000000..4eef5878eb --- /dev/null +++ b/utilities/local-cluster/shared/k3s/grafana-prometheus/grafana-ingress.yaml @@ -0,0 +1,24 @@ +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: grafana-ingress + annotations: + spec.ingressClassName: traefik + cert-manager.io/cluster-issuer: letsencrypt-prod + traefik.ingress.kubernetes.io/router.middlewares: default-my-basic-auth@kubernetescrd +spec: + rules: + - host: grafana.cluster.local + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: prometheus-stack-grafana + port: + number: 80 + tls: + - secretName: grafana-tls + hosts: + - grafana.cluster.local \ No newline at end of file diff --git a/utilities/local-cluster/shared/k3s/grafana-prometheus/prometheus-ingress.yaml b/utilities/local-cluster/shared/k3s/grafana-prometheus/prometheus-ingress.yaml new file mode 100644 index 0000000000..1368bbed67 --- /dev/null +++ b/utilities/local-cluster/shared/k3s/grafana-prometheus/prometheus-ingress.yaml @@ -0,0 +1,24 @@ +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: prometheus-ingress + annotations: + spec.ingressClassName: traefik + cert-manager.io/cluster-issuer: letsencrypt-prod + traefik.ingress.kubernetes.io/router.middlewares: default-my-basic-auth@kubernetescrd +spec: + rules: + - host: prometheus.cluster.local + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: prometheus-stack-kube-prom-prometheus + port: + number: 9090 + tls: + - secretName: prometheus-tls + hosts: + - prometheus.cluster.local \ No newline at end of file diff --git a/utilities/local-cluster/shared/k3s/grafana-prometheus/prometheus-values.yaml b/utilities/local-cluster/shared/k3s/grafana-prometheus/prometheus-values.yaml new file mode 100644 index 0000000000..8a4f45309b --- /dev/null +++ b/utilities/local-cluster/shared/k3s/grafana-prometheus/prometheus-values.yaml @@ -0,0 +1,53 @@ +# Disable etcd monitoring. See https://github.com/cablespaghetti/k3s-monitoring/issues/4 +kubeEtcd: + enabled: false + +# Disable kube-controller-manager and kube-scheduler monitoring. See https://github.com/cablespaghetti/k3s-monitoring/issues/2 +kubeControllerManager: + enabled: false +kubeScheduler: + enabled: false + +prometheus: + prometheusSpec: + retention: 3d + + # storageSpec: + # volumeClaimTemplate: + # metadata: + # name: prometheus-longhorn-pvc + # spec: + # accessModes: + # - ReadWriteOnce + # storageClassName: longhorn + # resources: + # requests: + # storage: 2Gi + +grafana: + plugins: + - grafana-piechart-panel + enabled: true + grafana.ini: + users: + viewers_can_edit: true + auth: + disable_login_form: true + disable_signout_menu: true + auth.anonymous: + enabled: true + org_role: Admin + auth.basic: + enabled: false + + # persistence: + # enabled: true + # type: pvc + # storageClassName: longhorn + # accessModes: + # - ReadWriteOnce + # size: 4Gi + # finalizers: + # - kubernetes.io/pvc-protection + # ALTERNATIVELY IF YOU HAVE AN EXISTING CLAME YOU WISH TO USE/REUSE + # existingClaim: prom-grafana diff --git a/utilities/local-cluster/shared/k3s/grafana-prometheus/traefik-dashboard-service.yaml b/utilities/local-cluster/shared/k3s/grafana-prometheus/traefik-dashboard-service.yaml new file mode 100644 index 0000000000..0fde627be0 --- /dev/null +++ b/utilities/local-cluster/shared/k3s/grafana-prometheus/traefik-dashboard-service.yaml @@ -0,0 +1,18 @@ +apiVersion: v1 +kind: Service +metadata: + name: traefik-dashboard + namespace: kube-system + labels: + app.kubernetes.io/instance: traefik + app.kubernetes.io/name: traefik-dashboard +spec: + type: ClusterIP + ports: + - name: traefik + port: 9000 + targetPort: traefik + protocol: TCP + selector: + app.kubernetes.io/instance: traefik-kube-system + app.kubernetes.io/name: traefik diff --git a/utilities/local-cluster/shared/k3s/grafana-prometheus/traefik-dashboard.yaml b/utilities/local-cluster/shared/k3s/grafana-prometheus/traefik-dashboard.yaml new file mode 100644 index 0000000000..ce1c49f397 --- /dev/null +++ b/utilities/local-cluster/shared/k3s/grafana-prometheus/traefik-dashboard.yaml @@ -0,0 +1,1411 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: traefik-dashboard + labels: + grafana_dashboard: "true" +data: + traefik-dashboard.json: |- + { + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "description": "Simple dashboard for Traefik 2", + "editable": true, + "gnetId": 11462, + "graphTooltip": 0, + "id": 28, + "iteration": 1621896379601, + "links": [], + "panels": [ + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": ["#299c46", "rgba(237, 129, 40, 0.89)", "#d44a3a"], + "datasource": "Prometheus", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "format": "s", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 6, + "w": 3, + "x": 0, + "y": 0 + }, + "id": 22, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "expr": "time() - process_start_time_seconds{job=\"$job\"}", + "format": "time_series", + "intervalFactor": 2, + "refId": "A" + } + ], + "thresholds": "", + "title": "Uptime", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": true, + "colors": ["#37872D", "#37872D", "#C4162A"], + "datasource": "Prometheus", + "decimals": 0, + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 6, + "w": 3, + "x": 3, + "y": 0 + }, + "id": 26, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "200%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(increase(traefik_service_requests_total{code=\"404\",protocol=~\"$protocol\"}[$interval]))", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "", + "metric": "traefik_requests_total", + "refId": "A", + "step": 60 + } + ], + "thresholds": "0,1", + "title": "404 Error Count", + "type": "singlestat", + "valueFontSize": "200%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "max" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": true, + "colors": ["#37872D", "#C4162A", "#C4162A"], + "datasource": "Prometheus", + "decimals": 0, + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 6, + "w": 3, + "x": 6, + "y": 0 + }, + "id": 32, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "200%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false, + "ymax": null, + "ymin": null + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(increase(traefik_service_requests_total{code=\"503\",protocol=~\"$protocol\"}[$interval]))", + "refId": "A" + } + ], + "thresholds": "0,1", + "timeFrom": null, + "timeShift": null, + "title": "503 Error count", + "type": "singlestat", + "valueFontSize": "200%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "max" + }, + { + "aliasColors": {}, + "breakPoint": "50%", + "cacheTimeout": null, + "combine": { + "label": "Others", + "threshold": 0 + }, + "datasource": "Prometheus", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fontSize": "80%", + "format": "short", + "gridPos": { + "h": 6, + "w": 4, + "x": 9, + "y": 0 + }, + "id": 18, + "interval": null, + "legend": { + "percentage": true, + "show": true, + "sort": null, + "sortDesc": null, + "values": true + }, + "legendType": "Right side", + "links": [], + "maxDataPoints": 3, + "nullPointMode": "connected", + "pieType": "pie", + "strokeWidth": 1, + "targets": [ + { + "expr": "topk(5, sum(traefik_service_requests_total{protocol=~\"$protocol\"}) by (code))", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{code}}", + "refId": "A" + } + ], + "title": "Top 5 $protocol return code", + "type": "grafana-piechart-panel", + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": ["#299c46", "rgba(237, 129, 40, 0.89)", "#d44a3a"], + "datasource": "Prometheus", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "format": "ms", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 6, + "w": 4, + "x": 13, + "y": 0 + }, + "id": 20, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(traefik_entrypoint_request_duration_seconds_sum) / sum(traefik_entrypoint_requests_total) * 1000", + "format": "time_series", + "intervalFactor": 2, + "refId": "A" + } + ], + "thresholds": "", + "title": "Average response time", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fieldConfig": { + "defaults": { + "custom": {}, + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 6, + "w": 7, + "x": 17, + "y": 0 + }, + "hiddenSeries": false, + "id": 14, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "7.4.2", + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(traefik_service_request_duration_seconds_sum{protocol=~\"$protocol\"}) / sum(traefik_entrypoint_requests_total{protocol=~\"$protocol\"}) * 1000", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Average response time (ms)", + "refId": "A", + "step": 240 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Average response time", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "ms", + "label": null, + "logBase": 10, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "decimals": 0, + "fieldConfig": { + "defaults": { + "custom": {}, + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 6, + "w": 12, + "x": 0, + "y": 6 + }, + "hiddenSeries": false, + "id": 10, + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "7.4.2", + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(increase(traefik_service_requests_total{code=\"404\",method=\"GET\",protocol=~\"$protocol\"}[$interval])) by (service)", + "format": "time_series", + "interval": "", + "intervalFactor": 2, + "legendFormat": "{{service}} ", + "refId": "A", + "step": 240 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Bad Status Code Count", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 0, + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": true, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fieldConfig": { + "defaults": { + "custom": {}, + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 6, + "w": 12, + "x": 12, + "y": 6 + }, + "hiddenSeries": false, + "hideTimeOverride": false, + "id": 4, + "legend": { + "alignAsTable": true, + "avg": true, + "current": false, + "max": true, + "min": true, + "rightSide": true, + "show": true, + "total": false, + "values": true + }, + "lines": false, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "7.4.2", + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(traefik_service_requests_total[$interval]))", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Total requests", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Total requests", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 0, + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "decimals": 0, + "format": "short", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fieldConfig": { + "defaults": { + "custom": {}, + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 6, + "w": 10, + "x": 0, + "y": 12 + }, + "hiddenSeries": false, + "id": 8, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null as zero", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "7.4.2", + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "process_open_fds{job=~\"$job\"}", + "format": "time_series", + "interval": "", + "intervalFactor": 2, + "legendFormat": "{{ instance }}", + "refId": "A", + "step": 240 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Used sockets", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "decimals": 0, + "fieldConfig": { + "defaults": { + "custom": {}, + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 6, + "w": 14, + "x": 10, + "y": 12 + }, + "hiddenSeries": false, + "id": 24, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": true, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "7.4.2", + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(traefik_service_requests_total{protocol=~\"http|https\"}[$interval])) by (service)", + "format": "time_series", + "interval": "", + "intervalFactor": 2, + "legendFormat": "{{service}} ", + "refId": "A", + "step": 240 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Access to services", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 0, + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fieldConfig": { + "defaults": { + "custom": {}, + "links": [] + }, + "overrides": [] + }, + "fill": 7, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 12, + "x": 0, + "y": 18 + }, + "hiddenSeries": false, + "id": 30, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": false, + "rightSide": true, + "show": true, + "sort": "avg", + "sortDesc": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "7.4.2", + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "sum(traefik_entrypoint_open_connections) by (method)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ method }}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "ENTRYPOINT - Open Connections", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 0, + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fieldConfig": { + "defaults": { + "custom": {}, + "links": [] + }, + "overrides": [] + }, + "fill": 7, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 12, + "x": 12, + "y": 18 + }, + "hiddenSeries": false, + "id": 28, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": false, + "rightSide": true, + "show": true, + "sort": "avg", + "sortDesc": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "7.4.2", + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "sum(traefik_service_open_connections) by (method)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ method }}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "SERVICE - Open Connections", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 0, + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "decimals": 0, + "fieldConfig": { + "defaults": { + "custom": {}, + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 24, + "x": 0, + "y": 25 + }, + "hiddenSeries": false, + "id": 12, + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "7.4.2", + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "alias": "/^[^234].*/", + "transform": "negative-Y" + } + ], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(increase(traefik_service_requests_total{protocol=~\"$protocol\"}[$interval])) by (code)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{code}}", + "refId": "A", + "step": 120 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Status Code Count ", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 0, + "format": "short", + "label": "", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "refresh": false, + "schemaVersion": 27, + "style": "dark", + "tags": ["traefik", "load-balancer", "docker", "prometheus"], + "templating": { + "list": [ + { + "allValue": null, + "current": { + "selected": false, + "text": "traefik-dashboard", + "value": "traefik-dashboard" + }, + "datasource": "Prometheus", + "definition": "", + "description": null, + "error": null, + "hide": 0, + "includeAll": false, + "label": "Job:", + "multi": false, + "name": "job", + "options": [], + "query": { + "query": "label_values(job)", + "refId": "Prometheus-job-Variable-Query" + }, + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 2, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "current": { + "selected": false, + "text": "All", + "value": "$__all" + }, + "datasource": "Prometheus", + "definition": "label_values(traefik_service_requests_total, protocol)", + "description": null, + "error": null, + "hide": 0, + "includeAll": true, + "label": "Service:", + "multi": true, + "name": "protocol", + "options": [], + "query": { + "query": "label_values(traefik_service_requests_total, protocol)", + "refId": "Prometheus-protocol-Variable-Query" + }, + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "auto": true, + "auto_count": 30, + "auto_min": "10s", + "current": { + "selected": false, + "text": "auto", + "value": "$__auto_interval_interval" + }, + "description": null, + "error": null, + "hide": 0, + "label": "Interval", + "name": "interval", + "options": [ + { + "selected": true, + "text": "auto", + "value": "$__auto_interval_interval" + }, + { + "selected": false, + "text": "1m", + "value": "1m" + }, + { + "selected": false, + "text": "10m", + "value": "10m" + }, + { + "selected": false, + "text": "30m", + "value": "30m" + }, + { + "selected": false, + "text": "1h", + "value": "1h" + }, + { + "selected": false, + "text": "6h", + "value": "6h" + }, + { + "selected": false, + "text": "12h", + "value": "12h" + }, + { + "selected": false, + "text": "1d", + "value": "1d" + }, + { + "selected": false, + "text": "7d", + "value": "7d" + }, + { + "selected": false, + "text": "14d", + "value": "14d" + }, + { + "selected": false, + "text": "30d", + "value": "30d" + } + ], + "query": "1m,10m,30m,1h,6h,12h,1d,7d,14d,30d", + "refresh": 2, + "skipUrlSync": false, + "type": "interval" + } + ] + }, + "time": { + "from": "now-3h", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": ["5m", "15m", "1h", "6h", "12h", "24h", "2d", "7d", "30d"] + }, + "timezone": "", + "title": "Traefik Metrics", + "uid": "3ipsWfViz333", + "version": 1 + } diff --git a/utilities/local-cluster/shared/k3s/grafana-prometheus/traefik-service-monitor.yaml b/utilities/local-cluster/shared/k3s/grafana-prometheus/traefik-service-monitor.yaml new file mode 100644 index 0000000000..ca38d65d24 --- /dev/null +++ b/utilities/local-cluster/shared/k3s/grafana-prometheus/traefik-service-monitor.yaml @@ -0,0 +1,20 @@ +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: traefik + namespace: default + labels: + app: traefik + release: prometheus-stack +spec: + jobLabel: traefik-metrics + selector: + matchLabels: + app.kubernetes.io/instance: traefik + app.kubernetes.io/name: traefik-dashboard + namespaceSelector: + matchNames: + - kube-system + endpoints: + - port: traefik + path: /metrics \ No newline at end of file diff --git a/utilities/local-cluster/shared/k3s/registries.yaml b/utilities/local-cluster/shared/k3s/registries.yaml new file mode 100644 index 0000000000..2f40e54892 --- /dev/null +++ b/utilities/local-cluster/shared/k3s/registries.yaml @@ -0,0 +1,5 @@ +# Sets up registries the k3s cluster can see +mirrors: + registry.cluster.test: + endpoint: + - "http://registry.cluster.test:5000" diff --git a/utilities/local-cluster/shared/k3s/server/manifests/registry-ui.yaml b/utilities/local-cluster/shared/k3s/server/manifests/registry-ui.yaml new file mode 100644 index 0000000000..5c9f818d36 --- /dev/null +++ b/utilities/local-cluster/shared/k3s/server/manifests/registry-ui.yaml @@ -0,0 +1,61 @@ +apiVersion: v1 +kind: Service +metadata: + name: registry-ui +spec: + type: ClusterIP + ports: + - port: 80 + targetPort: 80 + selector: + app: registry-ui +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: registry-ui +spec: + selector: + matchLabels: + app: registry-ui + replicas: 1 + template: + metadata: + labels: + app: registry-ui + spec: + containers: + - name: registry-ui + image: joxit/docker-registry-ui:latest + ports: + - containerPort: 80 + env: + - name: SINGLE_REGISTRY + value: "true" + - name: REGISTRY_TITLE + value: "Catalyst Test Cluster - Container Registry" + - name: REGISTRY_URL + value: "http://registry.cluster.test:5000" +--- +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: registry-ui-ingress + annotations: + spec.ingressClassName: traefik + cert-manager.io/cluster-issuer: letsencrypt-prod + # use this if you want basic auth on the UI + # you have to use the registry credential any way + # traefik.ingress.kubernetes.io/router.middlewares: default-registry-basic-auth@kubernetescrd +spec: + rules: + - host: registry.cluster.test + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: registry-ui + port: + number: 80 diff --git a/utilities/local-cluster/shared/k3s/server/manifests/traefik-dashboard-helmconfig.yml b/utilities/local-cluster/shared/k3s/server/manifests/traefik-dashboard-helmconfig.yml new file mode 100644 index 0000000000..302721f412 --- /dev/null +++ b/utilities/local-cluster/shared/k3s/server/manifests/traefik-dashboard-helmconfig.yml @@ -0,0 +1,17 @@ +apiVersion: helm.cattle.io/v1 +kind: HelmChartConfig +metadata: + name: traefik + namespace: kube-system +spec: + valuesContent: |- + additionalArguments: + - "--api" + - "--api.dashboard=true" + - "--api.insecure=true" + ports: + traefik: + expose: true + providers: + kubernetesCRD: + allowCrossNamespace: true diff --git a/utilities/local-cluster/shared/k3s/server/manifests/traefik-dashboard-ingress.yaml b/utilities/local-cluster/shared/k3s/server/manifests/traefik-dashboard-ingress.yaml new file mode 100644 index 0000000000..66acd51ed6 --- /dev/null +++ b/utilities/local-cluster/shared/k3s/server/manifests/traefik-dashboard-ingress.yaml @@ -0,0 +1,19 @@ +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: traefik-ingress + namespace: kube-system + annotations: + spec.ingressClassName: traefik +spec: + rules: + - host: traefik.cluster.local + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: traefik-dashboard + port: + number: 9000 diff --git a/utilities/local-cluster/shared/k3s/server/manifests/traefik-dashboard-service.yaml b/utilities/local-cluster/shared/k3s/server/manifests/traefik-dashboard-service.yaml new file mode 100644 index 0000000000..0fde627be0 --- /dev/null +++ b/utilities/local-cluster/shared/k3s/server/manifests/traefik-dashboard-service.yaml @@ -0,0 +1,18 @@ +apiVersion: v1 +kind: Service +metadata: + name: traefik-dashboard + namespace: kube-system + labels: + app.kubernetes.io/instance: traefik + app.kubernetes.io/name: traefik-dashboard +spec: + type: ClusterIP + ports: + - name: traefik + port: 9000 + targetPort: traefik + protocol: TCP + selector: + app.kubernetes.io/instance: traefik-kube-system + app.kubernetes.io/name: traefik diff --git a/utilities/local-cluster/shared/k3s/server/manifests/traefik-dashboard.old.yml b/utilities/local-cluster/shared/k3s/server/manifests/traefik-dashboard.old.yml new file mode 100644 index 0000000000..226973d1ac --- /dev/null +++ b/utilities/local-cluster/shared/k3s/server/manifests/traefik-dashboard.old.yml @@ -0,0 +1,48 @@ +#apiVersion: helm.cattle.io/v1 +#kind: HelmChartConfig +#metadata: +# name: traefik +# namespace: kube-system +#spec: +# valuesContent: |- +# additionalArguments: +# - "--api" +# - "--api.dashboard=true" +# - "--api.insecure=true" +# ports: +# traefik: +# expose: true +# providers: +# kubernetesCRD: +# allowCrossNamespace: true +#--- +#apiVersion: extensions/v1beta1 +#kind: Ingress +#metadata: +# name: traefik-ingress +#spec: +# rules: +# - host: traefik.cluster.local +# http: +# paths: +# - path: / +# backend: +# serviceName: traefik +# servicePort: 9000 +#--- +#apiVersion: traefik.containo.us/v1alpha1 +#kind: IngressRoute +#metadata: +# name: dashboard +#spec: +# entryPoints: +# - web +# - websecure +# routes: +# - match: Host(`traefik.${DOMAIN}`) +# kind: Rule +# services: +# - name: api@internal +# kind: TraefikService +# tls: +# secretName: traefik-tls