{"id":1475,"date":"2021-03-18T02:53:23","date_gmt":"2021-03-18T02:53:23","guid":{"rendered":"https:\/\/dft.wiki\/?p=1475"},"modified":"2026-06-08T23:26:05","modified_gmt":"2026-06-09T03:26:05","slug":"deploying-and-configuring-in-mass-with-ansible","status":"publish","type":"post","link":"https:\/\/dft.wiki\/?p=1475","title":{"rendered":"Deploying and Configuring in Mass with Ansible"},"content":{"rendered":"<p>Ansible is a tool for automating provisioning, configuration, and deployment across multiple hosts via SSH.<\/p>\n<p>Installing Ansible on Ubuntu 20.04<\/p>\n<pre><span class=\"token function\">sudo apt update -y\r\nsudo apt<\/span> <span class=\"token function\">install<\/span> ansible -y<\/pre>\n<p>Installing Ansible on CentOS 8<\/p>\n<pre>yum update -y\r\nyum install epel-release -y\r\nyum install ansible -y<\/pre>\n<p>Add the hosts at the end of <strong>\/etc\/ansible\/hosts<\/strong>:<\/p>\n<pre>[<span style=\"color: #0000ff;\">servers<\/span>]\r\n192.168.1.1\r\n192.168.1.2\r\n192.168.1.3\r\n192.168.1.4\r\n[<span style=\"color: #0000ff;\">servers<\/span>:vars]\r\nansible_user=root\r\n<\/pre>\n<p>Create and transfer the root SSH key:<\/p>\n<pre>ansible all --list-hosts\r\nssh-keygen -t rsa -C \"root@domain.com\"\r\nssh-copy-id 192.168.1.1\r\nssh-copy-id 192.168.1.2\r\nssh-copy-id 192.168.1.3\r\nssh-copy-id 192.168.1.4<\/pre>\n<p>Running simple commands with Ansible:<\/p>\n<pre>ansible-inventory --list -y\r\nansible <span style=\"color: #0000ff;\">servers<\/span> -m ping\r\nansible <span style=\"color: #0000ff;\">servers<\/span> -a \"apt update\"\r\nansible <span style=\"color: #0000ff;\">servers<\/span> -a \"apt upgrade -y\"\r\nansible all -m ping -u root\r\n<\/pre>\n<p>Check the full list of modules in the Ansible documentation [<a href=\"https:\/\/docs.ansible.com\/ansible\/latest\/collections\/index_module.html\">Link<\/a>].<\/p>\n<hr \/>\n<p><strong>PLAYBOOK<\/strong><\/p>\n<pre>nano playbook1.yaml<\/pre>\n<p>A playbook is made up of one or more plays, and each play contains one or more tasks.<\/p>\n<p>Use the template below and customize as needed:<\/p>\n<pre>---\r\n\r\n- name: PLAYBOOK ONE\r\n  hosts: servers\r\n  remote_user: root\r\n  become: true\r\n\r\n  pre_tasks:\r\n  - name: APT UPDATE\r\n    apt:\r\n      update_cache: yes\r\n    when: ansible_distribution == \"Ubuntu\"\r\n\r\n  tasks:\r\n  - name: INSTALL LOCATE\r\n    apt:\r\n      name: locate\r\n      state: latest\r\n\r\n  - name: COPY FILE\r\n    tags: webserver,apache\r\n    copy:\r\n      src: \/data\/site.html\r\n      dest: \/var\/www\/html\/index.html\r\n      owner: root\r\n      group: root\r\n      mode: 0644\r\n\r\n  - name: START SERVICE\r\n    service:\r\n      name: cron\r\n      state: started\r\n\r\n  - name: REMOVE LOCATE\r\n    apt:\r\n      name: locate\r\n      state: absent\r\n    when: ansible_distribution in [\"Debian\",\"Ubuntu\"]\r\n\r\n  - name: INSTALL UNZIP\r\n    package:\r\n      name: unzip\r\n\r\n  - name: DOWNLOAD AND EXTRACT A ZIP\r\n    src: https:\/\/example.com\/file.zip\r\n    dest: \/root\r\n    remote_src: yes\r\n    mode: 0755\r\n    owner: root\r\n    group: root\r\n\r\n  - name: START SERVICE\r\n    service:\r\n      name: httpd\r\n      state: started\r\n      enabled: yes\r\n\r\n  - name: CHANGE VARIABLE DATA IN FILE\r\n    lineinfile:\r\n      path: \/etc\/nginx\/nginx.conf\r\n      regexp: '^server_name'\r\n      line: server_name example.com;\r\n    register: webserver_admin_email\r\n\r\n  - name: RESTART IF CONFIG CHANGED ABOVE\r\n    service:\r\n      name: nginx\r\n      state: restarted\r\n    when: webserver_admin_email.changed\r\n\r\n\r\n- name: PLAYBOOK TWO - USERS MANAGEMENT\r\n  hosts: all\r\n  become: true\r\n  tasks:\r\n\r\n    - name: CREATE USER\r\n      user:\r\n        name: username\r\n        groups: groupname\r\n\r\n    - name: ADD SSH KEY\r\n      user:\r\n        name: username\r\n        key: \"copy and paste the key here\"<\/pre>\n<p>Dry-run first, then execute the playbook:<\/p>\n<pre>ansible-playbook playbook1.yaml --check\r\nansible-playbook playbook1.yaml<\/pre>\n<p>Check mode can also be set directly inside a play:<\/p>\n<pre>check_mode: yes\r\n\r\nOR\r\n\r\ncheck_mode: no<\/pre>\n<p>Other useful commands:<\/p>\n<pre>ansible all -m gather_facts\r\nansible all -m gather_facts --limit 192.168.1.1\r\nansible all -m apt -a update_cache=true --become --ask-become-pass\r\nansible all -m apt -a name=locate --become --ask-become-pass\r\nansible all -m apt -a \"name=locate state=latest\" --become --ask-become-pass\r\nansible all -m apt -a upgrade=dist --become --ask-become-pass<\/pre>\n<hr \/>\n<p><strong>ROLES<\/strong><\/p>\n<p>A playbook can be split into sections called roles to make it easier to manage.<\/p>\n<pre>- name: ROLES THAT APPLY TO SERVERS\r\n  hosts: servers\r\n  become: true\r\n<span style=\"color: #ff0000;\">  roles:\r\n    - base_role\r\n    - server_role<\/span>\r\n\r\n- name: ROLES THAT APPLY TO WORKSTATIONS\r\n  hosts: workstations\r\n  become: true\r\n<span style=\"color: #ff0000;\">  roles:\r\n    - base_role\r\n    - workstation_role<\/span><\/pre>\n<hr \/>\n<p><strong>HANDLERS<\/strong><\/p>\n<pre>- name: CHANGE VARIABLE DATA IN FILE\r\n  lineinfile:\r\n    path: \/etc\/nginx\/nginx.conf\r\n    regexp: '^server_name'\r\n    line: server_name example.com;\r\n<span style=\"color: #ff6600;\">  notify: restart_nginx<\/span><\/pre>\n<p>File structure for roles with tasks and handlers:<\/p>\n<pre><strong>roles\/<\/strong>\r\n<span style=\"color: #ff0000;\">      base_role\/\r\n                tasks\/main.yml\r\n<\/span><span style=\"color: #ff6600;\">                handlers\/main.yml<\/span>\r\n<span style=\"color: #ff0000;\">      server_role\/\r\n                  tasks\/main.yml\r\n<\/span><span style=\"color: #ff6600;\">                  handlers\/main.yml<\/span>\r\n<span style=\"color: #ff0000;\">      workstation_role\/\r\n                       tasks\/main.yml\r\n<\/span><span style=\"color: #ff6600;\">                       handlers\/main.yml<\/span><\/pre>\n<hr \/>\n<p><strong>PLAYBOOK OPTIMIZATION<\/strong><\/p>\n<p>Use callback plugins to identify tasks that may be slowing down the playbook.<\/p>\n<p>In <strong>ansible.cfg<\/strong>, add:<\/p>\n<pre><span class=\"hljs-section\">[defaults]\r\n<\/span><span class=\"hljs-attr\">inventory<\/span> = .\/hosts\r\n<span class=\"hljs-attr\">callbacks_enabled<\/span> = timer, profile_tasks, profile_roles<\/pre>\n<p>The <strong>forks<\/strong> setting controls how many tasks run in parallel.<\/p>\n<p>In <strong>ansible.cfg<\/strong>, add the desired number:<\/p>\n<pre>[defaults]\r\ninventory = .\/hosts\r\nforks=25\r\n<\/pre>\n<p>Or set it at runtime:<\/p>\n<pre>ansible-playbook playbookName.yaml --forks 25<\/pre>\n<p>Reuse established SSH connections for a set period to reduce overhead:<\/p>\n<pre>[ssh_connection]\r\nssh_args = -o <strong>ControlMaster=auto<\/strong> -o <strong>ControlPersist=30s<\/strong><\/pre>\n<p>In a controlled environment, you can disable host SSH key checking to improve performance:<\/p>\n<pre>[defaults]\r\nhost_key_checking = False<\/pre>\n<p>To allow tasks to run across servers without waiting for all hosts to finish each step:<\/p>\n<pre>---\r\n- name: PLAYBOOK\r\n  hosts: all\r\n  strategy: free\r\n<\/pre>\n<hr \/>\n<p><strong>PULL<\/strong><\/p>\n<p>Instead of pushing configuration from a manager host, Ansible can pull a configuration file from a Git repository and run it locally:<\/p>\n<pre>ansible-pull -U http:\/\/example.com\/file.git<\/pre>\n<hr \/>\n<p><strong>BONUS<\/strong><\/p>\n<p>Ansible has no built-in graphical interface, but pairing it with Ansible Semaphore greatly improves the user experience [<a href=\"https:\/\/github.com\/ansible-semaphore\/semaphore\">Link<\/a>].<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Ansible is a tool for automating provisioning, configuration, and deployment across multiple hosts via SSH. [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[4,6],"tags":[],"class_list":["post-1475","post","type-post","status-publish","format-standard","hentry","category-linux","category-raspberry-pi"],"_links":{"self":[{"href":"https:\/\/dft.wiki\/index.php?rest_route=\/wp\/v2\/posts\/1475","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/dft.wiki\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/dft.wiki\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/dft.wiki\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/dft.wiki\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=1475"}],"version-history":[{"count":20,"href":"https:\/\/dft.wiki\/index.php?rest_route=\/wp\/v2\/posts\/1475\/revisions"}],"predecessor-version":[{"id":5763,"href":"https:\/\/dft.wiki\/index.php?rest_route=\/wp\/v2\/posts\/1475\/revisions\/5763"}],"wp:attachment":[{"href":"https:\/\/dft.wiki\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=1475"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/dft.wiki\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=1475"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/dft.wiki\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=1475"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}