Ansible执行带管道的curl添加Docker GPG密钥时gpg卡住
问题原因
卡住的核心原因是gpg默认运行在交互模式,会尝试读取伪终端(TTY)输入等待用户操作反馈。Ansible执行shell模块任务时,默认不会给远程会话分配TTY,此时gpg进程因为拿不到可用的TTY输入源,会永久阻塞等待,对外表现为任务无响应卡住。
少部分特殊场景下的卡顿和系统熵池不足有关:gpg执行加解密、格式转换操作时需要调用系统随机数生成器,如果服务器熵池数值过低,进程会等待收集到足够的随机数后才会继续运行,也会表现为卡顿。
另外如果目标机不存在/etc/apt/keyrings目录,部分旧版本gpg不会直接抛出路径不存在的错误,也会进入异常阻塞状态。
修复方案
优先选择以下第一种调整方式,改动最小:
- 给
gpg命令添加--batch --yes参数,强制其运行在非交互模式,全程不等待任何用户输入;同时提前创建密钥存放目录,增加幂等判断避免重复执行。调整后的playbook配置如下:
--- - hosts: all become: yes tasks: - name: 确保apt密钥环存放目录存在 file: path: /etc/apt/keyrings state: directory mode: '0755' - name: 添加Docker GPG密钥 shell: "curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --batch --yes --dearmor -o /etc/apt/keyrings/docker.gpg" args: creates: /etc/apt/keyrings/docker.gpg
- 如果调整后仍存在卡顿(多为熵池不足导致),可以先在目标机安装熵服务补全随机数源,再执行上述任务:
- name: 安装haveged补充系统熵池(解决gpg随机数等待阻塞问题) apt: name: haveged state: present update_cache: yes
- 更符合Ansible最佳实践的写法是拆分管道命令,用原生模块替代shell拼接,从根源避免管道、交互环境导致的异常:
--- - hosts: all become: yes tasks: - name: 确保apt密钥环存放目录存在 file: path: /etc/apt/keyrings state: directory mode: '0755' - name: 下载Docker原始GPG公钥到临时目录 get_url: url: https://download.docker.com/linux/ubuntu/gpg dest: /tmp/docker_origin.gpg mode: '0644' - name: 转换公钥为apt兼容的二进制gpg格式 command: gpg --batch --yes --dearmor -o /etc/apt/keyrings/docker.gpg /tmp/docker_origin.gpg args: creates: /etc/apt/keyrings/docker.gpg - name: 清理临时公钥文件 file: path: /tmp/docker_origin.gpg state: absent
注意:不要通过给Ansible的shell任务加
pty: true参数强制分配TTY来规避问题,这种方式会导致sudo权限校验异常、命令输出截断等其他不稳定问题。
内容的提问来源于stack exchange,提问作者Vamp thehacker
相关产品推荐
相关产品推荐

