Understanding Ansible Connection Plugins
Ansible manages how it communicates with remote hosts through connection plugins. The default is usually ssh, but you can optimize this behavior using the smart connection type or by explicitly setting parameters in your inventory or playbook. To enable connection sharing, you must ensure that the underlying SSH client supports multiplexing via the -M (master) and -S (socket) flags.
When Ansible initiates a task, it checks if a persistent connection already exists. If one does, it attaches to the existing socket instead of opening a new port. This is crucial for performance-intensive tasks like large directory transfers where the setup time for SSH negotiation becomes a bottleneck relative to the data transfer speed.
Configuring Persistent Connections
To make Ansible reuse SSH connections, you need to configure the control master settings. This can be done globally in ansible.cfg or locally within a playbook. The key configuration items are control_path, control_master, and controlPersist.
- control_master: Set this to
autooryes.autoallows Ansible to decide based on other factors, whileyesforces master mode. - control_path: Define a path for the socket file. A common pattern is
/tmp/ansible-ssh-%h-%p-%r, which ensures uniqueness per host, port, and user. - controlPersist: Specify how long the connection should remain open after the last client disconnects. Setting this to
60sor higher keeps the channel warm for subsequent tasks.
Example configuration in ansible.cfg:
[ssh_connection]
control_path = /tmp/ansible-ssh-%%h-%%p-%%r
control_master = auto
controlPersist = 60s
This setup ensures that once the first task establishes an SSH session, all subsequent tasks within that run will piggyback on the same connection. This is particularly effective when combined with the synchronize module, which is Ansible's wrapper around rsync.
Using the Synchronize Module Efficiently
The synchronize module is the standard way to perform rsync operations in Ansible. It abstracts the complexity of rsync command-line arguments while allowing you to leverage the underlying SSH connection reuse. When you use the synchronize module, Ansible invokes rsync on the controller and pushes/pulls files to/from the target.
Because the synchronize module runs as a task, it benefits from the global SSH connection settings. However, for maximum efficiency, you can also pass extra arguments directly to rsync via the rsync_opts parameter. While these options don't change the SSH layer, they optimize the data transfer itself.
Consider the following playbook snippet:
- name: Sync directory using reused SSH connection
ansible.builtin.synchronize:
src: ./local/dir/
dest: /remote/path/
recursive: yes
compress: yes
delete: yes
In this scenario, if you have previously configured persistent SSH connections, the synchronize module will utilize the existing master socket. This means the initial handshake overhead is paid only once, regardless of how many files are transferred.
Handling Multiple Hosts
If you are syncing to multiple remote hosts, each host requires its own SSH master socket. The control_path template must include variables like %h (hostname) to prevent socket collisions. Without this, Ansible might try to route traffic for Host B through Host A's socket, leading to authentication failures or data corruption.
Ensure your inventory or group variables reflect distinct hostnames. If you are using aliases, resolve them to canonical names before generating the socket path. This detail is often overlooked but critical for stable multi-host deployments.
Debugging Connection Issues
Sometimes, connection reuse fails due to permission issues or stale sockets. If you encounter errors like "Permission denied" or "Connection reset," check the permissions of the directory specified in control_path. The user running Ansible must have write access to this directory.
You can also manually inspect the socket files to see if they are active. Using ls -l /tmp/ansible-ssh-* will show you the current master sockets. If a socket appears old but the connection is dead, you may need to clear the cache or adjust the controlPersist value.
For deeper insights, run Ansible with the -vvv flag. This verbose output will show exactly how the SSH connection is being established and whether it is attaching to an existing master or creating a new one. Look for lines containing "ControlMaster" and "ControlPath" in the debug logs.
Alternative Approaches
If you find that the synchronize module is too rigid for your needs, you can use the shell or command modules to invoke rsync directly. However, this bypasses some of Ansible's built-in optimizations and error handling. You would need to manually manage the SSH connection state, which is generally not recommended unless you have very specific requirements.
Another alternative is to use the copy module for smaller files, as it uses a different transport mechanism that may not benefit as much from SSH multiplexing. For large-scale directory syncs, sticking with synchronize and proper SSH configuration remains the best practice.
For more advanced scenarios involving network storage, you might explore mirroring strategies. See Using rsync to mirror the contents of a directory on a NAS for techniques applicable to static infrastructure.
Frequently Asked Questions
Does SSH connection reuse work with password authentication?
No, SSH multiplexing typically requires public key authentication or cached credentials. Password prompts break the non-interactive nature of the master socket. Ensure you have set up SSH keys for seamless automation.
What happens if the SSH connection drops during a sync?
Ansible will detect the broken pipe and attempt to reconnect. With controlPersist set, the master socket may remain open briefly, but if the network fails completely, a new connection will be established for the next task. Always implement retry logic for critical syncs.
Can I limit the number of concurrent SSH connections?
Yes, by using forks in your playbook or ansible.cfg. Reducing forks limits the number of simultaneous SSH sessions, which can help avoid overwhelming the server's connection table. This works in tandem with connection reuse to optimize resource usage.
How do I clean up stale SSH sockets?
You can manually delete files in the control_path directory. Alternatively, set a shorter controlPersist value so that sockets expire automatically. Regular cleanup prevents disk space issues and ensures fresh connections when needed.
Is rsync over SSH slower than direct NFS mounts?
Generally, no. Modern SSH compression and efficient packet handling make rsync over SSH highly performant. While NFS might offer lower latency for small files, rsync's delta-transfer algorithm saves bandwidth for large datasets. Choose based on your network topology and security requirements.