Skip to content

In a Nutshell (🌰)

  • Playbooks in SSM are Ansible-based automation scripts for infrastructure management
  • They provide idempotent, declarative configuration across multiple devices
  • Playbooks can be stored locally or in remote repositories
  • Variables and templates allow for flexible, reusable playbooks
  • Playbooks can be executed manually or triggered by automations

What are Playbooks in SSM?

In Squirrel Servers Manager, playbooks are Ansible-based automation scripts that define a series of tasks to be executed across your infrastructure. Playbooks allow you to automate complex operations, ensure consistent configurations, and manage your devices at scale.

Playbook Architecture Diagram
Figure 1: The Playbook Architecture in SSM

Key Components of the Playbooks Model

1. Playbook Structure

Playbooks are written in YAML and consist of several key elements:

  • Plays: Groups of tasks that run against specific hosts
  • Tasks: Individual actions to be performed
  • Handlers: Tasks that only run when notified by other tasks
  • Roles: Reusable collections of tasks, handlers, and variables
  • Variables: Dynamic values that can be used throughout the playbook
  • Templates: Files with variable placeholders that get filled in during execution

2. Playbook Storage

SSM supports multiple ways to store and manage playbooks:

  • Local Playbooks: Stored directly in SSM

    • Created and edited through the SSM interface
    • Immediately available for execution
    • Version controlled within SSM
  • Remote Playbooks: Stored in external repositories

    • Git repositories (GitHub, GitLab, etc.)
    • Integration with version control systems
    • Collaborative development workflows
    • Automatic synchronization

3. Playbook Execution

Playbooks can be executed in several ways:

  • Manual Execution: Run directly by users

    • Target specific devices or groups
    • Set variables at runtime
    • Monitor execution in real-time
  • Scheduled Execution: Run at specified times

    • Regular maintenance tasks
    • Off-hours operations
    • Recurring configurations

Playbook Lifecycle

Playbooks in SSM follow a defined lifecycle:

  1. Creation: Playbook is written or imported into SSM
  2. Testing: Playbook is tested against development or staging environments
  3. Deployment: Playbook is made available for production use
  4. Execution: Playbook is run against target devices
  5. Monitoring: Execution progress and results are tracked
  6. Maintenance: Playbook is updated as requirements change
  7. Versioning: Changes are tracked through version control

Real-World Examples

Example 1: System Updates and Security Hardening

Problem:

You need to ensure all servers are regularly updated and follow security best practices.

Solution using the Playbooks Model:

yaml
# system_maintenance.yml
- name: System Updates and Security Hardening
  hosts: all
  become: true
  vars:
    security_level: high
    reboot_if_needed: false
    
  tasks:
    - name: Update package cache
      apt:
        update_cache: yes
      when: ansible_os_family == "Debian"
      
    - name: Upgrade all packages
      apt:
        upgrade: dist
      when: ansible_os_family == "Debian"
      
    - name: Install security packages
      apt:
        name:
          - fail2ban
          - ufw
          - unattended-upgrades
        state: present
      when: ansible_os_family == "Debian"
      
    - name: Configure firewall
      ufw:
        rule: allow
        port: "{% raw %}{{ item }}{% endraw %}"
        proto: tcp
      loop:
        - 22
        - 80
        - 443
        
    - name: Enable firewall
      ufw:
        state: enabled
        policy: deny
        
    - name: Configure automatic updates
      template:
        src: auto-updates.j2
        dest: /etc/apt/apt.conf.d/20auto-upgrades
      when: ansible_os_family == "Debian"
      
    - name: Reboot if required
      reboot:
      when: reboot_if_needed and ansible_os_family == "Debian"

This playbook:

  • Updates the package cache
  • Upgrades all installed packages
  • Installs security-related packages
  • Configures and enables a firewall
  • Sets up automatic updates
  • Optionally reboots the system if needed

You can schedule this playbook to run weekly across all your devices, ensuring consistent security practices.

Example 2: Application Deployment

Problem:

You need to deploy a web application across multiple servers with environment-specific configurations.

Solution using the Playbooks Model:

yaml
---
# deploy_webapp.yml
- name: Deploy Web Application
  hosts: web_servers
  become: true
  vars:
    app_version: "1.2.3"
    app_env: production
    app_port: 8080
    db_host: "{% raw %}{{ hostvars['db_server']['ansible_host'] }}{% endraw %}"
    
  tasks:
    - name: Install dependencies
      apt:
        name:
          - nodejs
          - npm
        state: present
      when: ansible_os_family == "Debian"
      
    - name: Create application directory
      file:
        path: /opt/myapp
        state: directory
        owner: www-data
        group: www-data
        mode: '0755'
        
    - name: Download application package
      get_url:
        url: "https://example.com/releases/myapp-{% raw %}{{ app_version }}{% endraw %}.tar.gz"
        dest: /tmp/myapp.tar.gz
        
    - name: Extract application package
      unarchive:
        src: /tmp/myapp.tar.gz
        dest: /opt/myapp
        remote_src: yes
        owner: www-data
        group: www-data
        
    - name: Configure application
      template:
        src: config.js.j2
        dest: /opt/myapp/config.js
      notify: restart application
      
    - name: Create systemd service
      template:
        src: myapp.service.j2
        dest: /etc/systemd/system/myapp.service
      notify: reload systemd
      
    - name: Start and enable application service
      systemd:
        name: myapp
        state: started
        enabled: yes
        
  handlers:
    - name: reload systemd
      systemd:
        daemon_reload: yes
        
    - name: restart application
      systemd:
        name: myapp
        state: restarted

This playbook:

  • Installs required dependencies
  • Creates the application directory
  • Downloads and extracts the application package
  • Configures the application with environment-specific settings
  • Sets up a systemd service for the application
  • Starts and enables the service

You can use this playbook to deploy your application to different environments by changing the variables.

Playbook Patterns

1. Configuration Management

SSH Security Configuration

Ensure consistent SSH security settings across all servers

File: configure_ssh.yml

yaml
---
# configure_ssh.yml
- name: Configure SSH Security
  hosts: all
  become: true
  
  tasks:
    - name: Update SSH configuration
      lineinfile:
        path: /etc/ssh/sshd_config
        regexp: '{% raw %}{{ item.regexp }}{% endraw %}'
        line: '{% raw %}{{ item.line }}{% endraw %}'
        state: present
      loop:
        - { regexp: '^#?PermitRootLogin', line: 'PermitRootLogin no' }
        - { regexp: '^#?PasswordAuthentication', line: 'PasswordAuthentication no' }
        - { regexp: '^#?X11Forwarding', line: 'X11Forwarding no' }
        - { regexp: '^#?MaxAuthTries', line: 'MaxAuthTries 3' }
      notify: restart ssh
      
  handlers:
    - name: restart ssh
      service:
        name: sshd
        state: restarted
  • This playbook targets all hosts in your inventory
  • It uses the lineinfile module to modify specific lines in the SSH configuration
  • The loop allows multiple configuration changes with a single task
  • Changes only happen if the current configuration differs from desired state
  • The handler ensures SSH service is restarted only if configuration changes

2. Application Lifecycle Management

Application Lifecycle Management

Manage the complete lifecycle of applications with a single playbook

File: app_lifecycle.yml

yaml
---
# app_lifecycle.yml
- name: Application Lifecycle Management
  hosts: app_servers
  become: true
  vars:
    app_state: present  # Options: present, absent, updated
    app_version: '2.0.0'
    
  tasks:
    - name: Install application
      block:
        - name: Download application
          get_url:
            url: 'https://example.com/app-{% raw %}{{ app_version }}{% endraw %}.zip'
            dest: '/tmp/app-{% raw %}{{ app_version }}{% endraw %}.zip'
            
        - name: Install application
          unarchive:
            src: '/tmp/app-{% raw %}{{ app_version }}{% endraw %}.zip'
            dest: '/opt/applications/'
            remote_src: yes
      when: app_state == 'present' or app_state == 'updated'
      
    - name: Remove application
      file:
        path: '/opt/applications/app-{% raw %}{{ app_version }}{% endraw %}'
        state: absent
      when: app_state == 'absent'
  • This playbook uses a variable (app_state) to control its behavior
  • The block construct groups related tasks together
  • Conditional execution (when clause) determines which actions to perform
  • The same playbook handles installation, updates, and removal
  • Version control is managed through variables for easy updates

3. Infrastructure Provisioning

Web Server Provisioning

Set up a complete web server with HTTPS in one playbook

File: provision_webserver.yml

yaml
---
# provision_webserver.yml
- name: Provision Web Server
  hosts: new_servers
  become: true
  
  tasks:
    - name: Install web server packages
      apt:
        name:
          - nginx
          - php-fpm
          - certbot
        state: present
        
    - name: Configure virtual host
      template:
        src: vhost.conf.j2
        dest: /etc/nginx/sites-available/{% raw %}{{ domain_name }}{% endraw %}.conf
        
    - name: Enable virtual host
      file:
        src: /etc/nginx/sites-available/{% raw %}{{ domain_name }}{% endraw %}.conf
        dest: /etc/nginx/sites-enabled/{% raw %}{{ domain_name }}{% endraw %}.conf
        state: link
        
    - name: Obtain SSL certificate
      command: >
        certbot --nginx -d {% raw %}{{ domain_name }}{% endraw %} -d www.{% raw %}{{ domain_name }}{% endraw %}
        --non-interactive --agree-tos --email {% raw %}{{ admin_email }}{% endraw %}
      args:
        creates: /etc/letsencrypt/live/{% raw %}{{ domain_name }}{% endraw %}/fullchain.pem
  • This playbook targets newly added servers to set up a complete web stack
  • It installs all required packages in a single task
  • Templates are used for configuration files to customize for each domain
  • Symbolic links enable the virtual host configuration
  • The creates parameter ensures the SSL certificate is only obtained if it doesn't exist

Best Practices

💡 Do's

  • Write idempotent playbooks that can be run multiple times safely
  • Use roles to organize and reuse playbook components
  • Test playbooks in development environments before production
  • Use variables for values that might change
  • Include proper error handling and validation
  • Document your playbooks with comments and README files

⛔ Don'ts

  • Don't hardcode sensitive information like passwords or API keys
  • Don't write playbooks that make irreversible changes without confirmation
  • Don't ignore failed tasks without proper handling
  • Don't create overly complex playbooks that are hard to maintain
  • Don't forget to version control your playbooks

Common Misconceptions

Misconception 1: Playbooks are just scripts

Reality: While scripts execute commands sequentially, playbooks are declarative and idempotent. They define the desired state of the system and only make changes when necessary to achieve that state.

Misconception 2: Playbooks require deep Ansible knowledge

Reality: SSM provides templates and examples that make it easy to get started with playbooks. The web interface simplifies creation, editing, and execution, reducing the learning curve.

Misconception 3: Playbooks are only for large-scale deployments

Reality: Playbooks are valuable for infrastructures of any size. Even with just a few devices, playbooks ensure consistency and save time on repetitive tasks.

References:

Made with love