1.介绍
Ansible自动化运维工具,是用来实现一台主机对多台主机进行操作的开源软件。
主要功能:
- 批量对多台主机发送文件
- 批量对多台主机运行命令
特性: - 模块化
- 基于Python语言实现,有Paramiko,PyYAML和Jinja2三个关键模块
- 部署简单:agentless,可以不需要在需要操作的服务器上安装任何软件
- 支持自定义模块
- 支持Playbook,可以将任何配置写入Playbook,循环使用
-
幂等性,命令不管执行多少次,结果是一样的
Ansible配置系统结构图:
2.安装和配置说明
Ansible的安装需要使用epel源进行安装,所以在安装之前需要配置epel源
主要配置文件
/etc/ansible/hosts :主机清单配置文件
/etc/ansible/ansible.cnf:主配置文件
/etc/ansible/roles:角色定义目录
相关命令介绍
1.帮助类相关命令
- ansible-doc -l 查看当前支持的所有模块
- ansible-doc -s 模块名 查看当前指定模块使用方法
- ansible-doc -h 该命令使用方法
2.一次性执行命令相关
- ansible host|all -m 模块 -a “模块参数” -f 一次连接多少个主机
3.ansible-playbook相关命令
测试相关
- ansible-playbook --check 只检测可能会发生的改变,但不真正执行操作
- ansible-playbook --list-hosts 列出运行任务的主机
- ansible-playbook --list-tasks 列出要运行的任务列表
- ansible-playbook --syntax-check 语法检查
- ansible-playbook --list-tags 列出所有可用的标签
- ansible-playbook --list-tasks 列出所有任务列表
运行相关 - ansible-playbook yml_file
- ansible-playbook -t TAGS , --tags=TAGS 只运行指定标签的任务
- ansible-playbook --skip-tigs=SKIP_TIGS 跳过指定标签的任务
3.常用模块及实例
1.ping:测试与指定主机是否通讯正常
[root@ansible ~]# ansible ansible.test.com -m ping
ansible.test.com | SUCCESS => {
"changed": false,
"ping": "pong"
}
2.command:远程在指定主机执行命令,该模块是直接在内核级执行,所以没有bash的一些符号
相关参数:
chdir:指定运行命令目录
creates:创建文件或目录,若文件或目录存在,则不执行
removes:删除文件或目录,若文件或目录不存在时,则不执行
实例:
[root@ansible ~]# ansible ansible.test.com -m command -a "date"
ansible.test.com | SUCCESS | rc=0 >>
Tue Jun 12 03:23:01 EDT 2018
3.shell:远程在指定主机执行命令,该模块时基于bash运行,所以bash相关符号都支持
相关参数:
chdir:指定运行命令目录
creates:创建文件或目录,若文件或目录存在,则不执行
removes:删除文件或目录,若文件或目录不存在时,则不执行
实例:
[root@ansible ~]# ansible ansible.test.com -m shell -a "echo 123456 | passwd --stdin test1"
ansible.test.com | SUCCESS | rc=0 >>
Changing password for user test1.
passwd: all authentication tokens updated successfully.
4.group:远程在指定主机创建或删除组
相关参数:
gid:指定组的GID
name:指定组名
state:指定删除还是创建,present | absent
system:指定对应组是否为系统组
实例:
[root@ansible ~]# ansible ansible.test.com -m group -a "name=ansible state=present gid=2000"
ansible.test.com | SUCCESS => {
"changed": true,
"gid": 2000,
"name": "ansible",
"state": "present",
"system": false
}
[root@ansible ~]# ansible ansible.test.com -m group -a "name=ansible state=absent gid=2000"
ansible.test.com | SUCCESS => {
"changed": true,
"name": "ansible",
"state": "absent"
}
5.user:在指定主机创建或删除用户
相关参数:
name:指定用户名
group:指定主组
uid:指定用户的uid
goups:指定附加组
home:指定家目录
password:指定用户密码
state:指定状态,若和状态不想同则作出操作 present | absent
system:设定用户为系统用户
shell:设定登入shell
实例:
[root@ansible ~]# ansible ansible.test.com -m user -a "name=ansible uid=2000 password=123456 shell=/bin/sh"
ansible.test.com | SUCCESS => {
"changed": true,
"comment": "",
"createhome": true,
"group": 2000,
"home": "/home/ansible",
"name": "ansible",
"password": "NOT_LOGGING_PASSWORD",
"shell": "/bin/sh",
"state": "present",
"system": false,
"uid": 2000
}
[root@ansible ~]# ansible ansible.test.com -m user -a "name=ansible state=absent"
ansible.test.com | SUCCESS => {
"changed": true,
"force": false,
"name": "ansible",
"remove": false,
"state": "absent"
}
6.copy:从本地复制文件至指定服务器
相关配置:
src:本地文件路径
dest:远程服务器目录
owner:指定文件所有者
group:指定文件所属组
mode:指定文件权限
content:将指定内容复制至指定服务器
实例:
[root@ansible ~]# ansible ansible.test.com -m copy -a "src=issue dest=/tmp owner=memcached group=root mode=0444"
ansible.test.com | SUCCESS => {
"changed": true,
"checksum": "5c76e3b565c91e21bee303f15c728c71e6b39540",
"dest": "/tmp/issue",
"gid": 0,
"group": "root",
"md5sum": "f078fe086dfc22f64b5dca2e1b95de2c",
"mode": "0444",
"owner": "memcached",
"size": 23,
"src": "/root/.ansible/tmp/ansible-tmp-1528789534.05-118540157876873/source",
"state": "file",
"uid": 995
}
7.fetch:从远程服务器复制文件至本地,为了可以存多个服务器相同文件名,是创建一个以主机名为目录将复制文件放入目录中实现
相关配置:
src:远程地址
dest:本地地址
实例:
[root@ansible ~]# ansible ansible.test.com -m fetch -a "src=/etc/passwd dest=/tmp"
ansible.test.com | SUCCESS => {
"changed": true,
"checksum": "49ed3c6ed3359b339b94c0b4b69d596974de5ff2",
"dest": "/tmp/ansible.test.com/etc/passwd",
"md5sum": "256651c73ef0e89bc7cd5cffe786f27e",
"remote_checksum": "49ed3c6ed3359b339b94c0b4b69d596974de5ff2",
"remote_md5sum": null
}
8.file:对远程文件或目录进行操作
相关配置:
path:指定远程操作文件
state:指定path文件的类型,可以是dreectory、link、hard、file、touch,也可以是present或absent
src:本地路径,用于在指定连接文件时使用
owner:指定文件属主
group:指定文件属组
mode:指定文件权限
实例:
[root@ansible ~]# ansible ansible.test.com -m file -a "path=/tmp/file state=directory"
ansible.test.com | SUCCESS => {
"changed": true,
"gid": 0,
"group": "root",
"mode": "0755",
"owner": "root",
"path": "/tmp/file",
"size": 6,
"state": "directory",
"uid": 0
}
9.get_url:批量下载
相关配置:
url:指定url路径
owner:指定文件属主
group:指定文件属组
mode:指定文件权限
dest:指定目标路径,必须是一个目录
实例:
[root@ansible ~]# ansible ansible.test.com -m get_url -a "url=https://mirrors.aliyun.com/gentoo-portage/app-accessibility/SphinxTrain/SphinxTrain-1.0.8.ebuild dest=/tmp"
ansible.test.com | SUCCESS => {
"changed": true,
"checksum_dest": null,
"checksum_src": "b1a87e9c2e46841866387b11805d2cdf3d240577",
"dest": "/tmp/SphinxTrain-1.0.8.ebuild",
"gid": 0,
"group": "root",
"md5sum": "a52bed11534400b1901760bc1bcc9dd9",
"mode": "0644",
"msg": "OK (912 bytes)",
"owner": "root",
"size": 912,
"src": "/tmp/tmpNHTpAE",
"state": "file",
"uid": 0,
"url": "https://mirrors.aliyun.com/gentoo-portage/app-accessibility/SphinxTrain/SphinxTrain-1.0.8.ebuild"
}
10.git:用于下载git代码仓库命令,该命令需要安装git软件包才可以下载
相关配置:
repo:指定仓库地址
dest:指定目标路径
version:指定版本号,默认最新版本号
11.cron:为指定主机定义计划任务
相关配置:
minute:定义分钟
day:定义天
month:定义月
weekday:定义周
hour:定义时
job:定义命令
name:计划任务名
state:present:创建 | absent:删除
实例:
[root@ansible ~]# ansible ansible.test.com -m cron -a "name=mycron minute=*/5 job=date"
ansible.test.com | SUCCESS => {
"changed": true,
"envs": [],
"jobs": [
"mycron"
]
}
12.yum:软件包的安装,默认输出格式不对,这里是整理过的格式
相关配置:
name:程序包名,可以带版本号,若不指定,默认安装最新版
state:设置安装,卸载 installed | removed
enablerepo:启用某仓库
diablerepo:禁用某仓库
实例:
[root@ansible ~]# ansible ansible.test.com -m yum -a "name=tree state=installed"
ansible.test.com | SUCCESS => {
"changed": true,
"msg": "",
"rc": 0,
"results": [
"Loaded plugins: fastestmirror
Loading mirror speeds from cached hostfile
Resolving Dependencies
--> Running transaction check
---> Package tree.x86_64 0:1.6.0-10.el7 will be installed
--> Finished Dependency Resolution
Dependencies Resolved
================================================================================
Package Arch Version Repository Size
================================================================================
Installing:
tree x86_64 1.6.0-10.el7 bendi 46 k
Transaction Summary
================================================================================
Install 1 Package
Total download size: 46 k
Installed size: 87 k
Downloading packages:
Running transaction check
Running transaction test
Transaction test succeeded
Running transaction
Installing : tree-1.6.0-10.el7.x86_64 1/1
Verifying : tree-1.6.0-10.el7.x86_64 1/1
Installed:
tree.x86_64 0:1.6.0-10.el7
Complete!
"
]
}
13.service:服务相关
相关配置:
name:指定服务名称
state:指定服务状态,可以是started、restarted、reloaded、stoped
enabled:是否开机自启 true
runlevel:定义级别CentOS7版本不需要指定
实例:
[root@ansible ~]# ansible ansible.test.com -m service -a "name=memcached state=started"
ansible.lin.com | SUCCESS => {
·······这里显示的都是一些该服务的环境参数
}
"warnings": []
}
14.hostname:设置远程主机的主机名,一般不适用
15.pip:用于安装python模块
16.npm:用于安装JS模块
17.setup:显示当前系统中所有的变量,可以在配置文件中直接调用
显示:
ansible.test.com | SUCCESS => {
"ansible_facts": {
"ansible_all_ipv4_addresses": [
"192.168.1.161",
"192.168.1.111",
"192.168.1.112"
],
"ansible_all_ipv6_addresses": [
"fe80::880b:c17f:5022:67c3",
"fe80::acd6:5a07:96b5:c5d4",
"fe80::805f:d6bd:3a96:c3dc"
],
"ansible_architecture": "x86_64",
"ansible_bios_date": "07/02/2015",
"ansible_bios_version": "6.00",
"ansible_cmdline": {
"BOOT_IMAGE": "/vmlinuz-3.10.0-693.el7.x86_64",
"LANG": "en_US.UTF-8",
"crashkernel": "auto",
"quiet": true,
"rd.lvm.lv": "centos/swap",
"rhgb": true,
"ro": true,
"root": "/dev/mapper/centos-root"
},
"ansible_date_time": {
"date": "2018-06-12",
"day": "12",
"epoch": "1528792866",
"hour": "04",
"iso8601": "2018-06-12T08:41:06Z",
"iso8601_basic": "20180612T044106138105",
"iso8601_basic_short": "20180612T044106",
"iso8601_micro": "2018-06-12T08:41:06.138178Z",
18.template:用于复制模板配置文件,模板配置文件必须为 .j2格式
相关配置:
src:源文件
dest:目标路径
owner:属主
group:数组
mode:权限
Jinja2:
字面量:
字符串:使用单引号或双引号;
数字:整数,浮点数;
列表:[item1, item2, ...]
组:(item1, item2, ...)
字典:{key1:value1, key2:value2, ...}
布尔型:true/false
算术运算:
+, -, *, /, //, %, **
比较操作:
==, !=, >, >=, <, <=
逻辑运算:
and, or, not
4.Playbook:将需要在远程服务器上执行的命令写入配置文件中,调用配置文件即可执行
YAML
YAML:YAML(/ˈjæməl/,尾音类似camel骆驼)是一个可读性高,用来表达数据序列的格式。YAML参考了其他多种语言,包括:C语言、Python、Perl,并从XML、电子邮件的数据格式(RFC 2822)中获得灵感。Clark Evans在2001年首次发表了这种语言,另外Ingy döt Net与Oren Ben-Kiki也是这语言的共同设计者。目前已经有数种编程语言或脚本语言支持(或者说解析)这种语言。
YAML是"YAML Ain't a Markup Language"(YAML不是一种标记语言)的递归缩写。在开发的这种语言时,YAML 的意思其实是:"Yet Another Markup Language"(仍是一种标记语言),但为了强调这种语言以数据做为中心,而不是以标记语言为重点,而用反向缩略语重命名。
YAML的语法和其他高级语言类似,并且可以简单表达清单、散列表,标量等数据形态。它使用空白符号缩进和大量依赖外观的特色,特别适合用来表达或编辑数据结构、各种配置文件、倾印除错内容、文件大纲(例如:许多电子邮件标题格式和YAML非常接近)。
Playbook的核心元素
* Hosts:主机
* Tasks:任务列表
* Varoables:变量
* Templates:包含了模板语法文本文件
* Handlers:特定条件触发的任务
* Roles:角色,将重复需要执行的命令写成一个单独的功能模块,当需要使用时,直接使用即可,类似于函数
Playbook的基本组件
- hosts: 运行指定主机
remote_user: 远程主机执行任务所用的身份,一般为root
tasks: 任务列表
选项: 模块 参数
模块: 参数
handlers:特定模式下执行,需要在上述指定notify,在notify后面指定字符串,在下面至指定触发即可
-name:
实例:
[root@ansible ansible]# vim httpd.yml
- hosts: ansible.test.com
remote_user: root
tasks:
- name: install httpd package
yum: name=httpd state=installed
- name: start httpd servier
service: name=httpd state=started
[root@ansible ansible]# ansible-playbook httpd.yml
PLAY [ansible.test.com] *********************************************************
TASK [setup] *******************************************************************
ok: [ansible.test.com]
TASK [install httpd package] ***************************************************
changed: [ansible.test.com]
TASK [start httpd servier] *****************************************************
changed: [ansible.test.com]
PLAY RECAP *********************************************************************
ansible.test.com : ok=3 changed=2 unreachable=0 failed=0
variables:传递参数
1.facts:可以直接调用,使用setup查看
2.用户自定义变量
* ansible-playbook -e 变量
* -var1: value1
3.通过reles传递变量
4.在/etc/ansible/hosts文件中定义主机或是可以直接定义
ip var=value1
[groupname::vars]
varname=valus
条件测试:
when语句,在task中使用,当满足条件式才会执行
tasks:
- name: install conf file to centos7
template: src=files/nginx.conf.c7.j2
when: ansible_distribution_major_version == "7"
- name: install conf file to centos6
template: src=files/nginx.conf.c6.j2
when: ansible_distribution_major_version == "6"
循环,迭代,能够将重复任务循环完成
对迭代项引用,固定变量名为"item",而后给定列表
* 列表的方法有字符串和字典
- name: install some packages
yum: name={{ item }} state=present
with_items:
- nginx
- memcached
- php-fpm
- name: install some packages
yum: name={{ item }} state=present
with_items:
- { name: 'nginx', group: 'nginx' }
- { name: 'nginx', group: 'nginx' }
- { name: 'nginx', group: 'nginx' }
roles角色的定义:
角色目录结构
nginx/:指定角色名称,当需要调用时,也是根据该名称调用,在一下目录下的每一个目录,若需要使用,至少应该拥有一个main.yml文件,若需要扩展,则可以使用include进行扩展
- files/:存放有copy或script模块等调用的文件
- templates/:存放模板查看锁需要的目录,文件后缀为.j2
- tasks/:任务列表目录,存放要执行的任务
- handlers/:来用存放满足条件才会执行的任务列表
- vars/:变量目录
- meta/:定义当前角色的特殊设定及其依赖关系
- default/:设定默认变量是使用该目录
5.实践
利用roles实现模块化nginx
1.创建目录结构
[root@ansible ansible]# tree /etc/ansible/roles/nginx/
/etc/ansible/roles/nginx/
├── default
├── files
│ ├── proxy.html
│ └── web.html
├── handlers
│ └── main.yml
├── meta
├── tasks
│ └── main.yml
├── templates
│ ├── nginx.conf.j2
│ └── proxy.conf.j2
└── vars
└── main.yml
2.创建 tasks目录下main.yml
[root@ansible nginx]# cat tasks/main.yml
- name: install nginx package
yum: name=nginx state=installed
- name: create conf.d directory
file: path=/etc/nginx/conf.d state=directory
- name: install web conf file
template: src=templates/nginx.conf.j2 dest={{ nginx }}/nginx.conf
when: servertype == 'web'
notify: 'restart nginx server'
- name: install proxy conf file
template: src=templates/proxy.conf.j2 dest={{ nginx }}/nginx.conf
notify: 'restart nginx server'
when: servertype == 'proxy'
- name: create web index
file: path={{ webpath }} state=directory
when: servertype == 'web'
- name: create proxy index
file: path={{ proxypath }} state=directory
when: servertype == 'proxy'
- name: copy web index file
copy: src=files/web.html dest={{ webpath }}/index.html
when: servertype == 'web'
- name: copy proxy index file
copy: src=files/proxy.html dest={{ proxypath }}/index.html
when: servertype == 'proxy'
- name: start nginx service
service: name=nginx state=started enabled=true
3.创建对应的变量vars/main.yml
[root@ansible nginx]# cat vars/main.yml
nginx: /etc/nginx/conf.d/
servertype: web
webpath: /app/web/
proxypath: /app/proxy/
4.创建handles目录下main.yml
[root@ansible nginx]# cat handlers/main.yml
- name: restart nginx server
service: name=nginx state=restarted
5.配置模板文件templates
[root@ansible nginx]# cat templates/proxy.conf.j2
unstream tomser {
server tomcat1.lin.com:8080;
server tomcat2.lin.com:8080;
}
server {
listen 80;
server_name {{ ansible_fqdn }};
index index.html;
root {{ proxypath }};
location / {
proxy_pass http://tomser/;
}
}
[root@ansible nginx]# cat templates/nginx.conf.j2
server {
listen 80;
server_name {{ ansible_nodename }};
root {{ webpath }};
index index.jsp index.html;
location / {
proxy_pass http://{{ ansible_fqdn }}:8080;
}
}
6.创建对应的测试主页
[root@ansible nginx]# cat files/
proxy.html web.html
[root@ansible nginx]# cat files/*
<h1>proxy</h2>
<h1>test</h1>
7.根据参数来选择安装的类型
[root@ansible ansible]# ansible-playbook nginx.yml
或
[root@ansible ansible]# ansible-playbook -e server=proxy nginx.yml