1.roles角色
假设我们要写一个 playbook 来安装管理 lnmp 环境,那么这个 playbook 就会写很长。
所以我们希望把这个很大的文件分成多个功能拆分,分成:apache 管理、php 管理、mysql 管理,然后在需要使用的时候直接调用就可以了,以免重复写。
就类似编程里的模块化的概念,以达到代码复用的效果。
Roles 角色是 ansible 自1.2版本引入的新特性,用于层次性、结构化地组织 playbook。能够根据层次型结构自动装载变量文件、tasks 以及 handlers 等。
要使用 roles 只需要在 playbook 中使用include 指令即可。
简单来讲,roles 就是通过分别将变量、文件、任务、模板及处理器放置于单独的目录中,并可以便捷地 include 它们的一种机制。角色一般用于基于主机构建服务的场景中,但也可以是用于构建守护进程等场景中。
roles 优点:
-
模块中指令较少,方便编写
-
重复调用方便
-
排错方便
2.Roles目录编排
roles目录结构如下所示

每个角色,以特定的层级目录结构进行组织
roles 目录结构:
roles/nginx/
├── defaults/ # 默认变量
│ └── main.yml # 默认变量定义文件
├── files/ # 静态文件(如配置文件)
│ └── example.conf # 示例配置文件
│ └── index.html # 示例配置文件
├── handlers/ # 事件处理器
│ └── main.yml # 处理器定义文件
├── meta/ # 角色依赖关系
│ └── main.yml # 定义角色依赖关系
├── tasks/ # 任务列表
│ └── main.yml # 主任务文件
├── templates/ # Jinja2 模板文件
│ └── example.conf.j2 # 示例模板文件
├── tests/ # 测试配置
│ ├── inventory # 测试使用的主机清单文件
│ └── test.yml # 测试 Playbook 文件
└── vars/ # 变量
└── main.yml # 变量定义文件
Roles 各目录作用:
-
roles/:项目名称,有以下子目录 -
files/:存放由copy或script模块等调用的文件 -
templates/:template模块查找所需要模板文件的目录 -
tasks/:定义task,role的基本元素,至少应该包含一个名为main.yml的文件;其它的文件需要在此文件中通过include进行包含 -
handlers/:至少应该包含一个名为main.yml的文件;其它的文件需要在此文件中通过include进行包含 -
vars/:定义变量,至少应该包含一个名为main.yml的文件;其它的文件需要在此文件中通过include进行包含 -
meta/:定义当前角色的特殊设定及其依赖关系,至少应该包含一个名为main.yml的文件,其它文件需在此文件中通过include进行包含 -
default/:设定默认变量时使用此目录中的main.yml文件,比vars的优先级低
3.创建 role
创建 role 的步骤:
-
第一步: 创建以
roles命名的目录 -
第二步: 在
roles目录中分别创建以各角色名称命名的目录,如:mysql、nginx等 -
第三步: 在每个角色命名的目录中分别创建:
files、handlers、meta、tasks、templates和vars目录;用不到的目录可以创建为空目录,也可以不创建。 -
第四步: 在
playbook文件中,调用各角色,playbook文件可以直接定义在 roles 目录下,也可以定义在不同角色的目录下。
roles 的目录结构:
├── mysql
│ ├── files
│ ├── handlers
│ │ └── main.yml
│ ├── tasks
│ │ └── main.yml
│ ├── templates
│ └── vars
│ └── main.yml
└── nginx
├── files
├── handlers
│ └── main.yml
├── nginx.yml
├── tasks
│ ├── a1.yml
│ ├── a2.yml
│ └── main.yml
├── templates
└── vars
└── main.yml
请按照上述的目录结构来 roles ,在 roles 下分别有两个角色 mysql 和 nginx 。然后在 tasks、handlers、vars 等目录下创建 main.yml
切换到 nginx/tasks 目录分别创建 a1.yml 和 a2.yml ,然后在 main.yml 中通过 include 命令分别引入不同的任务,如下:
---
- name: install nginx
tags: nginx
include_tasks: a1.yml
- name: start nginx
include_tasks: a2.yml
在 playbook 中调用角色。
-
调用角色方法1:
- hosts: websrvs
remote_user: root
roles:- mysql
- nginx
- hosts: websrvs
-
调用角色方法2:
键role用于指定角色名称,后续的k/v用于传递变量给角色
---
- hosts: all
remote_user: root
roles:
- mysql
- { role: nginx, username: nginx }
- role: nginx
vars:
username: nginx
groupname: nginx
service_state: started
- 调用角色方法3:
还可基于条件测试实现角色调用
---
- hosts: all
remote_user: root
roles:
- { role: nginx, username: nginx, when: ansible_distribution_major_version == '7' }
roles 中 tags 使用
#nginx-role.yml
---
- hosts: websrvs
remote_user: root
roles:
- { role: nginx ,tags: [ 'nginx', 'web' ] ,when: ansible_distribution_major_version == "6" }
- { role: httpd ,tags: [ 'httpd', 'web' ] }
- { role: mysql ,tags: [ 'mysql', 'db' ] }
- { role: mariadb ,tags: [ 'mariadb', 'db' ] }
ansible-playbook --tags="nginx,httpd,mysql" nginx-role.yml
4.实战案例
基于 Ansible 来实现 LNMP 的远程发布。
4.1.Nginx
-
第一步:
Ansible目录及脚本文件定义定义变量
roleName=nginx
基于变量批量创建文件目录
mkdir -p roles/${roleName}/{tasks,handlers,vars,files,templates}
创建对应模块的主文件
touch roles/${roleName}/{tasks,handlers,vars,files,templates}/main.yml
-
第二步:切换到
files目录下,创建nginx.repo文件,配置如下内容:[nginx-stable]
name=nginx stable repo
baseurl=http://nginx.org/packages/centos/$releasever/$basearch/
gpgcheck=1
enabled=1
gpgkey=https://nginx.org/keys/nginx_signing.key
module_hotfixes=true -
第三步:切换至
tasks目录,创建nginx.yml文件,逐一配置执行任务。安装 yum-utils 工具包
- name: install utils
yum:
name: yum-utils
state: present
将files/nginx.repo文件复制到远程机器的/etc/yum.repos.d/目录下,并设置文件拥有者和所属组及权限
- name: copy nginx.repo
copy:
src: nginx.repo
dest: /etc/yum.repos.d/nginx.repo
owner: root
group: root
mode: '0644'
远程安装Nginx服务
- name: install nginx
yum:
name: nginx
state: present设置通知,也就是触发器,重启Nginx服务
notify:- restart nginx
- name: install utils
注意:这里不要在 tasks 目录下的主文件 main.yml 中定义执行任务,而是要在具体的配置文件中定义执行任务,最后通过 include_tasks 方式,在主文件 main.yml 中引入其他配置文件。
-
第四步:切换至
handlers目录下,编辑main.yml,来配置被通知时才执行的特殊任务。
- name: restart nginx
service:
name: nginx
state: restarted
- name: restart nginx
-
第五步:再次切换至
tasks/nginx.yml文件,继续添加执行任务。执行lineinfile模块实现对nginx.conf配置文件的内容替换
- name: configure nginx
lineinfile:要被替换的配置文件位置
path: /etc/nginx/nginx.conf使用正则表达式进行匹配
regexp: '^user'设置要替换的文本行
line: 'user root;'1.backrefs为no时,如果没有匹配,则添加一行line。如果匹配了,则把匹配内容替被换为line内容。
2.backrefs为yes时,如果没有匹配,则文件保持不变。如果匹配了,把匹配内容替被换为line内容
backrefs: yes
备份nginx配置文件
- name: backup default nginx config
command: cp /etc/nginx/conf.d/default.conf /etc/nginx/conf.d/default.conf.bak
args:
creates: /etc/nginx/conf.d/default.conf.bak
创建blog.conf配置文件,默认80端口
- name: create blog.conf
command: mv /etc/nginx/conf.d/default.conf /etc/nginx/conf.d/blog.conf
args:
creates: /etc/nginx/conf.d/blog.conf
使用模板文件,创建nginx配置文件
- name: config test.conf
template:
src: test.conf.j2
dest: /etc/nginx/conf.d/test.conf
- name: configure nginx
至此,部分配置结束,由于使用了模板文件,需要切换到 templates 目录下去定义模板文件内容。
-
第六步:切换至
vars目录下,编辑main.yml文件,定义配置所需变量。nginx_port: 8080
nginx_root_dir: /var/www/html -
第七步:切换至
templates目录,创建test.conf.j2模板文件,配置如下内容:server {
listen {{nginx_port}};
server_name localhost;
location / {
root {{ nginx_root_dir }};
index index.php index.html index.htm;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
} -
第八步:再次编辑
tasks/nginx.yml文件,继续添加执行任务。- name: create directory
file:
path: "{{ nginx_root_dir }}"
state: directory
owner: nginx
group: nginx
mode: '0644' - name: copy index.html
copy:
src: index.html
dest: "{{ nginx_root_dir }}/index.html"
owner: nginx
group: nginx
mode: '0644'
notify:- restart nginx
- name: create directory
-
第九步:切换至
files目录下,创建index.html文件,配置内容:helle world
-
第十步:将
tasks/nginx.yml文件包含到tasks/main.yml主配置文件中。
- name: install nginx
include_tasks: nginx.yml
- name: install nginx
-
第十一步:切换至
roles目录外,创建nginx_deploy.yml文件,配置内容:
- name: deploy nginx
hosts: web
user: root
gather_facts: yes
roles:- role: nginx
- name: deploy nginx
最后,使用命令 ansible-playbook nginx_deploy.yml 来执行任务。
4.2.MySQL
-
第一步:定义
MySQL的Roles角色和相关脚本文件roleName=mysql
mkdir -p roles/{roleName}/{tasks,handlers,vars,files,templates} touch roles/{roleName}/tasks/main.yml
touch roles/{roleName}/handlers/main.yml touch roles/{roleName}/vars/main.yml
touch roles/${roleName}/templates/main.yml -
第二步:编辑
mysql/tasks/mysql.yml文件下载 MySQL 源仓库配置文件并保存到/tmp目录中
- name: Download MySQL repo RPM
shell: |
wget -O /tmp/mysql80-community-release-el7-8.noarch.rpm https://dev.mysql.com/get/mysql80-community-release-el7-8.noarch.rpm
args:
creates: /tmp/mysql80-community-release-el7-8.noarch.rpm
安装 MySQL 源仓库
- name: Install MySQL repository
yum:
name: /tmp/mysql80-community-release-el7-8.noarch.rpm
state: present
安装 MySQL Server
- name: Install MySQL server
yum:
name: mysql-community-server
state: present
disable_gpg_check: yes
启动 MySQL 服务并设置自启动
- name: Start MySQL service
service:
name: mysqld
state: started
enabled: yes
使用模板文件,创建shell脚本,并设置0755权限
- name: Generate secure script
template:
src: mysql_secure.j2
dest: /tmp/mysql_secure.sh
mode: '0755'
执行 /tmp/mysql_secure.sh 文件
- name: Execute secure script
shell: bash /tmp/mysql_secure.sh
- name: Download MySQL repo RPM
-
第三步:切换至
templates目录下,创建mysql_secure.j2模板文件。#!/bin/bash
获取临时密码
TEMP_PASS=(grep 'temporary password' /var/log/mysqld.log | awk '{print NF}')
设置新密码
NEW_PASS="{{ mysql_root_password }}"
修改 root 用户密码
mysql -u root -p"{TEMP_PASS}" --connect-expired-password -e \ "ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY '{NEW_PASS}';"
-
第四步:编辑
vars/main.yml文件,设置变量。mysql_root_password: 密码
注意:MySQL 密码有强度要求!!!
MySQL有默认的密码策略:
至少包含 1 位大小写
至少包含 1 位数字
包含 1 个特殊符号
必须 8 位及以上
-
第五步:将
tasks/mysql.yml文件包含到tasks/main.yml主配置文件中。
- name: install mysql
include_tasks: mysql.yml
- name: install mysql
-
第六步:切换至
roles目录外,创建mysql_deploy.yml文件,配置内容:
- name: deploy mysql
hosts: web
user: root
gather_facts: yes
roles:- role: mysql
- name: deploy mysql
最后,使用命令 ansible-playbook mysql-deploy.yml 来执行任务。
注意:如果在执行过程中提示了,
MySQL启动服务失败,可以通过命令:rm -rf /var/lib/mysql/*来清除MySQL所有的数据后,再重新执行ansible-playbook mysql-deploy.yml命令。
4.3.PHP
-
第一步:定义
Php的Roles角色和相关脚本文件roleName=php
mkdir -p roles/{roleName}/{tasks,handlers,vars,files,templates} touch roles/{roleName}/tasks/main.yml
touch roles/{roleName}/handlers/main.yml touch roles/{roleName}/vars/main.yml
touch roles/${roleName}/templates/main.yml -
第二步:编辑
php/tasks/php.yml文件安装 EPEL 仓库
- name: install epel-release
yum:
name: epel-release
state: present
安装 Remi 仓库提供了较新版本的 PHP 和其他软件包。
- name: install remi-release-7
yum:
name: https://rpms.remirepo.net/enterprise/remi-release-7.rpm
state: present
启用 Remi PHP 7.4 仓库
- name: enable remi php7.4
command: yum-config-manager --enable remi-php74
创建 php 用户和组
- name: Create PHP-FPM user and group
user:
name: "{{ php_user }}"
group: "{{ php_group }}"
system: yes
shell: /sbin/nologin
create_home: no
安装 php7.4
- name: install php7.4
yum:
name:
- php
- php-fpm
- php-cli
- php-mysqlnd
- php-zip
- php-devel
- php-gd
- php-mcrypt
- php-mbstring
- php-curl
- php-xml
- php-pear
- php-bcmath
- php-redis
- php-opcache
state: present
enablerepo: remi-php74
配置 php-fpm 核心配置文件的用户,与nginx配置文件一致
- name: configure php-fpm user
lineinfile:
path: /etc/php-fpm.d/www.conf
regexp: '^user'
line: 'user={{ php_user }}'
backrefs: yes
配置 php-fpm 核心配置文件的所属组,与nginx配置文件一致
- name: configure php-fpm group
lineinfile:
path: /etc/php-fpm.d/www.conf
regexp: '^group'
line: 'group={{ php_group }}'
backrefs: yes
启动 php-fpm 并设置自启动
- name: start php-fpm
service:
name: php-fpm
state: started
enabled: yes
修改blog.conf,添加php访问支持
- name: add PHP configure to blog.conf
blockinfile:
path: /etc/nginx/conf.d/blog.conf
block: |
location ~ .php { root html; fastcgi_pass 127.0.0.1:9000; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME /var/www/htmlfastcgi_script_name;
include fastcgi_params;
}
insertafter: '^server {'
validate: 'nginx -t -c %s'
notify: reload nginx
- name: install epel-release
-
第三步:编辑
php/vars/main.yml文件,配置变量。php_user: nginx
php_group: nginx -
第四步:编辑
php/handlers/main.yml文件,添加触发任务。
- name: reload nginx
service:
name: nginx
state: restarted
- name: reload nginx
-
第五步:将
tasks/php.yml文件包含到tasks/main.yml主配置文件中。
- name: install php
include_tasks: php.yml
- name: install php
-
第六步:切换至
roles目录外,创建php_deploy.yml文件,配置内容:
- name: deploy php
hosts: web
user: root
gather_facts: yes
roles:- role: php
- name: deploy php
最后,使用命令 ansible-playbook php-deploy.yml 来执行任务。
4.4.部署wordPress
-
第一步:定义
wordpress的Roles角色和相关脚本文件roleName=wordpress
mkdir -p roles/{roleName}/{tasks,handlers,vars,files,templates} touch roles/{roleName}/tasks/main.yml
touch roles/{roleName}/handlers/main.yml touch roles/{roleName}/vars/main.yml
touch roles/${roleName}/templates/main.yml -
第二步:切换至
wordpress/tasks/wordpress.yml文件下载 wordpress
- name: download wordpress
shell: |
wget -O /tmp/wordpress-6.0.1-zh_CN.tar.gz https://cn.wordpress.org/wordpress-6.0.1-zh_CN.tar.gz
args:
creates: /tmp/wordpress-6.0.1-zh_CN.tar.gz
解压 wordpress
- name: tar wordpress
#command: tar xf /tmp/wordpress-6.0.1-zh_CN.tar.gz
unarchive:
src: /tmp/wordpress-6.0.1-zh_CN.tar.gz
dest: /tmp/
remote_src: yes
creates: /tmp/unarchived_files/example_file.txt
移动 wordpress
- name: move wordpress
shell: mv /tmp/wordpress/* /var/www/html/
备份 wp-config-sample.php
- name: backup config
command: cp /var/www/html/wp-config-sample.php /var/www/html/wp-config.php
更新 wp-config.php 配置文件,添加MySQL数据库连接配置
- name: update config
replace:
path: "/var/www/html/wp-config.php"
regexp: "define\( '{{ item.define }}', '{{ item.original }}' \);"
replace: "define( '{{ item.define }}', '{{ item.new }}' );"
with_items:- { define: 'DB_NAME', original: 'database_name_here', new: "{{ db_name }}" }
- { define: 'DB_USER', original: 'username_here', new: "{{ db_user }}" }
- { define: 'DB_PASSWORD', original: 'password_here', new: "{{ db_password }}" }
- { define: 'DB_HOST', original: 'localhost', new: "{{ db_host }}" }
- { define: 'DB_CHARSET', original: 'utf8', new: "{{ db_charset }}" }
修改 /var/www/html 的用户和组
- name: chmod
command: chown -R nginx:nginx /var/www/html/
修改 /var/www/html/ 的权限为755
- name: chmod
command: chmod -R 755 /var/www/html/
清空 /usr/share/nginx/html 目录下的所有文件
- name: clear
shell: cd /usr/share/nginx/html && rm -rf *
更新 /etc/nginx/conf.d/blog.conf 配置文件
- name: update nginx config1
replace:
path: /etc/nginx/conf.d/blog.conf
regexp: 'root /usr/share/nginx/html;'
replace: 'root /var/www/html;'
更新 /etc/nginx/conf.d/blog.conf 配置文件
- name: update nginx config2
replace:
path: /etc/nginx/conf.d/blog.conf
regexp: 'index index.html index.htm;'
replace: 'index index.php index.html index.htm;'
重启nginx
- name: restart nginx
service:
name: nginx
state: restarted
- name: download wordpress
-
第三步:编辑
php/handlers/main.yml文件,添加触发任务。
- name: restart nginx
service:
name: nginx
state: restarted
- name: restart nginx
-
第四步:将
tasks/wordpress.yml文件包含到tasks/main.yml主配置文件中。
- name: install wordpress
include_tasks: wordpress.yml
- name: install wordpress
-
第五步:切换至
roles目录外,创建wordpress_deploy.yml文件,配置内容:
- name: deploy wordpress
hosts: web
user: root
gather_facts: yes
roles:- role: wordpress
- name: deploy wordpress
最后,使用命令 ansible-playbook wordpress-deploy.yml 来执行任务。