Tags & Limits

What are Tags? Tags allow you to selectively execute specific portions of a playbook rather than running everything. They provide fine-grained control over which tasks run, making it easy to run maintenance operations, deploy specific components, or skip certain tasks without modifying playbook code.

Understanding Tags

Why Use Tags?

Tags solve common automation challenges:

  • Selective Execution: Run only database tasks in a full-stack deployment
  • Skip Operations: Bypass slow or unnecessary tasks during development
  • Maintenance Windows: Run only backup or monitoring tasks
  • Development Workflows: Test specific components without full deployment
  • Conditional Runs: Execute tasks based on operational needs

Tag Workflow

Using tags is a two-step process:

  1. Add Tags: Apply tags to tasks, blocks, plays, roles, or imports
  2. Select Tags: Use command-line options to run or skip tagged tasks

Adding Tags to Playbooks

Tagging Individual Tasks

Apply tags directly to tasks:

---
- name: Deploy web application
  hosts: webservers
  tasks:
    - name: Install packages
      ansible.builtin.yum:
        name:
          - httpd
          - php
          - php-mysql
        state: present
      tags:
        - packages
        - install

    - name: Copy configuration files
      ansible.builtin.copy:
        src: httpd.conf
        dest: /etc/httpd/conf/httpd.conf
      tags:
        - config
        - configuration

    - name: Start Apache service
      ansible.builtin.service:
        name: httpd
        state: started
        enabled: true
      tags:
        - service
        - httpd

    - name: Deploy application code
      ansible.builtin.git:
        repo: https://github.com/company/webapp.git
        dest: /var/www/html
        version: main
      tags:
        - deploy
        - application

Tagging Blocks

Apply tags to multiple tasks at once:

---
- name: Database setup
  hosts: databases
  tasks:
    - name: Database configuration
      tags:
        - database
        - db
      block:
        - name: Install PostgreSQL
          ansible.builtin.yum:
            name: postgresql-server
            state: present

        - name: Initialize database
          ansible.builtin.command: postgresql-setup initdb
          args:
            creates: /var/lib/pgsql/data/PG_VERSION

        - name: Configure authentication
          ansible.builtin.copy:
            src: pg_hba.conf
            dest: /var/lib/pgsql/data/pg_hba.conf

        - name: Start PostgreSQL
          ansible.builtin.service:
            name: postgresql
            state: started
            enabled: true

Tagging Plays

Apply tags to entire plays:

---
- name: Web server setup
  hosts: webservers
  tags:
    - webserver
    - web
  tasks:
    - name: Install nginx
      ansible.builtin.yum:
        name: nginx
        state: present

    - name: Configure nginx
      ansible.builtin.template:
        src: nginx.conf.j2
        dest: /etc/nginx/nginx.conf

- name: Application deployment
  hosts: webservers
  tags:
    - application
    - deploy
  tasks:
    - name: Clone repository
      ansible.builtin.git:
        repo: https://github.com/company/app.git
        dest: /opt/app

    - name: Install dependencies
      ansible.builtin.pip:
        requirements: /opt/app/requirements.txt

Tagging Roles

Apply tags to imported or included roles:

---
- name: Full infrastructure setup
  hosts: all
  roles:
    - role: common
      tags:
        - common
        - base

    - role: security
      tags:
        - security
        - hardening

    - role: monitoring
      tags:
        - monitoring
        - observability

    - role: webserver
      tags:
        - webserver
        - nginx

Tagging Imports and Includes

---
- name: Complex deployment
  hosts: all
  tasks:
    - name: Common tasks
      ansible.builtin.import_tasks: common.yml
      tags:
        - common
        - always

    - name: Database tasks
      ansible.builtin.import_tasks: database.yml
      tags:
        - database
        - db

    - name: Dynamic web configuration
      ansible.builtin.include_tasks: "{{ item }}"
      loop:
        - web_config.yml
        - ssl_setup.yml
      tags:
        - web
        - config

Special Tags

always Tag

Tasks tagged with always run unless explicitly skipped:

---
- name: Application deployment
  hosts: webservers
  tasks:
    - name: Check prerequisites
      ansible.builtin.command: which python3
      tags:
        - always
      changed_when: false

    - name: Install application
      ansible.builtin.yum:
        name: myapp
        state: present
      tags:
        - install

    - name: Send notification
      ansible.builtin.uri:
        url: https://hooks.slack.com/services/YOUR/WEBHOOK
        method: POST
        body_format: json
        body:
          text: "Deployment completed"
      tags:
        - always
      delegate_to: localhost

Run playbook skipping non-tagged tasks:

# Only 'always' tasks run
ansible-playbook site.yml --tags never

# Skip 'always' tasks
ansible-playbook site.yml --skip-tags always

never Tag

Tasks tagged with never only run when explicitly requested:

---
- name: Database management
  hosts: databases
  tasks:
    - name: Regular backup
      ansible.builtin.command: pg_dump mydb > /backup/mydb.sql
      tags:
        - backup

    - name: DANGEROUS - Drop database
      community.postgresql.postgresql_db:
        name: mydb
        state: absent
      tags:
        - never
        - destroy

    - name: DANGEROUS - Delete all data
      ansible.builtin.file:
        path: /var/lib/postgresql/data
        state: absent
      tags:
        - never
        - destroy
        - purge

Explicitly run never-tagged tasks:

# Must explicitly request 'never' tasks
ansible-playbook database.yml --tags destroy

tagged and untagged

Built-in special tags for filtering:

# Run only tasks with at least one tag
ansible-playbook site.yml --tags tagged

# Run only tasks without any tags
ansible-playbook site.yml --tags untagged

all Tag

Default behavior - runs all tasks except those tagged never:

# Equivalent commands (default behavior)
ansible-playbook site.yml
ansible-playbook site.yml --tags all

Running Tagged Tasks

Run Specific Tags

# Run tasks with single tag
ansible-playbook site.yml --tags configuration

# Run tasks with multiple tags (OR logic)
ansible-playbook site.yml --tags "packages,config"

# Tasks with 'packages' OR 'config' tag will run

Skip Specific Tags

# Skip tasks with specific tag
ansible-playbook site.yml --skip-tags testing

# Skip multiple tags
ansible-playbook site.yml --skip-tags "backup,monitoring"

Combine Tags and Skip-Tags

# Run web tasks but skip deployment
ansible-playbook site.yml --tags web --skip-tags deploy

# Note: skip-tags takes precedence over tags
Tag Precedence: When both --tags and --skip-tags are specified, skip-tags always takes precedence. If a task matches both, it will be skipped.

Listing Tags

View All Available Tags

# List all tags in playbook
ansible-playbook site.yml --list-tags

# Output example:
# playbook: site.yml
#
#   play #1 (webservers): Deploy web application
#     TAGS: [web, webserver]
#
#   play #2 (databases): Database setup
#     TAGS: [database, db]
#
# TASK TAGS: [application, backup, config, database, db,
#            deploy, install, packages, service, web, webserver]

Preview Tagged Tasks

# List tasks that would run with specific tags
ansible-playbook site.yml --tags config --list-tasks

# Output shows which tasks will execute:
# playbook: site.yml
#
#   play #1 (webservers): Deploy web application  TAGS: [web]
#     tasks:
#       Copy configuration files  TAGS: [config, configuration]
#
#   play #2 (databases): Database setup  TAGS: [database]
#     tasks:
#       Configure authentication  TAGS: [config, database]

Limiting Execution

Limit by Host Pattern

Combine tags with host limits for precise control:

# Run config tasks only on web01
ansible-playbook site.yml --tags config --limit web01

# Run database tasks on db servers in production
ansible-playbook site.yml --tags database --limit "databases:&production"

# Run on all except one host
ansible-playbook site.yml --limit "all:!problematic-host"

# Run on hosts matching pattern
ansible-playbook site.yml --limit "web*.example.com"

Limit by Group

# Run only on webservers group
ansible-playbook site.yml --limit webservers

# Run on multiple groups
ansible-playbook site.yml --limit "webservers:databases"

# Intersection of groups (hosts in both)
ansible-playbook site.yml --limit "webservers:&production"

Limit by Failed Hosts

# First run that might fail
ansible-playbook site.yml

# Creates retry file: site.retry with failed hosts

# Retry only failed hosts
ansible-playbook site.yml --limit @site.retry

Tag Inheritance

How Tags Cascade

Tags applied at higher levels automatically cascade to child elements:

---
- name: Infrastructure setup
  hosts: all
  tags:
    - infrastructure  # Applies to all tasks in this play
  tasks:
    - name: Update system
      ansible.builtin.yum:
        name: "*"
        state: latest
      # This task has 'infrastructure' tag automatically

    - name: Install security tools
      ansible.builtin.yum:
        name: aide
        state: present
      tags:
        - security  # This task has both 'infrastructure' and 'security'

Block Tag Inheritance

---
- name: Web configuration
  hosts: webservers
  tasks:
    - name: SSL setup
      tags:
        - ssl
        - security
      block:
        - name: Install mod_ssl
          ansible.builtin.yum:
            name: mod_ssl
            state: present
          # Inherits: ssl, security

        - name: Generate certificate
          ansible.builtin.command: openssl req -new -x509 -days 365 -nodes...
          tags:
            - certificates  # Has: ssl, security, certificates
          args:
            creates: /etc/pki/tls/certs/localhost.crt

Role Tag Inheritance

---
- name: Apply roles
  hosts: all
  roles:
    - role: common
      tags:
        - base
      # All tasks in 'common' role inherit 'base' tag

    - role: apache
      tags:
        - webserver
        - apache
      # All tasks in 'apache' role inherit both tags

Advanced Tag Patterns

Maintenance Tasks Pattern

---
- name: Application lifecycle
  hosts: webservers
  tasks:
    # Normal operations
    - name: Deploy application
      ansible.builtin.copy:
        src: app.jar
        dest: /opt/app/app.jar
      tags:
        - deploy
        - application

    # Maintenance operations (never run by default)
    - name: Clear cache
      ansible.builtin.file:
        path: /var/cache/app
        state: absent
      tags:
        - never
        - maintenance
        - cache

    - name: Rotate logs
      ansible.builtin.command: logrotate -f /etc/logrotate.d/app
      tags:
        - never
        - maintenance
        - logs

    - name: Vacuum database
      ansible.builtin.command: vacuumdb --all
      tags:
        - never
        - maintenance
        - database

# Normal deployment (cache/logs/vacuum not run)
# ansible-playbook site.yml --tags deploy

# Maintenance mode (only maintenance tasks)
# ansible-playbook site.yml --tags maintenance

Environment-Specific Pattern

---
- name: Multi-environment deployment
  hosts: all
  tasks:
    - name: Deploy to staging
      ansible.builtin.git:
        repo: https://github.com/company/app.git
        dest: /opt/app
        version: develop
      tags:
        - deploy
        - staging
      when: environment == "staging"

    - name: Deploy to production
      ansible.builtin.git:
        repo: https://github.com/company/app.git
        dest: /opt/app
        version: main
      tags:
        - deploy
        - production
      when: environment == "production"

    - name: Run database migrations
      ansible.builtin.command: /opt/app/migrate.sh
      tags:
        - deploy
        - database
        - migrations

# Deploy to staging only
# ansible-playbook site.yml --tags staging -e environment=staging

# Deploy to production only
# ansible-playbook site.yml --tags production -e environment=production

Component-Based Pattern

---
- name: Full stack deployment
  hosts: all
  tasks:
    # Frontend
    - name: Build frontend
      ansible.builtin.command: npm run build
      args:
        chdir: /opt/app/frontend
      tags:
        - frontend
        - ui
        - build

    - name: Deploy frontend
      ansible.builtin.copy:
        src: /opt/app/frontend/dist/
        dest: /var/www/html/
      tags:
        - frontend
        - ui
        - deploy

    # Backend
    - name: Build backend
      ansible.builtin.command: mvn package
      args:
        chdir: /opt/app/backend
      tags:
        - backend
        - api
        - build

    - name: Deploy backend
      ansible.builtin.copy:
        src: /opt/app/backend/target/app.jar
        dest: /opt/services/app.jar
      tags:
        - backend
        - api
        - deploy

    # Database
    - name: Run migrations
      ansible.builtin.command: flyway migrate
      tags:
        - database
        - db
        - migrations

# Deploy only frontend
# ansible-playbook site.yml --tags frontend

# Deploy only backend
# ansible-playbook site.yml --tags backend

# Deploy everything except database
# ansible-playbook site.yml --skip-tags database

Best Practices

Tagging Best Practices:
  • Consistent Naming: Use clear, descriptive tag names across playbooks
  • Multiple Tags: Apply multiple tags to tasks for flexible filtering
  • Hierarchical Tags: Use general and specific tags (deploy, deploy-frontend)
  • Document Tags: Maintain a list of available tags in README
  • Use 'never' Carefully: Tag destructive operations with 'never'
  • Test Tags: Use --list-tasks to verify tag behavior
  • Avoid Over-Tagging: Don't tag every task; focus on logical groupings
  • Combine with Limits: Use tags and limits together for precision

Common Tag Conventions

Tag Purpose Example Usage
always Tasks that always run Prerequisites, notifications, logging
never Dangerous/rare operations Data deletion, service shutdown
install Package installation Installing software packages
config Configuration changes Updating config files
deploy Application deployment Deploying application code
backup Backup operations Database backups, file backups
maintenance Maintenance tasks Cache clearing, log rotation
security Security operations Firewall rules, SSL setup
monitoring Monitoring setup Metrics, alerts, dashboards
testing Test execution Running tests, validation

Common Issues

Tags Not Working

If tags aren't filtering as expected:

  • Use --list-tags to verify tags are applied
  • Check for typos in tag names
  • Remember that --skip-tags takes precedence
  • Verify tasks aren't tagged with always

Unexpected Tasks Running

If unwanted tasks execute:

  • Check for always tags on tasks
  • Verify tag inheritance from plays/blocks
  • Use --list-tasks with your tag selection
  • Remember imported tasks inherit tags

No Tasks Running

If no tasks execute:

  • Verify tag names match exactly (case-sensitive)
  • Check if all tasks are tagged never
  • Ensure you're not skipping all tasks
  • Verify limit pattern matches hosts

Next Steps