Answers:
根据Ansible开发人员的说法,解决此问题的正确方法是使用类似以下内容的方法:
vars_files_locs: ['../path/to/file1', '../path/to/file2', ...]
- include_vars: "{{ item }}"
with_first_found: vars_files_locs
此外,他们说:
上面的代码将仅正确加载找到的第一个文件,并且比通过
vars_files
language关键字尝试加载更为灵活。
include_vars
与角色相比,在任务中变量的优先级更高,defaults
或者vars
我在一个安装程序中遇到了此问题,在该安装程序中,我需要向同一物理服务器(此处不允许使用虚拟机)创建多个部署环境(实时,演示,沙箱),然后创建用于部署任意svn仓库的脚本
这需要一个(可选)variable.yml文件的目录树,该目录树将彼此合并,并且在缺少任何地方时不会引发异常
首先在ansible中启用变量合并-请注意,这会进行浅层哈希合并(深度为1级),而不是完全递归的深度合并
[defaults]
hash_behaviour=merge ;; merge rather than replace dictionaries http://docs.ansible.com/ansible/intro_configuration.html###hash-behaviour
/group_vars
└── all.yml
/playbooks
├── boostrap.yml
├── demo.yml
├── live.yml
└── sandbox.yml
/roles/deploy/
├── files
├── tasks
│ ├── includes.yml
│ ├── main.yml
└── vars
├── main.yml
├── project_1.yml
├── project_2.yml
├── demo
│ ├── project_1.yml
│ ├── project_2.yml
│ └── main.yml
├── live
│ ├── project_1.yml
│ ├── project_2.yml
│ └── main.yml
└── sandbox
├── project_1.yml
├── project_2.yml
└── main.yml
这是可选变量文件的目录树的主要逻辑。
;; imports in this order:
;; - /roles/deploy/vars/main.yml
;; - /roles/deploy/vars/{{ project_name }}.yml
;; - /roles/deploy/vars/{{ project_name }}/main.yml
;; - /roles/deploy/vars/{{ project_name }}/{{ project_env }}.yml
- include_vars:
dir: 'vars'
files_matching: "{{ item }}"
depth: 1
with_items:
- "main.yml"
- "{{ project_name }}.yml"
- include_vars:
dir: 'vars/{{ env_name }}'
files_matching: "{{ item }}"
depth: 1
with_items:
- "main.yml"
- "{{ project_name }}.yml"
为项目以及各种用户和环境配置默认变量
project_users:
bootstrap:
env: bootstrap
user: ansible
group: ansible
mode: 755
root: /cs/ansible/
home: /cs/ansible/home/ansible/
directories:
- /cs/ansible/
- /cs/ansible/home/
live:
env: live
user: ansible-live
group: ansible
mode: 755
root: /cs/ansible/live/
home: /cs/ansible/home/ansible-live/
demo:
env: demo
user: ansible-demo
group: ansible
mode: 755
root: /cs/ansible/demo/
home: /cs/ansible/home/ansible-demo/
sandbox:
env: sandbox
user: ansible-sandbox
group: ansible
mode: 755
root: /cs/ansible/sandbox/
home: /cs/ansible/home/ansible-sandbox/
project_env: bootstrap
project_user: "{{ ansible_users[project_env] }}" ;; this will be retroactively updated if project_env is redefined later
项目默认值
ansible_project:
node_env: development
node_port: 4200
nginx_port: 4400
project_1的默认值
ansible_project:
node_port: 4201
nginx_port: 4401
现场环境的默认设置,覆盖项目默认设置
ansible_project:
node_env: production
实时环境中project_1的最终替代
ansible_project:
nginx_port: 80
为每种环境配置单独的剧本
- hosts: shared_server
remote_user: ansible-demo
vars:
project_env: demo
pre_tasks:
- debug: "msg='{{ facter_gid }}@{{ facter_fqdn }} ({{ server_pseudonym }})'"
- debug: var=project_ssh_user
roles:
- { role: deploy, project_name: project_1 }
警告:由于所有环境都位于单个主机上,因此所有剧本都必须单独运行,否则Ansible会尝试以第一个ssh登录用户身份运行所有脚本,并且仅对第一个用户使用变量。如果需要顺序运行所有脚本,请使用xargs将它们作为单独的命令运行。
find ./playbooks/*.yml | xargs -L1 time ansible-playbook
- hosts: all
vars_files: vars/vars.default.yml
vars:
optional_vars_file: "{{ lookup('first_found', 'vars/vars.yml', errors='ignore') }}"
tasks:
- when: optional_vars_file is file
include_vars: "{{ optional_vars_file }}"
注意:在运行ansible-playbook命令时,路径测试(是文件,是否存在...)仅适用于绝对路径或相对于当前工作目录的路径。这就是我们使用查找的原因。查找接受相对于剧本目录的路径,并在文件存在时返回绝对路径。
或者以一种更传统的方式:
- hosts: webservers
vars:
paths_to_vars_files:
- vars/{{ ansible_hostname }}.yml
- vars/default.yml
tasks:
- include_vars: "{{ item }}"
with_first_found: "{{ paths_to_vars_files }}"
也就是说,与其在方括号的一行上写一个数组,不如:
['path/to/file1', 'path/to/file2', ...]
使用yaml在多行上写数组值的方式,例如:
- path/to/file1
- path/to/file2
如前所述,这将查找名为的vars文件{{ ansible_hostname }}.yml
,如果不存在,则使用default.yml
基于最新Ansible版本的新答案-基本上,如果找不到文件,则应使用with_first_found
和skip: true
跳过任务。
- name: Include vars file if one exists meeting our condition.
include_vars: "{{ item }}"
with_first_found:
- files:
- vars/{{ variable_here }}.yml
skip: true
这样一来,您就不必在该列表中有一个后备vars文件。