Playbooks

Playbooks são arquivos YAML que definem como serviços devem ser deployados. Funcionam como templates executáveis que carregam a lógica de deployment.

Nota: Playbooks usam a sintaxe DPL (DeployAlly Playbook Language). Consulte a referência DPL para detalhes de sintaxe, tipos de input, interpolação e condicionais.

Visão Geral

Um playbook contém:

  • Metadata: Identificação e descrição
  • Taxonomia: Posição na hierarquia
  • Dependencies: Relações com outros serviços
  • Rules: Lógica condicional de deployment
  • Profiles: Configurações por ambiente
  • Inputs: Parâmetros fornecidos pelo usuário
  • Key Files: Arquivos de configuração gerenciados
  • Volumes, Ports, Networks: Configuração Docker

Estrutura Completa

version: "1.0"
kind: Asset | Application | Infrastructure | Composite

metadata:
  name: MySQL Database Server
  slug: mysql
  type: database
  category: assets
  description: Banco de dados relacional MySQL
  version: "8.4"
  priority: 5

taxonomy:
  kingdom: assets
  family: database
  species: mysql
  variant: standard
  specimen: "8.4"

dependencies:
  assets: []
  applications: []

rules:
  - name: singleton_check
    when: ...
    then: ...

profiles:
  minimal: ...
  development: ...
  production: ...

image:
  repository: mysql
  tag: "8.4"

inputs:
  required: ...
  optional: ...
  advanced: ...

key_files:
  - name: mysql_config
    container_path: /etc/mysql/conf.d/custom.cnf
    template: ...

volumes:
  - name: data
    mount_path: /var/lib/mysql

ports:
  - name: mysql
    container_port: 3306

network:
  name: mysql
  driver: bridge

healthcheck:
  type: tcp
  port: 3306

pre_deploy: []
post_deploy: []
upgrade: {}

Seções Detalhadas

Metadata

Identificação do playbook:

metadata:
  name: MySQL Database Server      # Nome amigável
  slug: mysql                       # Identificador único
  type: database                    # Tipo do serviço
  category: assets                  # Categoria
  description: Banco de dados...    # Descrição
  version: "8.4"                    # Versão do template
  priority: 5                       # Ordem de deploy (menor = primeiro)

Priority:

  • 1-4: Infrastructure (Traefik, networks)
  • 5-10: Assets (MySQL, Redis, PostgreSQL)
  • 20+: Applications (WordPress, n8n)

Dependencies

Define relações com outros serviços. Dois tipos:

Assets (Infraestrutura Compartilhada)

Serviços que podem ser compartilhados entre aplicações:

dependencies:
  assets:
    - slug: mysql
      optional: false
      check:
        type: container
        label: "da_type=mysql"
      provision:
        action: prompt              # prompt | auto | fail
        template: mysql
        message: "MySQL não encontrado. Criar agora?"
      exports:
        - from: container.name
          to: WORDPRESS_DB_HOST
        - from: MYSQL_DATABASE
          to: WORDPRESS_DB_NAME
        - from: MYSQL_PASSWORD
          to: WORDPRESS_DB_PASSWORD
          secret: true

Applications (Dependências Específicas)

Outras aplicações necessárias:

dependencies:
  applications:
    - slug: api-gateway
      optional: true

Alternativas

Quando há múltiplas opções (ex: PostgreSQL ou MySQL):

dependencies:
  assets:
    - slug: database
      alternatives:
        - slug: postgresql
          exports:
            - from: container.name
              to: DB_POSTGRESDB_HOST
        - slug: mysql
          exports:
            - from: container.name
              to: DB_MYSQLDB_HOST
      provision:
        action: prompt
        message: "Qual database usar?"
        options:
          - label: "PostgreSQL (recomendado)"
            template: postgresql
          - label: "MySQL"
            template: mysql

Dependência Opcional com Fallback

- slug: redis
  optional: true
  check:
    type: container
    label: "da_type=redis"
  provision:
    action: prompt
    message: "Redis melhora performance. Adicionar?"
  fallback:
    env:
      CACHE_TYPE: "file"
  when_present:
    env:
      CACHE_TYPE: "redis"
      REDIS_HOST: "{{REDIS_HOST}}"

Rules (Motor de Lógica)

Rules executam em ordem e podem tomar decisões automaticamente:

rules:
  - name: detect_production
    when:
      any:
        - env.ENVIRONMENT == "production"
        - context.domain not contains "dev."
    then:
      set_profile: production
      set:
        restart_policy: always
        resources.memory.limit: "{{profiles.production.memory}}"

  - name: singleton_check
    when:
      all:
        - context.containers_with_label("da_type=mysql").count > 0
    then:
      action: prompt
      message: "MySQL já existe. O que fazer?"
      options:
        - label: "Criar nova instância"
          action: update
          set:
            inputs.MYSQL_DATABASE: "{{inputs.MYSQL_DATABASE}}_{{context.generate_id(4)}}"
        - label: "Usar existente"
          action: abort

  - name: port_conflict
    when:
      all:
        - context.port_in_use(3306)
    then:
      action: prompt
      message: "Porta 3306 em uso. Como resolver?"
      options:
        - label: "Usar porta aleatória"
          set:
            ports.external: 0
        - label: "Parar container existente"
          action: stop_container

Ações disponíveis:

  • prompt: Perguntar ao usuário
  • auto: Executar automaticamente
  • warn: Mostrar aviso
  • require_input: Exigir valor
  • fail: Abortar deployment

Context Variables:

  • context.containers_with_label(...): Listar containers
  • context.port_in_use(port): Verificar porto
  • context.network_exists(name): Verificar network
  • context.server.memory_available: RAM disponível
  • context.traefik_available: Traefik rodando?

Profiles

Configurações pré-definidas para diferentes ambientes:

profiles:
  minimal:
    description: Configuração mínima para testes
    resources:
      memory: "128M"
    ports:
      expose: none
    volumes:
      persistent: false

  development:
    description: Configuração para desenvolvimento
    resources:
      memory: "256M"
    ports:
      expose: localhost
      external: 3306
      bind: "127.0.0.1"
    volumes:
      persistent: true
    environment:
      override:
        LOG_LEVEL: "DEBUG"

  production:
    description: Configuração para produção
    resources:
      memory: "512M"
      cpu: 1.0
    ports:
      expose: internal
    volumes:
      persistent: true
      backup: true
    restart_policy: always
    environment:
      override:
        LOG_LEVEL: "WARNING"

Inputs

Valores fornecidos pelo usuário durante deploy:

inputs:
  required:
    MYSQL_ROOT_PASSWORD:
      type: password
      label: Senha do root
      description: Senha do usuário root do MySQL
      secret: true
      validation: "^.{8,}$"
      generate:
        type: password
        length: 24

    MYSQL_DATABASE:
      type: string
      label: Nome do banco
      validation: "^[a-z][a-z0-9_]*$"
      validation_message: "Use apenas letras minúsculas, números e underscore"

  optional:
    MYSQL_USER:
      type: string
      label: Usuário do banco
      default: "app"
      profiles:
        development: "dev_user"
        production: "app_user"

  advanced:
    MAX_CONNECTIONS:
      type: number
      label: Conexões máximas
      default: 100
      profiles:
        minimal: 10
        production: 500

Tipos suportados:

  • password: Senha (oculta, secret)
  • string: Texto
  • number: Número inteiro
  • boolean: Checkbox
  • select: Dropdown com opções

Geração automática:

generate:
  type: password | uuid | slug
  length: 24
  charset: alphanumeric | hex | base64

Key Files

Arquivos de configuração gerenciados pelo DeployAlly:

key_files:
  - name: mysql_config
    description: Arquivo my.cnf customizado
    container_path: /etc/mysql/conf.d/custom.cnf
    mode: ro
    template: |
      [mysqld]
      innodb_buffer_pool_size = {{system.memory_mb | percent: 60}}M
      max_connections = {{inputs.MAX_CONNECTIONS | default: 100}}

    examples:
      - name: "Alta Performance"
        description: Configuração otimizada para produção
        content: |
          [mysqld]
          innodb_buffer_pool_size = 1G
          innodb_log_file_size = 256M
          max_connections = 500

      - name: "Baixo Consumo"
        description: Configuração para ambientes limitados
        content: |
          [mysqld]
          innodb_buffer_pool_size = 128M
          max_connections = 50

Template Filters:

{{system.memory_mb | percent: 60}}              # 60% da RAM
{{system.memory_mb | percent: 60 | min: 256}}   # Mínimo 256
{{system.cpus | multiply: 2}}                   # CPUs * 2
{{inputs.VALUE | default: "fallback"}}          # Valor padrão

Fluxo de Key Files:

  1. Deploy: Usuário escolhe template, exemplo ou arquivo próprio
  2. Storage: Salvo em /opt/deployally/{uid}/files/{name}
  3. Mount: Montado read-only no container
  4. Update: deployally update permite editar (backup automático)

Volumes

volumes:
  - name: data
    mount_path: /var/lib/mysql
    size: 10Gi
    persistent: true
    backup: true

  - name: config
    mount_path: /etc/mysql/conf.d
    type: config
    mode: ro

  - name: logs
    mount_path: /var/log/mysql
    type: bind
    host_path: /var/log/mysql-{{instance_id}}

Tipos:

  • named: Volume Docker nomeado (padrão)
  • bind: Bind mount do host
  • config: Arquivo de configuração
  • tmpfs: Em memória

Ports

ports:
  - name: mysql
    container_port: 3306
    expose: true
    protocol: TCP
    external: 3306              # Porta do host (0 = aleatória)
    bind: "0.0.0.0"            # IP para bind

  - name: admin
    container_port: 33060
    expose: false               # Não expor externamente

Network

network:
  name: mysql
  driver: bridge
  aliases:
    - mysql
    - db
    - database
  join:
    - public

Padrão de Networks:

  • Cada Asset cria sua própria network
  • Applications juntam a múltiplas networks
  • Exemplo: WordPress junta public, mysql, redis

Healthcheck

healthcheck:
  type: tcp | http | exec
  port: 3306                    # Para tcp
  path: /health                 # Para http
  command: ["mysqladmin", "ping"]  # Para exec
  initial_delay: 30
  interval: 10
  timeout: 5
  retries: 3

Lifecycle Hooks

Pre-Deploy

pre_deploy:
  - name: create_network
    action: docker_network
    network_name: "{{network.name}}"
    condition: "not context.network_exists(network.name)"

  - name: backup_existing
    action: shell
    command: "docker exec {{container}} mysqldump --all-databases > /backup/pre-upgrade.sql"
    condition: "context.upgrading"

Post-Deploy

post_deploy:
  - name: wait_healthy
    action: wait_healthy
    timeout: 60s

  - name: run_migrations
    action: exec
    command: "mysql < /docker-entrypoint-initdb.d/migrations.sql"
    condition: "context.has_migrations"

  - name: show_credentials
    action: display
    message: |
      MySQL disponível em: {{container.name}}:3306
      Database: {{inputs.MYSQL_DATABASE}}
      User: {{inputs.MYSQL_USER}}

Ações de Hook:

  • docker_network: Criar network
  • shell: Executar no host
  • exec: Executar no container
  • wait_healthy: Aguardar healthcheck
  • test_connection: Testar conexão
  • display: Mostrar mensagem

Upgrade Strategy

upgrade:
  strategy: rolling | replace | blue-green
  backup_before: true
  rollback_on_fail: true
  preserve_data: true

  post_upgrade:
    - action: exec
      command: "mysql_upgrade"
      condition: "context.major_version_change"

Playbooks Disponíveis

Playbook Kind Dependencies Descrição
mysql.yaml Asset Nenhuma MySQL 8.4, 5.7
postgresql.yaml Asset Nenhuma PostgreSQL 16
redis.yaml Asset Nenhuma Redis 7 Alpine
traefik.yaml Infrastructure Nenhuma (singleton) Reverse proxy + SSL
wordpress.yaml Application MySQL, Redis (opt) WordPress CMS
n8n.yaml Application PostgreSQL/MySQL, Redis (opt) Workflow automation
mautic.yaml Application MySQL Marketing automation
chatwoot.yaml Application PostgreSQL, Redis Helpdesk

Exemplo Completo: WordPress

version: "1.0"
kind: Application

metadata:
  name: WordPress
  slug: wordpress
  type: cms
  category: applications
  description: WordPress CMS com suporte a Redis
  version: "6"
  priority: 20

taxonomy:
  kingdom: applications
  family: cms
  species: wordpress
  variant: standard
  specimen: "6"

dependencies:
  assets:
    - slug: mysql
      optional: false
      check:
        type: container
        label: "da_type=mysql"
      provision:
        action: prompt
        template: mysql
      exports:
        - from: container.name
          to: WORDPRESS_DB_HOST
        - from: MYSQL_DATABASE
          to: WORDPRESS_DB_NAME
        - from: MYSQL_USER
          to: WORDPRESS_DB_USER
        - from: MYSQL_PASSWORD
          to: WORDPRESS_DB_PASSWORD
          secret: true

    - slug: redis
      optional: true
      check:
        type: container
        label: "da_type=redis"
      provision:
        action: prompt
        message: "Redis melhora performance. Adicionar?"
      fallback:
        env:
          WP_CACHE_TYPE: "file"
      when_present:
        env:
          WP_CACHE_TYPE: "redis"
          WP_REDIS_HOST: "{{REDIS_HOST}}"

rules:
  - name: detect_production
    when:
      all:
        - inputs.WORDPRESS_DOMAIN not contains "dev."
    then:
      set_profile: production

  - name: configure_traefik
    when:
      all:
        - inputs.WORDPRESS_DOMAIN is not empty
        - context.traefik_available
    then:
      action: auto
      set:
        labels:
          "traefik.enable": "true"
          "traefik.http.routers.wp-{{instance_id}}.rule": "Host(`{{inputs.WORDPRESS_DOMAIN}}`)"
          "traefik.http.routers.wp-{{instance_id}}.tls.certresolver": "myresolver"

profiles:
  development:
    resources:
      memory: "256M"
    environment:
      WP_DEBUG: "true"

  production:
    resources:
      memory: "512M"
    environment:
      WP_DEBUG: "false"

image:
  repository: wordpress
  tag: "6-php8.2-apache"

inputs:
  required:
    WORDPRESS_DOMAIN:
      type: string
      label: Domínio do site
      validation: "^[a-z0-9][a-z0-9.-]+\\.[a-z]{2,}$"

  optional:
    WORDPRESS_TABLE_PREFIX:
      type: string
      label: Prefixo das tabelas
      default: "wp_"

volumes:
  - name: wp-content
    mount_path: /var/www/html/wp-content
    persistent: true

ports:
  - name: http
    container_port: 80
    expose: false

network:
  name: public
  join:
    - mysql
    - redis

healthcheck:
  type: http
  path: /wp-admin/install.php
  port: 80
  initial_delay: 30

post_deploy:
  - name: show_info
    action: display
    message: |
      WordPress disponível em: https://{{inputs.WORDPRESS_DOMAIN}}
      Complete a instalação no navegador.

Próximos Passos

By Borlot.com.br on 13/02/2026