ansible(摘录,非原创)
简介展开目录
- Ansible 是一款基于 python 开发的自动运维工具,实现了批量系统配置、批量运行命令、批量程序部署等功能。
- Ansible 是模块化工作,它本事没有部署能力,它只是一个提供了一个框架,真正起作用的是它的模块。
- Ansible 不需要在远程主机上安装任何客户端或者代理端,因为它是基于 SSH 进行远程连接。
注意
环境展开目录
主机名 | IP | 系统 | 角色 |
ansible-1 | 192.168.137.194 | CentOS 7 | Ansible |
ansible-2 | 192.168.137.195 | CentOS 7 | node |
ansible-3 | 192.168.137.196 | CentOS 7 | node |
部署展开目录
- ansible-1 下载 Ansible 工具
-
yum -y install epel-release
-
yum -y install ansible
- ansible 配置文件几个常用的地方
- #inventory = /etc/ansible/hosts ## 主机列表配置文件
- #library = /usr/share/my_modules/ ## 模块存放目录
- #remote_tmp = ~/.ansible/tmp ## 临时 py 文件存放在远程主机目录
- #local_tmp = ~/.ansible/tmp ## 本机的临时执行目录
- #forks = 5 ## 默认并发数
- #sudo_user = root ## 默认 sudo 用户
- #remote_port = 22 ## 远程主机端口
- #host_key_checking = False ## 跳过检查主机指纹
- log_path = /var/log/ansible.log ##ansible 日志
主机列表的两种配置方式展开目录
- 基于密码链接
注意
- 基于密码链接需要把密码写到配置文件,这样做其实很危险;
- 密码一般都会定期更换,维护成本高;
- 需要将 ansible.cfg 里面的 '#host_key_checking = False
' 注释取消掉
-
[root@ansible-1 ~]# sed -i '/host_key_checking/s/#//' /etc/ansible/ansible.cfg
-
[root@ansible-1 ~]# mv /etc/ansible/hosts /etc/ansible/hosts.bak ##养成备份的习惯
-
cat > /etc/ansible/hosts << eof
-
[test]
-
192.168.137.195 ansible_ssh_pass='123456'
-
192.168.137.196 ansible_ssh_pass='123456'
-
eof
- 测试
-
[root@ansible-1 ~]# ansible test -m ping
- 基于密钥链接
- 免密互信
-
[root@ansible-1 ~]# ssh-keygen ##一直回车即可,生成密钥对
-
[root@ansible-1 ~]# ssh-copy-id -i ~/.ssh/id_rsa.pub root@192.168.137.195 ##将公钥发送给其他服务器
-
[root@ansible-1 ~]# ssh-copy-id -i ~/.ssh/id_rsa.pub root@192.168.137.196
- 测试
-
[root@ansible-1 ~]# ansible test -m ping
帮助手册展开目录
- 查看所有模块及其简介
-
[root@ansible-1 ~]# ansible-doc -l
-
[root@ansible-1 ~]# ansible-doc -l | grep shell ##这里查看shell模块
- 查看指定模块比较详细的说明及举例
-
[root@ansible-1 ~]# ansible-doc template ##这里查看 'template' 模块
- 查看指定模块的参数及简介
-
[root@ansible-1 ~]# ansible-doc -s template ##这里查看 'template' 模块
Ansible 命令部分参数介绍展开目录
- '-h' 参数可以查看 Ansible 所有的参数及对应的介绍
-
[root@ansible-1 ~]# ansible -h
- '-m' 指定模块,如果不指定模块默认使用 command
-
[root@ansible-1 ~]# ansible test -m ping
- '-a' 参数指定模块要执行的具体命令
-
[root@ansible-1 ~]# ansible test -m command -a 'date'
- '-f' 并行任务数,默认为 5
-
[root@ansible-1 ~]# ansible test -m command -a 'date' -f 10
- '-i' 指定主机清单位置,默认为 /etc/ansible/hosts
- 在 /opt 下创建一个新的测试主机清单,只添加一个主机
-
[root@ansible-1 ~]# echo -e '[test2]\n192.168.137.196' > /opt/hosts
-
[root@ansible-1 ~]# ansible -i /opt/hosts test2 -m ping
- '--list-hosts' 列出主机组里的主机
-
[root@ansible-1 ~]# ansible test --list-hosts
- '-o' 将输出结果压缩成一行
-
[root@ansible-1 ~]# ansible test -m ping -o
- '-v' '-vv' '-vvv' -'vvvv' 更详细的输出结果,v 越多越详细
-
[root@ansible-1 ~]# ansible test -m ping -vv
Ansible 部分模块介绍展开目录
setup 模块展开目录
- 用于统计远程主机的相关信息
-
[root@ansible-1 ~]# ansible -i /opt/hosts test2 -m setup ##因为太多了这里仅查看"ansible-3"的信息
ping 模块展开目录
- 用于远程主机的连通性测试
-
[root@ansible-1 ~]# ansible test -m ping
command 模块展开目录
注意
- 该模块常用命令
- chdir:执行命令前先切换到 chdir 指定的目录,如果这个目录不存在则命令不执行并报错
-
[root@ansible-1 ~]# ansible test -m command -a 'chdir=/opt/test ls' #因为远程主机上没有/opt/test目录,所以如图显示报错
-
[root@ansible-1 ~]# ansible test -m command -a 'chdir=/opt ls' ##远程主机上有/opt目录,执行成功,只是里面原本就没东西
- creates:如果目标文件存在,则后面的命令不执行
-
[root@ansible-1 ~]# ansible test -m command -a 'creates=/opt/a.txt ls /opt' ##因为/opt/a.txt不存在,所以后面的'ls /opt'才能执行
-
[root@ansible-1 ~]# ansible test -m file -a 'path=/opt/a.txt state=touch' ##现在创建/opt/a.txt模拟a.txt存在的情况
-
[root@ansible-1 ~]# ansible test -m command -a 'creates=/opt/a.txt ls /opt' ##可以看到提示/opt/a.txt已经存在,直接跳过后面的命令
- removes:如果目标文件存在,则后面的命令执行
-
[root@ansible-1 ~]# ansible test -m command -a 'removes=/opt/a.txt ls /opt' ##/opt/a.txt存在,则输出后面的'ls /opt'
-
[root@ansible-1 ~]# ansible test -m file -a 'path=/opt/a.txt state=absent' ##把/opt/a.txt删掉模拟a.txt不存在的情况
-
[root@ansible-1 ~]# ansible test -m command -a 'removes=/opt/a.txt ls /opt' ##由于a.txt已经被删了,所以显示跳过'ls /opt'命令
提醒
shell 模块展开目录
- 调用远程主机的 shell 解释器,基本上 shell 能用的命令这里都能用,不过 shell 用不了的这里也用不了,比如 'll' 命令
-
[root@ansible-1 ~]# ansible test -m shell -a 'll /opt'
- 不过可以将 'll' 命令替换为 'ls -l'
-
[root@ansible-1 ~]# ansible test -m shell -a 'ls -l /opt'
file 模块展开目录
- 常用命令
- path:文件的路径
- group:定义文件的所属组
- owner:定义文件的所属者
- mode:定义文件的权限
- recurse:递归,用于目录上,就是 '-R'
- src:源文件路径
- dest:目标文件路径
- state:
~ directory: 如果目录不存在则创建目录
~ file:返回目标文件的属性及状态,也可以用来判断文件存在与否
~ link:创建软连接
~ hard:创建硬链接
~ touch:如果目标文件不存在则创建,存在的话就会更新其最近修改时间
~ absent:删除目标文件
- 举例
- 在 /opt 下创建一个 test-1.txt
-
[root@ansible-1 ~]# ansible test -m file -a 'path=/opt/test-1.txt state=touch'
-
[root@ansible-1 ~]# ansible test -m shell -a 'ls /opt'
- 更改 /opt/test-1.txt 文件的所属主,所属组以及权限
-
[root@ansible-1 ~]# ansible test -m file -a 'path=/opt/test-1.txt group=nobody owner=nobody mode=666'
-
[root@ansible-1 ~]# ansible test -m shell -a 'ls -l /opt'
- 创建软连接 /opt/fstab 链接到 /etc/fstab
-
[root@ansible-1 ~]# ansible test -m file -a 'src=/etc/fstab dest=/opt/fstab state=link'
-
[root@ansible-1 ~]# ansible test -m shell -a 'ls -l /opt'
- 删除链接文件 /opt/fstab
-
[root@ansible-1 ~]# ansible test -m file -a 'path=/opt/fstab state=absent'
-
[root@ansible-1 ~]# ansible test -m shell -a 'ls /opt'
copy 模块展开目录
- 常用命令
- src:被复制到远程主机的本地文件,如果是目录则会递归复制
- dest:将 src 的本地文件复制到远程主机的目标位置
- content:可以代替 src,类似于 echo,直接将文本内容复制到远程主机的目标文件上
- backup:备份
~ yes:开启备份,备份文件名包含时间信息,原文件有变动才会进行备份
~ no:不备份 - directory_mode:递归设定目录的权限
- force:强制覆盖
~ yes:如果目标位置已经存在同名文件,但内容不同,也进行强制覆盖
~ no:目标位置不存在该文件才进行覆盖
- 举例
- 现在本机 ansible-1 中 /opt 下新建一个 test-2.txt 文件
-
[root@ansible-1 ~]# touch /opt/test-2.txt
- 将本机 ansible-1 中 /opt/test-2.txt 复制到远程主机上的 /opt 下
[root@ansible-1 ~]# ansible test -m copy -a 'src=/opt/test-2.txt dest=/opt'
[root@ansible-1 ~]# ansible test -m shell -a 'ls /opt'
- 用 'content' 命令将文本 'hello' 覆盖到远程主机 /opt/test-2.txt 中并备份原文件
-
[root@ansible-1 ~]# ansible test -m copy -a 'content="hello" dest=/opt/test-2.txt backup=yes'
-
[root@ansible-1 ~]# ansible test -m shell -a 'ls /opt'
-
[root@ansible-1 ~]# ansible test -m shell -a 'cat /opt/test-2.txt'
template 模块展开目录
- 这个模块用于将模版文件渲染后,输出到远程主机上,模版文件一般以.j2 为结尾,标识其是一个 jinja2 模版文件
- 常用命令
- src:模板文件路径
- dest:远程主机对应文件路径
- mode:权限
- attributes:特殊权限,类似于 chattr
- force:覆盖
- owner:所属者
- group:所属组
- 举例
- 现在本地(ansible-1)上 /opt 下创建一个 jinja2 模板文件 test.j2
-
cat > /opt/test.j2 << eof
-
{% if ansible_hostname == a %}
-
我的主机名是: {{ a }}
-
{% elif ansible_hostname == b %}
-
我的主机名是:{{ b }}
-
{% endif %}
-
eof
- 再在 /opt 下创建一个 yml 文件 test.yml
-
cat > /opt/test.yml << eof
-
---
-
-
vars:
-
-
-
tasks:
-
-
template:
-
src: /opt/test.j2
-
dest: /opt/test-3.txt
-
eof
- 执行 yml 文件
-
[root@ansible-1 ~]# ansible-playbook /opt/test.yml
-
[root@ansible-1 ~]# ansible test -m shell -a 'cat /opt/test-3.txt'
fetch 模块展开目录
- 该模块被用来从远程主机复制文件到本地主机
- 常用命令
- src:源文件,远程主机上的文件路径
- dest:目标位置,本地主机上的路径
- 举例
- 将远程主机上 /var/log/messages 日志复制到本地主机 /opt 下
-
[root@ansible-1 ~]# ansible test -m fetch -a 'src=/var/log/messages dest=/opt'
-
[root@ansible-1 ~]# ls /opt
user 模块展开目录
- 常用命令
- name:用户名
- home:指定用户家目录
- move_home:将用户家目录移动到指定位置
- groups:用户所属组
- force:配合 state=absent 强制删除用户
- uid:用户的 uid
- password:用户密码
- remove:配合 state=absent 使用,将用户及用户目录下的文件全部删除
- shell:指定 shell
- comment:用户信息描述
- system:是否为系统用户
- state:状态
~ present:创建用户,默认为 present
~ absent:删除用户
- 举例
- 创建一个名为 hz,uid 为 6666,密码为 123456,shell 为 /sbin/nologin 的用户
-
[root@ansible-1 ~]# ansible test -m user -a 'name=hz uid=6666 password=123456 shell=/sbin/nologin'
-
[root@ansible-1 ~]# ansible test -m shell -a 'cat /etc/passwd | grep hz'
- 将 hz 用户以及其家目录的文件删除
[root@ansible-1 ~]# ansible test -m user -a 'name=hz state=absent remove=yes'
[root@ansible-1 ~]# ansible test -m shell -a 'cat /etc/passwd | grep hz'
yum 模块展开目录
- 常用命令
- name:安装包名
- disable_gpg_check:是否禁止 gpg_check
- disablerepo:临时禁止某个 yum 源
- enablerepo:临时使用某个 yum 源
- state:
~ present | installed:安装
~ latest:安装最新的
~ absent | removed:卸载
- 举例
- 安装 httpd
-
[root@ansible-1 ~]# ansible test -m yum -a 'name=httpd state=present'
-
[root@ansible-1 ~]# ansible test -m shell -a 'rpm -qa | grep httpd'
- 卸载 httpd
-
[root@ansible-1 ~]# ansible test -m yum -a 'name=httpd state=removed'
-
[root@ansible-1 ~]# ansible test -m shell -a 'rpm -qa | grep httpd'
service 模块展开目录
- 常用命令
- name:服务名
- enabled:设置开机自启
- state:
~ started:启动服务
~ stopped:停止服务
~ restarted:重启服务
~ reloaded:重载配置
- 举例
- 关闭防火墙
-
[root@ansible-1 ~]# ansible test -m service -a 'name=firewalld state=stopped'
-
[root@ansible-1 ~]# ansible test -m shell -a 'systemctl status firewalld'
- 打开防火墙
-
[root@ansible-1 ~]# ansible test -m service -a 'name=firewalld state=started'
-
[root@ansible-1 ~]# ansible test -m shell -a 'systemctl status firewalld'
unarchive 模块展开目录
- 这个模块是用来解压文件的
- 常用命令
- remote_src:默认为 no
~ yes:表示需要解压的文件在远程主机上
~ no:将会先将本地主机(ansible-1)上的压缩包发送到远程主机上再解压 - src:源文件路径,取决于 remote_src 的值,决定 src 是表示远程主机的路径还是本地主机的路径
- dest:解压到远程主机的路径
- exclude:解压时排除指定的文件或目录
- owner:指定文件解压后的所属者
- group:指定文件解压后的所属组
- mode:指定文件解压后的权限
- 举例
- 在本地主机(ansible-1)/opt 下准备一个压缩包
-
[root@ansible-1 ~]# wget -P /opt http://nginx.org/download/nginx-1.20.1.tar.gz
- 发送到远程主机并解压到 /opt 下
-
[root@ansible-1 ~]# ansible test -m unarchive -a 'src=/opt/nginx-1.20.1.tar.gz dest=/opt'
-
[root@ansible-1 ~]# ansible test -m shell -a 'ls /opt'
get_url 模块展开目录
- 用来从网络上下载数据
- 常用命令
- url:文件的下载地址
- dest:文件保存的绝对路径
- mode:文件的权限
- backup:如果本地已有同名的数据,是否备份
- timeout:下载的超时时间
- 举例
- 在远程主机上 /opt 下下载 nginx 压缩包
-
[root@ansible-1 ~]# ansible test -m get_url -a 'url=http://nginx.org/download/nginx-1.20.1.tar.gz dest=/opt'
-
[root@ansible-1 ~]# ansible test -m shell -a 'ls /opt'
PlayBook展开目录
简介展开目录
playbook 由 yaml 语言编写,ansible 的模块其实类似于 linux 下的命令,而 playbook 其实就类似于 shell 脚本,这样就可以将原本一条条的 ansible 命令整合成一个 playbook 以方便解决一些过于复杂的操作。
格式展开目录
- yaml 脚本对格式有着很严格的要求
- YMAL 中的列表元素以”-” 开头然后紧跟着一个空格,后面为元素内容。
- 同一个列表中的元素应该保持相同的缩进。否则会被当做错误处理。
- hosts,variables,roles,tasks 等对象的表示方法都是键值中间以 ":" 分隔表示,":" 后面还要增加一个空格。
- 例如:下面是一个 yum 安装 httpd 然后启动并设置开机自启的 yml 脚本,将其放到本地主机(ansible-1)上的 /opt 下并命名为 httpd.yml
注意
-
---
-
- hosts: test #必须指定hosts,可以使用通配符格式,使用 hosts 指示使用哪个主机或主机组来运行下面的 tasks
-
tasks: #指定远端主机将要执行的一系列动作。tasks 的核心为 ansible 的模块,前面已经提到模块的用法。
-
- name: install httpd #name虽然不是必须的,但是为了方便阅读,还是建议加上去
-
yum:
-
name: httpd
-
state: present
-
- name: start httpd
-
service:
-
name: httpd
-
state: started
-
enabled: yes
- 然后执行
ansible-playbook /opt/httpd.yml
可以看到已经运行成功了
ansible-playbook /opt/httpd.yml -C
可以预执行命令,可以用来检查语法,但运行结果并不准确,因为后面的步骤假如需要用到前面步骤作为依赖,预执行又不会实际产生数据,这样会造成后面的步骤报错
roles展开目录
- 简介
- roles 是为了层次化、结构化地组织 Playbook。
- roles 就是通过分别将变量、文件、任务、模块及处理器放置于单独的目录中,并可以便捷地 include 它们。
- roles 一般用于基于主机构建服务的场景中,在企业复杂业务场景中应用的频率很高。
- 以特定的层级目录结构进行组织的 tasks、variables、handlers、templates、files 等;相当于函数的调用把各个功能切割成片段来执行。
- 创建一个名为 test 的 roles
-
[root@ansible-1 ~]# cd /etc/ansible/roles/
-
[root@ansible-1 roles]# ansible-galaxy init test
-
[root@ansible-1 roles]# tree test/ ##roles的结构
提示
- roles 结构的介绍
- default:用于设定默认变量
- files:存储由 copy 或 script 等模块调用的文件
- tasks:用于定义各 task
- handlers:用于定义各 handler
- meta:定义当前角色的特殊设定及其依赖关系
- templates:存储由 template 模块调用的模板文本
- vars:用于定义各变量
- 模拟用 roles 为远程主机用二进制安装方式部署 mysql
- 先下载 mysql 二进制包到 /etc/ansible/roles/files 下
-
[root@ansible-1 test]# wget -P /etc/ansible/roles/test/files https://mirrors.aliyun.com/mysql/MySQL-5.7/mysql-5.7.34-linux-glibc2.12-x86_64.tar.gz
- 编写 /etc/ansible/roles/tasks/main.yml
-
-
---
-
# tasks file for test
-
-
user:
-
name: mysql
-
state: present
-
-
-
unarchive:
-
src: mysql-5.7.34-linux-glibc2.12-x86_64.tar.gz
-
dest: /usr/local/
-
owner: mysql
-
group: mysql
-
-
-
shell: mv /usr/local/mysql-5.7.34-linux-glibc2.12-x86_64 /usr/local/mysql
-
-
-
file:
-
path: "{{ item }}"
-
state: directory
-
owner: mysql
-
group: mysql
-
recurse: yes
-
with_items:
-
-
-
-
-
-
template:
-
src: mysqlcnf.j2
-
dest: /etc/my.cnf
-
-
-
blockinfile:
-
path: /etc/profile
-
block: "export PATH=/usr/local/mysql/bin:$PATH"
-
notify:
-
-
-
-
shell: /usr/local/mysql/bin/mysqld --initialize-insecure --user=mysql --datadir=/data/mysql --basedir=/usr/local/mysql
-
-
-
shell: cp /usr/local/mysql/support-files/mysql.server /etc/init.d/mysqld
-
-
-
file:
-
path: /etc/init.d/mysqld
-
mode: 0777
-
-
-
shell: /etc/init.d/mysqld start
-
eof
- 准备触发器
这个触发器是为了刷新环境变量,虽然语法没问题但是实际没生效,因为用 shell 解释器刷新环境变量只会在 shell 解释过程中生效,解释完了回到原本的环境就失效了,目前我还没找到合适的方法解决,就当复习下触发器了
-
[root@ansible-1 test]# cat > /etc/ansible/roles/test/handlers/main.yml << eof
-
---
-
# handlers file for test
-
- name: 刷新环境变量
-
shell: source /etc/profile
-
eof
- 准备数据库配置的 jinja2 模板文件
-
[root@ansible-1 test]# cat > /etc/ansible/roles/test/templates/mysqlcnf.j2 << eof
-
{% if ansible_hostname == node1 %}
-
[mysqld]
-
user=mysql
-
basedir=/usr/local/mysql
-
datadir=/data/mysql
-
server_id={{ node1_id }}
-
log-error=/var/log/mysql/error.log #日志
-
port=3306
-
socket=/tmp/mysql.sock
-
[mysql]
-
socket=/tmp/mysql.sock
-
{% elif ansible_hostname == node2 %}
-
[mysqld]
-
user=mysql
-
basedir=/usr/local/mysql
-
datadir=/data/mysql
-
server_id={{ node2_id }}
-
log-error=/var/log/mysql/error.log #日志
-
port=3306
-
socket=/tmp/mysql.sock
-
[mysql]
-
socket=/tmp/mysql.sock
-
{% endif %}
-
eof
- 设置变量
-
[root@ansible-1 test]# cat > /etc/ansible/roles/test/vars/main.yml << eof
-
---
-
# vars file for test
-
node1: ansible-2
-
node2: ansible-3
-
node1_id: 7
-
node2_id: 8
-
eof
- 设置启动文件
-
[root@ansible-1 test]# cat > /etc/ansible/roles/test/tasks/test.yml << eof
-
---
-
- hosts: test
-
roles:
-
- test
-
eof
- 运行整个 roles
-
[root@ansible-1 tasks]# ansible-playbook /etc/ansible/roles/test/tasks/test.yml
- 到远程主机 'ansible-2' 检验
-
[root@ansible-2 ~]# cat /etc/my.cnf ##查看jinja模板有没有生效
-
[root@ansible-2 ~]# source /etc/profile ##刷新环境变量,原因在上面
-
[root@ansible-2 ~]# mysql
- 到远程主机 'ansible-3' 检验
-
[root@ansible-3 ~]# cat /etc/my.cnf ##查看jinja模板有没有生效
-
[root@ansible-3 ~]# source /etc/profile ##刷新环境变量,原因在上面
-
[root@ansible-3 ~]# mysql
- 至此已经成功部署了 mysql
- Ansible 模块丰富,以后遇到更重要的也会更新在这里