ansible-roles

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Ansible Roles

Ansible Roles

Structure and reuse automation code with Ansible roles for modular, maintainable infrastructure.
使用Ansible Roles构建并复用自动化代码,实现模块化、可维护的基础设施。

Role Directory Structure

Role目录结构

A well-organized Ansible role follows a standardized directory structure:
roles/
└── webserver/
    ├── README.md
    ├── defaults/
    │   └── main.yml
    ├── files/
    │   ├── nginx.conf
    │   └── ssl/
    │       ├── cert.pem
    │       └── key.pem
    ├── handlers/
    │   └── main.yml
    ├── meta/
    │   └── main.yml
    ├── tasks/
    │   ├── main.yml
    │   ├── install.yml
    │   ├── configure.yml
    │   └── security.yml
    ├── templates/
    │   ├── nginx.conf.j2
    │   └── site.conf.j2
    ├── tests/
    │   ├── inventory
    │   └── test.yml
    └── vars/
        └── main.yml
一个组织良好的Ansible Role遵循标准化的目录结构:
roles/
└── webserver/
    ├── README.md
    ├── defaults/
    │   └── main.yml
    ├── files/
    │   ├── nginx.conf
    │   └── ssl/
    │       ├── cert.pem
    │       └── key.pem
    ├── handlers/
    │   └── main.yml
    ├── meta/
    │   └── main.yml
    ├── tasks/
    │   ├── main.yml
    │   ├── install.yml
    │   ├── configure.yml
    │   └── security.yml
    ├── templates/
    │   ├── nginx.conf.j2
    │   └── site.conf.j2
    ├── tests/
    │   ├── inventory
    │   └── test.yml
    └── vars/
        └── main.yml

Basic Role Example

基础Role示例

tasks/main.yml

tasks/main.yml

yaml
---
yaml
---

Main task file for webserver role

Main task file for webserver role

  • name: Include OS-specific variables include_vars: "{{ ansible_os_family }}.yml"
  • name: Import installation tasks import_tasks: install.yml tags:
    • install
    • webserver
  • name: Import configuration tasks import_tasks: configure.yml tags:
    • configure
    • webserver
  • name: Import security tasks import_tasks: security.yml tags:
    • security
    • webserver
  • name: Ensure nginx is running service: name: "{{ nginx_service_name }}" state: started enabled: yes tags:
    • service
    • webserver
undefined
  • name: Include OS-specific variables include_vars: "{{ ansible_os_family }}.yml"
  • name: Import installation tasks import_tasks: install.yml tags:
    • install
    • webserver
  • name: Import configuration tasks import_tasks: configure.yml tags:
    • configure
    • webserver
  • name: Import security tasks import_tasks: security.yml tags:
    • security
    • webserver
  • name: Ensure nginx is running service: name: "{{ nginx_service_name }}" state: started enabled: yes tags:
    • service
    • webserver
undefined

tasks/install.yml

tasks/install.yml

yaml
---
yaml
---

Installation tasks for webserver role

Installation tasks for webserver role

  • name: Install nginx and dependencies (Debian/Ubuntu) apt: name: - nginx - nginx-extras - python3-passlib state: present update_cache: yes cache_valid_time: 3600 when: ansible_os_family == "Debian"
  • name: Install nginx and dependencies (RedHat/CentOS) yum: name: - nginx - nginx-mod-stream - python3-passlib state: present update_cache: yes when: ansible_os_family == "RedHat"
  • name: Create nginx directories file: path: "{{ item }}" state: directory owner: "{{ nginx_user }}" group: "{{ nginx_group }}" mode: '0755' loop:
    • "{{ nginx_conf_dir }}/sites-available"
    • "{{ nginx_conf_dir }}/sites-enabled"
    • "{{ nginx_log_dir }}"
    • "{{ nginx_cache_dir }}"
    • /var/www/html
  • name: Install certbot for SSL apt: name: certbot state: present when:
    • nginx_ssl_enabled
    • ansible_os_family == "Debian"
undefined
  • name: Install nginx and dependencies (Debian/Ubuntu) apt: name: - nginx - nginx-extras - python3-passlib state: present update_cache: yes cache_valid_time: 3600 when: ansible_os_family == "Debian"
  • name: Install nginx and dependencies (RedHat/CentOS) yum: name: - nginx - nginx-mod-stream - python3-passlib state: present update_cache: yes when: ansible_os_family == "RedHat"
  • name: Create nginx directories file: path: "{{ item }}" state: directory owner: "{{ nginx_user }}" group: "{{ nginx_group }}" mode: '0755' loop:
    • "{{ nginx_conf_dir }}/sites-available"
    • "{{ nginx_conf_dir }}/sites-enabled"
    • "{{ nginx_log_dir }}"
    • "{{ nginx_cache_dir }}"
    • /var/www/html
  • name: Install certbot for SSL apt: name: certbot state: present when:
    • nginx_ssl_enabled
    • ansible_os_family == "Debian"
undefined

tasks/configure.yml

tasks/configure.yml

yaml
---
yaml
---

Configuration tasks for webserver role

Configuration tasks for webserver role

  • name: Deploy main nginx configuration template: src: nginx.conf.j2 dest: "{{ nginx_conf_dir }}/nginx.conf" owner: root group: root mode: '0644' validate: 'nginx -t -c %s' backup: yes notify:
    • Reload nginx tags:
    • config
  • name: Deploy site configurations template: src: site.conf.j2 dest: "{{ nginx_conf_dir }}/sites-available/{{ item.name }}.conf" owner: root group: root mode: '0644' validate: 'nginx -t -c {{ nginx_conf_dir }}/nginx.conf' loop: "{{ nginx_sites }}" when: nginx_sites is defined notify:
    • Reload nginx
  • name: Enable sites file: src: "{{ nginx_conf_dir }}/sites-available/{{ item.name }}.conf" dest: "{{ nginx_conf_dir }}/sites-enabled/{{ item.name }}.conf" state: link loop: "{{ nginx_sites }}" when:
    • nginx_sites is defined
    • item.enabled | default(true) notify:
    • Reload nginx
  • name: Disable default site file: path: "{{ nginx_conf_dir }}/sites-enabled/default" state: absent when: nginx_disable_default_site notify:
    • Reload nginx
  • name: Configure log rotation template: src: logrotate.j2 dest: /etc/logrotate.d/nginx owner: root group: root mode: '0644'
undefined
  • name: Deploy main nginx configuration template: src: nginx.conf.j2 dest: "{{ nginx_conf_dir }}/nginx.conf" owner: root group: root mode: '0644' validate: 'nginx -t -c %s' backup: yes notify:
    • Reload nginx tags:
    • config
  • name: Deploy site configurations template: src: site.conf.j2 dest: "{{ nginx_conf_dir }}/sites-available/{{ item.name }}.conf" owner: root group: root mode: '0644' validate: 'nginx -t -c {{ nginx_conf_dir }}/nginx.conf' loop: "{{ nginx_sites }}" when: nginx_sites is defined notify:
    • Reload nginx
  • name: Enable sites file: src: "{{ nginx_conf_dir }}/sites-available/{{ item.name }}.conf" dest: "{{ nginx_conf_dir }}/sites-enabled/{{ item.name }}.conf" state: link loop: "{{ nginx_sites }}" when:
    • nginx_sites is defined
    • item.enabled | default(true) notify:
    • Reload nginx
  • name: Disable default site file: path: "{{ nginx_conf_dir }}/sites-enabled/default" state: absent when: nginx_disable_default_site notify:
    • Reload nginx
  • name: Configure log rotation template: src: logrotate.j2 dest: /etc/logrotate.d/nginx owner: root group: root mode: '0644'
undefined

tasks/security.yml

tasks/security.yml

yaml
---
yaml
---

Security tasks for webserver role

Security tasks for webserver role

  • name: Generate dhparam file command: openssl dhparam -out {{ nginx_conf_dir }}/dhparam.pem 2048 args: creates: "{{ nginx_conf_dir }}/dhparam.pem" when: nginx_ssl_enabled
  • name: Set secure permissions on dhparam file: path: "{{ nginx_conf_dir }}/dhparam.pem" owner: root group: root mode: '0600' when: nginx_ssl_enabled
  • name: Configure firewall rules (ufw) ufw: rule: allow port: "{{ item }}" proto: tcp loop:
    • "80"
    • "443" when:
    • nginx_configure_firewall
    • ansible_os_family == "Debian"
  • name: Configure firewall rules (firewalld) firewalld: service: "{{ item }}" permanent: yes state: enabled immediate: yes loop:
    • http
    • https when:
    • nginx_configure_firewall
    • ansible_os_family == "RedHat"
  • name: Create basic auth file htpasswd: path: "{{ nginx_conf_dir }}/.htpasswd" name: "{{ item.username }}" password: "{{ item.password }}" owner: root group: "{{ nginx_group }}" mode: '0640' loop: "{{ nginx_basic_auth_users }}" when: nginx_basic_auth_users is defined no_log: yes
undefined
  • name: Generate dhparam file command: openssl dhparam -out {{ nginx_conf_dir }}/dhparam.pem 2048 args: creates: "{{ nginx_conf_dir }}/dhparam.pem" when: nginx_ssl_enabled
  • name: Set secure permissions on dhparam file: path: "{{ nginx_conf_dir }}/dhparam.pem" owner: root group: root mode: '0600' when: nginx_ssl_enabled
  • name: Configure firewall rules (ufw) ufw: rule: allow port: "{{ item }}" proto: tcp loop:
    • "80"
    • "443" when:
    • nginx_configure_firewall
    • ansible_os_family == "Debian"
  • name: Configure firewall rules (firewalld) firewalld: service: "{{ item }}" permanent: yes state: enabled immediate: yes loop:
    • http
    • https when:
    • nginx_configure_firewall
    • ansible_os_family == "RedHat"
  • name: Create basic auth file htpasswd: path: "{{ nginx_conf_dir }}/.htpasswd" name: "{{ item.username }}" password: "{{ item.password }}" owner: root group: "{{ nginx_group }}" mode: '0640' loop: "{{ nginx_basic_auth_users }}" when: nginx_basic_auth_users is defined no_log: yes
undefined

Role Variables

Role变量

defaults/main.yml

defaults/main.yml

yaml
---
yaml
---

Default variables for webserver role

Default variables for webserver role

These can be overridden in playbooks or inventory

These can be overridden in playbooks or inventory

Package and service names

Package and service names

nginx_package_name: nginx nginx_service_name: nginx
nginx_package_name: nginx nginx_service_name: nginx

User and group

User and group

nginx_user: www-data nginx_group: www-data
nginx_user: www-data nginx_group: www-data

Directories

Directories

nginx_conf_dir: /etc/nginx nginx_log_dir: /var/log/nginx nginx_cache_dir: /var/cache/nginx nginx_pid_file: /var/run/nginx.pid
nginx_conf_dir: /etc/nginx nginx_log_dir: /var/log/nginx nginx_cache_dir: /var/cache/nginx nginx_pid_file: /var/run/nginx.pid

Main configuration

Main configuration

nginx_worker_processes: auto nginx_worker_connections: 1024 nginx_keepalive_timeout: 65 nginx_client_max_body_size: 10m
nginx_worker_processes: auto nginx_worker_connections: 1024 nginx_keepalive_timeout: 65 nginx_client_max_body_size: 10m

Performance tuning

Performance tuning

nginx_sendfile: on nginx_tcp_nopush: on nginx_tcp_nodelay: on nginx_gzip: on nginx_gzip_types:
  • text/plain
  • text/css
  • application/json
  • application/javascript
  • text/xml
  • application/xml
nginx_sendfile: on nginx_tcp_nopush: on nginx_tcp_nodelay: on nginx_gzip: on nginx_gzip_types:
  • text/plain
  • text/css
  • application/json
  • application/javascript
  • text/xml
  • application/xml

Security

Security

nginx_ssl_enabled: no nginx_ssl_protocols: "TLSv1.2 TLSv1.3" nginx_ssl_ciphers: "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256" nginx_ssl_prefer_server_ciphers: on nginx_disable_default_site: yes nginx_configure_firewall: yes nginx_server_tokens: off
nginx_ssl_enabled: no nginx_ssl_protocols: "TLSv1.2 TLSv1.3" nginx_ssl_ciphers: "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256" nginx_ssl_prefer_server_ciphers: on nginx_disable_default_site: yes nginx_configure_firewall: yes nginx_server_tokens: off

Sites configuration

Sites configuration

nginx_sites: []
nginx_sites: []

Example:

Example:

nginx_sites:

nginx_sites:

- name: example.com

- name: example.com

server_name: example.com www.example.com

server_name: example.com www.example.com

root: /var/www/example.com

root: /var/www/example.com

enabled: yes

enabled: yes

ssl: yes

ssl: yes

Basic authentication

Basic authentication

nginx_basic_auth_users:

nginx_basic_auth_users:

- username: admin

- username: admin

password: secretpassword

password: secretpassword

undefined
undefined

vars/main.yml

vars/main.yml

yaml
---
yaml
---

Variables that should not be overridden

Variables that should not be overridden

nginx_conf_path: "{{ nginx_conf_dir }}/nginx.conf" nginx_error_log: "{{ nginx_log_dir }}/error.log" nginx_access_log: "{{ nginx_log_dir }}/access.log"
nginx_conf_path: "{{ nginx_conf_dir }}/nginx.conf" nginx_error_log: "{{ nginx_log_dir }}/error.log" nginx_access_log: "{{ nginx_log_dir }}/access.log"

OS-specific overrides loaded via include_vars

OS-specific overrides loaded via include_vars

undefined
undefined

vars/Debian.yml

vars/Debian.yml

yaml
---
nginx_user: www-data
nginx_group: www-data
nginx_conf_dir: /etc/nginx
nginx_service_name: nginx
yaml
---
nginx_user: www-data
nginx_group: www-data
nginx_conf_dir: /etc/nginx
nginx_service_name: nginx

vars/RedHat.yml

vars/RedHat.yml

yaml
---
nginx_user: nginx
nginx_group: nginx
nginx_conf_dir: /etc/nginx
nginx_service_name: nginx
yaml
---
nginx_user: nginx
nginx_group: nginx
nginx_conf_dir: /etc/nginx
nginx_service_name: nginx

Role Handlers

Role处理器

handlers/main.yml

handlers/main.yml

yaml
---
yaml
---

Handlers for webserver role

Handlers for webserver role

  • name: Reload nginx service: name: "{{ nginx_service_name }}" state: reloaded listen: "reload nginx"
  • name: Restart nginx service: name: "{{ nginx_service_name }}" state: restarted listen: "restart nginx"
  • name: Validate nginx config command: nginx -t changed_when: false listen: "validate nginx"
  • name: Reload firewall service: name: ufw state: reloaded when: ansible_os_family == "Debian" listen: "reload firewall"
undefined
  • name: Reload nginx service: name: "{{ nginx_service_name }}" state: reloaded listen: "reload nginx"
  • name: Restart nginx service: name: "{{ nginx_service_name }}" state: restarted listen: "restart nginx"
  • name: Validate nginx config command: nginx -t changed_when: false listen: "validate nginx"
  • name: Reload firewall service: name: ufw state: reloaded when: ansible_os_family == "Debian" listen: "reload firewall"
undefined

Role Templates

Role模板

templates/nginx.conf.j2

templates/nginx.conf.j2

jinja2
undefined
jinja2
undefined

{{ ansible_managed }}

{{ ansible_managed }}

user {{ nginx_user }}; worker_processes {{ nginx_worker_processes }}; pid {{ nginx_pid_file }};
events { worker_connections {{ nginx_worker_connections }}; use epoll; multi_accept on; }
http { ## # Basic Settings ## sendfile {{ nginx_sendfile | ternary('on', 'off') }}; tcp_nopush {{ nginx_tcp_nopush | ternary('on', 'off') }}; tcp_nodelay {{ nginx_tcp_nodelay | ternary('on', 'off') }}; keepalive_timeout {{ nginx_keepalive_timeout }}; types_hash_max_size 2048; server_tokens {{ nginx_server_tokens | ternary('on', 'off') }}; client_max_body_size {{ nginx_client_max_body_size }};
include {{ nginx_conf_dir }}/mime.types;
default_type application/octet-stream;

##
# SSL Settings
##
{% if nginx_ssl_enabled %} ssl_protocols {{ nginx_ssl_protocols }}; ssl_ciphers {{ nginx_ssl_ciphers }}; ssl_prefer_server_ciphers {{ nginx_ssl_prefer_server_ciphers | ternary('on', 'off') }}; ssl_dhparam {{ nginx_conf_dir }}/dhparam.pem; ssl_session_cache shared:SSL:10m; ssl_session_timeout 10m; {% endif %}
##
# Logging Settings
##
access_log {{ nginx_access_log }};
error_log {{ nginx_error_log }};

##
# Gzip Settings
##
gzip {{ nginx_gzip | ternary('on', 'off') }};
{% if nginx_gzip %} gzip_vary on; gzip_proxied any; gzip_comp_level 6; gzip_types {{ nginx_gzip_types | join(' ') }}; {% endif %}
##
# Virtual Host Configs
##
include {{ nginx_conf_dir }}/sites-enabled/*;
}
undefined
user {{ nginx_user }}; worker_processes {{ nginx_worker_processes }}; pid {{ nginx_pid_file }};
events { worker_connections {{ nginx_worker_connections }}; use epoll; multi_accept on; }
http { ## # Basic Settings ## sendfile {{ nginx_sendfile | ternary('on', 'off') }}; tcp_nopush {{ nginx_tcp_nopush | ternary('on', 'off') }}; tcp_nodelay {{ nginx_tcp_nodelay | ternary('on', 'off') }}; keepalive_timeout {{ nginx_keepalive_timeout }}; types_hash_max_size 2048; server_tokens {{ nginx_server_tokens | ternary('on', 'off') }}; client_max_body_size {{ nginx_client_max_body_size }};
include {{ nginx_conf_dir }}/mime.types;
default_type application/octet-stream;

##
# SSL Settings
##
{% if nginx_ssl_enabled %} ssl_protocols {{ nginx_ssl_protocols }}; ssl_ciphers {{ nginx_ssl_ciphers }}; ssl_prefer_server_ciphers {{ nginx_ssl_prefer_server_ciphers | ternary('on', 'off') }}; ssl_dhparam {{ nginx_conf_dir }}/dhparam.pem; ssl_session_cache shared:SSL:10m; ssl_session_timeout 10m; {% endif %}
##
# Logging Settings
##
access_log {{ nginx_access_log }};
error_log {{ nginx_error_log }};

##
# Gzip Settings
##
gzip {{ nginx_gzip | ternary('on', 'off') }};
{% if nginx_gzip %} gzip_vary on; gzip_proxied any; gzip_comp_level 6; gzip_types {{ nginx_gzip_types | join(' ') }}; {% endif %}
##
# Virtual Host Configs
##
include {{ nginx_conf_dir }}/sites-enabled/*;
}
undefined

templates/site.conf.j2

templates/site.conf.j2

jinja2
undefined
jinja2
undefined

{{ ansible_managed }}

{{ ansible_managed }}

Site: {{ item.name }}

Site: {{ item.name }}

{% if item.ssl | default(false) %}
{% if item.ssl | default(false) %}

Redirect HTTP to HTTPS

Redirect HTTP to HTTPS

server { listen 80; listen [::]:80; server_name {{ item.server_name }}; return 301 https://$server_name$request_uri; }
server { listen 443 ssl http2; listen [::]:443 ssl http2; server_name {{ item.server_name }};
ssl_certificate {{ item.ssl_cert | default('/etc/letsencrypt/live/' + item.name + '/fullchain.pem') }};
ssl_certificate_key {{ item.ssl_key | default('/etc/letsencrypt/live/' + item.name + '/privkey.pem') }};
{% else %} server { listen 80; listen [::]:80; server_name {{ item.server_name }}; {% endif %}
root {{ item.root | default('/var/www/' + item.name) }};
index {{ item.index | default('index.html index.htm') }};
{% if item.access_log is defined %} access_log {{ item.access_log }}; {% endif %} {% if item.error_log is defined %} error_log {{ item.error_log }}; {% endif %}
{% if item.basic_auth | default(false) %} auth_basic "Restricted Access"; auth_basic_user_file {{ nginx_conf_dir }}/.htpasswd; {% endif %}
location / {
{% if item.proxy_pass is defined %} proxy_pass {{ item.proxy_pass }}; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; {% else %} try_files $uri $uri/ =404; {% endif %} }
{% if item.locations is defined %} {% for location in item.locations %} location {{ location.path }} { {% if location.proxy_pass is defined %} proxy_pass {{ location.proxy_pass }}; {% endif %} {% if location.alias is defined %} alias {{ location.alias }}; {% endif %} {% if location.return is defined %} return {{ location.return }}; {% endif %} } {% endfor %} {% endif %}
# Security headers
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
}
undefined
server { listen 80; listen [::]:80; server_name {{ item.server_name }}; return 301 https://$server_name$request_uri; }
server { listen 443 ssl http2; listen [::]:443 ssl http2; server_name {{ item.server_name }};
ssl_certificate {{ item.ssl_cert | default('/etc/letsencrypt/live/' + item.name + '/fullchain.pem') }};
ssl_certificate_key {{ item.ssl_key | default('/etc/letsencrypt/live/' + item.name + '/privkey.pem') }};
{% else %} server { listen 80; listen [::]:80; server_name {{ item.server_name }}; {% endif %}
root {{ item.root | default('/var/www/' + item.name) }};
index {{ item.index | default('index.html index.htm') }};
{% if item.access_log is defined %} access_log {{ item.access_log }}; {% endif %} {% if item.error_log is defined %} error_log {{ item.error_log }}; {% endif %}
{% if item.basic_auth | default(false) %} auth_basic "Restricted Access"; auth_basic_user_file {{ nginx_conf_dir }}/.htpasswd; {% endif %}
location / {
{% if item.proxy_pass is defined %} proxy_pass {{ item.proxy_pass }}; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; {% else %} try_files $uri $uri/ =404; {% endif %} }
{% if item.locations is defined %} {% for location in item.locations %} location {{ location.path }} { {% if location.proxy_pass is defined %} proxy_pass {{ location.proxy_pass }}; {% endif %} {% if location.alias is defined %} alias {{ location.alias }}; {% endif %} {% if location.return is defined %} return {{ location.return }}; {% endif %} } {% endfor %} {% endif %}
# Security headers
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
}
undefined

Role Dependencies

Role依赖

meta/main.yml

meta/main.yml

yaml
---
galaxy_info:
  role_name: webserver
  author: Your Organization
  description: Install and configure nginx web server
  company: Your Company
  license: MIT
  min_ansible_version: 2.9

  platforms:
    - name: Ubuntu
      versions:
        - focal
        - jammy
    - name: Debian
      versions:
        - buster
        - bullseye
    - name: EL
      versions:
        - 7
        - 8
        - 9

  galaxy_tags:
    - web
    - nginx
    - webserver
    - http

dependencies:
  - role: common
    vars:
      common_packages:
        - curl
        - wget

  - role: firewall
    when: nginx_configure_firewall

allow_duplicates: no
yaml
---
galaxy_info:
  role_name: webserver
  author: Your Organization
  description: Install and configure nginx web server
  company: Your Company
  license: MIT
  min_ansible_version: 2.9

  platforms:
    - name: Ubuntu
      versions:
        - focal
        - jammy
    - name: Debian
      versions:
        - buster
        - bullseye
    - name: EL
      versions:
        - 7
        - 8
        - 9

  galaxy_tags:
    - web
    - nginx
    - webserver
    - http

dependencies:
  - role: common
    vars:
      common_packages:
        - curl
        - wget

  - role: firewall
    when: nginx_configure_firewall

allow_duplicates: no

Using Roles in Playbooks

在Playbook中使用Role

Simple Role Usage

简单Role使用

yaml
---
- name: Configure web servers
  hosts: webservers
  become: yes

  roles:
    - webserver
yaml
---
- name: Configure web servers
  hosts: webservers
  become: yes

  roles:
    - webserver

Role with Variables

带变量的Role使用

yaml
---
- name: Configure web servers with custom settings
  hosts: webservers
  become: yes

  roles:
    - role: webserver
      vars:
        nginx_worker_processes: 4
        nginx_ssl_enabled: yes
        nginx_sites:
          - name: example.com
            server_name: example.com www.example.com
            root: /var/www/example.com
            ssl: yes
            ssl_cert: /etc/ssl/certs/example.com.crt
            ssl_key: /etc/ssl/private/example.com.key
yaml
---
- name: Configure web servers with custom settings
  hosts: webservers
  become: yes

  roles:
    - role: webserver
      vars:
        nginx_worker_processes: 4
        nginx_ssl_enabled: yes
        nginx_sites:
          - name: example.com
            server_name: example.com www.example.com
            root: /var/www/example.com
            ssl: yes
            ssl_cert: /etc/ssl/certs/example.com.crt
            ssl_key: /etc/ssl/private/example.com.key

Role with Tags

带标签的Role使用

yaml
---
- name: Configure infrastructure
  hosts: all
  become: yes

  roles:
    - role: webserver
      tags:
        - web
        - nginx

    - role: database
      tags:
        - db
        - postgres
yaml
---
- name: Configure infrastructure
  hosts: all
  become: yes

  roles:
    - role: webserver
      tags:
        - web
        - nginx

    - role: database
      tags:
        - db
        - postgres

Pre and Post Tasks

前置与后置任务

yaml
---
- name: Deploy web application
  hosts: webservers
  become: yes

  pre_tasks:
    - name: Announce deployment
      debug:
        msg: "Starting deployment to {{ inventory_hostname }}"

    - name: Check disk space
      command: df -h /
      register: disk_space
      changed_when: false

  roles:
    - webserver
    - monitoring

  post_tasks:
    - name: Verify nginx is responding
      uri:
        url: http://localhost
        status_code: 200
      retries: 3
      delay: 5

    - name: Notify completion
      debug:
        msg: "Deployment completed successfully"
yaml
---
- name: Deploy web application
  hosts: webservers
  become: yes

  pre_tasks:
    - name: Announce deployment
      debug:
        msg: "Starting deployment to {{ inventory_hostname }}"

    - name: Check disk space
      command: df -h /
      register: disk_space
      changed_when: false

  roles:
    - webserver
    - monitoring

  post_tasks:
    - name: Verify nginx is responding
      uri:
        url: http://localhost
        status_code: 200
      retries: 3
      delay: 5

    - name: Notify completion
      debug:
        msg: "Deployment completed successfully"

Role Inclusion Methods

Role包含方式

Static Import

静态导入

yaml
---
- name: Configure servers
  hosts: all

  tasks:
    - name: Import webserver role
      import_role:
        name: webserver
      vars:
        nginx_worker_processes: 2
      tags:
        - webserver
yaml
---
- name: Configure servers
  hosts: all

  tasks:
    - name: Import webserver role
      import_role:
        name: webserver
      vars:
        nginx_worker_processes: 2
      tags:
        - webserver

Dynamic Include

动态包含

yaml
---
- name: Configure servers based on conditions
  hosts: all

  tasks:
    - name: Include webserver role for web servers
      include_role:
        name: webserver
      when: "'webservers' in group_names"

    - name: Include database role for db servers
      include_role:
        name: database
      when: "'databases' in group_names"
yaml
---
- name: Configure servers based on conditions
  hosts: all

  tasks:
    - name: Include webserver role for web servers
      include_role:
        name: webserver
      when: "'webservers' in group_names"

    - name: Include database role for db servers
      include_role:
        name: database
      when: "'databases' in group_names"

Import with Task Files

与任务文件一起导入

yaml
---
- name: Custom installation workflow
  hosts: webservers

  tasks:
    - name: Run pre-installation checks
      import_role:
        name: webserver
        tasks_from: preflight

    - name: Install nginx
      import_role:
        name: webserver
        tasks_from: install

    - name: Configure nginx
      import_role:
        name: webserver
        tasks_from: configure
yaml
---
- name: Custom installation workflow
  hosts: webservers

  tasks:
    - name: Run pre-installation checks
      import_role:
        name: webserver
        tasks_from: preflight

    - name: Install nginx
      import_role:
        name: webserver
        tasks_from: install

    - name: Configure nginx
      import_role:
        name: webserver
        tasks_from: configure

Creating Roles with Ansible Galaxy

使用Ansible Galaxy创建Role

Initialize a New Role

初始化新Role

bash
undefined
bash
undefined

Create role structure

Create role structure

ansible-galaxy init roles/myapp
ansible-galaxy init roles/myapp

Create role with custom template

Create role with custom template

ansible-galaxy init --init-path roles/ myapp
ansible-galaxy init --init-path roles/ myapp

List role files

List role files

tree roles/myapp
undefined
tree roles/myapp
undefined

Install Roles from Galaxy

从Galaxy安装Role

bash
undefined
bash
undefined

Install a role

Install a role

ansible-galaxy install geerlingguy.nginx
ansible-galaxy install geerlingguy.nginx

Install specific version

Install specific version

ansible-galaxy install geerlingguy.nginx,2.8.0
ansible-galaxy install geerlingguy.nginx,2.8.0

Install from requirements file

Install from requirements file

ansible-galaxy install -r requirements.yml
undefined
ansible-galaxy install -r requirements.yml
undefined

requirements.yml

requirements.yml

yaml
---
yaml
---

Install from Ansible Galaxy

Install from Ansible Galaxy

  • name: geerlingguy.nginx version: 2.8.0
  • name: geerlingguy.postgresql version: 3.4.0
  • name: geerlingguy.nginx version: 2.8.0
  • name: geerlingguy.postgresql version: 3.4.0

Install from Git repository

Install from Git repository

Install from local path

Install from local path

  • name: internal-role src: /path/to/roles/internal-role
undefined
  • name: internal-role src: /path/to/roles/internal-role
undefined

Advanced Role Patterns

高级Role模式

Role with Multiple Entry Points

多入口点Role

yaml
undefined
yaml
undefined

roles/webserver/tasks/main.yml

roles/webserver/tasks/main.yml


  • name: Default task flow import_tasks: "{{ webserver_task_flow | default('standard') }}.yml"

```yaml

  • name: Default task flow import_tasks: "{{ webserver_task_flow | default('standard') }}.yml"

```yaml

roles/webserver/tasks/standard.yml

roles/webserver/tasks/standard.yml


  • import_tasks: install.yml
  • import_tasks: configure.yml
  • import_tasks: security.yml

```yaml

  • import_tasks: install.yml
  • import_tasks: configure.yml
  • import_tasks: security.yml

```yaml

roles/webserver/tasks/minimal.yml

roles/webserver/tasks/minimal.yml


  • import_tasks: install.yml
  • import_tasks: configure.yml
undefined

  • import_tasks: install.yml
  • import_tasks: configure.yml
undefined

Conditional Role Execution

条件化Role执行

yaml
---
- name: Configure servers with conditional roles
  hosts: all
  become: yes

  roles:
    - role: webserver
      when:
        - ansible_os_family == "Debian"
        - inventory_hostname in groups['webservers']

    - role: webserver-nginx
      when: webserver_type == "nginx"

    - role: webserver-apache
      when: webserver_type == "apache"
yaml
---
- name: Configure servers with conditional roles
  hosts: all
  become: yes

  roles:
    - role: webserver
      when:
        - ansible_os_family == "Debian"
        - inventory_hostname in groups['webservers']

    - role: webserver-nginx
      when: webserver_type == "nginx"

    - role: webserver-apache
      when: webserver_type == "apache"

Nested Role Dependencies

嵌套Role依赖

yaml
undefined
yaml
undefined

roles/application/meta/main.yml

roles/application/meta/main.yml


dependencies:
  • role: webserver vars: nginx_sites: - name: "{{ app_name }}" server_name: "{{ app_domain }}" proxy_pass: "http://localhost:{{ app_port }}"
  • role: database vars: db_name: "{{ app_db_name }}" db_user: "{{ app_db_user }}"
  • role: monitoring vars: monitor_services: - nginx - "{{ app_name }}"
undefined

dependencies:
  • role: webserver vars: nginx_sites: - name: "{{ app_name }}" server_name: "{{ app_domain }}" proxy_pass: "http://localhost:{{ app_port }}"
  • role: database vars: db_name: "{{ app_db_name }}" db_user: "{{ app_db_user }}"
  • role: monitoring vars: monitor_services: - nginx - "{{ app_name }}"
undefined

When to Use This Skill

何时使用该技能

Use the ansible-roles skill when you need to:
  • Structure reusable automation code across multiple playbooks and projects
  • Implement modular infrastructure as code with clear separation of concerns
  • Share automation logic between teams or projects
  • Create distributable automation packages for common infrastructure patterns
  • Organize complex playbooks into manageable, testable components
  • Implement role-based configuration management with variable precedence
  • Build layered infrastructure with role dependencies
  • Version control automation logic independently from playbooks
  • Create standardized infrastructure components for consistency
  • Implement security and compliance requirements through reusable roles
  • Build internal automation libraries for your organization
  • Contribute to or consume community automation from Ansible Galaxy
  • Test infrastructure components in isolation before integration
  • Implement different configurations for development, staging, and production
  • Create self-documenting infrastructure through role metadata
当你需要以下场景时,使用ansible-roles技能:
  • 在多个Playbook和项目中构建可复用的自动化代码
  • 实现关注点分离的模块化基础设施即代码
  • 在团队或项目间共享自动化逻辑
  • 为常见基础设施模式创建可分发的自动化包
  • 将复杂的Playbook组织为可管理、可测试的组件
  • 实现基于Role的配置管理,支持变量优先级
  • 通过Role依赖构建分层基础设施
  • 独立于Playbook对自动化逻辑进行版本控制
  • 创建标准化基础设施组件以确保一致性
  • 通过可复用的Role实现安全与合规要求
  • 为你的组织构建内部自动化库
  • 贡献或使用Ansible Galaxy中的社区自动化内容
  • 在集成前独立测试基础设施组件
  • 为开发、 staging和生产环境实现不同配置
  • 通过Role元数据创建自文档化的基础设施

Best Practices

最佳实践

  1. Follow standard directory structure - Use ansible-galaxy init to create roles with proper organization
  2. Use defaults wisely - Place overridable variables in defaults/main.yml, non-overridable in vars/main.yml
  3. Document thoroughly - Include comprehensive README.md with usage examples and variable documentation
  4. Keep roles focused - Each role should have a single, well-defined purpose
  5. Use role dependencies - Declare dependencies in meta/main.yml rather than in playbooks
  6. Tag appropriately - Apply meaningful tags to tasks for selective execution
  7. Implement idempotency - Ensure roles can be run multiple times safely
  8. Version your roles - Use semantic versioning for role releases
  9. Test roles independently - Include test playbooks in tests/ directory
  10. Use templates for configuration - Prefer Jinja2 templates over static files for flexibility
  11. Implement OS detection - Use ansible_os_family for cross-platform compatibility
  12. Secure sensitive data - Use ansible-vault for passwords and secrets in role variables
  13. Use handlers correctly - Only notify handlers when configuration changes
  14. Validate configurations - Use validate parameter in template/copy modules
  15. Name tasks clearly - Use descriptive names that explain what each task does
  1. 遵循标准目录结构 - 使用ansible-galaxy init创建具有合理组织的Role
  2. 明智使用默认变量 - 将可覆盖的变量放在defaults/main.yml中,不可覆盖的放在vars/main.yml中
  3. 全面文档化 - 包含详细的README.md,提供使用示例和变量说明
  4. 保持Role聚焦 - 每个Role应具有单一、明确的用途
  5. 使用Role依赖 - 在meta/main.yml中声明依赖,而非在Playbook中
  6. 合理添加标签 - 为任务应用有意义的标签以支持选择性执行
  7. 实现幂等性 - 确保Role可以安全地多次运行
  8. 为Role版本化 - 对Role发布使用语义化版本控制
  9. 独立测试Role - 在tests/目录中包含测试Playbook
  10. 使用模板进行配置 - 优先使用Jinja2模板而非静态文件以提升灵活性
  11. 实现操作系统检测 - 使用ansible_os_family实现跨平台兼容性
  12. 保护敏感数据 - 使用ansible-vault处理Role变量中的密码和机密信息
  13. 正确使用处理器 - 仅在配置变更时通知处理器
  14. 验证配置 - 在template/copy模块中使用validate参数
  15. 清晰命名任务 - 使用描述性名称说明每个任务的作用

Common Pitfalls

常见陷阱

  1. Overly complex roles - Trying to make one role do too many things
  2. Poor variable naming - Using generic names that conflict with other roles
  3. Missing role prefix - Not prefixing role variables with role name
  4. Ignoring variable precedence - Not understanding how Ansible resolves variable conflicts
  5. Hard-coded values - Embedding environment-specific values instead of using variables
  6. Missing dependencies - Not declaring role dependencies in meta/main.yml
  7. No validation - Deploying configurations without validation checks
  8. Skipping tests - Not including test playbooks or scenarios
  9. Poor handler design - Restarting services unnecessarily or not at all
  10. Missing OS support - Assuming all target systems are the same
  11. No backup strategy - Not backing up configurations before changes
  12. Ignoring idempotency - Using command/shell modules without proper guards
  13. Missing tags - Not tagging tasks for selective execution
  14. Poor template practices - Complex logic in templates instead of variables
  15. No version control - Not versioning roles or tracking changes
  1. 过于复杂的Role - 试图让一个Role处理过多事务
  2. 变量命名不佳 - 使用通用名称导致与其他Role冲突
  3. 缺少Role前缀 - 不为Role变量添加Role名称前缀
  4. 忽略变量优先级 - 不了解Ansible如何解决变量冲突
  5. 硬编码值 - 嵌入环境特定值而非使用变量
  6. 缺少依赖声明 - 未在meta/main.yml中声明Role依赖
  7. 未做验证 - 部署配置前未进行验证检查
  8. 跳过测试 - 未包含测试Playbook或场景
  9. 处理器设计不佳 - 不必要地重启服务或完全不重启
  10. 缺少操作系统支持 - 假设所有目标系统都相同
  11. 无备份策略 - 变更前未备份配置
  12. 忽略幂等性 - 未添加适当防护就使用command/shell模块
  13. 缺少标签 - 不为任务添加标签以支持选择性执行
  14. 模板实践不佳 - 在模板中使用复杂逻辑而非变量
  15. 未进行版本控制 - 未对Role进行版本控制或跟踪变更

Resources

资源