{"id":1475,"date":"2021-03-18T02:53:23","date_gmt":"2021-03-18T02:53:23","guid":{"rendered":"https:\/\/dft.wiki\/?p=1475"},"modified":"2023-08-11T22:02:16","modified_gmt":"2023-08-12T02:02:16","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 in 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 the file <strong>\/etc\/ansible\/hosts<\/strong>:<\/p>\n<pre>[<span style=\"color: #0000ff;\">servers<\/span>]\r\n<strong>192.168.1.1\r\n192.168.1.2 <\/strong>\r\n<strong>192.168.1.3 <\/strong>\r\n<strong>192.168.1.4<\/strong> \r\n[<span style=\"color: #0000ff;\">servers<\/span>:vars]\r\nansible_user=<strong>root<\/strong>\r\n<\/pre>\n<p>Create and transfer the root&#8217;s SSH Key:<\/p>\n<pre>ansible <strong>all --list-hosts<\/strong>\r\nssh-keygen -t rsa -C \"<strong>root@domain.com<\/strong>\"\r\nssh-copy-id <strong>192.168.1.1\r\n<\/strong>ssh-copy-id <strong>192.168.1.2\r\n<\/strong>ssh-copy-id <strong>192.168.1.3\r\n<\/strong>ssh-copy-id <strong>192.168.1.4<\/strong><\/pre>\n<p>Using ansible for simple commands:<\/p>\n<pre>ansible-inventory --list -y\r\nansible <span style=\"color: #0000ff;\">servers<\/span> <strong>-m ping<\/strong>\r\nansible <span style=\"color: #0000ff;\">servers<\/span> <strong>-a \"apt update\"<\/strong>\r\nansible <span style=\"color: #0000ff;\">servers<\/span> <strong>-a \"apt upgrade -y\"\r\n<\/strong>ansible <strong>all -m ping -u root\r\n<\/strong><\/pre>\n<p>Check the list of all modules on Ansible online documentation [<a href=\"https:\/\/docs.ansible.com\/ansible\/latest\/collections\/index_module.html\">Link<\/a>].<\/p>\n<p><strong>PLAYBOOK<\/strong><\/p>\n<pre>nano <strong><span style=\"color: #000000;\">playbook1.yaml<\/span><\/strong><\/pre>\n<p>A PlayBook is composed of one or more Plays, and each Play contains one or more tasks.<\/p>\n<p>Use the template and customize as necessary:<\/p>\n<pre>---\r\n \r\n- name: <strong>PLAYBOOK ONE<\/strong>\r\n  hosts: <strong>servers<\/strong>\r\n  remote_user: <strong>root<\/strong>\r\n  become: <strong>true<\/strong>\r\n\r\n  pre_tasks:\r\n  - name: <strong>APT UPDATE<\/strong>\r\n    apt:\r\n      update_cache: yes\r\n    when: ansible_distribution == \"Ubuntu\" \r\n\r\n\r\n  tasks:\r\n  - name: <strong>INSTALL LOCATE<\/strong>\r\n    apt:\r\n      name: locate\r\n      state: latest\r\n\r\n  - name: <strong>COPY FILE\r\n<\/strong>    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: <strong>START SERVICE<\/strong>\r\n    service:\r\n      name: cron\r\n      state: started\r\n\r\n  - name: <strong>REMOVE LOCATE<\/strong>\r\n    apt:\r\n      name: locate\r\n      state: absent\r\n    when: ansible_distribution in [\"Debian\",\"Ubuntu\"]\r\n\r\n  - name: <strong>INSTALL UNZIP<\/strong>\r\n    package:\r\n      name: unzip\r\n\r\n  - name: <strong>DOWNLOAD AND EXTRACT A ZIP<\/strong>\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: <strong>START SERVICE<\/strong>\r\n    service:\r\n      name: httpd\r\n      state: started\r\n      enabled: yes\r\n\r\n  - name: <strong>CHANGE VARIABLE DATA IN FILE<\/strong>\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: <strong>RESTART IF CONFIG CHANGED ABOVE<\/strong>\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: <strong>PLAYBOOK TWO - USERS MANAGEMENT<\/strong>\r\n  hosts: all\r\n  become: true\r\n  tasks:\r\n\r\n    - name: <strong>CREATE USER<\/strong>\r\n      user:\r\n        name: username\r\n        groups: groupname\r\n\r\n    - name: <strong>ADD SSH KEY<\/strong>\r\n      user:\r\n        name: username\r\n        key: \"copy and paste the key here\"<\/pre>\n<p>Check first, then run the PlayBook:<\/p>\n<pre>ansible-playbook <strong>playbook1.yaml --check<\/strong>\r\nansible-playbook <strong>playbook1.yaml<\/strong><\/pre>\n<p>The check mode (dry-run!) can be forced on a play by using the following option:<\/p>\n<pre>check_mode: yes\r\n\r\nOR\r\n\r\ncheck_mode: no<\/pre>\n<p>More useful command:<\/p>\n<pre>ansible <strong>all<\/strong> <strong>-m gather_facts\r\n<\/strong>ansible all -m gather_facts <strong>--limit 192.168.1.1\r\n<\/strong>ansible all -m apt <strong>-a update_cache=true --become --ask-become-pass\r\n<\/strong>ansible all -m apt -a <strong>name=locate<\/strong> --become --ask-become-pass\r\nansible all -m apt -a <strong>\"name=locate state=latest\"<\/strong> --become --ask-become-pass\r\nansible all -m apt -a <strong>upgrade=dist<\/strong> --become --ask-become-pass<\/pre>\n<p><strong>ROLES<\/strong><\/p>\n<p>The PlayBook can be broken into pieces or sections called roles to make the file easier to manage.<\/p>\n<pre>- name: <strong>ROLES THAT APPLY TO SERVERS<\/strong>\r\n  hosts: servers\r\n  become: true\r\n<strong><span style=\"color: #ff0000;\">  roles:\r\n    - base_role\r\n    - server_role<\/span><\/strong>\r\n\r\n- name: <strong>ROLES THAT APPLY TO WORKSTATIONS<\/strong>\r\n  hosts: workstations\r\n  become: true\r\n<span style=\"color: #ff0000;\"><strong>  roles:\r\n    - base_role\r\n    - workstation_role<\/strong><\/span><\/pre>\n<p><strong>HANDLERS<\/strong><\/p>\n<pre>- name: <strong>CHANGE VARIABLE DATA IN FILE<\/strong>\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;\">  <strong>notify: restart_nginx<\/strong><\/span><\/pre>\n<p>File structure for Roles with Tasks and Handlers:<\/p>\n<pre><strong>roles\/<\/strong>\r\n<span style=\"color: #ff0000;\"><strong>      base_role<\/strong>\/\r\n                <strong>tasks\/main.yml<\/strong><\/span>\r\n      <span style=\"color: #ff0000;\"><span style=\"color: #000000;\"><strong><span style=\"color: #ff6600;\">          handlers\/main.yml<\/span><\/strong><\/span>\r\n<\/span><span style=\"color: #ff0000;\"><strong>      server_role<\/strong>\/\r\n                  <strong>tasks\/main.yml<\/strong><\/span>\r\n<span style=\"color: #ff0000;\"><span style=\"color: #000000;\"><span style=\"color: #ff6600;\"><strong>                  handlers\/<\/strong><strong>main.yml<\/strong><\/span><\/span>\r\n<\/span>      <span style=\"color: #ff0000;\"><strong>workstation_role<\/strong>\/\r\n                       <strong>tasks\/main.yml<\/strong><\/span>\r\n                       <span style=\"color: #ff6600;\"><strong>handlers\/<\/strong><strong>main.yml<\/strong><\/span><\/pre>\n<p><strong>PLAYBOOK OPTIMIZATION<\/strong><\/p>\n<p>Using callback plugins to identify tasks that might be slowing down the playbook:<\/p>\n<p>At <strong>ansible.cfg<\/strong> add the following line:<\/p>\n<pre><span class=\"hljs-section\">[defaults]\r\n<\/span><span class=\"hljs-attr\">inventory<\/span> = .\/hosts\r\n<strong><span class=\"hljs-attr\">callbacks_enabled<\/span> = timer, profile_tasks, profile_roles<\/strong><\/pre>\n<p>The default parallelism (<strong>forks<\/strong>) number defines how many tasks are executed at the same time.<\/p>\n<p>At <strong>ansible.cfg<\/strong> add the following line with the desired number:<\/p>\n<pre>[defaults]\r\ninventory = .\/hosts\r\n<strong>forks=25\r\n<\/strong><\/pre>\n<p>Or dynamically at the playbook execution:<\/p>\n<pre>ansible-playbook playbookName.yaml --forks 25<\/pre>\n<p>Optimize the SSH connections\u00a0 by reusing the established connections for a defined period:<\/p>\n<pre>[ssh_connection]\r\nssh_args = -o <strong>ControlMaster=auto<\/strong> -o <strong>ControlPersist=30s<\/strong><\/pre>\n<p>In a controlled and dynamic environment, the host SSH key check can be disabled to increase performance by:<\/p>\n<pre>[defaults]\r\n<strong>host_key_checking = False<\/strong><\/pre>\n<p>To make the tasks run freely the servers (without waiting for all to finish each task before moving to the next):<\/p>\n<pre>---\r\n- name: PLAYBOOK\r\n  hosts: all\r\n<strong>  strategy: free\r\n<\/strong><\/pre>\n<p>&nbsp;<\/p>\n<hr \/>\n<p><strong>PULL<\/strong><\/p>\n<p>Instead of push configuration to many servers from a manager host, Ansible makes it possible to pull a configuration file from a git repository and execute locally:<\/p>\n<pre>ansible-pull -U <strong>http:\/\/example.com\/file.git<\/strong><\/pre>\n<hr \/>\n<p><strong>BONUS<\/strong><\/p>\n<p>Ansible does not offer a graphical interface but using it combined with Ansible Semaphore the user experience can be strongly improved [<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 in 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":17,"href":"https:\/\/dft.wiki\/index.php?rest_route=\/wp\/v2\/posts\/1475\/revisions"}],"predecessor-version":[{"id":3789,"href":"https:\/\/dft.wiki\/index.php?rest_route=\/wp\/v2\/posts\/1475\/revisions\/3789"}],"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}]}}