Ansible - 从 .env 文件中读取环境变量

16

我正在尝试设置一个playbook,其中包含运行命令以检查目标机器上安装的服务状态的步骤。该命令只有在执行了.env文件时才能生效。执行.env文件的命令是.<space>./.env_file_name,文件中包含环境变量列表,例如 export JAVA_HOME=/optware/java/jdk/1.2.

我尝试在运行命令之前使用以下playbook执行环境文件,但它没有起作用。

- hosts: name
  tasks: 
    - name: `execute env file`
      command: . ./.env_file_name
      register: result

有没有运行可执行环境文件并设置目标机器上存在的环境,然后运行我们命令的指南?


通常情况下,使用source关键字在shell中引用.env或任何其他文件。尝试这样做:command: source <path> - error404
1
你是否期望在其他任务中使用环境变量?因为这种方式是不可能的。如果你想在同一个任务中使用它们,那么你应该使用shell模块。否则,要在任务执行中使用环境变量,你需要使用environment关键字 - zigarn
@Zigarn,我需要在其他任务中使用环境变量。你有运行.env文件并在其他任务中使用环境变量的playbook示例吗? - Newbee2
注意,“。”和“source”命令基本上是相同的东西:https://dev59.com/e2Ij5IYBdhLWcg3wmWG1#20097303 - blong
相关链接:https://dev59.com/A5_ha4cB1Zd3GeqPui1T#42255589 - blong
2个回答

16

首先,. ./.env_file_name 语法是shell语法,不能与 command 模块 一起使用,需要使用shell 模块

其次,shell环境上下文在每个任务中都会被重置,因为每个任务都是一个ssh命令往返(即一个新的shell会话),在一个任务中加载环境变量不会使它们对下一个任务可用。

根据您的情况,您有几个选项:

1.清单环境变量

最佳选项是将环境设置为清单侧的变量,通过不同的值为每个组/主机分组在group_vars/host_vars中使用,然后将其用于 environment 关键字

# host_vars/my_host.yml
---
env_vars:
  VAR1: key1
  VAR2: key2

- hosts: my_host
  tasks: 
    - name: Display environment variables
      command: env
      environment: "{{ env_vars }}"

优点:

  • 提供了全套的Ansible解决方案
  • 适用于每个模块的环境

缺点:

  • 需要在Ansible端了解环境变量

2.为每个任务加载环境变量

如果您所有的任务都是shell/command(虽然我不建议这样做,因为最好在可能时使用适当的ansible模块),您可以使用shell模块每次加载env文件。

- hosts: my_host
  tasks: 
    - name: Display environment variables
      shell: |
        . ./.env_file_name && env

    - name: Do another action
      shell: |
        . ./.env_file_name && do_something_else

优点:

  • ansible端不需要知道环境变量

缺点:

  • 只适用于使用shell模块的任务

3. 从env_file加载环境变量到ansible事实中

此选项是为了一次性解析env文件并将其加载到ansible事实中,以便与environment关键字一起使用。

- hosts: my_host
  tasks: 
    - name: Get env file content
      slurp:
        src: ./.env_file_name
      register: env_file_content

    - name: Parse environment
      set_fact:
        env_vars: "{{ ('{' + (env_file_content.content | b64decode).split('\n') | select | map('regex_replace', '([^=]*)=(.*)', '\"\\1\": \"\\2\"') | join(',') + '}') | from_json }}"

    - name: Display environment variables
      command: env
      environment: "{{ env_vars }}"

或者,如果需要执行env文件而不是直接解析:

- hosts: my_host
  tasks: 
    - name: Get env file content
      shell: . ./.env_file_name && env
      register: env_file_result

    - name: Parse environment
      set_fact:
        env_vars: "{{ ('{' + env_file_result.stdout_lines | map('regex_replace', '([^=]*)=(.*)', '\"\\1\": \"\\2\"') | join(',') + '}') | from_json }}"

    - name: Display environment variables
      command: env
      environment: "{{ env_vars }}"

优点:

  • 适用于每个模块的环境
  • 无需在Ansible端了解环境变量

缺点:

  • 文件格式错误可能会导致失败

谢谢!虽然我认为最大的问题是正则表达式,因为它不支持在值周围加引号,也不支持注释(#)。 - Jimbo
没错!可以通过在 | map('regex_replace' 前添加 | map('regex_replace', '#.*', '') | map('trim') | reject() 来删除注释并将正则表达式更改为 '([^=]*)=['"]?(.*)['"]?' 以处理简单的带引号值的情况。 - zigarn
所以我按照您的指示使用了:{{ ('{' + (env_file_content.content | b64decode).split('\n') | select | map('regex_replace', '#.*', '') | map('trim') | reject() | map('regex_replace', '([^=]*)=['\"]?(.*)['\"]?', '\"\\1\": \"\\2\"') | join(',') + '}') | from_json }},但不幸的是这没有起作用。虽然我觉得这可能会变成一个单独的问题,但您知道我缺少什么吗? - Jimbo
我想我错了(没有测试):使用select而不是reject - zigarn
我无法让它正常工作,但找到了一个可以在.env文件中使用注释和换行符的答案:https://dev59.com/A5_ha4cB1Zd3GeqPui1T#42255589 - Jimbo
对我有效的是 env_vars: "{{ (env_file_content.content | b64decode).split('\n') | map('regex_replace', '^#.*', '') | select | map('regex_replace', '([^=]*)=(.*)', '\\1: \\2') | join('\n') | from_yaml }}" - 这将从 env 文件中删除注释行,现在可以使用设置事实变量 (env_vars) 来获取 env 键,例如 env_vars["Key1"] .. - Akshay Chandran

1
如果您正在使用Makefile来运行ansible playbooks, 并且您只在本地主机上运行playbook(而不是在远程主机上), 您可以使用以下命令: cat Makefile:
include .env_file_name
export

run-myplaybook:
    ansible-playbook myplaybook.yml -i hosts.yml

然后运行它:
make run-myplaybook

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接