ansible
ansible简介
Ansible是一种开源的自动化工具,可以简化应用程序部署、配置管理和任务执行。它使用简单易懂的语法和模块化的架构,可在多个目标系统上自动化执行任务,包括配置管理、应用程序部署、编排等。
以下是一些关于Ansible的重要特点和功能:
- 简单易用: Ansible使用基于YAML的Playbook语法,使得编写和理解任务配置变得容易。无需编写复杂的代码,即可执行自动化任务。
- 无需客户端代理: Ansible通过SSH协议与目标主机进行通信,不需要在目标主机上安装客户端或代理程序。这简化了配置和管理的过程,并降低了部署的复杂性。
- 剧本和角色: Ansible使用Playbook来组织和执行任务。Playbook是一个包含多个任务的声明性配置文件,可以定义主机、变量、任务和角色等。角色是可复用的任务集合,可在多个Playbook中共享和引用。
- 模块化架构: Ansible的功能通过模块实现,模块是用于执行特定任务的代码块。Ansible提供了丰富的内置模块,涵盖了系统操作、配置管理、云服务、网络设备等各个领域。
- 多平台支持: Ansible能够管理和自动化多种操作系统和云平台,包括Linux、Windows、网络设备和云服务提供商如AWS、Azure、GCP等。
- 可扩展性: Ansible具有良好的扩展性,可以通过插件机制添加自定义模块、回调和插件,以满足特定的需求。
- 可靠性和可重复性: 使用Ansible进行自动化操作,可以确保一致性和可重复性。通过编写Playbook,可以定义所需的状态和配置,并确保在不同环境中的一致执行。
ansible安装和配置
安装
# 环境:centos7
yum -y install epel-release
yum -y install ansible
目录结构
tree /etc/ansible
|-- ansible.cfg
|-- hosts
`-- roles
配置ansible.cfg
# 默认不使用初始目录,一般会新建一个目录
cp -r /etc/ansible /root/ansible
# 配置ansible.cfg文件
cat >/root/ansible/ansible.cfg<< EOF
[defaults]
# some basic default values...
inventory = /root/ansible/hosts
remoute_user = root
host_key_checking = False
EOF
配置hosts
# hosts文件用来按组的方式编写主机列表
cat >/root/ansible/hosts<<EOF
[ansible]
192.168.12.12 host_name=ansible
[server1]
192.168.12.13 host_name=server1
[server2]
192.168.12.14 host_name=server2
#[all:vars]
#ansible_user=root
#ansible_ssh_pass=13579@st
EOF
内置变量
ansible_host
:主机的连接地址(IP地址或主机名)。ansible_port
:SSH连接的端口号。ansible_user
:SSH连接的用户名。ansible_ssh_pass
:SSH连接的密码(不推荐使用,建议使用SSH密钥认证)。ansible_ssh_private_key_file
:SSH连接的私钥文件路径。ansible_connection
:主机连接方式,如ssh
、local
等。ansible_python_interpreter
:远程主机上使用的Python解释器路径。ansible_distribution
:远程主机的发行版名称。ansible_distribution_release
:远程主机的发行版版本。ansible_architecture
:远程主机的体系结构。ansible_facts
:包含有关主机的事实(如CPU信息、内存、磁盘等)的字典。
除了上述变量,Ansible还提供了其他用于访问主机清单、任务和Playbook的信息的变量,如:
inventory_hostname
:当前主机的名称(根据主机清单中的定义)。inventory_hostname_short
:当前主机的短名称(移除域名部分)。groups
:所有主机组的字典(组名作为键,包含组成员的列表作为值)。hostvars
:所有主机的字典(主机名作为键,包含主机变量的字典作为值)。vars
:Playbook中的全局变量。
ansible模块(应用)
command模块
说明: 特殊符号,自定义变量不能使用)
-
args
:要在目标主机上执行的命令。可以是单个命令字符串,也可以是包含多个命令的列表。- name: playbook名称 hosts: all gather_facts: false # 跳过检测,提升执行速度 become: <boolean> # 是否切换到特权用户执行任务 become_user: <user> # 切换到特权用户的用户名 tasks: - name: Run command with args command: args: echo "Hello, World!"
在上述示例中,
args
参数指定要执行的命令,即输出 “Hello, World!”。ansible all -m command -a 'echo "Hello, World!"'
-
chdir
:指定要执行命令时的工作目录。可以是绝对路径或相对路径。- name: Run command in specific directory command: cmd: pwd chdir: /path/to/directory
在上述示例中,
chdir
参数指定在/path/to/directory
目录中执行pwd
命令ansible all -m command -a 'chdir=/path/to/directory pwd'
-
creates
:指定一个文件路径,如果该文件已经存在,则命令将被跳过。适用于避免重复执行相同的命令。- name: Run command if file does not exist command: args: echo "File does not exist" creates: /path/to/file.txt
在上述示例中,
creates
参数指定只有当/path/to/file.txt
文件不存在时才执行命令.ansible all -m command -a 'creates=/path/to/file.txt echo "File does not exist"'
-
removes
:指定一个文件路径,如果该文件不存在,则命令将被跳过。适用于确保文件存在时才执行的命令。- name: Run command if file exists command: args: echo "File exists" removes: /path/to/file.txt
在上述示例中,
removes
参数指定只有当/path/to/file.txt
文件存在时才执行命令。ansible all -m command -a 'removes=/path/to/file.txt echo "File exists"'
-
executable
:指定要在目标主机上使用的可执行程序的路径。通常用于指定非默认的Shell。- name: Run command with custom shell command: args: ls -l executable: /bin/sh
在上述示例中,
executable
参数指定在目标主机上使用/bin/sh
作为执行命令的 shell。ansible all -m command -a 'executable=/bin/sh ls -l'
shell模块
说明: 支持管道符等特殊符号,比command用途广泛
- name: Run shell command
shell:
cmd: "your_command_here"
warn: true # 可选参数,生成警告而不是失败
executable: /bin/sh # 可选参数,指定要使用的可执行程序
creates: /path/to/file # 可选参数,仅当文件不存在时运行命令
removes: /path/to/file # 可选参数,仅当文件存在时运行命令
chdir: /path/to/directory # 可选参数,指定命令运行的工作目录
register: result_variable # 可选参数,将命令输出保存到变量中
eg1: 列出目录下文件
- name: ls dir
shell:
cmd: ls /data
warn: true
register: result
tags: shell_ls
- debug:
var: result.stdout_lines
tags: shell_ls
eg2: 执行多条命令
# 忽略错误
- name: Exec shell and ignore errors
shell: echo "ignore_errors" && exit 1
ignore_errors: true
- name: Exec shell and ignore errors with /bin/true
shell: echo "ignore_errors with /bin/true" && wrong_command || /bin/true
- name: Exec shell and ignore errors with cat
shell: echo "ignore_errors with cat" && wrong_command ||
# 执行多条命令
- name: Exec multi line command with |
shell: |
echo "multi line command with |"
echo "2"
echo "3"
- name: Exec multi line command with ;
shell:
echo "Exec multi line command with ;";
echo "2";
echo "3"
# 执行多条命令
- name: Exec multi shell command with &&
shell: echo "Exec multi line command with &&" && echo "2"
# 检查 test.log 是否存在,不存在则创建
- name: Exec and check
shell: ls|grep test.log
register: test_log
ignore_errors: true
- name: Check test_log
shell: touch test.log
when: test_log.stdout == ""
script模块
模块允许在受控节点上执行本地脚本。使用script
模块,您可以在远程主机上运行本地脚本,而无需将脚本复制到远程主机。
以下是script
模块的详细说明:
参数:
script
:(必需) 本地主机上要运行的脚本的路径。chdir
:(可选) 要切换到的远程主机上的工作目录。creates
:(可选) 一个文件或目录的路径,如果此文件或目录已经存在,则不运行脚本。
-
在远程主机上执行脚本
- name: example scrpit module gather_facts: false hosts: - server1 tasks: - name: exec script script: script-1.sh register: result - debug: var: result.stdout_lines
-
在远程主机上的指定目录执行脚本
- name: example scrpit module gather_facts: false hosts: - server1 tasks: - name: exec script script: script-1.sh args: chdir: /tmp register: result - debug: var: result.stdout_lines
-
在远程主机上指定目录,并判断某个文件如果存在,则不执行脚本
- name: example scrpit module gather_facts: false hosts: - server1 tasks: - name: exec script script: script-1.sh args: chdir: /tmp creates: /tmp/file # 如果tmp目录下存在file文件则跳过执行script-1.sh register: result - debug: var: result.stdout_lines
file模块
file是 Ansible 的一个核心模块,它用于管理文件,软链接和目录。有了 file
模块,你可以设置文件的属性(例如权限、归属、创建硬链接和符号链接等),也可以创建、删除单个文件或目录。
参数:
path
(必须):需要管理的文件/链接/目录的路径。state
:目标的状态。可以是absent
(不存在),directory
(将目标设置为目录),file
(设置为文件),touch
(功能和 Unix的 ‘touch’ 类似),link
(创建符号链接,或用hard
创建硬链接),hard
。mode
:设置文件或目录的权限,可以使用数字 (比如644
) 或符号 (a=r,u+rw
)。owner
:文件的拥有者。需要提供用户名,UID,或者'.'
,If the user does not exist on the target platform, the numerical ID will be set. 要求Ansible用户具有权限更改该文件的所有者。group
:文件的所属组。需要提供组名,GID,或者'.'
。如果组在目标平台上不存在,则将设置数值ID。要求Ansible用户具有权限更改该文件的组。
-
创建目录:
- name: Create directory file: path: /path/to/directory state: directory
-
创建文件
- name: Create file file: path: /path/to/file state: touch
-
更改文件权限和所有权:
- name: Change file ownership, group and permissions file: path: /path/to/myfile owner: foo group: foo mode: '0644'
-
删除文件:
- name: Remove file file: path: /path/to/myfile state: absent
-
创建软链接:
- name: Create symlink file: src: /path/to/source dest: /path/to/dest state: link
-
删除软链接
- name: Remove file file: path: /path/to/dest state: absent
copy模块
copy
模块是 Ansible 的核心模块之一,用于将本地文件复制到托管的远程节点上。以下是关于该模块的详细解释:
-
基本参数
-
src: 本地机器上的文件路径,这是你要复制到远程机器上的文件。
-
dest: 在远程机器上的目标路径。
-
content: 用于直接设置文件内容而不是从另一个文件复制的内容。当使用此参数时,不需要
src
参数。 -
force: 默认为
yes
,如果设置为no
,则只在目标文件不存在时才会复制。 -
backup: 默认为
no
。如果设置为yes
,在修改文件(例如更改权限或内容)之前,将对其进行备份。 -
remote_src: 默认为
no
。如果设置为yes
,将使用远程机器上的文件作为源文件,而不是使用控制机上的文件。 -
权限和所有权
-
owner: 文件的目标所有者。
-
group: 文件的目标组。
-
mode: 用于设置文件的权限。可以是数字(例如
0755
)或符号表示法(例如u=rw,g=r,o=r
)。 -
校验和验证
-
checksum: 用于验证文件的SHA-1校验和。通常,Ansible会自动计算这个值。
-
validate: 用于在将文件复制到其最终位置之前运行验证命令。这对于某些类型的文件(如配置文件)非常有用。
-
案例
-
简单复制
- name: Copy file to remote machine copy: src: /local/path/file.txt dest: /remote/path/file.txt
-
强制复制
- name: Copy file to remote machine copy: src: /local/path/file.txt dest: /remote/path/file.txt force: yes
-
设置权限和所有权
- name: Copy with permissions and ownership copy: src: /local/path/file.txt dest: /remote/path/file.txt owner: user1 group: group1 mode: '0755'
-
直接设置文件内容(覆盖的形式)
- name: Set file content directly copy: content: "This is the file content." dest: /remote/path/file.txt
-
复制远程机器上的文件
- name: Copy file to remote machine copy: src: /remote/path/file.txt dest: /remote/path/file1.txt remote_rc: yes
-
修改文件之前备份
备份生效源文件必须存在
- name: backup before change file copy: content: "shahhs" dest: /tmp/file04.txt owner: dockerroot mode: '0644' backup: yes
user模块
-
创建单个用户并加sudo
- name: create user single user: name: ansrole shell: /bin/bash password: "{{ '13579@st' | password_hash('sha512') }}" tags: single - name: sudo privilege single copy: content: "%ansrole ALL=(ALL) NOPASSWD: ALL" dest: /etc/sudoers.d/ansrole tags: single
-
创建多个用户
- name: create user multi user: name: "{{ item.name }}" shell: /bin/bash password: "{{ item.passwd | password_hash('sha512') }}" with_items: - {name: 'user01', passwd: '123456qq'} - {name: 'user02', passwd: '123456qw'} - {name: 'user03', passwd: '123456qe'} tags: multi - name: sudo privilege multi copy: content: "%{{ item }} ALL=(ALL) NOPASSWD: ALL" dest: "/etc/sudoers.d/{{ item }}" with_items: - 'user01' - 'user02' - 'user03' tags: multi
-
删除多个用户
- name: remove user multi user: name: "{{ item }}" state: absent remove: yes with_items: - 'user01' - 'user02' - 'user03' tags: remove - name: remove privilege file file: path: "/etc/sudoers.d/{{ item }}" state: absent with_items: - 'user01' - 'user02' - 'user03' tags: remove
cron模块
参数解析:
-
name
:cron任务的名称,需要在系统中唯一。 -
minute
,hour
,day
,month
,weekday
:用于指定cron任务的执行时间。具体的时间值可以是数字(0-59)或特殊字符。 -
特殊字符包括:
-
*
:所有值。 -
*/n
:每隔n个时间单位执行。 -
n
:具体的时间值。 -
job
:指定cron任务要执行的命令或脚本的路径。 -
user
:指定要运行cron任务的用户。默认为当前用户。 -
state
:指定cron任务的状态。可以是present
(任务存在)或absent
(任务不存在)。 -
reboot
:布尔值,设置为yes
表示cron任务在系统重启后运行。 -
special_time
:布尔值,设置为yes
表示可以在minute
和hour
参数中使用特殊时间字符串。创建一个任务
- name: Create a cron job cron: name: "My cron job" minute: "*/5" job: "/path/to/my/script.sh" state: present
-
修改现有的cron任务:
- name: Modify a cron job cron: name: "My cron job" minute: "0" hour: "1" job: "/path/to/my/updated_script.sh" state: present
-
删除cron任务:
- name: Remove a cron job cron: name: "My cron job" state: absent
lineinfile模块
-
lineinfile
模块的一些常用参数: -
path
: 指定要操作的目标文件的路径。 -
regexp
: 用于匹配待操作的行的正则表达式。 -
line
: 指定要添加或修改的行内容。 -
state
: 指定行的状态。可以是present
(存在,执行添加/修改行的操作)或absent
(不存在,执行删除行的操作)。 -
backrefs
: 是否使用后向引用,可以在替换时引用正则表达式的捕获组。 -
insertafter
,insertbefore
,,在某行之前/之后插入行,但是只在首次插入行时生效。 -
在文件中添加一行(如果不存在该行)
- name: Add a line to a file lineinfile: path: /path/to/file line: "This is the line to add" state: present
-
修改文件中匹配某个正则表达式的行:
- name: Modify a line in a file lineinfile: path: /path/to/file regexp: "^Some pattern.*" line: "New line content"
-
删除文件中匹配某个正则表达式的行
- name: Remove matching lines from a file lineinfile: path: /path/to/file regexp: "^Some pattern.*" state: absent
-
在某行之前插入一行
- name: Ensure we have our own comment added to /etc/services lineinfile: path: /etc/services insertbefore: '^www.*80/tcp' line: '# port for http by default'
-
在某行之后插入一行
- name: Ensure the default Apache port is 8080 lineinfile: path: /etc/httpd/conf/httpd.conf insertafter: '^#Listen ' line: Listen 8080
template模块
template
模块是Ansible中用于生成配置文件的强大工具。它允许你使用模板文件和变量来动态生成目标主机上的配置文件。
参数解析:
src
:指定模板文件的路径。模板文件可以是本地文件或从Ansible控制节点的文件系统中的相对路径。dest
:指定生成的配置文件的路径和文件名。owner
,group
,mode
:可选参数,用于设置生成的配置文件的属主、属组和权限。backup
:是否创建配置文件的备份。可以使用yes
或no
设置。validate
:验证生成的配置文件的语法是否正确的命令或脚本。vars
:一个字典类型参数,用于传递变量给模板文件。
-
添加ip域名对应关系
在ansible hosts文件中添加如下
[tem] ip1 host_name=name1 ip2 host_name=name2 ip3 host_name=name3
创建hosts.j2文件
{% for host in groups['tem'] %} {{ hostvars[host].inventory_hostname }} {{ hostvars[host].host_name }} {% endfor %}
创建template.yml
- name: TEMPLATE EXAMPLE hosts: tem gather_facts: false tasks: - name: config hosts file template: src: ./hosts.j2 dest: /etc/hosts tags: config
-
jinja2
变量 | 描述 |
---|---|
loop.index | 当前循环迭代的次数(从 1 开始) |
loop.index0 | 当前循环迭代的次数(从 0 开始) |
loop.revindex | 到循环结束需要迭代的次数(从 1 开始) |
loop.revindex0 | 到循环结束需要迭代的次数(从 0 开始) |
loop.first | 如果是第一次迭代,为 True 。 |
loop.last | 如果是最后一次迭代,为 True 。 |
loop.length | 序列中的项目数。 |
loop.cycle | 在一串序列间期取值的辅助函数。 |
-
for语法案例
{% for host in groups['zookeeper'] %} sever.{{ loop.index }}={{ hostvars[host].inventory_hostname }}:2888:3888 {% endfor %}
{% for host in groups['etcd'] %} {% if not loop.last %}sever.{{ loop.index }}=http://{{ hostvars[host].inventory_hostname }}:2379,{% else %}{{%- endif %} {% endfor %}
-
if语法案例
{% set var=2 %} {% if var %} var is: {{ var }} {% else %} var is not found {% endfi %}
-
循环控制
-
这个循环每两项跳过一次
{% for user in users %} {%- if loop.index is even %}{% continue %}{% endif %} ... {% endfor %}
-
这个循环 10 次迭代之后会终止处理
{% for user in users %} {%- if loop.index >= 10 %}{% break %}{% endif %} {%- endfor %}
-
jinja2内置模板函数
-
range语法格式
range([start, ]stop[, step])
-
range生成1~10内的奇数
# 输出是一个列表 - name: output range debug: msg: '{{ range(1,10,2)|list }}'
-
range结合count
{% for item in users %} {{ item }} {% endfor %} {% for n in range(10 -users|count) %} {{ n }} {% endfor %}
- hosts: localhost gather_facts: false tasks: - name: output range debug: msg: '{{ range(1,10,2)|list }}' # 将列表的内容以","拼接 #msg: '{{ range(1,10,2)|list|join(',') }}' - name: range and count vars: users: - user1 - user2 - user3 template: src: range.j2 dest: /tmp/file1 tags: rac
-
split
split(“.”)将字符串以"."为分割线转化为列表
{{ "192.168.4.1".split(".") }}
- name: debug split debug: msg: '{{ "192.168.4.1".split(".") }}''
split切片后重新转为字符
# 将"192.168.4.1"拼接为"192.168.4.254" - name: debug split debug: msg: '{{ "192.168.4.1".split(".")[:3].join('.').254 }}''
-
trim
移除字符串两边的空格
- name: debug trim debug: msg: '{{ " hello world "|trim}'
循环(loop|with_*)
-
标准循环
- name: debug standard criculation debug: msg: '{{ item }}' with_items: - user1 - user2 - user3 - user4 tags: stand
- name: debug stand criculation debug: msg: '{{ item.name,item.groups}}' with_items: - {name: 'user01', groups: 'wheel'} - {name: 'user02', groups: 'nginx'} - {name: 'user03', groups: 'root'} tags: stand
-
嵌套循环
- name: debug nest criculation debug: msg: '{{ item.name,item.groups}}' with_nested: - ['Alice','Joker'] - ['clientdb', 'employeedb', 'providerdb'] tags: nest
-
对哈希表循环
- name: debug hash criculation vars: users: Alice: name: Alice Mreia phone: 125-223-397 Bob: name: Bob Wer phone: 526-129-287 debug: msg: 'User: {{ item.key }} is {{ item.value.name }} ({{ item.value.phone }})' with_dict: - '{{ users }}' tags: hash
-
对文件列表使用循环
- name: debug file list criculation debug: msg: '{{ item }}' with_fileglob: - /etc/* tags: file
-
对并行数据集循环
- name: debug parallel data criculation debug: msg: '({{ item.0 }},{{ item.1 }})' with_together: - ['a','b','c'] - [1,2,4] tags: paral
-
Do-until循环
重试一个任务直到达到某个条件
- name: shell: /usr/bin/foo register: result until: result.stdout.find("all systems go") != -1 retries: 5 delay: 10
描述: 上面的例子递归运行shell模块,直到模块结果中的stdout输出中包含”all systems go”字符串,或者该任务按照10秒的延迟重试超过5次.”retries”和”delay”的默认值分别是3和5.
-
循环中使用注册器
- name: Loop with registered variable example hosts: localhost gather_facts: false vars: fruits: - apple - banana - orange tasks: - name: Print fruits debug: msg: "Fruit: {{ item }}" loop: "{{ fruits }}" register: loop_result - name: Print registered variable debug: msg: "Registered: {{ loop_result.results | map(attribute='item') | list }}"
描述: 使用注册变量
loop_result.results
并通过map
和attribute
过滤器提取item
属性,最后转换为一个列表,以输出注册变量中的值。
条件选择(when)
-
当ansible_os_family为ReadHat时执行shell
tasks: - name: shell: echo "only on Red Hat 6, derivatives, and later" when: ansible_os_family == "RedHat" and ansible_lsb.major_release|int >= 6
-
变量不存在,你可以使用Jinja2的
defined
命令跳过或略过tasks: - name: shell: echo "I've got '{{ foo }}' and am not afraid to use it!" when: foo is defined - fail: msg="Bailing out. this play requires 'bar'" when: bar is not defined