在被管理节点上创建文件或目录
一、修改文件并将其复制到主机
1. 描述文件模块
常用文件模块
模块名称 | 模块说明 |
---|---|
blockinfile | 插入、更新或删除由可自定义标记线包围的多行文本块 |
copy | 将文件从本地或远程计算机复制到受管主机上的某个位置。 类似于file模块,copy模块还可以设置文件属性,包括SELinux上下文件。 |
fetch | 此模块的作用和copy模块类似,但以相反方式工作。 此模块用于从远程计算机获取文件到控制节点,并将它们存储在按主机名组织的文件树中。 |
file | 设置权限、所有权、SELinux上下文以及常规文件、符号链接、硬链接和目录的时间戳等属性。 此模块还可以创建或删除常规文件、符号链接、硬链接和目录。 其他多个与文件相关的模块支持与file模块相同的属性设置选项,包括copy模块。 |
lineinfile | 确保特定行位于某文件中,或使用反向引用正则表达式来替换现有行。 此模块主要在用户想要更改文件的某一行时使用。 |
stat | 检索文件的状态信息,类似于Linux中的stat命令。 |
synchronize | 围绕rsync命令的一个打包程序,可加快和简化常见任务。 synchronize模块无法提供对rsync命令的完整功能的访问权限,但确实最常见的调用更容易实施。 用户可能仍需通过run command模块直接调用rsync命令。 |
blockinfile模块
插入、更新或删除由可自定义标记线包围的多行文本块
[root@apache ~]# echo "hello world" > /tmp/abc
[root@apache ~]# cat /tmp/abc
hello world
[root@ansible playbook]# cat test.yml
---
- hosts: 192.168.47.129
gather_facts: no
tasks:
- name: wjj
blockinfile:
path: /tmp/abc
block: | //block:要写的内容;|表示多行
hello wjj
hello wj
[root@ansible playbook]# ansible-playbook test.yml
PLAY [192.168.47.129] **********************************************************
TASK [wjj] *********************************************************************
changed: [192.168.47.129]
PLAY RECAP *********************************************************************
192.168.47.129 : ok=1 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[root@apache ~]# cat /tmp/abc
hello world
# BEGIN ANSIBLE MANAGED BLOCK
hello wjj
hello wj
# END ANSIBLE MANAGED BLOCK
[root@ansible playbook]# cat test.yml
---
- hosts: 192.168.47.129
gather_facts: no
tasks:
- name: wjj
blockinfile:
path: /tmp/abc
block: |
hello wjj
hello wj
hello lisa
[root@ansible playbook]# ansible-playbook test.yml
PLAY [192.168.47.129] **********************************************************
TASK [wjj] *********************************************************************
changed: [192.168.47.129]
PLAY RECAP *********************************************************************
192.168.47.129 : ok=1 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[root@apache ~]# cat /tmp/abc
hello world
# BEGIN ANSIBLE MANAGED BLOCK
hello wjj
hello wj
hello lisa
# END ANSIBLE MANAGED BLOCK
//替换 ansible管理的文件
不能自己去tmp/abc目录下手动改,改了一执行任务,就又会变回去
[root@ansible playbook]# cat test.yml
---
- hosts: 192.168.47.129
gather_facts: no
tasks:
- name: wjj
blockinfile:
path: /tmp/abc
block: |
举镜子的女孩
一步之遥
平凡的一天
[root@ansible playbook]# ansible-playbook test.yml
PLAY [192.168.47.129] **********************************************************
TASK [wjj] *********************************************************************
changed: [192.168.47.129]
PLAY RECAP *********************************************************************
192.168.47.129 : ok=1 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[root@apache ~]# cat /tmp/abc
hello world
# BEGIN ANSIBLE MANAGED BLOCK
举镜子的女孩
一步之遥
平凡的一天
# END ANSIBLE MANAGED BLOCK
fetch
把远程主机上的放到本地
此模块的作用和copy模块类似,但以相反方式工作。
此模块用于从远程计算机获取文件到控制节点,并将它们存储在按主机名组织的文件树中。
[root@ansible playbook]# cat test.yml
---
- hosts: 192.168.47.129
gather_facts: no
tasks:
- name: wjj
fetch:
src: /tmp/abc
dest: /opt
[root@ansible playbook]# ansible-playbook test.yml
PLAY [192.168.47.129] **********************************************************
TASK [wjj] *********************************************************************
changed: [192.168.47.129]
PLAY RECAP *********************************************************************
192.168.47.129 : ok=1 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[root@ansible playbook]# ls /opt/
192.168.47.129
[root@ansible playbook]# tree /opt/
/opt/
└── 192.168.47.129
└── tmp
└── abc
2 directories, 1 file
stat
检索文件的状态信息,类似于Linux中的stat命令。
[root@apache ~]# stat anaconda-ks.cfg
文件:anaconda-ks.cfg
大小:1396 块:8 IO 块:4096 普通文件
设备:fd00h/64768d Inode:67146822 硬链接:1
权限:(0600/-rw-------) Uid:( 0/ root) Gid:( 0/ root)
环境:system_u:object_r:admin_home_t:s0
最近访问:2021-03-01 23:09:33.720045011 +0800
最近更改:2021-03-01 23:08:45.041954579 +0800
最近改动:2021-03-01 23:08:45.041954579 +0800
创建时间:-
[root@ansible playbook]# cat test.yml
---
- hosts: 192.168.47.129
gather_facts: no
tasks:
- name: wjj
stat:
path: /root/anaconda-ks.cfg
register: result
- debug:
var: result
[root@ansible playbook]# ansible-playbook test.yml
PLAY [192.168.47.129] **********************************************************
TASK [wjj] *********************************************************************
ok: [192.168.47.129]
TASK [debug] *******************************************************************
ok: [192.168.47.129] => {
"result": {
"ansible_facts": {
"discovered_interpreter_python": "/usr/libexec/platform-python"
},
"changed": false,
"failed": false,
"stat": {
"atime": 1627383079.691803,
"attr_flags": "",
"attributes": [],
"block_size": 4096,
"blocks": 8,
"charset": "us-ascii",
"checksum": "6da6dcbc54117a4f355720d398bd85a7e576a8e6",
"ctime": 1614611325.0419545,
"dev": 64768,
"device_type": 0,
"executable": false,
"exists": true,
"gid": 0,
"gr_name": "root",
"inode": 67146822,
"isblk": false,
"ischr": false,
"isdir": false,
"isfifo": false,
"isgid": false,
"islnk": false,
"isreg": true,
"issock": false,
"isuid": false,
"mimetype": "text/plain",
"mode": "0600",
"mtime": 1614611325.0419545,
"nlink": 1,
"path": "/root/anaconda-ks.cfg",
"pw_name": "root",
"readable": true,
"rgrp": false,
"roth": false,
"rusr": true,
"size": 1396,
"uid": 0,
"version": "2506609426",
"wgrp": false,
"woth": false,
"writeable": true,
"wusr": true,
"xgrp": false,
"xoth": false,
"xusr": false
}
}
}
PLAY RECAP *********************************************************************
192.168.47.129 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
synchronize
围绕rsync命令的一个打包程序,可加快和简化常见任务。
synchronize模块无法提供对rsync命令的完整功能的访问权限,但确实最常见的调用更容易实施。
用户可能仍需通过run command模块直接调用rsync命令。
[root@apache ~]# yum -y install rsync
Updating Subscription Management repositories.
Unable to read consumer identity
This system is not registered to Red Hat Subscription Management. You can use subscription-manager to register.
上次元数据过期检查:2:40:22 前,执行于 2021年07月27日 星期二 16时13分56秒。
软件包 rsync-3.1.3-7.el8.x86_64 已安装。
依赖关系解决。
无需任何处理。
完毕!
//打包目录
[root@ansible playbook]# vim test.yml
[root@ansible playbook]# cat test.yml
---
- hosts: 192.168.47.129
gather_facts: no
tasks:
- name: wjj
yum:
name: rsync
state: present
- name: 同步文件
synchronize:
src: files
dest: /opt
[root@ansible playbook]# ansible-playbook test.yml
PLAY [192.168.47.129] **********************************************************
TASK [wjj] *********************************************************************
ok: [192.168.47.129]
TASK [同步文件] ********************************************************************
changed: [192.168.47.129]
PLAY RECAP *********************************************************************
192.168.47.129 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
//打包文件
[root@ansible playbook]# vim test.yml
[root@ansible playbook]# cat test.yml
---
- hosts: 192.168.47.129
gather_facts: no
tasks:
- name: wjj
yum:
name: rsync
state: present
- name: 同步文件
synchronize:
src: files/vsftpd.conf
dest: /opt
[root@ansible playbook]# ansible-playbook test.yml
PLAY [192.168.47.129] **********************************************************
TASK [wjj] *********************************************************************
ok: [192.168.47.129]
TASK [同步文件] ********************************************************************
changed: [192.168.47.129]
PLAY RECAP *********************************************************************
192.168.47.129 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
2. files模块的自动化示例
在受管主机上创建、复制、编辑和删除文件是用户可以使用Files模块库中的模块实施的常见任务。
以下示例显示了可以使用这些模块自动执行常见文件管理任务的方式。
2.1 确保受管主机上存在文件
使用file模块处理受管主机上的文件。其工作方式与touch命令类似,如果不存在则创建一个空文件,如果存在,则更新其修改时间。在本例中,除了处理文件之外,Ansible还确保将文件的所有者、组和权限设置为特定值。
- name: Touch a file and set permissions
file:
path: /path/to/file
owner: user1
group: group1
mode: 0640
state: touch
2.2 修改文件属性
使用file模块还可以确保新的或现有的文件具有正确的权限和SELinux类型
- name: SELinux type is set to samba_share_t
file:
path: /path/to/samba_file
setype: samba_share_t
文件属性参数在多个文件管理模块中可用。运行ansible-doc file和ansible-doc copy命令以获取其他信息。
2.3 在受管主机上复制和编辑文件
copy模块用于将位于控制节点上的Ansible工作目录中的文件复制到选定的受管主机。
默认情况下,此模块假定设置了force: yes。这会强制该模块覆盖远程文件(如果存在但包含与正在复制的文件不同的内容)。如果设置force: no,则它仅会将该文件复制到受管主机(如果该文件尚不存在)
- name: copy a file to managed hosts
copy:
src: file
dest: /path/to/file
二、jinja2模板管理
1、jinja2模板的用法(部署)
Ansible将jinja2模板系统用于模板文件。Ansible还使用jinja2语法来引用playbook中的变量。变量和逻辑表达式置于标记或分隔符之间。
{% EXPR %} 定义一个表达式,
{{ EXPR }} 引用变量,
{# COMMENT #} 表示注释的内容
jinja2模板是功能强大的工具,可用于自定义要在受管主机上部署的配置文件。创建了适用于配置文件的jinja2模板后,它可以通过template模板部署到受管主机上,该模块支持将控制节点中的本地文件转移到受管主机。
template模块功能与copy模块是一样的,但是区别在于jinja2模板的template模块可以把jinja2模板里面的变量和事实把它替换成对应的东西,而copy模块不可以。
[root@ansible files]# ls
hosts
[root@ansible files]# vim hosts
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
192.168.47.129 node
[root@ansible files]# mv hosts{,.j2}
[root@ansible files]# ls
hosts.j2
[root@ansible files]# cat hosts.j2
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
{# 注释 #}
{{ ansible_facts['default_ipv4']['address'] }} {{ ansible_facts['hostname'] }}
//copy模块 内容会被原封不动的显示出来
[root@ansible playbook]# cat test.yml
---
- hosts: "*"
tasks:
- name: wjj
copy:
src: files/hosts.j2
dest: /etc/hosts
[root@ansible playbook]# ansible-playbook test.yml
PLAY [*] ***********************************************************************
TASK [Gathering Facts] *********************************************************
ok: [192.168.47.129]
TASK [wjj] *********************************************************************
changed: [192.168.47.129]
PLAY RECAP *********************************************************************
192.168.47.129 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[root@node ~]# cat /etc/hosts
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
{# 注释 #}
{{ ansible_facts['default_ipv4']['address'] }} {{ ansible_facts['hostname'] }}
//template模块 把该替换的内容替换成对应的内容
[root@ansible playbook]# cat test.yml
---
- hosts: "*"
tasks:
- name: wjj
template:
src: files/hosts.j2
dest: /etc/hosts
[root@ansible playbook]# ansible-playbook test.yml
PLAY [*] ***********************************************************************
TASK [Gathering Facts] *********************************************************
ok: [192.168.47.129]
TASK [wjj] *********************************************************************
changed: [192.168.47.129]
PLAY RECAP *********************************************************************
192.168.47.129 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[root@node ~]# cat /etc/hosts
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
192.168.47.129 node
2、关于模板的说法(构建)
jinja2模板由多个元素组成:数据、变量和表达式。在呈现jinja2模板时,这些变量和表达式被替换为对应的值。模板中使用的变量可以在playbook的vars部分中指定。可以将受管主机的事实用作模板中的变量。
使用ansible system_hostname -i inventory_file -m setup命令来获取与受管主机相关的事实。
//引用变量
# {{ ansible_managed }} //ansible_managed是一个变量
# DO NOT MAKE LOCAL MODIFICATIONS TO THIS FILE AS THEY WILL BE LOST
Port {{ ssh_port }} //端口号定义的变量
ListenAddress {{ ansible_facts['default_ipv4']['address'] }} // 用事实取IP
HostKey /etc/ssh/ssh_host_rsa_key
HostKey /etc/ssh/ssh_host_ecdsa_key
HostKey /etc/ssh/ssh_host_ed25519_key
SyslogFacility AUTHPRIV
PermitRootLogin {{ root_allowed }} //允不允许root用户登录
AllowGroups {{ groups_allowed }} //允不允许组
AuthorizedKeyFile /etc/.rht_authorized_keys .ssh/authorized_keys
PasswordAuthentication {{ passwords_allowed }} //要不要允许密码认证
ChallengeResponseAuthentication no
GSSAPIAuthentication yes
GSSAPICleanupCredentials no
UsePAM yes
X11Forwarding yes
UsePrivilegeSeparation sandbox
AcceptEnv LANG LC_CTYPE LC_NUMERIC LC_TIME LC_COLLATE LC_MONETARY LC_MESSAGES
AcceptEnv LC_PAPER LC_NAME LC_ADDRESS LC_TELEPHONE LC_MEASUREMENT
AcceptEnv LC_IDENTIFICATION LC_ALL LANGUAGE
AcceptEnv XMODIFIERS
Subsystem sftp /usr/libexec/openssh/sftp-server
3、管理模板文件
为避免系统管理员修改Ansible部署的文件,最好在模板顶部包含注释,以指示不应手动编辑该文件。
可使用ansible_managed指令中设置的"Ansible managed"字符串来执行此操作。这不是正常变量,但可以在模板中用作一个变量。
ansible_managed指令在ansible.cfg文件中设置
[root@ansible files]# cat hosts.j2
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
{# 注释 #}
# {{ ansible_managed }}
{{ ansible_facts['default_ipv4']['address'] }} {{ ansible_facts['hostname'] }}
[root@ansible playbook]# cat test.yml
---
- hosts: "*"
tasks:
- name: wjj
template:
src: files/hosts.j2
dest: /etc/hosts
[root@ansible ansible]# ansible-playbook playbook/test.yml
PLAY [*] ***********************************************************************
TASK [Gathering Facts] *********************************************************
ok: [192.168.47.129]
TASK [wjj] *********************************************************************
changed: [192.168.47.129]
PLAY RECAP *********************************************************************
192.168.47.129 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[root@node ~]# cat /etc/hosts
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
# Ansible managed
192.168.47.129 node
4、控制结构
用户可以在模板文件中使用jinja2控制结构,以减少重复输入,为play中的每个主机动态输入条目,或者有条件地将文本插入到文件中。
4.1 循环语句
//for循环
[root@ansible playbook]# vim vars/user.yml //变量文件
[root@ansible playbook]# cat vars/user.yml
info:
- hello wang
- hello jing
- hello j
[root@ansible playbook]# vim test.yml
[root@ansible playbook]# cat test.yml
---
- hosts: "*"
gather_facts: no
vars_files: //引用变量文件
- vars/user.yml
tasks:
- name: wjj
template:
src: files/test.j2
dest: /tmp/abc
[root@ansible playbook]# vim files/test.j2 // playbook中引用的文件
[root@ansible playbook]# cat files/test.j2
{% for msg in info %}
{{ msg }}
=========
{% endfor %}
[root@ansible playbook]# ansible-playbook test.yml
PLAY [*] ***********************************************************************
TASK [wjj] *********************************************************************
changed: [192.168.47.129]
PLAY RECAP *********************************************************************
192.168.47.129 : ok=1 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[root@node ~]# cat /tmp/abc
hello wang
=========
hello jing
=========
hello j
=========
//if判断条件
[root@ansible playbook]# cat files/test.j2
{% for msg in info if msg == "hello wang" %} //只显示wang,如果不要wang就在if后面加个not,或者!=不等于
{{ msg }}
=========
{% endfor %}
[root@ansible playbook]# ansible-playbook test.yml
PLAY [*] ***********************************************************************
TASK [wjj] *********************************************************************
changed: [192.168.47.129]
PLAY RECAP *********************************************************************
192.168.47.129 : ok=1 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[root@node ~]# cat /tmp/abc
hello wang
========
//循环里面加判断语句,在for循环里面去判断
[root@ansible playbook]# cat files/test.j2
{% for msg in info %}
{% if msg == "hello wang" %}
{{ msg }}
=========
{% endif %}
{% endfor %}
[root@node ~]# cat /tmp/abc
hello wang
=========
//循环的次数
[root@ansible playbook]# cat files/test.j2
{% for msg in info %} // 像这样如果是在for里面包含了if语句的话,那就一定会执行,一定执行的话就变成了判断,然后执行第二次判断的时候就会跳过,因为符合要求,符号条件
{% if msg == "hello jing" %}
count {{ loop.index }} of info is {{ msg }}. //第几次被info变量循环的值是msg
{% endif %}
{% endfor %}
[root@ansible playbook]# ansible-playbook test.yml
PLAY [*] ***********************************************************************
TASK [wjj] *********************************************************************
changed: [192.168.47.129]
PLAY RECAP *********************************************************************
192.168.47.129 : ok=1 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[root@node ~]# cat /tmp/abc
count 2 of info is hello jing.
[root@ansible playbook]# cat files/test.j2
{% for msg in info if msg == "hello jing" %} //如果这个写成一行就会被跳过,直接不执行,就不会进入循环了。当然如果不用序号的话就无所谓,里面外面都可以写
count {{ loop.index }} of info is {{ msg }}.
{% endfor %}
[root@node ~]# cat /tmp/abc
count 1 of info is hello jing.
不需要用 {{}} 引用变量的场景:
debug模块里面的var参数
playbook中用when判断条件时
模块文件中定义的时候{% 定义的时候 %}
4.2 条件判断
jinja2使用if语句来提供条件控制。如果满足某些条件,这允许用户在已部署的文件中放置一行。
当变量的值为True时,只要不是空的都属于真,才可将result变量的值放入已部署的文件。
//引号里面没有东西,为空
[root@ansible playbook]# cat files/test.j2
{% if "" %} //引号为空,条件不成立
tiaojianpanduan
{% endif %}
[root@ansible playbook]# ansible-playbook test.yml
PLAY [*] ***********************************************************************
TASK [wjj] *********************************************************************
changed: [192.168.47.129]
PLAY RECAP *********************************************************************
192.168.47.129 : ok=1 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[root@node ~]# cat /tmp/abc
//引号里面有东西,为真 (包括空格)
[root@ansible playbook]# cat files/test.j2
{% if " " %}
tiaojianpanduan
{% endif %}
[root@node ~]# cat /tmp/abc
tiaojianpanduan
4.3 变量过滤器
jinja2提供了过滤器,更改模板表达式的输出格式
to_nice_json过滤器使用JSON格式化表达式输出
[root@ansible playbook]# cat vars/user.yml
info:
- name: wang
age: 18
- name: jing
age: 20
[root@ansible playbook]# cat files/test.j2
{% if " " %}
{{ info | to_nice_json }}
{% endif %}
[root@ansible playbook]# ansible-playbook test.yml
PLAY [*] ***********************************************************************
TASK [wjj] *********************************************************************
changed: [192.168.47.129]
PLAY RECAP *********************************************************************
192.168.47.129 : ok=1 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[root@node ~]# cat /tmp/abc
[
{
"age": 18,
"name": "wang"
},
{
"age": 20,
"name": "jing"
}
]