就业班 第三阶段(ansible) 2401--4.16 day2 ansible2 剧本+角色

六、Ansible playbook 简介

playbook 是 ansible 用于配置,部署,和管理被控节点的剧本。   通过 playbook 的详细描述,执行其中的一系列 tasks ,可以让远端主机达到预期的状态。playbook 就像 Ansible 控制器给被控节点列出的的一系列 to-do-list ,而被控节点必须要完成。   也可以这么理解,playbook 字面意思,即剧本,现实中由演员按照剧本表演,在Ansible中,这次由计算机进行表演,由计算机安装,部署应用,提供对外服务,以及组织计算机处理各种各样的事情。

七、Ansible playbook使用场景

执行一些简单的任务,使用ad-hoc命令可以方便的解决问题,但是有时一个设施过于复杂,需要大量的操作时候,执行的ad-hoc命令是不适合的,这时最好使用playbook。   就像执行shell命令与写shell脚本一样, 也可以理解为批处理任务,不过playbook有自己的语法格式。   使用playbook你可以方便的重用这些代码,可以移植到不同的机器上面,像函数一样,最大化的利用代码。在你使用Ansible的过程中,你也会发现,你所处理的大部分操作都是编写playbook。可以把常见的应用都编写成playbook,之后管理服务器会变得十分简单。

八、Ansible playbook格式

1、格式简介

playbook由YMAL语言编写。YAML( /ˈjæməl/ )参考了其他多种语言,包括:XML、C语言、Python、Perl以及电子邮件格式RFC2822,Clark Evans在2001年5月在首次发表了这种语言,另外Ingy döt Net与OrenBen-Kiki也是这语言的共同设计者。   YMAL格式是类似于JSON的文件格式,便于人理解和阅读,同时便于书写。首先学习了解一下YMAL的格式,对我们后面书写playbook很有帮助。

以下为playbook常用到的YMAL格式:    1、文件的第一行应该以 "---" (三个连字符)开始,表明YMAL文件的开始。    2、在同一行中,#之后的内容表示注释,类似于shell,python和ruby。    3、YMAL中的列表元素以”-”开头然后紧跟着一个空格,后面为元素内容。    4、同一个列表中的元素应该保持相同的缩进。否则会被当做错误处理。    5、play中hosts,variables,roles,tasks等对象的表示方法都是键值中间以":"分隔表示,":"后面还要增加一个空格。

下面是一个举例:

---
#安装与运行mysql服务
- hosts: node1
  remote_user: root
  tasks:  
    - name: install mysql-server package
      yum: name=mysql-server state=present
    - name: starting mysqld service
      service: name=mysql state=started

我们的文件名称应该以.yml结尾,像我们上面的例子就是mysql.yml。其中,有三个部分组成:

host部分:使用 hosts 指示使用哪个主机或主机组来运行下面的 tasks ,每个 playbook 都必须指定 hosts ,hosts也可以使用通配符格式。主机或主机组在 inventory 清单中指定,可以使用系统默认的/etc/ansible/hosts,也可以自己编辑,在运行的时候加上-i选项,指定清单的位置即可。在运行清单文件的时候,–list-hosts选项会显示那些主机将会参与执行 task 的过程中。 remote_user:指定远端主机中的哪个用户来登录远端系统,在远端系统执行 task 的用户,可以任意指定,也可以使用 sudo,但是用户必须要有执行相应 task 的权限。 tasks:指定远端主机将要执行的一系列动作。tasks 的核心为 ansible 的模块,前面已经提到模块的用法。tasks 包含 name要执行的模块,name 是可选的,只是为了便于用户阅读,不过还是建议加上去,模块是必须的,同时也要给予模块相应的参数。

使用ansible-playbook运行playbook文件,得到如下输出信息,输出内容为JSON格式。并且由不同颜色组成,便于识别。一般而言 | 绿色代表执行成功,系统保持原样 | 黄色代表系统代表系统状态发生改变 | 红色代表执行失败,显示错误输出   执行有三个步骤:1、收集facts 2、执行tasks 3、报告结果

2、核心元素

Playbook的核心元素:

Hosts:主机组; Tasks:任务列表; Variables:变量,设置方式有四种; Templates:包含了模板语法的文本文件; Handlers:由特定条件触发的任务;

3、基本组件

Playbooks配置文件的基础组件:

Hosts:运行指定任务的目标主机 remote_user:在远程主机上执行任务的用户; sudo_usertasks:任务列表

模块,模块参数

格式:     (1) action: module arguments     (2) module: arguments     注意:shell和command模块后面直接跟命令,而非key=value类的参数列表;

handlers:任务,在特定条件下触发;接收到其它任务的通知时被触发;

(1) 某任务的状态在运行后为changed时,可通过“notify”通知给相应的handlers;

(2) 任务可以通过“tags“打标签,而后可在ansible-playbook命令上使用-t指定进行调用;

举例

① 定义playbook

[root@server ~]# cd /etc/ansible
[root@server ansible]# vim nginx.yml
---
- hosts: web
  remote_user: root
  tasks:
    - name: install nginx
      yum: name=nginx state=present
    - name: copy nginx.conf
      copy: src=/tmp/nginx.conf dest=/etc/nginx/nginx.conf backup=yes
      notify: reload    #当nginx.conf发生改变时,通知给相应的handlers
      tags: reloadnginx   #打标签
    - name: start nginx service
      service: name=nginx state=started
      tags: startnginx   #打标签
​
  handlers:  #注意,前面没有-,是两个空格
    - name: reload
      service: name=nginx state=restarted  #为了在进程中能看出来
运行前三部曲
检查错误
ansible-playbook nginx.yml --syntax-check
​
列出所有任务
ansible-playbook nginx.yml --list-task
​
列出在那些机器执行
ansible-playbook nginx.yml --list-hosts
​
运行
ansible-playbook nginx.yml

② 测试运行结果   写完了以后,我们就可以运行了:

[root@server ansible]# ansible-playbook nginx.yml

  现在我们可以看看两台机器的端口是否开启:

[root@server ansible]# ansible web -m shell -a 'ss -nutlp |grep nginx'
192.168.37.122 | SUCCESS | rc=0 >>
tcp    LISTEN     0      128       *:80                    *:*                   users:(("nginx",pid=8304,fd=6),("nginx",pid=8303,fd=6))
​
192.168.37.133 | SUCCESS | rc=0 >>
tcp    LISTEN     0      128       *:80                    *:*                   users:(("nginx",pid=9671,fd=6),("nginx",pid=9670,fd=6))

③ 测试标签   我们在里面已经打上了一个标签,所以可以直接引用标签。但是我们需要先把服务关闭,再来运行剧本并引用标签:

[root@server ansible]# ansible web -m shell -a 'systemctl stop nginx'
[root@server ansible]# ansible-playbook nginx.yml -t startnginx

④ 测试notify   我们还做了一个notify,来测试一下:   首先,它的触发条件是配置文件被改变,所以我们去把配置文件中的端口改一下:

[root@server ansible]# vim /tmp/nginx.conf
    listen       8080;

然后我们重新加载一下这个剧本:

  发现我们执行的就是reload段以及我们定义的notify部分。   我们来看一看我们的端口号:

[root@server ansible]# ansible web -m shell -a 'ss -ntlp | grep nginx'
192.168.37.122 | SUCCESS | rc=0 >>
LISTEN     0      128          *:8080                     *:*                   users:(("nginx",pid=2097,fd=6),("nginx",pid=2096,fd=6))
​
192.168.37.133 | SUCCESS | rc=0 >>
LISTEN     0      128          *:8080                     *:*                   users:(("nginx",pid=3061,fd=6),("nginx",pid=3060,fd=6))

可以看出,我们的nginx端口已经变成了8080。

4、variables 部分

上文中,我们说到了variables是变量,有四种定义方 法,现在我们就来说说这四种定义方法:

① facts :可直接调用

上一篇中,我们有说到setup这个模块,这个模块就是通过调用facts组件来实现的。我们这里的variables也可以直接调用facts组件。   具体的facters我们可以使用setup模块来获取,然后直接放入我们的剧本中调用即可。

ansible_all_ipv4_addresses:仅显示ipv4的信息 ---> [u'192.168.95.143']
ansible_eth0['ipv4']['address']:仅显示ipv4的信息 ---> eth0 的ip地址
ansible_devices:仅显示磁盘设备信息
ansible_distribution:显示是什么系统,例:centos,suse等
ansible_distribution_version:仅显示系统版本
ansible_machine:显示系统类型,例:32位,还是64位
ansible_eth0:仅显示eth0的信息
ansible_hostname:仅显示主机名
ansible_kernel:仅显示内核版本
ansible_lvm:显示lvm相关信息
ansible_memtotal_mb:显示系统总内存
ansible_memfree_mb:显示可用系统内存
ansible_memory_mb:详细显示内存情况
ansible_swaptotal_mb:显示总的swap内存
ansible_swapfree_mb:显示swap内存的可用内存
ansible_mounts:显示系统磁盘挂载情况
ansible_processor:显示cpu个数(具体显示每个cpu的型号)
ansible_processor_vcpus:显示cpu个数(只显示总的个数)
ansible_python_version:显示python版本

例如:批量修改主机 host 文件

---
- hosts: web  
  vars:        
    IP: "{{ ansible_eth0['ipv4']['address'] }}"  
  tasks:        
  - name: 将原有的hosts文件备份          
    shell: mv /etc/hosts /etc/hosts_bak        
  - name: 将ansible端的hosts复制到各自机器上          
    copy: src=/root/hosts dest=/etc/ owner=root group=root mode=0644        
  - name: 在新的hosts文件后面追加各自机器内网ip和hostname          
    lineinfile: dest=/etc/hosts line="{{ IP }}  {{ ansible_hostname }} "
② 用户自定义变量

我们也可以直接使用用户自定义变量,想要自定义变量有以下两种方式:

通过命令行传入

ansible-playbook命令的命令行中的-e VARS, --extra-vars=VARS,这样就可以直接把自定义的变量传入。

在playbook中定义变量

我们也可以直接在playbook中定义我们的变量:

vars:
  - var1: value1
  - var2: value2
举例

① 定义剧本   我们就使用全局替换把我们刚刚编辑的文件修改一下:

[root@server ansible]# vim nginx.yml

  这样一来,我们的剧本就定义完成了。 ② 拷贝配置文件   我们想要在被监管的机器上安装什么服务的话,就直接在我们的server端上把该服务的配置文件拷贝到我们的/tmp/目录下。这样我们的剧本才能正常运行。   我们就以keepalived服务为例:

[root@server ansible]# cp /etc/keepalived/keepalived.conf /tmp/keepalived.conf

③ 运行剧本,变量由命令行传入

[root@server ansible]# ansible-playbook nginx.yml -e rpmname=keepalived

④ 修改剧本,直接定义变量   同样的,我们可以直接在剧本中把变量定义好,这样就不需要在通过命令行传入了。以后想要安装不同的服务,直接在剧本里把变量修改一下即可。

[root@server ansible]# vim nginx.yml

⑤ 运行定义过变量的剧本   我们刚刚已经把变量定义在剧本里面了。现在我们来运行一下试试看:

[root@server ansible]# ansible-playbook nginx.yml

  发现这样也是可以的~

③ 通过roles传递变量

具体的,我们下文中说到 roles 的时候再详细说明。

④ Host Inventory

我们也可以直接在主机清单中定义。   定义的方法如下:

向不同的主机传递不同的变量:

  IP/HOSTNAME varaiable=value var2=value2

向组中的主机传递相同的变量:

  [groupname:vars]
  variable=value

Ansible Inventory 内置参数

使用内置变量把用户名密码写在Inventory中,也就是/etc/ansible/hosts文件里,缺点就是暴露了账号密码,不安全。如果有多个主机需要使用同样的变量,可以用组变量的形式,书写格式如下:

[web]
192.168.100.10
192.168.100.11
192.168.100.12 
[web:vars]  #给名为webservers的组定义一个变量,:vars是固定格式
ansible_ssh_port=22
ansible_ssh_user='root'
ansible_ssh_pass='1234.com'

5、模板 templates

模板是一个文本文件,嵌套有脚本(使用模板编程语言编写)。   Jinja2:Jinja2是python的一种模板语言,以Django的模板语言为原本。 模板支持:

  字符串:使用单引号或双引号;
  数字:整数,浮点数;
  列表:[item1, item2, ...]
  元组:(item1, item2, ...)
  字典:{key1:value1, key2:value2, ...}
  布尔型:true/false
  算术运算:
    +, -, *, /, //, %, **
  比较操作:
    ==, !=, >, >=, <, <=
  逻辑运算:
    and, or, not

通常来说,模板都是通过引用变量来运用的。

举例

① 定义模板   我们直接把之前定义的/tmp/nginx.conf改个名,然后编辑一下,就可以定义成我们的模板文件了:

[root@server ansible]# cd /tmp
[root@server tmp]# mv nginx.conf nginx.conf.j2
[root@server tmp]# vim nginx.conf.j2
    worker_processes  {{ ansible_processor_vcpus }};
    listen       {{ nginxport }};

② 修改剧本   我们现在需要去修改剧本来定义变量:

[root@server ansible]# vim nginx.yml

  需要修改的部分如图所示。

copy模块 也需要修改为 template模块

③ 运行剧本   上面的准备工作完成后,我们就可以去运行剧本了:

[root@server ansible]# ansible-playbook nginx.yml -t reloadnginx
​
PLAY [web] *********************************************************************
​
TASK [setup] *******************************************************************
ok: [192.168.37.122]
ok: [192.168.37.133]
​
TASK [copy nginx.conf] *********************************************************
ok: [192.168.37.122]
ok: [192.168.37.133]
​
PLAY RECAP *********************************************************************
192.168.37.122             : ok=2    changed=0    unreachable=0    failed=0   
192.168.37.133             : ok=2    changed=0    unreachable=0    failed=0

6、条件测试

when语句:在task中使用,jinja2的语法格式。 举例如下:

tasks:
- name: install conf file to centos7
  template: src=files/nginx.conf.c7.j2
  when: ansible_distribution_major_version == "7"
- name: install conf file to centos6
  template: src=files/nginx.conf.c6.j2
  when: ansible_distribution_major_version == "6"

循环:迭代,需要重复执行的任务;   对迭代项的引用,固定变量名为"item",而后,要在task中使用with_items给定要迭代的元素列表; 举例如下:

tasks:
- name: unstall web packages
  yum: name={{ item }} state=absent
  with_items:
  - httpd
  - php
  - php-mysql

跳过错误:

tasks:
- name: unstall web packages
  yum: name=httpd state=absent
  ignore_errors: yes

7、字典

ansible playbook 还支持字典功能。举例如下:

- name: install some packages
  yum: name={{ item }} state=present
  with_items:
    - nginx
    - memcached
    - php-fpm
- name: add some groups
  group: name={{ item }} state=present
  with_items:
    - group11
    - group12
    - group13
- name: add some users
  user: name={{ item.name }} group={{ item.group }} state=present
  with_items:
    - { name: 'user11', group: 'group11' }
    - { name: 'user12', group: 'group12' }
    - { name: 'user13', group: 'group13' }
    
    
​

image-20240416205829529

8、角色订制:roles

① 简介

对于以上所有的方式有个弊端就是无法实现复用假设在同时部署Web、db、ha 时或不同服务器组合不同的应用就需要写多个yml文件。很难实现灵活的调用。   roles 用于层次性、结构化地组织playbook。roles 能够根据层次型结构自动装载变量文件、tasks以及handlers等。要使用roles只需要在playbook中使用include指令即可。简单来讲,roles就是通过分别将变量(vars)、文件(file)、任务(tasks)、模块(modules)及处理器(handlers)放置于单独的目录中,并可以便捷地include它们的一种机制。角色一般用于基于主机构建服务的场景中,但也可以是用于构建守护进程等场景中。

② 角色集合

角色集合:roles/ mysql/ httpd/ nginx/ files/:存储由copy或script等模块调用的文件; tasks/:此目录中至少应该有一个名为main.yml的文件,用于定义各task;其它的文件需要由main.yml进行“包含”调用; handlers/:此目录中至少应该有一个名为main.yml的文件,用于定义各handler;其它的文件需要由main.yml进行“包含”调用; vars/:此目录中至少应该有一个名为main.yml的文件,用于定义各variable;其它的文件需要由main.yml进行“包含”调用; templates/:存储由template模块调用的模板文本; meta/:此目录中至少应该有一个名为main.yml的文件,定义当前角色的特殊设定及其依赖关系;其它的文件需要由main.yml进行“包含”调用; default/:此目录中至少应该有一个名为main.yml的文件,用于设定默认变量;

③ 角色定制实例

1. 在roles目录下生成对应的目录结构

[root@server ansible]# cd roles/
[root@server roles]# ls
[root@server roles]# mkdir -pv ./{nginx,mysql,httpd}/{files,templates,vars,tasks,handlers,meta,default}
[root@server roles]# tree
.
├── httpd
│   ├── default
│   ├── files
│   ├── handlers
│   ├── meta
│   ├── tasks
│   ├── templates
│   └── vars
├── mysql
│   ├── default
│   ├── files
│   ├── handlers
│   ├── meta
│   ├── tasks
│   ├── templates
│   └── vars
└── nginx
    ├── default
    ├── files
    ├── handlers
    ├── meta
    ├── tasks
    ├── templates
    └── vars
​
24 directories, 0 files

2. 定义配置文件   我们需要修改的配置文件为/tasks/main.yml,下面,我们就来修改一下:

[root@server roles]# vim nginx/tasks/main.yml
- name: cp rpm for nginx
  copy: src=nginx-1.10.2-1.el7.ngx.x86_64.rpm dest=/tmp/nginx-1.10.2-1.el7.ngx.x86_64.rpm
- name: install
  yum: name=/tmp/nginx-1.10.2-1.el7.ngx.x86_64.rpm state=latest
- name: conf
  template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf
  tags: nginxconf
  notify: new conf to reload
- name: start service
  service: name=nginx state=started enabled=true

3. 放置我们所需要的文件到指定目录   因为我们定义的角色已经有了新的组成方式,所以我们需要把文件都放到指定的位置,这样,才能让配置文件找到这些并进行加载。   rpm包放在files目录下,模板放在templates目录下:

[root@server nginx]# cp /tmp/nginx-1.10.2-1.el7.ngx.x86_64.rpm ./files/
[root@server nginx]# cp /tmp/nginx.conf.j2 ./templates/
[root@server nginx]# tree
.
├── default
├── files
│   └── nginx-1.10.2-1.el7.ngx.x86_64.rpm
├── handlers
├── meta
├── tasks
│   └── main.yml
├── templates
│   └── nginx.conf.j2
└── vars
​
7 directories, 3 files

4. 修改变量文件   我们在模板中定义的变量,也要去配置文件中加上:

[root@server nginx]# vim vars/main.yml
nginxprot: 9999

5. 定义handlers文件   我们在配置文件中定义了notify,所以我么也需要定义handlers,我们来修改配置文件:

[root@server nginx]# vim handlers/main.yml
- name: new conf to reload
  service: name=nginx state=restarted

6. 定义剧本文件   接下来,我们就来定义剧本文件,由于大部分设置我们都单独配置在了roles里面,所以,接下来剧本就只需要写一点点内容即可:

[root@server ansible]# vim roles/roles.yml 
- hosts: web
  remote_user: root
  roles:
    - nginx
完成后的目录结构
# tree ./
./
├── httpd
│   ├── default
│   ├── files
│   ├── handlers
│   ├── meta
│   ├── tasks
│   ├── templates
│   └── vars
├── mysql
│   ├── default
│   ├── files
│   ├── handlers
│   ├── meta
│   ├── tasks
│   ├── templates
│   └── vars
├── nginx
│   ├── default
│   ├── files
│   │   └── nginx-1.10.2-1.el7.ngx.x86_64.rpm
│   ├── handlers
│   │   └── main.yml
│   ├── meta
│   ├── tasks
│   │   └── main.yml
│   ├── templates
│   │   └── nginx.conf.j2
│   └── vars
│       └── main.yml
└── roles.yml

7. 启动服务   剧本定义完成以后,我们就可以来启动服务了:

[root@server ansible]# ansible-playbook roles.yml
​
PLAY [web] *********************************************************************
​
TASK [setup] *******************************************************************
ok: [192.168.37.122]
ok: [192.168.37.133]
​
TASK [nginx : cp] **************************************************************
ok: [192.168.37.122]
ok: [192.168.37.133]
​
TASK [nginx : install] *********************************************************
changed: [192.168.37.122]
changed: [192.168.37.133]
​
TASK [nginx : conf] ************************************************************
changed: [192.168.37.122]
changed: [192.168.37.133]
​
TASK [nginx : start service] ***************************************************
changed: [192.168.37.122]
changed: [192.168.37.133]
​
RUNNING HANDLER [nginx : new conf to reload] ***********************************
changed: [192.168.37.122]
changed: [192.168.37.133]
​
PLAY RECAP *********************************************************************
192.168.37.122             : ok=6    changed=4    unreachable=0    failed=0   
192.168.37.133             : ok=6    changed=4    unreachable=0    failed=0

启动过后照例查看端口号:

[root@server ansible]# ansible web -m shell -a "ss -ntulp |grep 9999"
192.168.37.122 | SUCCESS | rc=0 >>
tcp    LISTEN     0      128       *:9999                  *:*                   users:(("nginx",pid=7831,fd=6),("nginx",pid=7830,fd=6),("nginx",pid=7829,fd=6))
​
192.168.37.133 | SUCCESS | rc=0 >>
tcp    LISTEN     0      128       *:9999                  *:*                   users:(("nginx",pid=9654,fd=6),("nginx",pid=9653,fd=6),("nginx",pid=9652,fd=6))

可以看出我们的剧本已经执行成功。

九、Ansible使用jinja2管理配置文件以及jinja2语法简介

1、Jinja2介绍

Jinja2是基于python的模板引擎,功能比较类似于PHP的smarty,J2ee的Freemarker和velocity。它能完全支持unicode,并具有集成的沙箱执行环境,应用广泛。jinja2使用BSD授权

Jinja2的语法是由variables(变量)和statement(语句)组成,如下;

1、variables:可以输出数据
 my_variables

{{ some_dudes_name | capitalize }}

2、statements: 可以用来创建条件和循环等
if语句:
{% if my_conditional %} 
...
{% endif %}
for 语句:
{% for item in all_items %}
`item` 
……
{% endfor %}

从上面第二个variables的例子中可以看出,jinja2支持使用带过滤器的Unix型管道操作符,有很多的内置过滤器可供使用。我们可以仅仅用一堆简单if和for就可以建立几乎任何的常规配置文件,不过如果你有意更进一步,jinja2 documentation (Jinja — Jinja Documentation (3.2.x))包含了很多有趣的东西可供了解。我们可以看到ansible允许在模板中使用诸如绘制时间此类的一些额外的模板变量

第一个例子:引用变量

# tree 
.
├── site.yml
├── templates
│   └── order.j2
└── vars
    └── main.yml
​
2 directories, 3 files

总调度yml文件:

# cat site.yml 
---
- hosts: 192.168.19.154
  user: root
  vars:
  - PROJECT: "JAVA"
    SWITCH: "ON"
    DBPORT: "8080"
  tasks:
  - name: create{{ PROJECT }}directory
    file: path=/data/{{ PROJECT }} state=directory
  - name: template transfor java
    template: src=order.j2 dest=/data/{{ PROJECT }}/order.conf

注意:这里 - role: template 和 - template 是一样的!

其他yml文件,如下:

# cat templates/order.j2 
project: {{ PROJECT }}
switch: {{ SWITCH }}
dbport: {{ DBPORT }}
​
​
测试:
# ansible-playbook templates.yml --syntax-check
playbook: templates.yml
​
执行:
​
PLAY [192.168.19.154] **********************************************************
​
TASK [Gathering Facts] *********************************************************
ok: [192.168.19.154]
​
TASK [createJAVAdirectory] *****************************************************
changed: [192.168.19.154]
​
TASK [template transfor java] **************************************************
changed: [192.168.19.154]
​
PLAY RECAP *********************************************************************
192.168.19.154             : ok=3    changed=2    unreachable=0    failed=0 
​
#cat /data/JAVA/order.conf
project: JAVA
switch: ON
dbport: 8080

第二个例子:for 语句

为远程主机生成服务器列表,加入该列表从192.168.13.201 web01.test.com 到192.168.13.211 web11.test.com 结束,如果手动添加就很不科学了,这里需要使用jinja2语法的for循环通过模板批量生成对应的配置文件,如下:

ansible目录结构:

#cd /etc/ansible/roles/test_hosts
.
├── meta
│   └── main.yml
├── tasks
│   ├── file1.yml
│   └── main.yml
├── templates
│   └── test1.j2
└── vars
    └── main.yml

各个目录下yml文件内容:

# cat tasks/file1.yml 
- name: ansible jinja2 template for hosts config
  template: src=test1.j2 dest=/etc/httpd/conf/httpd.conf.test
  
# cat tasks/main.yml 
- include: file1.yml
​
# cat templates/test1.j2 
{% for id in range(201,212) %}
192.168.13.{{ id }} web{{ "%02d" |format(id-200) }}.test.com
{% endfor %}
解释:
{{ id }} 提取for循环中对应的变量id值
"%02d"   调用的是python内置的字符串格式化输出(%d格式化整数)因为是01,02这种格式,所以是保留2位,故用02
然后将结果通过管道符 “|” 传递给format 函数做二次处理。

执行结果:

#cat httpd.conf.test
192.168.13.201 web01.test.com
192.168.13.202 web02.test.com
192.168.13.203 web03.test.com
192.168.13.204 web04.test.com
192.168.13.205 web05.test.com
192.168.13.206 web06.test.com
192.168.13.207 web07.test.com
192.168.13.208 web08.test.com
192.168.13.209 web09.test.com
192.168.13.210 web10.test.com
192.168.13.211 web11.test.com

第三个例子:if语句

说明:如果定义端口号,就绑定定义的端口号,如果不定义端口号,就绑定默认端口号

ansible目录结果
#cd /etc/ansible/roles/mysql_cnf
#tree
.
├── meta
│   └── main.yml
├── tasks
│   └── main.yml
├── templates
│   └── test3.j2
└── vars

主要的yml文件是templates目录下面的test3.j2

# cat templates/test3.j2 
{% if PORT %}
bind_address=10.0.90.27:{{ PORT }}
{% else %}
bind_address=10.0.90.27:3306
{% endif %}

playbook主文件

# cat jinj2_test.yml 
---
- hosts: 10.0.90.27
  user: root
  gather_facts: false
  vars:
    PORT: 3136
  tasks:
    - name: copy file to client
      template: src=/etc/ansible/roles/mysql_cnf/templates/test3.j2 dest=/root/my.cnf

执行:

# ansible-playbook jinj2_test.yml
PLAY [10.0.90.27] **************************************************************
TASK [copy file to client] *****************************************************
changed: [10.0.90.27]
PLAY RECAP *********************************************************************
10.0.90.27                 : ok=1    changed=1    unreachable=0    failed=0

查看

# cat my.cnf 
bind_address=10.0.90.27:3136

如果将vars变量去掉,执行结果:

# cat jinj2_test.yml 
---
- hosts: 10.0.90.27
  user: root
  gather_facts: false
  vars:
    PORT: false
  tasks:
    - name: copy file to client
      template: src=/etc/ansible/roles/mysql_cnf/templates/test3.j2 dest=/root/my.cnf

查看:

# cat my.cnf 
bind_address=10.0.90.27:3306
3、Jinja default()设定

精通程序编码的朋友皆知,default()默认值的设定有助于程序的健壮性和简洁性。所幸Jinja也支持该功能,上面的例子中生成Mysql配置文件中的端口定义,如果指定则PORT=3136,否则PORT=3306,我们将该案例改造为使用default()试试

编辑/etc/ansible/roles/mysql_cnf/templates/test3.j2内容如下,这种方法更简介。

bind_address=10.0.90.27:{{ PORT | default(3306) }}

2、ansible使用jinja2生成apache多主机配置

1、创建目录,创建好之后如下:
#cd /etc/ansible/roles/apache_conf
# tree ./
./
├── meta
│   └── main.yml
├── tasks
│   ├── file.yml
│   └── main.yml
├── templates
│   └── apache.config.j2
└── vars
    └── main.yml
​
4 directories, 5 files
2、创建tasks调度文件,如下:
#cat file.yml 
- name: ansible jinja2 template for apache config
  template: src=apache.config.j2 dest=/etc/httpd/conf/httpd.conf.template
  
#cat main.yml 
- include: file.yml
3、创建apache的jinja2模板文件,如下:
#cat apache.config.j2 
NameVirtualHost *:80
{% for vhost in apache_vhost %}
<VirtualHost *:80>
ServerName {{ vhost.servername }}
DocumentRoot {{ vhost.documentroot }}
{% if vhost.serveradmin is defined %}
ServerAdmin {{ vhost.serveradmin }}
{% endif %}
<Directory "{{ vhost.documentroot }}">
AllowOverride All
Options -Indexes FollowSymLinks
Order allow,deny
Allow from all
</Directory>
</VirtualHost>
{% endfor %}
4、创建变量,如下:
#cat vars/main.yml
apache_vhost:
- {servername: "apache.test1.com", documentroot: "/data/test1/"}
- {servername: "apache.test2.com", documentroot: "/data/test2/"}
5、创建总调度yml文件,如下:
#cat /etc/ansible/apache_test.yml 
---
- hosts: 10.0.90.27
  user: root
  gather_facts: no
  roles:
   - { role: apache_conf }
6、测试:
#ansible-playbook apache_test.yml --syntax-check
​
playbook: apache_test.yml
7、执行测试
#ansible-playbook apache_test.yml 
PLAY [10.0.90.27] **************************************************************
TASK [apache_conf : include] ***************************************************
included: /etc/ansible/roles/apache_conf/tasks/file.yml for 10.0.90.27
TASK [apache_conf : ansible jinja2 template for apache config] *****************
changed: [10.0.90.27]
PLAY RECAP *********************************************************************
10.0.90.27                 : ok=2    changed=1    unreachable=0    failed=0
8、到客户端查看
#cat httpd.conf.template 
NameVirtualHost *:80
<VirtualHost *:80>
ServerName apache.test1.com
DocumentRoot /data/test1/
<Directory "/data/test1/">
AllowOverride All
Options -Indexes FollowSymLinks
Order allow,deny
Allow from all
</Directory>
</VirtualHost>
<VirtualHost *:80>
ServerName apache.test2.com
DocumentRoot /data/test2/
<Directory "/data/test2/">
AllowOverride All
Options -Indexes FollowSymLinks
Order allow,deny
Allow from all
</Directory>
</VirtualHost>

3、ansible使用jiaja2生成nginx一个模板多种不同配置

说明:为2台Nginx Proxy,1台Nginx Web通过一套模板生成对应的配置

1、ansible目录结构:
# cd roles/nginx_conf/
#tree
.
├── files
├── meta
│   └── main.yml
├── tasks
│   ├── file.yml
│   └── main.yml
├── templates
│   └── nginx.conf.j2
└── vars
    └── main.yml
2、tasks目录下文件内容:
#cat tasks/file.yml 
- name: nginx.j2 template transfer example 
  template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf.template
  
#cat tasks/main.yml 
- include: file.yml
3、nginx模板文件
#cat templates/nginx.conf.j2 
{% if nginx_use_proxy %}
{% for proxy in nginx_proxies %}
upstream {{ proxy.name }}
   #server 127.0.0.1:{{ proxy.port }};
   server {{ ansible_eth0.ipv4.address }}:{{ proxy.port }};
}
{% endfor %}
{% endif%}
server {
    listen 80;
    servername {{ nginx_server_name }};
    access_log off;
    error_log /etc/nginx/nginx_error.log;
    rewrite ^ https://$server_name$request_uri? permanent;
}
server {
    listen 443 ssl;
    server_name {{ nginx_server_name }};
    ssl_certificate /etc/nginx/ssl/{{ nginx_ssl_cert_name }};
    ssl_certificate_key /etc/nginx/ssl/{{ nginx_ssl_cert_key }};
    root {{ nginx_web_root }};
    index index.html index.html;
{% if nginx_use_auth %}
   auth_basic  "Restricted";
   auth_basic_user_file /etc/nginx/{{ project_name }}.htpasswd;
{% endif %}
{% if nginx_use_proxy %}
{% for proxy in nginx_proxies %}
   location {{ proxy.location }} {
      proxy_set_header X-Real-IP $remote_addr;
      proxy_set_header X-Forwarded-Proto http;
      proxy_set_header X-Url-Scheme $scheme;
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_set_header Host $http_host;
      proxy_set_header X-NginX-Proxy true;
      proxy_redirect off;
      proxy_pass http://{{ proxy.name }};
      break;
}
{% endfor %}
{% endif %}
{% if nginx_server_static %}
   location / {
       try_files $url $url/ =404;
}
{% endif %}
}
4、ansible变量文件
cat vars/main.yml 
nginx_server_name: www.testnginx.com
nginx_web_root: /data/html/
nginx_proxies:
- name: suspicious
  location: /
  port: 1234
- name: suspicious-api
  location: /api
  port: 4567
5、ansible主playbook文件
#cat nginx_test.yml 
##The first roles
- name: Nginx Proxy Server's Config Dynamic Create
  hosts: "10.0.90.25:10.0.90.26"
  remote_user: root
  vars:
    nginx_use_proxy: true
    nginx_ssl_cert_name: ifa.crt
    nginx_ssl_cert_key: ifa.key
    nginx_use_auth: true
    project_name: suspicious
    nginx_server_static: true
  gather_facts: true
  roles:
     -  role: nginx_conf
##The second roles
- name: Nginx WebServer's Config Dynamic Create
  hosts: 10.0.90.27
  remote_user: root
  vars:
    nginx_use_proxy: false
    nginx_ssl_cert_name: ifa.crt
    nginx_ssl_cert_key: ifa.crt
    nginx_use_auth: false
    project_name: suspicious
    nginx_server_static: false
  gather_facts: false
  roles:
     -  role: nginx_conf
6、测试并执行:
#ansible-playbook nginx_test.yml --syntax-check
playbook: nginx_test.yml
​
执行:
# ansible-playbook nginx_test.yml
PLAY [Nginx Proxy Server's Config Dynamic Create] ******************************
​
TASK [setup] *******************************************************************
ok: [10.0.90.25]
ok: [10.0.90.26]
​
TASK [nginx_conf : include] ****************************************************
included: /etc/ansible/roles/nginx_conf/tasks/file.yml for 10.0.90.25, 10.0.90.26
​
TASK [nginx_conf : nginx.j2 template transfer example] *************************
changed: [10.0.90.26]
changed: [10.0.90.25]
​
PLAY [Nginx WebServer's Config Dynamic Create] *********************************
​
TASK [nginx_conf : include] ****************************************************
included: /etc/ansible/roles/nginx_conf/tasks/file.yml for 10.0.90.27
​
TASK [nginx_conf : nginx.j2 template transfer example] *************************
changed: [10.0.90.27]
​
PLAY RECAP *********************************************************************
10.0.90.25                 : ok=3    changed=1    unreachable=0    failed=0   
10.0.90.26                 : ok=3    changed=1    unreachable=0    failed=0   
10.0.90.27                 : ok=2    changed=1    unreachable=0    failed=0
7、查看检测执行结果

到Nginx Proxy 服务器查看配置文件

#cat nginx.conf.template 
upstream suspicious
   #server 127.0.0.1:1234;
   server 10.0.90.26:1234;
}
upstream suspicious-api
   #server 127.0.0.1:4567;
   server 10.0.90.26:4567;
}
server {
    listen 80;
    servername www.testnginx.com;
    access_log off;
    error_log /etc/nginx/nginx_error.log;
    rewrite ^ https://$server_name$request_uri? permanent;
}
server {
    listen 443 ssl;
    server_name www.testnginx.com;
    ssl_certificate /etc/nginx/ssl/ifa.crt;
    ssl_certificate_key /etc/nginx/ssl/ifa.key;
    root /data/html/;
    index index.html index.html;
   auth_basic  "Restricted";
   auth_basic_user_file /etc/nginx/suspicious.htpasswd;
   location / {
      proxy_set_header X-Real-IP $remote_addr;
      proxy_set_header X-Forwarded-Proto http;
      proxy_set_header X-Url-Scheme $scheme;
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_set_header Host $http_host;
      proxy_set_header X-NginX-Proxy true;
      proxy_redirect off;
      proxy_pass http://suspicious;
      break;
}
   location /api {
      proxy_set_header X-Real-IP $remote_addr;
      proxy_set_header X-Forwarded-Proto http;
      proxy_set_header X-Url-Scheme $scheme;
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_set_header Host $http_host;
      proxy_set_header X-NginX-Proxy true;
      proxy_redirect off;
      proxy_pass http://suspicious-api;
      break;
}
   location / {
       try_files $url $url/ =404;
}
}

到Nginx Web 服务器上查看配置文件

#cat nginx.conf.template 
server {
    listen 80;
    servername www.testnginx.com;
    access_log off;
    error_log /etc/nginx/nginx_error.log;
    rewrite ^ https://$server_name$request_uri? permanent;
}
server {
    listen 443 ssl;
    server_name www.testnginx.com;
    ssl_certificate /etc/nginx/ssl/ifa.crt;
    ssl_certificate_key /etc/nginx/ssl/ifa.crt;
    root /data/html/;
    index index.html index.html;
}

到这里,就结束了。用同样的模板通过简单的if和变量设置就可以完成不同类型主机的Nginx conf配置,所以一方面在了解Ansible强大的模板功能的同时,也需要看到模板质量的重要性。

补充:

改配置 vim /etc/vimrc

set ts=2

set nu

set nolist 设置取消隐藏字符

set cursorline

set cursorcolumn

gather_facts: false 不收集远程信息

Ansible 在执行 playbook 时,默认会收集目标主机的一些基本信息,这被称为 facts。这些信息包括操作系统的版本、网络接口、主机名、可用的内存等。

ansible-play 的一些剧本

image-20240416103210773

image-20240416103215903

每写一个剧本,先执行三部曲

三部曲:

image-20240416103250769

优先级

image-20240416110857652

早上:

掌握基本ansible-playbook 用法

template有点问题

nginx.conf 里面用{{a}}

nginx.yml 里面配置

vars:

a: 1等等

使用剧本给其他两个机器安装配置wordpress

安装nginx和php的源

安装nginx和php的包

安装mysql源

启动mysql

修改密码并创建数据库和远程用户

拷贝nginx配置文件

上线代码

启动nginx和php

php80-php-xsl php80-php php80-php-cli php80-php-devel php80-php-gd php80-php-pdo php80-php-mysql php80-php-fpm -y

stty echo 取消回显

when那块没太懂

要巩固一下,整体回顾一下

role角色巩固:

首先ansible-galaxy init mysql 初始化一个mysql目录

image-20240417211433147

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/562010.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

AI助力科研创新与效率双提升:ChatGPT深度科研应用、数据分析及机器学习、AI绘图与高效论文撰写

2022年11月30日&#xff0c;可能将成为一个改变人类历史的日子——美国人工智能开发机构OpenAI推出了聊天机器人ChatGPT3.5&#xff0c;将人工智能的发展推向了一个新的高度。2023年4月&#xff0c;更强版本的ChatGPT4.0上线&#xff0c;文本、语音、图像等多模态交互方式使其在…

Virtualenv:Python项目管理的救星

在Python的世界里&#xff0c;依赖包冲突是开发者的噩梦&#xff0c;但也是成长的催化剂。最近在写Python项目中就碰到了这样的问题&#xff0c;明明代码在自己的电脑上表现都是正常的&#xff0c;在另外一台电脑上却始终有些小问题&#xff0c;两台电脑安装的Python版本都是一…

(1)认识人工智能

第一章 认识人工智能 引言 本人目前大三&#xff0c;双非一本的人工智能专业&#xff0c;代码能力不算太差&#xff0c;做过项目&#xff0c;也打了比赛&#xff0c;获了奖&#xff0c;但是走技术路线总会有否定自己的感觉&#xff0c;可能是感觉自己的才能没有在搞技术方面实…

java-Spring-入门学习-第二天(单例模式和多例模式)

目录 Bean作用域 单例模式(默认可以不写) Spring下的 AutoWired 依赖注入 JaveEE下的 Resource 依赖注入 多例模式 Bean作用域 ​在Spring框架中&#xff0c;Bean是按照作用域来创建的&#xff0c;常见的作用域有两种&#xff1a;Singleton 和 Prototype。Singleton (单例…

数据结构----顺序表

在学习顺序表之前&#xff0c;我们先来了解一下数据结构。 数据是什么呢&#xff1f; 我们在生活中常见的名字&#xff0c;数字&#xff0c;性别等都属于数据。 结构又是什么呢&#xff1f; 在计算机中&#xff0c;结构就是用来保存数据的方式。 总的来说&#xff0c;数据…

anaconda配置的环境对应的地址查看,环境安装位置

打开conda指令窗口 这个和上面的都一样&#xff0c;哪个都行 点开后&#xff0c;输入 conda env list 这里显示的就是自己的每个环境对应的地址了

OpenCV杂记(1):绘制OSD(cv::getTextSize, cv::putText)

1. 简述 我们使用OpenCV时&#xff0c;有时会在图像的某个位置绘制OSD信息&#xff0c;如绘制一些字符串作为指示信息。 本文将简要介绍在图像&#xff08;cv::Mat&#xff09;上绘制固定的字符串信息。 2. 使用的API &#xff08;1&#xff09;cv::getTextSize() CV_EXPORT…

C++模板template(二十一)

在C的模板体现了一种泛型编程的思想&#xff0c;当我们不确定要传入的参数是何种数据类型时我们可以写一个模板类型来代替&#xff0c;当传入参数时才将类型告诉它。模板也是属于一种静态多态&#xff0c;&#xff0c;模板的不同类型发生在编译时。泛型编程&#xff1a;不是针对…

react中useState的值没有改变,而是旧的数值

问题背景 想实现点击按钮就改变数据的效果&#xff0c;但是在控制台的打印结果&#xff0c;总是上一次的修改情况&#xff0c;并不是最新的修改后的数据 代码&#xff1a; import { useState, useRef } from "react";// 实现sonA的数据传递给sonB const SonA () …

排序之插入排序:从斗地主到插入排序

目录 1.斗地主如何摸牌 2.从摸牌想到插入排序 3.完成插入排序 4.结束语 1.斗地主如何摸牌 不知道各位是否玩过几乎人人都玩过的斗地主游戏呢&#xff1f;相必各位或多或少都玩过一点&#xff0c;再没玩过也看别人打过。今天博主就将从这个游戏为大家讲解我们的插入排序。 在…

Zabbix监控Oracle归档日志空间

1、oracle查看归档日志空间的sql语句 select sum(PERCENT_SPACE_USED) from v$recovery_area_usage; 2、交互式查看oracle归档日志空间的命令&#xff0c;可以手动执行一下&#xff0c;注意要用oracle用户 sqlplus -S "/ as sysdba" << EOF select sum(PER…

攻防世界---misc---[中等] QR1

1.下载附件&#xff0c;是一张空白图片&#xff0c;打开看看&#xff0c;仔细看会发现有黑色小点点 2.图片太大了&#xff0c;我们缩小图片的宽高比例 3.将修改后的图片&#xff0c;用Stegsolve打开&#xff0c;切换图层&#xff0c;得到二维码 4.用QR进行二维码扫描 5.得到fla…

Spring之CGLIB和JDK动态代理底层实现

目录 CGLIB 使用示例-支持创建代理对象&#xff0c;执行代理逻辑 使用示例-多个方法&#xff0c;走不同的代理逻辑 JDK动态代理 使用示例-支持创建代理对象&#xff0c;执行代理逻辑 ProxyFactory 如何自动在CGLIB和JDK动态代理转换 使用示例-使用CGLIB代理方式 使用示…

OpenCV基本图像处理操作(十一)——图像特征Sift算法

图像尺度空间 在一定的范围内&#xff0c;无论物体是大还是小&#xff0c;人眼都可以分辨出来&#xff0c;然而计算机要有相同的能力却很难&#xff0c;所以要让机器能够对物体在不同尺度下有一个统一的认知&#xff0c;就需要考虑图像在不同的尺度下都存在的特点。 尺度空间的…

浏览器渲染流程中的 9 个面试点

记得 08 年以前&#xff0c;打开网页的时候一个页面卡死整个浏览器凉凉。 这是因为当时浏览器是单进程架构&#xff0c;一个页面或者插件卡死&#xff0c;整个浏览器都会崩溃&#xff0c;非常影响用户体验。 经过了一代代工程师的设计&#xff0c;现代浏览器改成了多进程架构&…

AD高速板设计-DDR(笔记)

【一】二极管 最高工作频率&#xff1a; 定义&#xff1a;二极管的最高工作频率&#xff0c;即二极管在电路中能够正常工作的最高频率。常见的硅二极管的最高工作频率通常在几十MHz到几百MHz之间。在高频下&#xff0c;二极管可能无法有效地阻止反向电流&#xff0c;但也不会…

Redis入门到通关之数据结构解析-Dict

文章目录 概述构成Dict的扩容Dict的rehash总结 概述 我们知道Redis是一个键值型&#xff08;Key-Value Pair&#xff09;的数据库&#xff0c;我们可以根据键实现快速的增删改查。而键与值的映射关系正是通过Dict来实现的。 Dict由三部分组成&#xff0c;分别是&#xff1a;哈…

数据输入输出流(I/O)

文章目录 前言一、数据输入输出流是什么&#xff1f;二、使用方法 1.DataInputStream类2.DataOutoutStream类3.实操展示总结 前言 数据输入输出流也是将文件输入输出流打包后使用的对象。相比于文件输入输出流&#xff0c;数据输入输出流提供了简单易用的方法去操作不同类型的数…

IDEA安装JAVA_HOME报错、启动界面卡死的解决方案

1、起因 在使用一段时间社区版的IDEA后&#xff0c;发现有些功能无法正常使用&#xff0c;于是打算安装正版旗舰版IDEA&#xff08;狗头&#xff09;。 2、JAVA_HOME报错 结果发现安装完后&#xff0c;经过一段操作&#xff0c;IDEA无法正常启动&#xff0c;报错如下&#x…

oracle一次sql优化笔记

背景&#xff1a;两个百万级数据量表需要连接&#xff0c;加全索引的情况下速度仍不见改善&#xff0c;苦查一下午解决问题未遂。 解决&#xff1a;经大佬指点了解到oracle优化器提示&#xff0c;使用/* USE_HASH(table1 table2) */或者/* USE_MERGE(table1 table2) */来指导优…