Ansible:根据目标库存切换/覆盖变量

Ansible:根据目标库存切换/覆盖变量,ansible,Ansible,我正在考虑使用Ansible在三种不同环境(prod/stag/dev)的主机上部署rails应用程序。但为每台主机设置不同的RAILS\u ENV却举步维艰 我尝试了以下设置 目录结构: . ├── group_vars │ └── app1.yml ├── inventories │ ├── develop │ │ └── group_vars │ │ └── app1.yml │ ├── production │ └── staging └── r

我正在考虑使用Ansible在三种不同环境(prod/stag/dev)的主机上部署rails应用程序。但为每台主机设置不同的
RAILS\u ENV
却举步维艰

我尝试了以下设置

目录结构:

.
├── group_vars
│   └── app1.yml
├── inventories
│   ├── develop
│   │   └── group_vars
│   │        └── app1.yml
│   ├── production
│   └── staging
└── roles
组变量/app1.yml
(用于跨环境的通用变量)

存货/develope/group_vars/app1.yml
(针对特定存货的VAR)

在判断变量是否已经定义时,Ansible似乎只查看顶层的键。因此,第二个文件中的
RAILS\u ENV
被无意中忽略。 (不确定为什么库存变量的优先级较低,我认为应该较高,因为它更具体?)

有什么干净的方法可以做到这一点吗?

正如Ansible文档的hash behavior一文所建议的:

默认\u散列\u行为 说明:此设置控制变量如何在Ansible中合并。默认情况下,Ansible将按照特定的优先顺序覆盖变量,如变量中所述。当一个优先级较高的变量获胜时,它将替换另一个值。一些用户更喜欢合并散列变量(Python术语中称为“字典”)。此设置称为“合并”。这不是默认行为,也不会影响值为标量(整数、字符串)或数组的变量。我们通常建议不要使用此设置,除非您认为您绝对需要它,并且官方示例中的剧本REPO在版本2.0中不使用此设置。添加了
combine
filter,以允许对特定变量(在Filters中描述)执行此操作

来源:
实现这一点的推荐方法是使用过滤器

这就是说,您的词典中确实有一个列表,这将使它成为一项相当复杂的任务。
换成字典可以减轻痛苦:

服务:
应用程序:
环境:
RAILS_ENV:开发
可重写的变量:foo
db:
福:酒吧

如果我理解正确的话,您是在尝试采用Ansible最佳实践

如果是这种情况,这里可能有一个与您的用例相匹配的解决方案,因为您可以在字典中的
服务
中转置您的列表,如上所述:

  • 在每个环境的组var文件中,以环境名称作为
    服务
    字典键的前缀,例如
    开发服务
    development\u服务:
    应用程序:
    环境:
    RAILS_ENV:开发
    可覆盖的变量:从库存组变量开发
    
  • 在您的剧本中,作为第一项任务,甚至作为一项
    pre_任务
    服务
    字典与与您的环境相匹配的字典结合,您可以将其作为路径的一部分:
    pre_任务:
    -设定事实:
    服务:{{services}combine(vars[inventory_file.split('/')[-2]~''u services'],recursive=True)}
    
  • 那就用它吧

    给定目录布局:

    .
    ├── group_vars
    │   └── app1.yml
    ├── inventories
    │   ├── develop
    │   │   ├── group_vars
    │   │   │   └── app1.yml
    │   │   └── hosts
    │   └── staging
    │       ├── group_vars
    │       │   └── app1.yml
    │       └── hosts
    └── play.yml
    
    组变量/app1.yml

    服务:
    应用程序:
    环境:
    酒吧:福
    可重写的变量:来自根组变量
    不覆盖:来自根组变量
    db:
    引擎:博士后
    
    清单/开发/主机

    全部:
    儿童:
    附录1:
    主持人:
    应用程序:
    
    存货/开发/集团变量/app1.yml

    development\u服务:
    应用程序:
    环境:
    RAILS_ENV:开发
    可覆盖的变量:从库存组变量开发
    
    库存/暂存/主机

    全部:
    儿童:
    附录1:
    主持人:
    应用程序:
    
    库存/暂存/组变量/app1.yml

    staging\u服务:
    应用程序:
    环境:
    RAILS_ENV:暂存
    可覆盖的变量:从库存组变量暂存
    
    play.yml

    -主机:所有
    收集事实:不
    学前任务:
    -设定事实:
    服务:{{services}combine(vars[inventory_file.split('/')[-2]~''u services'],recursive=True)}
    任务:
    -调试:
    msg:“{{services}}”
    
    develope
    运行它将提供以下概述:

    $ ansible-playbook play.yml -i inventories/develop
    
    PLAY [all] *********************************************************************************************************
    
    TASK [set_fact] ****************************************************************************************************
    ok: [app]
    
    TASK [debug] *******************************************************************************************************
    ok: [app] => {
        "msg": {
            "app": {
                "environment": {
                    "RAILS_ENV": "development",
                    "bar": "foo",
                    "do_not_override_me": "from root group_vars",
                    "overridable_var": "develop from inventories group_vars"
                }
            },
            "db": {
                "engine": "postgres"
            }
        }
    }
    
    PLAY RECAP *********************************************************************************************************
    app                        : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0 
    
    $ ansible-playbook play.yml -i inventories/staging
    
    PLAY [all] *********************************************************************************************************
    
    TASK [set_fact] ****************************************************************************************************
    ok: [app]
    
    TASK [debug] *******************************************************************************************************
    ok: [app] => {
        "msg": {
            "app": {
                "environment": {
                    "RAILS_ENV": "staging",
                    "bar": "foo",
                    "do_not_override_me": "from root group_vars",
                    "overridable_var": "staging from inventories group_vars"
                }
            },
            "db": {
                "engine": "postgres"
            }
        }
    }
    
    PLAY RECAP *********************************************************************************************************
    app                        : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0 
    
    登台运行它将提供重述:

    $ ansible-playbook play.yml -i inventories/develop
    
    PLAY [all] *********************************************************************************************************
    
    TASK [set_fact] ****************************************************************************************************
    ok: [app]
    
    TASK [debug] *******************************************************************************************************
    ok: [app] => {
        "msg": {
            "app": {
                "environment": {
                    "RAILS_ENV": "development",
                    "bar": "foo",
                    "do_not_override_me": "from root group_vars",
                    "overridable_var": "develop from inventories group_vars"
                }
            },
            "db": {
                "engine": "postgres"
            }
        }
    }
    
    PLAY RECAP *********************************************************************************************************
    app                        : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0 
    
    $ ansible-playbook play.yml -i inventories/staging
    
    PLAY [all] *********************************************************************************************************
    
    TASK [set_fact] ****************************************************************************************************
    ok: [app]
    
    TASK [debug] *******************************************************************************************************
    ok: [app] => {
        "msg": {
            "app": {
                "environment": {
                    "RAILS_ENV": "staging",
                    "bar": "foo",
                    "do_not_override_me": "from root group_vars",
                    "overridable_var": "staging from inventories group_vars"
                }
            },
            "db": {
                "engine": "postgres"
            }
        }
    }
    
    PLAY RECAP *********************************************************************************************************
    app                        : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0 
    

    另一个注意事项:请注意,这不允许playbook同时在两个环境中运行,正如使用文档的多个库存源一节下的注意事项所指出的:

    请记住,如果库存中存在可变冲突,则根据和中描述的规则解决冲突。合并顺序由库存源参数的顺序控制。如果暂存库存中的
    [all:vars]
    定义了
    myvar=1
    ,但生产库存定义了
    myvar=2
    ,则将使用
    myvar=2
    运行剧本。如果使用
    -i production-i staging
    运行playbook,则结果将相反


    来源:

    您是否可以选择使用主机变量?
    ?您可能正在寻找Ansible的和文档。因此,Ansible主张使用,以实现您所寻找的。稍后将添加一个示例。您在
    服务
    中有一个列表而不是dict有什么具体原因吗?即。另外,在
    环境
    之后,您的问题中是否存在缩进问题?i、 e.@souser我认为
    主机变量
    在优先级方面落后于
    组变量
    ,因此它无论如何都会被覆盖@β.εηοιτ.βε有问题的固定缩进不幸的是,我无法将
    服务
    更改为dict,因为许多其他剧本都提到了这一点。但是我认为你的回答看起来是实现我想要做的事情的最好方式。如果有一天我有机会修改所有的代码库,我可能会试试这个。谢谢