Ansible Playbook获取locale结果随控制端主机不同发生变化问题
成因分析
该现象是SSH默认的环境变量转发机制导致的,和Ansible无关:
- 控制端的SSH客户端默认开启了
SendEnv配置,会自动将本地的LANG、LC_*等locale相关环境变量传递到远程SSH会话 - 目标主机的sshd服务默认开启了
AcceptEnv配置,允许接收客户端传递的上述locale变量 - 你通过Ansible或者直接执行
ssh 目标主机 命令时,远程端默认启动的是非登录、非交互shell,不会加载/etc/profile、~/.bash_profile等系统级/用户级的登录配置,所以不会读取目标主机自身配置的默认locale,而是优先使用SSH会话传递过来的控制端locale变量,所以最终输出和控制端本地的LANG值完全一致。
解决方案
你可以根据使用场景选择以下任意一种方案获取目标主机本身的locale配置:
- 方案1:显式以登录shell执行命令,让远程主机加载自身的全局环境配置。把你原来的command模块改为如下写法即可:
- name: get locale info command: bash -lc "printenv LANG" register: my_loc
bash的-l参数会启动登录shell,会依次加载/etc/profile、/etc/profile.d/*.sh、~/.bash_profile等配置,会重置为目标主机自身配置的locale,不受SSH传递的变量影响。
- 方案2:直接读取目标主机的locale配置文件,跳过环境变量的干扰。对于CentOS/RHEL 7及以上版本,系统全局locale配置存放在
/etc/locale.conf,直接读取该文件即可:
- name: 读取系统全局locale配置 slurp: src: /etc/locale.conf register: locale_conf - name: 解析LANG配置 set_fact: target_lang: "{{ locale_conf.content | b64decode | regex_search('LANG=(.+)', '\\1') | first | replace('\"', '') }}"
- 方案3:直接使用Ansible内置的facts变量。你在
gather_facts阶段已经收集了目标主机的locale信息,直接调用{{ ansible_lang }}变量即可,这个值是Ansible从目标主机系统配置中读取的,完全不受SSH环境变量转发的影响,不需要额外编写task获取。 - 方案4(不推荐,会影响所有SSH会话):修改SSH配置禁止locale转发。如果想要全局关闭这个特性,可以在控制端的
/etc/ssh/ssh_config里注释掉SendEnv LANG LC_*这一行,或者在目标主机的/etc/ssh/sshd_config里注释掉AcceptEnv LANG LC_*这一行,重启sshd服务后生效。
内容的提问来源于stack exchange,提问作者grafra
相关产品推荐
相关产品推荐

