目录
01.发展
- On-Premises(本地部署):项目从零开始一切都自行负责
- Iaas(基础设施即服务):以电信行业发展为例,2008年联想风头正盛,营业额达到顶峰,硬件收入高(硬件)
- PaaS(平台即服务):之后微软到达顶峰,营业额达到顶峰(操作系统)
- SaaS(软件即服务):现在互联网走到风口,利润不断攀升(软件)
02.灰度发布
环境分类:开发环境(dev)、测试环境(test)、发布环境、生产环境(prod)、灰度环境
- 开发环境:程序员个人的办公电脑或项目的开发测试环境,部署开发软件,测试个人或项目整体的BUG的环境,管理者是程序员;
- 测试环境:测试经过开发环境测试通过的软件的功能和性能,判断是否达到项目的预期目标,生成测试报告,管理者是运维。测试环境往往有多套,测试环境满足测试功能即可,不宜过多。通常测试环境有多少套和产品线数量保持一样
- 预发布环境:使用和生产环境一样的数据库,缓存服务等配置,测试是否正常
- 发布环境:包括代码发布机,有些公司为堡垒机(安全屏障),往往需要有两台(主备)
- 生产环境:少数情况开放权限给核心开发,极少数公司将权限完全开放给开发人员并其运维
- 灰度环境:在全量发布代码前将代码的功能面向少数精准用户发布的环境,可基于主机或用户执行灰度发布。往往该版本功能变更大,为保险起见特意让一部分用户优先体验该功能,待这部分用户使用没有重大问题的时候,再全量发布至所有服务器(灰度发布,也成为金丝雀发布)
案例:共100台生产服务器,先发布其中的10台服务器(将10台服务器下线),这10台服务器就是灰度服务器。然后将这10台服务器更新服务后再上线。这时90台服务提供的是旧服务,另外10台提供的是新服务。若有重大BUG则将10台新服务还原成旧服务,否则则将剩余90台服务逐步10台/次更新。或者基于用户,先优先于付费用户进行更新,没问题后再全部用户更新。
03.程序发布
- 预发布验证:新版本的代码先发布到服务器(跟线上环境配置完全相同,只有未接入到调度器)
- 发布过程:在调度器上下线一批主机(标记为maintanance状态) --> 关闭服务 --> 部署新版本的应用程序 --> 启动服务 --> 在调度器上启用这一批服务器
04.自动运维工具
- Ansible:python便于二次开发,无需代理(SSH),中小型应用环境(300-500服务器,再多性能可能跟不上)
- Saltstack:python便于二次开发,需部署agent(有代理性能和功能更加强大),执行效率高,使用更大应用环境(1000+服务器)
- Puppet:ruby,功能强大,配置复杂,重型,适合大型环境(例如:Google)
05.Ansible工具引入
注意:ansible只能安装在linux上(主控端),但是可以控制windows机器(被控端)
安装:由于内网环境限制,笔者这里使用手动安装配置,操作系统为麒麟操作系统(其步骤大致为先挂载本地yum源,用于安装基本环境,然后手动安装所需模块)
-
首先确保虚拟机已经挂载ios文件,若重新挂载,挂载完成后需要重启虚拟机
-
将iso源挂载到麒麟操作系统并配置指定yum下载源:新建/mnt/cdrom/目录
mkdir /mnt/cdrom/
,之后挂载CDROM[root@server0 yum.repos.d]# mount -o loop /dev/cdrom /mnt/cdrom/
,然后配置yum源 -
安装基本环境:安装gcc
yum install gcc.x86_64
;安装zlibyum install zlib zlib-devel -y
;安装opensslyum install openssl openssl-devel
; -
安装python:python2.7下载地址
# 手动安装python包 tar xvzf Python-2.7.8.tgz cd Python-2.7.8 ./configure --prefix=/usr/local make make install # 将python头文件拷贝到标准目录,以避免编译ansible时,找不到所需的头文件 cd /usr/local/include/python2.7 cp -a ./* /usr/local/include/ ## 备份旧版本的python,并符号链接新版本的python cd /usr/local/bin mv python python.old ln -s /usr/local/bin/python2.7 /usr/local/bin/python rm -f /usr/bin/python && cp /usr/local/bin/python2.7 /usr/bin/python
-
模块安装:由于服务器在内网环境,没法用pip安装,所以需要把python模块从官网上逐个下载下来安装。pycrypto模块地址、setuptools模块地址、yaml模块地址、PyYAML模块地址、MarkupSafe模块地址、Jinja2模块地址、ecdsa模块地址、paramiko模块地址、simplejson模块地址、ansible地址
# pycrypto模块安装 tar xvzf pycrypto-2.6.1.tar.gz cd pycrypto-2.6.1 python setup.py install # setuptools模块安装 tar zxvf setuptools-0.6c11.tar.gz cd setuptools-0.6c11 python setup.py install # PyYAML模块安装 tar xvzf yaml-0.1.5.tar.gz cd yaml-0.1.5 ./configure --prefix=/usr/local make --jobs=`grep processor/proc/cpuinfo | wc -l` make install tar xvzf PyYAML-3.11.tar.gz cd PyYAML-3.11 python setup.py install # Jinja2模块安装 tar xvzf MarkupSafe-0.9.3.tar.gz cd MarkupSafe-0.9.3 python setup.py install tar xvzf Jinja2-2.7.3.tar.gz cd Jinja2-2.7.3 python setup.py install # paramiko模块安装 tar xvzf ecdsa-0.11.tar.gz cd ecdsa-0.11 python setup.py install tar xvzf paramiko-1.15.1.tar.gz cd paramiko-1.15.1 python setup.py install # simplejson模块安装 tar xvzf simplejson-3.6.5.tar.gz cd simplejson-3.6.5 python setup.py install # ansible安装 tar xvzf ansible-1.7.2.tar.gz cd ansible-1.7.2 python setup.py install
-
Ansible配置:安装ansible后发现找不到ansible.cfg,配置文件的路径如下图,并将配置文件拷贝过去
-
默认配置文件位置为/etc/ansible/ansilble.cfg,配置文件位置可以修改。Ansible 按照如下位置和顺序来查找ansible.cfg 文件:
- ANSIBLE_CONFIG 环境变量所指定的文件。
- ./ansible.cfg(当前目录下的ansible.cfg)。
- ~/.ansible.cfg(家目录下的.ansible.cfg)。
- /etc/ansible/ansible.cfg。
-
Ansible配置详解:
配置SSH免密登录:由于ansible使用的登陆方式是ssh,在主机需要配置ssh秘钥对,这样ansible才能正常使用。
# 服务端:192.168.2.121 客户端:192.168.2.250
# 一键生成非交互式秘钥对
ssh-keygen -t rsa -f /root/.ssh/id_rsa -P ""
# 公钥(id_rsa.pub)拷贝到客户端上:
ssh-copy-id -i /root/.ssh/id_rsa.pub root@192.168.2.250
# 本机也要拷贝:
cat /root/.ssh/id_rsa.pub >> /root/.ssh/authorized_keys
chmod 600 /root/.ssh/authorized_keys # 必须是600, 否则用ansible连接本机报错
# 在服务端测试ssh是否可以登录
ssh 192.168.2.250
06.Ansible相关工具介绍
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界面与用户交互的执行工具
ansible-doc:此工具用来显示模块帮助,格式
ansible-doc [options] [module...]
-l, --list #列出可用模块
-s, --snippet #显示指定模块的playbook片段
# 范例
# 列出所有模块
ansible-doc -l
# 查看指定模块帮助用法
ansible-doc ping
# 查看指定模块帮助用法
ansible-doc -s ping
# 模块使用格式
ansible <host-pattern> [-m module_name] [-a args]
# 选项说明
--version #显示版本
-m module #指定模块,默认为command
-v #详细过程 –vv -vvv更详细
--list-hosts #显示主机列表,可简写 --list
-k, --ask-pass #提示输入ssh连接密码,默认Key验证
-C, --check #检查,并不执行
-T, --timeout=TIMEOUT #执行命令的超时时间,默认10s
-u, --user=REMOTE_USER #执行远程执行的用户
-b, --become #代替旧版的sudo 切换
--become-user=USERNAME #指定sudo的runas用户,默认为root
-K, --ask-become-pass #提示输入sudo时的口令
# 范例
ansible all -k -m ping
利用sshpass批量实现基于key验证:Ansible此工具通过ssh协议,实现对远程主机的配置管理、应用部署、任务执行等功能。建议:使用此工具前,先配置ansible主控端能基于密钥认证的方式联系各个被管理节点
# 利用sshpass批量实现基于key验证
#!/bin/bash
ssh-keygen -f /root/.ssh/id_rsa -P ''
NET=192.168.100
export SSHPASS=magedu
for IP in {1..200};do
sshpass -e ssh-copy-id NET.IP
done
# 手动实现原理
[root@9019-kylin ~]# ssh-keygen
[root@9019-kylin ~]# ssh-copy-id 172.16.91.21
# 查看本机所有用户,ansible建议用root远程连接
[root@9019-kylin ~]#getent passwd
# 亦可用grep命令找文件看是否有指定用户
[root@9019-kylin ~]# grep secadm /etc/passwd
secadm:x:1001:1001::/secadm:/bin/bash
通配符:用于匹配被控制的主机的列表
# All :表示所有Inventory中的所有主机
ansible all -m ping
# *:通配符
ansible "*" -m ping
ansible 192.168.1.* -m ping
ansible "srvs" -m ping
# 或关系
ansible "webservers:appservers" -m ping
ansible "172.16.91.21:172.16.91.22" -m ping
# 逻辑与
# 在websrvs组并且在dbsrvs组中的主机
ansible “websrvs:&dbsrvs” -m ping
# 逻辑非
#在websrvs组,但不在dbsrvs组中的主机
#注意:此处为单引号
ansible 'websrvs:!dbsrvs' -m ping
# 综合逻辑
ansible 'websrvs:dbsrvs:&appsrvs:!ftpsrvs' -m ping
# 正则表达式
ansible "websrvs:dbsrvs" -m ping
ansible "~(web|db).*\.magedu\.com" -m ping
ansible命令执行过程:
- 加载自己的配置文件 默认/etc/ansible/ansible.cfg
- 加载自己对应的模块文件,如:command
- 通过ansible将模块或命令生成对应的临时py文件,并将该文件传输至远程服务器的对应执行用户$HOME/.ansible/tmp/ansible-tmp-数字/XXX.PY文件
- 给文件+x执行
- 执行并返回结果
- 删除临时py文件,退出
ansible使用范例:
#以wang用户执行ping存活检测
ansible all -m ping -u wang -k
#以wang sudo至root执行ping存活检测
ansible all -m ping -u wang -k -b
#以wang sudo至mage用户执行ping存活检测
ansible all -m ping -u wang -k -b --become-user=mage
#以wang sudo至root用户执行ls
ansible all -m command -u wang -a 'ls /root' -b --become-user=root -k -K
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 [create|decrypt|edit|encrypt|rekey|view]
# 范例:
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-console:此工具可交互执行命令,支持tab,ansible 2.0+新增
# 提示符格式:执行用户@当前操作的主机组 (当前组的主机数量)[f:并发数]$
# 常用子命令:设置并发数(forks n 例如: forks 10)、切换组(cd 主机组 例如: cd web)、列出当前组主机列表(list)、列出所有的内置命令(?或help)
#范例:
[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
ansible-galaxy:此工具会连接 https://galaxy.ansible.com 下载相应的roles
#列出所有已安装的galaxy
ansible-galaxy list
#安装galaxy
ansible-galaxy install geerlingguy.mysql
ansible-galaxy install geerlingguy.redis
#删除galaxy
ansible-galaxy remove geerlingguy.redis
07.Ansible常用模块详解
command模块:在远程主机执行命令,此为默认模块,可忽略-m选项(注意:此命令不支持 $VARNAME < > | ; & 等,用shell模块实现)
# 查看命令参数
[root@9019-kylin ~]# ansible-doc -s command
- name: Executes a command on a remote node
action: command
chdir # cd into this directory before running the command
creates # a filename, when it already exists, this step will *not* be run.
executable # change the shell used to execute the command. Should be an absolute path to the executable.
free_form= # the command module takes a free form command to run. There is no parameter actually named 'f
removes # a filename, when it does not exist, this step will *not* be run.
# 直接执行命令
[root@9019-kylin ansible]# ansible webservers -m command -a 'cat /etc/centos-release'
172.16.91.22 | success | rc=0 >>
CentOS Linux release 7.4.1708 (Core)
172.16.91.21 | success | rc=0 >>
CentOS Linux release 7.4.1708 (Core)
# chdir参数
[root@9019-kylin ansible]# ansible webservers -m command -a 'chdir=/etc cat centos-release'
172.16.91.21 | success | rc=0 >>
CentOS Linux release 7.4.1708 (Core)
172.16.91.22 | success | rc=0 >>
CentOS Linux release 7.4.1708 (Core)
# creates参数
[root@9019-kylin ~]# ansible webservers -m command -a 'chdir=/etc creates=/data/f1.txt cat centos-release'
172.16.91.21 | success | rc=0 >>
CentOS Linux release 7.4.1708 (Core)
172.16.91.22 | success | rc=0 >>
CentOS Linux release 7.4.1708 (Core)
# 有些shell通配符并不支持
[root@9019-kylin ~]# ansible webservers -m command -a 'rm -rf /data/*'
[root@9019-kylin ~]# ansible webservers -m command -a 'echo hello > /data/hello.log'
[root@9019-kylin ~]# ansible webservers -m command -a 'echo centos | passwd --stdin ansible' #修改密码
[root@9019-kylin ~]# ansible webservers -m command -a "echo $HOSTNAME"
shell模块:和command相似,用shell执行命令,支持大部分符号
[root@9019-kylin ~]# ansible webservers -m command -a 'echo $HOSTNAME'
# 修改默认执行的模块
[root@9019-kylin ~]# vim /etc/ansible/ansible.cfg
# 设置 module_name = shell
script模块:在远程主机上运行ansible服务器上的脚本
[root@9019-kylin ~]# vim test.sh
#!/bin/bash
echo My hostname is `hostname`
[root@9019-kylin ~]# chmod +x test.sh
[root@9019-kylin ~]# ./test.sh
My hostname is 9019-kylin
[root@9019-kylin ~]# ansible webservers -m script -a './test.sh'
172.16.91.21 | success >> {
"changed": true,
"rc": 0,
"stderr": "",
"stdout": "My hostname is 21-cent74\r\n"
}
172.16.91.22 | success >> {
"changed": true,
"rc": 0,
"stderr": "",
"stdout": "My hostname is 22-centos\r\n"
}
# 复制的远程文件在远程机器的./ansible/tmp/目录下
Copy模块:从ansible服务器主控端复制文件到远程主机
#如目标存在,默认覆盖,此处指定先备份
ansible webservers -m copy -a "src=/root/test.sh dest=/tmp/test.sh owner=ansible mode=600 backup=yes"
#指定内容,直接生成目标文件
ansible webservers -m copy -a "content='test line1\ntest line2' dest=/tmp/test.txt"
#复制/etc/下的文件,不包括/etc/目录自身
ansible webservers -m copy -a "src=/etc/ dest=/backup"
Fetch模块:从远程主机提取文件至ansible的主控端,copy相反,目前不支持目录(不支持目录提取,同时目标必须是指定的目录而不是文件)
ansible all -m fetch -a 'src=/etc/redhat-release dest=/data/'
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=user mode=755"
# 循环修改目录中文件权限
ansible all -m file -a "path=/data/mysql state=directory owner=mysql group=mysql"
# 创建软链接
ansible all -m file -a 'src=/data/testfile dest=/data/testfile-link state=link'
unarchive模块:解包解压缩。常见参数:copy(默认为yes,当copy=yes,拷贝的文件是从ansible主机复制到远程主机上,如果设置为copy=no,会在远程主机上寻找src源文件)、remote_src(和copy功能一样且互斥,yes表示在远程主机,不在ansible主机,no表示文件在ansible主机上)、src(源路径,可以是ansible主机上的路径,也可以是远程主机上的路径,如果是远程主机上的路径,则需要设置copy=no)、dest(远程主机上的目标路径)、mode(设置解压缩后的文件权限)
# 压缩包在ansible机器上
ansible webservers -m unarchive -a 'src=/data/etc.tar.gz dest=/data/ owner=user'
# 压缩包在远程主机上
ansible webservers -m unarchive -a 'src=/data/etc.tar.gz dest=/data/ mode=700 copy=no'
Archive模块:打包压缩。(dest为目标主机)
ansible webservers -m archive -a 'path=/var/log/ dest=/data/log.tar.bz2 format=bz2 owner=user mode=600'
Hostname模块:管理主机名
ansible webservers -m hostname -a "webservers"
ansible 172.16.91.20 -m hostname -a 'name=manager-module'
Cron模块:计划任务(支持时间:minute,hour,day,month,weekday)
# 备份数据库脚本
[root@9019-kylin ~]# cat mysql_backup.sh
# 创建定时任务
ansible dbservers -m cron -a 'hour=2 minute=30 weekday=1-5 name="backup mysql" job=/root/mysql_backup.sh'
# 远程主机查看是否存在任务
[root@21-cent74 etc]# crontab -l
[root@21-cent74 etc]# cat /var/spool/cron/root
# 暂停定时任务
ansible dbservers -m cron -a 'hour=2 minute=30 weekday=1-5 name="backup mysql" job=/root/mysql_backup.sh disable=yes'
# 启用定时任务
ansible dbservers -m cron -a 'hour=2 minute=30 weekday=1-5 name="backup mysql" job=/root/mysql_backup.sh disable=no'
# 删除定时任务
ansible dbservers -m cron -a 'name="backup mysql" state=absent'
Yum模块:管理软件包,只支持RHEL,CentOS,fedora,不支持Ubuntu其它版本
ansible websrvs -m yum -a 'name=httpd state=present' #安装
ansible websrvs -m yum -a 'name=httpd state=absent' #删除
Service模块:管理服务
# 开启服务
ansible all -m service -a 'name=httpd state=started'
# 停止服务
ansible all -m service -a 'name=httpd state=stopped'
# 查看启动情况
ansible all -a "ss -ntl"
# 设置开机启动
ansible all -m service -a 'name=httpd state=started enabled=yes'
# 修改监听端口
ansible all -m shell -a "sed -i 's/^Listen 80/Listen 8080/' /etc/httpd/conf/httpd.conf"
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'
# 删除用户及家目录等数据
ansible all -m user -a 'name=nginx state=absent remove=yes'
Group模块:管理组
# 创建组
ansible webservers -m group -a 'name=nginx gid=88 system=yes'
# 删除组
ansible webservers -m group -a 'name=nginx state=absent'
Lineinfile模块:相当于sed,可以修改文件内容。ansible在使用sed进行替换时,经常会遇到需要转义的问题,而且ansible在遇到特殊符号进行替换时,存在问题,无法正常进行替换 。其实在ansible自身提供了两个模块:lineinfile模块和replace模块,可以方便的进行替换。
ansible all -m lineinfile -a "path=/etc/selinux/config regexp='^SELINUX=' line='SELINUX=enforcing'"
ansible all -m lineinfile -a 'dest=/etc/fstab state=absent regexp="^#"'
Replace模块:该模块有点类似于sed命令,主要也是基于正则进行匹配和替换
ansible all -m replace -a "path=/etc/fstab regexp='^(UUID.*)' replace='#\1'"
ansible all -m replace -a "path=/etc/fstab regexp='^#(.*)' 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_processor*"
[root@ansible ~]#ansible all -m setup -a 'filter=ansible_python_version'
10.0.0.7 | SUCCESS => {
"ansible_facts": {
"ansible_python_version": "2.7.5",
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false
}
10.0.0.6 | SUCCESS => {
"ansible_facts": {
"ansible_python_version": "2.6.6",
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false
}
10.0.0.8 | SUCCESS => {
"ansible_facts": {
"ansible_python_version": "3.6.8",
"discovered_interpreter_python": "/usr/libexec/platform-python"
},
"changed": false
}
08.Ansible-Playbook详解
yaml语法:YAML是一个可读性高的用来表达资料序列的格式,目前很多软件中采有此格式的文件,如:ubuntu,anisble,docker,k8s等,YAML官方网站地址。语法简介:
- 在单一文件第一行,用连续三个连字号“-” 开始,还有选择性的连续三个点号( … )用来表示文件的结尾
- 次行开始正常写Playbook的内容,一般建议写明该Playbook的功能
- 使用#号注释代码
- 缩进必须是统一的,不能空格和tab混用
- 缩进的级别也必须是一致的,同样的缩进代表同样的级别,程序判别配置的级别是通过缩进结合换行来实现的
- YAML文件内容是区别大小写的,key/value的值均需大小写敏感
- 多个key/value可同行写也可换行写,同行使用,分隔
- v可是个字符串,也可是另一个列表
- 一个完整的代码块功能需最少元素需包括 name 和 task
- 一个name只能包括一个task
- YAML文件扩展名通常为yml或yaml
YAML的语法和其他高阶语言类似,并且可以简单表达清单、散列表、标量等数据结构。其结构(Structure)通过空格来展示,序列(Sequence)里的项用"-“来代表,Map里的键值对用”:"分隔,下面介绍常见的数据结构。
# List列表:列表由多个元素组成,每个元素放在不同行,且元素前均使用“-”打头,或者将所有元素用 [ ] 括起来放在同一行
# A list of tasty fruits
- Apple
- Orange
- Strawberry
- Mango
[Apple,Orange,Strawberry,Mango]
# Dictionary字典:字典由多个key与value构成,key和value之间用 :分隔,所有k/v可以放在一行,或者每个 k/v 分别放在不同行
# An employee record
name: Example Developer
job: Developer
skill: Elite
# 也可以将key:value放置于{}中进行表示,用,分隔多个key:value
# An employee record
{name: "Example Developer", job: "Developer", skill: "Elite"}
# 范例
name: John Smith
age: 41
gender: Male
spouse:
name: Jane Smith
age: 37
gender: Female
children:
- name: Jimmy Smith
age: 17
gender: Male
- name: Jenny Smith
age 13
gender: Female
三种常见的数据格式:XML(可扩展标记语言,可用于数据交换和配置);JSON(JavaScript 对象表记法,主要用来数据交换或配置,不支持注释);YAML(不是一种标记语言, 主要用来配置,大小写敏感,不支持tab)
可以用工具互相转换,参考网站:json2yaml、bejson
playbook核心元素:Hosts(执行的远程主机列表)、Tasks(任务集)、Variables(内置变量或自定义变量在playbook中调用)、Templates(模板,可替换模板文件中的变量并实现一些简单逻辑的文件)、Handlers和notify(结合使用,由特定条件触发的操作,满足条件方才执行,否则不执行)、tags( 标签 指定某条任务执行,用于选择运行playbook中的部分代码。ansible具有幂等性,因此会自动跳过没有变化的部分,即便如此,有些代码为测试其确实没有发生变化的时间依然会非常地长。此时,如果确信其没有变化,就可以通过tags跳过此些代码片断)
- hosts组件:playbook中的每一个play的目的都是为了让特定主机以某个指定的用户身份执行任务。hosts用于指定要执行指定任务的主机,须事先定义在主机清单中
- remote_user 组件:可用于Host和task中。也可以通过指定其通过sudo的方式在远程主机上执行任务,其可用于play全局或某任务;此外,甚至可以在sudo时使用sudo_user指定sudo时切换的用户
- hosts: webservers remote_user: root tasks: - name: test connection ping: remote_user: user sudo: yes #默认sudo为root sudo_user:Chang #sudo为Chang
- task列表和action组件:play的主体部分是task list,task list中有一个或多个task,各个task 按次序逐个在hosts中指定的所有主机上执行,即在所有主机上完成第一个task后,再开始第二个task。task的目的是使用指定的参数执行模块,而在模块参数中可以使用变量。模块执行是幂等的,这意味着多次执行是安全的,因为其结果均一致。每个task都应该有其name,用于playbook的执行结果输出,建议其内容能清晰地描述任务执行步骤。如果未提供name,则action的结果将用于输出。task两种格式:(1) action: module arguments (2) module: arguments 建议使用。注意:shell和command模块后面跟命令,而非key=value
--- - hosts: websrvs remote_user: root tasks: - name: install httpd yum: name=httpd - name: start httpd service: name=httpd state=started enabled=yes
- 其它组件:某任务的状态在运行后为changed时,可通过“notify”通知给相应的handlers。任务可以通过"tags“打标签,可在ansible-playbook命令上使用-t指定进行调用
# 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 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]
,有以下常见选项
-C --check #只检测可能会发生的改变,但不真正执行操作
--list-hosts #列出运行任务的主机
--list-tags #列出tag
--list-tasks #列出task
--limit 主机列表 #只针对主机列表中的主机执行
-v -vv -vvv #显示过程
# 范例
ansible-playbook file.yml --check #只检测
ansible-playbook file.yml
ansible-playbook file.yml --limit websrvs
09.Ansible-Playbook使用
利用 playbook 创建 mysql 用户:mysql_user.yml
[root@9019-kylin ansible]# vim create_mysql.yml
#create mysql user and group
- hosts: dbservers
remote_user: root
#gather_facts: no 不用收集主机信息,提升执行速度
tasks:
- {name: create group, group: name=mysql system=yes gid=306}
- name: create user
user: name=mysql system=yes group=mysql shell=/sbin/nologin createhome=no home=/data/mysql uid=306
# 检查语法
[root@9019-kylin ansible]# ansible-playbook -C create_mysql.yml
PLAY [dbservers] **************************************************************
GATHERING FACTS ***************************************************************
ok: [172.16.90.160]
TASK: [create group] **********************************************************
changed: [172.16.90.160]
TASK: [create user] ***********************************************************
changed: [172.16.90.160]
PLAY RECAP ********************************************************************
172.16.90.160 : ok=3 changed=2 unreachable=0 failed=0
# 执行
[root@9019-kylin ansible]# ansible-playbook create_mysql.yml
PLAY [dbservers] **************************************************************
TASK: [create group] **********************************************************
changed: [172.16.90.160]
TASK: [create user] ***********************************************************
changed: [172.16.90.160]
PLAY RECAP ********************************************************************
172.16.90.160 : ok=2 changed=2 unreachable=0 failed=0
# 查看结果
[root@9019-kylin ansible]# ansible dbservers -a 'getent passwd mysql'
172.16.90.160 | success | rc=0 >>
mysql:x:306:306::/data/mysql:/sbin/nologin
利用playbook安装nginx:install_nginx.yml
[root@9019-kylin ansible]# vim install_nginx.yml
---
# install nginx
- hosts: webservers
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: web page
copy: src=files/index.html dest=/usr/share/nginx/html/index.html
- name: Start Nginx
service: name=nginx state=started enabled=yes
# 看远程端口是否启用
[root@9019-kylin ansible]# ansible webservers -a 'ss -ntl'
# 检查yml文件语法
[root@9019-kylin ansible]# ansible-playbook -C install_nginx.yml
# 执行yml文件
[root@9019-kylin ansible]# ansible-playbook install_nginx.yml
# 查看用户和组
[root@9019-kylin ~]# ansible webservers -a 'ls -l /etc/passwd'
172.16.91.22 | success | rc=0 >>
-rw-r--r--. 1 root root 2114 Feb 20 09:21 /etc/passwd
[root@9019-kylin ~]# ansible webservers -a 'ls -l /etc/group'
172.16.91.22 | success | rc=0 >>
-rw-r--r--. 1 root root 925 Feb 20 09:21 /etc/group
更多案例,请点击链接
10.Ansible-Playbook高级用法
handlers和notify:Handlers本质是task list,类似于MySQL中的触发器触发的行为,其中的task与前述的task并没有本质上的不同,主要用于当关注的资源发生变化时,才会采取一定的操作。而Notify对应的action可用于在每个play的最后被触发,这样可避免多次有改变发生时,每次都执行指定的操作,仅在所有的变化发生完成后一次性的执行指定操作,在notify中列出的操作称为handler,也即notify中调用handler中定义的操作。(可以理解为当被触发语句标识色为黄色则触发触发器)
---
- hosts: webservers
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
tags组件:在playbook文件中,可以利用tags组件,为特定task指定标签,当在执行playbook时,可以只执行tags的task而非整个playbook文件。
---
- hosts: webservers
remote_user: root
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
tags: config
- name: ensure apache is running
service: name=httpd state=started enable=yes
handlers:
- name: restart httpd
service: name=httpd state=restarted
# 查看有哪些标签
[root@9019-kylin ~]# ansible-playbook --list-tags httpd.yml
# 针对标签进行执行
[root@9019-kylin ~]# ansible-playbook -t config httpd.yml
变量:仅能由字母、数字和下划线组成,且只能以字母开头。例如:http_port=80
,,通过{{ http_port }}调用变量(建议变量名前后加空格),有时用"{{ http_port }}"才生效。来源:
- .ansible 的 setup facts 远程主机的所有变量都可直接调用
# 范例 # 执行错误,变量只能在playbook中使用 [root@9019-kylin ~]# ansible all -m file -a 'path=/data/{{ ansible_nodename }}.log state=touch' # 执行成功 [root@9019-kylin ~]# vim var.yml --- # var.yml - host: all remote_user: root tasks: - name: create log file file: name=/data/{{ ansible_nodename }}.log state=touch owner=user mode=600 [root@9019-kylin ~]# ansible-playbook var.yml
- 通过命令行指定变量(优先级最高)
--- - hosts: webservers remote_user: root tasks: - name: install package yum: name={{ pkname }} state=present # 给变量赋值 [root@9019-kylin ~]# ansible-playbook -e pkname=memcached
- 在playbook文件中定义变量
--- - hosts: webservers remote_user: root vars: - username: user1 - groupname: group1 tasks: - name: create group group: name={{ groupname }} state=present - name: create user user: name={{ username }} group={{ groupname }} state=present # 验证是否创建成功 [root@21-cent74 ~]# id user1
- 使用变量文件(可以在一个独立的playbook文件中定义变量,在另一个playbook文件中引用变量文件中的变量,比playbook中定义的变量优化级高)
vim vars1.yml --- # variables file package_name: vsftpd service_name: vsftpd vim var2.yml --- #install package and start service - hosts: webservers remote_user: root vars_files: - vars1.yml tasks: - name: install package yum: name={{ package_name }} tags: install - name: start service service: name={{ service_name }} state=started enabled=yes
- 主机清单文件中定义变量
# 主机变量:在inventory主机清单文件中为指定的主机定义变量以便在playbook中使用 # 组(公共)变量:在inventory主机清单文件中赋予给指定组内的所有主机上的paybook中可用的变量,如果和主机变量是同名,优先级地域主机变量 [root@9019-kylin ansible]# vim hosts [appservers] [webservers] 172.16.91.21 host=node1 172.16.91.22 host=node2 [webservers:vars] domain=example.org [root@9019-kylin ansible]# ansible webservers -m hostname -a 'name={{host}}.{{domain}}'
11.Ansible-Playbook模板用法
简介:模板是一个文本文件,可以做为生成文件的模版,并且模板文件中还可嵌套jinja语法(语法详解地址)。可以根据和参考模块文件,动态生成相类似的配置文件,template文件必须存放于templates目录下,且命名为.j2结尾且yaml/yml 文件需和templates目录平级
[root@9019-kylin ansible]# vim templnginx.yml
---
- hosts: webservers
remote_user: root
tasks:
- name: install nginx
yum: name=nginx
- name: template config to remote hosts
template: src=nginx.conf.js dest=/etc/nginx/nginx.conf
- name: start service
service: name=nginx state=started enabled=yes
[root@9019-kylin ansible]# mkdir templates
[root@9019-kylin ansible]# cd templates/
[root@9019-kylin templates]# vim nginx.conf.j2
# Jinja 允许用计算值
[root@9019-kylin ansible]# vim nginx.conf.j2
worker_processes {{ ansible_processor_vcpus**2 }};
template中使用流程控制 for 和 if:template中也可以使用流程控制 for 循环和 if 条件判断,实现动态生成文件功能
[root@9019-kylin templates]# vim nginx.conf2.j2
{% for vhost in nginx_vhosts %}
server {
listen {{ vhost }}
}
{% endfor %}
[root@9019-kylin ansible]# vim templnginx2.yml
---
- hosts: webservers
remote_user: root
vars:
nginx_vhosts:
- 81
- 82
- 83
tasks:
- name: template config
template: src=nginx.conf.j2 dest=/data/nginx.conf
[root@9019-kylin ansible]# ansible-playbook -C templnginx2.yml
[root@9019-kylin ansible]# ansible-playbook templnginx2.yml
[root@9019-kylin ansible]# vim templnginx3.yml
- hosts: webservers
remote_user: root
vars:
nginx_vhosts:
- web1:
listen: 8080
root: "/var/www/nginx/web1/"
- web2:
listen: 8080
server_name: "web2.magedu.com"
root: "/var/www/nginx/web2/"
- web3:
listen: 8080
server_name: "web3.magedu.com"
root: "/var/www/nginx/web3/"
tasks:
- name: template config to
template: src=nginx.conf3.j2 dest=/data/nginx3.conf
[root@9019-kylin templates]# vim nginx.conf3.j2
{% for vhost in nginx_vhosts %}
server {
listen {{ vhost.listen }}
{% if vhost.server_name is defined %}
server_name {{ vhost.server_name }}
{% endif %}
root {{ vhost.root }}
}
{% endfor %}
# 生成结果
server {
listen 8080
root /var/www/nginx/web1/
}
server {
listen 8080
server_name web2.magedu.com
root /var/www/nginx/web2/
}
server {
listen 8080
server_name web3.magedu.com
root /var/www/nginx/web3/
}
playbook中使用流程控制 when 和 with_items:when语句,可以实现条件测试。如果需要根据变量、facts或此前任务的执行结果来做为某task执行与否的前提时要用到条件测试,通过在task后添加when子句即可使用条件测试,jinja2的语法格式。 with_items语句,可以实现迭代(当有需要重复性执行的任务时,可以使用迭代机制)。对迭代项的引用,固定变量名为”item“,要在task中使用with_items给定要迭代的元素列表。(列表元素格式:字符串、字典)
[root@9019-kylin ansible]# vim templnginx3.yml
---
- hosts: webservers
remote_user: root
tasks:
- name: install conf file to centos7
template: src=nginx.conf.c7.j2 dest=/etc/nginx/nginx.conf
when: ansible_distribution_major_version == "7"
- name: install conf file to centos6
template: src=nginx.conf.c6.j2 dest=/etc/nginx/nginx.conf
when: ansible_distribution_major_version == "6"
---
#remove mariadb server
- hosts: appsrvs:!192.168.38.8
remote_user: root
tasks:
- name: stop service
shell: /etc/init.d/mysqld stop
- name: delete files and dir
file: path={{ item }} state=absent
with_items:
- /usr/local/mysql
- /usr/local/mariadb-10.2.27-linux-x86_64
- /etc/init.d/mysqld
- /etc/profile.d/mysql.sh
- /etc/my.cnf
- /data/mysql
- name: delete user
user: name=mysql state=absent remove=yes
---
- hosts: websrvs
remote_user: root
tasks:
- name: add some groups
group: name={{ item }} state=present
with_items:
- nginx
- mysql
- apache
- name: add some users
user: name={{ item.name }} group={{ item.group }} state=present
with_items:
- { name: 'nginx', group: 'nginx' }
- { name: 'mysql', group: 'mysql' }
- { name: 'apache', group: 'apache' }
更多案例,请点击链接
12.Ansible-Playbook高级用法role
角色role,用于层次性、结构化地组织playbook。roles能够根据层次型结构自动装载变量文件、tasks以及handlers等。要使用roles只需要在playbook中使用include指令即可。简单来讲,roles就是通过分别将变量、文件、任务、模板及处理器放置于单独的目录中,并可以便捷地include它们的一种机制。角色一般用于基于主机构建服务的场景中,但也可以是用于构建守护进程等场景中。运维复杂的场景:建议使用roles,代码复用度高。roles:多个角色的集合, 可以将多个的role,分别放至roles目录下的独立子目录中。
Roles各目录作用:roles/project/ :项目名称,有以下子目录
- files/ :存放由copy或script模块等调用的文件
- templates/:template模块查找所需要模板文件的目录
- tasks/:定义task,role的基本元素,至少应该包含一个名为main.yml的文件;其它的文件需要在此文件中通过include进行包含
- handlers/:至少应该包含一个名为main.yml的文件;其它的文件需要在此文件中通过include进行包含
- vars/:定义变量,至少应该包含一个名为main.yml的文件;其它的文件需要在此文件中通过include进行包含
- meta/:定义当前角色的特殊设定及其依赖关系,至少应该包含一个名为main.yml的文件,其它文件需在此文件中通过include进行包含
- default/:设定默认变量时使用此目录中的main.yml文件,比vars的优先级低
创建role:创建role的步骤如下
- 创建以roles命名的目录
- 在roles目录中分别创建以各角色名称命名的目录,如webservers等
- 在每个角色命名的目录中分别创建files、handlers、meta、tasks、templates和vars目录;用不到的目录可以创建为空目录,也可以不创建
- 在playbook文件中,调用各角色
roles的目录结构:针对大型项目使用Roles进行编排
nginx-role.yml
roles/
└── nginx
├── files
│ └── main.yml
├── tasks
│ ├── groupadd.yml
│ ├── install.yml
│ ├── main.yml
│ ├── restart.yml
│ └── useradd.yml
└── vars
└── main.yml
playbook调用角色:
# 调用角色方法1:
---
- hosts: websrvs
remote_user: root
roles:
- mysql
- memcached
- nginx
# 调用角色方法2:键role用于指定角色名称,后续的k/v用于传递变量给角色
---
- hosts: all
remote_user: root
roles:
- mysql
- { role: nginx, username: nginx }
# 调用角色方法3:还可基于条件测试实现角色调用
---
- hosts: all
remote_user: root
roles:
- { role: nginx, username: nginx, when: ansible_distribution_major_version == ‘7’ }
# roles 中 tags 使用
#nginx-role.yml
---
- hosts: websrvs
remote_user: root
roles:
- { role: nginx ,tags: [ 'nginx', 'web' ] ,when: ansible_distribution_major_version == "6“ }
- { role: httpd ,tags: [ 'httpd', 'web' ] }
- { role: mysql ,tags: [ 'mysql', 'db' ] }
- { role: mariadb ,tags: [ 'mariadb', 'db' ] }
ansible-playbook --tags="nginx,httpd,mysql" nginx-role.yml
案例详解:更多案例请点击链接
# 案例:实现 httpd 角色
# 规划:1、安装软件 2、修改配置文件 3、部署网页 4、启动服务
[root@9019-kylin roles]# pwd
/root/ansible/roles
[root@9019-kylin roles]# mkdir httpd/{tasks,files,handles} -pv
mkdir: 已创建目录 "httpd"
mkdir: 已创建目录 "httpd/tasks"
mkdir: 已创建目录 "httpd/files"
mkdir: 已创建目录 "httpd/handles"
[root@9019-kylin ansible]# vim roles/httpd/tasks/install.yml
- name: install httpd package
yum: name=httpd
[root@9019-kylin ansible]# vim roles/httpd/tasks/config.yml
- name: config file
copy: src=httpd.conf dest=/etc/httpd/conf/ backup=yes
notify: restart
[root@9019-kylin ansible]# cd roles/httpd/files/
[root@9019-kylin files]# ls
httpd.conf
[root@9019-kylin ansible]# vim roles/httpd/tasks/index.yml
- name: index.html
copy: src=index.html dest=/var/www/html/
[root@9019-kylin ansible]# vim roles/httpd/files/index.html
<h1>Welcome to ansible!</h1>
[root@9019-kylin ansible]# vim roles/httpd/tasks/service.yml
- name: start service
service: name=httpd state=started enabled=yes
[root@9019-kylin ansible]# vim roles/httpd/tasks/main.yml
- include: install.yml
- include: config.yml
- include: index.yml
- include: service.yml
[root@9019-kylin roles]# vim roles/httpd/handlers/main.yml
- name: restart
service: name=httpd state=restarted
[root@9019-kylin roles]# tree httpd/
├── files
│ ├── httpd.conf
│ └── index.html
├── handlers
│ └── main.yml
└── tasks
├── config.yml
├── index.yml
├── install.yml
├── main.yml
└── service.yml
[root@9019-kylin ansible]# vim role_httpd.yml
---
# httpd role
- hosts: webservers
remote_user: root
roles:
- httpd
[root@9019-kylin ansible]ansible-playbook role_httpd.yml
# 注意:centos7安装软件的时候会自动创建账号;而centos8不会自动创建账号,直接安装会报错。建议在ansible脚本中配置添加账号
推荐资料:
http://galaxy.ansible.com
https://galaxy.ansible.com/explore
http://github.com
http://ansible.com.cn
https://github.com/ansible/ansible
https://github.com/ansible/ansible-examples
https://www.zsythink.net
http://www.wangxiaochun.com
https://www.junmajinlong.com