爱运动的围巾 · 新闻传播学专业简介(全日制学术型硕士研究生) ...· 3 月前 · |
胡子拉碴的小刀 · 公共营养师、注册营养师、临床营养师的状况与现 ...· 1 年前 · |
瘦瘦的大熊猫 · VR、AR、MR到底是啥1、VR=虚拟世界V ...· 1 年前 · |
活泼的草稿本 · 日本留学中介_日本读研究生_日本语言学校-乐 ...· 1 年前 · |
YAML使用三种节点类型表示任何本机数据结构:序列 - 有序的条目系列;映射 - 唯一键与值的无序关联;和标量 - 任何具有不透明结构的基准面,可表示为一系列 Unicode 字符。这些基元组合在一起,生成有向图结构。选择这些原语是因为它们既强大又熟悉:序列对应于Perl数组和Python列表,映射对应于Perl哈希表和Python字典。标量表示字符串、整数、日期和其他原子数据类型。
每个 YAML 节点除了其种类和内容外,还需要一个指定其数据类型的标记。类型说明符可以是全局 URI,也可以是单个应用程序的本地范围。例如,在 YAML 中,一个整数用标量加上全局标记“tag:yaml.org,2002:int”表示。同样,特定于给定组织的发票对象可以与本地标记“!invoice”一起表示为映射。这个简单的模型可以表示独立于编程语言的任何数据结构。
对于顺序访问媒体(如事件回调 API),YAML 表示形式必须序列化为有序树。由于在 YAML 表示形式中,映射键是无序的,并且节点可能被多次引用(具有多个传入的“箭头”),因此序列化过程需要对映射键施加排序,并将对给定节点的第二个和后续引用替换为称为别名的占位符.YAML 不指定如何选择这些序列化详细信息。YAML处理器可以提出人性化的键顺序和锚点名称,可能是在应用程序的帮助下。然后,可以遍历此过程的结果(YAML 序列化树),以生成一系列事件调用,以便对 YAML 数据进行一次性处理。
要使用串行 API 表示 YAML 表示形式,必须对映射键施加顺序,并使用别名节点来指示以前遇到的节点的后续出现。此过程的结果是一个序列化树,其中每个节点都有一组有序的子节点。对于基于事件的串行 API,可以遍历此树。从串行接口构造本机结构不应使用键序或锚点来保存重要数据。
从 YAML 流加载本机数据结构的过程有几个潜在的故障点。字符流可能格式不正确,别名可能未识别,未指定的标记可能无法解析,标记可能无法识别,内容可能无效,并且本机类型可能不可用.这些故障中的每一个都会导致不完整的加载。
部分表示不需要解析每个节点的标签,并且标量内容的规范形式也不需要可用。这种较弱的表示形式对于文档中使用的类型不完全了解的情况很有用。相反,完整表示指定每个节点的标记,并提供标量内容的规范形式,从而允许进行相等性测试。为了构造本机数据结构,需要完整的表示形式。
标量是最基本的不可在分的值,包含:
#使用缩进的方式 martin: name: Martin D'vloper job: Developer skill: Elite #key对应value,字典列表 - martin: name: Martin D'vloper job: Developer skills: - python - perl - pascal - tabitha: name: Tabitha Bitumen job: Developer skills: - lisp - fortran - erlang martin: {name: Martin D'vloper, job: Developer, skill: Elite} fruits: ['Apple', 'Orange', 'Strawberry', 'Mango'] #几种形式指定布尔值(true/false) create_key: yes needs_agent: no knows_oop: True likes_emacs: TRUE uses_cvs: false
#使用yaml表示一个家庭 name: John Smith age: 41 gender: Male spouse: { name: Jane Smith, age: 37, gender: Female } # 写在一行里 name: Jane Smith #也可以写成多行 age: 37 gender: Female children: [ {name: Jimmy Smith,age: 17, gender: Male}, {name: Jenny Smith, age: 13, gender: Female}, {name: hao Smith, age: 20, gender: Male } ] #写在一行 - name: Jimmy Smith #写在多行,更为推荐的写法 age: 17 gender: Male - {name: Jenny Smith, age: 13, gender: Female} - {name: hao Smith, age: 20, gender: Male }
PlayBook的核心组件
- https://docs.ansible.com/ansible/latest/reference_appendices/playbooks_keywords. html#playbook-keywords
playbook常见组件说明
一个playbook中由多个组件组成,其中所用到的常见组件类型如下:
- Hosts 执行的远程主机列表
- Tasks 任务集,由多个task的元素组成的列表实现,每个task是一个字典,一个完整的代码块功能需最 少元素需包括 name 和 task,一个name只能包括一个task
- Variables 内置变量或自定义变量在playbook中调用
- Templates 模板,可替换模板文件中的变量并实现一些简单逻辑的文件
- Handlers 和 notify 结合使用,由特定条件触发的操作,满足条件方才执行,否则不执行
- tags 标签 指定某条任务执行,用于选择运行playbook中的部分代码。ansible具有幂等性,因此 会自动跳过没有变化的部分,即便如此,有些代码为测试其确实没有发生变化的时间依然会非常地 长。此时,如果确信其没有变化,就可以通过tags跳过此些代码片断
hosts组件
Hosts:playbook中的每一个play的目的都是为了让特定主机以某个指定的用户身份执行任务。hosts用 于指定要执行指定任务的主机,须事先定义在主机清单中
one.example.com one.example.com:two.example.com 192.168.1.50 192.168.1.* Websrvs:dbsrvs #或者,两个组的并集 Websrvs:&dbsrvs #与,两个组的交集 webservers:!dbsrvs #在websrvs组,但不在dbsrvs组
remote_user组件
remote_user: 可用于Host和task中。也可以通过指定其通过sudo的方式在远程主机上执行任务,其可 用于play全局或某任务;此外,甚至可以在sudo时使用sudo_user指定sudo时切换的用户
- hosts: websrvs remote_user: root #指定任务执行默认用户 tasks: - name: test connection ping: remote_user: xiang sudo: yes #默认sudo为root sudo_user:Test #sudo为Testtask列表和action组件
play的主体部分是task list,task list中有一个或多个task,各个task 按次序逐个在hosts中指定的所有主 机上执行,即在所有主机上完成第一个task后,再开始第二个task task的目的是使用指定的参数执行模块,而在模块参数中可以使用变量。模块执行是幂等的,这意味着 多次执行是安全的,因为其结果均一致
每个task都应该有其name,用于playbook的执行结果输出,建议其内容能清晰地描述任务执行步骤。 如果未提供name,则action的结果将用于输出
task的两种格式
action: module arguments #示例: action: shell wall hello module: arguments #建议使用 #示例: shell: wall hello
- hosts: websrvs remote_user: root gather_facts: no tasks: - name: install httpd yum: name=httpd - name: start httpd service: name=httpd state=started enabled=yes
- shell和command模块后面跟命令,而非key=value
其他组件说明
- 某任务的状态在运行后为changed时,可通过"notify"通知给相应的handlers任务
- 还可以通过"tags"给task 打标签,可在ansible-playbook命令上使用-t指定进行调用
案例:对比shell与playbook
#shell 脚本实现安装httpd #!/bin/bash # 安装Apache yum install --quiet -y httpd # 复制配置文件 cp /tmp/httpd.conf /etc/httpd/conf/httpd.conf cp/tmp/vhosts.conf /etc/httpd/conf.d/ # 启动Apache,并设置开机启动 systemctl enable --now httpd
#playbook实验安装httpd - hosts: websrvs remote_user: root gather_facts: no tasks: - name: "安装Apache" yum: name=httpd - name: "复制配置文件" copy: src=/tmp/httpd.conf dest=/etc/httpd/conf/ - name: "复制配置文件" copy: src=/tmp/vhosts.conf dest=/etc/httpd/conf.d/ - name: "启动Apache,并设置开机启动" service: name=httpd state=started enabled=yes
playbook命令
https://docs.ansible.com/ansible/2.9/user_guide/playbooks.html#working-with-playbooks
ansible-playbook命令格式
ansible-playbook <filename.yml> ... [options]
--syntax-check #语法检查,可缩写成--syntax, 相当于bash -n -C --check #模拟执行,只检测可能会发生的改变,但不真正执行操作,dry run --list-hosts #列出运行任务的主机 --list-tags #列出tag --list-tasks #列出task --limit 主机列表 #只针对主机列表中的特定主机执行 -i INVENTORY #指定主机清单文件,通常一个项对应一个主机清单文件 --start-at-task START_AT_TASK #从指定task开始执行,而非从头开始,START_AT_TASK为任务的 -v -vv -vvv #显示过程
[root@ansible ansible]#cat hello.yml - hosts: websrvs tasks: - name: hello command: echo "hello ansible" ansible-playbook file.yml --check #只检测语法 ansible-playbook file.yml #直接执行 ansible-playbook file.yml --limit websrvs 只执行存在webservs列表内的主机
初步使用Playbook
yaml脚本
playbook创建用户与组(mysql_user.yaml)
- hosts: webservs #指定hostsliet remote_user: root #指定执行tasks的默认用户 gather_facts: no #关闭setup收集信息 tasks: - name: "创建组,组名:mysql 系统组 gid为306" group: name=mysql system=yes gid=306 - name: "创建用户 mysql,不可登录,不创建家目录,是系统用户加入mysql组" user: name=mysql shell=/sbin/nologin system=yes group=mysql uid=306 home=/data/mysql create_hoem=no - hosts: webservs #指定hostsliet remote_user: root #指定执行tasks的默认用户 gather_facts: no #关闭setup收集信息 tasks: - { name: create group,group: name=mysql system=yes gid=306 } - { name: create user, user: name=mysql shell=/sbin/nologin system=yes group=mysql uid=306 home=/data/mysql create_home=no } #环境清理 - hosts: webservs remote_user: root gather_facts: no tasks: - name: "删除nginx用户相关的组和目录" user: name=nginx state=absent remove=yesplaybook安装nginx(install_nginx)
- hosts: websers remote_user: root gather_facts: no tasks: - name: "创建挂载目录" file: path=/mnt/cdrom state=directory mode=755 - name: "临时挂载cdrom" mount: src=/dev/cdrom path=/mnt/cdrom fstype=iso9660 state=present - name: "创建nginx组" group: name=nginx state=present gid=307 system=yes - name: "创建nginx用户" user: name=nginx state=present group=nginx uid=307 system=yes create_home=no shell=/sbin/bologin - name: "安装nginx" yum: name=nginx state=present - name: "拷贝网页文件" copy: src=/root/files/index.html dest=/usr/share/nginx/html/index.html - name: "启动服务" service: name=nginx state=started enabled=yes - hosts: webservs remote_user: root gather_facts: no tasks: - { name: "创建挂载目录",file: path=/mnt/cdrom state=directory mode=755 } - { name: "临时挂载cdrom",mount: src=/dev/cdrom path=/mnt/cdrom fstype=iso9660 state=present } - { name: "创建nginx组",group: name=nginx state=present gid=307 system=yes } - { name: "创建nginx用户",user: name=nginx state=present group=nginx uid=307 system=yes create_home=no shell=/sbin/bologin } - { name: "安装nginx",yum: name=nginx state=present } - { name: "拷贝网页文件",copy: src=/root/files/index.html dest=/usr/share/nginx/html/index.html } - { name: "启动服务",service: name=nginx state=started enabled=yes } #环境清理 - hosts: webservs remote_user: root gather_facts: no tasks: - name: "停止服务" service: name=nginx state=stopped - name: "删除nginx用户相关的组和目录" user: name=nginx state=absent remove=yes - name: "卸载目录" mount: path=/mnt/cdrom state=unmounted - name: "删除index文件" file: path=/usr/share/nginx/html/index.html state=absentplaybook安装mysql5.6
#!/usr/bin/ansible-playbook #This is playbook file #install mysql 5.6 - hosts: dbservs remote_user: root gather_facts: yes vars: version: "mysql-5.6.46-linux-glibc2.12-x86_64" suffix: "tar.gz" pack_file: "{{version}}.{{suffix}}" bash: mysql-5.6_install.sh tasks: - name: install packages yum: name=libaio,perl-Data-Dumper,perl-Getopt-Long - name: create mysql group group: name=mysql system=yes gid=306 - name: create mysql user user: name=mysql group=mysql uid=306 system=yes create_home=no shell=/sbin/nologin home=/data/mysql - name: copy tar to remote host and file mode unarchive: src=/data/ansible/files/{{file}} dest=/usr/local/ owner=root group=root - name: create linkfile /usr/local/mysql file: src=/usr/local/{{version}} dest=/usr/local/mysql state=link - name: create linkfile /usr/local/mysql file: src=/usr/local/{{version}} dest=/usr/local/mysql state=link - name: data dir shell: chdir=/usr/local/mysql/ ./scripts/mysql_install_db --datadir=/data/mysql --user=mysql tags: data - name: config my.cnf copy: src=/data/ansible/files/my.cnf dest=/etc/my.cnf - name: service script shell: /bin/cp /usr/local/mysql/support-files/mysql.server /etc/init.d/mysqld - name: enable service shell: /etc/init.d/mysqld start;chkconfig --add mysqld;chkconfig mysqld on tags: service - name: PATH variable copy: content='PATH=/usr/local/mysql/bin:$PATH' dest=/etc/profile.d/mysql.sh - name: secure script script: /data/ansible/files/{{bash}} tags: script
playbook中的忽略错误组件:
ignore_errors
- hosts: websrvs tasks: - name: error command: /bin/false #执行后默认值为1,即rc=1,$?=1 ignore_errors: yes #忽略错误 - name: continue command: wall continue #广播 continue
- 如果一个task出错,默认将不会继续执行后续的其它task 但利用 ignore_errors: yes 可以忽略此task的错误,继续向下执行playbook其它task
playbook的触发器组件:
handlers和notify
Handlers本质是task list ,类似于MySQL中的触发器触发的行为,其中的task与前述的task并没有本质 上的不同,主要用于当关注的资源发生变化时,才会采取一定的操作。而Notify对应的action可用于在 每个play的最后被触发,这样可避免多次有改变发生时每次都执行指定的操作,仅在所有的变化发生完 成后一次性地执行指定操作。在notify中列出的操作称为handler,也即notify中调用handler中定义的操作;
- 如果多个task通知了相同的handlers, 此handlers仅会在所有tasks结束后运行一 次。
- 只有notify对应的task发生改变了才会通知handlers, 没有改变则不会触发handlers
- handlers 是在所有前面的tasks都成功执行才会执行,如果前面任何一个task失败,会导致handler跳 过执行,可以使用force_handlers: yes 强制执行handler
#复制httpd的配置文件到指定目录 cp -p /etc/httpd/conf/httpd.conf /root/files/ #生成playbook,对httpd.conf设置notify - hosts: websrvs remote_user: root gather_facts: no tasks: - name: Install httpd yum: name=httpd state=present - name: Install configure file copy: src=/root/files/httpd.conf dest=/etc/httpd/conf/ #当httpd.conf文件发生改变时触发notify notify: - restart httpd - wall - name: ensure apache is running service: name=httpd state=started enabled=yes handlers: - name: restart httpd service: name=httpd state=restarted - name: wall command: wall "The config file is changed" #执行playbook,可以发现没有触发notify,因此HANDLER直接跳过了 [root@Ansible-Master Date14:04]#ansible-playbook install_httpd.yaml PLAY [webservs] ********************************************************************************************************************************************************************************************************** TASK [Install httpd] ***************************************************************************************************************************************************************************************************** changed: [192.168.213.123] changed: [192.168.213.122] TASK [Install configure file] ******************************************************************************************************************************************************************************************** changed: [192.168.213.122] changed: [192.168.213.123] TASK [ensure apache is running] ****************************************************************************************************************************************************************************************** changed: [192.168.213.123] changed: [192.168.213.122] RUNNING HANDLER [restart httpd] ****************************************************************************************************************************************************************************************** changed: [192.168.213.123] changed: [192.168.213.122] RUNNING HANDLER [wall] *************************************************************************************************************************************************************************************************** skipping: [192.168.213.122] skipping: [192.168.213.123] PLAY RECAP *************************************************************************************************************************************************************************************************************** 192.168.213.122 : ok=4 changed=4 unreachable=0 failed=0 skipped=1 rescued=0 ignored=0 192.168.213.123 : ok=4 changed=4 unreachable=0 failed=0 skipped=1 rescued=0 ignored=0 #修改httpd.conf文档后在执行playbook sed -ri '/Listen/s/80/8088/' /root/files/httpd.conf #再次执行playbook,成功触发HANDLER [root@Ansible-Master Date14:07]#ansible-playbook -C install_httpd.yaml PLAY [webservs] ********************************************************************************************************************************************************************************************************** TASK [Install httpd] ***************************************************************************************************************************************************************************************************** ^C [ERROR]: User interrupted execution [root@Ansible-Master Date14:12]#ansible-playbook install_httpd.yaml PLAY [webservs] ********************************************************************************************************************************************************************************************************** TASK [Install httpd] ***************************************************************************************************************************************************************************************************** ok: [192.168.213.123] ok: [192.168.213.122] TASK [Install configure file] ******************************************************************************************************************************************************************************************** changed: [192.168.213.123] changed: [192.168.213.122] TASK [ensure apache is running] ****************************************************************************************************************************************************************************************** ok: [192.168.213.123] ok: [192.168.213.122] RUNNING HANDLER [restart httpd] ****************************************************************************************************************************************************************************************** changed: [192.168.213.123] changed: [192.168.213.122] RUNNING HANDLER [wall] *************************************************************************************************************************************************************************************************** changed: [192.168.213.122] changed: [192.168.213.123] PLAY RECAP *************************************************************************************************************************************************************************************************************** 192.168.213.122 : ok=5 changed=3 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 192.168.213.123 : ok=5 changed=3 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
#强制触发HANDLER - hosts: websers remote_user: root gather_facts: no force_handlers: yes #无论task中的任何一个task失败,仍强制调用handlers tasks: - name: config file copy: src=nginx.conf dest=/etc/nginx/nginx.conf notify: - restart nginx - name: install package yum: name=no_exist_package handlers: - name: restart nginx service: name=nginx state=restarted - name: "wall" command: wall "call handlers"
playbook中的标签组件:
tags
https://docs.ansible.com/ansible/latest/user_guide/playbooks_tags.html
- 在playbook文件中,可以利用tags组件,为特定 task 指定标签,当在执行playbook时,可以只执行特 定tags的task,而非整个playbook文件
- 可以一个task对应多个tag,也可以多个task对应一个tag
- 还有另外3个特殊关键字用于标签, tagged, untagged 和 all,它们分别是仅运行已标记,只有未标记和所 有任务。
#对单个任务添加标签 - hosts: webservs remote_user: root gather_facts: no tasks: - name: Install httpd yum: name=httpd state=present - name: Install configure file copy: src=files/httpd.conf dest=/etc/httpd/conf/ tags: - conf - file - name: start httpd service tags: service service: name=httpd state=started enabled=yes #查看标签 [root@Ansible-Master Date16:44]#ansible-playbook --list-tags tag_Test-01.yaml playbook: tag_Test-01.yaml play #1 (webservs): webservs TAGS: [] TASK TAGS: [conf, file, service] #运行单个标签 [root@Ansible-Master Date16:46]#ansible-playbook -t conf tag_Test-01.yaml PLAY [webservs] ********************************************************************************************************************************************************************************************************** TASK [Install configure file] ******************************************************************************************************************************************************************************************** ok: [192.168.213.122] ok: [192.168.213.123] PLAY RECAP *************************************************************************************************************************************************************************************************************** 192.168.213.122 : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 192.168.213.123 : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 #跳过某个标签 [root@Ansible-Master Date16:46]#ansible-playbook -t conf tag_Test-01.yaml PLAY [webservs] ********************************************************************************************************************************************************************************************************** TASK [Install configure file] ******************************************************************************************************************************************************************************************** ok: [192.168.213.122] ok: [192.168.213.123] PLAY RECAP *************************************************************************************************************************************************************************************************************** 192.168.213.122 : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 192.168.213.123 : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 [root@Ansible-Master Date16:46]#ansible-playbook --skip-tags conf tag_Test-01.yaml PLAY [webservs] ********************************************************************************************************************************************************************************************************** TASK [Install httpd] ***************************************************************************************************************************************************************************************************** ok: [192.168.213.123] ok: [192.168.213.122] TASK [start httpd service] *********************************************************************************************************************************************************************************************** ok: [192.168.213.123] ok: [192.168.213.122] PLAY RECAP *************************************************************************************************************************************************************************************************************** 192.168.213.122 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 192.168.213.123 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
#对tasks打标签 - hosts: websevs remote_user: root tags: install gather_facts: no tasks: - { name: "创建挂载目录",file: path=/mnt/cdrom state=directory mode=755 } - { name: "临时挂载cdrom",mount: src=/dev/cdrom path=/mnt/cdrom fstype=iso9660 state=present } - { name: "创建nginx组",group: name=nginx state=present gid=307 system=yes } - { name: "创建nginx用户",user: name=nginx state=present group=nginx uid=307 system=yes create_home=no shell=/sbin/bologin } - { name: "安装nginx",yum: name=nginx state=present } - { name: "拷贝网页文件",copy: src=/root/files/index.html dest=/usr/share/nginx/html/index.html } - { name: "启动服务",service: name=nginx state=started enabled=yes } - hosts: webservs remote_user: root tags: clear gather_facts: no tasks: - name: "停止服务" service: name=nginx state=stopped - name: "删除nginx用户相关的组和目录" user: name=nginx state=absent remove=yes - name: "卸载目录" mount: path=/mnt/cdrom state=unmounted - name: "删除index文件" file: path=/usr/share/nginx/html/index.html state=absent #查看标签 [root@Ansible-Master Date16:56]#ansible-playbook --list-tags tag_Test-02.yaml playbook: tag_Test-02.yaml play #1 (webservs): webservs TAGS: [install] TASK TAGS: [install] play #2 (webservs): webservs TAGS: [clear] TASK TAGS: [clear] #只运行clear标签 [root@Ansible-Master Date16:56]#ansible-playbook -t clear tag_Test-02.yaml PLAY [webservs] ********************************************************************************************************************************************************************************************************** PLAY [webservs] ********************************************************************************************************************************************************************************************************** TASK [停止服务] ************************************************************************************************************************************************************************************************************** ok: [192.168.213.123] ok: [192.168.213.122] TASK [删除nginx用户相关的组和目录] ************************************************************************************************************************************************************************************************** ok: [192.168.213.122] ok: [192.168.213.123] TASK [卸载目录] ************************************************************************************************************************************************************************************************************** changed: [192.168.213.122] changed: [192.168.213.123] TASK [删除index文件] ********************************************************************************************************************************************************************************************************* changed: [192.168.213.122] changed: [192.168.213.123] PLAY RECAP *************************************************************************************************************************************************************************************************************** 192.168.213.122 : ok=4 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 192.168.213.123 : ok=4 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
playbook的变量:
vars
Playbook中同样也支持变量
变量名:仅能由字母、数字和下划线组成,且只能以字母开头
变量定义:
variable=value variable: value
变量调用方式
- 通过 {{ variable_name }} 调用变量,且变量名前后建议加空格,有时用"{{ variable_name }}"才生效
ansible 的 setup facts 远程主机的所有变量都可直接调用
通过命令行指定变量,优先级最高
nsible-playbook -e varname=value test.yml
在playbook文件中定义
vars: vars1: value1 vars2: value2
在独立的变量YAML文件中定义
- hosts: all vars_files: - vars.yml
在主机清单文件中定义
- 主机(普通)变量:主机组中主机单独定义,优先级高于公共变量
- 组(公共)变量:针对主机组中所有主机定义统一变量
在项目中针对主机和主机组定义
- 在项目目录中创建 host_vars和group_vars目录
在role中定义
变量优先级顺序
-e 选项定义变量 -->playbook中vars_files --> playbook中vars变量定义 -->host_vars/主机名 文件 -->主机清单中主机变量--> group_vars/主机组名文件-->group_vars/all文件--> 主机清单组
从setup模块中获取的变量:
facts
- 本模块自动在playbook调用,不要用ansible命令调用,生成的系统状态信息, 并存放在facts变量中
- facts 包括的信息很多,如: 主机名,IP,CPU,内存,网卡等
- facts变量的实际使用常见案例
- 通过facts变量获取被控端CPU的个数信息,从而生成不同的Nginx配置文件
- 通过facts变量获取被控端内存大小信息,从而生成不同的memcached的配置文件
- 通过facts变量获取被控端主机名称信息,从而生成不同的Zabbix配置文件
#使用setup变量的方法 [root@Ansible-Master Date17:18]#ansible 192.168.213.122 -m setup -a 'filter="ansible_default_ipv4"' 192.168.213.122 | SUCCESS => { "ansible_facts": { "ansible_default_ipv4": { "address": "192.168.40.182", "alias": "eth0", "broadcast": "192.168.40.255", "gateway": "192.168.40.1", "interface": "eth0", "macaddress": "00:0c:29:af:fc:35", "mtu": 1500, "netmask": "255.255.255.0", "network": "192.168.40.0", "type": "ether" "discovered_interpreter_python": "/usr/bin/python" "changed": false
#在playbook中调用setup变量 - hosts: webservs remote_user: root gather_facts: yes tasks: - name: create log file file: name=/data/{{ ansible_nodename }}.log state=touch owner=wang mode=600
在playbook 中定义变量的几种方式
#命令行指定变量 #yaml主体 - hosts: websrvs remote_user: root tasks: - name: install package yum: name={{ pkname }} state=present #执行命令需-e 调用变量,多个变量可以用空格隔开 ansible-playbook -e pkname=httpd var2.yaml #多个变量 #yaml主体 - hosts: websrvs remote_user: root vars: username: user1 groupname: group1 tasks: - name: create group {{ groupname }} group: name={{ groupname }} state=present - name: create user {{ username }} user: name={{ username }} group={{ groupname }} state=present #命令行调用 ansible-playbook -e username=Test groupname=Test var2.yaml
#命令行指定变量文件 #yaml主体 tee vars <<EOF pkname1: memcached pkname2: vsftpd - hosts: websrvs remote_user: root tasks: - name: install package {{ pkname1 } yum: name={{ pkname1 }} state=present - name: install package {{ pkname2 } yum: name={{ pkname2 }} state=present #执行命令需-e ‘@变量文件路径与名称’调用变量文件 ansible-playbook -e '@vars' var2.yml
#变量之间的相互调用方法:文件内调用 - hosts: websrvs vars: suffix: "txt" file: "{{ ansible_nodename }}.{{suffix}}" tasks: - name: test var file: path="/data/{{file}}" state=touch #变量之间的相互调用,文件内变量+文件外变量 #生成变量文件vars1 tee vars1 <<EOF pkweb: httpd pkftp: vsftp #playbook主体 - hosts: webservs remote_user: root gather_facts: no vars: - Username: Test-1 - Groupname: Test-group - Dir: /home/{{ Username }} tasks: - name: "创建组{{ groupname }}" group: name={{ Groupname }} system=no gid=3099 - name: "创建用户{{ username }}" user: name={{ Username }} state=present system=no home={{ Dir }} uid=3099 shell=/sbin/nologin group={{ Groupname }} - name: "下载对应包到指定目录" yum: name={{ pkweb }} {{ pkftp }} download_dir={{ Dir }} download_only=yes #执行playbook [root@Ansible-Master Date10:38]#ansible-playbook -e '@vars1' vars1.yaml #环境清理 ansible webservs -m user -a 'name=Test-1 state=absent remove=yes'
#变量之间的相互调用,playbook文件内调用变量文件; #生成变量文件vars1 tee vars1.yml <<EOF pkweb: httpd pkftp: vsftp Username: Test-1 Groupname: Test-group Dir: /home/{{ Username }} #playbook主体 - hosts: webservs remote_user: root gather_facts: no vars: - vars1.yml tasks: - name: "创建组{{ groupname }}" group: name={{ Groupname }} system=no gid=3099 - name: "创建用户{{ username }}" user: name={{ Username }} state=present system=no home={{ Dir }} uid=3099 shell=/sbin/nologin group={{ Groupname }} - name: "下载对应包到指定目录" yum: name={{ pkweb }} {{ pkftp }} download_dir={{ Dir }} download_only=yes #执行playbook [root@Ansible-Master Date10:38]#ansible-playbook vars1.yaml
主机和主机组的变量
在主机清单中针对所有项目的主机和主机分组的变量
所有项目的主机变量
说明:
在inventory 主机清单文件中为指定的主机定义变量以便于在playbook中使用
范例:
[websrvs] www1.example.com http_port=80 maxRequestsPerChild=808 www2.example.com http_port=8080 maxRequestsPerChild=909
所有项目的组(公共)变量
说明:
在inventory 主机清单文件中赋予给指定组内所有主机上的在playbook中可用的变量,如果和主机变是 同名,优先级低于主机变量
范例:
[websrvs:vars] http_port=80 ntp_server=ntp.example.com nfs_server=nfs.example.com [all:vars] # --------- Main Variables --------------- # Cluster container-runtime supported: docker, containerd CONTAINER_RUNTIME="docker" # Network plugins supported: calico, flannel, kube-router, cilium, kube-ovn CLUSTER_NETWORK="calico" # Service proxy mode of kube-proxy: 'iptables' or 'ipvs' PROXY_MODE="ipvs" # K8S Service CIDR, not overlap with node(host) networking SERVICE_CIDR="192.168.0.0/16" # Cluster CIDR (Pod CIDR), not overlap with node(host) networking CLUSTER_CIDR="172.16.0.0/16" # NodePort Range NODE_PORT_RANGE="20000-60000" # Cluster DNS Domain CLUSTER_DNS_DOMAIN="example.local."
针对当前项目的主机和主机组的变量
上面的方式是针对所有项目都有效,而官方更建议的方式是使用ansible特定项目的主机变量和组变量
生产建议在项目目录中创建额外的两个变量目录,分别是host_vars和group_vars
host_vars下面的文件名和主机清单主机名一致,针对单个主机进行变量定义,格式:host_vars/hostname
group_vars下面的文件名和主机清单中组名一致, 针对单个组进行变量定义,格式: gorup_vars/groupname
group_vars/all文件内定义的变量对所有组都有效
范例:
[root@Ansible-Master ansible11:02]#tree /ansible/ /ansible/ ├── 1.sh ├── 2.sh ├── 3.sh ├── groups_vars │ ├── all │ └── webservs ├── group_vars │ ├── all │ └── webservs ├── host_vars │ ├── 192.168.213.122 │ └── 192.168.213.123 ├── Test_var7.yaml └── Test.yaml 3 directories, 11 files [root@Ansible-Master ansible11:03]#cat group_vars/ all webservs [root@Ansible-Master ansible11:03]#cat group_vars/webservs name: slave [root@Ansible-Master ansible11:03]#cat group_vars/all domain: Slave [root@Ansible-Master ansible11:03]#cat host_vars/192.168.213.122 id: 01 [root@Ansible-Master ansible11:04]#cat host_vars/192.168.213.123 id: 02 [root@Ansible-Master ansible11:04]#cat Test_var7.yaml #!/usr/bin/ansible-playbook # This is a playbook file - hosts: webservs remote_user: root gather_facts: no tasks: - name: get variable command: echo "{{name}}{{id}}.{{domain}}" register: result - name: print variable debug: msg: "{{result.stdout}}" [root@Ansible-Master ansible11:05]#ansible-playbook Test_var7.yaml PLAY [webservs] ********************************************************************************************************************************************************************************************************** TASK [Gathering Facts] *************************************************************************************************************************************************************************************************** ok: [192.168.213.123] ok: [192.168.213.122] TASK [get variable] ****************************************************************************************************************************************************************************************************** changed: [192.168.213.122] changed: [192.168.213.123] TASK [print variable] **************************************************************************************************************************************************************************************************** ok: [192.168.213.122] => { "msg": "slave1.slave01" ok: [192.168.213.123] => { "msg": "slave2.slave02" PLAY RECAP *************************************************************************************************************************************************************************************************************** 192.168.213.122 : ok=3 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 192.168.213.123 : ok=3 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
playbook中注册变量:
register
- 在playbook中可以使用register将捕获命令的输出保存在临时变量中,然后使用debug模块进行显示输出
#利用debug 模块输出变量 - hosts: dbsrvs remote_user: root gather_facts: no tasks: - name: get variable shell: hostname register: name - name: "print variable" debug: msg: "{{ name }}" #输出register注册的name变量的全部信息,注意变量要加" "引起来 #msg: "{{ name.cmd }}" #显示命令 #msg: "{{ name.rc }}" #显示命令成功与否 #msg: "{{ name.stdout }}" #显示命令的输出结果为字符串形式 #msg: "{{ name.stdout_lines }}" #显示命令的输出结果为列表形式 #msg: "{{ name.stdout_lines[0] }}" #显示命令的输出结果的列表中的第一个元素 #msg: "{{ name['stdout_lines'] }}" #显示命令的执行结果为列表形式 第一个 task 中,使用了 register 注册变量名为 name ;当 shell 模块执行完毕后,会将数据放到该 第二给 task 中,使用了 debug 模块,并从变量name中获取数据。
#使用register注册变量创建文件 - hosts: webservs remote_user: root gather_facts: no tasks: - name: "获取主机名并注册变量" shell: hostname register: file_name - name: ”创建文件“ file: dest=/tmp/{{ file_name }}.log state=touch
#register和debug一起使用 - hosts: webservs remote_user: root gather_facts: no tasks: - name: "出输出测试值给register注册" shell: echo hello word register: say - name: "获取root用户名称,并注册为变量" shell: "awk -F: 'NR==1{print $1}' /etc/passwd" register: user - name: "使用debug输出变量" debug: var=say.stdout - debug: var=user.stdout
#安装nginx并启动 - hosts: webservs remote_user: root gather_facts: yes vars: - pkname: nginx tasks: - name: "安装{{ pkname }}包" yum: name={{ pkname }} state=present - name: "启动{{ pkname }}服务" service: name={{ pkname }} state=started enabled=yes - name: "检查" shell: ps aux |grep {{ pkname }} register: check_value - debug: msg: "{{ check_value.stdout_lines }}"
#修改主机名 - hosts: webservs remote_user: root gather_facts: no vars: host: web domin: slave tasks: - name: "注册变量" shell: echo $RANDOM | md5sum | cut -c 1-8 #取8位随机数 register: get_random - name: "打印变量" debug: msg: "{{ get_random.stdout }}" - name: "修改主机名称" hostname: name={{ host }}-{{ get_random.stdout }}.{{ domain }}
playbook使用模板:
template组件
- 模板是一个文本文件,可以做为生成文件的模版,并且模板文件中还可嵌套jinja2语法
Jinja2语言介绍
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sNc2o7jc-1653902203437)(C:\Users\10163\AppData\Roaming\Typora\typora-user-images\image-20220524161245604.png)]
Jinja2 是一个现代的,设计者友好的,仿照 Django 模板的 Python 模板语言。 它速度快,被广泛使 用,并且提供了可选的沙箱模板执行环境保证安全:
jinja2语言特点
- 沙箱中执行
- 强大的 HTML 自动转义系统保护系统免受 XSS
- 模板继承
- 及时编译最优的 python 代码
- 可选提前编译模板的时间
- 易于调试。异常的行数直接指向模板中的对应行。
- 可配置的语法
官方中文文档
http://docs.jinkan.org/docs/jinja2/ https://www.w3cschool.cn/yshfid/
jinja2支持的类型
字面量,如: 字符串:使用单引号或双引号,数字:整数,浮点数 列表:[item1, item2, ...] 元组:(item1, item2, ...) 字典:{key1:value1, key2:value2, ...} 布尔型:true/false 算术运算:+, -, *, /, //, %, ** 比较操作:==, !=, >, >=, <, <= 逻辑运算:and,or,not 流表达式:For,If,When
常用数据类型介绍
- 表达式最简单的形式就是字面量。字面量表示诸如字符串和数值的 Python 对象。如"Hello World"
- 双引号或单引号中间的一切都是字符串。无论何时你需要在模板中使用一个字符串(比如函数调用、过 滤器或只是包含或继承一个模板的参数),如42,42.23
- 数值可以为整数和浮点数。如果有小数点,则为浮点数,否则为整数。在 Python 里, 42 和 42.0 是不 一样的
算术运算
+
:把两个对象加到一起。通常对象是素质,但是如果两者是字符串或列表,你可以用这 种方式来衔接 它们。无论如何这不是首选的连接字符串的方式!连接字符串见 ~ 运算符。 {{ 1 + 1 }} 等于 2-
:用第一个数减去第二个数。 {{ 3 - 2 }} 等于 1/
:对两个数做除法。返回值会是一个浮点数。 {{ 1 / 2 }} 等于 0.5//
:对两个数做除法,返回整数商。 {{ 20 // 7 }} 等于 2%
:计算整数除法的余数。 {{ 11 % 7 }} 等于 4*
:用右边的数乘左边的操作数。 {{ 2 * 2 }} 会返回 4 。也可以用于重 复一个字符串多次。 {{ ‘=’ * 80 }} 会打印 80 个等号的横条\**
:取左操作数的右操作数次幂; {{ 2**3 }} 会返回 8
比较操作符
- == :比较两个对象是否相等
- !=:比较两个对象不想等,等于==的取反
- > :如果左边大于右边,返回 true
- >= :如果左边大于等于右边,返回 true
- < :如果左边小于右边,返回 true
- <= :如果左边小于等于右边,返回 true
逻辑运算符
- 对于 if 语句,在 for 过滤或 if 表达式中,它可以用于联合多个表达式
- and 如果左操作数和右操作数同为真,返回 true
- or 如果左操作数和右操作数有一个为真,返回 true
- not 对一个表达式取反
- (expr)表达式组
- true / false true 永远是 true ,而 false 始终是 false
template介绍
可以根据和参考模块文件,动态生成相类似的配置文件 template文件必须存放于templates目录下,且命名为 .j2 结尾
例如:
yaml/yml 文件需和templates目录平级,目录结构如下:
./
├── temnginx.yml
└── templates
└── nginx.conf.j2
范例:利用template同步nginx配置文件
#创建template目录 mkdir "/root/Date/templates" #拷贝nginx配置文件 cp -p /etc/nginx/nginx.conf /root/Date/templates/nginx.conf.j2 #修改nginx.config.j2文件,这里使用的变量ansible_processor_vcpu是setup的主机变量(具体内容请看setup模块部分),故gather_facts必须为yes(也可以不写,该组件默认开启); sed -ri "/^worker_processe/s/auto/{{ ansible_processor_vcpu+2 }}/" #这里是逻辑运算符的运用 /root/Date/templates/nginx.conf.j2 #!/usr/bin/ansible-playbook # This is a playbook file - hosts: webservs remote_user: root gather_facts: yes #因为使用了setup变量,所以一定要收集主机信息 tasks: - name: create dir file: path=/data state=directory - name: templates template: src=/root/Date/templates/nginx.conf.j2 dest=/data/for.conf
Template中的流程控制 :
for循环和if判断
- template中也可以使用流程控制 for 循环和 if 条件判断,实现动态生成文件功能
template中的for循环格式与范例
{% for i in EXPR %} {% endfor %} {% for i in range(1,10) %} server_name web{{i}}; {% endfor %}
#playbook文件内容 #!/usr/bin/ansible-playbook # This is a playbook file - hosts: webservs remote_user: root gather_facts: yes vars: nginx_vhosts: - 81 - 82 - 83 tasks: - name: template config template: src=Test_for-2.j2 dest=/root/nginx.conf #template文件内容 {% for vhosts in vhost_list %} server { listen {{ vhosts }} {% endfor %} #执行命令 [root@Ansible-Master Date10:12]#ansible-playbook jinja_Template-2.yml --limit 192.168.213.122 #结果验证 [root@web-0aadc460 ~10:14]$cat nginx.conf server { linsten 100 server { linsten 101 server { linsten 102
#playbook内容 #!/sbin/bin/playbook #This is playbook file - hosts: webservs remote_user: root gather_facts: yes vars: vhosts_list: - listen: 8080 server_name: "web1.slave.com" path: "/data/www/nginx/web1" - listen: 8081 server_name: "web2.slave.com" path: "/data/www/nginx/web2" - listen: 8082 server_name: "web3.slave.com" path: "/data/www/nginx/web3" tasks: - name: "创建目录,并忽略错误" file: name=/data/www/nginx/ state=directory ignore_errors: yes - name: "拷贝模板配置" template: src=Test_for-3.j2 dest=/data/www/nginx/nginx—2.conf #template文件内容 {% for vhost in vhosts_list %} server{ linsten {{ vhost.listen }} server_name {{ vhost.server_name }} path {{ vhost.path }} {% endfor %} #执行命令 [root@Ansible-Master Date10:29]#ansible-playbook jinja_Template-3.yml --limit 192.168.213.123 #结果验证 [root@web-1654f449 nginx10:30]$cat nginx4.conf server{ linsten 8080 server_name web1.slave.com path: /data/www/nginx/web1 server{ linsten 8081 server_name web2.slave.com path: /data/www/nginx/web2 server{ linsten 8082 server_name web3.slave.com path: /data/www/nginx/web3
template中的if 条件判断格式与范例
{% if i is exrp %} {% endif %} {% for i is defined %} server_name web{{i}}; {% endif %}
#使用先前的playbook,增加if判断 #playbook内容 #!/sbin/bin/playbook #This is playbook file - hosts: webservs remote_user: root gather_facts: yes vars: vhosts_list: #删除web1的servername - listen: 8080 path: "/data/www/nginx/web1" - listen: 8081 server_name: "web1.slave.com" path: "/data/www/nginx/web2" - listen: 8082 server_name: "web1.slave.com" path: "/data/www/nginx/web3" tasks: - name: "创建目录,并忽略错误" file: name=/data/www/nginx/ state=directory ignore_errors: yes - name: "拷贝模板配置" template: src=Test_for-3.j2 dest=/data/www/nginx/nginx—3.conf #template文件内容 {% for vhost in vhosts_list %} server{ linsten {{ vhost.listen }} {% if vhost.server_name is defined %} #判断是否存在该值,若存在则输出; server_name {{ vhost.server_name }} {% endif %} path {{ vhost.path }} {% endfor %} #执行命令 [root@Ansible-Master Date10:29]#ansible-playbook jinja_Template-4.yml --limit 192.168.213.123 #结果验证 [root@web-1654f449 nginx10:49]$cat nginx5.conf server{ linsten 8080 path: /data/www/nginx/web1 server{ linsten 8081 server_name web1.slave.com path: /data/www/nginx/web2 server{ linsten 8082 server_name web1.slave.com path: /data/www/nginx/web3
Playbook中的循环:
with_items
对迭代项的引用,固定内置变量名为"item"
要在task中使用with_items给定要迭代的元素列表
注意: ansible2.5版本后,可以用loop代替with_items
迭代:当有需要重复性执行的任务时,可以使用迭代机制
列表元素格式
- 字符串
- 字典
示例:
--- - hosts: websrvs remote_user: root gather_facts: yes tasks: - name: "创建用户" user: name={{ item }} state=present groups=wheel #生成循环列表 with_items: - testuser1 - testuser2 - testuser3 #该with_items等价于 - user: name=testuser1 state=present groups=wheel;(重复3次) - hosts: websrvs remote_user: root gather_facts: no tasks: - name: copy file copy: src={{ item }} dest=/tmp/{{ item }} with_items: - file1 - file2 - file3
#卸载mysql - hosts: 192.168.213.124 remote_user: root gather_facts: no vars: - versions: 5.6.46 - pkname: mysql-{{ versions }}-linux-glibc2.12-x86_64 - path: /usr/local - config: my.cnf tasks: - name: "停止服务" shell: /etc/init.d/mysqld stop - name: "删除文件" file: path={{ item }} state=absent #生成列表 with_items: - {{ path }}/mysql - {{ path }}/{{ pkname }} - /etc/{{ my.cnf }} - /etc/init.d/mysqld - /etc/profile.d/mysql.sh - /data/mysql - name: "删除用户与相关配置" user: name=mysql state=absent remove=yes
#批量安装与卸载 #!/usr/bin/ansible-playbook #This is playbook file #remove mariadb server - hosts: webservs remote_user: root gather_facts: yes tags:install tasks: - name: mount sr0 shell: mount /dev/cdrom /mnt/cdrom ignore_errors: yes - name: yum mkcache shell: yum makecache - name: install some packages yum: name={{ item }} state=present loop: - nginx - memcached - php-fpm - hosts: webservs remote_user: root gather_facts: yes tags: remove tasks: - name: remove some packages yum: name={{ item }} state=absent loop: - nginx - memcached - php-fpm
迭代嵌套子变量
- 在迭代中,还可以嵌套子变量,关联多个变量在一起使用,实现对应关系
#!/usr/bin/ansible-playbook # This is ansible-playbook files # purpose: copy file and rename and clear - hosts: webservs remote_user: root gather_facts: no tags: create tasks: - name: "拷贝文件并重命名" copy: src=/data/{{ item.old }} dest=/tmp/{{ item.new }} with_items: - { old: 'file1', new: 'files_01' } - { old: 'file2', new: 'files_02' } - { old: 'file3', new: 'files_03' } - name: "查看文件" shell: ls /data/files_*;sleep 3; - hosts: webservs remote_user: root gather_facts: no tags: remove tasks: - name: "删除文件" file: name=/tmp/{{ item }} state=absent loop: - files_01 - files_02 - files_03
#!/usr/bin/ansible-playbook # This is ansible-playbook files # purpose: create user and clear - hosts: webservs remote_user: root gather_facts: yes tags: useradd vars: shell_dir: /sbin/nologin tasks: - name: create group group: name={{ item }} state=present with_items: - Test01 - Test02 - Test03 - name: create user user: name={{ item.name }} group={{ item.gname }} uid={{ item.num }} home={{ item.dir }} create_home=no shell={{ item.shell }} state=present loop: - { name: 'Test01', gname: 'Test01', num: '9009', dir: '/data/Test01',shell: "{{ shell_dir }}" } - { name: 'Test02', gname: 'Test02', num: '9010', dir: '/data/Test02',shell: "{{ shell_dir }}" } - { name: 'Test03', gname: 'Test03', num: '9011', dir: '/data/Test03',shell: "{{ shell_dir }}" } - hosts: webservs remote_user: root gather_facts: no tags: deluser tasks: - name: delete user user: name={{ item }} state=absent remove=yes loop: - Test01 - Test02 - Test03
#!/usr/bin/ansible-playbook # This is ansible-playbook files # purpose: Changing User Passwords in Batches - hosts: webservs remote_user: root gather_facts: no vars: - user1: mysql - user2: xiang tasks: - name: change user password user: user={{ item.name }} password={{ item.chpass | password_hash('sha512') }} update_password=always loop: - { name: "{{ user1 }}", chpass: 'redhat@2022' } - { name: '{{ user2 }}', chpass: 'redhat' }
#循环列表注册变量 - shell: "echo {{ item }}" loop: - "one" - "two" register: echo "changed": true, "msg": "All items completed", "results": [ "changed": true, "cmd": "echo \"one\" ", "delta": "0:00:00.003110", "end": "2013-12-19 12:00:05.187153", "invocation": { "module_args": "echo \"one\"", "module_name": "shell" "item": "one", "rc": 0, "start": "2013-12-19 12:00:05.184043", "stderr": "", "stdout": "one" "changed": true, "cmd": "echo \"two\" ", "delta": "0:00:00.002920", "end": "2013-12-19 12:00:05.245502", "invocation": { "module_args": "echo \"two\"", "module_name": "shell" "item": "two", "rc": 0, "start": "2013-12-19 12:00:05.242582", "stderr": "", "stdout": "two" #通过已注册变量进行后续循环以检查结果可能如下所示 - name: Fail if return code is not 0 fail: msg: "The command ({{ item.cmd }}) did not have a 0 return code" when: item.rc != 0 loop: "{{ echo.results }}"
Playbook中的循环控制:
loop_control组件
- 管理循环任务的限制输出,等待,引用外部循环等;
- 该组件为2.1版本的功能
label标签
:限制最终输出内容,只显示需要的值##增加label标签限制输出值 #未增加时yaml #!/usr/bin/ansible-playbook # This is ansible-playbook files # purpose: Changing User Passwords in Batches - hosts: webservs remote_user: root gather_facts: yes tasks: - name: change user password user: user={{ item.name }} password={{ item.chpass | password_hash('sha512') }} update_password=always loop: - { name: 'mysql', chpass: 'redhat@2022' } - { name: 'xiang', chpass: 'redhat' } # loop_control: # label: "{{ item.name }}" #为增加时的回显 [root@Ansible-Master Date16:03]#ansible-playbook -C loop_test-8.yml PLAY [webservs] ********************************************************************************************************************************************************************************************************** TASK [Gathering Facts] *************************************************************************************************************************************************************************************************** ok: [192.168.213.123] ok: [192.168.213.122] TASK [change user password] ********************************************************************************************************************************************************************************************** changed: [192.168.213.123] => (item={u'chpass': u'redhat@2022', u'name': u'mysql'}) changed: [192.168.213.122] => (item={u'chpass': u'redhat@2022', u'name': u'mysql'}) changed: [192.168.213.122] => (item={u'chpass': u'redhat', u'name': u'xiang'}) changed: [192.168.213.123] => (item={u'chpass': u'redhat', u'name': u'xiang'}) PLAY RECAP *************************************************************************************************************************************************************************************************************** 192.168.213.122 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 192.168.213.123 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 #增加label后的回显 sed -ri "/^#.*loop|label/s/#//" loop_test-8.yml [root@Ansible-Master Date16:18]#ansible-playbook -C loop_test-8.yml PLAY [webservs] ********************************************************************************************************************************************************************************************************** TASK [Gathering Facts] *************************************************************************************************************************************************************************************************** ok: [192.168.213.123] ok: [192.168.213.122] TASK [change user password] ********************************************************************************************************************************************************************************************** changed: [192.168.213.123] => (item=mysql) changed: [192.168.213.122] => (item=mysql) changed: [192.168.213.122] => (item=xiang) changed: [192.168.213.123] => (item=xiang) PLAY RECAP *************************************************************************************************************************************************************************************************************** 192.168.213.122 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 192.168.213.123 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
pause:循环内执行间隔
#!/usr/bin/ansible-playbook # This is ansible-playbook files # purpose: Changing User Passwords in Batches - hosts: webservs remote_user: root gather_facts: yes tasks: - name: change user password user: user={{ item.name }} password={{ item.chpass | password_hash('sha512') }} update_password=always loop: - { name: 'mysql', chpass: 'redhat@2022' } - { name: 'xiang', chpass: 'redhat' } loop_control: pause: 3 #默认单位为秒,每次执行完一次循环后等待3秒
index_var:循环进度追踪
- 要跟踪您在循环中的位置,请将该指令与 结合使用。此指令指定一个变量名称以包含当前循环索引(即变量计数)
#playbook组件 - hosts: webservs tasks: - name: count our fruit debug: msg: "{{ item }} with index {{ my_idx }}" loop: - apple - banana - pear loop_control: index_var: my_idx PLAY [webservs] ********************************************************************************************************************************************************************************************************** TASK [Gathering Facts] *************************************************************************************************************************************************************************************************** ok: [192.168.213.123] ok: [192.168.213.122] TASK [count our fruit] *************************************************************************************************************************************************************************************************** ok: [192.168.213.122] => (item=apple) => { "msg": "apple with index 0" ok: [192.168.213.122] => (item=banana) => { "msg": "banana with index 1" ok: [192.168.213.122] => (item=pear) => { "msg": "pear with index 2" ok: [192.168.213.123] => (item=apple) => { "msg": "apple with index 0" ok: [192.168.213.123] => (item=banana) => { "msg": "banana with index 1" ok: [192.168.213.123] => (item=pear) => { "msg": "pear with index 2"
内嵌循环执行:
loop_var
#playbook内容 [root@Ansible-Master Date17:00]#cat loop_test-10.yml - hosts: 192.168.213.122 remote_user: root gather_facts: no tasks: - include_tasks: inner.yml #引用外部任务 loop: loop_control: loop_var: outer_item [root@Ansible-Master Date17:00]#cat inner.yml - debug: msg: "outer item={{ outer_item }} inner item={{ item }}" loop: [root@Ansible-Master Date16:59]#ansible-playbook -C loop_test-10.yml PLAY [192.168.213.122] *************************************************************************************************************************************************************************************************** TASK [include_tasks] ***************************************************************************************************************************************************************************************************** included: /root/Date/inner.yml for 192.168.213.122 included: /root/Date/inner.yml for 192.168.213.122 included: /root/Date/inner.yml for 192.168.213.122 TASK [debug] ************************************************************************************************************************************************************************************************************* ok: [192.168.213.122] => (item=a) => { "msg": "outer item=1 inner item=a" ok: [192.168.213.122] => (item=b) => { "msg": "outer item=1 inner item=b" ok: [192.168.213.122] => (item=c) => { "msg": "outer item=1 inner item=c" TASK [debug] ************************************************************************************************************************************************************************************************************* ok: [192.168.213.122] => (item=a) => { "msg": "outer item=2 inner item=a" ok: [192.168.213.122] => (item=b) => { "msg": "outer item=2 inner item=b" ok: [192.168.213.122] => (item=c) => { "msg": "outer item=2 inner item=c" TASK [debug] ************************************************************************************************************************************************************************************************************* ok: [192.168.213.122] => (item=a) => { "msg": "outer item=3 inner item=a" ok: [192.168.213.122] => (item=b) => { "msg": "outer item=3 inner item=b" ok: [192.168.213.122] => (item=c) => { "msg": "outer item=3 inner item=c" PLAY RECAP *************************************************************************************************************************************************************************************************************** 192.168.213.122 : ok=6 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Playbook中的循环:
until循环
- 主要用于tasks的重试,直到满足某个条件后执行,是1.4版本得新功能;
- until为false时才会执行循环,为true则退出循环;
- until默认重试次数值为3次、即reteries: 3 ,延迟默认为5秒、即delay: 5
- 当您运行任务并将结果注册为变量时,注册的变量将包含一个名为“trys”的键,该键记录任务的重试次数
- 查看单个重试结果需ansible-playbook -vv
- hosts: localhost gather_facts: false tasks: - debug: msg="until" until: false retries: 3 #默认值即为3次 delay: 1 #一秒间隔
Playbook逐行处理:
with_lines
- 将输出的结果逐行显示
- 和with_items使用同一个变量item
- hosts: localhost tasks: - debug: msg={{ item }} with_lines: ls -l /var #默认输出值到了item变量
#批量创建用户 #!/usr/bin/ansible-playbook #This is playbook file - hosts: webservs remote_user: root gather_facts: yes tasks: - name: add several users user: name={{ item[0] }} state=present group{{ item[1] }} with_lines: - cat /root/username_list.txt - {while}
Playbook中的判断:
when
- when语句可以实现条件测试。如果需要根据变量、facts或此前任务的执行结果来做为某task执行与否 的前提时要用到条件测试,通过在task后添加when子句即可使用条件测试,jinja2的语法格式
#!/usr/bin/ansible-playbook # This is ansible-playbook files # purpose: shutdown the RedHat system - hsots: webservs remote_user: root gather_facts: yes tags: redhat tasks: - name: shutdown system command: /bin/shutdonw -h now when: ansible_os_family == "RedHat" # purpose: install sl package the Debian - hosts: dbservs remote_user: root gather_facts: yes tags: debian tasks: - name: install sl apt: name=sl state=present whne: ansible_os_family == "Debian"
#条件分组 - hsots: webservs remote_user: root gather_facts: yes tags: redhat tasks: - name: shutdown system command: /bin/shutdonw -h now when: (ansible_facts['distribution'] == "CentOS" and ansible_facts['distribution_major_version'] == "6") or (ansible_facts['distribution'] == "Debian" and ansible_facts['distribution_major_version'] == "7") #也可以写成列表的形式(逻辑为and) #!/usr/bin/ansible-playbook # This is ansible-playbook files # purpose: Checking the System Version is Centos 7 exec reboot - hosts: webservs remote_user: root gather_facts: yes tasks: - name: reboot Centos 7 command: /sbin/reboot when: - ansible_facts['distribution'] == "CentOS" - ansible_facts['distribution_major_version'] == "7"
#!/usr/bin/ansible-playbook # This is ansible-playbook files # purpose: Check whether the service is started - hosts: webservs remote_user: root gather_facts: yes tasks: - name: check nginx service conmand: systemctl is-active nginx ignore_errors: yes #忽略错误 register: check_nginx #注册变量 - name: Service nginx started service: name=nginx state=started when: check_nginx.rc == 0 #判断conmand任务是否执行成功
#在循环中使用判断 #!/usr/bin/ansible-playbook # This is ansible-playbook files # purpose: Prints a value greater than 3 - hosts: localhost remote_user: root gather_facts: yes tasks: - command: echo {{ item }} loop: - [1,2,3,4,5] when: item > 3
#判断执行状态 #!/usr/bin/ansible-playbook # This is ansible-playbook files # purpose: Determine execution status - hosts: localhost remote_user: root gather_facts: yes tasks: - name: export true command: /bin/true register: result ignore_errors: true - debug: msg="failed" when: result is failed - debug: msg="succeeded" when: result is succeeded - debug: msg="skipped" when: result is skipped
#字符串变量运算判断 #!/usr/bin/ansible-playbook # This is ansible-playbook files - hosts: 192.168.213.122 remote_user: root gather_facts: yes tasks: - shell: echo "only on Red Hat 6, derivatives, and later" when: ansible_facts['os_family'] == "RedHat" and ansible_facts['lsb']['major_release']|int >= 6
#使用default 筛选器来提供空迭代器,若列表为空则skipping - hosts: 192.168.213.122 tasks: - shell: echo {{ item }} >> /root/Test.txt loop: "{{ [ 0,1,2,3,4,5,6,7,8 ]|default([]) }}" when: item > 5
#在循环中使用字典 - command: echo {{ item.key }} loop: "{{ query('dict', mydict|default({})) }}" when: item.value > 5 - hosts: 192.168.213.122 tasks: - shell: echo {{ item.key }} >> /root/Test.txt loop: "{{ query('dict', { 'file': 7 }|default({})) }}" when: item.value > 5
failed_when
- File_when与when一样可以实现条件测试,但功能相反,当满足file_when条件时将tasks任务状态设置为失败;一般可以在playbook中实现剧本中断的效果;
#!/usr/bin/ansible-playbook # This is ansible-playbook files # purpose: Test failed_when - hosts: localhost remote_user: root gather_facts: yes tasks: - command: echo failed register: result failed_when: "'failed' in result.stdout" #failed_when: false 不满足条件,任务正常执行 #failed_when: true 满足条件,使用任务失败 - debug: msg="echo failed_when"
#!/usr/bin/ansible-playbook # This is ansible-playbook files # purpose: Test failed_when - hosts: localhost remote_user: root gather_facts: yes vars: - web: httpd tasks: - name: Checking service Status command: systemctl is-active {{ web }} register: web_Status failed_when: web_Status.rc != 0 - name: rc=0,restarted {{ web }} service: name={{ web }} state=restarted
changed_when
关闭changed状态:
当确定某个task不会对被控制端做修改时但执行结果却显示是黄色的ahanged状态,可以通过changed_when:false关闭changed状态;
使用changed_when之前 #!/usr/bin/ansible-playbook # This is ansible-playbook files # purpose: Test change_when - hosts: localhost remote_user: root gather_facts: yes tasks: - name: check sshd service shell: ps aux | grep sshd 使用changed_when之后,使用后会取消掉修改的表示(黄色),请确认该操作的确未修改文件: #!/usr/bin/ansible-playbook # This is ansible-playbook files # purpose: Test change_when - hosts: localhost remote_user: root gather_facts: yes tasks: - name: check sshd service shell: ps aux | grep sshd changed_when: false
#!/usr/bin/ansible-playbook # This is ansible-playbook files # purpose: Test change_when - hosts: websrvs remote_user: root tasks: - name: install nginx yum: name=nginx - name: config file template: src="nginx.conf.j2" dest="/etc/nginx/nginx.conf" notify: restart nginx - name: check config shell: /usr/sbin/nginx -t register: check_nginx_config changed_when: - (check_nginx_config.stdout.find('successful')) #如果执行结果中有successful字符串,则继续执行,如果没有则停止向下执行 - false #nginx -t 每次成功执行是changed状态,关闭此changed状态 - name: start service service: name=nginx state=started enabled=yes handlers: - name: restart nginx service: name=nginx state=restarted
Playbook中tasks分组:
block
- 当想在满足一个when条件下,执行多个任务时,既可以将其作为一个block,而不需要写多个when判断;
#!/usr/bin/ansible-playbook # This is ansible-playbook files # purpose: Test Block - hosts: localhost remote_user: root gather_facts: yes tasks: - block: - debug: msg="first" - debug: msg="second" when: - ansible_facts['distribution'] == "CentOS" - ansible_facts['distribution_major_version'] == "7"
Playbook中的滚动执行:
serial
管理节点过多导致的超时问题解决方法:
默认情况下,Ansible将尝试并行管理playbook中的所有主机,对于滚动执行更新用例,可以使用serial关键字
定义Ansible一次应管理多少主机,还可以将serial关键字指定为百分比,表示每次执行的主机占总数的比例;
使用serial前 #!/usr/bin/ansible-playbook # This is ansible-playbook files # purpose: Test serial - hosts: webservs remote_user: root gather_facts: yes tasks: - name: Test task 1 shell: wall "{{ ansible_nodename }} is running task 1" - name: Test task 2 shell: wall "{{ ansible_nodename }} is running task 2" #!/usr/bin/ansible-playbook # This is ansible-playbook files # purpose: Test serial - hosts: webservs remote_user: root gather_facts: yes serial: 1 tasks: - name: Test task 1 shell: wall "{{ ansible_nodename }} is running task 1" - name: Test task 2 shell: wall "{{ ansible_nodename }} is running task 2" Ansible总结Playbook介绍处理流程图playbook 剧本是由一个或多个"play"组成的列表play的主要功能在于将预定义的一组主机,装扮成事先通过ansible中的task定义好的角色。Task实 际是调用ansible的一个module,将多个play组织在一个playbook中,即可以让它们联合起来,按 事先编排的机制执行预定义的动作Playbook 文件是采用YAML语言编写的处理YAML信息信息模型为了最大限度地提高编程语言和实现之间的数据可移植性,YAML
RabbitMQ是实现了高级消息队列协议(AMQP)的开源消息代理软件(亦称面向消息的中间件)。RabbitMQ服务器是用Erlang语言编写的,而集群和故障转移是构建在开放电信平台框架上的。所有主要的编程语言均有与代理接口通讯的客户端库。 ansible 是一款轻量级自动化运维工具,由的 Python 语言开发,结合了多种自动化运维工具的特性,实现了批量系统配置,批量程序部署,批量命令执行等功能; ansible 是基于模块化实现批量操作的。如果要引用ansible plugins 中的 action 或者 module,只需要在tasks 中写入 名称,参数即可。 如果当action 和 module 中出现了重名的文件,ansible 如何选择。 ansible 只会执行 action 中的。 但是,如果代码逻辑不同,需要调用怎么办 在action 中如何调用 module 中的文件。ansible那点事——playbook范例一、playbook范例1、通过register获取返回结果,使用debug多种方式打印回显信息2、playbook搭建mysql主从复制(yum方式)3、playbook初始化centos7系统 一、playbook范例 1、通过register获取返回结果,使用debug多种方式打印回显信息 - hosts: node-2 user: root tasks: - name: test shell command shell: ps -efAnsible 是一个系统自动化工具,可以用来做系统配管理,批量对远程主机执行操作指令。我自己使用 Ansible 也有一段时间了,这里总结了一些使用 Ansible 过程中使用的心得与大家分享。 Ansible...`ansible-playbook` 是 Ansible 中用来执行 Playbook 的命令。Playbook 是一个 YAML 格式的文本文件,其中定义了一组任务,这些任务可以在多台远程主机上执行。使用 `ansible-playbook` 命令可以将 Playbook 中定义的任务自动化地在远程主机上执行。 `ansible-playbook` 命令的基本语法如下: ansible-playbook playbook.yml 其中 `playbook.yml` 是 Playbook 的文件名。执行该命令后,Ansible 会自动读取并执行 Playbook 中定义的任务。在执行过程中,Ansible 会将任务的执行结果输出到终端上,以便用户查看。