参考资料
运维自动化发展历程及技术应用 本地部署(On-Premises) -> 基础设施即服务(IaaS) -> 平台即服务(PaaS) -> 软件即服务(SaaS)
自动化运维应用场景
企业实际应用场景分析
1 Dev开发环境
使用者:程序员
功能:程序员开发软件,测试BUG的环境
管理者:程序员
2 测试环境
使用者:QA测试工程师
功能:测试经过Dev环境测试通过的软件的功能
管理者:运维
说明:测试环境往往有多套,测试环境满足测试功能即可,不宜过多
1、测试人员希望测试环境有多套,公司的产品多产品线并发,即多个版本,意味着多个版本同步测试
2、通常测试环境有多少套和产品线数量保持一样
程序发布
常用自动化运维工具
Ansible:python,Agentless,中小型应用环境,使用ssh协议
Saltstack:python,一般需部署agent(麻烦),执行效率更高
Puppet:ruby, 功能强大,配置复杂,重型,适合大型环境,需要agent端配合
Fabric:python,agentless
Chef:ruby,国内应用少
Cfengine
func
可以ansible部署saltstack;ansible无主无从架构,开箱即用,用完即扔。
运维自动化场景:
操作系统预备自动化:PXE, Kickstart, Cobbler
配置自动化: Ansible
监控自动化:
系统与应用监控: Zabbix
日志监控: ELK
代码持续继承与代码持续发布自动化: git, Docker, Jenkins, github
Ansible 特性
模块化:调用特定的模块,完成特定任务
Paramiko(python对ssh的实现),PyYAML,Jinja2(模板语言)三个关键模块
支持自定义模块
基于Python语言实现
部署简单,基于python和SSH(默认已安装),agentless = 安全,基于OpenSSH
支持playbook编排任务
幂等性:一个任务执行1遍和执行n遍效果一样,不因重复执行带来意外情况
无需代理不依赖PKI(无需ssl)
可使用任何编程语言写模块
YAML格式,编排任务,支持丰富的数据结构
较强大的多层解决方案
Ansible主要组成部分
Ansible命令执行来源:
USER,普通用户,即SYSTEM ADMINISTRATOR
CMDB(配置管理数据库) API 调用
PUBLIC/PRIVATE CLOUD API调用 (公有私有云的API接口调用)
USER-> Ansible Playbook -> Ansibile 利用ansible实现管理的方式:
Ad-Hoc 即ansible单条命令,主要用于临时命令使用场景
Ansible-playbook 主要用于长期规划好的,大型项目的场景,需要有前期的规划过程
Ansible-playbook(剧本)执行过程
将已有编排好的任务集写入Ansible-Playbook
通过ansible-playbook命令分拆任务集至逐条ansible命令,按预定规则逐条执行 Ansible主要操作对象
HOSTS主机
NETWORKING网络设备 注意事项:
执行ansible的主机一般称为主控端,中控,master或堡垒机
主控端Python版本需要2.6或以上
被控端Python版本小于2.4需要安装python-simplejson
被控端如开启SELinux需要安装libselinux-python
windows不能做为主控端
ansible不是服务,不会一直启动,只是需要的时候启动安装
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 yum -y install epel-release yum install ansible yum -y install python-jinja2 PyYAML python-paramiko python-babel python-crypto tar xf ansible-1.5.4.tar.gz cd ansible-1.5.4python setup.py build python setup.py install mkdir /etc/ansible cp -r examples/* /etc/ansible git clone git://github.com/ansible/ansible.git --recursive cd ./ansiblesource ./hacking/env-setupyum install python-pip python-devel yum install gcc glibc-devel zibl-devel rpm-bulid openssl-devel pip install --upgrade pip pip install ansible --upgrade [root@master ec2-user] ansible 2.9.25 config file = /etc/ansible/ansible.cfg configured module search path = [u'/root/.ansible/plugins/modules' , u'/usr/share/ansible/plugins/modules' ] ansible python module location = /usr/lib/python2.7/site-packages/ansible executable location = /bin/ansible python version = 2.7.5 (default, Nov 16 2020, 22:23:17) [GCC 4.8.5 20150623 (Red Hat 4.8.5-44)] [ec2-user@master ~]$ file /usr/bin/ansible /usr/bin/ansible: symbolic link to `/usr/bin/ansible-2.7' [ec2-user@master ~]$ ll /usr/bin/ansible lrwxrwxrwx 1 root root 20 Nov 18 16:29 /usr/bin/ansible -> /usr/bin/ansible-2.7
相关文件 1 2 3 4 5 6 7 8 9 10 11 12 13 14 rpm -ql ansible |less /etc/ansible/ansible.cfg /etc/ansible/hosts /etc/ansible/roles/ /usr/bin/ansible /usr/bin/ansible-doc /usr/bin/ansible-galaxy /usr/bin/ansible-playbook /usr/bin/ansible-pull /usr/bin/ansible-vault /usr/bin/ansible-console
Ansible 简单应用案例 使用ansible ping 模块实现测试主机互通性 集群免密登录方法:
shell写个循环
密码设置相同,然后-k 登录即可
1 2 3 4 5 6 7 8 ssh-keygen -t rsa -f /root/.ssh/id_rsa -N '' ssh-copy-id IP ansible all -m ping
在使用ansible连接之前,必须首先登录一下,保持know_hosts有连接记录,负责无法连接
ansible的ping不是基于ssh协议的
报错: ssh免密登录设置无法生效,具体如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 ssh 192.169.0.13 -v debug1: key_load_public: No such file or directory debug1: identity file /home/ec2-user/.ssh/id_rsa-cert type -1 ... debug1: No valid Key exchange context debug1: Next authentication method: gssapi-with-mic debug1: Unspecified GSS failure. Minor code may provide more information No Kerberos credentials available (default cache: KEYRING:persistent:1000) debug1: Unspecified GSS failure. Minor code may provide more information No Kerberos credentials available (default cache: KEYRING:persistent:1000) su ec2-user chmod 700 /home/ec2-user/ chmod 700 /home/ec2-user/.ssh chmod 644 /home/ec2-user/.ssh/authorized_keys chmod 600 /home/ec2-user/.ssh/id_rsa
使用ansible cron 模块实现配置多主机时间同步 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 - 国内建议使用阿里时钟源 time1.aliyun.com - 国际建议使用微软时钟源 time.windows.com sudo yum install ntpdate -y ansible 主机清单IP或分组名称 -m 模块 -a "参数" ansible 192.168.0.15 -m cron -a 'name="test cron1" job="sudo ntpdate ntp.aliyun.com" minute=0 hour=*/1' 192.168.0.15 | CHANGED => { "ansible_facts" : { "discovered_interpreter_python" : "/usr/bin/python" }, "changed" : true , "envs" : [], "jobs" : [ "test cron1" ] } crontab -l ansible 192.168.0.15 -m command -a 'crontab -l' 192.168.0.15 | CHANGED | rc=0 >> 0 */1 * * * sudo ntpdate ntp.aliyun.com
使用ansible copy 模块实现多主机配置文件同步 1 2 3 4 119.255.249.177 ansible 192.168.0.15 -m copy -a "src=/etc/hosts dest=/etc/hosts"
如果需要root权限,可以在root用户下执行操作,同时确保主机开启rootssh登录,方式如下:【此处是不成熟的解决办法,采用ansible -b参数,可以在连接后切换到root用户下】
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 最近使用这个工具,普通用户可以登录root用户不可以登录。将vi /etc/ssh/sshd_config按照下述配置解决问题 修改sshd配置文件:vi /etc/ssh/sshd_config PermitRootLogin yes PubkeyAuthentication no PasswordAuthentication yes UseLogin yes cat /etc/ssh/sshd_config |grep PermitRootLogin |grep -Ev '^#' grep -Ev '^#|^$' /etc/ssh/sshd_config |grep PermitRootLogin sudo sed -i "s#PermitRootLogin no#PermitRootLogin yes#" /etc/ssh/sshd_config ansible all -m command -a 'sudo cat /etc/ssh/sshd_config |grep PermitRootLogin |grep -Ev "^#"' ansible all -m command -a 'sudo sed -i "s#PermitRootLogin no#PermitRootLogin yes#" /etc/ssh/sshd_config'
Ansible 配置文件 Ansible 配置文件/etc/ansible/ansible.cfg (一般保持默认)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 vim /etc/ansible/ansible.cfg [defaults ] host_key_checking = False log_path=/var/log/ansible.log module_name = command
Ansible命令 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 Ansible系列命令 ansible ansible-doc ansible-playbook ansible-vault ansible-console ansible-galaxy ansible-pull ansible-doc: 显示模块帮助 ansible-doc [options] [module...] -a 显示所有模块的文档 -l, --list 列出可用模块 -s, --snippet 显示指定模块的playbook片段(简化版,便于查找语法) 示例: ansible-doc -l 列出所有模块 ansible-doc ping 查看指定模块帮助用法 ansible-doc -s ping 查看指定模块帮助用法
ansible 命令 ansible通过ssh实现配置管理、应用部署、任务执行等功能,建议配置ansible端能基于密钥认证的方式联系各被管理节点
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 ansible <host-pattern> [-m module_name] [-a args] ansible +被管理的主机(ALL) +模块 +参数 --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 --list 列出所有主机 ping模块: 探测网络中被管理主机是否能够正常使用 走ssh协议 如果对方主机网络正常,返回pong ansible-doc -s ping 查看ping模块的语法 检测所有主机的网络状态 1> 默认情况下连接被管理的主机是ssh基于key验证,如果没有配置key,权限将会被拒绝 因此需要指定以谁的身份连接,输入用户密码,必须保证被管理主机用户密码一致 ansible all -m ping -k 2> 或者实现基于key验证 将公钥ssh-copy-id到被管理的主机上 , 实现免密登录 ansible all -m ping
ansible的Host-pattern 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 匹配主机的列表 All :表示所有Inventory中的所有主机 ansible all –m ping * :通配符 ansible "*" -m ping (*表示所有主机) ansible 192.168.1.* -m ping ansible "*srvs" -m ping 或关系 ":" ansible "websrvs:internal" -m ping ansible “192.168.1.10:192.168.1.20” -m ping 逻辑与 ":&" ansible "websrvs:&dbsrvs" –m ping 在websrvs组并且在dbsrvs组中的主机 逻辑非 ":!" ansible 'websrvs:!dbsrvs' –m ping 在websrvs组,但不在dbsrvs组中的主机 注意:此处为单引号 综合逻辑 ansible 'websrvs:dbsrvs:&internal:!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文件,sleep 0退出
执行状态:
绿色:执行成功并且不需要做改变的操作
黄色:执行成功并且对目标主机做变更
红色:执行失败
Ansible常用模块详解 模块文档:https://docs.ansible.com/ansible/latest/modules/modules_by_category.html
command 在远程主机执行命令,默认模块,可忽略-m选项
1 2 3 4 5 6 7 8 9 10 11 12 ansible all -m command -a 'service vsftpd start' ansible all -m command -a 'echo adong |passwd --stdin 123456' ansible all -a "removes=/home/aa/tt cat /home/aa/tt" -b ansible all -a "creates=/home/aa/tt df -h" -b ansible all -a "chdir=/home/aa/ cat tt" ansible all -a "/data/f1.sh" -b ansible all -a "useradd test1" -b ansible all -a "getent passwd test1" ansible all -m shell -a "echo magedu|passwd --stdin test1" ansible all -m shell -a "echo $HOSTNAME "
注意:ubuntu和centos的命令不尽一样,所以以下命令能在centos上运行成功,再ubuntu上不一定能成功
Shell 和command相似,用shell执行命令,上述无法执行的命令可以通过该模块执行。因此,使用shell模块即可。同时,针对不同的应用场景,尽量采用相应的模块进行处理,例如,“rm -rf /file” 删除文件命令可以采用 file 模块进行处理。
1 2 3 4 5 6 7 8 9 10 11 ansible all -m shell -a 'getenforce' 查看SELINUX状态 ansible all -m shell -a "sed -i 's/SELINUX=.*/SELINUX=disabled' /etc/selinux/config" ansible all -m shell -a 'echo magedu|passwd --stdin test1' 调用bash执行命令 类似 cat /tmp/stanley.md | awk -F'|' '{print $1,$2}' &> /tmp/example.txt 这些复杂命令,即使使用shell也可能会失败, 解决办法:写到脚本时,copy到远程执行,再把需要的结果拉回执行命令的机器 修改配置文件,使shell作为默认模块 vim /etc/ansible/ansible.cfg module_name = shell
Script 在远程主机上运行ansible服务器上的脚本
1 ansible all -m script -a /data/test.sh
Copy 从主控端复制文件到远程主机
src : 源文件 指定拷贝文件的本地路径 (如果有/ 则拷贝目录内容,比拷贝目录本身)
dest: 指定目标路径
mode: 设置权限
backup: 备份源文件
content: 代替src 指定本机文件内容,生成目标主机文件
1 2 ansible all -m copy -a "src=/root/test1.sh dest=/tmp/test2.sh owner=root mode=600 backup=yes" ansible all -m copy -a "content='test content\nxxx' dest=/tmp/test.txt"
Fetch 从远程主机提取文件至主控端,copy相反,目前不支持目录,可以先打包,再提取文件
1 2 3 4 ansible all -m fetch -a 'src=/root/test.sh dest=/data/scripts' ansible all -m shell -a 'tar jxvf test.tar.gz /root/test.sh' ansible all -m fetch -a 'src=/root/test.tar.gz dest=/data/'
File:设置文件属性
path: 要管理的文件路径 (强制添加)
recurse: 递归,文件夹要用递归
src: 创建硬链接,软链接时,指定源目标,配合’state=link’ ‘state=hard’ 设置软链接,硬链接
state: 状态
1 2 3 4 5 ansible all -m file -a 'path=/app/test.txt state=touch' 创建文件 ansible all -m file -a "path=/data/testdir state=directory" 创建目录 ansible all -m file -a "path=/data/testdir state=absent" 删除 ansible all -m file -a "path=/root/test.sh owner=wang mode=755" 设置权限755 ansible all -m file -a 'src=/data/testfile dest=/data/testfile-link state=link' 创建软链接
unarchive:解包解压缩,有两种用法: 1、将ansible主机上的压缩包传到远程主机后解压缩至特定目录,设置copy=yes. 2、将远程主机上的某个压缩包解压缩到指定路径下,设置copy=no
常见参数:
copy:默认为yes,当copy=yes,拷贝的文件是从ansible主机复制到远程主机上,如果设置为copy=no,会在远程主机上寻找src源文件
src: 源路径,可以是ansible主机上的路径,也可以是远程主机上的路径,如果是远程主机上的路径,则需要设置copy=no
dest:远程主机上的目标路径
mode:设置解压缩后的文件权限
1 2 3 ansible all -m unarchive -a 'src=foo.tgz dest=/var/lib/foo' 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'
Archive:打包压缩
path: 指定路径
dest: 指定目标文件
format: 指定打包格式
owner: 指定所属者
mode: 设置权限
1 ansible all -m archive -a 'path=/etc/sysconfig dest=/data/sysconfig.tar.bz2 format=bz2 owner=wang mode=0777' #将远程主机目录打包
Hostname:管理主机名 1 2 ansible group -m hostname -a "name=app.adong.com" 更改一组的主机名 ansible 192.168.38.103 -m hostname -a "name=app2.adong.com" 更改单个主机名
Cron:计划任务 1 2 3 4 ansible all -m cron -a 'minute=*/5 job="/usr/sbin/ntpdate 172.16.0.1 &>/dev/null" name=Synctime' ansible all -m cron -a 'state=absent name=Synctime' ansible all -m cron -a 'minute=*/10 job="/usr/sbin/ntpdate 172.30.0.100" name=synctime disabled=true'
Yum:管理包 1 2 3 4 5 6 7 ansible all -m yum -a 'list=httpd' ansible all -m yum -a 'name=httpd state=present' ansible all -m yum -a 'name=httpd,vsftpd state=absent' ansible all -m copy -a 'src=/data/software.rpm dest=/dir/' ansible all -m yum -a 'name=dstat update_cache=yes' ansible all -m yum -a 'name=/dir/software.rpm disable_gpg_check=yes'
Service:管理服务 1 2 3 4 ansible all -m service -a 'name=httpd state=stopped' 停止服务 ansible all -m service -a 'name=httpd state=started enabled=yes' 启动服务,并设为开机自启 ansible all -m service -a 'name=httpd state=reloaded' 重新加载 ansible all -m service -a 'name=httpd state=restarted' 重启服务
User:管理用户
home 指定家目录路径
system 指定系统账号
group 指定组
remove 清除账户
shell 指定shell类型
1 2 3 4 5 6 7 8 9 10 ansible all -m user -a 'name=nginx shell=/sbin/nologin system=yes home=/var/nginx groups=root,bin uid=80 comment="nginx service"' ansible all -m user -a 'name=nginx state=absent remove=yes' ansible all -a 'ls /var/ -l' ansible all -a 'getent passwd nginx' ansible all -m user -a 'name=user1 comment="test user" uid=2048 home=/app/user1 group=root' ansible all -m user -a 'name=sysuser1 system=yes home=/app/sysuser1' ansible all -m user -a 'name=user1 state=absent remove=yes' 清空用户所有数据 ansible all -m user -a 'name=app uid=88 system=yes home=/app groups=root shell=/sbin/nologin password="$1$zfVojmPy$ZILcvxnXljvTI2PhP2Iqv1"' 创建用户 ansible all -m user -a 'name=app state=absent' 不会删除家目录
安装mkpasswd
yum insatll expect
mkpasswd 生成口令
openssl passwd -1 生成加密口令
删除用户及家目录等数据
Group:管理组 1 2 ansible all -m group -a "name=testgroup system=yes" 创建组 ansible all -m group -a "name=testgroup state=absent" 删除组
Ansible系列命令 ansible-galaxy
连接 https://galaxy.ansible.com
列出所有已安装的galaxy
安装galaxy
ansible-galaxy install geerlingguy.redis
删除galaxy
ansible-galaxy remove geerlingguy.redis
ansible-pull
ansible-playbook 可以引用按照标准的yml语言写的脚本 执行playbook
1 2 3 4 5 6 7 8 9 10 11 cat hello.yml --- - hosts: internal remote_user: ec2-user tasks: - name: hello world command : /usr/bin/wall hello world
ansible-vault (了解)
1 2 3 4 5 6 7 ansible-vault [create|decrypt|edit|encrypt|rekey|view] ansible-vault encrypt hello.yml 加密 ansible-vault view hello.yml 查看 ansible-vault edit hello.yml 编辑加密文件 ansible-vault rekey hello.yml 修改口令 ansible-vault create new.yml 创建新文件
Ansible-console:2.0+新增,可交互执行命令,支持tab (了解)
1 2 3 4 5 6 7 8 9 [ec2-user@master ~]$ ansible-console Welcome to the ansible console. Type help or ? to list commands. ec2-user@all (3)[f:5]$ cd internal ec2-user@internal (2)[f:5]$ forks 10 ec2-user@internal (2)[f:10]$ list ec2-user@internal (2)[f:10]$ ? 或 help ec2-user@internal (2)[f:10]$ command hostname
YAML语法简介 特性:
YAML的可读性好
YAML和脚本语言的交互性好
YAML使用实现语言的数据类型
YAML有一个一致的信息模型
YAML易于实现
YAML可以基于流来处理
YAML表达能力强,扩展性好
规则
在单一档案中,可用连续三个连字号(——)区分多个档案。另外,还有选择性的连续三个点号( … )用来表示档案结尾
次行开始正常写Playbook的内容,一般建议写明该Playbook的功能
使用#号注释代码
缩进必须是统一的,不能空格和tab混用
缩进的级别也必须是一致的,同样的缩进代表同样的级别,程序判别配置的级别是通过缩进结合换行来实现的
YAML文件内容是区别大小写的,k/v的值均需大小写敏感
多个k/v可同行写也可换行写,同行使用:分隔
v可是个字符串,也可是另一个列表[]
一个完整的代码块功能需最少元素需包括 name 和 task
一个name只能包括一个task
YAML文件扩展名通常为yml或yaml
playbook
playbook是由一个或多个”play”组成的列表
play的主要功能在于将预定义的一组主机,装扮成事先通过ansible中的task定义好的角色。Task实际是调用ansible的一个module,将多个play组织在一个playbook中,即可以让它们联合起来,按事先编排的机制执行预定义的动作
Playbook采用YAML语言编写
Playbook核心元素
Hosts
Tasks
Variables
Templates模板
Handlers和notify结合使用,由特定条件触发的操作,满足条件方才执行,否则不执行
tags标签
指定某条任务执行,用于选择运行playbook中的部分代码。ansible具有幂等性,因此会自动跳过没有变化的部分,即便如此,有些代码为测试其确实没有发生变化的时间依然会非常地长。此时,如果确信其没有变化,就可以通过tags跳过此些代码片断
ansible-playbook -t tagsname useradd.yml
playbook基础组件 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 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:!phoenix 在websrvs组,但不在dbsrvs组 示例: - hosts: websrvs:dbsrvs remote_user: 可用于Host和task中。 也可以通过指定其通过sudo的方式在远程主机上执行任务,其可用于play全局或某任务; 此外,甚至可以在sudo时使用sudo_user指定sudo时切换的用户 - hosts: websrvs remote_user: root (可省略,默认为root) 以root身份连接 tasks: 指定任务 - name: test connection ping: remote_user: magedu sudo: yes 默认sudo为root sudo_user:wang sudo为wang task列表和action 任务列表task:由多个动作,多个任务组合起来的,每个任务都调用的模块,一个模块一个模块执行 1 > play的主体部分是task list,task list中的各任务按次序逐个在hosts中指定的所有主机上执行, 即在所有主机上完成第一个任务后,再开始第二个任务 2 > task的目的是使用指定的参数执行模块,而在模块参数中可以使用变量。 模块执行是幂等的,这意味着多次执行是安全的,因为其结果均一致 3 > 每个task都应该有其name,用于playbook的执行结果输出,建议其内容能清晰地描述任务执行步骤。 如果未提供name,则action的结果将用于输出 tasks:任务列表 两种格式: (1) action: module arguments (2) module: arguments 建议使用 模块: 参数 注意:shell和command模块后面跟命令,而非key=value 某任务的状态在运行后为changed时,可通过"notify"通知给相应的handlers 任务可以通过"tags"打标签,可在ansible-playbook命令上使用-t指定进行调用 示例: tasks: - name: disable selinux 描述 command: /sbin/setenforce 0 模块名: 模块对应的参数 如果命令或脚本的退出码不为零,可以使用如下方式替代 tasks: - name: run this command and ignore the result shell: /usr/bin/somecommand || /bin/true 转错为正 如果命令失败则执行 true 或者使用ignore_errors来忽略错误信息 tasks: - name: run this command and ignore the result shell: /usr/bin/somecommand ignore_errors: True 忽略错误
样例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 --- - hosts: internal remote_user: ec2-user become: yes tasks: - name: create new File file: name=/home/ec2-user/newfile state=touch - name: create new user user: name=test2 shell=/sbin/nologin - name: install package yum: name=httpd - name: copy file copy: src=a.txt dest=/home/ec2-user/ - name: start service service: name=httpd state=started enabled=yes
1 2 3 4 5 ansible internal -a 'getent passwd test2'# 查看用户列表 ansible internal -a 'rpm -q httpd' # 查看是否安装 ansible internal -m file -a 'path=/home/ec2-user/a.txt state=touch' # 创建文件 ansible internal -a 'ls /home/ec2-user/ -l' # 查看文件是否创建成功 ansible internal -m shell -a 'netstat -tln|grep :80'
Playbook选项
运行playbook的方式
ansible-playbook <filename.yml> … [options]1 2 3 4 5 6 7 8 9 10 11 12 13 14 常见选项 --check -C 只检测可能会发生的改变,但不真正执行操作 (只检查语法,如果执行过程中出现问题,-C无法检测出来) (执行playbook生成的文件不存在,后面的程序如果依赖这些文件,也会导致检测失败) --list-hosts 列出运行任务的主机 --list-tags 列出tag (列出标签) --list-tasks 列出task (列出任务) --limit 主机列表 只针对主机列表中的主机执行 -v -vv -vvv 显示过程 示例 ansible-playbook hello.yml --check 只检测 ansible-playbook hello.yml --list-hosts 显示运行任务的主机 ansible-playbook hello.yml --limit websrvs 限制主机
playbook 与 shellscripts(安装httpd) 1 2 3 4 5 6 7 8 9 # !/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,并设置开机启动 service httpd start chkconfig httpd on
1 2 3 4 5 6 7 8 9 10 11 12 13 --- - hosts: all remote_user: root tasks: - name: "安装Apache" yum: name=httpd yum模块:安装httpd - name: "复制配置文件" copy: src=/tmp/httpd.conf dest=/etc/httpd/conf/ copy模块: 拷贝文件 - name: "复制配置文件" copy: src=/tmp/vhosts.conf dest=/etc/httpd/conf.d/ - name: "启动Apache,并设置开机启动" service: name=httpd state=started enabled=yes service模块: 启动服务
示例:Playbook 创建用户
1 2 3 4 5 6 7 8 9 10 --- - hosts: all remote_user: root tasks: - name: create mysql user user: name=mysql system=yes uid=36 - name: create a group group: name=httpd system=yes
Playbook示例 安装httpd服务 1 2 3 4 5 6 7 8 9 10 11 - hosts: websrvs 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/ - name: start service service: name=httpd state=started enabled=yes
Playbook示例 安装nginx服务 1 2 3 4 5 6 7 8 9 10 11 12 13 - hosts: all remote_user: root 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: Start Nginx service: name=nginx state=started enabled=yes
handlers和notify结合使用触发条件
Handlers 实际上就是一个触发器
是task列表,这些task与前述的task并没有本质上的不同,用于当关注的资源发生变化时,才会采取一定的操作
Notify此action可用于在每个play的最后被触发,这样可避免多次有改变发生时每次都执行指定的操作,仅在所有的变化发生完成后一次性地执行指定操作。在notify中列出的操作称为handler,也即notify中调用handler中定义的操作
Playbook中handlers使用 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 - hosts: websrvs 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 - name: ensure apache is running service: name=httpd state=started enabled=yes handlers: - name: restart ht tpd service: name=httpd state=restarted
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 - hosts: websrvs remote_user: root tasks: - name: add group nginx tags: user 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
tage: 添加标签 可以指定某一个任务添加一个标签,添加标签以后,想执行某个动作可以做出挑选来执行 多个动作可以使用同一个标签
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 - hosts: websrvs remote_user: root tasks: - name: Install httpd yum: name=httpd state=present tage: install - name: Install configure file copy: src=files/httpd.conf dest=/etc/httpd/conf/ tags: conf - name: start httpd service tags: service service: name=httpd state=started enabled=yes ansible-playbook –t install,conf httpd.yml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 - hosts: hbhosts remote_user: root tasks: - name: ensure heartbeat latest version yum: name=heartbeat state=present - name: authkeys configure file copy: src=/root/hb_conf/authkeys dest=/etc/ha.d/authkeys - name: authkeys mode 600 file: path=/etc/ha.d/authkeys mode=600 notify: - restart heartbeat - name: ha.cf configure file copy: src=/root/hb_conf/ha.cf dest=/etc/ha.d/ha.cf notify: - restart heartbeat handlers: - name: restart heartbeat service: name=heartbeat state=restarted - hosts: testsrv remote_user: root tags: inshttpd tasks: - name: Install httpd yum: name=httpd state=present - name: Install configure file copy: src=files/httpd.conf dest=/etc/httpd/conf/ tags: rshttpd notify: restart httpd handlers: - name: restart httpd service: name=httpd status=restarted ansible-playbook –t rshttpd httpd2.yml
Playbook中变量的使用 变量名:仅能由字母、数字和下划线组成,且只能以字母开头
变量来源:
ansible setup facts 远程主机的所有变量都可直接调用 (系统自带变量)setup模块可以实现系统中很多系统信息的显示可以返回每个主机的系统信息包括:版本、主机名、cpu、内存1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 ansible all -m setup -a 'filter="ansible_nodename"' ansible all -m setup -a 'filter="ansible_memtotal_mb"' ansible all -m setup -a 'filter="ansible_distribution_major_version"' ansible all -m setup -a 'filter="ansible_processor_vcpus"' ``` 2. 在/etc/ansible/hosts(主机清单)中定义变量 - 普通变量:主机组中主机单独定义,优先级高于公共变量(单个主机 ) - 公共(组)变量:针对主机组中所有主机定义统一变量(一组主机的同一类别) 3. 通过命令行指定变量,优先级最高 - ansible-playbook –e varname=value 4. 在playbook中定义 ```yml vars: - var1: value1 - var2: value2
在独立的变量YAML文件中定义
在role中定义
变量命名: 变量名仅能由字母、数字和下划线组成,且只能以字母开头
变量定义:key=value, 示例:http_port=80
变量调用方式:
通过 调用变量,且变量名前后必须有空格,有时用“”才生效
ansible-playbook –e 选项指定
ansible-playbook test.yml -e “hosts=www user=magedu”
在主机清单中定义变量,在ansible中使用变量
1 2 3 4 [internal ] 192.168 .38 .17 http_port=817 name=www 192.168 .38 .27 http_port=827 name=web
调用变量 ansible internal -m hostname -a’name=‘ 更改主机名为各自被定义的变量
针对一组设置变量 [internal:vars] make=”-“
ansible internal -m hostname -a ‘name=‘ ansible调用变量
将变量写进单独的配置文件中引用 vim vars.yml pack: vsftpd service: vsftpd
引用变量文件 vars_files:
Ansible基础元素 Facts:是由正在通信的远程目标主机发回的信息,这些信息被保存在ansible变量中。要获取指定的远程主机所支持的所有facts,可使用如下命令进行
通过命令行传递变量,在运行playbook的时候也可以传递一些变量供playbook使用,示例:
ansible-playbook test.yml -e “hosts=www user=magedu”
register 把任务的输出定义为变量,然后用于其他任务
示例:
1 2 3 4 tasks: - shell: /usr/bin/foo register: foo_result ignore_errors: True
示例:使用setup变量 1 2 3 4 5 6 - hosts: websrvs remote_user: root tasks: - name: create log file file: name=/var/log/ {{ ansible_fqdn }} state=touch
ansible-playbook var.yml
示例:变量 1 2 3 4 5 6 7 8 - hosts: websrvs remote_user: root tasks: - name: install package yum: name={{ pkname }} state=present ansible-playbook –e pkname=httpd var.yml
示例:变量 1 2 3 4 5 6 7 8 9 10 11 12 13 14 - hosts: websrvs remote_user: root vars: - username: user1 - groupname: group1 tasks: - name: create group group: name={{ groupname }} state=present - name: create user user: name={{ username }} state=present ansible-playbook var.yml ansible-playbook -e "username=user2 groupname=group2” var2.yml
变量
主机变量: 可以在inventory中定义主机时为其添加主机变量以便于在playbook中使用
示例:
1 2 3 [websrvs] www1.magedu.com http_port=80 maxRequestsPerChild=808 www2.magedu.com http_port=8080 maxRequestsPerChild=909
组变量: 组变量是指赋予给指定组内所有主机上的在playbook中可用的变量
示例:
1 2 3 4 5 6 7 [websrvs ] www1.magedu.com www2.magedu.com [websrvs:vars ] ntp_server=ntp.magedu.com nfs_server=nfs.magedu.com
示例:变量
示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 [apache ] httpd1.magedu.com httpd2.magedu.com [nginx ] ngx1.magedu.com ngx2.magedu.com [websrvs:children ] apache nginx [webservers:vars ] ntp_server=ntp.magedu.com
invertory参数
invertory参数:用于定义ansible远程连接目标主机时使用的参数,而非传递给playbook的变量1 2 3 4 5 6 7 8 9 10 11 ansible_ssh_host ansible_ssh_port ansible_ssh_user ansible_ssh_pass ansbile_sudo_pass 示例: cat /etc/ansible/hosts [websrvs ] 192.168 .0 .1 ansible_ssh_user=root ansible_ssh_pass=magedu 192.168 .0 .2 ansible_ssh_user=root ansible_ssh_pass=magedu
invertory参数
inventory参数: ansible基于ssh连接inventory中指定的远程主机时,还可以通过参数指定其交互方式; 这些参数如下所示:1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 ansible_ssh_host The name of the host to connect to, if different from the alias you wishto give to it. ansible_ssh_port The ssh port number, if not 22 ansible_ssh_user The default ssh user name to use. ansible_ssh_pass The ssh password to use (this is insecure, we strongly recommendusing --ask-pass or SSH keys) ansible_sudo_pass The sudo password to use (this is insecure, we strongly recommendusing --ask-sudo-pass) ansible_connection Connection type of the host. Candidates are local, ssh or paramiko. The default is paramiko before Ansible 1.2 , and 'smart' afterwards which detects whether usage of 'ssh' would be feasible based on whether ControlPersist is supported. ansible_ssh_private_key_file Private key file used by ssh. Useful if using multiple keys and you don't want to use SSH agent. ansible_shell_type The shell type of the target system. By default commands are formatted using 'sh' -style syntax by default. Setting this to 'csh' or 'fish' will cause commands executed on target systems to follow those shell's syntax instead. ansible_python_interpreter The target host python path. This is useful for systems with more than one Python or not located at "/usr/bin/python" such as \*BSD, or where /usr/bin/python is not a 2. X series Python. We do not use the "/usr/bin/env" mechanism as that requires the remote user's path to be set right and also assumes the "python" executable is named python,where the executable might be named something like "python26" . ansible\_\*\_interpreter Works for anything such as ruby or perl and works just like ansible_python_interpreter. This replaces shebang of modules which will run on that host.
ansible配置不同系统的nginx进程数
要求:根据系统CPU核数修改nginx进程数(默认auto)
模板 templates
文本文件,嵌套有脚本(使用模板编程语言编写) 借助模板生成真正的文件
Jinja2语言,使用字面量,有下面形式
字符串:使用单引号或双引号
数字:整数,浮点数
列表:[item1, item2, …]
元组:(item1, item2, …)
字典:{key1:value1, key2:value2, …}
布尔型:true/false
算术运算:+, -, *, /, //, %, **
比较操作:==, !=, >, >=, <, <=
逻辑运算:and,or,not
流表达式:For,If,When
Jinja2相关 字面量
表达式最简单的形式就是字面量。字面量表示诸如字符串和数值的 Python对象。如“Hello World”双引号或单引号中间的一切都是字符串。
无论何时你需要在模板中使用一个字符串(比如函数调用、过滤器或只是包含或继承一个模板的参数),如4242.23
数值可以为整数和浮点数。如果有小数点,则为浮点数,否则为整数。在Python 里, 42 和 42.0 是不一样的
逻辑运算符 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 对于 if 语句,在 for 过滤或 if 表达式中,它可以用于联合多个表达式 and 如果左操作数和右操作数同为真,返回 true or 如果左操作数和右操作数有一个为真,返回 true not 对一个表达式取反(见下) (expr) 表达式组 你可以容易地在 for循环中用列表和元组创建一个链接的列表 <ul> {% for href, caption in [('index.html', 'Index'), ('about.html', 'About'), ('downloads.html', 'Downloads')] %} <li><a href="{{ href }}">{{ caption }}</a></li> {% endfor %} </ul> ('tuple', 'of', 'values'): 元组与列表类似,只是你不能修改元组。 如果元组中只有一个项,你需要以逗号结尾它。 元组通常用于表示两个或更多元素的项。更多细节见上面的例子 {'dict': 'of', 'key': 'and', 'value': 'pairs'}: Python 中的字典是一种关联键和值的结构。 键必须是唯一的,并且键必须只有一个 值。 字典在模板中很少使用,罕用于诸如 xmlattr() 过滤器之类 true / false: true 永远是 true ,而 false 始终是 false
template 的使用 template功能:根据模块文件动态生成对应的配置文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 > template文件必须存放于templates目录下,且命名为 .j2 结尾 > yaml/yml 文件需和templates目录平级,目录结构如下: ./ ├── temnginx.yml └── templates └── nginx.conf.j2 ``` 示例:利用template 同步nginx配置文件 ```yml - hosts: websrvs remote_user: root tasks: - name: template config to remote hosts template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf
ansible-playbook temnginx.
Playbook中template变更替换修改文件nginx.conf.j2 下面行为
1 2 3 4 5 6 7 8 worker_processes {{ ansible_processor_vcpus }}; cat temnginx2.yml - hosts: websrvs remote_user: root tasks: - name: template config to remote hosts template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf
ansible-playbook temnginx2.yml
Playbook中template算术运算 算法运算: 示例:
1 2 3 # vim nginx.conf.j2 worker_processes {{ ansible_processor_vcpus**2 }}; worker_processes {{ ansible_processor_vcpus+2 }};
when 实现条件判断 条件测试:如果需要根据变量、facts或此前任务的执行结果来做为某task执行与否的前提时要用到条件测试,通过when语句实现,在task中使用,jinja2的语法格式
when语句
在task后添加when子句即可使用条件测试;when语句支持Jinja2表达式语法
示例:1 2 3 4 tasks: - name: "shutdown RedHat flavored systems" command: /sbin/shutdown -h now when: ansible_os_family == "RedHat" 当系统属于红帽系列,执行command模块
when语句中还可以使用Jinja2的大多”filter”, 例如要忽略此前某语句的错误并基于其结果(failed或者success)运行后面指定的语句, 可使用类似如下形式:1 2 3 4 5 6 7 8 9 10 tasks: - command: /bin/false register: result ignore_errors: True - command: /bin/something when: result|failed - command: /bin/something_else when: result|success - command: /bin/still/something_else when: result|skipped
此外,when语句中还可以使用facts或playbook中定义的变量示例:when条件判断 1 2 3 4 5 6 7 8 9 10 11 12 13 - hosts: websrvs remote_user: root tasks: - name: add group nginx tags: user 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: restart Nginx service: name=nginx state=restarted when: ansible_distribution_major_version == "6"
示例:when条件判断 1 2 3 4 5 6 7 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"
迭代:with_items 迭代:当有需要重复性执行的任务时,可以使用迭代机制
对迭代项的引用,固定变量名为”item”
要在task中使用with_items给定要迭代的元素列表
列表格式:
1 2 3 4 5 6 - name: add several users user: name={{ item }} state=present groups=wheel with_items: - testuser1 - testuser2
上面语句的功能等同于下面的语句:
1 2 3 4 - name: add user testuser1 user: name=testuser1 state=present groups=wheel - name: add user testuser2 user: name=testuser2 state=present groups=wheel
with_items中可以使用元素还可为hashes 1 2 3 4 5 6 - name: add several users user: name={{ item.name }} state=present groups={{ item.groups }} with_items: - { name: 'testuser1' , groups: 'wheel' } - { name: 'testuser2' , groups: 'root' }
ansible的循环机制还有更多的高级功能,具体请参见官方文档http://docs.ansible.com/playbooks_loops.html
示例:迭代 示例:将多个文件进行copy到被控端
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 --- - hosts: testsrv remote_user: root tasks - name: Create rsyncd config copy: src={{ item }} dest=/etc/{{ item }} with_items: - rsyncd.secrets - rsyncd.conf - hosts: websrvs remote_user: root tasks: - name: copy file copy: src={{ item }} dest=/tmp/{{ item }} with_items: - file1 - file2 - file3 - name: yum install httpd yum: name={{ item }} state=present with_items: - apr - apr-util - httpd - 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 tasks: - name: add some groups group: name={{ item }} state=present with_items: - group1 - group2 - group3 - name: add some users user: name={{ item.name }} group={{ item.group }} state=present with_items: - { name: 'user1' , group: 'group1' } - { name: 'user2' , group: 'group2' } - { name: 'user3' , group: 'group3' } 示例 --- - hosts: testweb remote_user: root tasks: - name: add several users user: name={{ item.name }} state=present groups={{ item.groups }} with_items: - { name: 'testuser1' , groups: 'wheel' } - { name: 'testuser2' , groups: 'root' } - name: 使用ufw模块来管理哪些端口需要开启 ufw: rule: “{{ item.rule }}” port: “{{ item.port }}” proto: “{{ item.proto }}” with_items: - { rule: 'allow' , port: 22 , proto: 'tcp' } - { rule: 'allow' , port: 80 , proto: 'tcp' } - { rule: 'allow' , port: 123 , proto: 'udp' } - name: 配置网络进出方向的默认规则 ufw: direction: "{{ item.direction }} " policy: "{{ item.policy }} " state: enabled with_items: - { direction: outgoing , policy: allow } - { direction: incoming , policy: deny } {% for vhost in nginx_vhosts % } server { listen {{ vhost.listen | default('80 default_server') }}; {% if vhost.server_name is defined % } server_name {{ vhost.server_name }}; {% endif % } {% if vhost.root is defined % } root {{ vhost.root }}; {% endif % } {% endfor % } --- - hosts: testweb remote_user: root vars: nginx_vhosts: - listen: 8080 {% for vhost in nginx_vhosts % } server { listen {{ vhost.listen }} } {% endfor % } server { listen 8080 } --- - hosts: mageduweb remote_user: root vars: nginx_vhosts: - web1 - web2 - web3 tasks: - name: template config template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf {% for vhost in nginx_vhosts % } server { listen {{ vhost }} } {% endfor % } server { listen web1 } server { listen web2 } server { listen web3 }