ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Flask与Redis容器化部署:Docker Compose多服务编排与持久化实践

Flask与Redis容器化部署:Docker Compose多服务编排与持久化实践 1. 项目概述与实验目标1.1 核心需求解析这是一个经典的容器化入门实验用 Flask 写一个 Web 应用每次访问首页时通过 Redis 的自增命令记录访问次数并在页面上展示。整个服务通过 docker-compose 一键编排启动Flask 容器和 Redis 容器各自独立运行通过 Docker 内部网络互通。别看这个实验规模不大它几乎涵盖了容器化部署的核心要素多服务编排、跨容器通信、数据持久化、依赖顺序控制、故障排查。这段时间我在本地搭这套环境时踩了不少坑从 Docker Desktop 启动失败到容器间网络不通再到 Redis 数据丢失一路排查下来收获很多。这篇博文把完整过程和调优细节整理出来涉及的工具和思路同样适用于其他 Web 应用容器化项目。先说结论这个实验非常适合三类人来动手做。一类是刚接触 Docker、想搞清楚 compose 到底怎么组织多容器的人一类是已经能跑单个容器、但没搞明白容器间如何通信和配置依赖关系的人还有一类是准备把自己的 Flask 应用容器化、但不确定 Redis 连接、数据持久化这些点怎么处理的人。做完这个实验你至少能回答三个问题compose 文件里每个字段干什么用、两个容器之间怎么互相访问、容器重启后数据去了哪里。1.2 方案选型考量为什么选 Flask Redis 而不是 Flask MySQL因为计数访问这个场景本质上是高频读写的键值操作Redis 的INCR命令是单线程原子操作天然适合计数器场景。MySQL 当然也能做但需要建表、写 SQL、维护连接对实验来说负担太重。Redis 的另一个优势是部署轻量官方镜像几百 MB 就能跑起来适合实验环境。为什么非要 docker-compose 而不是两个docker run分别启动compose 的价值在于用声明式配置取代命令式操作。两个容器分开跑不是不行但你得手动创建自定义网络、手动指定容器 IP 或者用--link参数已废弃还要记住启动顺序。compose 把这些固化到文件里一条命令拉起全部服务停止时也能按依赖关系逆序清理。对于团队协作来说这份 YAML 文件就是环境部署的唯一真相来源换台机器docker-compose up -d就复现了。顺便说一个容易混淆的点现在 Docker 官方推荐用docker compose带空格V2 插件而不是docker-compose带横线V1 独立二进制。但网上大量教程和文档还在用 V1 的写法而且某些 CI 环境里依然只有 V1。这篇实验我统一使用docker-compose命令因为兼容性更好、网上资料也最丰富如果你的环境装的是新版 Docker Desktop它内置了 compose 插件直接执行即可。2. 环境准备与基础服务搭建2.1 Docker 环境安装与验证这里只说 Linux 和 Windows 两套主流场景。Linux 环境安装 Docker Engine不同发行版的差异主要在软件源配置和包管理器上。我线上服务器用的 Ubuntu习惯直接走官方脚本curl -fsSL https://get.docker.com | sh systemctl enable --now docker如果你对官方脚本有顾虑也可以走包管理器添加 Docker 官方 GPG key、配置 apt 源然后apt install docker-ce docker-ce-cli containerd.io docker-compose-plugin。这里有个最容易踩的坑——很多教程只让你装docker-ce结果发现 compose 命令不存在就是因为少了docker-compose-plugin这个包。Windows 环境需要装 Docker Desktop。我一开始装完后启动一直失败报错信息是virtualization support not detected或者Docker Desktop failed to start because virtualisation support is disabled这通常集中在几个原因上WSL2 没启用、BIOS 里虚拟化没打开、或者 Hyper-V 没有开启。排查顺序建议这样来在 Windows 功能里勾选“适用于 Linux 的 Windows 子系统”和“虚拟机平台”重启。以管理员身份执行bcdedit /set hypervisorlaunchtype auto再重启。去 BIOS 确认 Intel VT-x 或 AMD-V 处于 Enabled 状态。执行wsl --set-default-version 2确认 WSL 默认版本是 2。这套组合拳打完Docker Desktop 基本就能起来了。验证安装是否成功用一条命令docker version docker compose version注意区分能显示 Client 和 Server 两段信息才算真正可用如果只有 Client 没有 Server说明守护进程没起来。2.2 Redis 镜像与 Flask 基础镜像选择Redis 镜像用官方redis镜像就够了不要用redis:alpine之外的奇怪变体。版本选择上redis:7和redis:6都是稳定选择实验环境直接redis:7-alpine可以减小拉取体积。对于 Linux 内核版本较旧的环境要注意Redis 7 在某些老内核上可能遇到 IO 线程相关问题保守起见用redis:6.2更稳妥。Flask 镜像的选型上有个思路值得说一下。你可以用python:3.11-slim作为基础镜像自己装 Flask也可以直接用现成的python:3.11-alpine。我实际用的是前者因为 alpine 虽然小但在编译某些 Python 依赖时需要装gcc musl-dev这类编译工具Python 基础镜像是 Debian 系的apt install装构建依赖更容易。还有一个容易忽视的点镜像 tag 一定要固定。用latest标签图省事的后果是某天团队里有人pull到一个新版本Redis 或 Python 版本变了整个环境行为就不可预测了。生产环境锁 tag实验环境哪怕不锁心里也要有数。3. 核心服务实现与细节打磨3.1 Flask 应用代码编写应用逻辑本身很简单建立 Redis 连接、在路由中执行INCR命令、获取当前计数并返回页面。但“简单”不等于“随便写”有几个细节直接影响后续容器化部署的稳定性。先看基础版本的app.pyimport os import redis from flask import Flask app Flask(__name__) # 从环境变量读取 Redis 连接信息这是容器化部署的关键 redis_host os.getenv(REDIS_HOST, localhost) redis_port int(os.getenv(REDIS_PORT, 6379)) # 创建 Redis 连接 r redis.Redis(hostredis_host, portredis_port, db0, decode_responsesTrue) app.route(/) def index(): count r.incr(page_visits) return fTotal visits: {count} if __name__ __main__: app.run(host0.0.0.0, port5000, debugFalse)这里有两个关键点。第一host0.0.0.0是必须的。默认 Flask 只监听 127.0.0.1在容器里这样写意味着外部根本访问不到。很多新手容器启动成功但访问不了排查半天发现是这里的问题。第二Redis 地址不能硬编码成localhost。因为 Flask 容器和 Redis 容器是独立的两个容器localhost指向的是 Flask 容器自身这个地方必须通过环境变量注入compose 文件里会相应配置。第二个版本加入连接池这是生产环境更合理的做法import os import redis from flask import Flask app Flask(__name__) redis_host os.getenv(REDIS_HOST, localhost) redis_port int(os.getenv(REDIS_PORT, 6379)) # 连接池配置 pool redis.ConnectionPool( hostredis_host, portredis_port, db0, max_connections20, decode_responsesTrue ) r redis.Redis(connection_poolpool)为什么要单独讲连接池Flask 默认是多线程处理请求的如果每个请求都创建新的 Redis 连接高并发下会大量产生 TCP 连接Redis 端的文件描述符会很快耗尽响应也跟着变慢。连接池复用一定数量的连接性能提升非常明显。但要注意max_connections不是越大越好——每个连接在 Redis 服务端都要占用内存理论上单机几万个连接没问题但实验项目开到 20 就够了。3.2 Redis 计数器实现原理访问计数用 Redis 的INCR命令这条命令的语义是对 key 的值做原子加 1 操作。为什么强调“原子”因为如果多个请求同时到达两个线程同时读到一个值N各自加 1 后写回结果可能还是N1而不是N2。Redis 是单线程执行命令的INCR在执行时不会被其他命令打断天然避免了竞态问题。存储结构上计数器的 key 就是一个普通的 Redis 字符串。如果之前 key 不存在INCR会将其初始化为 0再执行加 1 操作。这里涉及到一个值得考虑的点key 命名规范。用page_visits作为 key 名在实验环境没问题但真实项目建议用命名空间前缀比如stat:page:visits方便后续和其他统计 key 区分。如果要看当前计数而不增加它用GETcurrent r.get(page_visits)这里有个类型陷阱。当 Redis 设置了decode_responsesTrue时GET返回的是字符串类型比如42不是整数。做数值比较或计算时记得转换。我在实验里吃过这个亏直接把GET结果和整数比较Python 里字符串和整数比较不会报错但结果永远是 False排查了半天才发现类型问题。4. 编写 docker-compose 编排文件与启动部署4.1 工程目录结构与 requirements 清单开始编写 compose 文件之前先整理好项目目录结构。一个清晰的目录结构能让后续维护省很多事也方便别人看懂项目flask-redis-counter/ ├── docker-compose.yml ├── app/ │ ├── Dockerfile │ ├── requirements.txt │ └── app.pyrequirements.txt是 Python 依赖清单这个实验只需要两个依赖flask3.0.3 redis5.0.7锁版本号是必须的。如果写成flask3.0哪天 Flask 出了新版本把接口改动了应用很可能起不来。锁版本看似保守实则是可控性的保障部署环境的确定性永远优先于新功能的追逐。Dockerfile这样写FROM python:3.11-slim WORKDIR /app COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt COPY app.py . EXPOSE 5000 CMD [python, app.py]--no-cache-dir参数可以显著减小镜像体积尤其在使用 slim 基础镜像时不清理 pip 缓存会让镜像膨胀不少。WORKDIR /app设定了容器内的工作目录后续执行命令都以这里为基准。如果后续要加非 Python 依赖改造时还要注意一个顺序问题把依赖安装放在源码复制前面因为 Docker 构建是有层缓存的requirements.txt没变时pip install这层可以复用缓存加快多次构建速度。4.2 docker-compose.yml 细节逐行解析compose 文件是整个实验的核心配置我用 V3 版本来写version: 3.8 services: redis: image: redis:7-alpine container_name: flask-redis-counter-redis restart: unless-stopped ports: - 6379:6379 volumes: - redis_data:/data command: [redis-server, --appendonly, yes] web: build: ./app container_name: flask-redis-counter-web restart: unless-stopped ports: - 5000:5000 environment: - REDIS_HOSTredis - REDIS_PORT6379 depends_on: - redis volumes: redis_data:每个字段都不是随便写的逐个来说version: 3.8是 compose 文件规范版本。现在 Docker 官方对新项目更推荐省略version字段直接写结构因为新版本 compose 已经不再依赖这个字段。如果你用的是 Docker Desktop 自带的 compose V2省略version完全没问题。但考虑到网上 V1 资料还很多保留version: 3.8的兼容性更好。container_name给容器固定一个名字。不指定的话 compose 会自动生成项目名_服务名_序号这种格式排查日志时不好记。固定名字的代价是不能用同一个 compose 文件在同一台机器上启动多套环境但实验场景完全够用。restart: unless-stopped设置了容器的重启策略。容器进程崩溃或服务器重启后守护进程会自动拉起容器。对于依赖 Redis 的场景Redis 容器先启动、Flask 后启动这套策略在后面會讲一个关键坑。ports端口映射是重点。6379:6379表示把容器内的 6379 端口映射到宿主机的 6379 端口。生产环境要慎重——数据无加密时库被直接暴露在宿主机网络上扫描到端口就能连上来。实验环境图方便可以这样做但我更建议 Redis 端口只做容器间通信不映射到宿主机。改动也很简单ports那行注释掉或删掉web 容器通过 compose 内部网络照样能访问 Redis。Flask 的 5000 端口必须映射出来否则外部访问不到。volumes数据卷挂载是持久化的关键。Redis 容器用volumes把宿主机上的redis_data卷挂载到容器内/data目录。Redis 的 RDB 快照和 AOF 日志默认写入/data目录只要这个目录落盘到持久化存储容器删了重建数据都在。compose 文件末尾的顶级volumes声明是告诉 Docker“我要创建一个命名卷”命名卷的优点是 Docker 自动管理存储位置不需要你手动指定宿主机路径。command: [redis-server, --appendonly, yes]覆盖了镜像默认的启动命令。这里做了两件事以redis-server启动并且开启 AOF 持久化。官方镜像默认只开了 RDB 快照RDB 的缺点是两次快照之间的数据可能丢失AOF 则记录每一次写操作。对于计数器这种高频繁的小写入AOF 更合适即使容器重启或崩溃最多丢一两个计数。environment环境变量是容器间通信的关键联系。REDIS_HOSTredis的值为 Redis 服务的服务名compose 会自动创建一个默认网络服务名在 DNS 层面对应到容器 IP。所以 Flask 应用代码里的os.getenv(REDIS_HOST, localhost)会拿到redis这个值再通过这个值解析到 Redis 容器的内网 IP。depends_on指定依赖关系。compose 会先启动 Redis、再启动 Flask。然而这个字段只保证启动顺序不保证 Redis 已经处于可服务状态——Redis 容器启动到真正能接受连接中间还有几秒初始化时间。如果你实验时 Flask 一直报Connection refused大概率不是 Redis 没启动而是 Redis 还没准备好。4.3 解决依赖启动顺序问题针对depends_on的局限有几种常见解法。最轻量的是在 Flask 启动脚本里加一个“等待 Redis 就绪”的循环逻辑。在app.py中增加一段启动检查import time import redis def wait_for_redis(client, timeout30): start time.time() while time.time() - start timeout: try: client.ping() return True except redis.ConnectionError: time.sleep(1) return False然后在初始化代码里调用if not wait_for_redis(r): raise RuntimeError(Redis connection failed after timeout)对实验项目来说这个方案简单直接——应用启动进程不会被立即 kill而是等到依赖可用再继续。更完整的做法是用healthcheck命令配合 compose 的depends_on条件判断services: redis: ... healthcheck: test: [CMD, redis-cli, ping] interval: 5s timeout: 3s retries: 5 web: ... depends_on: redis: condition: service_healthy这种方式下compose 会定期执行redis-cli ping只有返回PONG才认为健康web 服务才会开始启动。生产环境推荐后者实验环境用启动等待逻辑就足够了。4.4 启动、验证与日志跟踪文件都准备好后在项目的根目录执行docker-compose up -d-d表示后台运行。建议第一次启动时去掉-d直接前台启动docker-compose up前台启动能看到所有容器的实时日志输出方便直观确认两个容器都正常起来了。确认没问题后再CtrlC停掉重新执行docker-compose up -d转后台。启动过程中需要关注的几种状态Creating network flask-redis-counter_default说明 compose 自动创建了默认网络两个容器都会连进来。Creating volume flask-redis-counter_redis_data命名卷创建成功。Creating flask-redis-counter-redis和Creating flask-redis-counter-web顺序应该是 Redis 先、web 后。容器都启动后用docker-compose ps查看状态两行都显示Up就算成功。然后用浏览器访问http://localhost:5000每次刷新页面访问次数都会递增。验证 Redis 里的实际数据用宿主机上的redis-cli连接如果在宿主机装了 redis-tools直接redis-cli GET page_visits就可以查看。没装的话进容器操作docker exec -it flask-redis-counter-redis redis-cli GET page_visits docker exec -it flask-redis-counter-redis redis-cli INCR page_visits docker exec -it flask-redis-counter-redis redis-cli TTL page_visits用 Redis Desktop Manager 可视化查看也可以。连接时注意 Host 填127.0.0.1因为做了端口映射Port 填6379。如果连不上先排查防火墙是否放行了 6379 端口或者 Redis 是否真的在监听。5. 性能调优与实际踩坑排查5.1 Redis 持久化策略与数据可靠性调试这套实验里最容易翻车的就是数据持久化。我前面提到容器删除或重建后计数归零的问题归零的根源在于Redis 默认启动配置不满足你的数据安全预期。先理解 RDB 和 AOF 的区别。RDB 是定时把内存数据全量快照到磁盘默认配置是“如果 900 秒内至少有 1 次写操作或者 300 秒内至少有 10 次写操作或者 60 秒内至少有 10000 次写操作就触发快照”。这种策略下如果 Redis 突然崩溃最后一次快照之后的写入全部丢失对于访问计数场景你损失的是“最近一小时甚至几分钟的访问数据”。AOF 则不同——每个写命令先追加到日志文件Redis 重启时按日志重放恢复数据。AOF 有三个刷盘级别always每命令都刷盘性能最差但数据最安全everysec每秒刷一次性能和数据安全比较均衡no交给操作系统决定刷盘时机数据可能丢最多。我在 compose 文件里用的--appendonly yes默认策略就是everysec丢数据的窗口控制在 1 秒内对计数场景完全够用。但还有一个细节值得展开持久化策略不只是开不开的问题还涉及触发频率。如果访问量极高每分钟上万次写入RDB 快照策略里的“60 秒内 10000 次写操作”条件会频繁触发每次快照都 fork 一个子进程把全量内存写到硬盘性能会有明显波动。AOF 的日志文件会持续增长容器长期运行后要注意文件膨胀问题。Redis 的BGREWRITEAOF命令可以重写日志文件压缩掉中间废弃的写命令。更省心的做法是在 compose 命令里覆盖 Redis 配置command: redis-server --appendonly yes --appendfsync everysec --auto-aof-rewrite-percentage 100 --auto-aof-rewrite-min-size 64mb这样配置完后即使 AOF 日志里充满了大量INCR page_visits命令重写发生时 Redis 会读当前内存状态直接生成一条“当前计数是多少”的记录日志体积得到有效控制。5.2 Redis 内存淘汰策略与 key 过期机制计数器的 key 会不会无限增长导致内存溢出这个担心要分情况讨论。单个计数器 key 无论加多少次这个 key 都只占一条记录的内存空间不会膨胀。但如果你在实验基础上扩展了功能——比如按用户 IP 分别计数、按日期分别计数——key 数量会随维度增长这时就要考虑内存淘汰策略了。Redis 的maxmemory参数控制最大内存超过后根据淘汰策略清理 key。Redis 7 默认策略是noeviction即内存满了后写入操作直接报错。实验环境触发这种情况很不友好——你的 Flask 应用调用INCR会突然抛OutOfMemory页面直接 500。推荐在 compose 里设置--maxmemory 128mb --maxmemory-policy allkeys-lru这样即使后续扩展了大量 keyRedis 也会自动淘汰最久没访问的 key 腾出空间服务不会中断。再说 key 过期。如果你把计数按天统计比如visits:2025-01-15就涉及到了EXPIRE命令r.incr(visits:2025-01-15) r.expire(visits:2025-01-15, 86400 * 2)expire设置过期时间单位为秒。Redis 删除过期 key 有两种机制惰性删除访问时发现已过期才删除和定期删除后台每隔一段时间扫描过期 key。两种机制下过期 key 都不会立即物理消失如果你短时间内用DBSIZE查看可能会看到过期 key 还在这是正常现象。5.3 高频并发下的 Redis 连接调优实验环境在本地跑并发量不大但如果你把这个实验搬到线上环境压测有几个参数值得提前调好。先是 Redis 连接数上限。Redis 配置里的maxclients默认是 10000看起来很多但要注意 Redis 是单线程处理命令的连接数越多上下文切换和 IO 多路复用的压力越大。实际经验是压测到几千并发连接时Redis 的吞吐量会先下降。这时候不是调大maxclients的事而是从应用侧减少连接占用——用连接池并且合理控制max_connections每个线程复用连接而不是新建连接。Flask 侧的连接池参数也要根据并发量调整。max_connections20在本地够用但如果压测时模拟了 50 个并发请求连接池不够就会排队等待。池不是越大越好如果同时有 100 个并发请求每个请求都拿着连接做 Redis 操作Redis 服务端同时处理 100 个连接的命令效果比 20 个连接排队差。合适的策略是把max_connections设置为并发数的 1/4 左右或者干脆根据压测结果来定——从 20 开始逐步加压观察响应时间拐点在哪里。还有一个容易被忽视的参数是 Redis 的timeout默认是 0表示空闲连接从不关闭。如果应用和 Redis 之间有防火墙或负载均衡设备空闲连接可能被中间设备断开但 Redis 端不知道后续使用这个连接时会报Connection reset by peer。设置--timeout 300让空闲 5 分钟以上的连接被 Redis 主动关闭应用侧连接池会自动重建连接反而更稳定。5.4 常见问题与排查技巧实录搭建和调试过程中我整理了高频问题基本都是前置踩坑总结出来的直接上个速查表现象可能原因排查命令解决方式Docker 启动失败报 virtualization 错误BIOS 未开启虚拟化WSL2 未启用systeminfo或 BIOS 检查开启 BIOS 虚拟化安装 WSL2docker-compose命令不存在未安装 compose 插件docker compose version安装 docker-compose-pluginFlask 容器启动后立即退出Redis 未就绪时 Flask 连不上进程崩溃docker-compose logs web加入等待 Redis 逻辑宿主机访问localhost:5000拒绝连接Flask 未监听 0.0.0.0docker exec -it web python -c import socket; print(socket.gethostbyname(socket.gethostname()))修改app.run(host0.0.0.0)Redis 连接报Connection refused端口未映射或防火墙拦截docker-compose ps查看端口映射检查ports配置和防火墙规则Redis 容器重启后计数全部丢失RDB 快照丢失两快照之间数据docker exec redis redis-cli info persistence开启 AOF 持久化多个 Redis 连接报MISCONF错误maxmemory满了且淘汰策略为 noevictionredis-cli info memory设置maxmemory-policy allkeys-lru页面报 500日志里有 ModuleNotFoundErrorrequirements.txt漏掉依赖或版本冲突docker logs web查看 traceback补齐依赖锁定版本除了表格里的清单有几个排查思路值得单独分享。第一个是查看日志的方法。docker-compose logs -f web可以实时跟踪 Flask 容器日志--tail100显示最后 100 行。排查启动问题时先看 web 容器日志因为 Redis 容器一般不会挂错误信息几乎都出现在 Flask 容器里。如果日志被清空了用docker inspect flask-redis-counter-web查看容器状态和重启次数RestartCount的值如果大于 1说明容器反复重启通常意味着启动命令瞬间失败。第二个是网络连通性排查。容器间网络不通时在 Flask 容器里直接 ping Redis 服务名docker exec -it flask-redis-counter-web ping redis如果 ping 不通或者解析不了redis这个主机名说明 web 容器和 redis 容器不在同一个 compose 网络里。检查docker-compose ps里两个容器的 NETWORK 字段是否为同一个网络。有时候手贱给容器单独执行了docker network disconnect就会导致这种问题。第三个是宿主机端口冲突。ports映射的宿主机端口如果已经被别的进程占用compose 会启动失败。执行docker-compose logs redis会看到类似bind: address already in use的报错。解决方式是把宿主机端口改掉比如5001:5000容器内走 5000 不变外部访问改走 5001。这个思路也可以推广到多套环境共存的情况。第四个是数据卷残留问题。我之前多次docker-compose down再up发现旧容器虽然删了但数据卷还在。down默认不会删除命名卷这是为了数据安全的设计。但如果代码里持久化了错误的测试数据需要用docker-compose down -v连数据卷一起删掉。这个命令属于破坏性操作执行前确认你真的不需要卷里的数据。6. 优化方向与扩展场景实验项目跑通只是起点这个架构可以横向扩展出很多实用功能。把访问计数做成多维度的统计在原来的基础上加个按用户 IP 计数的功能from flask import request app.route(/) def index(): user_ip request.remote_addr total r.incr(stat:page:total) user_count r.incr(fstat:page:user:{user_ip}) r.expire(fstat:page:user:{user_ip}, 3600) return fTotal: {total}, Your visits in this hour: {user_count}这里涉及到两个稍微进阶的用法字符串拼接的复杂 key、expire设置过期时间。stat:page:user:192.168.1.100这种 key 在 Redis 里存的是字符串冒号分割是 Redis key 的常见命名习惯便于可视化工具里按层级查看。再进一步把 Flask 容器做成可扩展的 Web 服务需要引入 Nginx 反向代理和 Gunicorn 多进程。原来的python app.py用的是 Flask 内置的开发服务器单进程性能有限不适合真实流量场景。生产级别的 Dockerfile 里你会看到类似这样的启动命令CMD [gunicorn, -w, 4, -b, 0.0.0.0:5000, app:app]-w 4开 4 个 worker 进程每个 worker 是独立进程配合连接池才能充分利用多核 CPU。这也是为什么连接池要设置成 20——4 个 worker 每个平均 5 个连接总数合理。如果不开连接池每个 worker 每个请求新建连接高并发下崩溃的概率呈指数增长。前面这些都是围绕同样的架构做增强你还可以往里面加 Celery 做异步任务、加 Nginx 做负载均衡但核心的容器编排思路——服务拆分、网络互通、依赖管理、数据持久化——一套实验全部涵盖。把这套思路想透了后续做任何多容器项目你都会自然地先思考容器间怎么通信、数据怎么持久化、服务怎么编排这些比任何单一技术都更值钱。按照我自己的迭代经验这类实验有一个特别适合的演进路径先把单机版跑顺接着加反向代理容器再做服务发现最后上 Kubernetes。每一步的坑都不一样但踩坑的方式是相通的——多看日志按依赖顺序排查理解每个配置参数背后的真实行为基本上都能自己解决。
返回列表