Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Ansible Best Practices at Scale

Ansible Best Practices at Scale

Keith Resar

March 23, 2017
Tweet

More Decks by Keith Resar

Other Decks in Technology

Transcript

  1. @KeithResar https://github.com/openshift/openshift-ansible/blob/master/docs/best_practices_guide.adoc#Ansible-files-SHOULD-NOT-use-JSON-use-pure-YAML-instead YAML is a superset of JSON, which means

    that Ansible allows JSON syntax to be interspersed. Even though YAML (and by extension Ansible) allows for this, JSON SHOULD NOT be used. Reasons: • Ansible is able to give clearer error messages when the files are pure YAML • YAML makes for nicer diffs as YAML tends to be multi-line, whereas JSON tends to be more concise • YAML reads more nicely (opinion?)
  2. @KeithResar https://github.com/openshift/openshift-ansible/blob/master/docs/best_practices_guide.adoc#Parameters-to-Ansible-modules-SHOULD-use-the-Yaml-dictionary-fo rmat-when-3-or-more-parameters-are-being-passed When a module has several parameters that

    are being passed in, it’s hard to see exactly what value each parameter is getting. It is preferred to use the Ansible Yaml syntax to pass in parameters so that it’s more clear what values are being passed for each parameter.
  3. @KeithResar https://github.com/openshift/openshift-ansible/blob/master/docs/best_practices_guide.adoc#Parameters-to-Ansible-modules-SHOULD-use-the-Yaml-dictionary-fo rmat-when-the-line-length-exceeds-120-characters # ✘ BAD - get_url: url=http://example.com/path/file.conf dest=/etc/foo.conf

    sha256sum=b5bb9d8014a0f9b1d61e21e796d78dccdf1352f23cd32812f4850b8 78ae4944c # ✔ GOOD - get_url: url: http://example.com/path/file.conf dest: /etc/foo.conf Sha256sum: B5bb9d8014a0f9b1d61e21e796d78dc...d32812f4850b878ae4944c
  4. @KeithResar https://github.com/openshift/openshift-ansible/blob/master/docs/best_practices_guide.adoc#Parameters-to-Ansible-modules-SHOULD-use-the-Yaml-dictionary-fo rmat-when-the-line-length-exceeds-120-characters Lines that are long quickly become a

    wall of text that isn’t easily parsable. It is preferred to use the Ansible Yaml syntax to pass in parameters so that it’s more clear what values are being passed for each parameter.
  5. @KeithResar https://github.com/openshift/openshift-ansible/blob/master/docs/best_practices_guide.adoc#The-Ansible-command-module-SHOULD-be-used-instead-of-the-Ans ible-shell-module # ✘ POOR - name: Bare shell

    execution shell: cat myfile # BETTER - name: Quoting templated variable to avoid injection shell: cat {{ myfile | quote }} # ✔ BEST - name: Quoting templated variable to avoid injection command: cat {{ myfile }}
  6. @KeithResar https://github.com/openshift/openshift-ansible/blob/master/docs/best_practices_guide.adoc#The-Ansible-command-module-SHOULD-be-used-instead-of-the-Ans ible-shell-module If you want to execute a command

    securely and predictably, it may be better to use the command module instead, using the shell module only when explicitly required. The Ansible shell module can run most commands that can be run from a bash CLI. This makes it extremely powerful, but it also opens our playbooks up to being exploited by attackers. When running ad-hoc commands, use your best judgement.
  7. @KeithResar https://github.com/openshift/openshift-ansible/blob/master/docs/best_practices_guide.adoc#Ansible-playbooks-MUST-begin-with-checks-for-any-variables-that-th ey-require --- - hosts: localhost gather_facts: no tasks:

    - fail: msg="Playbook requires g_env to be set and non empty" when: g_env is not defined or g_env == '' --- # tasks/main.yml - fail: msg="Role requires arl_env to be set and non empty" when: arl_env is not defined or arl_env == ''
  8. @KeithResar https://github.com/openshift/openshift-ansible/blob/master/docs/best_practices_guide.adoc#Ansible-playbooks-MUST-begin-with-checks-for-any-variables-that-th ey-require If an Ansible playbook or role requires

    certain variables to be set, it’s best to check for these up front before any other actions have been performed. In this way, the user knows exactly what needs to be passed into the playbook.
  9. @KeithResar https://github.com/openshift/openshift-ansible/blob/master/docs/best_practices_guide.adoc#Ansible-tasks-SHOULD-NOT-be-used-in-ansible-playbooks-Instead- use-pre_tasks-and-post_tasks # ✘ BAD - hosts: localhost tasks:

    - name: Executes AFTER the example_role, so it’s confusing debug: msg="in tasks list" roles: - role: example_role # ✔ GOOD - hosts: localhost pre_tasks: - name: Executes BEFORE the example_role, so it makes sense debug: msg="in pre_tasks list" roles: - role: example_role
  10. @KeithResar https://github.com/openshift/openshift-ansible/blob/master/docs/best_practices_guide.adoc#Ansible-tasks-SHOULD-NOT-be-used-in-ansible-playbooks-Instead- use-pre_tasks-and-post_tasks An Ansible play is defined as a

    Yaml dictionary and because of that Ansible doesn’t know if the play’s tasks list or roles list was specified first. Therefore, Ansible always runs tasks after roles. This can be quite confusing if the tasks list is defined in the playbook before the roles list because people assume in order execution in Ansible. Therefore, we SHOULD use pre_tasks and post_tasks to make it more clear when the tasks will be run.
  11. @KeithResar https://github.com/openshift/openshift-ansible/blob/master/docs/best_practices_guide.adoc#All-tasks-in-a-role-SHOULD-be-tagged-with-the-role-name Ansible tasks can be tagged, and then these

    tags can be used to either run or skip the tagged tasks using the --tags and --skip-tags ansible-playbook options respectively. This is very useful when developing and debugging new tasks. It can also significantly speed up playbook runs if the user specifies only the roles that changed.
  12. @KeithResar https://github.com/openshift/openshift-ansible/blob/master/docs/best_practices_guide.adoc#The-Ansible-roles-directory-MUST-maintain-a-flat-structure production # inventory file for production servers staging

    # inventory file for staging environment group_vars/ host_vars/ site.yml # master playbook webservers.yml # playbook for webserver tier dbservers.yml # playbook for dbserver tier roles/ common/ # this hierarchy represents a "role" tasks/, handlers/, templates/, files/, vars/, defaults/, meta/
  13. @KeithResar https://github.com/openshift/openshift-ansible/blob/master/docs/best_practices_guide.adoc#Ansible-Roles-SHOULD-be-named-like-technology_component_subc omponent For consistency, role names SHOULD follow the

    above naming pattern. It is important to note that this is a recommendation for role naming, and follows the pattern used by upstream. Many times the technology portion of the pattern will line up with a package name. It is advised that whenever possible, the package name should be used.
  14. @KeithResar https://github.com/openshift/openshift-ansible/blob/master/docs/best_practices_guide.adoc#The-default-filter-SHOULD-replace-empty-strings-lists-etc - hosts: localhost gather_facts: no vars: somevar: ''

    tasks: - debug: var=somevar # ✘ BAD - name: "Will output 'somevar: []'" debug: "msg='somevar: [{{ somevar | default('empty str') }}]'" # ✔ GOOD - name: "Will output 'somevar: [the string was empty]'" debug: "msg='somevar: [{{ somevar | default('empty str', true)}}]'"
  15. @KeithResar https://github.com/openshift/openshift-ansible/blob/master/docs/best_practices_guide.adoc#The-default-filter-SHOULD-replace-empty-strings-lists-etc When using the jinja2 default filter, unless the

    variable is a boolean, specify true as the second parameter. This will cause the default filter to replace empty strings, lists, etc with the provided default rather than only undefined variables. This is because it is preferable to either have a sane default set than to have an empty string, list, etc. For example, it is preferable to have a config value set to a sane default than to have it simply set as an empty string.