ansible入门
ansible简介
ansible是一个IT自动化配置管理工具,ansible可以集成丰富的模块和强大的功能组件,能减少运维人员重复性工作。
ansible主要功能
批量执行远程命令,可以同时对n台主机进行命令的执行
批量配置软件服务,可以进行自动化的方式配置和管理服务
实现软件开发,jumpserver底层使用了ansible
编排IT任务,利用playbook可以进行编排工作
ansible特点
无代理(salt需要,但是salt并非性能会高于ansible)
ansible任务是串行进行的,如果某个任务卡住会导致后续任务无法进行
操作灵活,有较多模块
简单易用,可以使用ad-hoc或者playbook
安全可靠,使用ssh协议通信
移植性高
幂等性,执行一次和n次效果一样,不会反复执行一下操作
ansible架构
ansible安装
pip安装(需要先安装python),ansible本身是python开发的
yum/apt 安装
root@ub-4:~# ansible localhost -m ping -o # 安装完了ansible之后可以ping自己 localhost | SUCCESS => {"changed": false,"ping": "pong"}
配置命令自动补全
[root@k81 ~]# yum -y install python-argcomplete [root@k81 ~]# activate-global-python-argcomplete # 要求bash版本大于等于4.2 # 操作完成之后需要断开终端重新连接,然后就可以敲命令用 tab 进行自动补全了 [root@k81 k8s_kubeadm]# bash --version GNU bash, version 4.2.46(2)-release (x86_64-redhat-linux-gnu) [root@k81 k8s_kubeadm]# ansible all_hosts -- --args --become-method --forks --list-hosts --private-key --timeout --version --ask-become-pass --become-user --help --module-name --scp-extra-args --tree --ask-pass --check --inventory --module-path --sftp-extra-args --user --ask-vault-pass --connection --inventory-file --one-line --ssh-common-args --vault-id --background --diff --key-file --playbook-dir --ssh-extra-args --vault-password-file --become --extra-vars --limit --poll --syntax-check --verbose [root@k81 k8s_kubeadm]# ansible all_hosts --list-hosts hosts (2): master01 node01
ansible的配置文件
配置文件查看
[root@k81 ~]# rpm -qc ansible /etc/ansible/ansible.cfg # 主配置文件路径 /etc/ansible/hosts # 资产文件
ansible.cfg较为重要的一些配置
[defaults] # some basic default values... #inventory = /etc/ansible/hosts # 资产文件路径 #library = /usr/share/my_modules/ # 模块路径 #module_utils = /usr/share/my_module_utils/ #remote_tmp = ~/.ansible/tmp # 执行ansible的时候远程主机的模块临时存放位置 #local_tmp = ~/.ansible/tmp # 执行ansible的时候本地主机的模块临时存放位置 #plugin_filters_cfg = /etc/ansible/plugin_filters.yml #forks = 5 # 同时可以执行的主机数量,也可以在ansible执行的时候-f来设置 #poll_interval = 15 #sudo_user = root #ask_sudo_pass = True #ask_pass = True #transport = smart #remote_port = 22 # 远程主机的ssh端口 #module_lang = C #module_set_locale = False #roles_path = /etc/ansible/roles # role存放路径 #host_key_checking = False # ansible第一次连接远程主机时候是否需要检查
配置文件优先级
在ansible.cfg中有这样一段描述
# nearly all parameters can be overridden in ansible-playbook # or with command line flags. ansible will read ANSIBLE_CONFIG, # ansible.cfg in the current working directory, .ansible.cfg in # the home directory or /etc/ansible/ansible.cfg, whichever it # finds first
这一段是描述ansible.cfg的配置是有优先级的,优先级排名度为:ANSIBLE_CONFIG环境变量 > 当前目录下的ansible.cfg > 当前用户家目录下.ansible.cfg > /etc/ansible/ansible.cfg
想要查看ansible当前加载的是哪个配置文件可以直接以如下命令查看
[root@k81 ~]# ansible --version ansible 2.9.27 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, Jun 28 2022, 15:30:04) [GCC 4.8.5 20150623 (Red Hat 4.8.5-44)]
然后我们演示一下其他几种情况下的配置文件加载情况
ANSIBLE_CONFIG环境变量
[root@k81 ~]# touch /opt/ansible.cfg # 文件名建议仍然叫ansible.cfg [root@k81 ~]# export ANSIBLE_CONFIG=/opt/ansible.cfg [root@k81 ~]# ansible --version ansible 2.9.27 config file = /opt/ansible/ansible.cfg # 已经切换过来了,切换的前提是这个文件得存在 [root@k81 ~]# unset ANSIBLE_CONFIG
当前目录的ansible.cfg
这种情况请不要在/tmp目录下创建配置文件,否则会有如下报错提示:
[WARNING] Ansible is being run in a world writable directory (/tmp), ignoring it as an ansible.cfg source. For more information see https://docs.ansible.com/ansible/devel/reference_appendices/config.html#cfg-in-world-writable-dir
这种情况下配置的inventory最好也用相对路径来配置,避免移植之后路径出现变化
[root@k81 ~]# mkdir /opt/project/ [root@k81 ~]# touch /opt/project/ansible.cfg && cd /opt/project/ [root@k81 project]# ansible --version ansible 2.9.27 config file = /opt/project/ansible.cfg
当前用户家目录配置文件
[root@k81 ~]# touch ~/.ansible.cfg [root@k81 ~]# ansible --version ansible 2.9.27 config file = /root/.ansible.cfg
如果无以上三种配置就加载/etc/ansible/ansible.cfg
总结
当ansible管理的项目较多时候,可以使用第二种方式来定义ansible配置文件
可以在每个项目的文件夹中同时定义一个ansible.cfg和一个inventoy文件
这样可以避免各个项目之间的干扰
同时这样在ansible的playbook移植的时候会方便很多
inventory
简介:inventory文件主要来记录被控主机及主机组信息,默认路径是/etc/ansible/hosts,如果想临时调用一个inventory文件的话,可以在ansible执行命令的时候使用-i来制定inventory文件位置
[root@k81 an]# cat >hosts<<EOF [ubuntu-hosts] ub1 ub2 EOF [root@k81 an]# ansible -i hosts all -m ping -o [WARNING]: Invalid characters were found in group names but not replaced, use -vvvv to see details ub1 | SUCCESS => {"ansible_facts": {"discovered_interpreter_python": "/usr/bin/python3"}, "changed": false, "ping": "pong"} ub2 | SUCCESS => {"ansible_facts": {"discovered_interpreter_python": "/usr/bin/python3"}, "changed": false, "ping": "pong"} [root@k81 an]# ansible -i hosts ubuntu-hosts --list [WARNING]: Invalid characters were found in group names but not replaced, use -vvvv to see details hosts (2): ub1 ub2
inventory文件定义
直接定义单主机: 1.2.3.4 # IP地址的方式 192.168.12.[1:10] # 包含192.168.12.1-192.168.12.10 ub1 # 主机名/域名的方式 db-[99:101]-node.example.com # 包含db-99-node.example.com到db-101-node.example.com ab[x:z] # 包含abx aby abz 192.168.[23:24].[1:10] # 包含192.168.23.1-10和192.168.24.1-10 [webservers] # 主机组的方式,这种一般会在下面定义多个主机 1.23.45.6 ub2 cn3 [dbs] 192.168.12.[1:10] db-[99:101]-node.example.com [test:children] # 把别的主机组包含进来,下面写上其他的主机组 [webservers] [dbs]
demo
[root@k81 ~]# head /etc/ansible/hosts [ubuntus] ub[1:5] [k8s1] k8[2:3] [k8s2] rocky[1:3] [k8s:children] k8s1 k8s2 [root@k81 ~]# ansible ubuntus --list hosts (5): ub1 ub2 ub3 ub4 ub5 [root@k81 ~]# ansible k8s1 --list hosts (2): k82 k83 [root@k81 ~]# ansible k8s2 --list hosts (3): rocky1 rocky2 rocky3 [root@k81 ~]# ansible k8s --list hosts (5): k82 k83 rocky1 rocky2 rocky3 [root@k81 ~]# ansible all -m ping -o ub2 | SUCCESS => {"ansible_facts": {"discovered_interpreter_python": "/usr/bin/python3"}, "changed": false, "ping": "pong"} ub1 | SUCCESS => {"ansible_facts": {"discovered_interpreter_python": "/usr/bin/python3"}, "changed": false, "ping": "pong"} ub4 | SUCCESS => {"ansible_facts": {"discovered_interpreter_python": "/usr/bin/python3"}, "changed": false, "ping": "pong"} ub3 | SUCCESS => {"ansible_facts": {"discovered_interpreter_python": "/usr/bin/python3"}, "changed": false, "ping": "pong"} ub5 | SUCCESS => {"ansible_facts": {"discovered_interpreter_python": "/usr/bin/python3"}, "changed": false, "ping": "pong"} rocky3 | UNREACHABLE!: Failed to connect to the host via ssh: Permission denied (publickey,gssapi-keyex,gssapi-with-mic,password). rocky2 | UNREACHABLE!: Failed to connect to the host via ssh: Permission denied (publickey,gssapi-keyex,gssapi-with-mic,password). k83 | SUCCESS => {"ansible_facts": {"discovered_interpreter_python": "/usr/bin/python"}, "changed": false, "ping": "pong"} k82 | SUCCESS => {"ansible_facts": {"discovered_interpreter_python": "/usr/bin/python"}, "changed": false, "ping": "pong"} rocky1 | UNREACHABLE!: Failed to connect to the host via ssh: ssh: connect to host rocky1 port 22: Connection timed out
ansible远程操作本质上是用的ssh,因此必须得ansible能够ssh到远程主机方可执行命令,上面我之所以有三个节点失败就是因为这三个节点无法远程过去
定义变量来帮助我们连接
[k8s2] rocky[1:3] ansible_ssh_port=22 ansible_ssh_user=ze ansible_ssh_pass='ze'
然后再来尝试
[root@k81 ~]# ansible rocky2 -m ping -o rocky2 | SUCCESS => {"ansible_facts": {"discovered_interpreter_python": "/usr/bin/python"}, "changed": false, "ping": "pong", "warnings": ["Platform linux on host rocky2 is using the discovered Python interpreter at /usr/bin/python, but future installation of another Python interpreter could change this. See https://docs.ansible.com/ansible/2.9/reference_appendices/interpreter_discovery.html for more information."]} [root@k81 ~]# ansible rocky3 -m ping -o rocky3 | SUCCESS => {"ansible_facts": {"discovered_interpreter_python": "/usr/bin/python"}, "changed": false, "ping": "pong", "warnings": ["Platform linux on host rocky3 is using the discovered Python interpreter at /usr/bin/python, but future installation of another Python interpreter could change this. See https://docs.ansible.com/ansible/2.9/reference_appendices/interpreter_discovery.html for more information."]}
也可以直接对一个组来进行变量定义
[k8s2:vars] ansible_ssh_port=22 ansible_ssh_user=ze ansible_ssh_pass='ze'
免密
将密码明文写入文件总是不好,因此我们可以先进行免密之后再来连接,下面演示了用sshpass进行免密,当然也可以直接用ansible或者expect免密,具体可以查询这篇blog
ssh-keygen -t rsa -b 2048 -P "" -f /root/.ssh/id_rsa -q # export SSHPASS=xxxx #xxxx对应自己的密码,必须要提前声明,否则会报错 export hosts="xxx xxx xxx" for host in hosts;do # sshpass -e ssh-copy-id -o StrictHostKeyChecking=no $host sshpass -p 123456 ssh-copy-id -o StrictHostKeyChecking=no $host done
ansible指定远端主机的方式
ansible的命令格式如下:
ansible <host-pattern> [-m module_name] [-a args]
ansible中host-pattern的指定方式
# 指定所有的组 ansible all --list # 通配符指定 ansible * --list ansible 192.168.* --list # 与: 在db组且在web组 ansible "db:&web" --list # 或:在db组或在web组 ansible "db:web" --list # 非:在db组,但是不在web组 ansible "db:!web" --list # 正则匹配 ansible "~(web|db).*" --list
普通用户使用ansible控制远程主机
在ansible服务器上新建普通用户,并给与sudo无需密码权限
useradd ze visudo ze ALL=(ALL) NOPASSWD: ALL
被控服务器新建普通用户,并且也配置sudo无密码权限
useradd zc vim /etc/sudoers zc ALL=(ALL) NOPASSWD: ALL ## 小提示,改完了之后可以用visudo -c来检查语法是否正确
ansible服务器普通用户免密被控机器普通用户
su - ze ssh-keygen -t rsa -b 2048 -P "" -f /root/.ssh/id_rsa -q sshpass -p 123456 ssh-copy-id -o StrictHostKeyChecking=no zc@xxx
修改ansible服务器的ansible.cfg
[privilege_escalation] become=True become_method=sudo # 配置sudo become_user=root become_ask_pass=False remote_user = zc # 远端服务器用户名