以下配置都是以下表环境为例
角色 | 主机名 | IP地址 | 组名 | CPU |
控制主节点 | ansiblecontrol | 192.168.242.10 | --- | 2C |
被管理节点 | web1 | 192.168.242.11 | webservers | 2C |
被管理节点 | web2 | 192.168.242.12 | webservers | 2C |
Ansible安装
安装前提
安装Ansible
Ansible环境准备
角色名 | IP |
master.zjm.com | 192.168.242.10 |
node1.zjm.com | 192.168.242.11 |
node2.zjm.com | 192.168.242.12 |
源码安装:源码安装需要python2.6以上版本,其依赖模块paramiko、PyYAML、Jinja2、httplib2、 simplejson、pycrypto模块,以上模块可以通过pip或easy_install 进行安装
pip安装:pip是专门用来管理Python模块的工具,Ansible会将每次正式发布都更新到pip仓库中。所以通过pip 安装或更新Ansible,会比较稳妥的拿到最新稳定版。
yum安装
安装 CentOS 7 的 EPEL repository
[root@master ~]# yum install -y epel-release
使用 yum 来安装 ansible
[root@master ~]# yum install -y ansible
查看ansible的版本
[root@master ~]# ansible --version
ansible 2.9.23
config file = /etc/ansible/ansible.cfg
configured module search path = [u'/root/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
ansible python module location = /usr/lib/python2.7/site-packages/ansible
executable location = /bin/ansible
python version = 2.7.5 (default, Aug 7 2019, 00:51:29) [GCC 4.8.5 20150623 (Red Hat 4.8.5-39)]
ad-hoc的方式确定下ansible能否正常工作
[root@master ~]# ansible localhost -m ping
localhost | SUCCESS => {
"changed": false,
"ping": "pong"
}
配置运行环境
配置Ansible环境
Ansible配置文件是以ini格式存储配置数据的,在 Ansible 中,几乎所有的配置项都可以通过
使用公钥认证
~/.ansible.cfg 或 /etc/ansible/ansible.cfg 的配置项:
[defaults]
host_key_checking = False
或者直接在控制主机的操作系统中设置环境变量如下:
$export ANSIBLE_HOST_KEY_CHECKING=False
配置 Linux 主机 SSH 无密码访问
[root@master ~]# vi /etc/hosts
[root@master ~]# tail -3 /etc/hosts
192.168.242.10 master
192.168.242.11 node1
192.168.242.12 node2
1、在控制主机上创建密钥
[root@master ~]# ssh-keygen -f ~/.ssh/id_rsa -P '' -q
[root@master ~]# ls -l ~/.ssh
total 8
-rw-------. 1 root root 1679 Aug 11 23:02 id_rsa
-rw-r--r--. 1 root root 393 Aug 11 23:02 id_rsa.pub
2、下发密钥到被管理节点
[root@master ~]# ssh-copy-id node1
[root@master ~]# ssh-copy-id node2
3、验证SSH无密钥配置是否成功
[root@master ~]# for name in node{1,2}; do ssh $name hostname; done
node1
node2
Ansible Inventory
在大规模的配置管理工作中,我们需要管理不同业务的不同机器,这些机器的信息都存放在Ansible的Inventory组件里面,在我们工作中配置部署针对的主机必须先存放在Inventory里面,这样才能使用Ansible对它进行操作,默认Ansible的Inventory是一个静态的INI格式的文件/etc/ansible/hosts,当然,还可以通过ANSIBLE_HOSTS环境变量指定或者运行ansible和ansible-playbook的时候用-i参数临时设置
定义主机和主机组
具体的定义实例
[root@master ~]# vi /etc/ansible/hosts
[root@master ~]# tail -11 /etc/ansible/hosts
192.168.242.11 ansible_ssh_pass='123'
192.168.242.12 ansible_ssh_pass='123'
[docker]
192.168.242.1[1:2]
[docker:vars]
ansible_ssh_pass='123'
[ansible:children]
docker
第一二行:定义了一个主机是192.168.242.11/12,使用Inventory内置变量定义了SSH登录密码
第三行:定义了一个docker的组,第四行:定义了docker组下有两台主机192.168.242.11/192.168.242.12,用':'可以表示连续的多个,例如1:5,则为从一到五
第五六行:针对docker组使用了Inventory内置变量定义了SSH登陆密码
第七八行:定义了一个ansible的组,在这个组下包含了docker组
[root@master ~]# ansible 192.168.242.11:192.168.242.12 -m ping -o
192.168.242.12 | SUCCESS => {"ansible_facts": {"discovered_interpreter_python": "/usr/bin/python"}, "changed": false, "ping": "pong"}
192.168.242.11 | SUCCESS => {"ansible_facts": {"discovered_interpreter_python": "/usr/bin/python"}, "changed": false, "ping": "pong"}
[root@master ~]# ansible docker -m ping -o
192.168.242.12 | SUCCESS => {"ansible_facts": {"discovered_interpreter_python": "/usr/bin/python"}, "changed": false, "ping": "pong"}
192.168.242.11 | SUCCESS => {"ansible_facts": {"discovered_interpreter_python": "/usr/bin/python"}, "changed": false, "ping": "pong"}
[root@master ~]# ansible ansible -m ping -o
192.168.242.12 | SUCCESS => {"ansible_facts": {"discovered_interpreter_python": "/usr/bin/python"}, "changed": false, "ping": "pong"}
192.168.242.11 | SUCCESS => {"ansible_facts": {"discovered_interpreter_python": "/usr/bin/python"}, "changed": false, "ping": "pong"}
动态Inventory
在实际应用部署中会有大量的主机列表,如果手动维护这些列表将是一个非常繁琐的事情,其实Ansible还支持动态的Inventory,动态Inventory就是Ansible所有的Inventory文件里面的主机列表和变量信息都支持从外部拉取
[root@master ~]# vi hosts.py
[root@master ~]# cat hosts.py
#!/usr/bin/env python3
import argparse
import sys
import json
def lists():
r = {}
h = [ '192.168.242.1' + str(i) for i in range(0,2) ]
hosts = {'host': h}
r['docker'] = hosts
return json.dumps(r,indent=3)
def hosts(name):
r = {'ansible_ssh_pass': '123'}
cpis=dict(r.items())
return json.dumps(cpis)
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument('-l', '--list' , help='hosts list' , action='store_true')
parser.add_argument('-H', '--host', help='hosts vars')
args = vars(parser.parse_args())
if args['list']:
print(lists())
elif args['host']:
print(hosts(args['host']))
else:
parser.print_help()
测试脚本
[root@master ~]# chmod +x hosts.py
[root@master ~]# ./hosts.py -l
{
"docker": {
"host": [
"192.168.242.10",
"192.168.242.11",
"192.168.242.12"
]
}
}
[root@master ~]# ./hosts.py -H 192.168.242.12
{"ansible_ssh_pass": "123"}
Ansible组成介绍
[root@master ~]# tree /etc/ansible/
/etc/ansible/
├── ansible.cfg #ansible的配置文件
├── hosts #资源清单文件
└── roles
1 directory, 2 files
主机联通性测试
#修改主机与组的配置
[root@master ~]# cat >> /etc/ansible/hosts << EOF
> [webservers]
> node[1:2]
> EOF
#测试一台主机
[root@master ~]# ansible node1 -m ping
node1 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"ping": "pong"
}
#测试一组主机
[root@master ~]# ansible webservers -m ping
node1 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"ping": "pong"
}
node2 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"ping": "pong"
}
批量执行命令
#使用ansible在远程机器输出“hello ansible!"
#使用shell模块
[root@master ~]# ansible webservers -m shell -a '/bin/echo hello ansible!' -o
node2 | CHANGED | rc=0 | (stdout) hello ansible!
node1 | CHANGED | rc=0 | (stdout) hello ansible!
#使用command模块
[root@master ~]# ansible webservers -a '/bin/echo hello ansible!' -o
node1 | CHANGED | rc=0 | (stdout) hello ansible!
node2 | CHANGED | rc=0 | (stdout) hello ansible!
#使用raw模块
[root@master ~]# ansible webservers -m raw -a '/bin/echo hello ansible!'
node1 | CHANGED | rc=0 >>
hello ansible!
Shared connection to node1 closed.
node2 | CHANGED | rc=0 >>
hello ansible!
Shared connection to node2 closed.
获取帮助信息
ansible-doc:用于查看模块信息
//参数-1 列出可使用的模块
[root@master ~]# ansible-doc -l
fortios_router_community_list Configure community lists in Fortinet's FortiOS and FortiGate
azure_rm_devtestlab_info Get Azure DevTest Lab facts
ecs_taskdefinition register a task definition in ecs
avi_alertscriptconfig Module for setup of AlertScriptConfig Avi RESTful Object
tower_receive Receive assets from Ansible Tower
netapp_e_iscsi_target NetApp E-Series manage iSCSI target configuration
azure_rm_acs Manage an Azure Container Service(ACS) instance
fortios_log_syslogd2_filter Filters for remote system server in Fortinet's FortiOS and FortiGate
//-s 列岀某个模块支持的动作
[root@master ~]# ansible-doc -s shell
- name: Execute shell commands on targets
shell:
chdir: # Change into this directory before running the command.
cmd: # The command to run followed by optional arguments.
creates: # A filename, when it already exists, this step will *not*
be run.
executable: # Change the shell used to execute the command. This
expects an absolute path
to the executable.
free_form: # The shell module takes a free form command to run, as a
string. There is no actual
parameter named 'free
form'. See the examples on
how to use this module.
removes: # A filename, when it does not exist, this step will *not*
be run.
stdin: # Set the stdin of the command directly to the specified
value.
stdin_add_newline: # Whether to append a newline to stdin data.
warn: # Whether to enable task warnings.
[root@master ~]# ansible-doc -v shell
Using /etc/ansible/ansible.cfg as config file
> SHELL (/usr/lib/python2.7/site-packages/ansible/modules/commands/shell.py)
The `shell' module takes the command name followed by a list
of space-delimited arguments. Either a free form command or
`cmd' parameter is required, see the examples. It is almost
exactly like the [command] module but runs the command through
a shell (`/bin/sh') on the remote node. For Windows targets,
use the [win_shell] module instead.
* This module is maintained by The Ansible Core Team
* note: This module has a corresponding action plugin.
ansible:用于执行ad-hoc命令
[root@master ~]# ansible localhost -a date
localhost | CHANGED | rc=0 >>
Thu Aug 12 00:22:39 CST 2021
[root@master ~]# ansible node1 -m ping -vv
ansible 2.9.23
config file = /etc/ansible/ansible.cfg
configured module search path = [u'/root/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
ansible python module location = /usr/lib/python2.7/site-packages/ansible
executable location = /usr/bin/ansible
python version = 2.7.5 (default, Nov 16 2020, 22:23:17) [GCC 4.8.5 20150623 (Red Hat 4.8.5-44)]
Using /etc/ansible/ansible.cfg as config file
Skipping callback 'actionable', as we already have a stdout callback.
Skipping callback 'counter_enabled', as we already have a stdout callback.
Skipping callback 'debug', as we already have a stdout callback.
Skipping callback 'dense', as we already have a stdout callback.
Skipping callback 'dense', as we already have a stdout callback.
Skipping callback 'full_skip', as we already have a stdout callback.
Skipping callback 'json', as we already have a stdout callback.
Skipping callback 'minimal', as we already have a stdout callback.
Skipping callback 'null', as we already have a stdout callback.
Skipping callback 'oneline', as we already have a stdout callback.
Skipping callback 'selective', as we already have a stdout callback.
Skipping callback 'skippy', as we already have a stdout callback.
Skipping callback 'stderr', as we already have a stdout callback.
Skipping callback 'unixy', as we already have a stdout callback.
Skipping callback 'yaml', as we already have a stdout callback.
META: ran handlers
node1 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"ping": "pong"
}
META: ran handlers
META: ran handlers