一文总结Ansible

1.Ansible相关工具

  • /usr/bin/ansible 主程序,临时命令执行工具
  • /usr/bin/ansible-doc 查看配置文档,模块功能查看工具
  • /usr/bin/ansible-galaxy 下载/上传优秀代码或Roles模块的官网平台
  • /usr/bin/ansible-playbook 定制自动化任务,编排剧本工具
  • /usr/bin/ansible-pull 远程执行命令的工具
  • /usr/bin/ansible-vault 文件加密工具
  • /usr/bin/ansible-console 基于Console界面与用户交互的执行工具

批量免密脚本

    #!/bin/bash
    ssh-keygen -f /root/.ssh/id_rsa  -P ''
    NET=192.168.1
    SSHPASS='pwd@20180808'
    for IP in {61..63};do 
        echo $NET.$IP
        sshpass -p $SSHPASS  ssh-copy-id -o StrictHostKeyChecking=no  $NET.$IP 
    done

ansible-doc 显示模块帮助

#列出所有模块
ansible-doc -l  
#查看指定模块帮助用法
ansible-doc ping  
#查看指定模块帮助用法
ansible-doc -s  ping 

ansible-playbook 执行编写好的 playbook 任务

ansible-playbook hello.yml
cat  hello.yml
---
#hello world yml file
- hosts: websrvs
  remote_user: root  
  tasks:
    - name: hello world
      command: /usr/bin/wall hello world

ansible-vault 加密解密yml文件

ansible-vault encrypt hello.yml     #加密
ansible-vault decrypt hello.yml     #解密
ansible-vault view hello.yml        #查看
ansible-vault edit  hello.yml       #编辑加密文件
ansible-vault rekey  hello.yml      #修改口令
ansible-vault create new.yml        #创建新文件

ansible-galaxy 下载相应的roles

#列出所有已安装的galaxy
ansible-galaxy list
#安装galaxy
ansible-galaxy install geerlingguy.mysql
ansible-galaxy install geerlingguy.redis
#删除galaxy
ansible-galaxy remove geerlingguy.redis

ansible-console 可交互执行命令 执行用户@当前操作的主机组 (当前组的主机数量)[f:并发数]$

[root@ansible ~]#ansible-console
Welcome to the ansible console.
Type help or ? to list commands.

root@all (3)[f:5]list
10.0.0.8
10.0.0.7
10.0.0.6
root@all (3)[f:5] cd websrvs
root@websrvs (2)[f:5]list
10.0.0.7
10.0.0.8
root@websrvs (2)[f:5] forks 10
root@websrvs (2)[f:10]cd appsrvs
root@appsrvs (2)[f:5] yum name=httpd state=present
root@appsrvs (2)[f:5]$ service name=httpd state=started

2.模块

ping模块 用来检测主机连通性

[root@master01 ~]# ansible 172.31.194.117 -m ping
/usr/lib/python2.7/site-packages/requests/__init__.py:91: RequestsDependencyWarning: urllib3 (1.25.3) or chardet (2.2.1) doesn't match a supported version!
  RequestsDependencyWarning)
172.31.194.117 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": false, 
    "ping": "pong"
}

command模块 远程主机执行命令,可忽略参数-m,不支持$ < > |&

[root@localhost ~]# ansible es -m command -a 'chdir=/etc cat centos-release'
172.16.0.61 | CHANGED | rc=0 >>
CentOS Linux release 7.6.1810 (Core) 

172.16.0.63 | CHANGED | rc=0 >>
CentOS Linux release 7.6.1810 (Core) 

172.16.0.62 | CHANGED | rc=0 >>
CentOS Linux release 7.6.1810 (Core)
# creates 存在则跳过
[root@localhost ~]# ansible es -m command -a 'chdir=/etc creates=/data/f1.txt cat centos-release'
172.16.0.61 | SUCCESS | rc=0 >>
skipped, since /data/f1.txt exists

172.16.0.62 | CHANGED | rc=0 >>
CentOS Linux release 7.6.1810 (Core) 

172.16.0.63 | CHANGED | rc=0 >>
CentOS Linux release 7.6.1810 (Core)
#removes 不存在则跳过
[root@localhost ~]# ansible es -m command -a 'chdir=/etc removes=/data/f1.txt cat centos-release'
172.16.0.62 | SUCCESS | rc=0 >>
skipped, since /data/f1.txt does not exist

172.16.0.63 | SUCCESS | rc=0 >>
skipped, since /data/f1.txt does not exist

172.16.0.61 | CHANGED | rc=0 >>
CentOS Linux release 7.6.1810 (Core) 

shell模块和command模块类似,支持$ < > | & *

[root@localhost ~]# ansible es -m shell -a 'echo $HOSTNAME'
172.16.0.62 | CHANGED | rc=0 >>
localhost.localdomain

172.16.0.61 | CHANGED | rc=0 >>
localhost.localdomain

172.16.0.63 | CHANGED | rc=0 >>
localhost.localdomain

将shell模块代替command,设为默认模块

 [root@ansible ~]#vim /etc/ansible/ansible.cfg 
 #修改下面一行 
 module_name = shell

Script模块,在远程主机上运行ansible服务器上的脚本(无需执行权限)

 ansible websrvs -m script -a /data/test.sh

Copy 模块,从ansible服务器主控端复制文件到远程主机

src=file 如果是没指明路径,则为当前目录或当前目录下的files目录下的file文件

 #如目标存在,默认覆盖,此处指定先备份 
 ansible websrvs -m copy -a "src=/root/test1.sh dest=/tmp/test2.sh  owner=wang  mode=600 backup=yes" 
 #指定内容,直接生成目标文件 
 ansible websrvs -m copy -a "content='test line1\ntest line2\n'  dest=/tmp/test.txt" 
 #复制/etc目录自身,注意/etc/后面没有/ 
 ansible websrvs -m copy -a "src=/etc dest=/backup"
 #复制/etc/下的文件,不包括/etc/目录自身,注意/etc/后面有/ 
 ansible websrvs -m copy -a "src=/etc/ dest=/backup

Get_url 模块,用于将文件从http、https或ftp下载到被管理机节点上

  • url: 下载文件的URL,支持HTTP,HTTPS或FTP协议
  • dest: 下载到目标路径(绝对路径),如果目标是一个目录,就用服务器上面文件的名称,如果目标设置了 名称就用目标设置的名称
  • owner:指定属主
  • group:指定属组
  • mode:指定权限
  • force: 如果yes,dest不是目录,将每次下载文件,如果内容改变,替换文件。如果否,则只有在目标不存 在时才会下载该文件
  • checksum: 对目标文件在下载后计算摘要,以确保其完整性
  • url_username: 用于HTTP基本认证的用户名。 对于允许空密码的站点,此参数可以不使用 'url_password'
  • url_password: 用于HTTP基本认证的密码。 如果未指定'url_username'参数,则不会使用 `url_password'参数
    validate_certs:如果“no”,SSL证书将不会被验证。 适用于自签名证书在私有网站上使用
  • timeout: URL请求的超时时间,秒为单位
 [root@ansible ~]#ansible websrvs -m get_url -a  'url=http://nginx.org/download/nginx-1.18.0.tar.gz  dest=/usr/local/src/nginx.tar.gz  checksum="md5:b2d33d24d89b8b1f87ff5d251aa27eb8"'

File 模块, 设置文件属性,创建软链接等

 #创建空文件 
 ansible all -m file -a 'path=/data/test.txt state=touch'
 ansible all -m file -a 'path=/data/test.txt state=absent' 
 ansible all -m file -a "path=/root/test.sh owner=wang mode=755"
 #创建目录 
 ansible all -m file -a "path=/data/mysql state=directory owner=mysql  group=mysql" 
 #创建软链接 ansible all -m file -a 'src=/data/testfile path|dest|name=/data/testfile-link  state=link' 
 #创建目录
 ansible all -m file -a 'path=/data/testdir state=directory'
 #递归修改目录属性,但不递归至子目录
 ansible all -m file -a "path=/data/mysql state=directory owner=mysql  group=mysql" 
 #递归修改目录及子目录的属性 
 ansible all -m file -a "path=/data/mysql state=directory owner=mysql group=mysql  recurse=yes"

unarchive 模块,解压缩

  • copy:默认为yes,当copy=yes,拷贝的文件是从ansible主机复制到远程主机上,如果设置为 copy=no,会在远程主机上寻找src源文件
  • remote_src:和copy功能一样且互斥,yes表示在远程主机,不在ansible主机,no表示文件在ansible 主机上
  • src:源路径,可以是ansible主机上的路径,也可以是远程主机(被管理端或者第三方主机)上的路径,如果 是远程主机上的路径,则需要设置copy=no
  • dest:远程主机上的目标路径
  • mode:设置解压缩后的文件权限
 ansible all -m unarchive -a 'src=/data/foo.tgz dest=/var/lib/foo owner=wang  group=bin' 
 ansible all -m unarchive -a 'src=/tmp/foo.zip dest=/data copy=no mode=0777' 
 ansible all -m unarchive -a 'src=https://example.com/example.zip dest=/data  copy=no' 
 ansible websrvs -m unarchive -a 'src=https://releases.ansible.com/ansible/ansible-2.1.6.0-0.1.rc1.tar.gz  dest=/data/  owner=root remote_src=yes' 
 ansible websrvs -m unarchive -a 'src=http://nginx.org/download/nginx- 1.18.0.tar.gz dest=/usr/local/src/ copy=no'

Archive 模块, 打包压缩保存在被管理节点

 ansible websrvs -m archive -a 'path=/var/log/ dest=/data/log.tar.bz2 format=bz2  owner=wang mode=0600'

Hostname 模块, 管理主机名

ansible node1 -m hostname -a "name=websrv" 
ansible 10.0.0.18 -m hostname -a 'name=node18.test.com'

Cron 模块,计划任务

 #备份数据库
 [root@centos8 ~]#cat /root/mysql_backup.sh  
 #!/bin/bash 
 mysqldump -A -F --single-transaction --master-data=2 -q -uroot |gzip >  /data/mysql_`date +%F_%T`.sql.gz 
 
 #创建任务 
 ansible 10.0.0.8 -m cron -a 'hour=2 minute=30 weekday=1-5 name="backup mysql"  job=/root/mysql_backup.sh' 
 ansible websrvs  -m cron -a "minute=*/5 job='/usr/sbin/ntpdate ntp.aliyun.com  &>/dev/null' name=Synctime" 
 #禁用计划任务 
 ansible websrvs  -m cron -a "minute=*/5 job='/usr/sbin/ntpdate 172.20.0.1  &>/dev/null' name=Synctime disabled=yes" 
 #启用计划任务 
 ansible websrvs  -m cron -a "minute=*/5 job='/usr/sbin/ntpdate 172.20.0.1  &>/dev/null' name=Synctime disabled=no" 
 #删除任务 
 ansible websrvs -m cron -a "name='backup mysql' state=absent"
 ansible websrvs -m cron -a 'state=absent name=Synctime'

Yum 和 Apt 模块

 ansible websrvs -m yum -a 'name=httpd state=present' #安装 
 ansible websrvs -m yum -a 'name=nginx state=present enablerepo=epel' #启用epel源 进行安装
 ansible websrvs -m yum -a 'name=* state=lastest exclude=kernel*,foo*' #升级除 kernel和foo开头以外的所有包
 ansible websrvs -m yum -a 'name=httpd state=absent'
 [root@ansible ~]#ansible websrvs -m yum -a  "name=https://mirror.tuna.tsinghua.edu.cn/zabbix/zabbix/5.2/rhel/7/x86_64/zabbix -agent-5.2.5-1.el7.x86_64.rpm"
  [root@ansible ~]#ansible localhost -m yum -a "list=tree" #查看包

yum_repository 模块

创建和删除仓库

 [root@ansible ~]#cat yum_repo.yml 
 - hosts: websrvs
   tasks:
     - name: Add multiple repositories into the same file
       yum_repository:
         name: test
         description: EPEL YUM repo
         file: external_repos
         baseurl:  https://download.fedoraproject.org/pub/epel/$releasever/$basearch/
         gpgcheck: no
#创建
[root@ansible ~]#ansible-playbook yum_repo.yml 
[root@web1 ~]#cat /etc/yum.repos.d/external_repos.repo  
[test] 
baseurl = https://download.fedoraproject.org/pub/epel/$releasever/$basearch/ 
gpgcheck = 0 
name = EPEL YUM repo 
#删除
[root@ansible ~]#cat remove_yum_repo.yml 
- hosts: websrvs  
  tasks:
  - name: remove repo
    yum_repository:  
      name: test
      file: external_repos
      state: absent
[root@ansible ~]#ansible-playbook remove_yum_repo.yml

Service 模块

 ansible all -m service -a 'name=httpd state=started enabled=yes' #启动并开机启动
 ansible all -m service -a 'name=httpd state=stopped' 
 ansible all -m service -a 'name=httpd state=reloaded' 
 ansible all -m shell -a "sed -i 's/^Listen 80/Listen 8080/'  /etc/httpd/conf/httpd.conf" #修改httpd配置
 ansible all -m service -a 'name=httpd state=restarted'

Group 模块

 #创建组 
 ansible websrvs -m group -a 'name=nginx gid=88 system=yes' 
 #删除组 
 ansible websrvs -m group -a 'name=nginx state=absent'

User 模块

 #创建用户 
 ansible all -m user -a 'name=user1 comment="test user" uid=2048 home=/app/user1  group=root' 
 ansible all -m user -a 'name=nginx comment=nginx uid=88 group=nginx  groups="root,daemon" shell=/sbin/nologin system=yes create_home=no  home=/data/nginx non_unique=yes'
 #remove=yes表示删除用户及家目录等数据,默认remove=no 
 ansible all -m user -a 'name=nginx state=absent remove=yes'

Lineinfile 模块

ansible在使用sed进行替换时,经常会遇到需要转义的问题,而且ansible在遇到特殊符号进行替换时, 存在问题,无法正常进行替换 。其实在ansible自身提供了两个模块:lineinfile模块和replace模块,可以方便的进行替换

regexp参数 :使用正则表达式匹配对应的行,当替换文本时,如果有多行文本都能被匹配,则只有最 后面被匹配到的那行文本才会被替换,当删除文本时,如果有多行文本都能被匹配,这么这些行都会被 删除。

 ansible websrvs -m lineinfile -a "path=/etc/httpd/conf/httpd.conf  regexp='^Listen' line='Listen 80'" 
 ansible all -m  lineinfile -a "path=/etc/selinux/config regexp='^SELINUX='  line='SELINUX=disabled'" 
 ansible all -m lineinfile -a 'dest=/etc/fstab state=absent regexp="^#"'

Replace 模块

 ansible all -m replace -a "path=/etc/fstab regexp='^(UUID.*)' replace='#\1'"
 ansible all -m replace -a "path=/etc/fstab regexp='^#(UUID.*)' replace='\1'"

Setup 模块

setup 模块来收集主机的系统信息,这些 facts 信息可以直接以变量的形式使用,但是如果主机 较多,会影响执行速度, 可以使用 gather_facts: no 来禁止 Ansible 收集 facts 信息

  ansible all -m setup 
  ansible all -m setup -a "filter=ansible_nodename" 
  ansible all -m setup -a "filter=ansible_hostname" 
  ansible all -m setup -a "filter=ansible_domain" 
  ansible all -m setup -a "filter=ansible_memtotal_mb" 
  ansible all -m setup -a "filter=ansible_memory_mb" 
  ansible all -m setup -a "filter=ansible_memfree_mb" 
  ansible all -m setup -a "filter=ansible_os_family" 
  ansible all -m setup -a "filter=ansible_distribution_major_version" 
  ansible all -m setup -a "filter=ansible_distribution_version"
  ansible all -m setup -a "filter=ansible_processor_vcpus" 
  ansible all -m setup -a "filter=ansible_all_ipv4_addresses"
  ansible all -m setup -a "filter=ansible_architecture" 
  ansible all -m setup -a "filter=ansible_uptime_seconds" 
  ansible all -m setup -a "filter=ansible_processor*" 
  ansible all -m setup -a 'filter=ansible_env'
   #取所有IP 
   ansible 10.0.0.101 -m setup -a 'filter=ansible_all_ipv4_addresses
   #取默认IP 
   ansible all -m setup -a 'filter="ansible_default_ipv4"'

3.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: magedu
           sudo: yes #默认sudo为root
           sudo_user:wang #sudo为wang
task列表和action组件

play的主体部分是task list,task list中有一个或多个task,各个task 按次序逐个在hosts中指定的所有主机上执行,即在所有主机上完成第一个task后,再开始第二个task。
task的目的是使用指定的参数执行模块,而在模块参数中可以使用变量。模块执行是幂等的,这意味着多次执行是安全的,因为其结果均一致 每个task都应该有其name,用于playbook的执行结果输出,建议其内容能清晰地描述任务执行步骤。 如果未提供name,则action的结果将用于输出

 --- 
 # first yaml file  
 - hosts: websrvs  
   remote_user: root  
   gather_facts: no  #不收集系统信息,提高执行效率  
   tasks: 
     - name: test network connection  
       ping:  
     - name: excute command  
       command: wall "hello world!"
--- 
- 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
ShellScripts VS Playbook
 #SHELL脚本实现 
 #!/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实现 
 --- 
 - 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 命令 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为任务的 name 
 -v -vv -vvv       #显示过程
 ansible-playbook file.yml --check     #只检测 
 ansible-playbook file.yml --limit websrvs

利用 playbook 创建 mysql 用户

 --- 
 # install nginx  
 - hosts: websrvs  
   remote_user: root
   gather_facts: no  
   
   tasks:
     - name: add group nginx  
       group: name=nginx state=present
     - name: add user nginx 
       user: name=nginx state=present group=nginx 
     - name: Install Nginx  
       yum: name=nginx state=present
     - name: web page  
       copy: src=files/index.html dest=/usr/share/nginx/html/index.html 
     - name: Start Nginx  
       service: name=nginx state=started enabled=yes

利用 playbook 安装nginx

 --- 
 - hosts: dbsrvs  
   remote_user: root  
   gather_facts: no 
   
   tasks:  
     - name: add group nginx
       group: name=nginx state=present  
     - name: add user nginx
       user: name=nginx state=present group=nginx
     - name: Install Nginx 
       yum: name=nginx state=present
     - name: web page 
       copy: src=files/index.html dest=/usr/share/nginx/html/index.html  
     - name: Start Nginx
       service: name=nginx state=started enabled=yes

利用 playbook 安装和卸载 httpd

安装

--- 
- hosts: dbsrvs  
  remote_user: root  
  gather_facts: no 
  
  tasks: 
    - name: Instal1 httpd
      yum: name=httpd
    - name: Modify config list port
      lineinfile:
        path: /etc/httpd/conf/httpd.conf
        regexp: '^Listen'
        line: 'Listen 8080'  
    - name: Modify config data1 
      lineinfile:  
        path: /etc/httpd/conf/httpd.conf
        regexp: '^DocumentRoot "/var/www/html"'
        line: 'DocumentRoot "/data/html"'
    - name: Modify config data2
      lineinfile: 
        path: /etc/httpd/conf/httpd.conf
        regexp: '^<Directory "/var/www/html">'
        line: '<Directory "/data/html">'
    - name: Mkdir website dir
      file: path=/data/html state=directory
    - name: Web html
      copy: src=files/index.html dest=/data/html/
    - name: Start service
      service: name=httpd state=started enabled=yes

卸载

--- 
- hosts: dbsrvs  
  remote_user: root  
  gather_facts: no 
  
  tasks: 
    - name: remove httpd package 
      yum: name=httpd state=absent
    - name: remove apache user
      user: name=apache state=absent
    - name: remove config file
      file: name=/etc/httpd state=absent
    - name: remove web html
      file: name=/data/html/ state=absent

利用 playbook 安装二进制的 MySQL 5.6

/data/ansible/files/my.cnf

  [mysqld] 
  socket=/tmp/mysql.sock
  user=mysql
  symbolic-links=0
  datadir=/data/mysql
  innodb_file_per_table=1
  log-bin
  pid-file=/data/mysql/mysqld.pid
  
  [client]
  port=3306
  socket=/tmp/mysql.sock
  
  [mysqld_safe]
  log-error=/var/log/mysqld.log
/data/ansible/files/secure_mysql.sh
 #!/bin/bash 
 /usr/local/mysql/bin/mysql_secure_installation <<EOF
 y 
 magedu 
 magedu 
 y
 y
 y
 y 
 EOF

/data/ansible/install_mysql.yml

---
- hosts: dbsrvs  
  remote_user: root  
  gather_facts: no 
  
  tasks: 
    - name: install packages
      yum: name=libaio,perl-Data-Dumper,perl-Getopt-Long
    - name: create mysql group
      group: name=mysql gid=306
    - name: create mysql user
      user: name=mysql uid=306 group=mysql shell=/sbin/nologin system=yes create_home=no home=/data/mysql
    - name: copy tar to remote host and file mode
      unarchive: src=/data/ansible/files/mysql-5.6.46-linux-glibc2.12- x86_64.tar.gz dest=/usr/local/ owner=root group=root
    - name: create linkfile /usr/local/mysql
      file: src=/usr/local/mysql-5.6.46-linux-glibc2.12-x86_64  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/secure_mysql.sh 
      tags: script

忽略错误 ignore_errors

如果一个task出错,默认将不会继续执行后续的其它task 利用 ignore_errors: yes可以忽略此task的错误,继续向下执行playbook其它task

---
- hosts: dbsrvs  
  remote_user: root  
  gather_facts: no 
  
  tasks: 
    - name: error
      command: /bin/false
      ignore_errors: yes  
    - name: continue
      command: wall continue

handlers和notify

的触发器触发的行为,其中的task与前述的task并没有本质 上的不同,主要用于当关注的资源发生变化时,才会采取一定的操作。而Notify对应的action可用于在每个play的最后被触发,这样可避免多次有改变发生时每次都执行指定的操作,仅在所有的变化发生完成后一次性地执行指定操作。

  • 如果多个task通知了相同的handlers, 此handlers仅会在所有tasks结束后运行一 次。
  • 只有notify对应的task发生改变了才会通知handlers, 没有改变则不会触发handlers
  • handlers 是在所有前面的tasks都成功执行才会执行,如果前面任何一个task失败,会导致handler跳过执行,可以使用force_handlers: yes 强制执行handler
#修改配置后重启服务并邮件通知root
---
- hosts: dbsrvs  
  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/ 
      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"

---
#修改配置后重启nginx并检查存活性
- hosts: dbsrvs  
  remote_user: root  
  gather_facts: no 
  
  tasks: 
    - name: add group nginx
      user: name=nginx state=present
    - name: add user nginx
      user: name=nginx state=present group=nginx
    - name: Install Nginx 
      yum: name=nginx state=present
    - name: config 
      copy: src=/root/config.txt dest=/etc/nginx/nginx.conf
      notify: 
        - Restart Nginx
        - Check Nginx Process
  
  handlers: 
    - name: Restart Nginx 
      service: name=nginx state=restarted enabled=yes 
    - name: Check Nginx process
      shell: killall -0 nginx &> /tmp/nginx.log
---
# 利用 force_handlers 实现强制执行handler
- hosts: dbsrvs  
  remote_user: root  
  gather_facts: no 
  
  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

tags组件

利用tags组件,为特定task指定标签,当在执行playbook时,可以只执行特定tags的task,而非整个playbook文件

 ---
 - hosts: dbsrvs  
   remote_user: root  
   gather_facts: no 
   
   tasks: 
     - name: install http
       yum: name=httpd state=present
     - name: Install configure file
       copy: src=files/httpd.conf dest=/etc/httpd/conf/
       tags: [ conf,file ] #写在一行 
         - conf   #写成多行
         - file
     - name: start httpd service
       tags: service
       service: name=httpd state=started enabled=yes
 [root@ansible ~]#ansible-playbook –-list-tags httpd.yml
 [root@ansible ~]#ansible-playbook –t conf,service httpd.yml
 [root@ansible ~]#ansible-playbook --skip-tags conf httpd.yml
 [root@ansible ~]#ansible-playbook  httpd.yml --skip-tags untagged

Playbook中使用变量

变量定义:

 variable=value 
 variable: value

变量调用方式:

通过 {{ variable_name }}调用变量,且变量名前后建议加空格,有时用"{{ variable_name }}"才生效

  • ansible 的 setup facts 远程主机的所有变量都可直接调用
  • 通过命令行指定变量,优先级最高
    ansible-playbook -e varname=value test.yml
  • 在playbook文件中定义
 vars:  
   var1: value1  
   var2: value2
  • 在独立的变量YAML文件中定义
  • 在主机清单文件中定义
  • 在项目中针对主机和主机组定义( host_vars和group_vars目录)
  • role
使用 setup 模块中变量

查询

 [root@centos8 ~]#ansible 10.0.0.8 -m setup -a
 "filter=ansible_nodename" 10.0.0.8 | SUCCESS => {
    "ansible_facts": {  
        "ansible_nodename": "centos8.magedu.org",  
        "discovered_interpreter_python": "/usr/libexec/platform-python" 
    }, 
    "changed": false 
 }

var1.yml

 ---
 - hosts: dbsrvs  
   remote_user: root  
   gather_facts: yes 
   
   tasks:
     - name: create log file  
       file: name=/data/{{ ansible_nodename }}.log state=touch owner=wang  mode=600

显示 eth0 网卡的 IP 地址

  - hosts: websrvs 
  tasks: 
    - name: show eth0 ip address {{ ansible_facts["eth0"]["ipv4"]["address"] }}
    debug: 
      msg: IP address {{ ansible_eth0.ipv4.address }}  
      #msg: IP address {{ ansible_facts["eth0"]["ipv4"]["address"] }}
      #msg: IP address {{ ansible_facts.eth0.ipv4.address }}
      #msg: IP address {{ ansible_default_ipv4.address }}
      #msg: IP address {{ ansible_eth0.ipv4.address }}
      #msg: IP address {{ ansible_eth0.ipv4.address.split('.')[-1] }} #取IP中 的最后一个数字
在playbook 命令行中定义变量
  --- 
  - hosts: websrvs  
  remote_user: root  
  tasks: 
    - name: install package 
      yum: name={{ pkname }} state=present
      
[root@ansible ~]#ansible-playbook –e pkname=httpd var2.yml

也可以将多个变量放在一个文件中

 [root@ansible ~]#cat vars 
 pkname1: memcached 
 pkname2: vsftpd
 --- 
 - hosts: websrvs  
 remote_user: root  
 tasks:  
   - name: install package  
     yum: name={{ pkname1 }} state=present  
   - name: install package  
     yum: name={{ pkname2 }} state=present  

[root@ansible ~]#ansible-playbook -e '@vars' var2.yml

playbook文件中定义变量
  ---
  - hosts: websrvs
    remote_user: root
    vars:  
      collect_info: "/data/test/{{ansible_default_ipv4['address']}}/"  
      
    tasks:  
      - name: create IP directory
      file: name="{{collect_info}}" state=directory

执行结果

 tree
 /data/test/ /data/test/ 
 └── 10.0.0.102 
 1 directory, 0 files

register 注册变量

debug模块

- hosts: websrvs  
  remote_user: root  
  tasks:
    - shell: echo hello world
      register: say_hi 
    - shell: "awk -F: 'NR==1{print $1}' /etc/passwd"
      rengister: user
    - debug: var=user.stdout
    - debug: var=say_hi.stdout

使用register将捕获命令的输出保存在临时变量中,然后使用debug模块进行显示输出

- hosts: websrvs  
 remote_user: root  
 tasks: 
   - name: get variable
     shell: hostname
     register: name
   - name: "print variable" 
     debug:  
       msg: "{{ name }}" 
 #说明 第一个 task 中,使用了 register 注册变量名为 name ;当 shell 模块执行完毕后,会将数据放到 该变量中。 
 #第二给 task 中,使用了 debug 模块,并从变量name中获取数据。

使用 register 注册变量创建文件

- hosts: websrvs  

 tasks: 
    - name: get variable
      shell: hostname
      register: name
    - name: create file
      file: dest=/tmp/{{ name.stdout }}.log state=touch

template 模板

template 模板
[root@localhost nginx]# tree
.
├── nginx.yml
└── templates
    └── nginx.conf.j2
---
- hosts: websrvs
  remote_user: root

  tasks:
    - name: Add multiple repositories into the same file
      yum_repository:
        name: test
        description: EPEL YUM repo
        file: external_repos
        baseurl: https://mirrors.aliyun.com/epel/$releasever\Server/$basearch/
        gpgcheck: no
    - name: install nginx
      yum:
        name: nginx
    - name: config to remote hosts
      template:
        src: nginx.conf.j2
        dest: /etc/nginx/nginx.conf
    - name: start service
      service:
        name: nginx
        state: restarted
        enabled: yes
worker_processes {{ansible_processor_vcpus}};
……
[root@localhost nginx]# ansible-playbook  nginx.yml
PLAY [websrvs] **************************************************************************************

TASK [Gathering Facts] ******************************************************************************
ok: [172.16.0.61]

TASK [Add multiple repositories into the same file] *************************************************

TASK [install nginx] ********************************************************************************
changed: [172.16.0.61
TASK [config to remote hosts] ***********************************************************************
changed: [172.16.0.61]

TASK [start service] ********************************************************************************
changed: [172.16.0.61]

PLAY RECAP ******************************************************************************************
172.16.0.61                : ok=5    changed=2    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

template中使用流程控制 for 和 if

---
- hosts: websrvs
  remote_user: root
  vars:
    nginx_vhosts:
      - 81
      - 82
      - 83

  tasks:
    - name: Add multiple repositories into the same file
      yum_repository:
        name: test
        description: EPEL YUM repo
        file: external_repos
        baseurl: https://mirrors.aliyun.com/epel/$releasever\Server/$basearch/
        gpgcheck: no
    - name: install nginx
      yum:
        name: nginx
    - name: config to remote hosts
      template:
        src: nginx.conf2.j2
        dest: /etc/nginx/nginx.conf
    - name: start service
      service:
        name: nginx
        state: restarted
        enabled: yes

templates/nginx.conf2.j2

worker_processes {{ansible_processor_vcpus}};
……
http {
    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    sendfile            on;
    tcp_nopush          on;
    tcp_nodelay         on;
    keepalive_timeout   65;
    types_hash_max_size 2048;

    include             /etc/nginx/mime.types;
    default_type        application/octet-stream;

    include /etc/nginx/conf.d/*.conf;
  {% for vhost in nginx_vhosts %}
   server {
      listen    {{ vhost }};
   }
  {% endfor %}
}

生成keepalived配置文件

vrrp_instrance VI_1 
{ 
 {% if ansible_fqdn == "ka1" %}  
    state MASTER  priority 100 
 {% elif ansible_fqdn == "ka2" %}  
    state SLAVE  
    priority 80 
 {% endif% } 
 ......
}

使用循环迭代 with_items(loop)

对迭代项的引用,固定内置变量名为"item",要在task中使用with_items给定要迭代的元素列表

注意: ansible2.5版本后,可以用loop代替with_items

---
- hosts: websrvs
  remote_user: root

  tasks:
    - name: Add Server Users
      user: name={{ item }} state=present groups=wheel
      with_items:
        - testuser1
        - testuser2
        - testuser3

安装多个包

---
- hosts: websrvs
  remote_user: root

  tasks:
    - name: install some packages 
      yum: name={{ item }} state=present
      with_items:
        - nginx
        - memcached
        - php-fpm

在迭代中,还可以嵌套子变量,关联多个变量在一起使用

- hosts: websrvs
  remote_user: root
  vars:
    rsyncd_conf: /etc/rsync.conf 
    rsync_pass: /etc/rsync.pass  
    
    tasks:
      - name: Configure Rsyncd Service
        template: src={{ item.src }} dest={{ item.dest }} mode={{ item.mode }}
        with items:
          - {src: './rsyncd.conf.j2', dest: {{ rsyncd_conf }}, mode: 0644 } 
          - {src: './rsync.pass.j2', dest: {{ rsync_pass }}, mode: 0600 }

playbook使用 when

- hosts: websrvs
  remote_user: root
    tasks:
      - name: "shutdown RedHat flavored systems" 
      command: /sbin/shutdown -h now  
      when: ansible_os_family == "RedHat"

判断服务状态决定是否重新启动

- hosts: websrvs
  remote_user: root
    tasks:
      - name: Check nginx  #检查nginx服务是否是活动的
        command: systemctl is-active nginx
        ignore_ errors: yes 
        register: check_nginx 
      - name: Httpd Restart #如果check nginx执行命令结果成功,即check_nginx.rc等于0,则 执行重启nginx,否则跳过  
        service: name=nginx state=restarted
        when: check_nginx.rc == 0

判断执行状态

- hosts: websrvs
  remote_user: root
    tasks:
      - 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

failed_when 满足条件时,使任务失败

- hosts: websrvs
 remote_user: root
   tasks:
     - command: echo faild  
       register: result  
       failed_when: "'faild' in result.stdout"  
       #failed_when: false 不满足条件,任务正常执行  
       #failed_when: true 满足条件,使用任务失败 
     - debug: msg=" echo failed_when"

分组 block

# 一个条件下,执行多个任务
- hosts: all    
 remote_user: root
 tasks:
   - block:
     - debug: msg="first"  
     - debug: msg="second"  
   when:
     - ansible_facts['distribution'] == "CentOS"
     - ansible_facts['distribution_major_version'] == "8"

滚动执行 serial

管理节点过多导致的超时问题解决方法

默认情况下,Ansible将尝试并行管理playbook中所有的机器。对于滚动更新用例,可以使用serial关键 字定义Ansible一次应管理多少主机

- hosts: all    
  remote_user: root
  serial: 2 #每次只同时处理2个主机,将所有task执行完成后,再选下2个主机再执行所有task,直至所 有主机 
  #serial: "20%"  #每次只同时处理20%的主机
  gather_facts: False  
  
  tasks:  
    - name: task one  
      comand: hostname  
    - name: task two  
      command: hostname
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,132评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,802评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,566评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,858评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,867评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,695评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,064评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,705评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,915评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,677评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,796评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,432评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,041评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,992评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,223评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,185评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,535评论 2 343