Ansible 中的全局修改 $PATH 无法在常规 Linux shell 中按预期工作

Posted

技术标签:

【中文标题】Ansible 中的全局修改 $PATH 无法在常规 Linux shell 中按预期工作【英文标题】:Global modified $PATH in Ansible not working as expected from regular Linux shell 【发布时间】:2019-08-07 12:42:31 【问题描述】:

我想下载一些像Helm 这样的二进制文件,并使用$PATH 使它们在全球范围内可用。为了避免使用 root 权限下载或者必须执行步骤(使用标准用户下载并移动到 $PATH 中的某个 bin 文件夹,例如 /usr/local/bin),我的想法是创建 $HOME/bin 并将其添加到 $PATH

This blog article 用于向/etc/environment 添加自定义路径。然后我将其重新加载为described here。这是我的 POC 手册,我尝试在其中添加 exa:

- name: Test
  hosts: all

  vars:
    - bin: /home/vagrant/bin

  tasks:
  - name: Test task
    file:
      path: "bin"
      state: directory

  - name: Add bin to path
    become: yes
    lineinfile: >
        dest=/etc/environment
        state=present
        backrefs=yes
        regexp='PATH=(["]*)((?!.*?bin).*?)(["]*)$'
        line="PATH=\1\2:bin\3"

  - name: Check path1
    shell: echo $PATH

  - name: Download exa
    unarchive:
      src: https://github.com/ogham/exa/releases/download/v0.8.0/exa-linux-x86_64-0.8.0.zip
      dest: "bin"
      remote_src: yes

  - name: reload env file
    shell: for env in $( cat /etc/environment ); do export $(echo $env | sed -e 's/"//g'); done

  - name: Check path after reload env file
    shell: echo $PATH

  - name: Test exa from PATH
    shell: exa-linux-x86_64 --version

在最后一个 tash Test exa from PATH 它抛出错误:

"stderr": "/bin/sh: 1: exa-linux-x86_64: not found"

echo $PATH 命令都保留在

"stdout": "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games"

但修改后的/etc/environment 有效。当我在没有 ansible 的情况下在机器上使用 ssh 时,$PATH 很好,exa-linux-x86_64 --version 也可以:

~$ echo $PATH
/home/vagrant/bin:/home/vagrant/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/home/vagrant/bin:/snap/bin

环境

运行 Vagrant 的 Ubuntu 18.04 主机系统和 Ubuntu 16.04 机器。 Ansible 由 Vagrant 在 Ubuntu 16.04 上执行。

可能的解决方法

使用单独的环境变量

这样设置环境变量时

  - name: Test exa from PATH
    shell: exa-linux-x86_64 --version
    environment:
      PATH: " ansible_env.PATH :bin"

它有效。但我必须至少在游戏层面应用这些线。我想像 /etc/environment 在常规 shell 中那样全局设置它。 This questions 似乎有相同的目标,但在 Solaris 上。 answear 似乎只从主机设置$PATH,这对我没有用,因为自定义 bin 目录不存在。

只使用绝对路径

  - name: Test exa from PATH
    shell: "bin/exa-linux-x86_64 --version"

这会减少开销,但您必须记住始终使用路径变量作为命令的前缀。似乎也容易出错

了解问题

我想要一个真正的解决方案,并了解导致问题的原因。我不清楚为什么 $PATH 修改在 Ansible 上如此困难,在底层 linux 系统中可以很容易地完成。 This question 说我们在 ansible 中没有交互式会话。似乎没有可用的$PATH。根据the documentation,我们可以通过将-l 传递给bash 来归档它。所以我发现以下工作:

  - name: Test exa from PATH
    shell: bash -l -c "exa-linux-x86_64 --version"

但以下导致错误:

  - name: Test exa from PATH
    shell: exa-linux-x86_64 --version
    args:
      executable: /bin/bash -l

这里 Ansible 通过错误引用 args 来中断命令:

"'/bin/bash -l' -c 'exa-linux-x86_64 --version'"

This ticket 建议 Ansible 团队修复此问题,以便我们获得带有 $PATH 的登录 shell。自 2014 年以来,根本没有提供真正的解决方案。

问题

    访问修改后的$PATH 的不同shell 类型的目的是什么? 为什么 Ansible 会使事情复杂化?提供一个解决这个问题的登录shell不是更容易吗?他们这样做有什么原因吗? 我们如何处理由此产生的问题?什么是最佳实践?

【问题讨论】:

@jww:这是一个编程和开发问题。我认为这是“软件开发独有的实用、可回答的问题”。 Ansible 是否是开发的一部分是有争议的。管理员和开发人员越来越融合。尤其是在这个问题被要求构建一个本身应该作为开发平台的 Kubernetes 集群的情况下。但我认为这不能证明我得到的反对票是合理的,因为这个问题本身就是一个有效的问题——如果他在 SO 或被转移到 DevOps 等其他平台(可以转移),则独立。 @VladimirBotka 我会更进一步:编写 Ansible 配置软件开发,只是不使用通用编程语言。 【参考方案1】:

回答你的问题

1) 访问修改后的 $PATH 的不同 shell 类型的目的是什么?

在 Ansible 支持的所有操作系统中统一它是不值得的。这也解释了“我不清楚为什么在 Ansible 上修改 $PATH 如此困难,而在底层 linux 系统中可以很容易地完成。”

2) 为什么 Ansible 会使事情复杂化?提供一个解决这个问题的登录shell不是更容易吗?他们这样做有什么理由吗?

相反,不关心它更容易。保持简单愚蠢是原因。

3) 我们如何处理由此产生的问题?最佳做法是什么?

几十年来的最佳实践是Tools, no policy

【讨论】:

以上是关于Ansible 中的全局修改 $PATH 无法在常规 Linux shell 中按预期工作的主要内容,如果未能解决你的问题,请参考以下文章

ansible 的file 模块

无法从 Ansible 变量中搜索子字符串

Delphi 中全局变量无法被修改

流程控制优化

Ansible 中的 Powershell 脚本

windows环境下无法引用全局安装的模块问题