Windows 作为 Ansible 节点的完整部署流程(含 Docker 部署 Ansible)

前言

在日常运维中,Windows 主机上往往存在大量的 bat、ps1 脚本,每台机器跑的脚本还不一样,有些甚至需要多台机器联动。手动维护既麻烦,又容易出错。

我的场景里,Windows 系统非常关键,不允许开发人员或普通用户随意访问,因此需要一个安全、统一的方式来管理这些脚本。

最开始考虑的方案是 JenkinsAnsible

  • Jenkins 的优势在于能直观看到节点是否在线,但权限粒度不足:用户可以新建任意任务并选择指定节点执行,风险太大(比如误操作删除文件)。 目前开发同事工作需要登录 Jenkins 并创建 Job。
  • Ansible 没有内置的节点在线监控,且 Windows 作为节点无需额外安装 agent 和开启 SSH 服务器 ,只要启用系统自带的 WinRM 功能即可。 Ansible 目前完全由 IT 管理,不用担心权限泄露问题

综合考虑后,还是选择了 Ansible 来统一管理 Windows 脚本。下面记录下从原理到完整落地的全过程。


一、工作原理

Windows 作为 Ansible 节点的核心机制,可以用一句话概括:

控制端发送 PowerShell/命令 → Windows 执行 → 返回 JSON 结果 → 控制端解析

具体分为几个部分:

  1. 三要素

    • 控制节点(Linux 上的 Ansible)
    • 被管理节点(Windows,不需要安装 Ansible)
    • 通信协议(WinRM,默认端口 5985/5986)
  2. 连接与认证

    • 控制端通过 pywinrm 库和 Windows WinRM 服务通信
    • 常见认证:basic、NTLM、Kerberos
    • 内网环境可以用 basic+HTTP,生产推荐 Kerberos/HTTPS
  3. 模块执行流程

    • 控制端选择目标主机
    • 建立 WinRM 会话
    • 传输 PowerShell 模块/命令到 Windows
    • Windows 执行并产出 JSON 结果
    • 结果返回控制端解析
  4. 文件与脚本管理

    • win_copy:复制文件
    • win_command / win_shell:执行 bat/命令
    • win_powershell:执行 PowerShell 脚本
  5. 幂等性

    • 尽量使用模块(如 win_featurewin_package),而不是裸命令
    • 自写脚本需处理"检查-执行"逻辑
  6. 权限

    • 通常用管理员账号或 become_method: runas
  7. 离线环境

    • Windows 开启 WinRM 不需要联网
    • 控制端 Linux 如需安装 pywinrm,可提前下载 wheel 包离线安装

二、Ansible 版本要求

  • 2.8 及以上版本原生支持 Windows 节点

  • 推荐使用最新稳定版,兼容性更好

  • 查看版本:

    bash 复制代码
    ansible --version
  • 检查支持的模块:

    bash 复制代码
    ansible-doc -l | grep win

如果版本过旧,可以通过 pip install --upgrade ansible 升级(离线环境提前下载好包)。


三、环境部署

这里给一个完整的部署流程。

Ansible 部署(Docker)

  • 1、Ansible 官方 镜像不更新了
  • 2、用 Python 镜像部署 Ansible 更加轻量级,更方便自定义

所以下面使用 Python 镜像进行 Ansible 部署。

Ansible 容器镜像

bash 复制代码
docker pull python:3.9.23-trixie

拉取 python:3.9.23-trixie 容器镜像

编写 Dockerfile 并构建镜像

bash 复制代码
vim Dockerfile

FROM python:3.9.23-trixie
ARG http_proxy="http://IP:PORT"
ARG https_proxy="http://IP:PORT"  # 代理,用不上可以不加
RUN apt update && apt install -y sshpass git
RUN pip install ansible pywinrm

docker build -t python:3.9.23-trixie-ansible .

测试

bash 复制代码
docker run --rm python:3.9.23-trixie /bin/bash -c "ansible --version && ansible-doc -l | grep win"

显示 Ansible 版本号和 win 支持模块即容器镜像完成构建。

启动 Ansible

bash 复制代码
docker run -it --name ansible -v /root/ansible/ansible:/etc/ansible python:3.9.23-trixie /bin/bash

把本地 /root/ansible/ansible 目录映射到容器的 /etc/ansible 目录

不用 -p 映射端口出来,Ansible 能访问 Win 节点端口就行,Win 节点不用访问 Ansible。

三、Windows 节点配置

为方便测试,后续连接 Wiundows 均使用以下账号密码:

  • 账号:lian
  • 密码:lian

且 Windows 的 IP 为 192.168.62.148

开启 WinRM

但官方不建议使用这个脚本(安全问题),建议最好自己敲 PowerShell 命令去开启服务,如果非要用的话建议删除并只保留自己需要的命令。

感兴趣的可以试一下上面 ps1 脚本,开启 WinRM 总共就两条命令,这里我就手敲执行好了。

管理员 PowerShell 执行:

powershell 复制代码
# 启用 WinRM(管理员)
winrm quickconfig -q

# 允许 Basic 认证 & 明文传输(建议仅限内网/测试用)
winrm set winrm/config/service/auth '@{Basic="true"}'
winrm set winrm/config/service '@{AllowUnencrypted="true"}'
# 执行这一句的时候会要求网络类型改为'域'或'专用'(默认'公共')
# 在'网络设置'→'以太网'→'网络'→点击勾选'专用',再执行命令即可生效

# 放行防火墙
New-NetFirewallRule -Name "WinRM" -DisplayName "WinRM" -Protocol TCP -LocalPort 5985 -Action Allow

# 授权用户可通过 WinRM 远程执行命令(Remote Management Users 是 Windows 用户组)
net localgroup "Remote Management Users" ansible /add

# 检查监听器
winrm e winrm/config/listener

四、配置 Ansible Inventory

在 Ansible 的 /etc/ansible/hosts 内写入:

ini 复制代码
[windows]
192.168.62.148

[windows:vars]
ansible_user=lian
ansible_password=lian
ansible_connection=winrm
ansible_winrm_transport=basic
ansible_port=5985

⚠ 注意:如果用 Docker 容器跑的 Ansible,192.168.62.148 必须能从宿主机/容器访问。


五、测试连通性

在 Ansible 容器里执行:

bash 复制代码
ansible windows -m win_ping

成功输出:

json 复制代码
win01 | SUCCESS => {
    "changed": false,
    "ping": "pong"
}

六、执行脚本示例

把 Windows 上的脚本都放到 Ansible 控制端 ,然后在执行时传输到 Windows 节点再运行,这样 更好管理 脚本。

先准备个测试用的 BAT 批处理脚本(test.bat):

bat 复制代码
@echo off
chcp 65001 >nul

echo ================================
echo 当前路径信息
echo ================================
echo 当前路径是:%cd%
echo.
echo 当前目录下的文件和文件夹:
dir
echo.

echo ================================
echo 当前时间和时区信息
echo ================================
echo 当前日期和时间:%date% %time%
echo.
echo 当前时区:
where tzutil >nul 2>&1 && tzutil /g
echo.

pause

PowerShell 脚本(test.ps1):

powershell 复制代码
# 获取当前时间
$time = Get-Date -Format "yyyy-MM-dd HH:mm:ss"

# 获取计算机名
$computer = $env:COMPUTERNAME

# 获取当前用户名
$user = $env:USERNAME

# 输出结果
Write-Output "当前时间: $time"
Write-Output "计算机名: $computer"
Write-Output "当前用户名: $user"

这两个脚本都放到 Ansible/etc/ansible/file 目录下。

在 Ansible 上调用 Windows bat 脚本,有三种解决方法:

方法 1:win_copy + 执行

先把脚本从控制节点复制到 Windows,再执行。

bash 复制代码
vim test1.yml
yaml 复制代码
- name: Run scripts on Windows
  hosts: windows
  tasks:
    - name: Copy bat file to Windows
      ansible.windows.win_copy:
        src: /etc/ansible/file/test.bat
        dest: C:\Users\lian\Desktop\script\test.bat

    - name: Run bat file
      ansible.windows.win_command: C:\Users\lian\Desktop\script\test.bat

    - name: Copy ps1 script to Windows
      ansible.windows.win_copy:
        src: /etc/ansible/file/test.ps1
        dest: C:\Users\lian\Desktop\script\test.ps1

    - name: Run ps1 file
      ansible.windows.win_powershell:
        script: |
          & "C:\Users\lian\Desktop\script\test.ps1"
bash 复制代码
ansible-playbook test1.yml

这样 Windows 脚本统一放在 Ansible 项目里(比如 /etc/ansible/file/ 目录),方便版本管理。

如果要打印脚本输出的,playbook 脚本改为如下:

yaml 复制代码
- name: Run scripts on Windows
  hosts: windows
  tasks:
    - name: Copy bat file to Windows
      ansible.windows.win_copy:
        src: /etc/ansible/file/test.bat
        dest: C:\Users\lian\Desktop\script\test.bat

    - name: Run bat file and show output
      ansible.windows.win_command: C:\Users\lian\Desktop\script\test.bat
      register: bat_result

    - name: Display bat output
      debug:
        var: bat_result.stdout_lines

    - name: Copy ps1 script to Windows
      ansible.windows.win_copy:
        src: /etc/ansible/file/test.ps1
        dest: C:\Users\lian\Desktop\script\test.ps1

    - name: Run ps1 file and show output
      ansible.windows.win_shell: powershell.exe -ExecutionPolicy Bypass -File C:\Users\lian\Desktop\script\test.ps1
      register: ps1_result

    - name: Display ps1 output
      debug:
        var: ps1_result.stdout_lines

另外会发现,Windows 执行这些脚本只有返回到 Ansilble 只有执行和打印输出信息如果脚本本身就有问题,Ansible 执行过程是不会中断、也不会有脚本以外的报错等信息

这样可以结合输出,追加脚本打印输出,跟据 Windows 执行脚本时返回的信息,判断输出结果符不符合预期(如:Success),符合的话就是正确执行。

方法 2:直接传脚本内容(小脚本用)

如果脚本不大,可以直接嵌到 Playbook,用 win_powershell / win_shellinline script 方式:

yaml 复制代码
- name: Run scripts on Windows (inline)
  hosts: windows
  tasks:
    - name: Run bat inline
      ansible.windows.win_shell: |
        if not exist "C:\Users\lian\Desktop\script\test2.bat" echo. > "C:\Users\lian\Desktop\script\test2.bat"
        echo echo Hello from BAT > "C:\Users\lian\Desktop\script\test2.bat"
        "C:\Users\lian\Desktop\script\test2.bat"

    - name: Run ps1 inline
      ansible.windows.win_powershell:
        script: |
          Write-Output "Hello from PowerShell"

缺点:脚本内容写在 YAML 里,不好维护,适合临时命令。

方法 3:Ansible roles + 模板化(更适合大规模)

方法 1 差不多。

把 bat/ps1 脚本放到 /etc/ansible/file/目录下,用 win_copy 统一分发并执行,方便团队协作和版本控制。

bash 复制代码
vim test3.yml
yaml 复制代码
- name: Copy and run BAT
  hosts: windows
  tasks:
    - block:
        - name: Copy BAT file
          win_copy:
            src: /etc/ansible/file/test.bat
            dest: C:\Users\lian\Desktop\script\test.bat

        - name: Run BAT file
          win_command: C:\Users\lian\Desktop\script\test.bat
      tags:
        - bat

- name: Copy and run PS1
  hosts: windows
  tasks:
    - block:
        - name: Copy PS1 file
          win_copy:
            src: /etc/ansible/file/test.ps1
            dest: C:\Users\lian\Desktop\script\test.ps1

        - name: Run PS1 file
          win_powershell:
            script: C:\Users\lian\Desktop\script\test.ps1
      tags:
        - ps1

执行:

bash 复制代码
ansible-playbook -i windows test3.yml -t bat

注意事项

测试过程中,发现 Windows LTSC 版阉 割太多,好多事情都做不了,一个简单的 CMD、简单的 bat 脚本,都会把变量里的内容打印并识别成执行语句。

Ansible 里的 win_xx 等命令就更不用说了,Windows LTSC 上很多依赖调用不了,执行会报错。

当然,用 Windows Home 版 作为 Ansbile 节点也不行,因为它无法开启 WinRM 服务。

所以实际上,只能用 Server 版专业/企业版 作为 Ansible 节点。

好在我实际使用场景都是 Window Server 版,所以不用担心功能严格问题。


总结

  1. Ansible 控制端 (Docker 内)通过 Python 的 pywinrm 库发送 WinRM 请求。
  2. Windows 节点 WinRM 服务接收请求 → 验证用户身份 → 调用 PowerShell 引擎执行命令。
  3. 返回结果 通过 WinRM 协议传回 Ansible。
  4. Ansible 汇总输出,显示在控制端。

虽说 Windows 的 bat/ps1 脚本也可以存放到 Windows 节点上,但不好管理。

Windows 的脚本都放到 Ansible 上,并且 Playbook 也在 Ansible 上,再加上 Git 仓库,这样便于对整套 Playbook 和 Windows 脚本进行版本管理。可实现,一个平台(Ansible)上就可以完成脚本编写 + 下发了。

相关推荐
東雪蓮☆2 小时前
Ansible Playbook 编写与模块详解
linux·运维·网络·ansible
Lin_Aries_04213 小时前
部署 Jenkins 服务器
运维·服务器·docker·容器·云计算·jenkins
AganTee3 小时前
Win11共享打印0x0000bc4,三步解决共享难题
windows·打印机·win11共享打印0x0000bc4
huangdengji4 小时前
【docker默认防火墙行为调整】
docker·容器
ftswsfb4 小时前
Docker进阶-管理和应用
运维·docker·容器
gs801404 小时前
在 openEuler 上排查 Docker 同桥网络不通:从“全线超时”到定位容器没启动
网络·docker·容器
jqh_04844 小时前
docker jenkins gitlab 流水线构建
docker·gitlab·jenkins
Kaede65 小时前
Docker和K8S的区别详解
docker·容器·kubernetes
伞啊伞6 小时前
开源的容器化平台:Docker
docker·容器·开源