ARTICLE DETAIL

资讯详情

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

本地开发利器:Docker Compose + 免费公网映射实现远程联调

本地开发利器:Docker Compose + 免费公网映射实现远程联调 上周跟外地的同事联调一个支付回调本地起的服务怎么都到不了对方那边。折腾了半天在路由器里找端口映射发现运营商给的本来就是私网地址公网根本进不来。后来想明白了一个道理像这种“让别人临时访问我本地服务”的需求压根不用去碰公网IP本地服务器用Docker跑起来再挂一条免费公网地址映射链接发过去问题十分钟就解决了。这套流程我后来固定成了模板不管换哪台电脑从零到能给别人演示基本就是一杯茶的功夫。这套组合看起来是把三个名词堆在一起本地搭建项目运行服务器、免费公网地址映射、Docker。实际上它们是一条完整的链路Docker负责把项目环境打包成标准化的“集装箱”本地服务器把容器里的服务在开发机上跑起来公网地址映射再给这个“只在你电脑上”的服务补一个公网入口让同事、客户、第三方平台都能访问到你。三个环节各管一段缺一个都不舒服。这篇文章适合这么几类人一个人管好几个项目的全栈或后端开发需要远程联调的团队成员准备做毕设或者作品集、想在简历里放一个可访问链接的学生。跟着走一遍你能在一台比较干净的系统上用Docker Compose一键起一套包含MySQL、Redis、后端、Nginx的完整运行环境然后把任意一个端口映射成公网链接演示完一键停掉不给系统留下垃圾。1. 先拆思路三个工具是怎么串成一条链路的1.1 没有Docker时本地起服务器的四个老毛病先说Docker解决了什么。以前我习惯直接在电脑上装环境刚开始觉得挺方便项目多了以后就苦不堪言。第一个毛病是版本冲突。一个项目要Node 14另一个要Node 18切换起来焦头烂额数据库更典型项目A用的是MySQL 5.7SQL里依赖了老版本的排序规则项目B要求MySQL 8.0同一个数据库装两个版本共存依赖、端口、配置文件处处打架。我印象最深的一次是为了让两个项目共存把系统搞到连不上网最后重装系统收场。第二个毛病是环境不一致。同一个项目在我电脑上跑得好好的同事拉下来就报错最后排查半天发现他少了某个系统库或者Redis版本不对。一个人开发的时候这个问题不明显一旦上了团队协作每天光“我这边可以跑啊”这句话就要说十遍。第三个毛病是迁移成本高。换电脑或者换服务器等于把所有环境重装一遍。更头痛的是你根本记不全当初装了哪些东西——有些依赖是项目明确写的有些是当年临时装完就忘掉的等到新机器上缺少某个运行库时你才想起来原来还有这么个东西存在。第四个毛病是清理不干净。想卸载某个服务删了安装目录、清了缓存总觉得已经弄干净了可过几天端口还是被占注册表或者系统服务里还留着残留。尤其是Windows上装Linux工具集各种二进制混在一起想彻底恢复干净只能重装系统。Docker把这些问题全打包解决了。容器里跑什么版本、用哪个运行时跟宿主机完全隔离环境打包成镜像之后团队每个人拿到的都是同一个东西换机器只需要把镜像或Compose文件搬过去pull一下就能跑不用了直接删容器删镜像干净利落。类比一下以前是往自己家里搬各种家电装一个就要占一块地方现在是租集装箱每个项目的东西都封在自己箱子里用哪个开哪个。1.2 公网地址映射解决的是“让别人访问你”很多人把公网地址映射理解成“加快访问速度”或者“代理”其实方向搞反了。它解决的核心问题是让公网上的其他人能够访问到跑在你本地电脑上的某个端口。为什么默认访问不到因为你电脑上的服务监听的是localhost或者内网IP这个地址在整个局域网之外是不可路由的。运营商给你的是共享带宽下的私网地址路由器把内网机器藏在NAT后面外面的人根本没有一条路走到你家路由器更别说走到你电脑上了。即使你有公网IP顺手一查防火墙规则、拨号IP是否固定、入站端口是否被运营商默认屏蔽又是一个深坑。免费公网地址映射工具的工作原理并不神秘本地客户端主动向服务商的服务器发起一条长连接服务商分配给你一个公网可访问的地址当有人访问这个地址时流量被服务商的服务器沿着这条长连接转回你本地的指定端口。说白了就是你主动连它别人通过它来连你。它专门用来解决“自己被别人访问”的难题。什么场景下特别需要它第一是回调接口。微信支付、支付宝、第三方登录平台会往你配置的URL发请求这个URL必须是公网能访问的而开发阶段你的服务往往在本地。没有映射工具这类功能根本没法联调。第二是给异地同事或客户演示。发一个链接过去对方浏览器直接打开不需要远程桌面不需要录视频所见即所得。第三是前后端分离联调。前端在另一个城市后端在你电脑上或者反过来用一个公网地址把两边串起来。第四是个人作品展示。简历里放一个“在线体验地址”比一堆截图有说服力得多。1.3 为什么是“本地映射”而不是直接上云服务器有人会问既然最终目的是让公网能访问为什么不直接把服务部署到云服务器上买一个固定公网IP多省事这个问题的答案取决于你的使用频率和预算。我从实际体验出发做一张对比表对比项本地Docker 免费公网映射云服务器部署环境准备速度分钟级拉镜像起容器即可先买服务器、选系统再配环境小时级持续成本基本免费只花本地电费每月少则几十配置高则几百公网访问稳定性免费版有限流和随机域名适合联调演示固定IP稳定适合正式跑业务带宽资源取决于本地宽带上行看服务器规格通常不大适用场景开发联调、临时演示、轻量访问正式上线、持续提供服务所以这不是一个非此即彼的选择题而是先后顺序的问题先在本地把环境和服务跑通再考虑要不要上云。很多项目根本活不到需要云服务器的阶段花几十块钱买一台服务器只为了演示一次其实不划算。等到项目确认要长期跑、访问量稳定了再迁移到云服务器也完全来得及——Docker镜像保证了你在哪里部署行为都是一样的。2. Docker环境搭建装好、配好、三个报错别慌2.1 Windows、macOS、Linux三平台安装要点Docker的安装方式跟系统强相关分开说。Windows目前主流方案是装Docker Desktop底层引擎用WSL2。先确保系统满足基本要求Windows 10 64位、2004版本以上或者Windows 11。装之前最好先执行一次WSL更新管理员PowerShell运行wsl --install装完重启再安装Docker Desktop。安装包下载完成后一路Next首次启动会提示选择使用WSL 2还是Hyper-V选WSL 2。如果之前没启用过“虚拟机平台”和“适用于Linux的Windows子系统”安装向导会引导你开启。开启后需要再重启一次。常见的一个检查项任务管理器 性能 CPU看“虚拟化”这一项是否显示“已启用”。如果显示“已禁用”要去BIOS里打开Intel VT-x或AMD SVM否则Docker Desktop会直接罢工。macOSmacOS的Docker Desktop区分Apple Silicon和Intel芯片下载时注意选对版本。安装包是dmg拖进应用程序即可。首次启动后会申请权限输入密码授权。建议在设置里把内存调到6到8GB因为默认的2GB跑Java或Node项目会比较吃力。LinuxUbuntu/Debian和CentOS的安装命令不同。Ubuntu走官方Docker仓库最省心sudo apt-get update sudo apt-get install ca-certificates curl gnupg lsb-release sudo mkdir -p /etc/apt/keyrings curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg echo deb [arch$(dpkg --print-architecture) signed-by/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable | sudo tee /etc/apt/sources.list.d/docker.list /dev/null sudo apt-get update sudo apt-get install docker-ce docker-ce-cli containerd.io docker-compose-pluginCentOS用yum加仓库sudo yum install -y yum-utils sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo sudo yum install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin sudo systemctl enable --now docker装完Linux别忘了把当前用户加进docker组不然每条命令都要sudo后面讲报错时会详细说。2.2 搜索引擎里最常被搜的三个Docker安装报错报错一docker desktop failed to start because virtualisation support wasnt detected这个报错基本是Windows用户的噩梦原因就是虚拟化没开。排查顺序如下先看任务管理器里“虚拟化”是否启用没启用就进BIOS开启VT-x或AMD SVM。如果是虚拟机里再装Docker Desktop需要在宿主机虚拟机设置里开启“嵌套虚拟化”。确认“虚拟机平台”和“适用于Linux的Windows子系统”这两项Windows功能都是勾选状态。控制面板 程序和功能 启用或关闭Windows功能里操作。如果以上都正常去微软官网手动安装WSL2内核更新包重启后再试。报错二permission denied while trying to connect to the docker api at unix:///var/run/docker.sock这个报错在Linux上极为常见原因是当前用户不在docker组里。Docker守护进程的socket文件只允许root和docker组的用户访问普通用户执行docker命令就会收到这个错误。修法sudo usermod -aG docker $USER newgrp docker执行完重新登录终端再跑docker ps验证。这个坑几乎每个Linux新人都踩搜这个报错的人特别多遇到别慌一行命令的事。报错三failed to start docker application container engine这个报错比较笼统Windows和Linux都可能出现。常见原因有旧的Docker Desktop版本和当前Windows版本不兼容、磁盘空间不足、第三方安全软件拦截了docker进程。处理思路是按顺序排查重启Docker Desktop等一分钟看是否恢复。确认系统盘剩余空间Docker镜像和容器日志很占磁盘低于10GB就可能启动失败。退出Docker Desktop删除C:\Users\你的用户名\AppData\Local\Docker下面的缓存目录再启动。还不行就直接卸载重装最新版很多诡异问题重装后自然消失。另外镜像下载慢也要一并处理。这不算报错但会让人误以为装失败了。配置镜像加速器Linux直接修改/etc/docker/daemon.json{ registry-mirrors: [ https://docker.m.daocloud.io, https://docker.nju.edu.cn ] }然后sudo systemctl daemon-reload sudo systemctl restart dockerWindows下是在Docker Desktop的Settings Docker Engine里直接编辑JSON保存后Apply Restart。不同地区的网络对不同镜像站的支持情况不一样一个不行就换一个基本上换了加速器之后拉大型镜像的速度是天壤之别。2.3 装完先验三件事顺手记住一组高频命令装完Docker后别急着跑业务先做三个验证docker version正常输出包含Client和Server两个部分如果只出现Client没有Server说明守护进程没起来。docker run hello-world能拉下镜像并打印一段欢迎信息证明容器能创建能运行这一步是完整流程的最低验证。docker compose version确认Compose插件装好了后面编排多个容器需要用到。Docker命令数量多新手容易记混真正高频的就那么几条我用表列一下命令作用docker ps查看运行中的容器docker ps -a查看所有容器包括已停止的docker images查看本地镜像列表docker logs -f 容器名跟随查看容器日志排错必备docker exec -it 容器名 bash进入容器内部执行命令docker stop 容器名停止容器docker start 容器名启动已停止的容器docker rm 容器名删除容器docker compose up -d按Compose配置启动所有服务docker compose down停止并移除配置中的容器和网络docker compose logs -f查看整个编排的日志经验之谈不用的容器和镜像要定期清理容器还好镜像和日志文件是真的吃磁盘。跑上几个月不管随便就能占几十个GB。3. 用Docker Compose把项目服务器完整跑起来3.1 为什么选Docker Compose而不是裸用docker run单容器场景用docker run没问题但真实项目的服务从来不止一个数据库、缓存、后端、前端静态资源每个都要单独跑而且它们之间有依赖关系有同一个网络端口还可能互相引用。如果全部用docker run手敲一条命令两三行长四个服务就是四行超长命令每次启动要重新记一遍参数换个环境配置全变。这种命令没写几天自己都不想看。Docker Compose把这一切变成一份YAML配置文件。所有服务、镜像、端口映射、数据卷、环境变量、依赖关系写在一个文件里一条docker compose up -d全部搞定。团队协作时只需要把一个docker-compose.yml丢到群里别人拉下来就能起环境。更好的地方在于Compose会给这些容器自动创建一个网络容器之间用服务名互相访问不需要查IP地址。比如后端容器要连数据库连接串里写mysql:3306就行而这个mysql正是Compose文件里定义的服务名。这个机制让配置变得非常清晰可读性比一堆docker run参数高太多。用一句话概括区别docker run是点菜一道一道报菜名Compose是配好的套餐一个按钮全上齐。3.2 一份可直接修改的四服务Compose配置以最典型的前后端分离项目为例我直接把配置贴出来这套结构我反复用了很多次注释写在关键位置version: 3.8 services: mysql: image: mysql:8.0 container_name: demo-mysql restart: unless-stopped environment: MYSQL_ROOT_PASSWORD: root123456 MYSQL_DATABASE: demo MYSQL_USER: demo MYSQL_PASSWORD: demo123 ports: - 3306:3306 volumes: - ./mysql-data:/var/lib/mysql command: - --character-set-serverutf8mb4 - --collation-serverutf8mb4_unicode_ci redis: image: redis:7-alpine container_name: demo-redis restart: unless-stopped ports: - 6379:6379 volumes: - ./redis-data:/data command: redis-server --appendonly yes backend: image: node:18-alpine container_name: demo-backend working_dir: /app volumes: - ./backend:/app ports: - 8080:3000 command: sh -c npm install npm run dev depends_on: - mysql - redis nginx: image: nginx:1.25-alpine container_name: demo-nginx ports: - 80:80 volumes: - ./nginx.conf:/etc/nginx/conf.d/default.conf - ./frontend:/usr/share/nginx/html depends_on: - backend逐项解释几个关键点。端口映射的格式是宿主机端口:容器端口冒号左边是外部访问的入口右边是容器内部服务监听的端口。宿主机的3306映射到容器MySQL的3306宿主机的8080映射到后端容器的3000宿主机的80映射到Nginx的80。如果宿主机3306已经被本机MySQL占了可以把左边改成3307不影响容器内部逻辑。数据卷是容器持久化的关键。容器本身是临时产物删除后数据会消失所以MySQL和Redis的数据目录要挂载到宿主机目录我用的是相对路径./mysql-data和./redis-data在本目录下会自动创建。删容器不删数据下次重新起来数据还在。depends_on表示启动顺序的依赖关系后端先依赖数据库和缓存起来。但要注意它只保证“先启动”不保证数据库“已经就绪”所以后端代码里最好有重连机制或者配合restart策略让它自己恢复。Nginx的配置单独写一个nginx.conf文件再挂载到容器里。示例配置server { listen 80; location / { root /usr/share/nginx/html; index index.html; } location /api/ { proxy_pass http://backend:3000; } }注意proxy_pass里写的是http://backend:3000这个backend是Compose网络里的服务名Nginx容器和backend容器在同一个自定义网络里所以可以直接这样访问。如果写成127.0.0.1:3000在Nginx容器里访问的其实是它自己请求就会失败——这个坑我被绊过好几次。后端用的镜像是node:18-alpine如果你的后端是Java、Go、Python换成对应镜像就行核心逻辑是挂载源码目录、映射端口。开发阶段用挂载方式改代码即改即生效但正式部署建议先构建成镜像再跑不要在容器里现装依赖。3.3 启动、验证、备份与停止的完整动作启动docker compose up -d-d表示后台运行不加的话会前台占用终端日志直接刷屏CtrlC就会停掉所有服务。后台运行之后想看状态docker compose psSTATUS列全部显示Up基本就正常了。然后逐个验证访问链路的每一环curl http://localhost curl http://localhost/api/health第一个验证前端静态页面是否正常第二个验证Nginx反代到后端是否通。确保宿主机的3306和6379端口没有冲突的情况下本地数据库客户端也能直接连容器里的MySQL和Redis。如果本地没有数据库客户端就在容器里验证docker exec -it demo-mysql mysql -uroot -proot123456 -e show databases;日志排查时用docker compose logs -f backend docker compose logs -f nginx-f是跟随模式日志会实时滚动接口调不通时先看这里。停掉的命令要分清两种docker compose down这个命令停止并移除容器和网络但保留数据卷里的数据重启后数据还在。如果要连数据一起删掉需要手动删除./mysql-data目录。执行down之后想重新起一条docker compose up -d数据自动回来。数据备份建议用mysqldump比直接拷数据目录更保险因为直接拷目录如果MySQL还在运行可能复制到不一致的状态docker exec demo-mysql mysqldump -uroot -proot123456 demo backup.sql整体看下来这套流程本质上就是把“配环境”这件事抽象成了一堆声明式文件环境是代码的一部分走到哪里都带着走。4. 免费公网地址映射实操把localhost变成公网链接4.1 免费工具横向对比cpolar、ngrok、花生壳公网映射工具市场上不少我实际用下来最适合配合Docker做开发联调的是命令行风格的工具。做一张对比表工具是否需要注册免费版特点适合场景cpolar是随机域名有流量限制跨平台命令行国内访问较稳个人演示ngrok是随机域名1个并发连接带请求检查面板接口联调、Webhook调试花生壳是客户端式操作免费带宽较低个人网站、远程桌面等简单场景工具选择没有绝对优劣。cpolar对国内网络的连通性普遍更友好ngrok的Request Inspector功能对调接口很有帮助花生壳适合不想敲命令的人。我这里重点讲cpolar和ngrok因为它们是命令行工具可以脚本化能跟Docker启动流程串起来。再强调一个免费版的通病域名是随机的重启隧道后地址会变。所以免费映射最适合的场景是“临场联调”和“短期演示”不适合当作长期在线服务。需要固定地址且流量不大的可以看看各家的付费套餐一旦业务量上来还是老老实实上云服务器加反向代理。4.2 cpolar完整流程注册、认证、启动一条隧道先在cpolar官网注册账号注册后控制台里能找到authtoken。然后在你的机器上安装客户端。Windows直接下载安装包装好后在命令行里执行cpolar authtoken 你的TokenLinux用命令安装curl -L https://www.cpolar.com/static/downloads/releases/cpolar-stable_linux_amd64.tgz | tar -xz sudo cp ./cpolar /usr/local/bin/cpolar cpolar authtoken 你的Token认证只需要做一次Token会保存在本机配置里。然后启动隧道把本地的8080端口映射到公网cpolar http 8080终端会输出一段信息重点看这两行Tunnel Status online https://xxxxxxxx.cpolar.cn - http://localhost:8080复制https://xxxxxxxx.cpolar.cn这个地址打开浏览器访问就相当于访问你本地的8080端口。如果你的服务跑在Docker容器里链路是这样子的公网用户访问cpolar地址cpolar服务端把流量转发到本机cpolar客户端cpolar客户端再把流量打到localhost:8080也就是宿主机端口而宿主机8080映射到了Docker容器内部的3000端口。整条链路是通的不需要在容器里再装任何映射工具。cpolar默认前台运行关掉终端隧道就断了。要后台常驻可以nohup cpolar http 8080 cpolar.log 21 或者用cpolar自带的系统服务模式cpolar service install cpolar service start这样隧道在系统后台跑掉线了会自动重连比前台挂着省心。cpolar还有个本地管理面板默认地址是http://localhost:9200打开能看到隧道的流量、连接状态还有请求日志排查问题比对着黑乎乎的终端强多了。有一个实战细节想单独说前端联调时免费域名的随机性会带来一些麻烦。地址变了前端代码里的API地址就要跟着改。我的做法是在启动脚本里用一行命令从cpolar的API动态读取当前公网地址自动写进前端的环境变量文件再重启前端容器。这样每次重新起隧道前端自动跟着新地址走不用手动改。写进脚本之后整个流程就是一条命令的事。4.3 ngrok的等效流程以及免费版限制ngrok的注册流程类似注册后在Dashboard拿到authtoken。下载对应平台的压缩包解压二进制文件放到PATH里。认证ngrok config add-authtoken 你的Token启动隧道ngrok http 8080输出信息里同样会有一个公网地址Forwarding https://xxxx.ngrok-free.app - http://localhost:8080ngrok比cpolar多一个明显优势是它还自带一个Web面板默认本地地址http://127.0.0.1:4040里面能看到每一个请求的完整信息URL、请求头、请求体、响应状态。调试Webhook回调时第三方平台发来的POST请求里带了什么参数、签名怎么生成的在这个面板里一目了然。微信支付、支付宝回调这类看不到请求内容的联调用ngrok排查效率能提升一个量级。而ngrok免费版的限制也很明确同一时间只能有一个ngrok进程在线、一个并发连接。意味着如果你开着ngrok做演示同时有好几个人点开链接第二个人开始就会访问失败。这个限制对“临时看一眼”够用对“给一群人演示”就力不从心了。多人同时需要访问时用cpolar或者直接上云服务器更实际。4.4 一个容易踩的HTTPS和地址误区公网映射工具给出的下载地址本身就是https开头TLS证书由隧道服务商在公网入口处帮你终止所以本地服务不需要自己配证书。很多第一次用的人误以为要在本地搞一套HTTPS证书其实是白折腾。反过来的坑倒是更常见如果本地Nginx或者其他服务自己开启了HTTPS而隧道工具默认按HTTP协议转发数据到了隧道服务商那里被加上TLS再以HTTP回源到你的本地端口就会导致证书不匹配、重定向循环、页面打不开这些奇怪现象。遇到这种情况先把本地服务的HTTPS关掉让隧道工具统一处理TLS层问题通常会消失。另一个高频误区是前端代码里硬编码了地址。比如前端打包时把API地址写死成http://127.0.0.1:8080本地跑没问题一映射成公网地址发给别人对方打开页面浏览器里的请求还在往他们自己的127.0.0.1:8080发当然啥也访问不到。正确做法是前端用相对路径或者把API地址做成可配置的环境变量映射地址变化时能快速切换。5. 高频问题排查从起不来到打不开5.1 Docker常见问题速查表Docker相关的报错网上问得最多的我汇总成一个速查表方便按图索骥报错信息原因处理方法virtualisation support was not detectedBIOS未开启虚拟化或Windows功能未启用BIOS开VT-x/AMD SVM启用虚拟机平台和WSLpermission denied while trying to connect to the docker api用户不在docker组sudo usermod -aG docker $USER后重新登录failed to start docker application container engine版本兼容问题、磁盘满、配置损坏清理磁盘、重置缓存、卸载重装port is already allocated宿主机端口被占用修改Compose里的宿主机端口如改成3307:3306docker pull 卡住或超时网络到Docker Hub不通配置镜像加速器并重启DockerWSL2长时间卡死WSL状态异常或资源耗光管理员PowerShell运行wsl --shutdown后重启Docker这里有两个我反复遇到过的情况要提醒。一是MySQL容器反复重启。如果用挂载目录方式启动MySQL宿主机数据目录的属主和容器内mysql进程的属主不一致容器会一直报权限错误。解决方法是把目录属主改成MySQL镜像内的uidMySQL 8.0官方镜像里mysql用户的uid是999mkdir -p ./mysql-data sudo chown -R 999:999 ./mysql-data二是容器内服务正常、宿主机访问不到。多数情况是服务监听了127.0.0.1而不是0.0.0.0。容器做了8080:3000端口映射但容器里的进程只绑定了127.0.0.1外部流量根本进不去。检查应用配置把监听地址改成0.0.0.0这个细节不留意真的能卡半天。5.2 公网映射常见问题速查表公网映射这边的问题也很有规律现象常见原因处理方法公网地址打不开隧道客户端没运行确认cpolar/ngrok进程还活着重新启动隧道手机4G访问失败电脑正常后端监听了127.0.0.1改成监听0.0.0.0映射后页面白屏前端硬编码了127.0.0.1改用相对路径或环境变量地址一会儿能用一会儿不能用免费隧道被断开或进程被kill用systemd或service安装模式保活打开地址显示404隧道映射的是端口路径不匹配检查本地服务路径规则以及Nginx的location配置Nginx做了HTTPS但隧道按HTTP转发证书错乱或重定向循环本地关掉HTTPS统一让隧道处理TLS多人同时访问失败ngrok免费版限单并发换cpolar或上云服务器排查这类问题有个基本功把链路一段一段拆开验证。先确认本地服务通不通再确认隧道客户端在线最后用curl -I验证公网地址返回状态码。链路拆开了问题定位就快了。5.3 三个真实排错案例复盘案例一MySQL容器启动不了日志里全是权限报错。有次我在一台新机器上部署这套Compose拉到MySQL镜像后容器一直在重启。docker compose logs mysql一看日志里反复出现chown: changing ownership of /var/lib/mysql/...: Permission denied。原因就是我前面说的数据目录属主问题。宿主机上ls -la看一下mysql-data目录的属主是root而容器内MySQL以uid 999运行。执行sudo chown -R 999:999 ./mysql-data之后容器立刻恢复正常。这个坑的特点是出现得特别安静日志不会告诉你“你应该改权限”需要自己联想到数据卷属主。案例二容器进程活着宿主机访问就是超时。另一个项目里后端服务在容器里能正常跑起来Docker也显示端口映射正常但宿主机访问localhost:8080始终超时。检查了Compose配置端口映射没问题进入容器里curl localhost:3000也通。后来进容器看监听端口才发现后端框架默认只监听了127.0.0.1:3000。容器外部的流量经过端口映射进来后到达容器网络接口再转发到3000端口但进程只监听回环地址数据包被拒绝了。把配置改成监听0.0.0.0:3000后一切正常。这个案例再次证明不是所有“端口映射成功”都等于“外部能访问”进程监听地址和端口映射是两码事。案例三映射地址在同事手机上打不开。给客户演示前我习惯先用模拟器验证一遍。那次cpolar输出的链接在电脑上访问一切正常但发到同事手机上却打不开。排查过程是这样的先在手机上用4G网络访问排除WiFi局域网因素再用电脑访问隧道地址确认隧道本身在线。后来发现问题出在Nginx反代配置里写死了proxy_pass http://127.0.0.1:3000而在Nginx容器里127.0.0.1指向容器自己。电脑上碰巧能通是因为某些请求绕过了Nginx直接访问了后端端口而手机上的请求全走Nginx自然全军覆没。把proxy_pass改成http://backend:3000后问题消失。这三个案例有一个共性问题都不在Docker本身而在链路中某个“看起来正常但方向错了”的配置上。所以我也养成了一个习惯——遇到访问不通先画链路公网用户 - 隧道服务端 - 隧道客户端 - 宿主机端口 - Docker端口映射 - 容器内端口 - 容器内监听地址沿着这条链路逐个验证任何一环断掉都能快速定位。这套方法同样适合你。写到这里结合我实际用的体会再多说两句。我开始用这套组合之后最大的变化是把部署步骤全部固化成了脚本。现在要做演示只需要执行一条命令脚本里自动执行docker compose up -d、拉起cpolar隧道、把新公网地址填到前端环境变量并重启前端容器最后把地址打印出来。整个过程手不再忙脚不乱。免费工具偶尔会掉线脚本里再加一个简单的健康检查确认隧道断了就自动重启并重新打印地址。这套东西看起来不起眼但实际用起来非常省心。如果你也是自己管项目的开发者建议先别急着买服务器把本地这套环境跑顺了再做决定可能你会发现很多需求根本不需要一台云服务器。真到了要上线的时候Docker镜像原样搬过去中间几乎不用改什么那才是这套组合最舒服的地方。
返回列表