示例工程DevOps【免费下载链接】ansible-for-devopsAnsible for DevOps examples.项目地址https://gitcode.com/gh_mirrors/an/ansible-for-devops点击查看免费下载本文以 ansible-for-devops 仓库中的 docker-flask 示例为骨架完整讲解如何用 Vagrant 拉起一台本地虚拟机、用 Ansible 在虚拟机内安装 Docker再通过 Ansible 的docker_image与docker_container模块构建并运行wwwFlask、dbMySQL、dataBusybox 数据卷三个容器最终在浏览器验证 Flask 与 MySQL 的连通性。读完本文你将掌握用 Ansible 描述整个 Docker 容器生命周期的完整套路包括镜像构建、容器启动、数据卷挂载、环境变量注入以及容器内部再跑 Ansible 的容器内自配置模式。一、背景为什么用 Ansible 管理 Docker 容器生命周期Docker 负责构建和管理 Linux 容器Ansible 则擅长描述和管理容器的整个生命周期。这个组合的价值在于容器构建、启动、配置、数据卷挂载等步骤都可以用声明式的 playbook 表达并沉淀为可重复执行的代码。本示例通过一个 Vagrant profile先由 Ansible 把本地 VM 配置成带 Docker 环境的主机然后再用 Ansible 构建并运行三个容器组成一套 Docker 风格的 Flask MySQL 简单 Web 应用栈容器镜像作用www基于 Ubuntu 构建Flask 应用对外提供 HTTP 服务端口 80db基于 Ubuntu 构建MySQL 数据库端口 3306dataBusybox承载 MySQL 数据目录/var/lib/mysql的数据卷容器用于持久化需要特别说明的是原文档亦明确声明该示例的目的在于演示Ansible 与 Docker 容器生命周期的交互方式并非所有场景下的最佳实践。管理容器构建与编排还有 Docker Compose、Kubernetes 等众多方案本示例的结构刻意保持简单透明方便读者看清每一步。二、环境准备与启动流程原文档给出的完整上手步骤分为两部分宿主机环境准备以及 Vagrant Ansible 的启动。1. 宿主机前置条件按顺序完成以下安装下载并安装 VirtualBox下载并安装 Vagrant安装 Ansible打开终端macOS 上的 Terminal 等cd进入包含Vagrantfile的目录即docker-flask目录运行以下命令安装本 profile 所需的 Ansible 角色$ ansible-galaxy install -r requirements.yml这里的 requirements.yml 内容极简仅声明了一个角色--- roles: - name: geerlingguy.docker该角色负责在目标主机上安装并配置 Docker安装 Docker CE、Python 客户端依赖等。查看 docker-flask/provisioning/main.yml 可以看到它在正式任务前被roles引用是整个环境安装的关键一步。2. 启动与登录完成以上准备后只需一条命令即可启动全部流程$ vagrant upVagrant 会自动完成创建新 VM → 安装基础 box → 通过 Ansible provisioner 配置它。当vagrant up执行完毕、回到命令行提示符后如果想登录 VM 查看内部状态可以执行$ vagrant ssh3. 配置宿主机 hosts 文件为了让浏览器能以域名访问测试页需要修改宿主机的 hosts 文件——Mac/Linux 为/etc/hostsWindows 为%systemroot%\system32\drivers\etc\hosts——追加以下一行192.168.56.39 docker-flask.test配置完成后在浏览器访问 http://docker-flask.test/ 即可看到测试页页面会显示 MySQL 连接测试结果从而确认 Flask 容器能够与 MySQL 容器正常通信。三、Vagrantfile 解读VM 与 Ansible provisioner 的绑定查看 docker-flask/Vagrantfile 可了解 VM 的完整定义Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| config.vm.box geerlingguy/ubuntu2004 config.vm.network private_network, ip: 192.168.56.39 config.ssh.insert_key false config.vm.hostname docker-flask.test config.vm.provider :virtualbox do |v| v.name docker-flask.test v.memory 1024 v.cpus 2 v.customize [modifyvm, :id, --natdnshostresolver1, on] v.customize [modifyvm, :id, --ioapic, on] end # Enable provisioning with Ansible. config.vm.provision ansible do |ansible| ansible.playbook provisioning/main.yml end end关键点box 选择使用geerlingguy/ubuntu2004Ubuntu 20.04与后续容器镜像、测试脚本保持同一发行版系网络私有网络 IP 固定为192.168.56.39这正是上一节 hosts 文件中docker-flask.test所指向的地址VM hostname 同样设为docker-flask.test资源分配 1024 MB 内存、2 核 CPU并开启 NAT DNS host resolver 与 IO-APIC对网络解析和多核支持更友好Ansible 集成通过config.vm.provision ansible将 Ansible provisioner 绑定到 provisioning/main.ymlVM 创建后 Vagrant 会自动在其上执行该 playbook。四、provisioning/main.yml整个配置流程的入口docker-flask/provisioning/main.yml 是 Vagrant 调用的总入口 playbook--- - hosts: all become: true vars: build_root: /vagrant/provisioning pre_tasks: - name: Update apt cache if needed. apt: update_cacheyes cache_valid_time3600 roles: - role: geerlingguy.docker tasks: - import_tasks: setup.yml - import_tasks: docker.yml执行顺序与要点pre_tasks更新 apt 缓存cache_valid_time3600表示 1 小时内缓存有效则跳过避免每次都做无谓更新roles运行geerlingguy.docker角色安装 Dockertasks依次导入 setup.yml环境准备与 docker.yml镜像构建与容器运行。build_root: /vagrant/provisioning是一个关键变量——Vagrant 会把docker-flask目录同步到 VM 的/vagrant因此宿主机上的 Dockerfile 等在 VM 内的路径即/vagrant/provisioning/...后续构建镜像时docker_image模块的build.path会引用它。setup.yml运行容器前的环境准备docker-flask/provisioning/setup.yml 完成三件事- name: Add vagrant user to docker group. user: name: vagrant groups: docker append: true - name: Install Pip. apt: namepython3-pip statepresent - name: Install Docker Python library. pip: namedocker statepresent将vagrant用户加入docker组使其具备管理 Docker 容器的权限安装python3-pip与 Docker 的 Python 库docker——这是 Ansibledocker_*系列模块能够驱动 Docker API 的底层依赖。值得留意的是脚本顶部的注释透露了一个真实运维细节Ansible 默认使用 SSH ControlPersist 复用连接。playbook 首次运行时若由vagrant用户直接执行 docker 命令会失败因为持久化的连接状态感知不到该用户刚被加入 docker 组这一变化因此整个 playbook 通过become: true以 sudo 身份运行绕开这个坑。五、docker.yml用 Ansible 构建镜像并运行三容器docker-flask/provisioning/docker.yml 是本示例的核心它把构建镜像 运行容器全部用 Ansible 模块声明出来。1. 构建三个镜像- name: Build Docker images from Dockerfiles. docker_image: name: {{ item.name }} tag: {{ item.tag }} source: build build: path: {{ build_root }}/{{ item.directory }} pull: false state: present with_items: - { name: data, tag: latest, directory: data } - { name: flask, tag: latest, directory: www } - { name: db, tag: latest, directory: db }要点使用with_items循环一次性构建data、flask、db三个镜像分别对应data、www、db三个子目录下的 Dockerfilesource: build表示从 Dockerfile 构建build.path指向/vagrant/provisioning/{data|www|db}pull: false表示构建时不主动拉取基础镜像的更新本地已有则直接用构建更快、行为更可预期state: present保证镜像存在。2. 运行 data 数据卷容器- name: Run a Data container. docker_container: image: data:latest name: data state: present注意注释中的关键设计数据卷容器不需要处于运行状态也能被使用。因此data容器只用state: present创建即可不启动。它的作用是持有 MySQL 数据目录/var/lib/mysql为持久化提供挂载来源。3. 运行 wwwFlask容器- name: Run a Flask container. docker_container: image: flask:latest name: www state: started command: python3 /opt/www/index.py ports: 80:80state: started确保容器启动command指定启动命令为python3 /opt/www/index.py即上一节由容器内 Ansible 生成的应用入口ports: 80:80将容器 80 端口映射到 VM 的 80 端口——这正是浏览器访问http://docker-flask.test/时命中的端口。4. 运行 dbMySQL容器- name: Run a MySQL container. docker_container: image: db:latest name: db state: started volumes_from: data ports: 3306:3306 env: MYSQL_ROOT_PASSWORD: root MYSQL_DATABASE: flask MYSQL_USER: flask MYSQL_PASSWORD: flaskvolumes_from: data把数据卷从data容器继承过来MySQL 的数据写入/var/lib/mysql后即落在数据卷中实现持久化ports: 3306:3306暴露 MySQL 端口VM 内部 Flask 通过容器网络访问时也可用env注入 MySQL 官方镜像约定的初始化变量——root 密码root、创建数据库flask、创建用户flask及其密码flask。这些凭据与后面 Flask 应用的数据库连接串完全对应见第七节。六、三个 Dockerfile从基础镜像到应用就绪data最小化的数据卷容器docker-flask/provisioning/data/Dockerfile 极简基于busyboxFROM busybox MAINTAINER Jeff Geerling geerlingguymac.com RUN mkdir -p /var/lib/mysql VOLUME /var/lib/mysql创建/var/lib/mysql目录并用VOLUME指令声明为数据卷。busybox 镜像体积小非常适合只承担数据载体职责的容器。dbMySQL 5.7 容器docker-flask/provisioning/db/DockerfileFROM mysql:5.7 MAINTAINER Jeff Geerling geerlingguymac.com EXPOSE 3306直接以官方mysql:5.7为基础镜像EXPOSE 3306声明服务端口。数据库初始化所需的库名、用户名、密码全部由运行时注入的环境变量决定见上节env配置。www容器内嵌 Ansible 的 Flask 容器docker-flask/provisioning/www/Dockerfile 是这个示例中最有特色的一层——它基于geerlingguy/docker-ubuntu2004-ansible预装了 Ansible 的 Ubuntu 20.04 镜像并在构建镜像的过程中直接调用 ansible-playbook 完成应用配置FROM geerlingguy/docker-ubuntu2004-ansible MAINTAINER Jeff Geerling geerlingguymac.com RUN apt-get update RUN apt-get install -y libmysqlclient-dev build-essential \ python3-dev python3-pip RUN pip3 install flask flask-sqlalchemy mysqlclient COPY playbook.yml /etc/ansible/playbook.yml COPY index.py.j2 /etc/ansible/index.py.j2 COPY templates /etc/ansible/templates RUN mkdir -m 755 /opt/www RUN ansible-playbook /etc/ansible/playbook.yml --connectionlocal EXPOSE 80三步走安装构建/运行 Flask 所需的系统依赖与 Python 包flask、flask-sqlalchemy、mysqlclient把 playbook.yml、模板 index.py.j2、以及templates目录内含 index.html拷入容器内的/etc/ansible/用--connectionlocal在本容器内执行 Ansible生成 Flask 应用文件。这种在 Dockerfile 的构建阶段直接跑 Ansible的做法把配置管理工具的能力延伸到容器镜像内部是 Docker Ansible 组合的一种典型玩法。七、容器内 playbook模板化注入宿主 IP容器构建时执行的 docker-flask/provisioning/www/playbook.yml 如下- hosts: localhost become: true tasks: - name: Get host IP address. shell: /sbin/ip route | awk /default/ { print $3 } register: host_ip changed_when: false - name: Set host_ip_address variable. set_fact: host_ip_address: {{ host_ip.stdout }} - name: Copy Flask app into place. template: src: /etc/ansible/index.py.j2 dest: /opt/www/index.py mode: 0755 - name: Copy Flask templates into place. copy: src: /etc/ansible/templates dest: /opt/www mode: 0755它的巧妙之处在于动态探测数据库地址通过ip route提取默认网关awk /default/ { print $3 }即宿主机的 IP并注册为变量host_ip用set_fact将其转换为host_ip_address变量以template模块渲染 index.py.j2 到/opt/www/index.py让 Flask 应用在运行时知道该连哪台 MySQL。对应的 index.py.j2 核心部分from flask import Flask, Markup, render_template from flask_sqlalchemy import SQLAlchemy from sqlalchemy import text app Flask(__name__) db_uri mysql://flask:flask{{ host_ip_address }}/flask app.config[SQLALCHEMY_DATABASE_URI] db_uri db SQLAlchemy(app) app.route(/) def test(): mysql_result False try: query text(SELECT 1) result db.engine.execute(query) if [row[0] for row in result][0] 1: mysql_result True except: pass ...连接串mysql://flask:flask{{ host_ip_address }}/flask中的用户名、密码、库名与 docker.yml 中 MySQL 容器的envflask/flask/flask一一对应。路由/对数据库执行SELECT 1成功则页面显示绿色PASS失败则显示红色FAIL。页面模板 index.html 通过{{ result }}输出这一结果。八、验证与测试仓库自带的自动化佐证除了手动访问 http://docker-flask.test/ 查看PASS/FAIL之外仓库还在 tests/docker-flask.yml 中提供了可直接执行的测试入口- hosts: all pre_tasks: - name: Update the apt cache. apt: update_cacheyes cache_valid_time600 roles: - geerlingguy.docker - import_playbook: ../docker-flask/provisioning/main.yml vars: build_root: {{ playbook_dir }}它先安装geerlingguy.docker角色再以import_playbook复用 provisioning/main.yml并通过build_root: {{ playbook_dir }}覆盖默认的/vagrant/provisioning路径使同一套构建逻辑可以脱离 Vagrant、在任意已装好 Docker 的主机上直接跑——这正是本示例一处编写、多处复用的可移植性体现。仓库根目录的测试脚本体系如 tests/collection.sh 等也是围绕这类 playbook 进行批量验证的。九、适用范围与注意事项小结回顾整个示例值得记住的几点声明式描述容器生命周期镜像构建docker_image、容器创建/启动docker_container、数据卷挂载volumes_from、环境变量注入env全部收敛在 playbook 中可重复执行数据卷容器模式用state: present的 Busybox 容器专门持有 MySQL 数据目录容器不运行也能被引用是 Docker 时代经典的持久化手段容器内嵌配置管理在 Dockerfile 构建阶段以--connectionlocal执行 Ansible把模板渲染、配置下发纳入镜像构建流程路径与凭据的对应关系build_root/vagrant/provisioning、VM 私有 IP192.168.56.39、MySQL 凭据flask/flask三处紧密耦合改任何一处都需同步调整这是本示例结构简单的代价也是阅读时最需要留意的点适用范围正如原文档强调的本示例用于教学演示 Ansible 与 Docker 的交互方式生产级容器编排还应评估 Docker Compose、Kubernetes 等更完整的方案。本示例由 Jeff Geerling 创建作为其著作《Ansible for DevOps》中的配套实例与仓库内其他示例如更简单的 docker 入门示例共同构成了一条循序渐进的学习路径。赞分享示例工程DevOps【免费下载链接】ansible-for-devopsAnsible for DevOps examples.项目地址https://gitcode.com/gh_mirrors/an/ansible-for-devops点击查看免费下载相关推荐docker-curriculum 实战用 Docker Compose 编排 Flask Elasticsearch 多容器应用docker curriculum 实战用 Docker Compose 编排 Flask Elasticsearch 多容器应用 docker curr云原生DevOpsDocker on AWS 实战使用 Elastic Beanstalk 部署单容器 Flask 应用docker-curriculum 部署篇Docker on AWS 实战使用 Elastic Beanstalk 部署单容器 Flask 应用docker curriculum 部署篇 本文是云原生DevOpsdocker-curriculum 实战指南用 Busybox 容器吃透 docker pull、docker run 与容器生命周期管理docker curriculum 实战指南用 Busybox 容器吃透 docker pull、docker run 与容器生命周期管理 本篇是 docke云原生DevOps上一篇Xbyak APX扩展详解解锁新一代x86性能提升利器下一篇freeCodeCamp 每日编程挑战解读用字符编码与模运算实现凯撒密码解译Message Decoder创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考