diff --git a/traefik/traefik.yaml b/traefik/traefik.yaml new file mode 100644 index 0000000..cd72834 --- /dev/null +++ b/traefik/traefik.yaml @@ -0,0 +1,277 @@ +services: + keepalived-master: + environment: + KEEPALIVED_STATE: MASTER + KEEPALIVED_INTERFACE: eth0 + KEEPALIVED_PRIORITY: "150" + KEEPALIVED_ROUTER_ID: "51" + KEEPALIVED_PASSWORD: ${KEEPALIVED_PASSWORD} + KEEPALIVED_VIRTUAL_IPS: ${KEEPALIVED_VIRTUAL_IPS} + KEEPALIVED_UNICAST_PEERS: "#PYTHON2BASH:['192.168.4.31', '192.168.4.32']" + command: --copy-service + cap_add: [NET_ADMIN, NET_BROADCAST, NET_RAW] + networks: [host] + image: osixia/keepalived:2.0.20 + volumes: + - /volume1/docker/keepalived/data/my-keepalived.conf:/container/service/keepalived/assets/keepalived.conf + deploy: + placement: + constraints: [node.hostname == docker-3] + labels: [traefik.enable=false] + resources: + limits: {cpus: '1', memory: 128M} + # stop-first: host network + VRRP — two concurrent keepalived speakers with the + # same router-id would fight over the VIP. Never run old+new simultaneously. + update_config: + parallelism: 1 + delay: 30s + failure_action: rollback + monitor: 15s + order: stop-first + rollback_config: + parallelism: 1 + failure_action: pause + order: stop-first + + keepalived-backup: + environment: + KEEPALIVED_STATE: BACKUP + KEEPALIVED_INTERFACE: eth0 + KEEPALIVED_PRIORITY: "100" + KEEPALIVED_ROUTER_ID: "51" + KEEPALIVED_PASSWORD: ${KEEPALIVED_PASSWORD} + KEEPALIVED_VIRTUAL_IPS: ${KEEPALIVED_VIRTUAL_IPS} + KEEPALIVED_UNICAST_PEERS: "#PYTHON2BASH:['192.168.4.32', '192.168.4.33']" + cap_add: [NET_ADMIN, NET_BROADCAST, NET_RAW] + networks: [host] + image: osixia/keepalived:2.0.20 + volumes: + - /volume1/docker/keepalived/data/my-keepalived.conf:/container/service/keepalived/assets/keepalived.conf + deploy: + placement: + constraints: [node.hostname != docker-3] + labels: [traefik.enable=false] + resources: + limits: {cpus: '1', memory: 128M} + # stop-first: host network + VRRP (see keepalived-master) + update_config: + parallelism: 1 + delay: 30s + failure_action: rollback + monitor: 15s + order: stop-first + rollback_config: + parallelism: 1 + failure_action: pause + order: stop-first + + reverse-proxy: + image: public.ecr.aws/docker/library/traefik:latest + hostname: traefik + command: + - --accesslog.filePath=/traefik/logs/access.log + - --accesslog.fields.names.StartUTC=drop + - --log.filePath=/traefik/logs/traefik.log + - --log.format=json + - --log.level=DEBUG + - --providers.swarm=true + - --providers.swarm.endpoint=unix:///var/run/docker.sock + - --providers.file.directory=/traefik/rules + - --providers.file.watch=true + - --entrypoints.web.http.redirections.entryPoint.to=websecure + - --entrypoints.web.http.redirections.entryPoint.scheme=https + - --entrypoints.web.address=:80 + - --entrypoints.websecure.address=:443 + - --entryPoints.websecure.transport.respondingTimeouts.readTimeout=0s + - --entryPoints.websecure.transport.respondingTimeouts.writeTimeout=0s + - --entryPoints.websecure.transport.respondingTimeouts.idleTimeout=3600s + - --entrypoints.mqtt.address=:1883 + - --entrypoints.iperf-tcp.address=:5201 + - --entrypoints.postgresql.address=:5431 + - --entrypoints.iperf-udp.address=:5201/udp + - --certificatesresolvers.letsencrypt.acme.tlschallenge=true + - --certificatesresolvers.letsencrypt.acme.email=avb@bryanmail.net + - --certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json + - --entryPoints.web.forwardedHeaders.insecure + - --entryPoints.websecure.forwardedHeaders.insecure + - --entrypoints.web.forwardedHeaders.trustedIPs=127.0.0.1/32,10.0.0.0/8,172.16.0.0/12 + - --entrypoints.websecure.forwardedHeaders.trustedIPs=127.0.0.1/32,10.0.0.0/8,172.16.0.0/12 + - --serversTransport.insecureSkipVerify=true + - --api.dashboard=true + - --experimental.plugins.bouncer.modulename=github.com/maxlerebourg/crowdsec-bouncer-traefik-plugin + - --experimental.plugins.bouncer.version=v1.5.1 + - --serversTransport.forwardingTimeouts.responseHeaderTimeout=0s + - --serversTransport.forwardingTimeouts.idleConnTimeout=0s + environment: + - TZ=US/Alaska + ports: + - {target: 80, published: 80, protocol: tcp, mode: host} + - {target: 443, published: 443, protocol: tcp, mode: host} + - {target: 1883, published: 1883, protocol: tcp, mode: host} + - {target: 5201, published: 5201, protocol: tcp, mode: host} + - {target: 5201, published: 5201, protocol: udp, mode: host} + - {target: 5432, published: 5431, protocol: tcp, mode: host} + networks: [traefik_backend, traefik_frontend] + stdin_open: true + tty: true + volumes: + - /var/run/docker.sock:/var/run/docker.sock:ro + - /volume1/docker/traefik:/traefik:rw + - /volume1/docker/letsencrypt:/letsencrypt:rw + - /volume1/docker/traefik/cloudflare:/cloudflare:ro + deploy: + mode: global + labels: + - traefik.enable=true + - traefik.http.services.traefik.loadbalancer.server.port=888 + - traefik.http.routers.traefik.rule=Host(`traefik.${DOMAIN}`) + - traefik.http.routers.traefik.entrypoints=websecure + - traefik.http.routers.traefik.tls.certresolver=letsencrypt + - traefik.http.routers.traefik.service=api@internal + - traefik.http.routers.traefik.middlewares=forwardAuth-authentik@file, crowdsec@file + resources: + limits: {cpus: '4', memory: 512M} + # stop-first: host-mode published ports (80/443/1883/5201/5431) — a start-first + # replacement task can never bind while the old task holds the ports, so + # start-first would deadlock/rollback every update. Global mode + parallelism 1 + # means only one node is briefly down; keepalived VIP + remaining nodes cover it. + update_config: + parallelism: 1 + delay: 30s + failure_action: rollback + monitor: 15s + order: stop-first + rollback_config: + parallelism: 1 + failure_action: pause + order: stop-first + + traefik-certs-dumper: + image: ghcr.io/ldez/traefik-certs-dumper:v2.10.0 + entrypoint: sh -c 'apk add jq ; while ! [ -e /letsencrypt/acme.json ] || ! [ `jq ".[] | .Certificates | length" /letsencrypt/acme.json` != 0 ]; do sleep 1 ; done && traefik-certs-dumper file --version v3 --watch --source /letsencrypt/acme.json --dest /letsencrypt/certs' + volumes: + - /volume1/docker/letsencrypt:/letsencrypt + networks: [traefik_frontend] + deploy: + labels: [traefik.enable=false] + resources: + limits: {cpus: '1', memory: 64M} + update_config: + parallelism: 1 + delay: 30s + failure_action: rollback + monitor: 15s + order: start-first + rollback_config: + parallelism: 1 + failure_action: pause + order: start-first + + speedtest: + image: openspeedtest/latest + networks: [traefik_backend] + ports: + - 3001:3000 + volumes: + - /volume1/docker/Speedtest/ssl:/etc/ssl + deploy: + labels: + - traefik.enable=true + - traefik.http.routers.speedtest.rule=Host(`speedtest.${DOMAIN}`) + - traefik.http.routers.speedtest.tls=true + - traefik.http.routers.speedtest.tls.certresolver=letsencrypt + - traefik.http.routers.speedtest.entrypoints=websecure + - traefik.http.services.speedtest.loadbalancer.server.port=3000 + - traefik.http.services.speedtest.loadbalancer.server.scheme=http + - traefik.http.routers.speedtest.middlewares=limit + - traefik.http.middlewares.limit.buffering.maxRequestBodyBytes=10000000000 + - traefik.swarm.network=traefik_backend + - autoheal=true + resources: + limits: {cpus: '8', memory: 1G} + update_config: + parallelism: 1 + delay: 30s + failure_action: rollback + monitor: 15s + order: start-first + rollback_config: + parallelism: 1 + failure_action: pause + order: start-first + + iperf3-server: + image: networkstatic/iperf3:latest + stdin_open: true + tty: true + command: ["-s", "-p 5201"] + entrypoint: ["iperf3"] + networks: [traefik_backend] + deploy: + labels: + - traefik.enable=true + - traefik.tcp.routers.iperf.entrypoints=iperf-tcp + - traefik.tcp.routers.iperf.rule=HostSNI(`*`) + - traefik.tcp.services.iperf.loadbalancer.server.port=5201 + - traefik.tcp.routers.iperf.service=iperf + - traefik.swarm.network=traefik_backend + - traefik.udp.routers.iperf-udp.entrypoints=iperf-udp + - traefik.udp.routers.iperf-udp.service=iperf-udp + - traefik.udp.services.iperf-udp.loadbalancer.server.port=5201 + - autoheal=true + resources: + limits: {cpus: '4', memory: 128M} + update_config: + parallelism: 1 + delay: 30s + failure_action: rollback + monitor: 15s + order: start-first + rollback_config: + parallelism: 1 + failure_action: pause + order: start-first + + whoami: + image: emilevauge/whoami + networks: [traefik_backend] + deploy: + labels: + - traefik.enable=true + - traefik.http.routers.whoami.rule=Host(`whoami.${DOMAIN}`) + - traefik.http.routers.whoami.tls=true + - traefik.http.routers.whoami.tls.certresolver=letsencrypt + - traefik.http.routers.whoami.entrypoints=websecure + - traefik.http.services.whoami.loadbalancer.server.port=80 + - traefik.http.services.whoami.loadbalancer.passHostHeader=false + - traefik.swarm.network=traefik_backend + - traefik.http.routers.whoami.middlewares=crowdsec@file, forwardAuth-authentik@file + resources: + limits: {cpus: '1', memory: 16M} + update_config: + parallelism: 1 + delay: 30s + failure_action: rollback + monitor: 15s + order: start-first + rollback_config: + parallelism: 1 + failure_action: pause + order: start-first + +networks: + traefik_frontend: + name: traefik_frontend + driver: overlay + driver_opts: + com.docker.network.driver.mtu: "8950" + attachable: true + traefik_backend: + name: traefik_backend + driver: overlay + driver_opts: + com.docker.network.driver.mtu: "8950" + attachable: true + host: + name: host + external: true