- ansible介绍
- ansible常用模块使用
- playbook
- templates,模板
- 条件测试和循环迭代
- roles,角色
一、ansible介绍
ansible:自动化运维工具,实现了批量系统配置、批量程序部署、批量运行命令
特性:
模块化:调用特定的模块,完成特定任务
基于Python语言实现:包含Paramiko, PyYAML和Jinja2三个关键模块
部署简单:agentless,不需在被配置主机安装客户端
支持自定义模块
支持playbook
幂等性:任意多次执行所产生的影响均与一次执行的影响相同-
文件结构:
配置文件:/etc/ansible/ansible.cfg
主机清单:/etc/ansible/hosts- 主机清单配置文件格式:
[webservers] // 主机组名,包含下面的主机 alpha.example.org beta.example.org 192.168.1.100 192.168.1.110
主程序:
/usr/bin/ansible
/usr/bin/ansible-playbook
/usr/bin/ansible-doc
二、ansible常用模块使用
(一)ansible使用语法:
// 调用模块执行操作
ansible HOST-PATTERN -m MOD_NAME -a MOD_ARGS -f FORKS -C -u USERNAME -c CONNECTION
// 列出所有可以调用的模块
ansible-doc -l
// 列出指定模块的使用方法
ansible-doc -s MOD_NAME
- 测试1:ping模块,测试管理的主机的网络连接状态,连接成功返回pong
ansible all -m ping
(二)command模块:在远程主机运行命令
- chdir=/PATH/TO/DIR:
执行命令前切换工作目录至指定的位置 - creates=/PATH/TO/SOMEFILE_OR_DIR:
如果此处给定的文件或目录存在,则不执行命令 - removes=/PATH/TO/SOMEFILE_OR_DIR:
如果此处给定的文件或目录不存在,则不执行命令;即此处给定的文件或目录存在时方执行命令 - 测试2:查询管理主机指定网卡状态
ansible all -m command -a 'ip a show ens33'
- 测试3:chdir的作用为在执行命令前切换至相应目录
ansible 192.168.136.230 -m command -a 'pwd chdir=/tmp'
ansible 192.168.136.230 -m command -a 'pwd'
- 省略-m MOD_NAME时,则代表command模块
(三)shell模块:在远程主机的shell进程下运行命令,支持shell特性,如管道等
- chdir=:
执行命令前切换工作目录至指定的位置 - creates=/PATH/TO/SOMEFILE_OR_DIR:
如果此处给定的文件或目录存在,则不执行命令 - removes=/PATH/TO/SOMEFILE_OR_DIR:
如果此处给定的文件或目录不存在,则不执行命令;即此处给定的文件或目录存在时方执行命令 - executable=/PATH/TO/SHELL:指定运行命令使用的shell解释器
- 测试4:管理远程主机——修改账号密码
ansible websrvs -m shell -a 'echo centos | passwd --stdin user1 '
(四)group模块:管理组账号
- name=:必须参数,组账号名
- state=present | absent:建立/删除组账号
- system=yes | no:是否为系统账号
- gid=:组ID
- 测试5:管理远程主机——建立组
ansible websrvs -m group -a 'name=haproxy system=yes state=present'
(五)user模块:管理用户账号
- name=:必须参数,用户账号名
- system=yes | no:是否为系统账号
- uid=:用户ID
- shell=:指定shell类型
- group=:指定主组
- groups=:指定附加组
- comment=:指定说明
- home=:指定家目录
- generate_ssh_key=:是否生成ssh密钥
- 测试6:管理远程主机——建立用户
ansible websrvs -m user -a 'name=john groups=haproxy state=present shell=/bin/tcsh generate_ssh_key=true'
(六)copy模块: Copies files to remote locations
- 用法1:src= dest=:
将本地的文件复制到管理的主机组中 - 用法2:content= dest=:
在管理的主机组中中创建文件,由content关键词指定内容 - owner=:指定所有者
- group=:指定所属组
- mode=:指定权限
- 测试7:复制文件至远程主机指定目录
ansible all -m copy -a 'src=test.txt dest=/tmp/ owner=nobody group=daemon mode=664'
- 测试8:将内容装入文件复制至远程主机指定目录
ansible all -m copy -a "content='hello everyone\n' dest=/tmp/test2.txt owner=nobody group=daemon mode=664"
(七)fetch模块:Fetches a file from remote nodes
从远程节点获取文件
(八)file模块: Sets attributes of files
用法:
创建链接文件:path= src= state=link
修改属性:path= owner= mode= group=
创建目录:path= state=directory注意:state属性的可用值
file:仅在修改已经存在文件的属性时使用
directory:目录
link:软链接
hard:硬链接
touch:创建空白文件
absent:删除-
测试9:在远程主机建立目录
ansible all -m file -a "path=/tmp/hidir state=directory mode=770"
-
测试10:在远程主机建立空文件
ansible all -m file -a "path=/tmp/hifile state=touch mode=660"
-
测试11:在远程主机建立软链接
ansible all -m file -a "path=/tmp/mytext.txt src=/tmp/test2.txt state=link"
-
测试12:在远程主机删除软链接
ansible all -m file -a "path=/tmp/mytext.txt state=absent"
(九)get_url模块: Downloads files from HTTP, HTTPS, or FTP to node
- url=:必须参数
- dest=:必须参数
- sha256sum=:校验完整性
- owner, group, mode:所有者,所属组,权限
- 测试13:在远程主机上从网络链接下载文件
ansible all -m get_url -a "url=http://172.16.0.1/centos/7/Packages/ImageMagick-6.7.8.9-15.el7_2.x86_64.rpm dest=/tmp/"
(十)cron 模块:Manage cron.d and crontab entries.
- minute=:时间
- day=:天
- month=:月
- weekday=:工作日
- hour=:消失
- job=:执行的程序
- name=:名称,必须参数
- state=present|absent:创建或删除
- 测试14:设置远程主机每5分钟向主机172.18.0.1同步时间
ansible all -m cron -a "name='timesync' job='/usr/sbin/ntpdate 172.18.0.1 &> /dev/null' minute='*/5' "
(十一)hostname模块:Manage hostname
- name=:主机名
(十二)包管理相关模块
(1)yum模块:Manages packages with the 'yum' package manager
- name=:程序包名称,可以带版本号
- state=
present, latest, installed:安装
absent, removed:卸载 - 测试15:远程安装软件包
ansible websrvs -m yum -a "name=nginx state=latest"
- 查看远程主机指定软件包的安装状态
ansible websrvs -m yum -a "list=nginx"
(2)pip模块:Manages Python library dependencies
- name=
- state=
- version=
(3)npm模块:Manage node.js packages with npm
- name=
- state=
- version=
(十三)service模块:管理服务
- name=:服务名称,必备参数
- state=started | stopped | restarted:服务启动,关闭,重启
- enabled=:是否开机启动
- runlevel=:运行级别,适用于init脚本启动
- 测试16:远程启动指定服务,并设置为开机启动服务
ansible websrvs -m service -a "name=nginx enabled=true state=started"
(十四)其他模块
(1)git模块:Deploy software (or files) from git checkouts
- repo=:git源
- dest=:存储的本地路径
- version=
(2)deploy_helper模块:Manages some of the steps common in deploying projects
(3)haproxy模块:Enable, disable, and set weights for HAProxy backend servers using socket commands.
- backend=:后端主机
- host=:必备参数,后端主机名称
- state=:必备参数,后端主机状态
- weight=:后端主机权重
三、playbook
- playbook:一种简单的配置管理系统与多机器部署系统的基础,可以编排有序的执行过程,甚至于做到在多组机器间,来回有序的执行特别指定的步骤,并且可以同步或异步的发起任务
(一)YAML介绍:
- playbook采用YAML格式
- YAML:Yet Another Markup Language,一个可读性高,用来表达数据序列的格式
- YAML能表达的基本数据结构:标量、数组、关联数组
(二)playbook的运用:
(1)playbook的核心元素:
- hosts:主机
- tasks:任务列表
- variables:变量
- templates:包含了模板语法的文本文件
- handlers:由特定条件触发的任务
(2)playbook的基础组件:
hosts:运行指定任务的目标主机
remoute_user:在远程主机上执行任务的用户,权限提升时可能要用到sudo_user
-
tasks:任务列表
- 格式:
(1) action: module arguments
(2) module: arguments
注意:shell和command模块后面直接跟命令,而非key=value类的参数列表; - 某任务的状态在运行后为changed时,可通过notify通知给相应的handlers;
- 任务可以通过tags打标签,而后可在ansible-playbook命令上使用-t指定进行调用;
- 格式:
handlers:处理器,在特定条件下触发任务
接收到其它任务的通知时被触发
notify: HANDLER TASK NAME
(三)变量:variables
(1)直接调用
- 注意:可使用setup模块直接获取目标主机的facters
(2)用户自定义变量:
方法一:ansible-playbook命令行中指定
-e VARS, --extra-vars=VARS方法二:在playbook中定义变量
- var1: value1
变量引用:{{ variable }},注意变量名前后均有空格方法三:通过roles传递变量
-
方法四:Host Inventory,主机清单
-
用户自定义变量
- 向不同的主机传递不同的变量
IP/HOSTNAME varaiable=value var2=value2 - 向组中的主机传递相同的变量
[groupname:vars]
variable=value - 注意:优先级低于playbook中的定义
- 向不同的主机传递不同的变量
invertory参数
用于定义ansible远程连接目标主机时使用的参数,而非传递给playbook的变量
IP/HOSTNAME [ ansible_ssh_host | ansible_ssh_port | ansible_ssh_user | ansible_ssh_pass | ansbile_sudo_pass],危险不建议使用
-
(3)测试playbook:
- ansible-playbook --check|-C
只检测可能会发生的改变,但不真正执行操作 - ansible-playbook --list-hosts
列出运行任务的主机 - ansible-playbook --list-tasks
列出要运行的任务列表 - ansible-playbook --syntax-check
语法检查
(四)实验1:playbook实现基本的远程配置
实验环境:
web服务器:192.168.136.230, 192.168.136.130
数据库服务器:192.168.136.131实现目标:
web服务器:自动安装并启动nginx服务
数据库服务器:自动安装redis,统一配置文件内容,最后启动redis服务
(1)实现过程:
准备步骤:在ansible主机上使用
ssh-keygen -t rsa
生成公钥和私钥,使用ssh-copy-id ip_address
将公钥复制到需要管理的每台主机上步骤1:配置/etc/ansible/hosts文件,将服务器归类称为不同的组,方便管理
[websrvs] // web服务器组,命名为websrvs
192.168.136.230
192.168.136.130
[dbsrvs] // web服务器组,命名为dbsrvs
192.168.136.131
- 步骤2:配置playbook文件
- hosts: websrvs
remote_user: root
tasks:
- name: install nginx package // 安装nginx服务
yum: name=nginx state=latest
- name: start nginx service // 启动nginx服务
service: name=nginx enabled=true state=started
- hosts: dbsrvs
remote_user: root
tasks:
- name: install redis package // 安装redis服务
yum: name=redis state=latest
- name: install conf file // 复制redis配置文件至远程主机
copy: src=/root/redis.conf dest=/etc/redis.conf owner=redis group=root mode=644
// 提前准备好redis配置文件
- name: start redis service // 启动redis服务
service: name=redis state=started
- 步骤3:测试并运行
ansible-playbook --list-hosts nginx.yaml // 列出playbook中的主机
ansible-playbook --list-tasks nginx.yaml // 列出playbook中的任务
ansible-playbook --syntax-check nginx.yaml // 检查YAML文件的语法
ansible-playbook -C nginx.yaml // 预测执行playbook可能发生的变化,但实际不执行
ansible-playbook nginx.yaml // 执行playbook
ansible websrvs -m setup // 查看执行playbook时收集的信息
列出playbook中的主机
列出playbook中的任务
预测执行playbook可能发生的变化
(2)缺陷分析:
- 问题1:当配置文件修改后,执行playbook会重复执行所有任务,而大部分任务没有修改
- 问题2:虽然配置得到了更新,但是服务已经开启,故服务不会重启载入配置
- 解决:问题1可以通过定义标签,指定只执行标签处的任务;问题2可以通过定义重新启动服务的任务,并声明只在配置更改时执行:
- 实现步骤1:修改playbook文件
vim nginx.yaml
- hosts: websrvs
remote_user: root
tasks:
- name: install nginx package
yum: name=nginx state=latest
- name: start nginx service
service: name=nginx enabled=true state=started
- hosts: dbsrvs
remote_user: root
tasks:
- name: install redis package
yum: name=redis state=latest
- name: install conf file
copy: src=/root/redis.conf dest=/etc/redis.conf owner=redis group=root mode=644
tags: instconf // 对install conf file任务打标签
notify: restart redis service // 当配置文件变更时,才执行名为restart redis service的handler
- name: start redis service
service: name=redis state=started
handlers: // 定义handler,由notify语句在某些情况下被触发
- name: restart redis service
service: name=redis state=restarted
- 实现步骤2:修改/root/redis.conf文件,执行playbook并指定只执行标签instconf处的任务
ansible-playbook -t instconf nginx.yaml
可以看到执行结果中只执行了tag处的任务,并且触发执行名为restart redis service 的handler
- 实现步骤3:再次执行上一条命令
可以看到只执行了标签instconf的任务,但由于配置没有改变,故没有触发执行名为restart redis service 的handler
(五)实验2:playbook中定义变量
- 编辑instalpkg.yml文件,实现:当不指定变量pkgname时,自动安装tree;当指定pkgname的值时,安装指定的软件包
- hosts: websrvs
remote_user: root
vars:
- pkgname: tree
tasks:
- name: install package
yum: name={{ pkgname }} state=latest
- 可以看到被管理的主机成功安装;变量的引用也可以应用到name中,这样可以看到当前被安装的软件名称,对instalpkg.yml文件做修改后如下:
- hosts: websrvs
remote_user: root
vars:
- pkgname: tree
tasks:
- name: install package {{ pkgname }} // 做修改处
yum: name={{ pkgname }} state=latest
- 此时可以看到默认安装tree
- 指定变量pkgname的值
ansible-playbook -e "pkgname=memcached" -C instalpkg.yml
此时可以看到安装软件为memcached
四、templates,模板
(一)template介绍:
定义:基于模板方式生成一个文件复制到远程主机
实质:文本文件,嵌套有脚本(使用模板编程语言编写),类比php嵌入html文件的关系
(二)template配置:
template模块的使用:类似copy
src, dest, owner, group, mode-
脚本语言:Jinja2,语法如下
- 字符串:使用单引号或双引号;
- 数字:整数,浮点数;
- 列表:[item1, item2, ...]
- 元组:(item1, item2, ...)
- 字典:{key1:value1, key2:value2, ...}
- 布尔型:true/false
- 算术运算:+, -, *, /, //, %, **
- 比较操作:==, !=, >, >=, <, <=
- 逻辑运算:and, or, not
(三)实验3:实现自动安装redis,之后修改配置文件/etc/redis.conf的maxmemory值为主机总内存大小的一半,并且自动重启服务使配置生效
- 步骤1:编辑/root/redis_install_and_conf.yml文件,实现实验要求
vim /root/redis_install_and_conf.yml
- hosts: dbsrvs
remote_user: root
tasks:
// 安装
- name: install redis
yum: name=redis state=latest
// 复制配置文件模板
- name: install redis conf
template: src=/root/redis.conf.j2 dest=/etc/redis.conf owner=redis group=root mode=644
notify: restart redis service
tags: install_conf
// 启动服务
- name: start redis service
service: name=redis state=started
// 条件触发任务
handlers:
- name: restart redis service
service: name=redis state=restarted
- 步骤2:准备配置文件
cp /etc/redis.conf /root/redis.conf.j2
vim /root/redis.conf.j2
maxmemory {{ ansible_memtotal_mb /2 }}mb // 添加此行,自动根据安装主机的内存容量设置
- 步骤3:测试并执行playbook
ansible-playbook -C /root/redis_install_and_conf.yml
ansible-playbook /root/redis_install_and_conf.yml
可以看到install redis conf任务成功执行
查看被安装的主机上的/etc/redis.conf文件,maxmemory值根据主机内存情况动态设置
五、条件测试和循环迭代:
(一)条件测试:when
适用于根据被管理主机参数的不同采取不同的操作
when语句:在task中使用,jinja2的语法格式
tasks:
- name: install conf file to centos7
template: src=/etc/nginx.conf.c7.j2 dest=/etc/nginx.conf owner=root group=root
when: ansible_distribution_major_version == "7"
- name: install conf file to centos6
template: src=/etc/nginx.conf.c6.j2 dest=/etc/nginx.conf owner=root group=root
when: ansible_distribution_major_version == "6"
(二)循环:迭代,需要重复执行的任务
对迭代项的引用,固定变量名为"item"
而后,要在task中使用with_items给定要迭代的元素列表
列表方法:字符串,字典
// 字符串列表方法
- name: install some packages
yum: name={{ item }} state=present
with_items:
- nginx
- memcached
- php-fpm
- name: add some groups
group: name={{ item }} state=present
with_items:
- group11
- group12
- group13
// 字典列表方法
- name: add some users
user: name={{ item.name }} group={{ item.group }} state=present
with_items:
- { name: 'user11', group: 'group11' }
- { name: 'user12', group: 'group12' }
- { name: 'user13', group: 'group13' }
六、roles,角色
(一)角色的目录结构
角色集合:/etc/ansible/roles/目录下每个角色一个目录
-
每个角色以特定的层级目录结构进行组织:
- files/ :存放由copy或script模块等调用的文件
- templates/:template模块查找所需要模板文件的目录
- tasks/:至少应该包含一个名为main.yml的文件;其它的文件需要在此文件中通过include进行包含
- handlers/:至少应该包含一个名为main.yml的文件;其它的文件需要在此文件中通过include进行包含
- vars/:至少应该包含一个名为main.yml的文件;其它的文件需要在此文件中通过include进行包含
- meta/:至少应该包含一个名为main.yml的文件,定义当前角色的特殊设定及其依赖关系;其它的文件需要在此文件中通过include进行包含
- default/:设定默认变量时使用此目录中的main.yml文件
(二)playbook中角色的调用
- 调用角色的语法:
- hosts: websrvs
remote_user: root
roles:
- mysql
- nginx
- 调用角色同时传递变量给角色
- hosts:
remote_user: root
roles:
- { role: nginx, username: nginx }
- 基于条件测试实现角色调用
- hosts:
remote_user: root
roles:
- { role: nginx, when: "ansible_distribution_major_version == '7' " }
(三)实验4:
- 步骤1:建立目录结构
mkdir /etc/ansible/roles/nginx/{tasks,handlers,vars,files,templates} -pv
cd /etc/ansible/roles
- 步骤2:编辑task目录,定义需要执行的任务
vim nginx/tasks/main.yml
- name: install nginx package // 安装nginx
yum: name=nginx state=latest
- name: install conf file // 复制配置模板文件
template: src=web.conf.j2 dest=/etc/nginx/conf.d/web.conf
notify: reload nginx service // 触发服务重载
tags: instconf
- name: create doc root // 建立网页文件根目录
file: path={{ ngx_doc_root }} state=directory
tags: instconf
- name: start nginx service // 启动nginx服务
service: name=nginx enabled=true state=started
- 步骤3:编辑模板配置文件
vim nginx/templates/web.conf.j2
server {
listen {{ ngx_server_port }};
server_name {{ ngx_server_name }};
location / {
root {{ ngx_doc_root }};
}
}
- 步骤4:编辑变量配置文件
vim nginx/vars/main.yml
ngx_server_port: 80
ngx_server_name: www.hellopeiyang.com
ngx_doc_root: /app/webdata
- 步骤5: 配置handlers配置文件
vim nginx/handlers/main.yml
- name: reload nginx service
service: name=nginx state=reloaded
- 步骤6: 编辑playbook
vim /root/mywebsrvs.yml
- hosts: websrvs
remote_user: root
roles:
- nginx
- 步骤7: 测试并执行playbook
ansible-playbook -C /root/mywebsrvs.yml
ansible-playbook /root/mywebsrvs.yml
- 测试过程1:成功执行playbook
- 执行后可以看到配置文件中的信息按照定义的变量值配置
- 在运行playbook时指定变量值,优先级高于配置文件,同时指定只执行标签instconf处的任务
ansible-playbook -e "ngx_server_port=1008" -t instconf /root/mywebsrvs.yml
- 执行后可以看到配置文件中相应的变化
- 也可以在playbook中直接传递变量给角色
vim /root/mywebsrvs.yml
- hosts: websrvs
remote_user: root
roles:
- { role: nginx, ngx_server_port: 8090 } // 指定传入的角色,变量名:变量值
ansible-playbook -t instconf /root/mywebsrvs.yml
- 同样,执行后变量定义处的配置信息也发生了相应的变化