Example Voting App:一个覆盖 Docker、Compose、Swarm 与 Kubernetes 的多容器分布式投票应用实战指南 示例工程云原生后端【免费下载链接】example-voting-appExample distributed app composed of multiple containers for Docker, Compose, Swarm, and Kubernetes项目地址https://gitcode.com/GitHub_Trending/ex/example-voting-app点击查看免费下载本指南以example-voting-app仓库中的 README.md 为核心脉络完整介绍这套多语言分布式示例应用的架构组成、三种主流容器编排方式Docker Compose / Docker Swarm / Kubernetes的部署与访问方法并结合仓库源码逐层剖析投票数据从前端到 Redis 队列、再到 Postgres 与实时结果页的完整链路。读完本文你将掌握一套可直接复制运行的分布式应用示例的部署命令、端口规划、健康检查与去重机制并理解消息队列、持久化与多语言容器协作的工程实践。项目概览一个跨语言的分布式投票应用Example Voting App 是一个简单但五脏俱全的分布式应用运行在多套 Docker 容器之上。项目采用 Python、Node.js、.NET 三种语言分别实现不同职责的组件并用 Redis 作为消息队列、Postgres 作为持久化存储README 明确说明了技术栈组合。整个应用由五个核心服务组成它们通过容器网络相互协作构成一条完整的投票数据处理流水线组件语言/运行时职责vote 前端Python (Flask Gunicorn)提供两个选项的投票页面redisRedis (alpine)暂存收集的新投票消息队列worker.NET (C#)消费 Redis 中的投票并写入 PostgresdbPostgreSQL (alpine)通过 Docker volume 持久化投票数据result 前端Node.js (Express Socket.IO)实时展示投票统计结果从仓库的目录布局可以清晰地看到各服务的源码与部署文件被独立组织前端与后端代码分别位于 vote/、worker/ 与 result/而 Kubernetes 清单统一放在 k8s-specifications/ 目录下。快速开始使用 Docker Compose 一键启动环境准备Mac / Windows安装 Docker DesktopDocker Compose 会随安装自动附带Linux确保安装了最新版本的 Docker Compose。启动命令在仓库根目录执行docker compose up启动后vote投票应用运行在 http://localhost:5000result结果页运行在 http://localhost:5001Compose 文件的服务编排细节仓库中的 docker-compose.yml 采用当前 Compose Spec 规范文件中注明 v1.27 版本即可使用v2/v3 已合并其编排设计值得逐一解读服务构建与本地开发挂载。vote服务通过build.context: ./vote与build.target: dev构建把 vote/ 目录挂载进容器/usr/local/app配合 vote/Dockerfile 中的dev阶段安装watchdog、设置FLASK_ENVdevelopment、以python app.py启动实现本地开发热更新result服务则通过entrypoint: nodemon --inspect0.0.0.0 server.js使用 nodemon 进行本地开发调试。健康检查与依赖顺序。Compose 文件为所有服务配置了depends_on与condition: service_healthy强制容器按依赖顺序就绪vote依赖 redis 健康result依赖 db 健康worker同时依赖 redis 与 db 健康。健康检查脚本统一放在 healthchecks/ 目录并挂载进容器redis使用 redis.shdb使用 postgres.sh。例如 postgres.sh 通过psql执行SELECT 1并校验返回结果为1来判断数据库外部可连通性脚本强制使用--host走网络而非本地 unix socket确保测试的是“外部可达性”。双网段隔离。Compose 定义了front-tier与back-tier两个网络vote/result/seed 同时接入前后两个网络而 worker、redis、db 仅在back-tier中。这种“前端服务可访问后端后端服务彼此隔离于前端”的设计模拟了生产环境的网络分层。种子数据 Profile。seed服务使用profiles: [seed]声明默认不会启动如需灌入测试数据使用docker compose --profile seed up -d显式开启它会在vote健康后运行 seed-data/ 中的脚本向应用灌入投票数据且restart: no保证只执行一次。扩展运行Docker Swarm 与 docker-stack.yml如果希望在多节点 Swarm 集群上运行README 给出了完整流程。初始化 Swarm如尚未初始化docker swarm init部署 Stackdocker stack deploy --compose-file docker-stack.yml voteSwarm 清单的要点仓库中的 docker-stack.yml 专为 Swarm 设计文件注释说明了两个关键背景该文件不能在 Compose 下直接使用因为多个副本会争抢绑定同一端口Swarm 目前不支持 Compose Spec因此文件锁定为较旧的version: 3.9。该清单使用预构建镜像dockersamples/examplevotingapp_vote等而不是本地构建并利用deploy.replicas实现水平扩展vote与worker均配置为 2 个副本result为 1 个副本。网络拆分为frontend/backendworker同时挂接两个网络以桥接投票与持久化两侧。注意 Swarm 模式下端口仅暴露在 manager 节点上vote5000:80、result5001:80访问地址取决于集群节点地址而非 localhost。部署到 Kubernetesk8s-specifications 清单解析一键部署与清理k8s-specifications/ 目录存放着全部服务的 YAML 清单。README 给出的操作步骤为# 创建 Deployment 与 Service在当前 namespace 下创建未修改则为 default kubectl create -f k8s-specifications/ # 清理资源 kubectl delete -f k8s-specifications/部署后voteWeb 应用可通过集群每个节点的31000端口访问resultWeb 应用可通过31001端口访问。各服务清单对应关系服务DeploymentServicevotevote-deployment.yamlvote-service.yamlresultresult-deployment.yamlresult-service.yamlworkerworker-deployment.yaml—dbdb-deployment.yamldb-service.yamlredisredis-deployment.yamlredis-service.yaml关键清单细节NodePort 对外暴露。vote与result的 Service 均使用type: NodePortvote 服务port: 5000 → targetPort: 80 → nodePort: 31000result 服务port: 5001 → targetPort: 80 → nodePort: 31001这就对应了 README 中“端口 31000 / 31001”的说明。内部通信服务。db与redis的 Service 使用type: ClusterIP仅暴露在集群内部分别为 5432 与 6379供 vote、worker、result 通过服务名如db、redis访问。存储策略的差异。Compose 场景下db使用命名 volumedb-data持久化到/var/lib/postgresql/data而在 k8s 清单中db-deployment.yaml 与 redis-deployment.yaml 均使用emptyDir: {}卷意味着数据随 Pod 生命周期存亡——这是示例场景下“无持久化”的简化取舍。镜像来源。Kubernetes 清单使用预构建镜像如dockersamples/examplevotingapp_vote、postgres:15-alpine、redis:alpine部署前需确保集群节点可拉取这些公共镜像。源码级解读从投票到结果展示的完整链路1. vote 前端写入 Redis 队列vote/app.py 是 Python/Flask 投票入口。其核心逻辑为两个选项通过环境变量OPTION_A/OPTION_B配置默认值为Cats与Dogs每个客户端首次访问时生成一个 64 位随机voter_idhex(random.getrandbits(64))并通过 cookie 下发用于后续去重提交 POST 请求后将{voter_id, vote}序列化为 JSON通过redis.rpush(votes, data)从列表右端推入Redis 的votes列表Redis 在此扮演消息队列角色Redis 连接采用 Flask 的g上下文按请求复用Redis(hostredis, db0, socket_timeout5)。if request.method POST: redis get_redis() vote request.form[vote] data json.dumps({voter_id: voter_id, vote: vote}) redis.rpush(votes, data)生产模式下 vote/Dockerfile 的final阶段以 Gunicorn 多 worker 运行--workers 4并为健康检查安装了curl。2. worker消费队列并写入 Postgresworker/Program.cs 是 .NET 消费者实现了“拉取-处理-保活”的循环使用redis.ListLeftPopAsync(votes)从列表左端弹出消息与 rpush 构成 FIFO 队列语义每 100ms 轮询一次以防 CPU 空转解析 JSON 后调用UpdateVote写入 Postgres先尝试INSERT若因voter_id唯一约束冲突抛出DbException则转为UPDATE——这一“插入冲突则更新”的幂等策略保证了同一浏览器不会重复计票正是 README 所述“每个客户端浏览器只接受一票”的落地实现启动时自动执行CREATE TABLE IF NOT EXISTS votes (id VARCHAR(255) NOT NULL UNIQUE, vote VARCHAR(255) NOT NULL)建表内置容错Redis/DB 连接断开时打印提示并无限重连Waiting for db/Waiting for redis并通过对 Postgres 定期执行SELECT 1保持连接活跃。3. result 前端实时聚合与展示result/server.js 是 Node.js 结果服务负责把投票数据实时推送到浏览器通过pg.Pool连接 Postgres连接串postgres://postgres:postgresdb/postgres并使用async.retry1000 次 × 1s 间隔等待数据库就绪每 1 秒执行一次SELECT vote, COUNT(id) AS count FROM votes GROUP BY vote将统计结果封装后通过 Socket.IO 以scores事件广播浏览器端 result/views/index.html 配合 result/views/app.js 订阅事件并实时刷新柱状图。4. 测试与辅助资源result/tests/ 提供针对 result 服务的渲染与功能测试tests.sh、render.js配合 docker-compose.test.yml 使用seed-data/ 包含 generate-votes.sh 与 make-data.py用于批量生成投票数据。注意事项与适用边界投票去重机制应用通过浏览器 cookie 中的voter_id结合数据库唯一约束实现“一客户端一票”不统计同一客户端的重复投票示例定位README 明确强调这不是一个架构设计完美的生产级分布式应用而是展示队列、持久化等各类组件与语言在 Docker 中以基础方式协作的简单示例部署前提Kubernetes 清单中的 NodePort 与预构建镜像要求集群节点可达Swarm 清单要求已初始化 Swarm 且不能与 Compose 混用Compose 清单需要 Docker Compose v1.27。无论是学习容器编排、体验消息队列与持久化协作还是作为多语言微服务教学模板这套 Example Voting App 都是一份可直接运行的参考实现。赞分享示例工程云原生后端【免费下载链接】example-voting-appExample distributed app composed of multiple containers for Docker, Compose, Swarm, and Kubernetes项目地址https://gitcode.com/GitHub_Trending/ex/example-voting-app点击查看免费下载相关推荐Example Voting App 项目教程从零构建分布式投票系统Example Voting App 项目教程从零构建分布式投票系统 前言为什么需要分布式投票系统 在现代Web应用开发中分布式系统已成为处理高并发、高示例工程云原生后端上一篇【亲测免费】 NomNom - No Mans Sky 专业的存档编辑器下一篇实体消歧技术详解从字符串匹配到向量重排的GraphRAG实现创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考