Ver Fonte

feat(compose): simplify Docker Swarm placement with unified variable (#1359)

- Replace swarm_placement_mode and swarm_placement_host with single swarm_placement variable
- Support three modes: 'replicated', 'global', or custom constraints (e.g., 'node.hostname==myhost')
- Add default value 'replicated' in module spec to avoid empty string validation issues
- Update Traefik template to use new unified placement variable with 'global' default

feat(traefik): improve secret management for Cloudflare API tokens

- Create .env.secret file containing only the API token
- Use CF_API_TOKEN_FILE approach for both standard and Swarm modes
- Mount .env.secret as volume in standard mode, Docker secret in Swarm mode
- Consistent secret handling across deployment modes

feat(traefik): add configurable HTTP/HTTPS ports

- Add traefik_http_port (default: 80) and traefik_https_port (default: 443)
- Move traefik_dashboard_enabled to traefik section for better organization
- Keep dashboard port (8080) hardcoded but conditional on ports_enabled

Closes #1359
xcad há 6 meses atrás
pai
commit
bd467584c2

+ 4 - 8
cli/modules/compose.py

@@ -145,15 +145,11 @@ spec = OrderedDict(
             "type": "int",
             "default": 1,
           },
-          "swarm_placement_mode": {
-            "description": "Swarm placement mode",
-            "type": "enum",
-            "options": ["global", "replicated"],
-            "default": "replicated"
-          },
-          "swarm_placement_host": {
-            "description": "Limit placement to specific node",
+          "swarm_placement": {
+            "description": "Swarm placement mode or node constraint",
             "type": "str",
+            "default": "replicated",
+            "extra": "Options: 'replicated', 'global', or 'node.hostname==myhost' for custom placement",
           }
         },
       },

+ 3 - 19
library/compose/traefik/.env.j2

@@ -1,21 +1,5 @@
 # Traefik Environment Variables
-# This file contains sensitive credentials for ACME DNS providers
-
-{% if traefik_tls_enabled %}
-# ACME DNS Challenge Configuration
-{% if traefik_tls_acme_provider == "cloudflare" %}
-# Cloudflare API Token
-# Required permissions: Zone:DNS:Edit
-# Create token at: https://dash.cloudflare.com/profile/api-tokens
-{% if swarm_enabled %}
-# Swarm mode: API token read from Docker secret
-CF_DNS_API_TOKEN_FILE=/run/secrets/{{ traefik_tls_acme_secret_name }}
-{% else %}
-# Standard mode: API token from environment variable
-CF_API_TOKEN={{ traefik_tls_acme_token }}
-{% endif %}
-{% endif %}
-
-{% else %}
-# ACME/TLS is disabled - no DNS provider credentials needed
+# Reference to secret file containing API token
+{% if traefik_tls_enabled and traefik_tls_acme_provider == "cloudflare" %}
+CF_API_TOKEN_FILE=/.env.secret
 {% endif %}

+ 1 - 0
library/compose/traefik/.env.secret.j2

@@ -0,0 +1 @@
+{% if traefik_tls_enabled %}{{ traefik_tls_acme_token }}{% endif %}

+ 16 - 8
library/compose/traefik/compose.yaml.j2

@@ -1,6 +1,6 @@
 services:
   {{ service_name }}:
-    image: docker.io/library/traefik:v3.2
+    image: docker.io/library/traefik:v3.5.3
     {% if not swarm_enabled %}
     container_name: {{ container_name }}
     {% endif %}
@@ -16,7 +16,10 @@ services:
       - /var/run/docker.sock:/var/run/docker.sock:ro
       - ./config/:/etc/traefik/:ro
       - ./certs/:/var/traefik/certs/:rw
-    {% if traefik_tls_enabled %}
+      {% if traefik_tls_enabled %}
+      {% if not swarm_enabled %}
+      - ./.env.secret:/.env.secret:ro
+      {% endif %}
     env_file:
       - ./.env
     {% endif %}
@@ -35,17 +38,22 @@ services:
     {% if swarm_enabled %}
     {% if traefik_tls_enabled %}
     secrets:
-      - {{ traefik_tls_acme_secret_name }}
+      - source: {{ traefik_tls_acme_secret_name }}
+        target: /.env.secret
+        mode: 0400
     {% endif %}
     deploy:
-      mode: {{ swarm_placement_mode }}
-      {% if swarm_placement_mode == 'replicated' %}
+      {% if swarm_placement in ['global', 'replicated'] %}
+      mode: {{ swarm_placement }}
+      {% if swarm_placement == 'replicated' %}
       replicas: {{ swarm_replicas }}
       {% endif %}
-      {% if swarm_placement_host %}
+      {% else %}
+      mode: replicated
+      replicas: {{ swarm_replicas }}
       placement:
         constraints:
-          - {{ swarm_placement_host }}
+          - {{ swarm_placement }}
       {% endif %}
     {% else %}
     restart: {{ restart_policy }}
@@ -54,7 +62,7 @@ services:
 {% if swarm_enabled and traefik_tls_enabled %}
 secrets:
   {{ traefik_tls_acme_secret_name }}:
-    external: true
+    file: ./.env.secret
 {% endif %}
 
 {% if network_enabled %}

+ 18 - 22
library/compose/traefik/template.yaml

@@ -10,7 +10,7 @@ metadata:
     Project: https://traefik.io/
 
     Documentation: https://doc.traefik.io/traefik/
-  version: v3.2
+  version: v3.5.3
   author: "Christian Lempa"
   date: "2025-10-02"
   tags:
@@ -56,7 +56,7 @@ metadata:
        - Review and limit network exposure
 
     For more information, visit: https://doc.traefik.io/traefik/
-  draft: true
+  draft: false
 spec:
   general:
     title: "General"
@@ -80,16 +80,11 @@ spec:
         description: "HTTP entrypoint name (non-TLS)"
         default: "web"
         extra: "Standard HTTP traffic on port 80"
-      traefik_tls_entrypoint:
-        type: "str"
-        description: "HTTPS entrypoint name (TLS)"
-        default: "websecure"
-        extra: "Secure HTTPS traffic on port 443"
-      traefik_tls_certresolver:
-        type: "str"
-        description: "Certificate resolver name"
-        default: "cloudflare"
-        extra: "Must match the certificateResolvers name in traefik.yaml"
+      traefik_dashboard_enabled:
+        type: "bool"
+        description: "Enable Traefik dashboard (insecure mode)"
+        default: false
+        extra: "WARNING: Don't use in production! Exposes dashboard on port 8080"
   traefik_tls:
     title: "Traefik TLS Settings"
     description: "Configure TLS/SSL with Let's Encrypt ACME"
@@ -128,11 +123,16 @@ spec:
   ports:
     toggle: "ports_enabled"
     vars:
-      traefik_dashboard_enabled:
-        type: "bool"
-        description: "Enable Traefik dashboard (don't use in production)"
-        default: false
-        extra: "Exposes dashboard on port 8080 in insecure mode"
+      traefik_http_port:
+        type: "int"
+        description: "HTTP port (external)"
+        default: 80
+        extra: "Maps to entrypoint 'web' (port 80)"
+      traefik_https_port:
+        type: "int"
+        description: "HTTPS port (external)"
+        default: 443
+        extra: "Maps to entrypoint 'websecure' (port 443)"
   network:
     vars:
       network_enabled:
@@ -141,12 +141,8 @@ spec:
         default: "proxy"
   swarm:
     vars:
-      swarm_placement_mode:
+      swarm_placement:
         default: "global"
-      swarm_placement_host:
-        type: str
-        description: "Placement constraint for node selection (optional)"
-        default: ""
   authentik:
     title: Authentik Middleware
     description: Enable Authentik SSO integration for Traefik