一、剧本重用与解耦
在大型项目中,涉及到的功能模块多且杂,你不可能全部放入一个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