运维之ansible
ansible
与salt对比
- 相同
- 都是为了同时在多台机器上执行相同的命令
- 都是python开发
- 不同
- agent(saltstack需要安装、ansible不需要)
- 配置(salt配置麻烦,ansible基本不用配置)
- 学习路线(salt比较陡峭,ansible比较平缓)
- 第三方工具(salt比较少)
- 开源社区的对接(salt比较少)
- 现有用户(salt还是ansible少一些)
- 二次开发扩展的能力(ansible比较差,尤其是2.0以后)
- 大规模并发(200以内一样,200以上salt会好一些,当然我们也可以对ansible做一些配置使其在200以上追上salt)
- Windows的支持(salt会好很多)
安装
yum install -y ansible
查看ansible生成的命令,用到的命令
ansible
ansible-doc
ansible-galaxy(下载第三方插件)
ansible-playbook
查看ansible 安装生成的
rpm -ql ansible |more
/etc/ansible
/etc/ansible/ansible.cfg #配置文件
/etc/ansible/hosts #主要文件
hosts文件详解
cat /etc/ansible/hosts
# This is the default ansible 'hosts' file.
#
# It should live in /etc/ansible/hosts
#
# - Comments begin with the '#' character #注释为#
# - Blank lines are ignored #空白行被忽略
# - Groups of hosts are delimited by [header] elements #主机组名被写在[]里面
# - You can enter hostnames or ip addresses #你可以写ip地址也可以写hostnames
# - A hostname/ip can be a member of multiple groups #一个主机可以被多个主机组包含
可以在hosts文件中填写的内容
ansible_ssh_host
ansible通过ssh连接的IP或者FQDN
ansible_ssh_port
SSH连接端口
ansible_ssh_user
默认SSH连接用户
ansible_ssh_pass
SSH连接的密码(这是不安全的,ansible极力推荐使用--ask-pass选项或使用SSH keys)
ansible_sudo_pass
sudo用户的密码
ansible_connection
SSH连接的类型:local,ssh,paramiko,在ansible 1.2之前默认是paramiko,后来智能选择,优先使用基于ControlPersist的ssh(支持的前提)
ansible_ssh_private_key_file
SSH连接的公钥文件
查看ansible的命令帮助
ansible <host-pattern> [options]
-a MODULE_ARGS 模块参数
-m MODULE_NAME 模块名称
-f forks 指定一次执行的机器
-C 测试
--list-hosts 查看运行的机器
-v 输出详细信息
第一个ansible程序
ansible test -m ping
获取文档
ansible-doc --help
-s 指定模块名称
-l 列出所有的模块
操作日志
/var/log/message
命令相关
shell command script
command模块 [执行远程命令]
ansible all -a 'echo "hello world"'
ansible all -a 'pwd'
ansible all -a 'echo "oldboy"|passwd --stdin user1' #直接输出结果
script模块 [在远程主机执行主控端的shell/python脚本 ] (使用相对路径)
ansible all -m script -a 'a.sh' #执行本地脚本
ansible all -a 'ls /' #查看文件目录
shell模块 [执行远程主机的shell/python脚本,支持管道]
ansible all -m shell -a 'echo oldboy|passwd --stdin user1' #设置密码
ansible all -m shell -a 'cat /etc/shadow|grep user1' #查看用户
ansible all -m shell -a 'python a.py' #执行远程脚本
文件相关
copy
dest 目标地址
src 本地地址
mode 权限 wrx/755
owner 属主
group 属组
backup
content 直接写内容,可以用转移符号
ansible all -m copy -a 'dest=/data src=/data/a.txt' #复制单个文件
ansible all -m copy -a 'src=/etc/init.d dest=/data/'
ansible all -m copy -a 'src=/etc/init.d/ dest=/data' #如果带/则复制里面的内容,不带/则复制目录,如果是目录的话,则会递归复制
ansible all -m copy -a 'content="hello world" dest=/data/test.txt' 直接输入内容
file
path
src
state
file file代表拷贝后是文件
link link代表最终是个软链接
directory directory代表文件夹
hard hard代表硬链接
touch touch代表生成一个空文件
absent absent代表删除
ansible all -m file -a 'dest=/data/html state=directory' #创建目录
ansible all -m file -a 'dest=/data/html2 state=link src=/etc' #创建软链接
ansible all -m file -a 'dest=/data/a.txt state=touch'
ansible all -m file -a 'dest=/data/a.txt state=absent' 删除
fetch
dest
src
ansible 10.211.55.14 -m fetch -a 'src=/data/test.txt dest=/data'
软件相关
pip
ansible all -m pip -a 'name=django==1.11'
yum
name
state
absent #卸载
installed #安装
latest #安装最新的版本
present #安装
removed #卸载
ansible all -m yum -a 'name=python-pip state=latest'
ansible all -m yum -a 'name=nginx state=latest'
ansible all -m yum -a 'name=nginx state=absent'
service
name
state
ansible all -m service -a 'name=nginx state=started'
ansible all -m service -a 'name=nginx state=stopped'
cron
name
weekday 周
hour 时
day 天
minute 分钟
month 月
job
state
absent #删除
present #创建
ansible all -m cron -a 'name=testjob minute=1 job=ntpdate'
ansible all -m cron -a 'name=testjob state=absent'
user
name
password
shell
state
uid
group
groups
update_password
home
ansible all -m user -a 'name=usertest'
ansible all -m user -a 'name=usertest state=absent'
group
gid
name
state #present 创建 absent 删除
system #是否是系统组
ansible all -m group -a 'name=usertest '
ansible all -m group -a 'name=usertest state=absent'
playbook 剧本
操作都是幂等的
- 什么是幂等的
- 操作过以后就不会操作了
为什么要用playbook
- 有一个更好的知识沉淀
- 有一些好的功能
知识回顾
ymal
格式
- 字典:
- key : value 冒号后面必须有空格
- 列表:
- -
建议一个文件处理一个对应一组相关的任务
ansible-playbook [options] playbook.yml
-C # 干跑,检查
-f FORKS # 用来做并发,来指定并发数
--list-hosts #列出执行命令的主机
--syntax-check # 检查语法
--list-tasks #列出playbook要执行的任务列表
-t TAGS, #指定要运行到tags
-e EXTRA_VARS #给playbook传递变量
#单个playbook
- hosts: web #指定要运行命令的主机
remote_user: root # 指定运行命令的用户
tasks: #任务列表
- name: mkdir # 任务1,name是必须的
file: path=/data state=directory # 指定的模块: 模块的参数
- name: copyfile
copy: src=/etc/fstab dest=/data/f
##多个playbook
- hosts: web
remote_user: root
tasks:
- name: mkdir
file: path=/data state=directory
- name: copyfile
copy: src=/etc/fstab dest=/data/f
- hosts: db
remote_user: root
tasks:
- name: wget
shell: "wget -O /data/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo"
##指定tags
- hosts: web
remote_user: root
tasks:
- name: mkdir
file: path=/data state=directory
- name: copyfile
copy: src=/etc/fstab dest=/data/f
tags: copyfile
任务是从上到下依次执行,每台机器都执行完才执行下一个任务
变量引入
- 写一个playbook,需要多次创建,比如每次需要创建的不同的用户
第一种设置变量的方法
## 传递变量 -e"key=value"
- hosts: web
remote_user: root
tasks:
- name: yum {{pkg_name}} pkg
yum: name={{pkg_name}}
第二种设置变量的方法
- hosts: web
remote_user: root
vars:
- pkg_name: memcached
tasks:
- name: yum {{pkg_name}} pkg
yum: name={{pkg_name}}
第三种设置变量的方法
#在hosts文件里面写,值可以不同
[web]
192.168.19.9 pkg_name=nginx
192.168.19.26 pkg_name=redis
第四种设置变量的方法
[web:vars]
pkg_name=nginx
第五种传参方式
第五种传参方式: 通过register注册,直接用.stdout来获取值
- hosts: db
remote_user: root
tasks:
- name: installbc
yum: name=bc
- name: sum
shell: echo 20+21|bc
register: sum
- name: echo
shell: echo {{sum}} > /tmp/sum.txt
- name: createuser
user: name=alex{{sum.stdout}}
变量的应用顺序
-e > yml文件 > hosts文件 #命令行里面是最高的,hosts文件是最低的
条件
when 条件判断
- hosts: cache
remote_user: root
tasks:
- name: copyfile1
copy: content='大弦嘈嘈如急雨' dest=/tmp/a.txt
when: ansible_os_family=="RedHat" #只有为真的时候才会执行上面的操作
- name: copyfile2
copy: content='小弦切切如私语' dest=/tmp/b.txt
when: ansible_os_family=="OpenBSD"
循环
with_item 循环添加
- hosts: cache
remote_user: root
tasks:
- name: create user
user: name={{item}} ## 循环下面的with_items
with_items:
- yuchao
- yantao
- name: create group
group: name={{item}}## 循环下面的with_items
with_items:
- yuchao2
- yantao2
循环嵌套
- hosts: cache
remote_user: root
tasks:
- name: create group
group: name={{item}}
with_items:
- yuchao4
- yantao4
- name: create user
user: name={{item.name}} group={{item.group}} #可以通过字典取值
with_items:
- {"name":yuchao3,"group":yuchao4}
- {"name":yantao3,"group":yuchao4}
服务启动
- hosts: web
remote_user: root
vars:
- pkg_name: nginx
tasks:
- name: yum {{pkg_name}} pkg
yum: name={{pkg_name}} state=installed
- name: start
service: name={{pkg_name}} state=started
handlers(每次变更文件需要重启服务)
- hosts: web
remote_user: root
vars:
- pkg_name: nginx
tasks:
- name: yum {{pkg_name}} pkg
yum: name={{pkg_name}} state=installed
- name: copyfile
copy: src=nginx.conf dest=/etc/nginx/nginx.conf
notify: restart #变更后才会触发handlers的任务
handlers:
- name: restart
service: name={{pkg_name}} state=restarted
template
基于janja2语言
- hosts: cache
remote_user: root
tasks:
- name: install redis
yum: name=redis
- name: copyfile
template: src=redis.conf.j2 dest=/etc/redis.conf ## 模板基于jinja2
- name: start
service: name=redis state=started
#模板文件放在templates,可以直接用相对路径去调用配置文件
roles
作用:
- 结构清晰
- 可以重用
tasks #目录是必须的,存放任务
templates #是存放模板
vars #用来存放变量 ### 切记,不能加-,加-报错
files #用来存放文件
mkdir -p {nginx,uwsgi,mysql}/{tasks,templates,vars,files} #创建目录结构的命令
hosts: web
remote_user: root
roles:
- role: nginx
tags: [ 'web','nginx'] # 指定tags
- { role: http,tags: [ 'web','http']} # 指定tags
用 -t 来调用
- hosts: web
remote_user: root
roles:
- role: nginx
tags: [ 'web','nginx']
when: ansible_distribution_major_version== "7" # 条件
- role: http
tags: [ 'web','http']
when: ansible_distribution_major_version== "6" # 条件
Ansible Galaxy
Ansible Galaxy 是一个自由网站,网站提供所有类型的由社区开发的 roles,这对于实现你的自动化项目是一个很好的参考。网站提供这些 roles 的排名、查找以及下载。
应用实例
你现在已经学过 tasks 和 handlers,那怎样组织 playbook 才是最好的方式呢?简单的回答就是:使用 roles ! Roles 基于一个已知的文件结构,去自动的加载某些 vars_files,tasks 以及 handlers。基于 roles 对内容进行分组,使得我们可以容易地与其他用户分享 roles 。
如果 roles/x/tasks/main.yml 存在, 其中列出的 tasks 将被添加到 play 中
如果 roles/x/handlers/main.yml 存在, 其中列出的 handlers 将被添加到 play 中
如果 roles/x/vars/main.yml 存在, 其中列出的 variables 将被添加到 play 中
如果 roles/x/meta/main.yml 存在, 其中列出的 “角色依赖” 将被添加到 roles 列表中 (1.3 and later)
所有 copy tasks 可以引用 roles/x/files/ 中的文件,不需要指明文件的路径。
所有 script tasks 可以引用 roles/x/files/ 中的脚本,不需要指明文件的路径。
所有 template tasks 可以引用 roles/x/templates/ 中的文件,不需要指明文件的路径。
所有 include tasks 可以引用 roles/x/tasks/ 中的文件,不需要指明文件的路径。
production # inventory file for production servers 关于生产环境服务器的清单文件
stage # inventory file for stage environment 关于 stage 环境的清单文件
group_vars/
group1 # here we assign variables to particular groups 这里我们给特定的组赋值
group2 # ""
host_vars/
hostname1 # if systems need specific variables, put them here 如果系统需要特定的变量,把它们放置在这里.
hostname2 # ""
library/ # if any custom modules, put them here (optional) 如果有自定义的模块,放在这里(可选)
filter_plugins/ # if any custom filter plugins, put them here (optional) 如果有自定义的过滤插件,放在这里(可选)
site.yml # master playbook 主 playbook
webservers.yml # playbook for webserver tier Web 服务器的 playbook
dbservers.yml # playbook for dbserver tier 数据库服务器的 playbook
roles/
common/ # this hierarchy represents a "role" 这里的结构代表了一个 "role"
tasks/ #
main.yml # <-- tasks file can include smaller files if warranted
handlers/ #
main.yml # <-- handlers file
templates/ # <-- files for use with the template resource
ntp.conf.j2 # <------- templates end in .j2
files/ #
bar.txt # <-- files for use with the copy resource
foo.sh # <-- script files for use with the script resource
vars/ #
main.yml # <-- variables associated with this role
defaults/ #
main.yml # <-- default lower priority variables for this role
meta/ #
main.yml # <-- role dependencies
webtier/ # same kind of structure as "common" was above, done for the webtier role
monitoring/ # ""
fooapp/ # ""
site.yml
在 site.yml 中,我们包含了一个定义了整个基础设施的 playbook.注意这个 playbook 是非常短的, 因为它仅仅包含了其他 playbooks.记住, playbook 不过就是一系列的 plays:
---
# file: site.yml
- include: webservers.yml
- include: dbservers.yml
在诸如 like webservers.yml 的文件中(同样也在顶层结构),我们仅仅将 Web 服务器组与对应的 role 行为做映射.同样值得注意的是这也非常的短小精悍.例如:
---
# file: webservers.yml
- hosts: webservers
roles:
- common
- webtier
理念是我们能够通过 “运行”(running) site.yml 来选择整个基础设施的配置.或者我们能够通过运行其子集 webservers.yml 来配置. 这与 Ansible 的 “–limit” 类似,而且相对的更为显式:
ansible-playbook site.yml --limit webservers
ansible-playbook webservers.yml
接下来的示例任务文件展示了一个 role 是如何工作的.我们这里的普通 role 仅仅用来配置 NTP,但是如果我们想的话,它可以做更多:
---
# file: roles/common/tasks/main.yml
- name: be sure ntp is installed
yum: pkg=ntp state=installed
tags: ntp
- name: be sure ntp is configured
template: src=ntp.conf.j2 dest=/etc/ntp.conf
notify:
- restart ntpd
tags: ntp
- name: be sure ntpd is running and enabled
service: name=ntpd state=running enabled=yes
tags: ntp
这是个处理文件样例.作为一种审核,它只有当特定的任务报告发生变化时会被触发,并在每个 play 结束时运行:
---
# file: roles/common/handlers/main.yml
- name: restart ntpd
service: name=ntpd state=restarted