| 主机名 | ip | 分组 |
|---|---|---|
| crontol | 192.168.88.1 | |
| node1 | 192.168.88.11 | test |
| node2 | 192.168.88.12 | proxy |
| node3 | 192.168.88.13 | webservers |
| node4 | 192.168.88.14 | webservers |
| node5 | 192.168.88.15 | database |
所有操作只需在crontol上操作即可
ansible# 依赖一般也会跟着一起装好
yum install -y ansible
for i in {1..5}; do echo -e "192.168.88.1$i\tnode$i" >> /etc/hosts; done
ssh-keygen # 回车即可
for i in node{1..5}; do ssh-copy-id $i ;done # 按要求输入密码即可
ansible工作目录mkdir ansible && cd ansible
etc/ansible/ansible.cfg),以下操作都必须在工作目录下执行vim ansible.cfg
# ansible.cfg内容
[defaults]
inventory = hosts # 管理的主机,配置在当前目录的hosts文件中,hosts名是自定义的。=号两边空格可有可无
vim hosts
# hosts内容
[test]
node1
[proxy]
node2
[webservers]
node[3:4]
[database]
node5
[cluster:children]
webservers
database
# 测试是否成功
ansible all --list-hosts
# 输出下列结果表示成功
hosts (5):
node2
node1
node3
node4
node5
ansible远程管理
adhoc临时命令,也就是在命令行执行管理命令playbook剧本,把管理任务用特定格式写到文件中ansible 主机或组列表 -m 模块 -a "参数" # -a是可选的
ansible all -m ping
# 查看所有模块
ansible-doc -l
# 查看指定模块
ansible-doc -l | grep file
# 查看模块使用文档,/EXAMPLE可以查看示例
ansible-doc file
ansible默认模块,用于在远程主机上执行任意命令command不支持shell特性,如管道、重定向。# 在所有被管主机上创建目录/tmp/demo
ansible all -a "mkdir /tmp/demo"
# 查看node1的ip地址
ansible node1 -a "ifconfig" # ansible node1 -a "ifconfig | head -5"就会报错
command模块类似,但是支持shell特性,如管道、重定向。ansible node1 -m shell -a "ifconfig | grep inet"
# 控制端先创建一个安装vsftpd服务的脚本
vim install.sh
# install.sh内容
#!/bin/bash
yum install -y vsftpd
systemctl start vsftpd
# 在test组执行这个脚本
ansible test -m script -a "install.sh"
注意:
command、shell、script这三个模块一般不用,因为它们没有幂特性
path:指定文件路径owner:设置文件所有者group:设置文件所属组state:状态,touch表示创建文件,directory表示创建目录,link表示创建超链接,absent表示删除mode:设置权限src:源文件,设置超链接的时候会用到dest:目标文件,设置超链接的时候会用到# 查看使用帮助
ansible-doc file
# 在test组的主机上创建/tmp/test.txt
ansible test -m file -a "path=/tmp/test.txt state=touch"
# 将test组的主机上的/tmp/test.txt属主和属组都修改为adm,权限修改为0777
ansible test -m file -a "path=/tmp/test.txt owner=adm group=adm mode='0777'"
# 在test组的主机上创建/tmp/demo,创建的同时设置该目录的属主和属组都修改为adm,权限修改为0777
ansible test -m file -a "path=/tmp/demo owner=adm group=adm mode='0777' state=directory"
# 在test组的主机上创建/etc/hosts的超链接,存放在/tmp/demo/hosts
ansible test -m file -a "src=/etc/hosts dest=/tmp/demo/hosts state=link"
# 删除test组的主机上的/tmp/test.txt和/tmp/demo
ansible test -m file -a "path=/tmp/demo state=absent"
ansible test -m file -a "path=/tmp/test.txt state=absent"
src:源文件路径dest:目标路径content:内容owner:设置文件所有者group:设置文件所属组mode:设置文件权限# 将本地的/etc/hostname拷贝到test组服务器的/root/下
ansible test -m copy -a "src=/etc/hostname dest=/root/"
# 在目标主机上创建/tmp/test.txt,内容是Hello bhlu
ansible test -m copy -a "content='Hello bhlu' dest=/tmp/test.txt"
src:源文件路径dest:目标路径flag:yes代表直接下载文件,不会递归下载目录# 将test组的主机上的/etc/hostname下载到本地的/root/下
ansible test -m fetch -a "src=/etc/hostname dest=/root/"
cat /root/node1/etc/hostname
# node1
path:待修改的文件路径line:写入文件的一行内容regexp:正则表达式,用于查找文件中内容# 检测test组的主机的/tmp/test.txt文件中,是否有aaa,如果有,则不操作,没有就添加aaa到文件结尾
ansible test -m lineinfile -a "path=/tmp/test.txt line='aaa'"
# 将test组的主机的/tmp/test.txt文件中的包含aaa的行替换成bbb,从下往上,只替换一次
ansible test -m lineinfile -a "path=/tmp/test.txt line='bbb' regexp='aaa'"
lineinfile会替换一行,replace替换关键词path:待修改的文件路径replace:替换成的内容regexp:正则表达式,需要替换的内容# 将test组的主机上的/tmp/test.txt中bb全部替换成haha
ansible test -m replace -a "path=/tmp/test.txt replace='haha' regexp='bbb'"
name:待创建的用户名uid:用户IDgroup:设置主组groups:设置附加组home:设置家目录password:设置用户密码state:状态,present表示创建,也是默认选项,absent表示删除remove:删除家目录、邮箱等,yes或者true# 在test组的主机上,创建一个bhlu的用户,uid为1020,设置主组为adm,附加组为root,密码是123456
ansible test -m user -a "name=bhlu uid=1020 group=adm groups=root password=123456"
# 修改test组的主机上的bhlu的密码为666666,使用加密算法
ansible test -m user -a "name=bhlu password={{'666666'|password_hash('sha512')}}"
# 删除test组的主机上的bhlu的用户,不删除家目录
ansible test -m user -a "name=bhlu state=absent"
# 删除test组的主机上的tools的用户,删除家目录
ansible test -m user -a "name=bhlu state=absent remove=yes"
name:待创建的组名gid:GIDstate:状态,present表示创建,也是默认选项,absent表示删除# 在test组的主机上创建一个uid为1030的组,名称为project
ansible test -m group -a "name=project gid=1030"
# 将test组的主机上的名为project的组删除
ansible test -m group -a "name=project state=absent"
file:指定文件名name:指定仓库名称description:仓库描述baseurl:仓库地址gpgcheck:是否检查gpg,填yes|no,0和1都行enabled:是否开启,填yes|no,0和1都行# 在test组的主机上创建yum文件,文件为myrepo.repo,仓库名为myRepo,描述为My Repo,baseurl为ftp://yum-server/base/,开启状态,不检查gpg
ansible test -m yum_repository -a "file=myrepo name=myRepo description='My Repo' baseurl=ftp://yum-server/base/ enabled=yes gpgcheck=0"
# 被控主机
cat myrepo.repo
[myRepo]
baseurl = ftp://yum-server/base/
enabled = 1
gpgcheck = 0
name = My Repo
rpm软件包管理,如安装、升级、卸载name:包名state:状态,present表示安装,如果安装则忽略;latest表示安装或者升级到最新版本;absent表示卸载# 在test组的主机上安装tree
ansible test -m yum -a "name=tree"
# 在test组的主机上卸载tree
ansible test -m yum -a "name=tree state=absent"
name:控制的服务名state:状态,started表示启动;stopped表示关闭;restarted表示重启enabled:yes表示设置开机自启;no表示设置开机不自启# 在test组的主机上开启vsftpd,并设置开机自启
ansible test -m service -a "name=vsftpd state=started enabled=yes"
# 在test组的主机上关闭vsftpd
ansible test -m service -a "name=vsftpd state=stopped"
device:待分区的设备number:分区编号state:状态,present表示创建;absent表示删除part_start:分区起始位置,不写表示从开头part_end:分区结束位置,不写表示结尾# 在test组的主机上,对20G的/dev/nvme0n2进行操作,分两个分区,第一个5G,第二个15G
ansible test -m parted -a "device=/dev/nvme0n2 number=1 state=present part_end=5GiB"
ansible test -m parted -a "device=/dev/nvme0n2 number=2 state=present part_start=5GiB"
vg:定义卷组名。vg:volume grouppvs:物理卷,分号隔开。pvs:physical volumesstate:状态,present表示创建,默认状态;absent表示删除# 在test组的主机上创建一个myvg的卷组,是有/dev/nvme0n2p1和/dev/nvme0n2p2组成
ansible test -m lvg -a "vg=myvg pvs=/dev/nvme0n2p1,/dev/nvme0n2p2 state=present"
vg:指定那个卷组lv:逻辑卷名。lv:logical volumesize:逻辑卷大小,不写单位的情况下,默认以M为单位state:状态,present表示创建,默认状态;absent表示删除# 在test组的主机上创建一个逻辑卷,卷名mylv,大小为5G
ansible test -m lvol -a "vg=myvg lv=mylv size=5G"
# 修改mylv的大小为10G
ansible test -m lvol -a "vg=myvg lv=mylv size=10G"
fstype:指定文件系统类型dev:指定要格式化的设备,可以是分区,也可以是逻辑卷force:yes,强制的意思,当格式化或者删除dev的时候,如果dev上有数据,需要添加这个# 将test组的主机上的mylv格式化成xfs格式
ansible test -m filesystem -a "fstype=xfs dev=/dev/myvg/mylv"
path:挂载点src:待挂载的设备fstype:文件系统类型state:状态,mounted表示永久挂载;absent表示卸载# 将test组的主机上的/dev/myvg/mylv挂载到/data
ansible test -m mount -a "path=/data src=/dev/myvg/mylv fstype=xfs state=mounted"
# 将test组的主机上的/dev/myvg/mylv挂载到/data
ansible test -m mount -a "path=/data src=/dev/myvg/mylv fstype=xfs state=absent"
port:端口permanent:是否永久生效,yes|noimmediate:立即生效,临时生效,默认为nostate:放行enabled,拒绝disabled# 放行80端口,文件内容如下
---
- name: set firewalld
hosts: test
tasks:
- name: allow 80/tcp
firewalld:
port: 80/tcp
permanent: yes
immediate: yes
state: enabled
jinja2语法,跟copy模块不同src:源文件路径dest:目标文件路径vim test.j2
# 文件内容如下
Hello {{name}},server is {{ansible_hostname}}
vim temp.yml
# 文件内容如下
---
- name: test template module
hosts: test
vars:
name: "bhlu"
tasks:
- name: copy test.j2 to test
template:
src: test.j2
dest: /var/www/html/index.html
# 执行,会有个警告,关于name变量,不用管
ansible-playbook temp.yml
# 测试
curl node1 # Hello bhlu,server is node1
所有操作均对test组中的主机生效
在目标主机上创建/tmp/mydemo目录,属主和属组都是adm,权限为0777
将控制端的/etc/hosts文件上传到目标主机的/tmp/mydemo目录中,属主和属组都是adm,权限为0600
替换目标主机/tmp/mydemo/hosts文件中的node5为server5
将目标主机/tmp/mydemo/hosts文件下载到控制端的当前目录
# 在目标主机上创建/tmp/mydemo目录,属主和属组都是adm,权限为0777
ansible test -m file -a "path=/tmp/mydemo owner=adm group=adm mode='0777' state=directory"
# 将控制端的/etc/hosts文件上传到目标主机的/tmp/mydemo目录中,属主和属组都是adm,权限为0600
ansible test -m copy -a "src=/etc/hosts dest=/tmp/mydemo owner=adm group=adm mode='0600'"
# 替换目标主机/tmp/mydemo/hosts文件中的node5为server5
ansible test -m replace -a "path=/tmp/mydemo/hosts replace='server5' regexp='node5'"
# 将目标主机/tmp/mydemo/hosts文件下载到控制端的当前目录
ansible test -m fetch -a "src=/tmp/mydemo/hosts dest=."
playbook也是通过模块和它的参数,在特定主机上执行任务playbook是一个文件,该文件中需要通过yaml格式进行书写yaml文件的文件名,一般以yml或yaml作为扩展名---作为第一行,不是必须的,但是常用:表示,冒号后面必须有空格-表示,-后面必须有空格tab,必须使用空格vim ~/.vimrc
set ai # 设置自动缩进
set ts=2 # 设置按tab键,缩进2个空格
set et # 将tab转换成相应的空格
---
- name: 简介
hosts: 主机或组,用分号隔开
tasks:
- name: 任务1介绍
file:
path: ...
state: ...
mode: ...
- name: 任务2介绍
copy:
src: ...
copy: ...
test组和node2上创建/tmp/demo目录,权限是0600,将控制端/etc/hosts拷贝到被控主机的/tmp/demo中vim fileop.yml---
- name: create directory and copy file
hosts: test,node2
tasks:
- name: create directory
file:
path: /tmp/demo
state: directory
mode: '0600'
- name:
copy:
src: /etc/hosts
dest: /tmp/demo/hosts
ansible-playbook fileop.ymlvim test.yml(文件中的content的|可以保留换行符,如果是>那就是将多行合并成一行)---
- name: create user and touch file
hosts: test
tasks:
- name: create user bob
user:
name: bob
groups: adm
- name: touch file
copy:
dest: /tmp/test.txt
content: |
Hello bhlu
ansible-playbook test.ymlvim user.yml---
- name: create user
hosts: test
tasks:
- name: create user bhlu
user:
name: bhlu
uid: 1040
group: daemon
password: "{{'123'|password_hash('sha512')}}"
ansible-playbook user.yml将test组的主机上/dev/nvme0n3,创建两个物理盘,第一个5G,第二个15G,/dev/nvme0n3一共是20G
将两个物理盘组成一个叫test-vg的卷组
在test-vg卷组上创建一个叫test-lv的逻辑卷,大小5G
将test-lv格式化成xfs
将test-lv永久挂载到/data
vim disk.yml---
- name: disk manage
hosts: test
tasks:
- name: create pv1
parted:
device: /dev/nvme0n3
number: 1
state: present
part_end: 5GiB
- name: create pv2
parted:
device: /dev/nvme0n3
number: 2
state: present
part_start: 5GiB
- name: create vg
lvg:
vg: test-vg
pvs: /dev/nvme0n3p1,/dev/nvme0n3p2
- name: create lv
lvol:
vg: test-vg
lv: test-lv
size: 5G
- name: create filesystem
filesystem:
dev: /dev/test-vg/test-lv
fstype: xfs
- name: mount
mount:
path: /data
src: /dev/test-vg/test-lv
fstype: xfs
state: mounted
ansible-playbook disk.yml---
- name: install pkg
hosts: test
tasks:
- name: install httpd,tree,tar
yum:
name: [httpd,tree,tar]
state: present
# 查看软件包组
yum grouplist
# 如果显示是中文,可以加LANG=C yum grouplist
LANG=c yum grouplist
# 安装组
yum groupinstall "组名"
---
- name: install package groups
hosts: test
tasks:
- name: install Development Tools
yum:
name: "@Development Tools"
state: present
yum update---
- name: update packages
hosts: test
tasks:
- name: update system
yum:
name: "*"
state: latest
facts变量是ansible自带的预定义变量,用于描述被控端软硬件信息facts变量ansible test -m setup
filter来过滤想要查看的信息# 查看所有ipv4地址信息
ansible test -m setup -a "filter=ansible_all_ipv4_addresses"
# 查看可用内存
ansible test -m setup -a "filter=ansible_memfree_mb"
常用的facts变量
ansible_all_ipv4_addresses:所有的IPV4地址ansible_bios_version:BIOS版本信息ansible_memtotal_mb:总内存大小ansible_hostname:主机名示例
---
- name: display host info
hosts: test
tasks:
- name: display hostname and memory
debug:
msg: "hostname: {{ansible_hostname}} mem: {{ansible_memtotal_mb}}MB"
引入变量,可以方便Playbook重用。比如装包的playbook,包名使用变量。多次执行playbook,只要改变变量名即可,不用编写新的playbook。
ansible支持10种以上的变量定义方式。常用的变量来源如下:
使用inventory变量示例,在node1主机上创建一个用户bhlu,在webservers组的主机上创建一个用户maomao
vim hosts
# hosts内容如下
[test]
node1 username="bhlu" # 这里定义test组的
[proxy]
node2
[webservers]
node[3:4]
[database]
node5
[cluster:children]
webservers
database
[webservers:vars] # 固定写法 :vars
username="maomao"
# 创建yml文件
vim var.yml
# var.yml内容如下
---
- name: create users
hosts: test,webservers
tasks:
- name: create user
user:
name: "{{username}}"
state: present
# 执行
ansible-playbook var.yml
---
- name: create user
hosts: test
vars: # 固定是vars
username: "bhlu"
passowrd: "123"
tasks:
- name: create bhlu
user:
name: "{{username}}"
password: "{{passowrd|password_hash('sha512')}}"
state: present
vim user_vars.yml
# 文件内容
---
user: "maomao"
pwd: "123"
vim user.yml
# 文件内容
---
- name: create
hosts: test
vars_files: user_vars.yml
tasks:
- name: create maomao
user:
name: "{{user}}"
password: "{{pwd|password_hash('sha512')}}"
state: present
# 执行
ansible-playbook user.yml
# 默认是下面这样写的,但是当启动test服务失败时,会直接跳出,不会执行下面的任务了
---
- name: test error
hosts: test
tasks:
- name: start test service
service:
name: test
state: started
enabled: yes
- name: touch a file
file:
path: /tmp/test.txt
state: touch
# 优化后
cat test.yml
---
- name: test error
hosts: test
tasks:
- name: start test service
ignore_errors: yes # 忽略错误
service:
name: test
state: started
enabled: yes
- name: touch a file
file:
path: /tmp/test.txt
state: touch
# 全局优化
---
- name: test error
hosts: test
ignore_errors: yes # 不管哪个任务发生错误,都会忽略
tasks:
- name: start test service
service:
name: test
state: started
enabled: yes
- name: touch a file
file:
path: /tmp/test.txt
state: touch
# 不管有没有修改配置文件,都会重启服务
---
- name: test trigger
hosts: test
vars:
http_port: "80"
tasks:
- name: upload httpd.conf
template:
src: httpd.conf
dest: /etc/httpd/conf/httpd.conf
- name: restart httpd
service:
name: httpd
state: restarted
# 优化后,只有第一个任务changed,才会执行第二个任务
---
- name: test trigger
hosts: test
vars:
http_port: "8080"
tasks:
- name: upload httpd.conf
template:
src: httpd.conf
dest: /etc/httpd/conf/httpd.conf
notify: restart httpd # 通知,后面的要对应上,空格也不能少
handlers:
- name: restart httpd
service:
name: httpd
state: restarted
只有满足条件时,才执行任务
常用操作符
==:等于!=:不等于>=:大于等于<=:小于等于>:大于<:小于多个条件或以使用and或or进行连接
when表达式中的变量,可以不使用{{}}
# 当内存大于2G,才能运行httpd
---
- name: test when
hosts: test
tasks:
- name: when mem > 2G
service:
name: httpd
state: started
when: ansible_memtotal_mb>2048
# 当hostname为node1,并且系统是RedHat,才运行httpd
---
- name: test when and
hosts: test
tasks:
- name: start httpd
service:
name: httpd
state: started
when: >
ansible_hostname == "node1"
and
ansible_distribution == "RedHat"
---
- name: test block tasks
hosts: test
tasks:
- name: install httpd and start httpd
block:
- name: install httpd
yum:
name: httpd
state: present
- name: start httpd
service:
name: httpd
state: started
when: ansible_hostname == "node1"
block和rescue、always联合使用
block中的任务都成功,rescue中的任务不执行block中的任务出现失败(failed),rescue中的任务执行block中的任务不管怎么样,always中的任务总是执行---
- name: test block rescue always tasks
hosts: test
tasks:
- name: block / rescue / always file
block:
- name: touch /tmp/1.txt
file:
path: /tmp/1.txt
state: touch
rescue:
- name: touch /tmp/2.txt
file:
path: /tmp/2.txt
state: touch
always:
- name: touch /tmp/3.txt
file:
path: /tmp/3.txt
state: touch
shell中for循环ansible中循环用到的变量名是固定的,叫item# 创建多个目录
---
- name: create directory
hosts: test
tasks:
- name: create /tmp/test01 /tmp/test02 /tmp/test03
file:
path: /tmp/{{item}}
state: directory
loop: [test01, test02, test03]
# 创建多个用户
---
- name: create users
hosts: test
tasks:
- name: create test01 test02 test03
user:
name: "{{item.username}}"
password: "{{item.password|password_hash('sha512')}}"
state: present
loop:
- {"username": "test01", "password": "test01@123"}
- {"username": "test02", "password": "test02@123"}
- {"username": "test03", "password": "test03@123"}
playbook重用,可以使用role角色role相当于把任务打散,放到不同的目录中role角色定义好之后,可以在其他playbook中直接调用# 创建角色
# 1. 声明角色存放的位置
vim ansible.cfg
[defaults]
inventory = hosts
roles_path = roles
# 2. 创建角色目录
mkdir roles
# 3. 创建名为user的角色
ansible-galaxy init roles/user
# 4. 查看目录结构
tree roles/user
roles/user/
├── defaults # 定义变量的目录,优先级最低
│ └── main.yml
├── files # 保存上传的文件(如copy要用到的文件)
├── handlers # handlers任务写到这个目录的main.yml
│ └── main.yml
├── meta # 保存说明数据,如角色作者,版本等
│ └── main.yml
├── README.md # 保存角色如何使用之类的说明
├── tasks # 保存任务
│ └── main.yml
├── templates # 保存template模块上传的模板文件
├── tests # 保存测试用的playbook,可选
│ ├── inventory
│ └── test.yml
└── vars # 定义变量的位置,推荐使用
└── main.yml
project,解释器为/bin/tcsh,并传一个test.txt到他的家目录# 1. 配置变量
vim roles/user/defaults/main.yml
# 文件内容
---
# defaults file for roles/user
username: "bhlu"
password: "123"
# 2. 准备一个test.txt文件
touch roles/user/files/test.txt
# 3. 包装任务
cat roles/user/tasks/main.yml
# 文件内容
---
# tasks file for roles/user
- name: create user
user:
name: "{{username}}"
password: "{{password|password_hash('sha512')}}"
state: present
group: project
shell: /bin/tcsh
- name: copy file
copy:
src: test.txt
dest: /home/{{username}}/test.txt
owner: "{{username}}"
group: project
# 4. 创建create_maomao.yml
vim create_maomao.yml
# 文件内容
---
- name: create maomao
hosts: test
vars:
username: "maomao"
password: "maomao123"
roles:
- user
# 5. 执行
ansible-playbook create_maomao.yml
ansible加解密:ansible-vaultecho "hello bhlu" > test.txt
# 加密: encrypt
ansible-vault encrypt test.txt
New Vault password: # 密码
Confirm New Vault password: # 再次输入密码
Encryption successful # 提示成功
# 检查
cat test.txt
# 解密: decrypt
ansible-vault decrypt test.txt
Vault password: # 密码
Decryption successful # 提示成功
# 再次加密
ansible-vault encrypt test.txt
# 修改密码: rekey
ansible-vault rekey test.txt
Vault password: # 旧密码
New Vault password: # 新密码
Confirm New Vault password: # 再次输入新密码
Rekey successful # 提示成功
# 只查看不解密: view
ansible-vault view test.txt
Vault password: # 密码
# 使用文件加密
ansible-vault decrypt --vault-id=pass.txt data.txt
ansible_ssh_user:指定登录远程主机的用户名ansible_ssh_pass:指定登录远程主机的密码ansible_ssh_port:指定登录远程主机的端口号vim ansible.cfg
# 文件内容如下
[defaults]
inventory = hosts
vim hosts
# 文件内容
[group1]
node1 ansible_ssh_user=root ansible_ssh_pass=123456 ansible_ssh_port=220
node2 ansible_ssh_user=root ansible_ssh_pass=123456
node3 ansible_ssh_user=root ansible_ssh_pass=123456