这次我们来看一个面向运维新手的实战项目,核心是 Ansible 和 Docker 的整合应用。对于很多刚接触运维的朋友来说,自动化部署和容器化管理听起来很复杂,但实际落地时,最关心的是能不能快速上手、环境好不好配、有没有现成的脚本能用。这篇文章就围绕“零基础实战”这个目标,带你从零开始,完成 Ansible 和 Docker 的环境搭建、基础配置,并实现一个简单的自动化部署任务。
文章的重点不是讲深奥的理论,而是提供一套可执行、可验证的操作流程。你会看到具体的安装命令、配置文件示例、以及如何用 Ansible 去管理 Docker 容器。整个过程会重点关注环境依赖、常见报错排查以及如何验证功能是否生效。无论你是想搭建个人实验环境,还是为团队探索自动化运维方案,这套流程都能提供一个清晰的起点。
1. 核心能力速览
在深入细节之前,我们先通过一个表格快速了解这个实战项目涵盖的核心技术和能力边界,这有助于你判断是否值得继续往下看。
| 能力项 | 说明 |
|---|---|
| 项目类型 | 自动化运维实战教程,侧重 Ansible 与 Docker 的整合应用。 |
| 技术栈 | Ansible(配置管理与自动化)、Docker(应用容器化)。 |
| 目标读者 | 运维初学者、DevOps 入门者、希望实现基础自动化的开发人员。 |
| 环境门槛 | 一台 Linux 服务器(如 CentOS 7/8, Ubuntu 20.04/22.04)或具备 Linux 环境的个人电脑。对硬件无特殊要求,2核4G内存足以运行实验。 |
| 核心功能 | 1. Ansible 基础环境安装与配置。 2. Docker 引擎的自动化安装与配置。 3. 使用 Ansible Playbook 批量管理 Docker 容器(部署、启动、停止)。 4. 实现一个简单的应用(如 Nginx)的容器化部署与更新。 |
| 启动与验证 | 通过命令行执行 Ansible 命令和 Playbook 进行验证,无图形化一键启动包。 |
| 是否支持 API | Ansible 本身提供丰富的模块和可通过ansible-runner等方式调用,但本实战侧重于 CLI 使用。Docker 提供 REST API。 |
| 是否支持批量任务 | 是,这是 Ansible 的核心优势,可对多台主机进行批量、并行的配置管理和容器部署。 |
| 适合场景 | 自动化服务器初始化、批量部署微服务、持续集成/持续部署(CI/CD)中的基础设施环节、学习 DevOps 工具链。 |
2. 适用场景与使用边界
了解一个工具能做什么和不能做什么同样重要。Ansible 和 Docker 的组合并非万能,但在特定场景下能极大提升效率。
这个实战项目适合谁?
- 运维新人:想通过实际动手理解自动化运维的工作流。
- 应用开发者:希望将自己的应用打包成 Docker 镜像,并寻求一种可靠的方式部署到多台服务器。
- 中小团队:需要一套简单、无需复杂 Agent 的配置管理方案来管理测试或生产环境。
- 学生或个人爱好者:在本地虚拟机或云服务器上搭建学习环境。
能解决什么问题?
- 环境标准化:通过 Ansible 确保所有目标服务器上的 Docker 版本、配置一致。
- 部署自动化:编写一次 Playbook,即可在任意多台服务器上重复、无误地部署相同的 Docker 容器。
- 流程可追溯:Ansible Playbook 本身即文档,记录了部署的每一步操作。
- 快速回滚:通过 Playbook 可以快速停止旧容器、启动指定版本的旧容器,实现回滚。
不适合什么场景?
- 超大规模集群管理:对于成千上万的节点,可能需要更专业的平台(如 Kubernetes)配合 Ansible 进行底层初始化。
- 需要复杂状态管理和服务发现的场景:Ansible 更适合“命令与执行”模式,对于容器间网络、动态扩缩容,需结合 Docker Compose、Swarm 或 K8s。
- Windows 环境为主的运维:虽然 Ansible 和 Docker 都支持 Windows,但本实战基于 Linux,在 Windows 上步骤差异较大。
安全与合规边界提醒:
- 权限控制:Ansible 通常需要 SSH 免密登录目标主机,务必妥善保管私钥,并遵循最小权限原则。
- 镜像安全:从 Docker Hub 拉取镜像时,尽量使用官方或可信来源的镜像,避免潜在安全风险。
- 生产环境:本实战示例适用于学习和测试。在生产环境使用前,必须进行充分的测试,并考虑网络策略、数据持久化、日志收集和监控告警等完整方案。
3. 环境准备与前置条件
开始实战前,请确保你的实验环境满足以下基本要求。我们将以一个典型的场景为例:你有一台控制机(Control Node)和至少一台被管理机(Managed Node),为了简化,你也可以在一台机器上同时扮演这两个角色。
1. 操作系统
- 推荐使用CentOS 7/8或Ubuntu 20.04/22.04 LTS。其他发行版步骤可能略有不同。
- 本文后续命令以CentOS 7为例,Ubuntu 用户请注意包管理命令的差异(
apt代替yum)。
2. 网络与主机名
- 确保控制机可以通过 SSH 连接到被管理机。
- 为每台机器设置好主机名(如
control-node,node-01),或准备好 IP 地址清单。
3. 系统账户与权限
- 在控制机和所有被管理机上,需要一个具有
sudo权限的普通用户(如ops)。不建议直接使用root。 - 控制机需要生成 SSH 密钥对,并将公钥分发到所有被管理机,实现免密登录。这是 Ansible 工作的基础。
4. Python 环境
- Ansible 由 Python 编写,控制机需要 Python 3.6 或更高版本。CentOS 7 默认可能为 Python 2.7,需要额外安装 Python 3。
- 被管理机也需要 Python 解释器(至少 Python 2.7 或 Python 3.5+),因为 Ansible 模块需要在目标机器上执行。大多数 Linux 发行版已预装。
5. 资源要求
- CPU 与内存:实验环境对资源要求不高。控制机 1核2G,被管理机 1核1G 即可运行基础容器。
- 磁盘空间:预留至少 10GB 空间用于安装软件和存储 Docker 镜像。
- 网络:需要能访问互联网以下载安装包和 Docker 镜像。
4. 安装部署与启动方式
我们将分两步走:先在控制机上安装 Ansible,然后使用 Ansible 去自动化地在被管理机上安装 Docker。这本身就体现了“用自动化工具部署自动化基础设施”的思路。
4.1 控制机安装 Ansible
在控制机上执行以下操作。
步骤一:配置 EPEL 仓库(CentOS/RHEL 系统)EPEL 仓库提供了 Ansible 的稳定版本。
sudo yum install -y epel-release步骤二:安装 Ansible
sudo yum install -y ansible步骤三:验证安装安装完成后,检查版本以确保安装成功。
ansible --version如果看到类似ansible 2.9.27的输出,说明安装成功。
(针对 Ubuntu 系统)
sudo apt update sudo apt install -y software-properties-common sudo apt-add-repository --yes --update ppa:ansible/ansible sudo apt install -y ansible4.2 配置 Ansible 清单与 SSH 免密登录
步骤一:配置主机清单Ansible 通过“清单”文件来管理它要操作的主机。编辑/etc/ansible/hosts文件(或创建一个项目专用的清单文件)。
sudo vim /etc/ansible/hosts在文件末尾添加你的被管理机信息,例如:
[web_servers] node-01 ansible_host=192.168.1.101 ansible_user=ops node-02 ansible_host=192.168.1.102 ansible_user=ops [docker_hosts:children] web_servers这里定义了一个web_servers组,包含两台主机,并指定了连接用的 IP 和用户。docker_hosts组继承了web_servers。
步骤二:配置 SSH 免密登录在控制机上,为ops用户生成 SSH 密钥(如果尚未生成)。
ssh-keygen -t rsa -b 2048一路回车使用默认设置即可。
将公钥复制到所有被管理机。假设被管理机 IP 为192.168.1.101。
ssh-copy-id ops@192.168.1.101输入目标机器的ops用户密码。对所有被管理机重复此操作。
步骤三:测试 Ansible 连接使用ping模块测试到web_servers组所有主机的连通性。
ansible web_servers -m ping如果看到每个主机都返回"ping": "pong",则表示 SSH 连接和 Python 环境均正常,Ansible 可以正常工作。
4.3 使用 Ansible Playbook 自动化安装 Docker
现在,我们不再手动登录每台被管理机去安装 Docker,而是编写一个 Ansible Playbook 来完成。
步骤一:创建 Playbook 文件创建一个名为install_docker.yml的文件。
vim install_docker.yml步骤二:编写 Playbook 内容将以下内容写入文件。这个 Playbook 完成了:添加 Docker 官方 YUM 仓库、安装 Docker 引擎和必要工具、启动并设置 Docker 服务开机自启。
--- - name: Install and start Docker on CentOS hosts: docker_hosts # 指定在哪个主机组执行 become: yes # 使用 sudo 权限执行任务 tasks: - name: Install required packages (yum-utils) yum: name: yum-utils state: present - name: Add Docker CE stable repository get_url: url: https://download.docker.com/linux/centos/docker-ce.repo dest: /etc/yum.repos.d/docker-ce.repo mode: '0644' - name: Install Docker CE, CLI, and Containerd yum: name: - docker-ce - docker-ce-cli - containerd.io state: latest update_cache: yes - name: Start and enable Docker service systemd: name: docker state: started enabled: yes - name: Add management user to docker group (optional) user: name: "{{ ansible_user }}" groups: docker append: yes notify: - restart docker handlers: - name: restart docker systemd: name: docker state: restarted注意:最后一个任务将当前 Ansible 用户加入docker组,使其无需sudo即可运行docker命令。这触发了handler来重启 Docker 服务使组变更生效。
(针对 Ubuntu 系统的 Playbook 差异)主要区别在于包管理工具和仓库配置。你需要一个不同的 Playbook 或使用条件判断。这里提供一个 Ubuntu 的简化示例片段:
- name: Add Docker GPG key apt_key: url: https://download.docker.com/linux/ubuntu/gpg state: present - name: Add Docker repository apt_repository: repo: "deb [arch=amd64] https://download.docker.com/linux/ubuntu {{ ansible_distribution_release }} stable" state: present - name: Install Docker packages apt: name: - docker-ce - docker-ce-cli - containerd.io state: latest update_cache: yes步骤三:执行 Playbook在控制机上运行以下命令:
ansible-playbook install_docker.yml你将看到 Ansible 输出执行过程,显示每个任务的执行状态(ok,changed,failed)。如果一切顺利,所有changed的任务表示 Docker 被成功安装和启动。
5. 功能测试与效果验证
安装完成后,我们需要验证 Docker 是否真的安装成功,并且 Ansible 能否有效地管理 Docker 容器。
5.1 验证 Docker 安装
我们可以写一个简单的 Ansible 任务来在被管理机上运行docker --version。
方法一:使用 Ad-hoc 命令在控制机上,对docker_hosts组执行:
ansible docker_hosts -m shell -a "docker --version"如果返回类似Docker version 20.10.12, build e91ed57的信息,则证明 Docker 安装成功。
方法二:通过 Playbook 验证创建一个验证 Playbookverify_docker.yml:
--- - name: Verify Docker installation hosts: docker_hosts tasks: - name: Check Docker version command: docker --version register: docker_version_result - name: Print Docker version debug: msg: "Docker version on {{ inventory_hostname }}: {{ docker_version_result.stdout }}"执行它:
ansible-playbook verify_docker.yml5.2 使用 Ansible 部署第一个 Docker 容器
现在,我们来完成核心实战:用 Ansible 在远程主机上启动一个 Nginx 容器。
创建部署 Playbook创建一个名为deploy_nginx.yml的文件。
--- - name: Deploy Nginx container hosts: web_servers # 在 web_servers 组的主机上执行 become: yes tasks: - name: Pull the latest Nginx image docker_image: name: nginx tag: latest source: pull - name: Create a directory for web content file: path: /home/ops/web_content state: directory mode: '0755' - name: Create a simple index.html copy: dest: /home/ops/web_content/index.html content: | <html> <body> <h1>Hello from Ansible & Docker on {{ inventory_hostname }}!</h1> </body> </html> - name: Run Nginx container docker_container: name: my_nginx image: nginx:latest state: started restart_policy: unless-stopped ports: - "8080:80" # 映射主机 8080 端口到容器 80 端口 volumes: - /home/ops/web_content:/usr/share/nginx/html:ro # 挂载自定义网页这个 Playbook 做了以下几件事:
- 拉取最新的 Nginx 镜像。
- 在主机上创建一个目录和自定义的
index.html文件。 - 启动一个名为
my_nginx的容器,将主机的 8080 端口映射到容器的 80 端口,并将自定义网页目录挂载到容器内。
执行部署
ansible-playbook deploy_nginx.yml验证部署结果
- 在控制机上检查容器状态:
应该能看到ansible web_servers -m shell -a "docker ps | grep my_nginx"my_nginx容器处于Up状态。 - 访问 Web 服务: 打开浏览器,访问
http://<被管理机IP>:8080。例如http://192.168.1.101:8080。你应该能看到 “Hello from Ansible & Docker on node-01!” 的页面。 - 批量验证:如果
web_servers组有多台主机,可以依次访问它们的 IP 和 8080 端口,会发现每台主机都独立运行着一个内容相同的 Nginx 容器。这证明了 Ansible 批量部署的能力。
5.3 扩展测试:容器生命周期管理
Ansible 的docker_container模块可以轻松管理容器的整个生命周期。
停止容器创建一个stop_nginx.yml:
--- - name: Stop Nginx container hosts: web_servers tasks: - name: Stop the container docker_container: name: my_nginx state: stopped执行后,容器将停止,浏览器无法再访问。
删除容器创建一个remove_nginx.yml:
--- - name: Remove Nginx container hosts: web_servers tasks: - name: Remove the container (will also stop it if running) docker_container: name: my_nginx state: absent执行后,容器将被删除。
更新容器(滚动更新示例)假设我们要将 Nginx 镜像从latest更新到alpine标签,并更换挂载的网页内容。
--- - name: Update Nginx container hosts: web_servers become: yes tasks: - name: Pull nginx:alpine image docker_image: name: nginx tag: alpine source: pull - name: Update index.html copy: dest: /home/ops/web_content/index.html content: | <html> <body> <h1>Updated! Running Nginx Alpine on {{ inventory_hostname }}</h1> </body> </html> - name: Recreate container with new image docker_container: name: my_nginx image: nginx:alpine # 使用新镜像标签 state: started restart_policy: unless-stopped ports: - "8080:80" volumes: - /home/ops/web_content:/usr/share/nginx/html:ro force_kill: yes # 强制停止旧容器 recreate: yes # 重新创建容器这个 Playbook 展示了如何拉取新镜像、更新配置,然后通过recreate: yes参数让 Ansible 自动停止旧容器并用新配置创建新容器,实现简单的“滚动更新”。
6. 接口 API 与批量任务
虽然本实战主要使用 Ansible CLI,但了解其与 API 和批量任务的深度结合方式对构建自动化流水线至关重要。
6.1 Ansible 的 API 与集成
Ansible 本身可以通过ansible-runner库或直接调用ansible/ansible-playbook命令行工具的方式,被其他程序(如 Python 脚本、CI/CD 平台)集成。
Python 调用示例以下是一个简单的 Python 脚本,用于执行一个 Ansible Playbook 并获取结果。
#!/usr/bin/env python3 import json import subprocess import sys def run_playbook(playbook_path, inventory_path='./hosts'): """ 运行指定的 Ansible Playbook。 """ cmd = [ 'ansible-playbook', '-i', inventory_path, playbook_path, '--verbose' # 获取更详细的输出 ] try: # 执行命令并捕获实时输出 process = subprocess.Popen( cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, bufsize=1, universal_newlines=True ) # 实时打印输出 for line in process.stdout: print(line, end='') # 等待命令完成 stdout, stderr = process.communicate() if process.returncode != 0: print(f"Playbook execution failed with error:\n{stderr}", file=sys.stderr) return False else: print("Playbook executed successfully.") return True except FileNotFoundError: print("Error: ansible-playbook command not found. Is Ansible installed?", file=sys.stderr) return False except Exception as e: print(f"An unexpected error occurred: {e}", file=sys.stderr) return False if __name__ == '__main__': # 指定你的 Playbook 和清单文件路径 playbook = 'deploy_nginx.yml' inventory = '/etc/ansible/hosts' # 或自定义清单路径 success = run_playbook(playbook, inventory) sys.exit(0 if success else 1)这个脚本封装了ansible-playbook的调用,可以集成到 Web 后台或自动化调度系统中。
6.2 高级批量任务策略
Ansible 的批量能力不仅体现在同时操作多台主机,还体现在灵活的任务执行策略上。
1. 串行与并行控制在 Playbook 中,你可以控制同时操作多少台主机。
- name: Update application on all servers hosts: web_servers serial: 2 # 每次只在2台主机上执行,实现“滚动更新”,避免全部同时停机 tasks: - name: Stop app container docker_container: name: my_app state: stopped - name: Pull latest image docker_image: name: my_app_image tag: latest source: pull - name: Start app container docker_container: name: my_app image: my_app_image:latest state: started2. 动态清单与分组主机清单可以是静态文件,也可以是从云平台(AWS EC2, Azure VM)、CMDB 或自定义脚本动态获取的。这允许你根据标签、环境等属性动态确定批量操作的目标。
# 使用 AWS EC2 动态清单 ansible-playbook -i aws_ec2.yml deploy.yml3. 任务委托与滚动执行对于需要特定顺序的操作(如先更新负载均衡器配置,再更新后端服务器),可以使用delegate_to和serial。
- name: Rolling update of backend services hosts: backend_servers serial: 1 # 一台一台地更新 tasks: - name: Take server out of load balancer uri: url: "http://lb-manager/api/disable/{{ inventory_hostname }}" method: POST delegate_to: localhost # 在控制机上执行此任务,调用LB的API - name: Update backend service # ... 更新容器的任务 ... - name: Wait for service health check wait_for: port: 8080 host: "{{ inventory_hostname }}" delay: 5 timeout: 60 - name: Put server back into load balancer uri: url: "http://lb-manager/api/enable/{{ inventory_hostname }}" method: POST delegate_to: localhost7. 资源占用与性能观察
在自动化运维中,了解工具本身的资源消耗以及对被管理节点的影响很重要。
1. Ansible 控制机资源占用
- CPU/内存:运行
ansible-playbook时,控制机主要负责生成任务、通过 SSH 发送命令、接收并解析结果。对于管理几十上百台节点,单次 Playbook 运行对控制机的资源消耗(CPU 和内存)通常很低,可以忽略不计。 - 网络带宽:Ansible 通过 SSH 传输模块代码(通常很小)和任务结果。主要网络负载在于执行
copy、get_url等模块时传输文件。在安装 Docker 的 Playbook 中,大部分流量是 YUM 从互联网仓库下载软件包,这发生在被管理机上,不经过控制机。
2. 对被管理机的影响
- SSH 连接:Ansible 会为每个被管理机建立 SSH 连接。默认使用 OpenSSH 的 ControlPersist 功能来复用连接,减少认证开销。
- 临时文件:Ansible 会将模块代码传输到被管理机的临时目录(如
~/.ansible/tmp)并执行。任务完成后会自动清理。 - 任务执行负载:真正的负载来自于你 Playbook 中定义的任务。例如,
yum install docker-ce会触发包管理器的解析和下载操作,消耗被管理机的 CPU、内存和网络。
3. 性能优化观察点
- 减少“收集事实”:Ansible 默认会在每个 Play 开始时自动收集目标主机的事实(
gather_facts: yes)。这可能会消耗一些时间。如果 Playbook 不需要这些系统信息,可以关闭它以加速执行。- hosts: web_servers gather_facts: no # 关闭事实收集 tasks: - ... - 使用
async和poll:对于长时间运行的任务(如编译软件),可以异步执行,避免 SSH 连接超时。- name: Run long-running operation command: /usr/bin/long_running_script.sh async: 3600 # 最大运行时间(秒) poll: 0 # 启动后立即轮询,不等待 register: long_task - 合理设置
forks:ansible.cfg中的forks参数控制并行执行的主机数。默认是 5。增加此值(如 20)可以加快批量任务速度,但会增加控制机网络和 CPU 负载。 - Docker 容器资源限制:使用 Ansible 的
docker_container模块启动容器时,可以设置资源限制,避免单个容器耗尽主机资源。- name: Run container with resource limits docker_container: name: my_app image: my_app:latest state: started cpu_shares: 512 # CPU 权重 mem_limit: "512m" # 内存限制 memswap_limit: "1g" # 内存+交换分区限制
8. 常见问题与排查方法
在实战过程中,你可能会遇到以下问题。这里提供快速的排查思路。
| 问题现象 | 可能原因 | 排查方式 | 解决方案 |
|---|---|---|---|
执行ansible-playbook时报错Failed to connect to the host via ssh | 1. SSH 免密登录未配置成功。 2. 目标主机防火墙阻止了 SSH 端口。 3. 清单文件中 ansible_host或ansible_user配置错误。 | 1. 手动ssh ops@目标IP测试。2. 检查目标机 sshd服务状态和防火墙规则 (sudo systemctl status sshd,sudo firewall-cmd --list-all)。3. 检查 /etc/ansible/hosts文件。 | 1. 重新执行ssh-copy-id。2. 开放防火墙 22 端口或关闭防火墙(测试环境)。 3. 修正清单文件。 |
执行 Playbook 时提示ModuleNotFoundError: No module named 'docker' | 目标主机上缺少 Python 的 Docker SDK (docker模块)。Ansible 的docker_*模块依赖它。 | 在目标主机上手动运行python3 -c "import docker"确认。 | 在目标主机上安装:sudo pip3 install docker。或者在 Playbook 开头增加一个安装任务。 |
| Docker 服务启动失败 | 1. 内核版本过旧。 2. 存储驱动冲突。 3. 端口被占用。 | 1.journalctl -u docker.service查看详细日志。2. docker info检查存储驱动。 | 1. 升级内核。 2. 编辑 /etc/docker/daemon.json调整存储驱动。3. 检查并释放被占用的端口(如 2375, 2376)。 |
Ansible 执行yum install很慢或失败 | 1. 网络问题,无法访问仓库。 2. 仓库缓存过期。 | 1. 在目标主机上手动ping download.docker.com。2. 执行 sudo yum clean all && sudo yum makecache。 | 1. 配置网络代理或更换国内镜像源。 2. 在 Playbook 的 yum任务中增加update_cache: yes参数。 |
docker_container模块报错Error starting container | 1. 镜像不存在。 2. 端口映射冲突。 3. 挂载的卷路径不存在。 | 1. 检查镜像是否已拉取 (docker images)。2. 检查主机端口是否已被占用 ( netstat -tlnp | grep :8080)。3. 检查 Playbook 中 volumes指定的主机路径。 | 1. 先执行docker_image任务拉取镜像。2. 更换主机端口或停止占用端口的进程。 3. 确保 file模块已创建好目录。 |
| Playbook 执行成功,但浏览器无法访问 Nginx | 1. 主机防火墙未开放映射端口(如 8080)。 2. 容器内部服务未正常启动。 3. 网络策略限制。 | 1. 在目标主机上curl localhost:8080。2. 查看容器日志 docker logs my_nginx。3. 检查防火墙规则。 | 1. 开放防火墙端口:sudo firewall-cmd --add-port=8080/tcp --permanent && sudo firewall-cmd --reload。2. 根据容器日志排查 Nginx 配置问题。 |
| Ansible 执行速度慢 | 1.gather_facts开启。2. forks值设置过低。3. 网络延迟高。 | 1. 观察 Playbook 输出,看时间消耗在哪个阶段。 2. 检查 ansible.cfg中forks设置。 | 1. 关闭不必要的gather_facts。2. 适当增加 forks值(在ansible.cfg中设置)。3. 考虑在局域网内部署。 |
9. 最佳实践与使用建议
基于这个实战项目,我们可以总结出一些在更复杂场景下也能适用的最佳实践。
1. 项目结构标准化不要把所有 Playbook 都扔在一个目录。建议按以下结构组织:
ansible-docker-demo/ ├── inventories/ # 清单目录 │ ├── production # 生产环境清单 │ └── staging # 测试环境清单 ├── group_vars/ # 组变量 │ └── docker_hosts.yml # 为 docker_hosts 组定义的变量 ├── host_vars/ # 主机变量 │ └── node-01.yml # 为 node-01 定义的变量 ├── roles/ # 角色目录(可选,用于复杂项目) │ ├── common │ ├── docker │ └── nginx ├── playbooks/ # Playbook 目录 │ ├── base_setup.yml │ ├── install_docker.yml │ └── deploy_app.yml └── ansible.cfg # Ansible 配置文件2. 使用变量提高灵活性将配置信息抽取为变量,使 Playbook 更通用。例如,在group_vars/docker_hosts.yml中:
--- docker_version: "20.10" nginx_container_name: "my_nginx" nginx_host_port: 8080 nginx_container_port: 80在 Playbook 中引用:
- name: Run Nginx container docker_container: name: "{{ nginx_container_name }}" image: nginx:latest state: started ports: - "{{ nginx_host_port }}:{{ nginx_container_port }}"3. 为 Playbook 添加标签为任务打上标签,方便只运行特定部分。
tasks: - name: Install Docker yum: name: docker-ce state: present tags: docker_install - name: Deploy Nginx docker_container: ... tags: deploy_nginx然后可以运行:ansible-playbook site.yml --tags "deploy_nginx"
4. 实现幂等性Ansible 模块设计是幂等的,意味着多次运行同一个 Playbook 不会导致意外结果。确保你的自定义脚本或命令也具备这个特性。例如,使用creates或removes参数来避免重复操作。
5. 日志与审计
- 使用
ansible-playbook的-v(verbose) 参数获取详细输出。 - 使用
--check模式进行“模拟运行”,查看会有什么更改,而不实际执行。 - 考虑将 Playbook 的执行日志输出到文件或发送到日志系统,便于审计和排错。
ansible-playbook deploy.yml | tee /var/log/ansible/deploy-$(date +%Y%m%d).log
6. 安全加固
- 清单文件安全:不要将包含密码或密钥的清单文件提交到版本控制系统。使用
ansible-vault加密敏感数据。 - 最小权限原则:为 Ansible 执行用户配置
sudo时,尽量限制其权限,仅授予必要的命令。 - 镜像来源:始终从可信的仓库拉取 Docker 镜像,并定期扫描镜像漏洞。
10. 总结与下一步
通过这个从零开始的实战,我们完成了 Ansible 与 Docker 整合的基础闭环:在控制机安装 Ansible,配置免密登录,编写 Playbook 自动化安装 Docker,最后再用 Ansible 去批量部署和管理 Docker 容器。整个过程清晰地展示了如何用代码(Playbook)来定义和维护基础设施状态。
这个项目最值得尝试的点在于它的“可重复性”和“批量能力”。一旦 Playbook 编写完成,你可以在几分钟内让一套全新的服务器环境达到完全一致的状态,这是手动操作无法比拟的效率。
对于初次尝试者,建议最先验证的功能就是“一键部署 Nginx 容器”。它能让你立刻看到成果,理解 Ansible 和 Docker 是如何协同工作的。最容易踩的坑通常是SSH 免密登录配置和目标主机防火墙,务必按照步骤仔细检查。
掌握了这个基础框架后,你可以向多个方向深入:
- 复杂应用部署:尝试部署一个多容器的应用栈(如 WordPress,包含 Web、数据库容器),学习使用
docker_network和容器链接。 - 集成 CI/CD:将你的 Ansible Playbook 放入 Jenkins、GitLab CI 或 GitHub Actions 的流水线中,实现代码提交后自动测试和部署。
- 使用 Ansible Roles:当 Playbook 变得庞大时,将其重构为 Roles,实现代码的复用和模块化。
- 探索 Docker Compose:对于复杂的多容器应用,可以编写
docker-compose.yml文件,然后使用 Ansible 的docker_compose模块来管理整个应用栈。 - 结合配置管理:不仅管理容器,还用 Ansible 管理容器内部的配置(通过
docker exec或将配置文件挂载为卷)。
工具的价值在于解决实际问题。建议你从手头一个真实的小需求开始,比如自动化部署一个内部工具或测试环境,将本次实战学到的模式应用进去,边做边学,积累的经验会扎实得多。