161 lines
6.6 KiB
YAML
161 lines
6.6 KiB
YAML
---
|
|
# playbooks/docker/deploy_traefik_kop.yml
|
|
#
|
|
# Purpose:
|
|
# Deploy the traefik-kop Swarm service, which bridges Swarm service labels
|
|
# to Traefik routing via Redis. Once deployed, any Swarm service labelled
|
|
# with traefik.enable=true will have its routes published automatically.
|
|
#
|
|
# Architecture:
|
|
# Swarm services → traefik-kop → Redis (10.0.0.151:6379) → Traefik (heimdall)
|
|
# traefik-kop reads Docker service state on the Swarm manager and writes
|
|
# routing rules to Redis. Traefik's redis provider picks them up in real time.
|
|
#
|
|
# Pre-requisites:
|
|
# - Swarm must be active and swarm-manager-1 (10.0.0.211) must be reachable
|
|
# - Redis on Heimdall (10.0.0.151:6379) must be running
|
|
# - community.docker collection installed: ansible-galaxy collection install community.docker
|
|
#
|
|
# Usage:
|
|
# ansible-playbook -i inventory/hosts.ini playbooks/docker/deploy_traefik_kop.yml
|
|
#
|
|
# Dry-run (no changes to Swarm):
|
|
# ansible-playbook -i inventory/hosts.ini playbooks/docker/deploy_traefik_kop.yml --check
|
|
#
|
|
# Tear down:
|
|
# ansible-playbook -i inventory/hosts.ini playbooks/docker/deploy_traefik_kop.yml \
|
|
# -e "stack_state=absent"
|
|
#
|
|
# Labelling Swarm services for auto-discovery:
|
|
# After this deploys, Swarm services only need these labels (under deploy.labels):
|
|
#
|
|
# deploy:
|
|
# labels:
|
|
# - "traefik.enable=true"
|
|
# - "traefik.http.routers.<name>.rule=Host(`<domain>.castaldifamily.com`)"
|
|
# - "traefik.http.routers.<name>.entrypoints=websecure"
|
|
# - "traefik.http.routers.<name>.tls.certresolver=cloudflare"
|
|
# - "traefik.http.services.<name>.loadbalancer.server.port=<port>"
|
|
#
|
|
# NOTE: Use deploy.labels (not top-level labels) for Swarm services.
|
|
# Top-level labels apply to the container image; deploy.labels apply
|
|
# to the Swarm service — which is what traefik-kop reads.
|
|
|
|
- name: Deploy traefik-kop Swarm stack
|
|
hosts: swarm_managers
|
|
become: false
|
|
gather_facts: false
|
|
vars:
|
|
traefik_kop_stack_state: "{{ stack_state | default('present') }}"
|
|
vars_files:
|
|
- ../../group_vars/all.yml
|
|
|
|
tasks:
|
|
# --------------------------------------------------
|
|
# STEP 1: Assert Swarm is active and reachable
|
|
# --------------------------------------------------
|
|
|
|
- name: Verify target is an active Swarm manager
|
|
ansible.builtin.command: >
|
|
docker info --format '{{ "{{" }}.Swarm.LocalNodeState{{ "}}" }}|{{ "{{" }}.Swarm.ControlAvailable{{ "}}" }}'
|
|
register: _swarm_info
|
|
changed_when: false
|
|
when: inventory_hostname == groups['swarm_managers'][0]
|
|
|
|
- name: Assert Swarm manager pre-conditions
|
|
ansible.builtin.assert:
|
|
that:
|
|
- _swarm_info.stdout is search('active')
|
|
- _swarm_info.stdout is search('true')
|
|
fail_msg: >-
|
|
{{ inventory_hostname }} must be an active Swarm manager.
|
|
Current state: {{ _swarm_info.stdout | default('unknown') }}
|
|
when: inventory_hostname == groups['swarm_managers'][0]
|
|
|
|
# --------------------------------------------------
|
|
# STEP 2: Ensure proxy-net overlay network exists
|
|
# WHY: The traefik-kop stack declares proxy-net as an external overlay.
|
|
# Future Swarm services join this network to be discoverable by kop.
|
|
# This network is separate from the bridge of the same name on Heimdall.
|
|
# WHY attachable: allows standalone containers to join for debugging.
|
|
# --------------------------------------------------
|
|
|
|
- name: Ensure proxy-net overlay network exists on Swarm
|
|
community.docker.docker_network:
|
|
name: "{{ edge_routing.swarm.proxy_network }}"
|
|
driver: overlay
|
|
attachable: true
|
|
state: present
|
|
when: inventory_hostname == groups['swarm_managers'][0]
|
|
tags: [network]
|
|
|
|
# --------------------------------------------------
|
|
# STEP 3: Verify Redis is reachable from manager
|
|
# WHY: Fail fast before deploying — if kop can't reach Redis, the
|
|
# container will start but immediately fail to publish routes.
|
|
# --------------------------------------------------
|
|
|
|
- name: Verify Redis on Heimdall is reachable from Swarm manager
|
|
ansible.builtin.wait_for:
|
|
host: "{{ edge_routing.edge_host.ip }}"
|
|
port: 6379
|
|
timeout: 10
|
|
state: started
|
|
when: inventory_hostname == groups['swarm_managers'][0]
|
|
tags: [preflight]
|
|
|
|
# --------------------------------------------------
|
|
# STEP 4: Deploy traefik-kop stack
|
|
# WHY swarm_stack_deploy role: handles template render, compose validation,
|
|
# docker stack deploy idempotently, and external network pre-checks.
|
|
# --------------------------------------------------
|
|
|
|
- name: Deploy traefik-kop stack
|
|
ansible.builtin.include_role:
|
|
name: swarm_stack_deploy
|
|
vars:
|
|
stack_name: "traefik-kop"
|
|
stack_compose_src: "{{ playbook_dir }}/../../templates/stacks/traefik-kop.stack.yml"
|
|
stack_state: "{{ traefik_kop_stack_state }}"
|
|
stack_required_external_networks:
|
|
- "{{ edge_routing.swarm.proxy_network }}"
|
|
stack_required_directories: []
|
|
when: inventory_hostname == groups['swarm_managers'][0]
|
|
tags: [deploy]
|
|
|
|
# --------------------------------------------------
|
|
# STEP 5: Verify the service is running
|
|
# --------------------------------------------------
|
|
|
|
- name: Wait for traefik-kop service to converge
|
|
ansible.builtin.command: >
|
|
docker service ls --filter name=traefik-kop_traefik-kop --format '{{ "{{" }}.Replicas{{ "}}" }}'
|
|
register: _kop_replicas
|
|
retries: 6
|
|
delay: 5
|
|
until: _kop_replicas.stdout is search('1/1')
|
|
changed_when: false
|
|
when:
|
|
- inventory_hostname == groups['swarm_managers'][0]
|
|
- traefik_kop_stack_state == 'present'
|
|
- not ansible_check_mode
|
|
tags: [verify]
|
|
|
|
- name: Report deployment result
|
|
ansible.builtin.debug:
|
|
msg:
|
|
- "================================================"
|
|
- "traefik-kop deployment complete."
|
|
- "================================================"
|
|
- "Stack : traefik-kop"
|
|
- "Manager : {{ inventory_hostname }} ({{ ansible_host | default('') }})"
|
|
- "Redis : {{ edge_routing.integration.redis_addr }}"
|
|
- "Bind IP : {{ edge_routing.swarm.bind_ip }}"
|
|
- "Network : {{ edge_routing.swarm.proxy_network }} (overlay)"
|
|
- "------------------------------------------------"
|
|
- "To verify routes in Redis, run on Heimdall:"
|
|
- " docker exec redis redis-cli keys 'traefik/*'"
|
|
- "================================================"
|
|
when: inventory_hostname == groups['swarm_managers'][0]
|
|
tags: [always]
|