Implementing Advanced Patterns
1. Using Delegation Strategies
| Strategy | Description | Use Case | Example |
|---|---|---|---|
| delegate_to | Runs the task on a different host than the one specified in the play's hosts | When you need to execute a task on a specific host, not the target host | |
| delegate_facts | Collects facts from the delegated host and makes them available in the play's context | When you want to use facts from a different host in your playbook | |
| delegate_to + delegate_facts | Combines delegation and fact gathering for complex workflows | When you need to run tasks on a host and use its facts in subsequent tasks | |
delegate_to does not change the inventory or target hosts for other tasks in the play.2. Implementing Rolling Updates
| Parameter | Description | Default Value | Notes |
|---|---|---|---|
| batch_size | Number of hosts to update at once | 1 | Can be a percentage (e.g., 25%) or integer |
| delay | Seconds to wait between batches | 0 | Useful for monitoring or cooldown periods |
| max_fail_percentage | Maximum percentage of hosts that can fail before aborting | 0 | Set to 0 to stop on any failure |
| serial | Number of hosts to update in serial mode | 1 | Overrides batch_size if set |
Example: Rolling Update with Batch Size
- name: Update web servers with rolling updates
hosts: webservers
vars:
batch_size: 25%
tasks:
- name: Deploy new version
ansible.builtin.copy:
src: app.tar.gz
dest: /opt/app/app.tar.gz
Example: Rolling Update with Delay
- name: Update database servers with delay
hosts: databases
vars:
delay: 30
tasks:
- name: Restart service
ansible.builtin.systemd:
name: mysql
state: restarted
max_fail_percentage too high may lead to partial rollouts and inconsistent states across hosts.
3. Implementing Blue-Green Deployments
Blue-green deployments are a deployment strategy that reduces downtime and risk by running two identical production environments. One environment (blue) is active, while the other (green) is idle. When a new version is ready, it's deployed to the idle environment, and traffic is switched from blue to green.
| Component | Description | Notes |
|---|---|---|
| blue_environment | ansible-playbook deploy-blue.yml |
Active environment with current version |
| green_environment | ansible-playbook deploy-green.yml |
Idle environment for new version |
| traffic_switch | ansible-playbook switch-traffic.yml |
Switches traffic from blue to green |
Example: Blue-Green Deployment Setup
# deploy-blue.yml
- hosts: web_servers
vars:
environment: blue
tasks:
- name: Deploy application to blue environment
ansible.builtin.copy:
src: app.tar.gz
dest: /opt/app/app.tar.gz
mode: '0644'
Example: Switching Traffic to Green
# switch-traffic.yml
- hosts: load_balancer
tasks:
- name: Update load balancer to point to green servers
ansible.builtin.template:
src: lb_config.j2
dest: /etc/nginx/conf.d/app.conf
Benefits of Blue-Green Deployment
- Zero Downtime - Traffic is switched instantly.
- Rollback Simplicity - Easy to switch back if issues arise.
- Testing - New version can be tested in isolation before going live.
Blue-Green vs Other Deployment Strategies
- Blue-Green: Two environments, zero downtime
- Rolling Update: Gradual replacement of instances, some downtime
- Recreate: Full shutdown and restart, full downtime
4. Using Canary Deployments
Canary deployments in Ansible involve gradually rolling out changes to a subset of servers before deploying to the entire fleet. This approach minimizes risk by allowing you to observe behavior on a small scale before full rollout.
| Parameter | Description | Example |
|---|---|---|
| canary_hosts | Hosts to include in the canary group | webservers:canary_hosts |
| canary_percentage | Percentage of hosts to deploy to in canary phase | 10 |
| canary_delay | Time (in seconds) to wait between canary phases | 30 |
Example: Canary Deployment Playbook
---
- name: Canary deployment for web app
hosts: webservers
vars:
canary_hosts: 10%
canary_delay: 30
tasks:
- name: Deploy to canary hosts first
ansible.builtin.copy:
src: app.tar.gz
dest: /opt/app.tar.gz
when: inventory_hostname in groups['canary_hosts']
- name: Restart service on canary hosts
ansible.builtin.systemd:
name: webapp.service
state: restarted
when: inventory_hostname in groups['canary_hosts']
- name: Wait before full rollout
ansible.builtin.wait_for:
timeout: "{{ canary_delay }}"
Canary Deployment Steps
- Define a subset of hosts to be part of the canary group
- Deploy changes to canary hosts first
- Monitor for any issues or performance degradation
- Gradually expand deployment to remaining hosts
5. Implementing Zero-Downtime Deployments
Zero-downtime deployments ensure that applications remain available during updates. Ansible provides several strategies to achieve this, particularly through load balancing and rolling updates.
| Strategy | Description | Use Case |
|---|---|---|
| Rolling Updates | Update instances one at a time, ensuring that at least one instance remains active. | Web servers, microservices |
| Blue-Green Deployment | Run two identical production environments (blue and green). Switch traffic to the new version once deployed. | High availability systems |
| Canary Releases | Deploy to a small subset of instances first, then gradually increase traffic. | Testing new features with real users |
Example: Rolling Update with Load Balancer
- name: Perform rolling update
hosts: web_servers
vars:
max_fail_percentage: 10
serial: 2
tasks:
- name: Deploy new version
ansible.builtin.copy:
src: app.tar.gz
dest: /opt/app/app.tar.gz
- name: Restart service
ansible.builtin.systemd:
name: app.service
state: restarted
Example: Blue-Green Deployment
- name: Switch to new environment
hosts: load_balancer
tasks:
- name: Update load balancer to point to new servers
ansible.builtin.command: |
haproxy -f /etc/haproxy/haproxy.cfg
Best Practices for Zero-Downtime Deployment
- Use serial execution to control the number of instances updated at once.
- Implement health checks before and after deployment to ensure service stability.
- Use load balancers that support graceful draining of connections during updates.
6. Using Pre and Post Tasks
Example: Using pre_task and post_task
---
- name: Example playbook with pre and post tasks
hosts: all
pre_tasks:
- name: Ensure log directory exists
file:
path: /var/log/myapp
state: directory
mode: '0755'
tasks:
- name: Deploy application
copy:
src: app.py
dest: /opt/myapp/app.py
mode: '0755'
post_tasks:
- name: Restart service
systemd:
name: myapp.service
state: restarted
| Property | Description | Values |
|---|---|---|
| pre_tasks | Tasks to run before the main tasks | List of task definitions |
| post_tasks | Tasks to run after the main tasks | List of task definitions |
pre_tasks and post_tasks are executed in the order they appear, and can include any valid task type.
Key Points
- pre_tasks run before the main tasks in a play
- post_tasks run after the main tasks in a play
- Both
pre_tasksandpost_taskssupport all task features (handlers, loops, conditionals) - Useful for setup and cleanup operations
7. Implementing Health Checks
| Check Type | Description | Configuration | Notes |
|---|---|---|---|
| http | HTTP health check | { "url": "http://localhost:8080/health", "status_code": 200 } |
Useful for web services |
| tcp | TCP port check | { "host": "localhost", "port": 8080 } |
Verifies port availability |
| file | File existence check | { "path": "/var/run/app.pid" } |
Checks for process files |
| command | Command execution check | { "cmd": "pgrep app" } |
Runs shell command and checks exit code |
Example: HTTP Health Check
- name: Check web service health
uri:
url: http://localhost:8080/health
status_code: 200
register: health_result
retries: 3
delay: 5
Example: TCP Port Check
- name: Verify application port
wait_for:
host: localhost
port: 8080
timeout: 30
Example: File Existence Check
- name: Check if process file exists
stat:
path: /var/run/app.pid
register: pid_file
- name: Fail if file does not exist
assert:
that: pid_file.stat.exists
fail_msg: "Process file missing"
Example: Command Execution Check
- name: Verify application is running
command: pgrep app
register: process_check
ignore_errors: true
- name: Fail if no process found
assert:
that: process_check.rc == 0
fail_msg: "Application not running"
8. Using Smoke Tests
Smoke tests in Ansible are used to quickly verify that a system or service is functioning correctly after deployment. These tests typically run early in the deployment pipeline to catch obvious issues.
| Test Type | Description | Example |
|---|---|---|
| HTTP Status Check | Verifies that a web service returns an expected HTTP status code. | curl -f http://example.com/health |
| Service Availability | Checks that a service is running and accessible. | |
| Port Check | Ensures that a specific port is open and accepting connections. | |
Example: Smoke Test Playbook
- name: Run smoke tests
hosts: all
tasks:
- name: Check HTTP status
ansible.builtin.uri:
url: http://{{ ansible_host }}/health
status_code: 200
register: result
- name: Fail if service is not healthy
ansible.builtin.fail:
msg: "Service is not healthy"
when: result.status != 200
9. Implementing Rollback Strategies
| Strategy | Description | Usage |
|---|---|---|
| rollback | Rollback to a previous state or version of a configuration or deployment | ansible-playbook rollback.yml |
| version_control | Use version control to track and revert configurations | git checkout <commit> |
| snapshot | Create snapshots of system states before changes | ansible-galaxy collection install community.general |
Example: Rollback using tags
- name: Deploy application
hosts: web_servers
tags:
- deploy
tasks:
- name: Install new version
apt:
name: myapp
state: latest
- name: Rollback to previous version
hosts: web_servers
tags:
- rollback
tasks:
- name: Revert to previous version
apt:
name: myapp
state: "2.0.0"
10. Using Configuration Drift Detection
Example: Detecting Configuration Drift with Ansible
- name: Check for configuration drift
hosts: all
tasks:
- name: Gather facts about current system
setup:
- name: Compare local config with remote
command: diff /etc/nginx/nginx.conf /tmp/expected.conf
register: config_diff
ignore_errors: yes
- name: Report drift if found
debug:
msg: "Configuration drift detected in nginx.conf"
when: config_diff.rc != 0
| Option | Values | Description |
|---|---|---|
| ansible.builtin.setup | yes |
Gathers facts about the target system |
| ansible.builtin.command | diff |
Compares local and remote configuration files |
| ansible.builtin.debug | msg |
Reports drift detection results |
diff command must be available on all target hosts for this approach to work.