ansible
自动化运维工具
- shell脚本
- ansible
- saltstack
服务器部署的流程
服务器 ->安装操作系统 -> 环境部署 -> 软件部署 -> 配置部署 ->启动服务 -> 加入集群
Ansible基础架构
1. 连接插件(connection plugin) 连接客户端
2. 主机清单(Host Inventory) 定义ansible需要操作的主机的范围
3. 核心模块 (Core Modules) 依赖于ansilbe自带的模块执行ansible命令
4. 自定义模块 (Custom Modules) 自定义模块执行ansible命令
5. 任务剧本 (playbooks) ansible的配置文件, 将多个任务定义在剧本中, 由ansible自动执行
6. 插件 (plugins) 邮件插件, 日志插件
Ansible安装配置
准备机器
192.168.43.3 管控节点
192.168.43.14 被管控节点
192.168.43.15 被管控节点
192.168.43.16 被管控节点
192.168.43.17 被管控节点
管控节点安装ansilbe
$ curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo
$ yum install -y ansible
ssh部署公钥到被管控节点
$ ssh-copy-id -i ~/.ssh/id_rsa.pub root@192.168.43.14
$ ssh-copy-id -i ~/.ssh/id_rsa.pub root@192.168.43.15
$ ssh-copy-id -i ~/.ssh/id_rsa.pub root@192.168.43.16
$ ssh-copy-id -i ~/.ssh/id_rsa.pub root@192.168.43.17
ansible 命令格式
Usage: ansible <host-pattern> [options]
-a MODULE_ARGS 模块参数
-C, --check 检查语法
-f FORKS 并发
--list-hosts 列出主机列表
-m MODULE_NAME 模块名字
ssh 认证方式
-
密码
-
秘钥
-
ssh-keygen 生成密钥对
-
ssh-copy-id 复制公钥到远程主机
-
私钥加密,公钥解密
-
查看ansible生成的文件
rpm -ql ansible
/etc/ansible
/etc/ansible/ansible.cfg # ansible 配置文件
/etc/ansible/hosts
/etc/ansible/roles
ansible第一条命令
ansible 192.168.43.15 -m ping ping一台机器
ansible 192.168.43.15,192.168.43.16 -m ping ping多台机器
ansible all -m ping ping所有机器
ansible web -m ping ping一个组
ansible "web:&db" -m ping ping web组和db组的都有的机器(交集)
ansible "web:db" -m ping ping web组和db组的所有的机器(并集)
ansible 'web:!db' -m ping ping web组中有的但是db组中没有的机器
ansible'!web:db' -m ping ping web组中没有的但是db中有的机器
hosts文件内容
# 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地址
# - A hostname/ip can be a member of multiple groups 一台主机可以被分配多个组
www[001:006].example.com www001到www006.example.com
host-pattern格式
- 单个机器
- 多个机器, 逗号隔开
- 全部机器,all
- 可以写一个分组
- 可以写多个分组
- 并集
- 逗号隔开
- 冒号隔开
- 交集: :& 隔开
- 差集: 两台主机组之间用冒号隔开,在不包括差集机器的主机组前加上& (比如 web:!db,!web:db )
- 并集
查看模块帮助信息
ansible-doc [-l|-F|-s] [options] [-t <plugin type> ] [plugin]
-j 以json格式显示所有模块信息
-l 列出所有模块
-s 显示模块的摘要信息
# 不加任何选项,则显示模块的所有帮助信息
ansible 特性: 幂等性
同样的数据不进行第二次相同的操作
命令相关
removes和creates 起到判断的作用 (判断的是被管控机上的文件是否存在)
- removes: 如果条件存在,则执行后面的命令
- creates: 如果条件存在,则不执行后面的命令
ansible web -a 'ls'
ansible web -a 'chdir=/tmp pwd' #先切换目录, 再执行命令pwd 一般情况下在编译时候使用
ansible web -a 'creates=/tmp pwd' #如果creates的文件存在,则不执行后面的命令
ansible web -a 'removes=/tmp pwd' #如果creates的文件存在,则执行后面的命令
ansible web -a 'removes=/tmp mkdir /data' #会执行后面的mkdir命令
ansible web -a 'creates=/data2 mkdir /data2' #会执行后面的mkdir 命令
补充
查看用户是否被创建成功
tail -1 /etc/passwd
tail -1 /etc/shadow
id <用户名>
echo '<密码>' |passwd --stdin <用户名> 非交互式设置密码
shell
< > | ; & $ 这些特殊字符command不支持
ansible web -a "useradd alex" 对web组的机器创建用户alex
ansible web -m shell -a 'echo '1'|passwd --stdin alex' 设置alex的密码
ansible 192.168.43.15 -m shell -a '/root/a.sh' 执行目标机器上的shell脚本,前提是脚本有可执行权限
ansible 192.168.43.15 -m shell -a '/root/a.py' 执行目标机器上python脚本,前提是脚本有可执行权限
script
ansible db -m script -a '/root/m.sh' 执行管控机上的文件
ansible web -m script -a 'creates=/root/a.sh /root/m.sh' #查看的是被管控机上的文件是否存在
文件相关的模块
copy
ansible db -m copy -a 'dest=/tmp/a.sh src=/root/m.sh' 复制文件到远程主机
ansible db -m copy -a 'dest=/tmp/a.sh src=/root/m.sh backup=yes' 复制文件并备份远程文件
#如果之前执行过一次 ansible db -m copy -a 'dest=/tmp/a.sh src=/root/m.sh‘, 并且m.sh里的数据没有任何改变, 此时再加上参数backup=yes, 根据ansible幂等性特性,执行不成功
nsible web -m copy -a 'dest=/tmp/a.sh src=/root/m.sh owner=alex mode=700' 修改复制后的文件的属主和权限
ansible web -m copy -a "src=/etc/init.d dest=/tmp" 复制目录到远程主机
ansible web -m shell -a "ls /tmp" 复制目录里面的文件到远程主机
ansible web -m copy -a "src=/etc/ansible dest=/tmp owner=alex" 复制目录到远程主机,并修改目录的属主,并且里面文件的属主也被修改了(类似于 chmod -R )
ansible web -m copy -a "content='大弦嘈嘈如急雨,小弦切切如私语' dest=/tmp/b.txt 直接将content里面的内容添加到dest的文件里面,如果dest文件里面有内容,则内容被替换
file
补充
ln -s <源文件地址> <目标地址> 创建软链接
ln <源文件地址> <目标地址> 创建应链接
ansible cache -m file -a "path=/tmp/wupeiqi state=directory" 创建一个目录
ansible cache -m file -a "path=/tmp/wupeiqi.txt state=touch" 创建一个文件
ansible cache -m file -a "path=/tmp/t state=link src=/etc/init.d" 创建软链接 path是目标文件 src是源文件
ansible cache -m file -a "path=/tmp/t state=absent" 删除文件(linux中一切皆文件,软链接也是文件的一种)
fetch
fetch 用来拉去被管控机的文件或者目录,每个被管控机创建一个文件夹,并且保留原来的目录结构
ansible web -m fetch -a "dest=/tmp src=/var/log/cron"软件包相关
软件包相关
yum
回顾
- rpm与yum的区别
- redhat package manage
- yum 源配置方式
[epel] #组名
name=Extra Packages for Enterprise Linux 7 - $basearch #名字
baseurl=http://mirrors.aliyun.com/epel/7/$basearch #url,可以写http,https,ftp,file:
failovermethod=priority
enabled=1 #是否启用, 1表示启用,0表示不启用
gpgcheck=0 #是否校验gpgkey这个文件, 0表示不校验,1表示校验
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-7
为什么要校验: 一般情况下,用rpm的包,会用gpgkey去加密,然后拿到这个key对它进行解密,证明这个文件没有问题,才能去装, yum自动完成这一步操作
- yum 安装包组
yum grouplist
yum groupinstsall -y 'Development Tools'
rpm -qa python2-pip 查看软件包是否安装
ansible web -m yum -a 'name=python2-pip' 安装python2-pip包
ansible web -m yum -a 'name=@Development Tools' 安装包组
ansible web -m yum -a 'name=redis state=absent' 卸载
pip
pip freeze > a.txt 给当前python环境的包打快照
pip install -r a.txt 安装文件里面所有的包
pip list 查询所有安装的包以及版本号
ansible web -m pip -a 'name=flask' 安装pip包
service
service nginx start|stop|restart #centos6
chkconfig add nginx
chkconfig nginx on 设置开机启动
chkconfig --list
systemctl start|stop|restart nginx #centos7
systemctl enable nginx #设置开机自启动
ss -tnlp 查看启动的端口
ansible web -m service -a 'name=nginx state=started' #启动服务
ansible web -m service -a 'name=nginx state=stopped' #停止服务
cron
分 时 日 月 周 job
1 0 * * *
* * * * * tar zcvf /tmp/etc.tar.gz /etc/ 这是一个错误的示范
2 */3 * * * 每隔3小时第2分钟做某件事
0 15-17 * * 2,3 每周二,周三的15-17点的0分做某件事
day: 天
hour: 小时
job: 执行的任务
minute: 分钟
month: 月
name: 名字
weekday: 周
ansible web -m cron -a 'minute=09 job="touch /tmp/alex.txt" name=touchfile' #新建计划任务
ansible web -m cron -a 'minute=12 job="touch /tmp/alex.txt" name=touchfile disabled=yes'
#注释掉计划任务
ansible web -m cron -a 'name=touchfile state=absent' #删除计划任务
用户相关
用户:
超级用户 root 0
系统用户 不能登录 201-999 centos7 1-499 centos6
普通用户 可以登入系统 1000-60000 centos7 500-65535 centos6
组:
超级组: root 0
系统组: 201-999 centos7 1-499 centos6
普通组: 1000-60000 centos7 500-65535 centos6
#在 /etc/login.defs 中定义
useradd -d /opt/alex alex 指定用户的家目录
useradd -M -d /opt/alex2 alex2 不创建用户的家目录
userdel -r alex3 删除用户并删除用户的家目录
用户和组的关系
- 一对一 主组
- 一对多 附加组
- 多对多
user
ansible db -m user -a "name=mysql home=/opt/mysql groups=root uid=2000" 创建用户,并指定用户的家目录,并指定用户的附加组,指定用户的uid
ansible db -m user -a "name=mysql state=absent" 删除用户,但是不删除用户的家目录
ansible db -m user -a "name=mysql state=absent remove=yes" 删除用户并删除用户的家目录
setup
ansible_all_ipv4_addresses 所有ipv4地址
ansible_all_ipv6_addresses 所有ipv6地址
ansible_architecture 系统的架构
ansible_date_time 系统的时间
ansible_default_ipv4 默认的ipv4的值
ansible_distribution 系统名称
ansible_distribution_file_variety 系统的家族
ansible_distribution_major_version 系统的版本
ansible_domain 主机所在的域
ansible_fqdn 系统的主机名
ansible_hostname 系统的主机名,简写
ansible_os_family 系统的家族信息
ansible_processor_cores cpu的核数(单核或者双核)
ansible_processor_count cpu的颗数(几个CPU,1个或者2个)
ansible_processor_vcpus cpu的核心总数
group
ansible db -m group -a "name=wusir" 创建一个普通组
ansible db -m group -a "name=wusir state=absent" 删除组
#/etc/group 存储组信息
创建一个用户alex
ansible web -m user -a ‘name=alex’
创建一个用户wusir
ansible web -m user -a ‘name=wusir’
复制 /etc/fstab 文件到 /tmp目录下面
ansible web -m copy -a ‘dest=/tmp src=/etc/fstab’
安装nignx
ansible web -m yum ‘name=nginx’
安装redis
ansible web -m yum -a ‘name=redis’
并新建crontab 每天的晚上12点重启nginx
ansible web -m cron -a ‘minute=0 hour=12 job=systemctl restart nginx name=restart nginx’
playbook剧本
yaml
列表: -
字典: key: value
后缀名: yaml, yml
ansible-playbook的命令格式
ansible-playbook [options] playbook.yml [playbook2 ...]
-C, --check 干跑
-f FORKS 用来做并发
--list-hosts 列出主机列表
--syntax-check 语法检查
一个yml文件里可以写多个列表,列表间用列表(-)隔开, 一般情况下,一个文件里就写一个剧本,易维护
单个 playbook
---
- hosts: cache
remote_user: root
tasks:
- name: create user
user: name=alex
- name: create group
group: name=wusir
- name: install redis
yum: name=redis
执行过程: 所有机器都执行完第一个任务,再去执行第二个任务
playbook的参数
- hosts: web
remote_user: root
tasks:
- name: create {{ user }}
user: name={{ user }}
传参方式
- 第一种传参方式: -e
ansible-playbook v3.yml -e user=alexsb
- 第二种传参方式: hosts文件里面主机后面写(/etc/ansible/hosts)
[web]
192.168.43.14 user=alexsb2
192.168.43.15 user=alexsb3
- 第三种传参方式: hosts文件里面写 [groupname:vars]
[web]
192.168.43.14
192.168.43.15
[web:vars]
user=alexsb4
- 第四种传参方式:playbook文件中vars来指定
- hosts: web
remote_user: root
vars:
- user: alexsb5
tasks:
- name: create {{ user }}
user: name={{ user }}
- 第五种传参方式: 通过register注册,使用的时候要使用参数的stdout值
- hosts: web
remote_user: root
tasks:
- name: sum
shell: echo 3+4 |bc
register: user
- name: create{{ user }}
user: name=alexsb{{ user.stdout }}
优先级
-e > playbook的vars > host文件
条件判断(when)
- hosts: web
tasks:
- name: file
copy: content="凿壁偷光" dest=/tmp/wg.txt
when: num == "2"
- name: file
copy: content="耍流氓" dest=/tmp/wg.txt
when: num == "3"
- hosts: cache
tasks:
- name: create file
copy: content="小弦切切如私语" dest=/tmp/ppx.txt
when: ansible_python.version.major==1 #取字典内的值
修改redis 配置文件
bind 0.0.0.0 修改绑定的ip
requirepass s14 为redis设置密码s14
#部署redis并启动服务
- hosts: cache
remote_user: root
tasks:
- name: install
yum: name=redis
- name: copyfile
copy: dest=/etc/redis.conf src=/root/yaml/redis.conf
- name: start redis
service: name=redis state=started
标签
- hosts: cache
remote_user: root
tasks:
- name: install
yum: name=redis
tags: install
- name: copyfile
copy: dest=/etc/redis.conf src=/root/yaml/redis.conf
tags: copyfile
- name: start redis
service: name=redis state=started
tags: start
ansible-playbook -t copyfile v8.yml #执行打上某个标签的任务
模板
#创建目录template, 并将redis.conf配置文件拷贝到此目录并改名redis.conf.j2
mkdir templates
mv redis.conf{,.j2}
vim redis.conf
bind {{ansible_default_ipv4.address}} #根据不同的主机来定制不同的监听地址
- hosts: cache
remote_user: root
tasks:
- name: install
yum: name=redis
tags: install
- name: copyfile
template: dest=/etc/redis.conf src=redis.conf.j2 #可以使用相对路径,在当前目录的templates目录里面
tags: copyfile
- name: start redis
service: name=redis state=started
tags: start
循环with_item
- hosts: db
tasks:
- name: create user
user: name={{ item }}
with_items:
- alex10
- wusir10
- taiba10
循环嵌套
- hosts: db
tasks:
- name: create group
group: name={{item}}
with_items:
- alex20
- wusir20
- taibai20
- name: create user
user: name={{ item.name }} group={{item.group}}
with_items:
- {name: alex30,group: alex20}
- {name: wusir30,group: wusir20}
- {name: taibai30,group: taibai20}
handlers
- hosts: cache
remote_user: root
tasks:
- name: install
yum: name=redis
tags: install
- name: copyfile
template: dest=/etc/redis.conf src=redis.conf.j2
tags: copyfile
notify: restart redis
- name: start redis
service: name=redis state=started
tags: start
handlers:
- name: restart redis
service: name=redis, state=restarted
roles
特点
- 目录结构清晰
- 重复调用相同的任务
目录结构
首先新建roles文件, 然后再在roles文件中新建需要调用的文件的目录,将调用的文件放在目录中,使得结构更清晰
mkdir roles
mkdir -pv {web,db}/{tasks,vars,templates,handlers}
vim web.yml #总执行文件, roles目录下是调用的文件
- hosts: web
remote_user: root
roles:
- web #直接写目录文件名
web/
- tasks
- install.yml
- name: install {{pkg}}
yum: name={{pkg}}
- copyfile.yml
- name: copyfile
template: src=nginx.conf.j2 dest=/etc/nginx/nignx.conf
notify: restart
- start.yml
- name: start {{pkg}}
service: name={{pkg}} state=started
- main.yml #导入所有要执行的文件
- import_tasks: install.yml
- import_tasks: copyfile.yml
- import_tasks: start.yml
- templates
- nginx.conf.j2 # 由nginx的配置文件/etc/nginx/nginx.conf 拷贝而来
worker_processes { ansible_processor_vcpus*2 }; #进程数是cpu个数的2倍
worker_connections 65535; #最大连接数
- vars
- main.yml #定义变量
pkg: nginx
- files
- handlers
- main.yml
- name: restart
service: name=nginx state=restarted
tasks目录里面的查找规则:
- 先找main.yml, 通过import_tasks 导入task,
- 如果有handlers目录,找到main.yml,通过notify去找handlers里面的里面的task
- template模块去templates目录里面找需要复制的文件
常见报错解决
[WARNING]: sftp transfer mechanism failed
ansible 执行命令时,部分主机出现[WARNING]: sftp transfer mechanism failed on [xx]. Use ANSIBLE_DEBUG=1 to see detailed information的报错
一、修改sshd_config文件,取消注释Subsystem sftp /usr/lib/ssh/sftp-server
Subsystem sftp /usr/lib/ssh/sftp-server
当该行注释时,表示禁用sftp,需取消注释启用,修改配置后重启sshd服务
二、当sftp已启用时,报错仍然存在,修改ansible配置文件,添加scp_if_ssh=True
vi /etc/ansible/ansible.cfg
[ssh_connection]
scp_if_ssh=True
重新执行ansible,报错不存在了