D10.6 Πρακτικό παράδειγμα — Production Swarm 🏭

Αρχιτεκτονική

3-node Swarm cluster:

  manager-01 ┐
  manager-02 ├── Manager nodes (Raft quorum)
  manager-03 ┘

  worker-01 ┐
  worker-02 ├── Worker nodes (εκτελούν containers)
  worker-03 ┘

  Services:
  ├── nginx    (3 replicas, workers, ingress :80/:443)
  ├── myapp    (2 replicas, workers)
  ├── postgres (1 replica, manager, volume)
  ├── redis    (1 replica, worker)
  └── node_exporter (global, all nodes)

Full playbook

---
# swarm-production.yml

- name: "Init Swarm cluster"
  import_playbook: setup-swarm.yml

# ─────────────────────────────────────────────────────
- name: "Setup Swarm infrastructure"
  hosts: manager-01
  become: true
  gather_facts: true

  vars:
    app_version: "{{ new_version | mandatory }}"
    app_domain:  "example.com"

  tasks:

    # ════════════════════════════════════════
    # NETWORKS
    # ════════════════════════════════════════
    - name: "🌐 Frontend overlay network"
      community.docker.docker_network:
        name:   frontend
        driver: overlay
        state:  present

    - name: "🌐 Backend overlay network (internal)"
      community.docker.docker_network:
        name:     backend
        driver:   overlay
        state:    present
        internal: true

    # ════════════════════════════════════════
    # SECRETS
    # ════════════════════════════════════════
    - name: "🔐 Database secret"
      community.docker.docker_secret:
        name:  pg_password
        data:  "{{ vault_postgres_pass }}"
        state: present
      no_log: true

    - name: "🔐 App secret"
      community.docker.docker_secret:
        name:  app_secret_key
        data:  "{{ vault_app_secret }}"
        state: present
      no_log: true

    # ════════════════════════════════════════
    # CONFIGS
    # ════════════════════════════════════════
    - name: "⚙️ Nginx config"
      community.docker.docker_config:
        name:  nginx_conf
        data:  "{{ lookup('template', 'templates/nginx.conf.j2') }}"
        state: present

    # ════════════════════════════════════════
    # NODE LABELS
    # ════════════════════════════════════════
    - name: "🏷️ Label manager nodes (storage)"
      ansible.builtin.command:
        cmd: "docker node update --label-add storage=true {{ item }}"
      loop: "{{ groups['swarm_managers'] }}"
      changed_when: true

    # ════════════════════════════════════════
    # SERVICES
    # ════════════════════════════════════════
    - name: "📡 node_exporter (global)"
      community.docker.docker_swarm_service:
        name:    node_exporter
        image:   "prom/node-exporter:v1.7.0"
        state:   present
        mode:    global
        mounts:
          - source: /
            target: /host
            type:   bind
            readonly: true
        publish:
          - published_port: 9100
            target_port:    9100
            mode:           host

    - name: "🐘 PostgreSQL (manager, 1 replica)"
      community.docker.docker_swarm_service:
        name:    postgres
        image:   "postgres:15-alpine"
        state:   present
        replicas: 1
        placement:
          constraints:
            - "node.role == manager"
            - "node.labels.storage == true"
        networks:
          - name: backend
        secrets:
          - secret_name: pg_password
            filename:    /run/secrets/pg_password
        env:
          POSTGRES_PASSWORD_FILE: /run/secrets/pg_password
          POSTGRES_USER:          appuser
          POSTGRES_DB:            myapp
        mounts:
          - source: postgres_data
            target: /var/lib/postgresql/data
            type:   volume

    - name: "🚀 App service (2 replicas, rolling)"
      community.docker.docker_swarm_service:
        name:    myapp
        image:   "myapp:{{ app_version }}"
        state:   present
        replicas: 2
        placement:
          constraints:
            - "node.role == worker"
        networks:
          - name: frontend
          - name: backend
        secrets:
          - secret_name: app_secret_key
            filename:    /run/secrets/secret_key
        env:
          NODE_ENV:    production
          SECRET_FILE: /run/secrets/secret_key
        update_config:
          parallelism:    1
          delay:          15s
          failure_action: rollback
          order:          start-first

    - name: "🌐 Nginx (3 replicas)"
      community.docker.docker_swarm_service:
        name:    nginx
        image:   "nginx:1.25-alpine"
        state:   present
        replicas: 3
        placement:
          constraints:
            - "node.role == worker"
        networks:
          - name: frontend
        configs:
          - config_name: nginx_conf
            filename:    /etc/nginx/nginx.conf
        publish:
          - published_port: 80
            target_port:    80
            mode:           ingress
          - published_port: 443
            target_port:    443
            mode:           ingress
        update_config:
          parallelism: 1
          delay:       10s
          failure_action: rollback

    # ════════════════════════════════════════
    # VERIFICATION
    # ════════════════════════════════════════
    - name: "📊 Service list"
      ansible.builtin.command: >
        docker service ls --format "table {{ '{{' }}.Name{{ '}}' }}\t{{ '{{' }}.Replicas{{ '}}' }}\t{{ '{{' }}.Image{{ '}}' }}"
      register:     services
      changed_when: false

    - name: " Swarm Production Report"
      ansible.builtin.debug:
        msg:
          - "╔══════════════════════════════════════╗"
          - "  🐝 SWARM PRODUCTION DEPLOYED!       ║"
          - "╠══════════════════════════════════════╣"
          - "{{ services.stdout_lines }}"
          - "╚══════════════════════════════════════╝"
# Deploy
ansible-playbook swarm-production.yml \
    -e "new_version=2.5.0" \
    --ask-vault-pass

# Update μόνο app service
ansible-playbook swarm-production.yml \
    -e "new_version=2.6.0" \
    --tags app \
    --ask-vault-pass

Σύνοψη Κεφ. D10

Docker Swarm με Ansible
│
├── D10.1: Concepts (Manager/Worker, Service/Task)
├── D10.2: Setup (init + join managers + join workers)
├── D10.3: Services (replicated/global) + Stacks
├── D10.4: Rolling updates + scaling + rollback
├── D10.5: Secrets (encrypted) + Configs
└── D10.6: Production stack (6 services, 3+3 nodes)

Swarm = Simple HA για Docker → Bridge to Kubernetes