Ansible runs a whole lot of SSH commands one after another.
The Problem
Ansible opens an SSH connection for every playbook run. When you have multiple servers you need to configure in parallel with multiple playbooks being applied to them then it all adds up.
This is how a typical SSH log file may look like when Ansible runs against a host in order to configure it:
Sep 1 18:32:54 admin1 sshd[]: pam_unix(sshd:session): session opened for user ansible by (uid=0) Sep 1 18:33:17 admin1 sshd[]: pam_unix(sshd:session): session opened for user ansible by (uid=0) Sep 1 18:33:40 admin1 sshd[]: pam_unix(sshd:session): session opened for user ansible by (uid=0) Sep 1 18:34:02 admin1 sshd[]: pam_unix(sshd:session): session opened for user ansible by (uid=0) Sep 1 18:35:14 admin1 sshd[]: pam_unix(sshd:session): session opened for user ansible by (uid=0)
Reusing the connections could make a difference.
The Solution
Use SSH multiplexing.
OpenSSH multiplexing can re-use an existing outgoing connection for multiple concurrent SSH sessions to a remote server, avoiding the overhead of creating a new connection and re-authenticating each time. OpenSSH client supports multiplexing using the ControlMaster, ControlPath and ControlPersist configuration directives.
We are going to use ~/.ssh/multiplexing
directory to store control sockets. Since this directory does not exist by default, we need to create it on the Ansible control node:
$ mkdir ~/.ssh/multiplexing
We also have to update ansible.cfg
to use multiplexing:
[default] transport = ssh [ssh_connection] ssh_args = -o ControlMaster=auto -o ControlPersist=3600 control_path = ~/.ssh/multiplexing/ansible-ssh-%%r@%%h:%%p
In this case ControlMaster=auto
creates a master session automatically, and if there is a master session already available, subsequent sessions are automatically multiplexed.
Setting ControlPersist=3600
will leave the master connection open in the background to accept new connections for 3600 seconds (1 hour).
Note that the control_path
can be changed to suit your needs. It can be something a bit more generic if you don’t feel like using a specific directory, for example:
control_path = %(directory)s/ansible-ssh-%%r@%%h:%%p
Test it by running some playbook, e.g:
$ ansible-playbook playbooks/configure-admin-hosts.yml
Then check to see if control sockets were created:
$ ls -1 ~/.ssh/multiplexing/ [email protected]:22 [email protected]:22
There should only be a single session opened for user ansible on both hosts if you check each server’s SSH logs.
Note that the first connection to the server will create a control socket in the directory ~/.ssh/multiplexing/
, and any subsequent connections, up to 10 by default as set by MaxSessions
on the SSH server, will re-use that control path automatically as multiplexed sessions.