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