一、剧本重用与解耦
在大型项目中,涉及到的功能模块多且杂,你不可能全部放入一个playbook中
为了方便管理,我们必须
1、开发的时候
- 要把不同的功能放入不同的文件中实现解耦合吗
- 一些文件可以被共享引用实现复用
2、执行的时候:最好能统一在一起一键执行
实现方式有两种
1、include功能
2、基于roles进行工程化开发
Ansible 的 roles 是一种结构化的方式,用于组织任务、模板、文件和变量。
此结构使管理复杂的自动化设置更为简单,因为与特定角色相关的所有内容都包含在其目录中
它就跟你开发一个django项目,不同的文件放入不同的目录里一样的道理
二、include使用示例
2.1 使用inclulde_tasks引入存放task的文件
1)把两个小task放入不同的文件,注意每个小task的文件是无法单独运行的
cat > play1.yml << "EOF"
- name: task1
copy:
content: "111"
dest: "/tmp/1.txt"
EOF
cat > play2.yml << "EOF"
- name: task2
copy:
content: "222"
dest: "/tmp/2.txt"
EOF
2)用include_tasks指令来引入task文件
[root@m01 project]# vim main.yml
- hosts: group5
tasks:
- include_tasks: /workspace/play1.yml
- include_tasks: /workspace/play2.yml
2.2 使用import_playbook来直接复用一整个剧本
每个playbook文件都是一个可以独立运行的剧本,如果你想复用的是一个整个剧本,那需要使用import_playbook指令
[root@m01 project]# cat main.yml
- import_playbook: ./base.yml
- import_playbook: ./nginx.yml
- import_playbook: ./php.yml
- import_playbook: ./wordpress.yml
- import_playbook: ./mariadb.yml
三、Ansible Roles
3.1 Roles基本概述
通过使用 roles,你可以将复杂的设置和操作流程封装在一个统一的文件夹下,进而实现代码的复用和模块化
例如你要部署负载均衡、web服务器、nfs、数据库,那你可以创建四个role
每个role都组织管理了好了各自需要的所有元素(包括任务、变量、handler、文件等)的目录结构。
3.2 创建单独一个Role
一个完整的Role里包含的目录和文件可能较多,手动去创建所有这些目录和文件是一件比较烦人的事,好在可以使用ansible-galaxy init ROLE_NAME命令来快速创建一个符合Role文件组织规范的框架。
[root@lb workspace]# ansible-galaxy init first_role
[root@lb workspace]# tree first_role/
first_role/ # 角色名称,或者叫项目名
├── README.md
├── defaults # 默认的变量(优先级很低)
│ └── main.yml
├── files # 存放文件,使用copy模块时自动获取
├── handlers # 存放触发器的配置
│ └── main.yml
├── meta # 依赖的服务,执行该项目时先执行其他的项目
│ └── main.yml
├── tasks # 默认执行的playbook
│ └── main.yml
├── templates # 存放jinja2模板,使用template模块时自动获取
├── tests
│ ├── inventory
│ └── test.yml
└── vars # 存放变量
└── main.yml
3.3 一些关键介绍
一、Ansible Roles的依赖关系说明
`roles`允许你再使用roles时自动引入其他的roles。role依赖关系存储在roles目录中meta/main.yml文件中。
例如:推送wordpress并解压,前提条件,必须要安装nginx和php,把服务跑起来,才能运行wordpress的页面,此时我们就可以在wordpress的roles中定义依赖nginx和php的roles
[root@m01 roles]# vim /etc/ansible/roles/wordpress/meta/main.yml
dependencies:
- { role: nginx }
- { role: php }
如果编写了meta目录下的main.yml文件,那么Ansible会自动先执行meta目录中main.yml文件中的dependencies文件,如上所示,就会先执行nginx和php的安装。
二、Role中有两个地方可以定义变量:
- (1).roles/xxx/defaults/main.yml:用于定义Role的默认变量
- (2).roles/xxx/vars/main.yml :用于定义其它变量
这两个文件之间的区别在于,defaults/main.yml中定义的变量优先级低于vars/main.yml中定义的变量。事实上,defaults/main.yml中的变量优先级几乎是最低的,基本上其它任何地方定义的变量都可以覆盖它。
3.4、基于roles机制重构playbook
基于roles机制将https://egonlin.com/?p=355第三小节的playbook进行重构
你可以git clone https://gitee.com/egonlin/ansible-playbook-test.git
把之前我们写的这个剧本拉到本地,然后用roles实现重构
1.配置主机清单
[root@manager ~]# cat /etc/ansible/hosts
[lb]
lb01 ansible_ssh_pass='1'
[nfs_server]
nfs ansible_ssh_pass='1'
[web_group]
web01 ansible_ssh_pass='1'
web02 ansible_ssh_pass='1'
[db_server]
db01 ansible_ssh_pass='1'
[www:children]
lb
nfs_server
web_group
db_server
2.配置hosts
[root@manager ~]# cat /etc/hosts # 添加如下内容
192.168.71.12 lb01
192.168.71.13 nfs
192.168.71.14 web01
192.168.71.15 web02
192.168.71.16 db01
3、创建项目及各个role
# 1、创建项目目录,项目名就叫roles吧,好理解
mkdir /project
mkdir /project/roles
# 2、在roles目录下创建一系列的role
cd /project/roles # 切换到工作目录下
ansible-galaxy init base # 基础优化role
ansible-galaxy init nfs # 部署nfs服务的role
ansible-galaxy init web # 部署web服务的role
ansible-galaxy init mysql # 部署mysql服务的role
ansible-galaxy init lb # 部署lb负载均衡服务的role
ansible-galaxy init wordpress # 部署wordpress项目的role
4、base role
既然是tasks文件,那必然是只放tasks下的内容就好了,你在tasks/main.yml里再出现如下层级是错误的
- hosts: all
tasks:
- name: 任务1
...
- name: 任务2
...
直接把任务1、任务2摘出来放入tasks/main.yml即可,后面都是如此
[root@m01 roles]# cat base/tasks/main.yml
- name: Stop Selinux
selinux:
state: disabled
- name: Stop Firewalld
systemd:
name: firewalld
state: stopped
- name: Create www Group
group:
name: www
gid: 1666
state: present
- name: Create www User
user:
name: www
uid: 1666
group: www
shell: /sbin/nologin
create_home: false
state: present
5、nfs role
1、准备文件
[root@m01 roles]# cat nfs/files/exports.txt
/data 192.168.71.0/24(rw,sync,all_squash)
2、编写tasks
[root@m01 roles]# cat nfs/tasks/main.yml
- name: Install nfs-util
yum:
name: nfs*
state: present
- name: mkdir /data
file:
path: "/data"
state: directory
- name: Config nfs
copy:
src: "exports.txt" # 直接引用文件即可
dest: /etc/exports
- name: Start nfs-server
systemd:
name: nfs-server
state: restarted
enabled: true
6 web role
部署两台web上的nginx+php环境,并且挂载好nfs共享存储
1)准备包和配置文件
cd /project/roles
1、nginx的安装源文件
cat > web/files/nginx.repo << "EOF"
[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
[nginx-mainline]
name=nginx mainline repo
baseurl=http://nginx.org/packages/mainline/centos/$releasever/$basearch/
gpgcheck=1
enabled=0
gpgkey=https://nginx.org/keys/nginx_signing.key
module_hotfixes=true
EOF
2、nginx转发php-fpm的配置
cat > web/files/myweb.conf << "EOF"
server {
listen 8181;
server_name localhost;
location / {
root /usr/share/nginx/html;
index index.php index.html;
}
location ~ \.php$ {
fastcgi_pass 127.0.0.1:9000;
fastcgi_param SCRIPT_FILENAME /usr/share/nginx/html$fastcgi_script_name;
fastcgi_param HTTPS on;
include fastcgi_params;
}
}
EOF
3、准备好php-fpm的配置文件
cat > web/files/www.conf << "EOF"
[www]
user = www
group = www
listen = 127.0.0.1:9000
listen.allowed_clients = 127.0.0.1
pm = dynamic
pm.max_children = 50
pm.start_servers = 5
pm.min_spare_servers = 5
pm.max_spare_servers = 35
slowlog = /var/opt/remi/php74/log/php-fpm/www-slow.log
php_admin_value[error_log] = /var/opt/remi/php74/log/php-fpm/www-error.log
php_admin_flag[log_errors] = on
php_value[soap.wsdl_cache_dir] = /var/opt/remi/php74/lib/php/wsdlcache
EOF
4、查看如下
[root@m01 roles]# ls web/files/
myweb.conf nginx.repo www.conf
2)编写部署php-fpm+nginx的剧本
[root@m01 roles]# cat web/tasks/main.yml
# 1、安装php
- name: Gather OS version
command: cat /etc/redhat-release
register: os_version
- name: Extract major version from OS version
set_fact:
os_major_version: "{{ os_version.stdout.split()[3] | regex_replace('\\..*$', '') }}"
- name: Extract minor version from OS version
set_fact:
os_minor_version: "{{ os_version.stdout.split()[3] | regex_replace('^[^.]*\\.', '') }}"
- name: Install rpm package for CentOS 7.9
yum:
name: http://rpms.remirepo.net/enterprise/remi-release-7.rpm
state: latest
when: os_major_version == '7' and os_minor_version == '9.2009'
- name: Install rpm package for CentOS 9.3
yum:
name: http://rpms.remirepo.net/enterprise/remi-release-9.3.rpm
state: latest
when: os_major_version == '9' and os_minor_version == '3'
- name: Install php-fpm
yum:
name:
- 'php74-php-pdo'
- 'php74-php-mbstring'
- 'php74-php-cli'
- 'php74-php-fpm'
- 'php74-php-mysqlnd'
state: latest
- name: Config php-fpm
copy:
src: www.conf
dest: /etc/opt/remi/php74/php-fpm.d/www.conf
notify: restart_php
- name: Start php-fpm
systemd:
name: php74-php-fpm
state: restarted
enabled: true
#2、安装nginx,配置nginx代理php-fpm
- name: copy nginx.repo
copy:
src: nginx.repo
dest: /etc/yum.repos.d/nginx.repo
- name: Install nginx
yum:
name: nginx
state: latest
- name: Config nginx
copy:
src: myweb.conf
dest: /etc/nginx/conf.d/myweb.conf
notify: restart_nginx
- name: Start nginx server
systemd:
name: nginx
state: restarted
enabled: true
#3、配置所有web服务挂载nfs
- name: 安装nfs
yum:
name: nfs-utils
state: latest
- name: 挂载
mount:
path: /usr/share/nginx/html
src: "{{ nfs_share_dir }}"
fstype: nfs
opts: defaults
state: mounted
配置触发器handler
[root@m01 roles]# cat web/handlers/main.yml
- name: restart_php
systemd:
name: php74-php-fpm
state: restarted
- name: restart_nginx
systemd:
name: nginx
state: restarted
创建变量
[root@m01 roles]# cat web/vars/main.yml
nfs_share_dir: "192.168.71.13:/data"
7 mysql role
安装mysql_db模块
ansible-galaxy collection install community.mysql
编写剧本
[root@m01 roles]# cat mysql/tasks/main.yml
- name: Download PyMySQL tar.gz
get_url:
url: https://files.pythonhosted.org/packages/44/39/6bcb83cae0095a31b6be4511707fdf2009d3e29903a55a0494d3a9a2fac0/PyMySQL-0.8.1.tar.gz
dest: /tmp/PyMySQL-0.8.1.tar.gz
- name: Extract PyMySQL tar.gz
unarchive:
src: /tmp/PyMySQL-0.8.1.tar.gz
dest: /tmp/
remote_src: yes
- name: Install PyMySQL
command:
cmd: "python setup.py install"
chdir: "/tmp/PyMySQL-0.8.1"
- name: clear mysql
shell: "yum remove mysql* -y"
ignore_errors: True
- name: Install mariadb
yum:
name: mariadb*
state: latest
- name: init maridb
shell: "rm -rf /var/lib/mysql/*"
- name: Start mariadb
systemd:
name: mariadb
state: restarted
enabled: true
- name: create database
mysql_db:
# root登录localhost不允许,需要用套接字登录
login_unix_socket: /var/lib/mysql/mysql.sock
# 引用变量名必须加引号,否则报错
name: "{{ my_db.name }}"
state: present
encoding: "{{ my_db.encoding }}"
- name: grant all on *.* to 'bob'@'192.168.71.%' identified by '12345';
mysql_user:
login_unix_socket: /var/lib/mysql/mysql.sock
# 引用变量名必须加引号,否则报错
name: "{{ my_user.name }}"
host: "{{ my_user.host }}"
password: "{{ my_user.password }}"
priv: "{{ my_user.priv }}"
state: present
创建变量文件
[root@m01 roles]# cat mysql/vars/main.yml
my_db:
name: wordpress
encoding: utf8mb4
my_user:
name: bob
host: 192.168.71.%
password: 12345
priv: '*.*:ALL'
8 lb role
1) 准备文件
准备nginx.repo
cat > lb/files/nginx.repo << "EOF"
[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
[nginx-mainline]
name=nginx mainline repo
baseurl=http://nginx.org/packages/mainline/centos/$releasever/$basearch/
gpgcheck=1
enabled=0
gpgkey=https://nginx.org/keys/nginx_signing.key
module_hotfixes=true
EOF
准备证书
openssl genrsa -out server.key 2048
openssl req -new -x509 -days 3650 -key server.key -out server.crt -subj "/C=CH/ST=mykey/L=mykey/O=mykey/OU=mykey/CN=domain1/CN=www.egon.com/CN=domain3"
放置证书到lb/files目录下
[root@m01 roles]# mv server.* lb/files/
准备配置文件
cat > lb/files/nginx.conf << "EOF"
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;
include /usr/share/nginx/modules/*.conf;
events {
worker_connections 1024;
}
http {
upstream webserver {
server 192.168.71.14:8181;
server 192.168.71.15:8181;
}
server {
listen 443 ssl;
server_name www.egon.com 192.168.71.12;
ssl_certificate /etc/nginx/ssl_key/server.crt;
ssl_certificate_key /etc/nginx/ssl_key/server.key;
location / {
proxy_pass http://webserver;
# 把真实的访问者ip发给后端web,后端web会据此来拼接静态文件的url地址以便让访问者浏览器发起二次请求
# 如果没有下面的这段内容,后端web会将静态资源的url地址拼成http://webserver/static/img/1.jpg的形式,导致访问者浏览器二次访问失败
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_next_upstream error timeout http_500 http_502 http_503 http_504 http_403 http_404;
}
}
server {
listen 80;
server_name 192.168.71.12 www.egon.com;
rewrite (.*) https://$server_name$1;
}
}
EOF
文件总共这么多
[root@m01 roles]# ls lb/files/
nginx.conf nginx.repo server.crt server.key
编写剧本
[root@m01 roles]# cat lb/tasks/main.yml
#1、安装nginx,配置nginx负载均衡
- name: clear nginx
shell: >
yum remove nginx* -y ; rm -rf /etc/nginx /usr/share/nginx
- name: copy nginx.repo
copy:
src: nginx.repo
dest: /etc/yum.repos.d/nginx.repo
- name: Install nginx
yum:
name: nginx
state: latest
- name: Create dir
file:
path: /etc/nginx/ssl_key
state: directory
- name: copy multiple files
copy:
src: "{{ item.src }}"
dest: "{{ item.dest }}"
with_items:
- { src: 'nginx.conf', dest: '/etc/nginx/nginx.conf'}
- { src: 'server.crt', dest: '/etc/nginx/ssl_key/server.crt'}
- { src: 'server.key', dest: '/etc/nginx/ssl_key/server.key'}
notify: restart_nginx
- name: Start nginx server
systemd:
name: nginx
state: restarted
enabled: true
配置触发器
[root@m01 roles]# cat lb/handlers/main.yml
- name: restart_nginx
systemd:
name: nginx
state: restarted
9 wordpress role
准备文件
1、安装包
wget https://wordpress.org/latest.zip
mv latest.zip wordpress/files/
2、准备好配置文件(配置上数据库相关信息)
cat > wordpress/files/wp-config.php << "EOF"
<?php
define( 'DB_NAME', 'wordpress' );
define( 'DB_USER', 'bob' );
define( 'DB_PASSWORD', '12345' );
define( 'DB_HOST', '192.168.71.16' );
define( 'DB_CHARSET', 'utf8mb4' );
define( 'DB_COLLATE', '' );
define( 'AUTH_KEY', 'put your unique phrase here' );
define( 'SECURE_AUTH_KEY', 'put your unique phrase here' );
define( 'LOGGED_IN_KEY', 'put your unique phrase here' );
define( 'NONCE_KEY', 'put your unique phrase here' );
define( 'AUTH_SALT', 'put your unique phrase here' );
define( 'SECURE_AUTH_SALT', 'put your unique phrase here' );
define( 'LOGGED_IN_SALT', 'put your unique phrase here' );
define( 'NONCE_SALT', 'put your unique phrase here' );
$table_prefix = 'wp_';
define( 'WP_DEBUG', false );
if ( ! defined( 'ABSPATH' ) ) {
define( 'ABSPATH', __DIR__ . '/' );
}
require_once ABSPATH . 'wp-settings.php';
EOF
编写剧本(解压到nfs共享目录里就发布给了所有的web服务)
[root@m01 roles]# cat lb/handlers/main.yml
me: restart_nginx
systemd:
name: nginx
state: restarted
[root@m01 roles]# vi wordpress/tasks/main.yml
[root@m01 roles]# cat wordpress/tasks/main.yml
- name: mkdir /data
copy:
src: "latest.zip"
dest: "/data"
- name: install unzip
yum:
name: unzip
state: present
- name: 发布
shell: unzip /data/latest.zip -d /data
- name: 传送配置
copy:
src: "wp-config.php"
dest: "/data/wordpress/wp-config.php"
10 整合为一个playbook
编写一个palybook剧本,剧本里引入各个子role,运行的时候运行这一个plabook即可
[root@m01 roles]# cat /project/roles/run.yml
- name: 优化部分
hosts: all
roles:
- base
- name: 安装nfs
hosts: nfs_server
roles:
- nfs
- name: 安装web
hosts: web_group
roles: # 其实你可以将安装web进一步细分为nginx role与php role,留给你作业了
- web
- name: 安装数据库
hosts: db_server
roles:
- mysql
- name: 配置负载均衡和高可用
hosts: lb_server
roles:
- lb
#- keepalived # 高可用role留给你来实现
- name: 发布wordpress项目
hosts: nfs_server
roles:
- wordpress
补充:各个子role里的hosts其实不用指定,run.yml已经指定了
执行
ansible-playbook /project/roles/run.yml
11 测试
运行出错,修复后可以直接重新执行,因为是幂等的,所以不必担心有什么 影响
而且重复执行后,因为之前一些步骤已经完成了,会快一些
本地添加解析
# C:\Windows\System32\drivers\etc
192.168.71.12 www.egon.com
访问负载均衡地址:http://192.168.71.12/wordpress
12 代码地址
本节课程代码都放到了这里:https://gitee.com/egonlin/ansible-playbook-test
目录下有一个hosts.txt内记录着与本节实验相关的两个文件内容
/etc/ansible/hosts
/etc/hosts