1. 概述

在管理 Docker 容器时,我们通常会手动执行一系列 CLI 命令。当只有一两个容器时,这种方式或许可行,但当我们面对多个服务、环境或配置时,这种手动操作容易出错且效率低下。这时我们可以借助 Ansible,它是一个自动化工具,通过名为 playbook 的 YAML 文件在多台系统上执行任务。

更方便的是,Ansible 可以与 Docker 等工具集成,使我们能够轻松实现 Docker 命令的自动化执行、容器部署,甚至是编排。

在本教程中,我们将通过一个实际且易懂的示例,学习如何使用 Ansible 来运行 Docker 命令。文中将以 Ubuntu Linux 系统为例,演示如何结合 Docker Engine 和 Ansible 使用。


2. 为什么要使用 Ansible 来运行 Docker 命令?

以下是几个使用 Ansible 来运行 Docker 或 Docker Compose 命令的常见原因:

  • 作为 CI/CD 流水线的一部分自动部署容器
  • 避免重复执行相同的命令行操作
  • 通过自动化简化开发流程
  • 统一配置本地或测试环境

使用 Ansible,我们可以对 Docker 的工作流进行版本控制,并轻松复用。


3. 问题描述

我们的问题是:使用 Ansible 来运行 Docker Compose 命令。例如:

$ docker-compose -f docker-compose.yml -f docker-compose.prod.yml up -d

在开始之前,需要确保 Ansible 已安装。

⚠️ 虽然 Ubuntu 的 apt 包管理器提供了 Ansible,但该版本常常存在插件依赖问题(如 Jinja2 相关警告)。为了避免这些问题并确保更好的兼容性,建议使用 pip 安装 Ansible

$ sudo apt update && sudo apt install python3-pip -y && pip install --user ansible jinja2

上面的命令将 Ansible 安装到用户本地目录(~/.local/bin/),避免系统级冲突和插件错误,从而确保在不同 Ubuntu 系统上的安装一致性。

安装完成后,可通过以下命令验证:

$ ansible --version
ansible [core 2.17.13]
...

输出 Ansible 版本即表示安装成功。

此外,我们选择使用 Docker Engine 而不是 Docker Desktop,因为前者更适合与 Ansible 在 Linux 上配合使用,提供更一致的部署流程。


4. 项目搭建

我们将创建一个项目,使用 Docker Compose 启动一个简单的 Nginx Web 服务器,并通过 Ansible 自动化启动服务。

首先创建工作目录并进入:

$ mkdir ansible-docker-demo && cd ansible-docker-demo

接下来完成项目的其余部分。

4.1. 创建一个简单的 Web 应用

创建一个基础的 HTML 文件:

$ mkdir app && touch app/index.html

打开 app/index.html 并写入以下内容:

<!DOCTYPE html>
<html>
  <head>
    <title>Hello from Ansible</title>
  </head>
  <body>
    <h1>Hello from Docker + Ansible!</h1>
  </body>
</html>

Nginx 默认会从 /usr/share/nginx/html 目录中加载网页文件。我们将在后续通过 Docker volume 将本地 app 目录挂载到容器中的这个路径。


4.2. 创建 Docker Compose 文件

创建 docker-compose.yml 文件:

version: '3'

services:
  web:
    image: nginx:alpine
    ports:
      - "8080:80"
    volumes:
      - ./app:/usr/share/nginx/html:ro

该文件定义了一个基于 nginx:alpine 镜像的服务,映射 8080 端口,并挂载本地的 app 目录作为静态资源目录。

接着创建 docker-compose.prod.yml 文件:

version: '3'

services:
  web:
    environment:
      - ENV=production

该文件为服务添加了一个环境变量,虽然示例简单,但它展示了如何通过 override 文件为不同环境(如 dev、staging、prod)定制部署配置。


4.3. 创建 Ansible Inventory 文件

Ansible 通过 inventory 文件来指定需要管理的主机。我们这里只在本地运行,因此创建 inventory.ini 文件:

[local]
localhost ansible_connection=local ansible_python_interpreter=/usr/bin/python3

说明:

  • ansible_connection=local:告诉 Ansible 在本地执行命令,而不是通过 SSH
  • ansible_python_interpreter:指定使用的 Python 解释器,避免警告

如果要在多台服务器上部署,可以扩展为:

[webservers]
192.168.10.10 ansible_user=ubuntu
192.168.10.11 ansible_user=ubuntu

这样就可以复用同一个 playbook 用于本地测试和生产部署。


4.4. 编写 Ansible Playbook

创建 playbook.yml 文件:

- name: Run Docker Compose with Ansible
  hosts: local
  become: yes
  tasks:

    - name: Ensure Docker is installed
      package:
        name: docker.io
        state: present

    - name: Ensure Docker Compose is installed
      package:
        name: docker-compose
        state: present

    - name: Ensure Docker service is running
      service:
        name: docker
        state: started
        enabled: true

    - name: Pull Docker images
      command: docker-compose -f docker-compose.yml -f docker-compose.prod.yml pull
      args:
        chdir: "{{ playbook_dir }}"

    - name: Run Docker Compose
      command: docker-compose -f docker-compose.yml -f docker-compose.prod.yml up -d
      args:
        chdir: "{{ playbook_dir }}"

Playbook 说明如下:

  • name:用于标识每个任务的作用
  • hosts: local:指定在 inventory.ini 中定义的 local 主机组执行
  • become: yes:以 sudo 权限执行任务(安装包、操作 Docker 服务)
  • tasks:按顺序执行的操作列表

各任务参数说明:

  • package:确保安装 Docker 和 Docker Compose
  • state: present:表示安装状态
  • service:确保 Docker 服务运行并开机自启
  • command:执行 Docker Compose 命令
  • chdir:指定命令执行目录为 playbook 所在目录
  • {{ playbook_dir }}:Ansible 内置变量,表示 playbook 文件所在路径

该 playbook 会安装 Docker 和 Docker Compose(如未安装),然后运行 compose 命令启动服务。


4.5. 运行 Playbook

一切准备就绪后,运行 playbook:

$ ansible-playbook -i inventory.ini playbook.yml --ask-become-pass
BECOME password: 

PLAY [Run Docker Compose with Ansible] *******************************************************************************************************

TASK [Gathering Facts] ***********************************************************************************************************************
ok: [localhost]

TASK [Ensure Docker is installed] ************************************************************************************************************
ok: [localhost]

TASK [Ensure Docker Compose is installed] ****************************************************************************************************
ok: [localhost]

TASK [Ensure Docker service is running] ******************************************************************************************************
ok: [localhost]

TASK [Pull Docker images] ********************************************************************************************************************
changed: [localhost]

TASK [Run Docker Compose] ********************************************************************************************************************
changed: [localhost]

PLAY RECAP ***********************************************************************************************************************************
localhost                  : ok=6    changed=2    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

输出显示 Ansible 按顺序执行了每个任务,--ask-become-pass 会提示输入 sudo 密码。

验证服务是否运行成功:

$ curl http://localhost:8080
<!DOCTYPE html>
<html>
  <head>
    <title>Hello from Ansible</title>
  </head>
  <body>
    <h1>Hello from Docker + Ansible!</h1>
  </body>
</html>

可以看到我们的页面已成功运行在 Nginx 容器中,并由 Ansible 管理。

⚠️ 如果遇到权限错误(如连接 Docker daemon socket 被拒绝),请将当前用户加入 docker 组并重启系统

$ sudo usermod -aG docker $USER

5. 总结

在本文中,我们演示了如何使用 Ansible 来运行 Docker 和 Docker Compose 命令。

我们构建了一个简单的 Nginx 应用,定义了多个 Compose 文件,并通过 Ansible 实现了一键自动化部署。借助 Ansible 与 Docker Compose 的结合,我们能够实现:

  • 环境一致性(可重复性)
  • 服务扩展性(轻松添加新容器或服务)
  • 部署自动化(避免手动操作)

现在你可以在测试和生产环境中自动化复杂的基础设施部署,而不仅仅局限于开发环境。


原始标题:Run Docker Commands With Ansible