概述
Ansible 是一个极其简单的 IT 自动化平台,可让您的应用程序和系统更易于部署和维护。从代码部署到网络配置再到云管理,使用一种接近简单英语的语言,使用 SSH 实现一切自动化,无需在远程系统上安装代理。
GitHub:github.com/ansible/ansible
Ansible官网:www.ansible.com
安装配置和使用
安装
配置好扩展源(epel-release)就可以使用yum安装了
代码语言:txt复制yum -y install ansible
配置
Ansible的配置文件存在优先级问题,默认状态下会使用/etc/ansible/ansible.cfg具体优先级关系如下:
最高优先级是执行命令的当前目录下
./ansible.cfg
如果当前目录下找不到配置文件就会查找执行用户的家目录寻找
~/.ansible.cfg
以上位置就会选择默认的配置文件
/etc/ansible/ansible.cfg
代码语言:txt复制 [root@host ~]# cp /etc/ansible/ansible.cfg ~/.ansible.cfg
[root@host ~]# vim ./anaconda-ks.cfg
//找到defaults段,这段不取消注释则采用默认配置,下面的参数可以自己配置
inventory /etc/ansible/hosts //主机清单文件路径
roles_path /etc/ansible/roles //role存放目录
remote_user root //执行命令的用户
//找到privilege_escalation段,这一块主要是和提权相关这里取不取消注释无所谓可以按照自己环境来修改
become=True //是否开启提权
become_method=sudo //定义执行方式
become_user=root //定义执行用户
become_ask_pass=False //定义提示密码
使用
**配置hosts主机文件**
使用的时候需要定义host主机文件,里面是存放被控主机的ip地址,建议必须是使用可以ssh免密登录的主机。
代码语言:txt复制[root@host ~]# echo "" > /etc/ansible/hosts //清除hosts主机文件
[root@host ~]# vim /etc/ansible/hosts //编辑hosts主机文件,并向里面添加主机
[host]
192.168.1.112
[host2]
192.168.1.113
hosts主机还有多种写法,具体请看本文的其他栏
ps:写好主机文件之后的操作需要建立在ssh免密之后才可以执行,具体方法可以看文章的其他栏,有问题欢迎在评论区提问
简单使用方法如下
代码语言:txt复制[root@host ~]# ansible all --list //列出所有主机
hosts (2):
192.168.1.112
192.168.1.113
[root@host ~]# ansible all -m ping //验证全部主机的连通性
192.168.1.112 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/libexec/platform-python"
},
"changed": false,
"ping": "pong"
}
192.168.1.113 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/libexec/platform-python"
},
"changed": false,
"ping": "pong"
}
常用模块
使用方法
代码语言:txt复制[root@host ~]# ansible 组/主机 -m 模块 //使用-m参数来指定相应模块
模块使用文档
ansible为每个模块都提供了文档
使用命令ansible-doc -l 可以列出全部的ansible模块
使用命令ansible-doc {模块名称} 可以查看对应模块的帮助文档
ping模块
测试主机的连通性
直接使命令:ansible 主机/组 -m ping
代码语言:txt复制[root@host ~]# ansible all -m ping
192.168.1.113 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/libexec/platform-python"
},
"changed": false,
"ping": "pong"
}
192.168.1.112 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/libexec/platform-python"
},
"changed": false,
"ping": "pong"
}
返回pong则证明连通性没问题
shell/command模块
执行命令
直接使命令:ansible 主机/组 -m shell/command -a "执行的命令"
代码语言:txt复制[root@host ~]# ansible all -m shell -a "ping baidu.com -c 1"
192.168.1.113 | CHANGED | rc=0 >>
PING baidu.com (220.181.38.148) 56(84) bytes of data.
64 bytes from 220.181.38.148 (220.181.38.148): icmp_seq=1 ttl=50 time=18.5 ms
--- baidu.com ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 18.489/18.489/18.489/0.000 ms
192.168.1.112 | CHANGED | rc=0 >>
PING baidu.com (220.181.38.148) 56(84) bytes of data.
64 bytes from 220.181.38.148 (220.181.38.148): icmp_seq=1 ttl=50 time=17.6 ms
--- baidu.com ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 17.597/17.597/17.597/0.000 ms
Shell和Command都是执行命令 但是两者有一定的区别
Command
该模块命令里如果有一下字符部分执行不成功 “<” “>” “|” “&””;”
Shell
用法基本和command一样 不过时通过/bin/sh进行执行,所以shell模块可以执行任何命令,就像在本机执行命令一样,但是这样有潜在的shell注入的风险
两个模块都要避免使用,你应该优先考虑ansible的模块
其他参数可以查看ansible-doc来详细学习
Script模块
主要用于执行管理主机上的脚本 原理就是将shell复制到远程主机,再远程主机上执行
使用命令:ansible 主机/组 -m script -a "控制端的脚本"
代码语言:txt复制[root@host ~]# echo "echo hello,world" > 1.sh
[root@host ~]# ansible all -m script -a './1.sh'
192.168.1.112 | CHANGED => {
"changed": true,
"rc": 0,
"stderr": "Shared connection to 192.168.1.112 closed.rn",
"stderr_lines": [
"Shared connection to 192.168.1.112 closed."
],
"stdout": "hello,worldrn",
"stdout_lines": [
"hello,world"
]
}
192.168.1.113 | CHANGED => {
"changed": true,
"rc": 0,
"stderr": "Shared connection to 192.168.1.113 closed.rn",
"stderr_lines": [
"Shared connection to 192.168.1.113 closed."
],
"stdout": "hello,worldrn",
"stdout_lines": [
"hello,world"
]
}
Stdout_lines参数就是实际机器返回的值
其他参数可以查看ansible-doc来详细学习
user模块
主要用于管理用户
使用命令:ansible 主机/组 -m user -a '参数'
添加一个用户ansible 主机/组 -m user -a ‘name=admin state=present’
state可以理解为动作 增加删除修改 默认state就是present
代码语言:txt复制[root@host ~]# ansible all -m user -a "name=admin state=present"
192.168.0.103 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/libexec/platform-python"
},
"changed": true,
"comment": "",
"create_home": true,
"group": 1000,
"home": "/home/admin",
"name": "admin",
"shell": "/bin/bash",
"state": "present",
"system": false,
"uid": 1000
}
使用命令:ansible 主机/组 -m user -a ‘name=admin state=absent’ 可以删除admin用户
代码语言:txt复制[root@host ~]# ansible all -m user -a "name=admin state=absent"
192.168.0.103 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/libexec/platform-python"
},
"changed": true,
"force": false,
"name": "admin",
"remove": false,
"state": "absent"
}
其他可以查看ansible-doc来详细学习
yum_repository模块
主要用于批量更新yum源
ansible 主机/组 -m yum_repository -a '参数'
ansible 主机/组 -m yum_repository -a 'name="CentOS" description="CentOS" baseurl="file:///mntcdrom" enabled=yes gpgcheck=no'
name 设置了文件名和文件中[]的内容
description 设置了文件中name的内容
baseurl 设置了文件中源的地址
enabled 设置了enable参数
gpgcheck 设置了是否需要密钥来验证包
代码语言:txt复制[root@host ~]# ansible all -m yum_repository -a 'name="CentOS" description="CentOS" baseurl="file:///mntcdrom" enabled=yes gpgcheck=no'
192.168.0.103 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/libexec/platform-python"
},
"changed": true,
"repo": "CentOS",
"state": "present"
}
[root@host ~]# ssh root@192.168.0.103
Last login: Sun Apr 3 12:20:11 2022 from 192.168.0.102
[root@localhost ~]# cat /etc/yum.repos.d/CentOS.repo
[CentOS]
baseurl = file:///mntcdrom
enabled = 1
gpgcheck = 0
name = CentOS
他会在对控制主机里生成相应的yum源配置文件
还有很多参数可以用ansible-doc yum_repository来查看文档
yum模块
主要是用来操作yum的
ansible 主机/组 -m yum -a ‘参数’
参数详解
Name 包名
State 选择是安装还是删除还是更新(present和installed是安装 latest是更新 removed和absent是移除)
这是基本使用 还有很多参数详情请使用ansible-doc yum查看
copy模块
主要是用来批量传输文件的
ansible 主机/组 -m copy -a ‘参数’
src 写本地目录
dest 客户端目录
其他请使用ansible-doc copy查看
service模块
主要是用来管理服务用的
ansible 主机/组 -m service -a ‘参数’
name 包名
state 设置状态(started开启 stopped关闭 restarted重启 reloaded重置)
enabled 参数只有yes和no yes为开机自启 no就是开机不开启
其他请使用ansible-doc service查看
set-up模块
主要是用来显示对应主机的facts变量的,写roles文件用的比较多
ansible 主机/组 -m setup -a ‘参数’
用来显示对应主机的facts变量
使用参数 filter=’关键词 可以进行显示检索
具体请使用ansible-doc setup来查看’
firewalld模块
用来管理firewalld防护墙
ansible 主机/组 -m firewalld -a ‘参数’
参数:
Service 设置服务名称
Permanent 是否永久更改(yes,no)
State 是否放行(enabled,disabled)
Zone 选择区域
Port 设置端口(/tcp,/udp)
其他具体请使用ansible-doc firewalld来查看
template模块
主要是用来复制jnja2文件的,jnja2文件后面会讲
ansible 主机/组 –m template -a ‘参数’
src 文件目录
dest 复制后的文件目录
其他参数请使用ansible-doc template查看
debug模块
主要是用来debug的输出信息
ansible 主机/组 -m debug -a ‘参数’
msg 输出内容
var 输出变量
其他请使用ansible-doc debug查看
Playbook剧本
Playbook剧本 类似和脚本一样 用来批量执行模块
使用palybook
Playbook有着严格的缩进写法,语法非常严谨,使用yml文件来写
代码语言:txt复制[root@host test]# cat creatuser.yml
---
- name: create user
hosts: 192.168.0.103
tasks:
- name: create admin
user:
name: admin
state: present
开头必须使用---
一个-代表一个任务的开头
如果一个块需要配置子参数则就需要严格缩进
name是描述
Hosts是主机清单
Tasks是配置任务
子任务中name是描述
User则就代表user模块
模块的子参数就不需要-了
name则是user的配置参数
运行playbook的命令是ansible-playbook palybook文件
undefined
这是执行除此之外还可以使用命令"ansible-playbook --syntax-check 文件"来检查文件语法是否有误
还有命令"ansible-playbook -C 文件"来运行测试,他会使用文件进行运行测试但不会在目的主机上发生实际改变
变量
变量的名称必须以字母开头,并且只能含有字母,数字和下划线.
通过vars声明变量通过“{{变量名}}”进行调用
undefined
左边的就是使用变量写的,右边就是没用.实质效果一样
也可以通过指定一个变量文件来实现 参数:vars_files:文件名
undefined
我这边定义的是相对目录下的vars.yml 然后图的右边就是vars.yml文件的内容
魔法变量
魔法变量是ansible的内置变量,直接被定义好的,可以直接拿来使用.
常见的魔法变量:
hostvars 列出所有受管理的主机信息.啊如果没有收集facts信息则不会显示facts信息
group_names 列出当前受管理主机所属的所有组
groups 列出清单中所有组的字典/映射
inventory_hostname 列出清单中所有配置的当前主机名称
其他的可以使用setup模块进行查看
Facts变量
Facts变量用于采集客户端的信息,比如网络信息,主机名,硬件信息等.
每次执行playbook时会对客户端主机进行数据采集
实际上它是通过setup模块进行收集数据
Ansible 主机/组 -m setup可以列出所有的facts变量
When判断
When就是判断 他只会判断某一条是否为true 否则跳过 可以理解为判断一个布尔类型
When虽然不是一个模块但是他的缩进必须和模块对其 卸载tasks后面
代码语言:txt复制---
- name: create user
hosts: 192.168.0.104
vars:
run: true
tasks:
- name: create user
user:
name: admin
state: present
when: run
这是单条的判断 when会判断上面的值是否为true 是则执行不是则跳过
代码语言:txt复制---
- name: create user
hosts: 192.168.0.104
tasks:
- name: create user
user:
name: admin
state: presend
when:
- ansible_distribution == "CentOS" and ansible_machine == "x86_64"
- ansible_distribution == "CentOS" and ansible_machine == "RedHat"
里面的两个值都是facts的变量,只有满足CentOS系统内核为x86和redhat的系统才会执行,否则跳过
只有满足CentOS系统内核为x86和redhat的系统才会执行 否则跳过
常用判断语句
== 等于
< 小于
代码语言:txt复制大于
<= 小于等于 = 大于等于 != 不等于 is defined 变量是否定义,定义为true 未定义为false si not defined 变量是否定义,未定义为false 魔法变量判断
when: inventory_hostname in groups[“VMhost”]
只有VMhost组中主机才会执行此操作
Loop循环
代码语言:txt复制---
- name: create user
hosts: 192.168.0.104
tasks:
- name: create user
user:
name: "{{item.name}}"
uid: "{{item.uid}}"
state: presend
loop:
- name: admin1
uid: 3001
- name: admin2
uid: 3002
- name: admin3
uid: 3003
Item是循环变量 只要用loop循环执行变量就必须使用item 点的后面使用loop定义的内容 循环的开始都要用 – 表示
Block块
Ansble的playbook可以把多个和任务组成一个块,然后根据不同条件来执行这个块
还能执行失败时执行其他命令
Block 定义块 写的时候要求和任务(tasks)的name对齐
Rescue 当上面的块执行失败时,该关键字下麦呢的任务将被执行
Always 不管block是否执行成功之后都会执行这个任务
代码语言:txt复制---
- name: cat file
hosts: 192.168.0.104
tasks:
- name: cat a.txt
block:
- debug:
msg: "查看文件"
- shell: cat /1.txt
rescue:
- debug:
msg: "我giao,查看失败,创建文件"
- shell: echo hello,world > /1.txt
- debug:
msg: "查看文件"
- shell: cat /1.txt
always:
- debug:
msg: "执行完成"
如下执行结果
undefined
register命令返回
以上一个block为例子,给他改一些东西
代码语言:txt复制---
- name: cat file
hosts: 192.168.0.104
tasks:
- name: cat a.txt
block:
- debug:
msg: "查看文件"
- shell: cat /1.txt
- debug:
var: cattxt
register: cattxt
rescue:
- debug:
msg: "我giao,查看失败,创建文件"
- shell: echo hello,world > /1.txt
- debug:
msg: "查看文件"
- shell: cat /1.txt
always:
- debug:
msg: "执行完成"
执行结果如下
undefined
Roles角色
介绍
Ansible roles提供了便捷的方式让你能够轻松的重复利用ansible代码 可以在标准化的目录结构中大伯所有 任务 变量 文件 模板以及完成任务所需要的资源,这样我们只需要将roles从一个项目复制到另一个项目即可在play中直接调用并执行他
undefined
从第二排开始就是roles的文件 文件中包含很多项目就是第三排的内容 然后第四行就是每个项目中的子目录 这几个子目录都有自己的作用
Roles子目录
Default: 此目录中main.yml文件定义新角色变量的默认值,该目录中定义的优先级较低,使用角色时可以覆盖这些变量
Files: 存放角色任务中引用的静态文件
Handlers: 此目录中main.yml 文件定义处理程序
Meta: 此目录中main.yml 文件定义角色相关信息 如:作者,平台,依赖等等
Tasks: 此目录中main.yml 文件定义角色中的任务
Templates: 存放jinja2的模板文件
Tests: 此目录中可以包含清单和test.yml(playbook)用于测试角色
Vars: 此目录中main.yml文件定义角色使用的变量值,优先级高于default目录
Galaxy
Galax是ansible的一个功能库 你可以使用其他人创建好的roles也可以分享自己的roles.
就像docker镜像库一样 需要什么功能就可以直接去下载使用
官方网站:https://galaxy.ansible.com
Ansible-galaxy install 包名
默认安装会的话会自动安装到~/.ansible/roles/下 可以使用-p参数指定位置
然后参数init可以自动生成roles目录
Ansible-galaxy init 文件夹名字
参数 -r 可以执行yml下载文件
例如
代码语言:txt复制---
- src: roles文件地
name: 下载后的本地昵称
- src: roles文件地址
name: 下载后的本地昵称
安装的时候可以使用命令
Ansible-galaxy install -r yml.yml 进行下载
装好的角色可以使用ansible-galaxy list查看
J2
详解
J2全名为jinja2是python下一个被广泛运用的模板引擎,他的设计思想来源于Django的模板引擎,并拓展了其他语法和一系列强大的功能,ansible使用jinja2模板来启用动态表达式和访问变量。
构成
Jinja2模板的构成:数据 变量 表达式
在使用jinja2模板时变量和表达式会被替代成对应的值,变量的值可以在plasybook中定义也可以直接调用facts事实,当然调用facts需要你编写的playbook开启了facts收集
写法
{{EXPR}} 用于装载表达式,比如变量,运算表达式,比较表达式
{%EXPR%} 用于装载控制语句 比如if,for等
{# #} 用于注释
Ps:jinja2模板文件本身不需要指定文件扩展名,使用.j2为后缀名只是为了更方便我们管理jinja2的模板
创建和使用角色
使用命令"ansible-galaxy init galaxy"创建一个galaxy模板
代码语言:txt复制[root@Ansible roles]# ansible-galaxy init galaxy
- Role galaxy was created successfully
[root@Ansible roles]# ls
galaxy
[root@Ansible roles]# cd galaxy/
[root@Ansible galaxy]# ls
defaults files handlers meta README.md tasks templates tests vars
编辑tasks的main.yml文件写入以下内容
代码语言:txt复制---
# tasks file for galaxy
- name: install apache
yum:
name: httpd
- name: start httpd
service:
name: "{{item}}"
state: started
enabled: yes
loop:
- httpd
- firewalld
- name: set firewalld
firewalld:
service: http
permanent: yes
state: enabled
immediate: yes
- name: set index
template:
src: index.html.j2
dest: /var/www/html/index.html
tasks/main.yml文件只需要定义命令,不需要定义主机
上面这个main文件是使用yum下载了一个httpd之后使用service开启了防火墙和httpd的服务,又实用防火墙模块放行了对应的服务,之后把j2文件复制到了对应的网站目录页面。
之后写一个j2文件放到templates目录里,内容如下
代码语言:txt复制[root@Ansible galaxy]# cat templates/index.html.j2
Welcome to {{ansible_default_ipv4.address}}
ansible_default_ipv4.address是facts变量中对应主机的ip
写好之后我们来写一个playbook来运行写的roles
代码语言:txt复制---
- name: roles galaxy
hosts: 192.168.0.104
roles:
- /root/ansible/roles/galaxy
运行结果如下,通过http访问返回内容
undefined
Vault加密
场景
使用ansible的时候难免会有一些比较敏感的数据,比如密码,key等信息直接明文暴露显然不是很好,vault管理加密/解密yml(palybook)文件工具,有时编写的playbook文件中会存在重要敏感信息,考虑到安全,可以使用此工具进行加密!
参数详解
Ansible-vault 参数
Create: 创建
Decrypt: 解密
Edit: 编辑加密文件
Encrypt: 加密
rekey: 修改口令
view: 查看
加密之后执行playbook的时候需要附加–ask-vault-pass参数
实例
创建用户,用户信息使用vault进行加密,使其不能以明文的形式查看
代码语言:txt复制[root@Ansible ansible]# cat vault.yml
---
- name: vault
vars_file: ./userinfo.yml
tasks:
- name: create user
user:
name: "{{name}}"
password: "{{password}}"
[root@Ansible ansible]# cat userinfo.yml
---
- name: "admin"
password: "abc123"
[root@Ansible ansible]# ansible-vault encrypt userinfo.yml
New Vault password:
Confirm New Vault password:
Encryption successful
[root@Ansible ansible]# cat userinfo.yml
$ANSIBLE_VAULT;1.1;AES256
63356239383039396263323732396663333132616561323362636662383265626233643465376365
3838633930316666373234633533643065643238653239380a313530633763366262643135363336
62386533313439393761353966316534323464326533306564363565623737393766316231383035
6361363665333837320a316465306139373564623930303330623261343466366336653537333266
61386330336363366633633632303465613535303766653663363734663138393064646237363063
3431616565353131633931326531383262353234366131306130
执行需要使用参数 "–ask-vault-pass" 执行
undefined
其他
hosts主机文件写法
一般写法:
组名
IP
域名
······
连续主机写法:
组名
1a-f.example.com
······
父组写法:
组名:children
组名
组名
······
undefined
undefined
undefined
undefined
undefined
undefined
undefined
undefined
undefined
undefined