Ansible — Practical
Ansible — Practical patterns
Section titled “Ansible — Practical patterns”Project layout
Section titled “Project layout”ansible/ ansible.cfg inventory/ prod.ini staging.ini group_vars/ all.yml web.yml host_vars/ web1.example.com.yml playbooks/ site.yml deploy.yml roles/ common/ nginx/ app/ collections/ requirements.ymlansible.cfg
Section titled “ansible.cfg”[defaults]inventory = inventory/prod.iniroles_path = ./rolescollections_path = ./collectionshost_key_checking = Falseretry_files_enabled = Falseforks = 50strategy = mitogen_linearstdout_callback = yamlgathering = smartfact_caching = jsonfilefact_caching_connection = ./.ansible_factsfact_caching_timeout = 86400
[ssh_connection]pipelining = Truessh_args = -o ControlMaster=auto -o ControlPersist=60sSite playbook (orchestration)
Section titled “Site playbook (orchestration)”- import_playbook: common.yml- import_playbook: web.yml- import_playbook: db.ymlRolling deploy
Section titled “Rolling deploy”- hosts: web serial: 5 max_fail_percentage: 0 pre_tasks: - name: drain from LB command: aws elbv2 deregister-targets ... delegate_to: localhost
tasks: - name: pull image docker_image: { name: ghcr.io/org/api, tag: "{{ tag }}", source: pull } - name: restart container docker_container: name: api image: ghcr.io/org/api:{{ tag }} state: started restart: true published_ports: ["8080:8080"] env: { LOG_LEVEL: info }
post_tasks: - name: wait healthy uri: { url: "http://{{ inventory_hostname }}:8080/healthz", status_code: 200 } retries: 30 delay: 2 - name: re-add to LB command: aws elbv2 register-targets ... delegate_to: localhostRole: common
Section titled “Role: common”- name: ensure timezone timezone: { name: UTC }
- name: base packages apt: name: - curl - htop - vim - jq - tcpdump state: present update_cache: true
- name: SSH hardening lineinfile: path: /etc/ssh/sshd_config regexp: '^#?PermitRootLogin' line: 'PermitRootLogin no' notify: restart sshd
- name: deploy users user: name: "{{ item.name }}" groups: sudo shell: /bin/bash state: present loop: "{{ admin_users }}"Template + handler pattern
Section titled “Template + handler pattern”- name: install apt: { name: nginx, state: present }
- name: site config template: { src: site.conf.j2, dest: /etc/nginx/sites-available/default, mode: '0644' } notify: reload nginx
- name: enable + start service: { name: nginx, state: started, enabled: true }- name: reload nginx service: { name: nginx, state: reloaded }Vault usage
Section titled “Vault usage”# createansible-vault create group_vars/prod/secrets.yml# editansible-vault edit group_vars/prod/secrets.yml# stringansible-vault encrypt_string 'super' --name 'db_password' >> group_vars/prod/vars.yml# runansible-playbook site.yml --vault-password-file ~/.vault_passDynamic inventory (AWS EC2)
Section titled “Dynamic inventory (AWS EC2)”plugin: amazon.aws.aws_ec2regions: [eu-west-1]keyed_groups: - key: tags.role prefix: role - key: tags.env prefix: envhostnames: - tag:Namefilters: tag:env: prodansible-inventory -i inventory/aws_ec2.yml --list --graphMolecule test (per role)
Section titled “Molecule test (per role)”driver: { name: docker }platforms: - name: ubuntu22 image: geerlingguy/docker-ubuntu2204-ansible privileged: trueprovisioner: { name: ansible }verifier: { name: ansible }- hosts: all roles: [nginx]- hosts: all tasks: - name: nginx serves uri: { url: "http://localhost", status_code: 200 }molecule test- run: ansible-lint .- run: ansible-playbook -i inventory/staging.ini site.yml --check --diff- run: ansible-playbook -i inventory/staging.ini site.ymlUseful CLI
Section titled “Useful CLI”ansible all -m pingansible web -m setup -a 'filter=ansible_distribution*' # factsansible-playbook play.yml --start-at-task "deploy site"ansible-playbook play.yml -e tag=1.2.3 # extra varsansible-doc apt # module docsansible-config dump --only-changed- Ansible Lint — best practices.
- Molecule — role testing.
- AWX / Ansible Tower / AAP — UI + RBAC.
- Galaxy / collections — share/reuse.
- Mitogen — speedup plugin.