Ansible自动化运维工具
介绍
ansible是新出现的自动化运维工具,由python开发,集合了众多自动化运维工具的优点,实现了批量 系统部署、批量程序部署,批量运行命令等功能。ansible是基于模块工作的,本身没有批量部署的能 力,真正具有批量部署能力的是ansible运行的模块,ansible只是提供一个框架。
核心组件
Ansible
:Ansible核心程序。
HostInventory
:记录由Ansible管理的主机信息,包括端口、密码、ip等。
Playbooks
:“剧本”YAML格式文件,多个任务定义在一个文件中,定义主机需要调用哪些模块来完成的功能。
CoreModules
:核心模块,主要操作是通过调用核心模块来完成管理任务。
CustomModules
:自定义模块,完成核心模块无法完成的功能,支持多种语言。
ConnectionPlugins
:连接插件,Ansible和Host通信使用
ansible 特点
- 部署简单,只需在主控端部署Ansible环境,被控端无需做任何操作;
- 默认使用SSH协议对设备进行管理;
- 有大量常规运维操作模块,可实现日常绝大部分操作;
- 配置简单、功能强大、扩展性强;
- 支持API及自定义模块,可通过Python轻松扩展;
- 通过Playbooks来定制强大的配置、状态管理;
- 轻量级,无需在客户端安装agent,更新时,只需在操作机上进行一次更新即可;
- 提供一个功能强大、操作性强的Web管理界面和REST API接口——AWX平台。
ansible 命令执行过程
- 加载自己的配置文件,默认
/etc/ansible/ansible.cfg
; - 查找对应的主机配置文件,找到要执行的主机或者组;
- 加载自己对应的模块文件,如 command;
- 通过ansible将模块或命令生成对应的临时py文件(python脚本), 并将该文件传输至远程服务器;
- 对应执行用户的家目录的
.ansible/tmp/XXX/XXX.PY
文件; - 给文件 +x 执行权限;
- 执行并返回结果;
- 删除临时py文件,
sleep 0
退出;
ansible 配置详解
ansible 安装方式
ansible安装常用两种方式,yum安装
和pip程序安装
。
使用 pip(python的包管理模块)安装
首先,我们需要安装一个python-pip
包,安装完成以后,则直接使用pip
命令来安装我们的包
yum install python-pip
pip install ansible
使用 yum 安装
yum install epel-release -y
yum install ansible –y
ansible 程序结构
安装目录如下(yum安装):
配置文件目录:/etc/ansible/
- /etc/ansible/ansible.cfg:主配置文件
- /etc/ansible/hosts:主机清单文件
- /etc/ansible/roles:角色目录
执行文件目录:/usr/bin/
Lib库依赖目录:/usr/lib/pythonX.X/site-packages/ansible/
Help文档目录:/usr/share/doc/ansible-X.X.X/
Man文档目录:/usr/share/man/man1/
nsible配置文件查找顺序
- 检查环境变量
ANSIBLE_CONFIG
指向的路径文件(export ANSIBLE_CONFIG=/etc/ansible.cfg); ~/.ansible.cfg
,检查当前目录下的ansible.cfg配置文件;/etc/ansible.cfg
检查etc目录的配置文件。
ansible配置文件
ansible 的配置文件为/etc/ansible/ansible.cfg
,ansible 有许多参数,下面列出一些常见的参数:
[defaults]
# some basic default values...
inventory = /etc/ansible/hosts #这个参数表示资源清单inventory文件的位置
library = /usr/share/ansible #指向存放Ansible模块的目录,支持多个目录方式,只要用冒号(:)隔开就可以
forks = 5 #并发连接数,默认为5
sudo_user = root #设置默认执行命令的用户
remote_port = 22 #指定连接被管节点的管理端口,默认为22端口,建议修改,能够更加安全
host_key_checking = False #设置是否检查SSH主机的密钥,值为True/False。关闭后第一次连接不会提示配置实例
timeout = 60 #设置SSH连接的超时时间,单位为秒
log_path = /var/log/ansible.log #指定一个存储ansible日志的文件(默认不记录日志)
ansuble主机清单
- 定义主机hosts文件
[root@ansible ~]# tail /etc/hosts
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
192.168.174.10 ansible
192.168.174.20 node1
192.168.174.30 node2
- 定义ansible主机清单
[root@ansible ~]# grep -Ev '#|^$' /etc/ansible/hosts
[all]
ansible
node1
node2
[nodes]
node1
node2
- 生成主机密钥对
[root@ansible ~]# ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/root/.ssh/id_rsa):
Created directory '/root/.ssh'.
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /root/.ssh/id_rsa.
Your public key has been saved in /root/.ssh/id_rsa.pub.
The key fingerprint is:
SHA256:IVCukQxzkroHAUvVovvB4ga3JrY4OlkwMnV9rZhVEFE root@ansible
The key's randomart image is:
+---[RSA 2048]----+
|o.=o+o. +BE |
|o.oB.=. o . |
|.+..= o=.. |
|B. oo... |
|.*o . S |
|oo+o |
|o=o.. |
|*+o. |
|**. |
+----[SHA256]-----+
- 发送主机公钥到受控节点实现免密登录
[root@ansible ~]# cd .ssh/
[root@ansible .ssh]# ll
总用量 8
-rw------- 1 root root 1679 9月 11 09:54 id_rsa
-rw-r--r-- 1 root root 394 9月 11 09:54 id_rsa.pub
[root@ansible .ssh]# ssh-copy-id -i id_rsa.pub root@192.168.174.20
/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "id_rsa.pub"
The authenticity of host '192.168.174.20 (192.168.174.20)' can't be established.
ECDSA key fingerprint is SHA256:l5y8+0D0KcBmCK2edW3ZSY7RyIDgBdlLOE10JAlVtKk.
ECDSA key fingerprint is MD5:60:21:02:4d:b8:ce:cd:bc:19:33:0d:58:d6:4c:bd:fe.
Are you sure you want to continue connecting (yes/no)? yes
/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
/usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys
root@192.168.174.20's password:
Number of key(s) added: 1
Now try logging into the machine, with: "ssh 'root@192.168.174.20'"
and check to make sure that only the key(s) you wanted were added.
[root@ansible .ssh]# ssh-copy-id -i id_rsa.pub root@192.168.174.30
/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "id_rsa.pub"
The authenticity of host '192.168.174.30 (192.168.174.30)' can't be established.
ECDSA key fingerprint is SHA256:l5y8+0D0KcBmCK2edW3ZSY7RyIDgBdlLOE10JAlVtKk.
ECDSA key fingerprint is MD5:60:21:02:4d:b8:ce:cd:bc:19:33:0d:58:d6:4c:bd:fe.
Are you sure you want to continue connecting (yes/no)? yes
/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
/usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys
root@192.168.174.30's password:
Number of key(s) added: 1
Now try logging into the machine, with: "ssh 'root@192.168.174.30'"
and check to make sure that only the key(s) you wanted were added.
- 测试ssh免密登录
[root@ansible ~]# ssh root@node1
The authenticity of host 'node1 (192.168.174.20)' can't be established.
ECDSA key fingerprint is SHA256:l5y8+0D0KcBmCK2edW3ZSY7RyIDgBdlLOE10JAlVtKk.
ECDSA key fingerprint is MD5:60:21:02:4d:b8:ce:cd:bc:19:33:0d:58:d6:4c:bd:fe.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added 'node1' (ECDSA) to the list of known hosts.
Last login: Sat Sep 11 09:59:04 2021 from 192.168.174.10
[root@node1 ~]# 登出
Connection to node1 closed.
[root@ansible ~]# ssh root@node2
The authenticity of host 'node2 (192.168.174.30)' can't be established.
ECDSA key fingerprint is SHA256:l5y8+0D0KcBmCK2edW3ZSY7RyIDgBdlLOE10JAlVtKk.
ECDSA key fingerprint is MD5:60:21:02:4d:b8:ce:cd:bc:19:33:0d:58:d6:4c:bd:fe.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added 'node2' (ECDSA) to the list of known hosts.
Last login: Sat Sep 11 09:59:21 2021 from 192.168.174.10
[root@node2 ~]#
- 测试主机连通性
[root@ansible ~]# ansible -m ping nodes # 显示为绿色
node2 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"ping": "pong"
}
node1 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"ping": "pong"
}
ansible的执行状态
- 绿色:执行成功并且不需要做改变的操作
- 黄色:执行成功并且对目标主机做变更
- 红色:执行失败
- 粉色:警告信息
- 蓝色:显示ansible命令执行的过程
ansible 常用命令
ansible 命令集
/usr/bin/ansible
Ansibe AD-Hoc 临时命令执行工具,常用于临时命令的执行
/usr/bin/ansible-doc
Ansible 模块功能查看工具
/usr/bin/ansible-galaxy
下载/上传优秀代码或Roles模块 的官网平台,基于网络的
/usr/bin/ansible-playbook
Ansible 定制自动化的任务集编排工具
/usr/bin/ansible-pull
Ansible远程执行命令的工具,拉取配置而非推送配置(使用较少,海量机器时使用,对运维的架构能力要求较高)
/usr/bin/ansible-vault
Ansible 文件加密工具
/usr/bin/ansible-console
Ansible基于Linux Consoble界面可与用户交互的命令执行工具
其中,我们比较常用的是/usr/bin/ansible
和/usr/bin/ansible-playbook
。
ansible-doc 命令
ansible-doc 命令常用于获取模块信息及其使用帮助,一般用法如下:
ansible-doc -l #获取全部模块的信息
ansible-doc -s MOD_NAME #获取指定模块的使用帮助
[root@server ~]# ansible-doc
Usage: ansible-doc [options] [module...]
Options:
-h, --help show this help message and exit # 显示命令参数API文档
-l, --list List available modules #列出可用的模块
-M MODULE_PATH, --module-path=MODULE_PATH #指定模块的路径
specify path(s) to module library (default=None)
-s, --snippet Show playbook snippet for specified module(s) #显示playbook制定模块的用法
-v, --verbose verbose mode (-vvv for more, -vvvv to enable # 显示ansible-doc的版本号查看模块列表:
connection debugging)
--version show program's version number and exit
- 以mysql为例
[root@server ~]# ansible-doc -l |grep mysql
mysql_db Add or remove MySQL databases from a remote...
mysql_replication Manage MySQL replication
mysql_user Adds or removes a user from a MySQL databas...
mysql_variables Manage MySQL global variables
[root@server ~]# ansible-doc -s mysql_user
[root@ansible ~]# ansible-doc -s mysql_user
- name: Adds or removes a user from a MySQL database
mysql_user:
append_privs: # Append the privileges defined by priv to the existing ones
for this user instead of
overwriting existing ones.
ca_cert: # The path to a Certificate Authority (CA) certificate. This
option, if used, must
specify the same certificate
as used by the server.
check_implicit_admin: # Check if mysql allows login as root/nopassword before
trying supplied credentials.
client_cert: # The path to a client public key certificate.
client_key: # The path to the client private key.
config_file: # Specify a config file from which user and password are to
be read.
connect_timeout: # The connection timeout when connecting to the MySQL server.
encrypted: # Indicate that the 'password' field is a
`mysql_native_password`
hash.
host: # The 'host' part of the MySQL username.
host_all: # Override the host option, making ansible apply changes to
all hostnames for a given
user. This option cannot be
used when creating users.
login_host: # Host running the database.
login_password: # The password used to authenticate with.
login_port: # Port of the MySQL server. Requires `login_host' be defined
as other than localhost if
login_port is used.
login_unix_socket: # The path to a Unix domain socket for local connections.
login_user: # The username used to authenticate with.
name: # (required) Name of the user (role) to add or remove.
password: # Set the user's password..
ansible 命令详解
命令的具体格式如下:
ansible <host-pattern> [-f forks] [-m module_name] [-a args]
也可以通过ansible -h
来查看帮助,下面我们列出一些比较常用的选项,并解释其含义:
-a MODULE_ARGS
#模块的参数,如果执行默认COMMAND的模块,即是命令参数,如: “date”,“pwd”等等
-k
,--ask-pass
#ask for SSH password。登录密码,提示输入SSH密码而不是假设基于密钥的验证
--ask-su-pass
#ask for su password。su切换密码
-K
,--ask-sudo-pass
#ask for sudo password。提示密码使用sudo,sudo表示提权操作
--ask-vault-pass
#ask for vault password。假设我们设定了加密的密码,则用该选项进行访问
-B SECONDS
#后台运行超时时间
-C
#模拟运行环境并进行预运行,可以进行查错测试
-c CONNECTION
#连接类型使用
-f FORKS
#并行任务数,默认为5
-i INVENTORY
#指定主机清单的路径,默认为/etc/ansible/hosts
--list-hosts
#查看有哪些主机组
-m MODULE_NAME
#执行模块的名字,默认使用 command 模块,所以如果是只执行单一命令可以不用 -m参数
-o
#压缩输出,尝试将所有结果在一行输出,一般针对收集工具使用
-S
#用 su 命令
-R SU_USER
#指定 su 的用户,默认为 root 用户
-s
#用 sudo 命令
-U SUDO_USER
#指定 sudo 到哪个用户,默认为 root 用户
-T TIMEOUT
#指定 ssh 默认超时时间,默认为10s,也可在配置文件中修改
-u REMOTE_USER
#远程用户,默认为 root 用户
-v
#查看详细信息,同时支持-vvv
,-vvvv
可查看更详细信息
ansible 常用模块
1) 主机连通性测试
我们使用ansible web -m ping
命令来进行主机连通性测试
[root@ansible ~]# ansible nodes -m ping
node2 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"ping": "pong"
}
node1 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"ping": "pong"
}
2)command 模块
-
默认使用的模块
-
这个模块可以直接在远程主机上执行命令,并将结果返回本主机。
-
不支持管道,变量及重定向等
[root@ansible ~]# ansible-doc -s command - name: Executes a command on a remote node
[root@ansible ~]# ansible node1 -m command -a 'ss -tanl'
node1 | CHANGED | rc=0 >>
State Recv-Q Send-Q Local Address:Port Peer Address:Port
LISTEN 0 128 *:22 *:*
LISTEN 0 100 127.0.0.1:25 *:*
LISTEN 0 128 :::22 :::*
LISTEN 0 100 ::1:25 :::*
3)shell 模块
shell模块可以在远程主机上调用shell解释器运行命令,支持shell的各种功能,例如管道等。
[root@ansible ~]# ansible node1 -m shell -a "cat /etc/passwd | grep 'root'"
node1 | CHANGED | rc=0 >>
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
4)user模块
[root@node1 ~]# ansible-doc -s user
comment # 用户的描述信息
createhom # 是否创建家目录
force # 在使用`state=absent'是, 行为与`userdel --force'一致.
group # 指定基本组
groups # 指定附加组,如果指定为('groups=')表示删除所有组
home # 指定用户家目录
name # 指定用户名
password # 指定用户密码
remove # 在使用 `state=absent'时, 行为是与 `userdel --remove'一致.
shell # 指定默认shell
state #设置帐号状态,不指定为创建,指定值为absent表示删除
system # 当创建一个用户,设置这个用户是系统用户。这个设置不能更改现有用户
uid #指定用户的uid
update_password # 更新用户密码
expires #指明密码的过期时间
示例:
1.添加系统用户,指定uid、家目录、主组及注释
[root@ansible ~]# ansible -m user -a "system=yes name=zhangsan home=/home/zhangsan uid=111 comment='hello zhangsan'" node1
node1 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": true,
"comment": "hello zhangsan",
"create_home": true,
"group": 111,
"home": "/home/zhangsan",
"name": "zhangsan",
"shell": "/bin/bash",
"state": "present",
"system": true,
"uid": 111
}
2.删除用户及家目录
[root@ansible ~]# ansible -m user -a "name=zhangsan state=absent remove=yes" node1
node1 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": true,
"force": false,
"name": "zhangsan",
"remove": true,
"state": "absent",
"stderr": "userdel: zhangsan 邮件池 (/var/spool/mail/zhangsan) 未找到\n",
"stderr_lines": [
"userdel: zhangsan 邮件池 (/var/spool/mail/zhangsan) 未找到"
]
}
5)group模块
[root@node1 ~]# ansible-doc -s group
- name: 添加或删除组
action: group
gid # 设置组的GID号
name= # 管理组的名称
state # 指定组状态,默认为创建,设置值为absent为删除
system # 设置值为yes,表示为创建系统组
示例:
1.创建用户组
[root@ansible ~]# ansible -m group -a "name=mocking gid=111 system=yes" node1
node1 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": true,
"gid": 111,
"name": "mocking",
"state": "present",
"system": true
}
2.删除用户组
[root@ansible ~]# ansible -m group -a "name=mocking gid=111 state=absent" node1
node1 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": true,
"name": "mocking",
"state": "absent"
}
6)script 模块
该模块用于将本机的脚本在被管理端的机器上运行。
free_form参数: 必须参数,指定需要执行的脚本,脚本位于 ansible 管理主机本地,并没有具体的一个参数名叫 free_form,具体解释请参考 command 模块。
chdir参数: 此参数的作用就是指定一个远程主机中的目录,在执行对应的脚本之前,会先进入到chdir 参数指定的目录中。
creates参数: 使用此参数指定一个远程主机中的文件,当指定的文件存在时,就不执行对应脚本,可参考 command 模块中的解释。
removes参数: 使用此参数指定一个远程主机中的文件,当指定的文件不存在时,就不执行对应脚本,可参考 command 模块中的解释。
示例:
- 首先,我们写一个脚本,并给其加上执行权限:
[root@server ~]# vim /tmp/df.sh
#!/bin/bash
date >> /tmp/disk_total.log
df -lh >> /tmp/disk_total.log
[root@server ~]# chmod +x /tmp/df.sh
- 运行命令来实现在被管理端执行该脚本
[root@ansible ~]# ansible node1 -m script -a "/tmp/df.sh"
node1 | CHANGED => {
"changed": true,
"rc": 0,
"stderr": "Shared connection to node1 closed.\r\n",
"stderr_lines": [
"Shared connection to node1 closed."
],
"stdout": "",
"stdout_lines": []
}
- 查看文件内容
[root@ansible ~]# ansible node1 -m shell -a " cat /tmp/disk_total.log"
node1 | CHANGED | rc=0 >>
2021年 09月 11日 星期六 12:13:31 CST
文件系统 容量 已用 可用 已用% 挂载点
/dev/mapper/centos-root 17G 1.5G 16G 9% /
devtmpfs 898M 0 898M 0% /dev
tmpfs 910M 0 910M 0% /dev/shm
tmpfs 910M 9.6M 901M 2% /run
tmpfs 910M 0 910M 0% /sys/fs/cgroup
/dev/sda1 1014M 146M 869M 15% /boot
tmpfs 182M 0 182M 0% /run/user/0
7) copy
[root@node1 ~]# ansible-doc -s copy
backup:在覆盖之前,将源文件备份,备份文件包含时间信息。
content:用于替代“src”,可以直接设定指定文件的值
dest:必选项。要将源文件复制到的远程主机的绝对路径
directory_mode:递归设定目录的权限,默认为系统默认权限
force:强制覆盖目的文件内容,默认为yes
others:所有的file模块里的选项都可以在这里使用
src:被复制到远程主机的本地文件,可以是绝对路径,也可以是相对路径。如果路径是一个目录,它将递归 复制
ansible -m copy -a "src=/本地文件 dest=/远程文件" nodes
- 在创建文件时修改文件的属主和属组信息
[root@ansible ~]# ansible -m copy -a "src=/root/test1 dest=/root/test owner=root group=root" node1
node1 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": true,
"checksum": "da39a3ee5e6b4b0d3255bfef95601890afd80709",
"dest": "/root/test",
"gid": 0,
"group": "root",
"md5sum": "d41d8cd98f00b204e9800998ecf8427e",
"mode": "0644",
"owner": "root",
"size": 0,
"src": "/root/.ansible/tmp/ansible-tmp-1631335550.82-23060-93283576299397/source",
"state": "file",
"uid": 0
}
- 在传输文件时修改文件的权限信息,并且备份远程主机文件
[root@ansible ~]# ansible -m copy -a "src=/root/test1 dest=/root/test bakup=yes mode=1777" node1
node1 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": true,
"checksum": "da39a3ee5e6b4b0d3255bfef95601890afd80709",
"dest": "/root/test",
"gid": 0,
"group": "root",
"mode": "01777",
"owner": "root",
"path": "/root/test",
"size": 0,
"state": "file",
"uid": 0
}
- 创建一个文件并直接编辑文件
[root@ansible ~]# ansible -m copy -a "content='hello siri' dest=/root/test1" node1
8) file
该模块主要用于设置文件的属性,比如创建文件、创建链接文件、删除文件等。
[root@node1 ~]# ansible-doc -s file
- name: Sets attributes of files
force:需要在两种情况下强制创建软链接,一种是源文件不存在,但之后会建立的情况下;另一
种是目标软 链接已存在,需要先取消之前的软链,然后创建新的软链,有两个选项:yes|no
group:定义文件/目录的属组
mode:定义文件/目录的权限
owner:定义文件/目录的属主
path:必选项,定义文件/目录的路径
recurse:递归设置文件的属性,只对目录有效
src:被链接的源文件路径,只应用于state=link的情况
dest:被链接到的路径,只应用于state=link的情况
state:
absent: 删除文件
directory:如果目录不存在,就创建目录
file:验证文件是否存在,即使文件不存在,也不会被创建
link:创建软链接
hard:创建硬链接
touch:如果文件不存在,则会创建一个新的文件,如果文件或目录已存在,则更新其后修改时间
示例:
创建目录
[root@ansible ~]# ansible -m file -a "name=test1 owner=root group=root mode=1644 state=directory " server2
创建文件
[root@ansible ~]# ansible -m file -a "path=/root/test2 owner=root group=root mode=1644 state=touch" server2
删除文件
[root@ansible ~]# ansible -m file -a "path=/root/test2 owner=root group=root mode=1644 state=absent" server2
创建软链文件
[root@ansible ~]# ansible -m file -a "src=/root/test1 dest=/root/test2 state=link" server2
创建硬链接文件
[root@ansible ~]# ansible -m file -a "src=/root/test.txt dest=/root/test2 state=hard" server2
9) yum
[root@node1 ~]# ansible-doc -s yum
conf_file #设定远程yum安装时所依赖的配置文件。如配置文件没有在默认的位置。
disable_gpg_check #是否禁止GPG checking,只用于`present' or `latest'。
disablerepo #临时禁止使用yum库。 只用于安装或更新时。
enablerepo #临时使用的yum库。只用于安装或更新时。
name= #所安装的包的名称
state #present安装, latest安装新的, absent 卸载软件。
update_cache #强制更新yum的缓存
示例:
ansible -m yum -a "name=httpd state=latest" nodes
10) service
[root@node1 ~]# ansible-doc service
> SERVICE (/usr/lib/python2.7/site-packages/ansible/modules/system/service.py)
Controls services on remote hosts. Supported init systems include BSD init, OpenRC, SysV, Solaris
SMF, systemd, upstart. For Windows targets, use the [win_service] module instead.
* note: This module has a corresponding action plugin.
arguments #命令行提供额外的参数
enabled #设置开机启动,可以设置为yes或者no。
name= #服务名称
runlevel #开机启动的级别,一般不用指定。
sleep #在重启服务的过程中,是否等待。如在服务关闭以后等待2秒再启动。
state #started启动服务, stopped停止服务, restarted重启服务, reloaded重载配置
示例:
- 设置开机自启动服务
ansible -m service -a "name=httpd state=started" nodes
11)selinux
[root@node1 ~]# ansible-doc -s selinux
# selinux模块针对selinux的修改操作是针对配置文件进行修改的
- name: Change policy and state of SELinux
selinux:
configfile: # path to the SELinux configuration file, if non-standard
policy: # name of the SELinux policy to use
state: # (required) The SELinux mode
12)cron 模块
该模块适用于管理cron
计划任务的。
其使用的语法跟我们的crontab
文件中的语法一致,同时,可以指定以下选项:
day=
#日应该运行的工作( 1-31, *, */2, )
hour=
# 小时 ( 0-23, *, */2, )
minute=
#分钟( 0-59, *, */2, )
month=
# 月( 1-12, *, /2, )
weekday=
# 周 ( 0-6 for Sunday-Saturday, )
job=
#指明运行的命令是什么
name=
#定时任务描述
reboot
# 任务在重启时运行,不建议使用,建议使用special_time
special_time
#特殊的时间范围,参数:reboot(重启时),annually(每年),monthly(每月),weekly(每周),daily(每天),hourly(每小时)
state
#指定状态,present表示添加定时任务,也是默认设置,absent表示删除定时任务
user
# 以哪个用户的身份执行
添加计划任务
[root@ansible ~]# ansible node1 -m cron -a 'name="ntp update every 5min" minute=*/5 job="/sbin/ntpdate 192.168.174.10 &> /dev/null"'
node1 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": true,
"envs": [],
"jobs": [
"ntp update every 5min"
]
}
我们可以去查看一下:
[root@ansible ~]# ansible node1 -m shell -a "crontab -l"
node1 | CHANGED | rc=0 >>
#Ansible: ntp update every 5min
*/5 * * * * /sbin/ntpdate 192.168.174.10 &> /dev/null
set up
ansible -m setup nodes #获取远程主机的详细信息
ansible-doc -l # 可以查询ansible具有的所有模块
https://docs.ansible.com/ansible/latest/index.html # 官方文档
Playbook
简介
playbook是由一个或者多个play组成的列表,可以让这些列表按事先编排的机制执行;所谓task是调用 ansible的具体模块,在模块参数中可以使用变量。模块执行是幂等性的,意味着多次执行结果相同。使 用yaml语言编写playbook,后缀名一般为.yml
特点
- yaml的可读性好
- yaml和脚本语言的交互性好
- yaml使用实现语言的数据类型
- yaml有一个一致性的信息模型
- yaml易于实现
- yaml可以基于流来处理
核心组件
- hosts:执行的远程主机列表
- tasks:任务,由模块定义操作列表
- variables:内置变量或者自定义变量
- templates:模板,定义模板文件,模板文件一般是由jinja2语言编写的
- handlers:和notity结合使用,为条件触发操作,满足条件则执行
- roles:角色
Playbook语法
playbook
使用yaml
语法格式,后缀可以是yaml
,也可以是yml
。
- 在单一一个
playbook
文件中,可以连续三个连子号(---
)区分多个play
。还有选择性的连续三个点好(...
)用来表示play
的结尾,也可省略。 - 次行开始正常写
playbook
的内容,一般都会写上描述该playbook
的功能。 - 使用#号注释代码。
- 缩进必须统一,不能空格和
tab
混用。 - 缩进的级别也必须是一致的,同样的缩进代表同样的级别,程序判别配置的级别是通过缩进结合换行实现的。
YAML
文件内容和Linux
系统大小写判断方式保持一致,是区分大小写的,k/v
的值均需大小写敏感k/v
的值可同行写也可以换行写。同行使用:分隔。v
可以是个字符串,也可以是一个列表- 一个完整的代码块功能需要最少元素包括
name: task
官方示例
官方文档: http://www.ansible.com.cn/docs/playbooks_intro.html
在线检测工具:http://www.yamllint.com/
---
- hosts: webservers
vars:
http_port: 80
max_clients: 200
remote_user: root
tasks:
- name: ensure apache is at the latest version
yum: pkg=httpd state=latest
- name: write the apache config file
template: src=/srv/httpd.j2 dest=/etc/httpd.conf
notify:
- restart apache
- name: ensure apache is running
service: name=httpd state=started
handlers:
- name: restart apache
service: name=httpd state=restarted
常见变量
主机名: "{{ ansible_hostname }}"
操作系统版本: "{{ ansible_distribution }}" "{{ ansible_distribution_version
}}"
内核版本: "{{ ansible_kernel }}"
系统位数: "{{ ansible_userspace_bits }}"
网卡:"{{ ansible_eth0["device"] }}"
IP地址: "{{ ansible_eth0["ipv4"]["address"] }}"
子网掩码: "{{ ansible_eth0["ipv4"]["netmask"] }}"
总内存: "{{ ansible_memory_mb["real"]["total"] }}"
内存空闲: "{{ ansible_memfree_mb }}"
自定义剧本
安装httpd
[root@ansible ansible]# cat httpd_install.yml
- name: Configure Apache HTTP Server
hosts: node1
remote_user: root
tasks:
- name: Install httpd
yum:
name: httpd
state: latest
- name: Start httpd
service:
name: httpd
state: started
- 检查脚本格式
[root@ansible ansible]# ansible-playbook --syntax-check httpd_install.yml
playbook: httpd_install.yml
- 执行脚本
[root@ansible ansible]# ansible-playbook httpd_install.yml
PLAY [Configure Apache HTTP Server] *******************************************************
TASK [Gathering Facts] ********************************************************************
ok: [node1]
TASK [Install httpd] **********************************************************************
ok: [node1]
TASK [Start httpd] ************************************************************************
changed: [node1]
PLAY RECAP ********************************************************************************
node1 : ok=3 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
定义网站内容
[root@ansible ansible]# cat template/index.j2
<h1>hello siri~</h1>
这是我的博客地址,欢迎大家学习ansible!
This web server is {{ ansible_hostname }}
[root@ansible ansible]# cat index.yml
- name: Configure Apache index file
hosts: nodes
remote_user: root
tasks:
- name: Copy index.j2 to nodes servers
template:
src: /ansible/template/index.j2
dest: /var/www/html/index.html
- 执行脚本
[root@ansible ansible]# ansible-playbook httpd_install.yml
PLAY [Configure Apache HTTP Server] *******************************************************
TASK [Gathering Facts] ********************************************************************
ok: [node2]
ok: [node1]
TASK [Install httpd] **********************************************************************
ok: [node1]
changed: [node2]
TASK [Start httpd] ************************************************************************
ok: [node1]
changed: [node2]
PLAY RECAP ********************************************************************************
node1 : ok=3 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
node2 : ok=3 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[root@ansible ansible]# ansible-playbook index.yml
PLAY [Configure Apache index file] ********************************************************
TASK [Gathering Facts] ********************************************************************
ok: [node1]
ok: [node2]
TASK [Copy index.j2 to nodes servers] *****************************************************
ok: [node1]
changed: [node2]
PLAY RECAP ********************************************************************************
node1 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
node2 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
- 验证
[root@ansible ansible]# curl node1
<h1>hello siri~</h1>
这是我的博客地址,欢迎大家学习ansible!
This web server is node1
[root@ansible ansible]# curl node2
<h1>hello siri~</h1>
这是我的博客地址,欢迎大家学习ansible!
This web server is node2
条件判断
- 选择性关闭node1的apache服务
[root@ansible ansible]# cat httpd_stop.yml
- name: Stop httpd
hosts: nodes
remote_user: root
tasks:
- name: stop httpd
service:
name: httpd
state: stopped
when: ansible_hostname == "node1"
[root@ansible ansible]# ansible-playbook --syntax-check httpd_stop.yml
playbook: httpd_stop.yml
[root@ansible ansible]# ansible-playbook httpd_stop.yml
PLAY [Stop httpd] *************************************************************************
TASK [Gathering Facts] ********************************************************************
ok: [node1]
ok: [node2]
TASK [stop httpd] *************************************************************************
skipping: [node2]
changed: [node1]
PLAY RECAP ********************************************************************************
node1 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
node2 : ok=1 changed=0 unreachable=0 failed=0 skipped=1 rescued=0 ignored=0
循环迭代
- 创建用户
[root@ansible ansible]# cat user_create.yml
- name: Create User
hosts: node1
remote_user: root
tasks:
- name: Create server users
user:
name: "{{ item.name }}"
group: "{{ item.group }}"
state: "present"
with_items:
- { name: 'zhangsan', group: 'wheel'}
- { name: 'lisi', group: 'root'}
[root@ansible ansible]# ansible-playbook user_create.yml
PLAY [Create User] ************************************************************************
TASK [Gathering Facts] ********************************************************************
ok: [node1]
TASK [Create server users] ****************************************************************
changed: [node1] => (item={u'group': u'wheel', u'name': u'zhangsan'})
changed: [node1] => (item={u'group': u'root', u'name': u'lisi'})
PLAY RECAP ********************************************************************************
node1 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
# 验证
[root@node1 ~]# id zhangsan
uid=1000(zhangsan) gid=10(wheel) 组=10(wheel)
[root@node1 ~]# id lisi
uid=1001(lisi) gid=0(root) 组=0(root)
安装nginx并且修改配置文件
[root@VM-4-10-centos ~]# cat nginx.yaml
- name: Update web servers
hosts: node1
remote_user: root
tasks:
- name: install epel
yum:
name: epel-release.noarch
state: latest
- name: install nginx
yum:
name: nginx
state: present
- name: copy nginx configure file
copy:
src: /root/ansible/conf/site1.conf
dest: /etc/nginx/conf.d/site1.conf
- name: creat dir
shell: mkdir -pv /usr/share/nginx/html/{bbs,blog,www}
- name: creat index1.html
shell: echo "bbs" > /usr/share/nginx/html/bbs/index.html && echo "www" > /usr/share/nginx/html/www/index.html && echo "blog" > /usr/share/nginx/html//blog/index.html
- name: start nginx
service:
name: nginx
state: restarted
- 定义conf文件
[root@VM-4-10-centos ~]# cat site1.conf
server {
listen *:8080;
server_name bbs.eagle.com;
location / {
root /usr/share/nginx/html/bbs;
index index.html;
}
}
server {
listen *:8080;
server_name blog.eagle.com;
location / {
root /usr/share/nginx/html/blog;
index index.html;
}
}
server {
listen *:8080;
server_name www.eagle.com;
location / {
root /usr/share/nginx/html/www;
index index.html;
}
}
[root@ansible bin]# ansible-playbook nginx.yaml
[WARNING]: Invalid characters were found in group names but not replaced, use -vvvv
to see details
PLAY [Update web servers] ***********************************************************
TASK [Gathering Facts] **************************************************************
ok: [server2]
TASK [install epel] *****************************************************************
ok: [server2]
TASK [install nginx] ****************************************************************
ok: [server2]
TASK [copy nginx configure file] ****************************************************
changed: [server2]
TASK [creat dir] ********************************************************************
[WARNING]: Consider using the file module with state=directory rather than running
'mkdir'. If you need to use command because file is insufficient you can add 'warn:
false' to this command task or set 'command_warnings=False' in ansible.cfg to get
rid of this message.
changed: [server2]
TASK [creat index1.html] ************************************************************
changed: [server2]
TASK [creat index2.html] ************************************************************
changed: [server2]
TASK [creat index3.html] ************************************************************
changed: [server2]
TASK [start nginx] ******************************************************************
changed: [server2]
PLAY RECAP **************************************************************************
server2 : ok=9 changed=6 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
- 验证
[root@ansible bin]# curl bbs.eagle.com:8080
bbs
[root@ansible bin]# curl blog.eagle.com:8080
blog
[root@ansible bin]# curl www.eagle.com:8080
www
roles介绍
角色(roles)是ansible自1.2版本开始引入的新特性,用于层次性,结构化地组织playbook。roles能够根据层次型结构自动装载变量文件、tasks以及handlers等。要使用roles只需要在playbook中使用include指令即可。简单的说,roles就是通过分别将变量、文件、任务、模块及处理器放置于单独的目录中、并可以便捷地include他们的一种机制。角色一般用于基于主机构建服务的场景中、但也可以是用于构建守护进程等场景中。
一个项目的结构如下:
site.yml
webservers.yml
fooservers.yml
roles/
common/
files/
templates/
tasks/
handlers/
vars/
defaults/
meta/
webservers/
files/
templates/
tasks/
handlers/
vars/
defaults/
meta/
一个 playbook 如下:
---
- hosts: webservers
roles:
- common
- webservers
这个 playbook 为一个角色 ‘x’ 指定了如下的行为:
- 如果 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/ 中的文件,不需要指明文件的路径。
示例:
[root@ansible ansible]# cd /etc/ansible/roles/
[root@ansible roles]# ansible-galaxy init apache
- Role apache was created successfully
[root@ansible roles]# ls
apache
[root@ansible roles]# ll apache/
总用量 4
drwxr-xr-x 2 root root 22 9月 11 21:20 defaults
drwxr-xr-x 2 root root 6 9月 11 21:20 files
drwxr-xr-x 2 root root 22 9月 11 21:20 handlers
drwxr-xr-x 2 root root 22 9月 11 21:20 meta
-rw-r--r-- 1 root root 1328 9月 11 21:20 README.md
drwxr-xr-x 2 root root 22 9月 11 21:20 tasks
drwxr-xr-x 2 root root 6 9月 11 21:20 templates
drwxr-xr-x 2 root root 39 9月 11 21:20 tests
drwxr-xr-x 2 root root 22 9月 11 21:20 vars
[root@ansible roles]# tree /etc/ansible/roles/
/etc/ansible/roles/
└── apache
├── defaults
│ └── main.yml
├── files
├── handlers
│ └── main.yml
├── meta
│ └── main.yml
├── README.md
├── tasks
│ └── main.yml
├── templates
├── tests
│ ├── inventory
│ └── test.yml
└── vars
└── main.yml
* 目录结构:
- tasks:此目录中至少有一个名为main.yaml文件,用于定义各种task,其他文件需要由main.yaml文件进行调用
- handlers:此目录中至少有一个名为main.yaml文件,用于定义各种handler,其他文件需要被main.yaml进行调用
- vars:此目录中至少有一个名为main.yaml文件,用于定义各种变量,其他文件需要被main.yaml进行调用
- templates:存储template模块调用的模板文件
- meta:此目录中至少有一个名为main.yaml文件,定义当前角色的设定及其依赖关系,其他的文件需要被main.yaml文件进行调用
- default:此目录中至少有一个main.yaml文件,用于设定默认的值
- files:此目录存放copy或者script等模块调用的文件
使用角色安装httpd
- 准备tasks里的main.yml文件
[root@ansible tasks]# cat main.yml
---
# tasks file for apache
- name: Install httpd
yum:
name: httpd
state: present
- name: Start httpd
service:
name: httpd
state: started
- name: write conf file
shell: echo "httpd2" > /var/www/html/index.html
[root@ansible tasks]# pwd
/etc/ansible/roles/apache/tasks
- 准备site.yml文件
[root@ansible roles]# cat site.yml
- hosts: node2
remote_user: root
roles:
- apache
[root@ansible roles]# pwd
/etc/ansible/roles
- 验证并执行
[root@ansible roles]# ansible-playbook --syntax-check site.yml
playbook: site.yml
[root@ansible roles]# ansible-playbook site.yml
[root@ansible roles]# curl node2
httpd2