SpringBoot Docker镜像跨平台部署与Linux验收

发布时间:2026/10/29 0:58:46

SpringBoot Docker镜像跨平台部署与Linux验收 简介这是一份面向 Java 后端开发者与运维初学者的 Docker 部署实践文档围绕在 Windows 环境中将 SpringBoot 项目构建为镜像并迁移到 Linux 主机运行展开。内容从 Dockerfile 基础写法切入串联 jar 包复制、端口暴露、镜像构建、容器启动与日志查看并延伸到容器网络连通性测试、宿主机或独立 MySQL 容器访问、数据库挂载目录持久化等常见问题。文档还涉及共享主机网络、ping 与 telnet 排查、Docker Compose 管理多容器应用等排错思路对镜像命名、端口冲突、容器重启策略、MySQL 初始化密码与目录映射等细节也有交代帮助读者理解镜像、容器与数据卷之间的关系形成从本地开发机到 Linux 部署环境的完整参考。文件包共 1 个 docx约 2.48MB以图文说明和命令示例为主便于对照实践。已有 135 人学习适合作为 SpringBoot 容器化入门与跨平台部署的实操资料。1. Windows 里把镜像跑起来只是前半场搬到 Linux 才是真正的验收在 Windows 上把 SpringBoot 项目打成 Docker 镜像、docker run起容器、浏览器打开 8080 看到首页很多人到这一步就收工了等docker save出一个几百兆的 tar 丢到 Linux 上docker load起来容器启动几秒就退出日志里一行Connection refused指向数据库才发现这套环境从来不是“装个 Docker”这么简单。Dockerfile 里 jar 路径写错容器网络默认桥接解析不了容器名MySQL 数据目录挂载权限对不上Linux 上的 docker-ce 版本比镜像还老任何一处都能让页面白屏。这套流程适合手上有 SpringBoot MySQL Redis、想在 Windows 上开发调试、再把同一份镜像搬到 Linux 跑起来的人。下面按装什么、怎么装、坏了怎么救走一遍。2. Dockerfile 落地openjdk:8-jdk-alpine 五行写死一个可移植镜像镜像能不能在另一台机器上活着跑起来八成取决于 Dockerfile 里那几个路径和基础镜像选得对不对。这一章先把项目结构钉死再逐行拆一份能直接抄的 Dockerfile最后把docker build和docker run两刀砍下去。2.1 先把 jar 包位置和 Dockerfile 摆放位置固定下来SpringBoot 项目打包用 Maven 就是一条命令产出的 jar 默认落在target目录下名字带版本号。真正容易翻车的是位置Dockerfile必须放在项目根目录也就是pom.xml同级因为它决定了docker build的构建上下文build contextCOPY后面的源路径永远是相对这个上下文算的不是相对Dockerfile所在行的位置。springboot-demo/ ├── pom.xml ├── Dockerfile - 必须在这一层 ├── src/ │ └── main/java/... └── target/ └── demo-app-1.0.0.jar - mvn package 之后才有打包命令用跳过测试的那条本地验证过功能再跳别在 CI 里也一路跳过# 清理旧产物并跳过测试打包产物落在 target/ 下 mvn clean package -DskipTests打包完先ls target/*.jar看一眼真实文件名。target目录里经常还有xxx.jar.original这种后缀COPY target/*.jar app.jar在某些情况下会匹配到多个文件直接报错所以我在正式 Dockerfile 里一律写死完整文件名宁可改一次 Dockerfile 也不留这个隐患。如果你的项目名和版本号经常变那就退一步用COPY target/*.jar前先确认target下只有一个 jar或者加.dockerignore把*.original排除掉。2.2 逐行拆 DockerfileFROM、WORKDIR、COPY、EXPOSE、ENTRYPOINT这是能直接用的版本比原始写法多了一个时区参数原因后面讲# 基础镜像用 OpenJDK 8 的 alpine 精简版体积小够跑 SpringBoot FROM openjdk:8-jdk-alpine # 容器内的工作目录后面的相对路径都基于它 WORKDIR /app # 把本地构建出的 jar 复制进镜像并重命名为固定的 app.jar COPY target/demo-app-1.0.0.jar app.jar # 声明应用监听 8080属于元数据不做端口映射 EXPOSE 8080 # 启动命令exec 形式PID 1 就是 java 进程 ENTRYPOINT [java, -Duser.timezoneAsia/Shanghai, -jar, /app/app.jar]FROM选openjdk:8-jdk-alpine的理由很实际SpringBoot 2.x 配 JDK 8 是主流组合alpine 版本镜像只有百来兆推来推去不心疼。要注意 alpine 里没有 glibc项目如果依赖 netty-tcnative 或者某些本地库运行时会报Error loading shared library这种项目就得换openjdk:8-jdk-slim这类基于 Debian 的镜像。WORKDIR /app不只是切目录它会在镜像层里创建这个目录后面的COPY和ENTRYPOINT里写/app/app.jar才对得上。COPY的两个参数顺序是“源 目标”源必须在构建上下文里../target/xxx.jar这种写法直接失败因为上下文之外的文件 Docker 看不见。EXPOSE 8080只是声明不 publish真正对外还得靠docker run -p。写它的价值在于别人docker inspect镜像时能看到这个服务该用哪个端口。ENTRYPOINT用 JSON 数组的 exec 形式不是ENTRYPOINT java -jar app.jar这种 shell 形式。区别很致命shell 形式下 PID 1 是/bin/sh -cjava 进程是子进程docker stop发的 SIGTERM 到不了 JVM容器只能等 10 秒超时后被 SIGKILL 强杀SpringBoot 的优雅停机、连接池关闭全都不执行。这个坑在开发环境看不出来上了 Linux 跑久了才会发现每次重启都丢在途请求。时区参数-Duser.timezoneAsia/Shanghai是我必加的。alpine 镜像默认 UTC容器里new Date()出来的时间比北京时间少 8 小时日志时间戳全是错的排查问题时能把人绕晕。alpine 里没装 tzdata所以配TZ环境变量没用直接给 JVM 传时区最省事。2.3 docker build 后面那个点以及镜像命名和缓存构建命令在 PowerShell 里执行先cd到含Dockerfile的项目根目录# -t 指定镜像名和标签最后那个点代表当前目录作为构建上下文 docker build -t demo-app:1.0.0 .那个.是最容易被忽略又最容易出事的地方。它把当前目录整个打包发给 Docker daemontarget里几百兆的 jar、.git目录、node_modules都会被送进去构建慢得像卡住。常见做法是在项目根目录放一个.dockerignore.git .idea *.iml target/*.original logs/注意别把target/整个排除掉jar 就在里面COPY会直接失败。-t demo-app:1.0.0的命名建议固定成“项目名:版本号”后面在 Linux 上docker save、docker load、docker run全程用这个名字版本号跟着pom.xml走。见过有人用docker build -t app .结果本地攒了七八个同名不同内容的app:latest出问题时根本分不清跑的是哪个包这就是自找的。缓存问题也得提一句。COPY target/xxx.jar app.jar这一行只要 jar 内容变了缓存就失效后面的层全部重建这是正常的。但如果改完代码忘了mvn packageCOPY拿到的还是旧 jar构建依然“成功”容器里的代码却是老的排查半天以为是环境问题。我一般把打包和构建串成一条命令mvn clean package -DskipTests; if ($?) { docker build -t demo-app:1.0.0 . }if ($?)是 PowerShell 里判断上一条命令是否成功打包失败就不构建省得拿着旧包骗自己。2.4 起容器、看日志、确认端口映射# -d 后台运行-p 宿主机端口:容器端口--name 给容器起个固定名字 docker run -d -p 8080:8080 --name demo-app demo-app:1.0.0 # 看容器是否还活着STATUS 里出现 Up 才算数 docker ps # 跟踪日志出问题第一眼看这里 docker logs -f demo-app-p 8080:8080左边是 Windows 宿主机端口右边是容器内端口右边必须和 Dockerfile 里EXPOSE以及 SpringBoot 的server.port一致。左边被占用是最常见的启动失败原因比如本机已经跑了一个 Tomcat 或者另一个 SpringBootdocker run会直接报port is already allocated改左边的端口就行比如-p 8081:8080。docker logs是这套环境的黑匣子。SpringBoot 启动失败都会在日志里留下痕迹UnknownHostException指向数据库地址解析不了Access denied for user指向账号密码或授权范围不对Communications link failure指向网络不通。容器刚起来就退出的时候docker ps看不到它得用docker ps -a找再docker logs看退出原因。浏览器访问http://localhost:8080能出页面说明 Dockerfile、构建、端口映射这三段路是通的。但页面能出来不代表业务能跑只要涉及数据库查询下一步就得处理容器怎么连到 MySQL。3. 容器网络与中间件dev_net、MySQL 8.0.24 和 Redis 怎么串起来Windows 上跑容器访问本机数据库是这套流程里最容易“看起来通了其实没通”的一段。原文里试过--nethost也试过先 ping 再改配置我把顺序重新理一遍顺手把 MySQL 和 Redis 也容器化。3.1 默认 bridge 解析不了容器名dev_net 才行Docker 容器默认挂在bridge网络上这个默认网络只有 IP 转发没有内嵌 DNS容器之间用容器名互相访问会直接报UnknownHostException。自己docker network create出来的用户自定义网络才带 DNS 解析容器名可以直接当主机名用。# 创建一个自定义桥接网络后面的应用、MySQL、Redis 都接进来 docker network create dev_net # 看网络列表确认 dev_net 在里面 docker network ls接入用docker network connect容器跑起来之后也能接不用重建docker network connect dev_net mysqldoc docker network connect dev_net redis docker network connect dev_net demo-app应用容器这一步经常被漏掉。MySQL 和 Redis 都连上dev_net了应用还在默认bridge上照样解析不了mysqldoc。三条connect一条都不能少接了之后用docker inspect验一下# 只取容器在 dev_net 里的 IP有输出说明接上了 docker inspect -f {{range $k, $v : .NetworkSettings.Networks}}{{$k}} {{$v.IPAddress}}{{end}} demo-app3.2 从容器里 ping 和 telnet 3306先判断再改配置连不上数据库时别急着改 yml先在容器里做两步诊断。原始做法是从应用容器 ping 数据库容器或 IP再 telnet 3306 端口。# 容器内 ping 数据库容器名验证 DNS 解析和二层连通 docker exec -it demo-app ping mysqldoc # 容器内 telnet 数据库端口验证 TCP 层通不通 docker exec -it demo-app telnet mysqldoc 3306这里有个现实问题openjdk:8-jdk-alpine镜像里既没有ping也没有telnet直接执行会报not found。常见做法是临时进容器装一个 busybox 扩展或者反过来从 MySQL 容器往应用容器 ping因为mysql:8.0.24镜像里通常有ping。更省事的做法是# 用自带 bash 的容器做网络探测把它接到同一个网络里 docker run --rm --net dev_net busybox ping -c 2 mysqldoc--rm表示跑完即删不留垃圾容器--net dev_net让它和业务容器在同一个网络里这样测出来的结果才有参考价值。ping 通只说明网络层没问题3306 还得单独验端口没监听或者 MySQL 没起来ping 是通但 telnet 不通的。3.3 MySQL 8.0.24 容器化四个挂载目录和 3307 端口Windows 上先建挂载目录PowerShell 里一条mkdir可以带多个路径mkdir D:\development_sources\docker\mysql\log,D:\development_sources\docker\mysql\data,D:\development_sources\docker\mysql\conf,D:\development_sources\docker\mysql\mysql-files然后跑容器参数一个一个摆开docker run -p 3307:3306 --restartalways --name mysqldoc -v D:\development_sources\docker\mysql\log:/var/log/mysql -v D:\development_sources\docker\mysql\data:/var/lib/mysql -v D:\development_sources\docker\mysql\conf:/etc/mysql -v D:\development_sources\docker\mysql\mysql-files:/var/lib/mysql-files -e MYSQL_ROOT_PASSWORDroot -d mysql:8.0.24PowerShell 里的续行符是反引号别抄成 Linux 的反斜杠\抄错了命令会被拆成几条执行报一堆莫名其妙的错。参数作用取舍说明-p 3307:3306宿主机 3307 映射容器 3306本机已有 MySQL 占了 3306开发机这样错开最省事--restartalways容器异常退出或 Docker 重启后自动拉起开发机也建议加省得每次开机手动 start--name mysqldoc固定容器名后面容器名要写进 yml名字不能乱改-v .../log:/var/log/mysql日志落宿主机出问题直接在 Windows 上看日志文件-v .../data:/var/lib/mysql数据文件落宿主机容器删了数据还在这条是命根子-v .../conf:/etc/mysql配置文件挂进去想改my.cnf不用进容器-v .../mysql-files:/var/lib/mysql-files导入导出目录LOAD DATA之类操作要用-e MYSQL_ROOT_PASSWORDrootroot 初始密码只在数据目录为空、首次初始化时生效最后一条特别容易误解MYSQL_ROOT_PASSWORD只在/var/lib/mysql为空、容器执行初始化时读取。挂载目录里已经有数据了改这个环境变量密码不会变得进容器用ALTER USER改。容器起来后用数据库客户端连127.0.0.1:3307验证注意端口是 3307 不是 3306。业务账号别直接用 root在容器里建一个限定来源的账号# 进入容器内的 mysql 客户端 docker exec -it mysqldoc mysql -uroot -p-- 应用账号只允许从任意容器来源连接密码自己换掉 CREATE USER app_user% IDENTIFIED BY App123456; GRANT ALL PRIVILEGES ON app_db.* TO app_user%; FLUSH PRIVILEGES; -- 如果只允许某个固定 IP 来源把 % 换成具体地址 -- CREATE USER app_user192.168.0.27 IDENTIFIED BY App123456;MySQL 8 的默认认证插件是caching_sha2_password老的 JDBC 驱动连它会报Public Key Retrieval is not allowed所以后面 JDBC URL 里要带allowPublicKeyRetrievaltrue或者把账号改成mysql_native_password。这两条路选一条别两边都改完再互相干扰。3.4 Redis 容器6380 端口、AOF 和密码Redis 的部署结构简单得多一个数据目录就够mkdir D:\development_sources\docker\redis\data docker run -p 6380:6379 --restartalways --name redis -v D:\development_sources\docker\redis\data:/data -d redis redis-server --appendonly yes --requirepass redis-p 6380:6379同样是为了避开宿主机已经占用的 6379。--appendonly yes打开 AOF 持久化每条写命令追加到文件容器重启后数据能重建不打开的话重启即清空开发环境丢点缓存无所谓但如果拿 Redis 存了业务状态就会出事。--requirepass redis设密码最后这几个参数是传给redis-server的命令行参数顺序必须在镜像名之后写到镜像名前面会被 Docker 当成自己的参数而报错。容器起来后docker network connect dev_net redis接进同一个网络再用 Redis 桌面客户端连127.0.0.1:6380密码填redis能PING出PONG就算通了。3.5 yml 里写容器名还是 IP以及 --nethost 在 Windows 上的局限网络通了之后改 SpringBoot 的配置文件host直接写容器名spring: datasource: url: jdbc:mysql://mysqldoc:3306/app_db?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/ShanghaiuseSSLfalseallowPublicKeyRetrievaltrue username: app_user password: App123456 redis: host: redis port: 6379 password: redis两个端口别写错容器内 MySQL 永远是 3306Redis 永远是 63793307和6380只是宿主机映射出去给 Windows 上的客户端用的。在 yml 里写成 3307容器之间是连不上的这个错我见过不止一次。serverTimezoneAsia/Shanghai和前面 JVM 的时区参数是一套的两边都不写插入的时间字段就会差 8 小时。useSSLfalse在开发环境关掉省事生产环境该开还得开。至于--nethost原文试过之后评价“意义不大”我补一下原因Windows 上的 Docker Desktop 跑在一层轻量虚拟机里--nethost共享的是那台虚拟机的网络栈不是 Windows 宿主机本身所以想靠它连 Windows 上的 MySQL大概率还是不通。Linux 上--nethost是真共享宿主机网络行为完全不同。跨平台部署时这个差异足够让人怀疑人生所以我的做法是统一走dev_net加容器名Windows 和 Linux 行为一致迁移的时候不用改配置。4. 避坑与排查容器起不来、连不上库的五个现场下面五条都是我自己踩过或者帮别人收拾过的现场按“现象 → 原因 → 解决”记。4.1 构建和启动阶段的三条第一条容器启动几秒就 Exiteddocker ps里看不到。现象docker run回车后返回一串容器 IDdocker ps空空如也docker ps -a能看到状态是Exited (1)。原因九成是 jar 路径不对或者 jar 本身没打出来。COPY在构建阶段就会失败但如果是ENTRYPOINT里的路径写错构建能过运行时 java 找不到 jar 直接退出。解决先docker logs 容器名看最后几行典型报错是Error: Unable to access jarfile /app/app.jar。回到项目里ls target/*.jar确认文件名再核对COPY的目标名和ENTRYPOINT里的是否一致顺便确认mvn package真的执行过别拿着空target目录构建。第二条改了代码镜像重建了容器里跑的还是老逻辑。现象接口返回的字段和本地代码对不上日志里的时间戳也停在几小时前。原因docker build用了缓存或者更常见的是打包那步漏了COPY复制进去的就是旧 jar。Docker 只按文件内容算哈希内容没变就复用缓存层它不会知道你改的是src里的 java 文件。解决养成mvn clean package再docker build的固定顺序怀疑缓存问题时加--no-cachedocker build --no-cache -t demo-app:1.0.0 .--no-cache会把所有层重建慢但干净。另外docker run前先docker rm -f demo-app删旧容器不然--name冲突会直接报错有人以为报错就是构建失败其实只是名字被占了。第三条docker run报端口已被占用。现象Bind for 0.0.0.0:8080 failed: port is already allocated。原因宿主机 8080 已经被别的进程或容器占着Windows 上常见的是另一份 SpringBoot 在 IDEA 里跑着没关或者上次的容器没删干净。解决netstat -ano | findstr :8080找到占用进程该关的关掉不想关就换映射端口-p 8081:8080容器内还是 8080对外访问改成 8081 即可。别去改 Dockerfile 里的EXPOSE那是元数据改了也解决不了冲突。4.2 连库和迁移阶段的两条第四条容器里访问数据库报UnknownHostException: mysqldoc。现象应用启动日志里抛java.net.UnknownHostException或者Communications link failure但用数据库客户端从 Windows 连127.0.0.1:3307是好的。原因应用容器和 MySQL 容器不在同一个用户自定义网络上默认bridge没有 DNS 解析容器名根本不是一个能解析的主机名。解决确认三方都接进了dev_netdocker network inspect dev_net看Containers里是不是三个容器都在。少哪个就docker network connect dev_net 名字补上然后重启应用容器让 SpringBoot 重新解析。还有一种情况是 yml 里写了容器的 IP容器重建后 IP 变了所以写容器名、不写 IP。第五条数据库容器升级或者换机器后数据“没了”。现象在 Windows 上跑得好好的库换到 Linux 上重新docker run之后表全空只剩一个空库。原因-v挂的是宿主机目录换机器等于换了一个空目录MySQL 发现/var/lib/mysql为空就重新初始化。容器本身不会随镜像带走数据这点和镜像完全两回事。解决迁移前先mysqldump导出 SQL在新机器上起容器、建库、导数据不要指望把 Windows 的数据目录直接拷到 Linux 上能用——目录里的文件属主是容器内的 mysql 用户uid 通常是 999Linux 上权限对不上容器会起不来日志里一堆Permission denied。如果非要拷目录得在新机器上chown -R 999:999对齐 uid还得处理 SELinux 上下文不如导出导入干净。5. 迁移到 Linuxdocker save 打包 CentOS 7 装 docker-ce-18.03.1.ceWindows 那边验证通过了接下来的活是把镜像搬到 Linux。核心就三件事docker save出 tar、目标机装 Docker、docker load回来重跑。5.1 docker save 三个 tar应用、MySQL、Redis镜像必须一个一个存docker save一条命令只打包一个镜像新版本可以带多个镜像名但老版本不行别赌# -o 指定输出文件后面跟镜像名:标签 docker save -o demo-app.tar demo-app:1.0.0 docker save -o mysqlimage.tar mysql:8.0.24 docker save -o myredisimage.tar redis三个 tar 都要存因为 Linux 上的 Docker 不保证能拉到完全一样的镜像尤其是没有外网或者镜像站抽风的时候。文件大小心里要有数MySQL 8.0.24 的镜像 tar 通常几百兆应用镜像看依赖几十兆到几百兆。三个加起来超过 1G 很正常传输前先看目标盘的剩余空间。镜像名和标签要和 Linux 上docker run用的完全一致save的时候写mysql:8.0.24load回来就还是mysql:8.0.24写mysql不带标签load 回来就是mysql:latest后面启动脚本里的标签对不上容器起不来。这个细节我吃过亏现在 save 之前都先docker images抄一遍完整名字。还有一个跨架构的注意点Windows 上的 Docker Desktop 默认拉的是linux/amd64架构的镜像和 x86_64 的 CentOS 7 一致正常不会出问题。如果构建机是 ARM 架构就得在docker build时显式指定--platform linux/amd64否则 load 到 Linux 上会报no matching manifest或者容器起来直接exec format error。5.2 CentOS 7 上装 docker-ce-18.03.1.ce源、依赖、启动Linux 侧先确认版本内核 3.10 的 CentOS 7 是这套组合里最常见的底子uname -r # 3.10.0-1062.56.1.el7.x86_64远程连接工具随便挑一个顺手的 SSH 客户端输入 IP、端口、账号密码连上命令行和文件管理都在一个界面里后面传 tar 包方便。开发环境为了省事经常直接关防火墙生产环境千万别这么干# 关闭防火墙并禁用开机自启仅限内网开发环境 systemctl stop firewalld systemctl disable firewalld装 Docker 之前先把旧版本清干净CentOS 7 上有些老包会互相干扰# 卸载可能存在的旧版本没装过会提示 nothing to do正常 yum remove docker docker-common docker-selinux docker-engine # yum-utils 提供 yum-config-manager另外两个是存储驱动依赖 yum install -y yum-utils device-mapper-persistent-data lvm2 # 添加 docker-ce 的 yum 源地址换成你环境能访问的镜像站 yum-config-manager --add-repo http://你的镜像站地址/docker-ce/linux/centos/docker-ce.repo # 列出可安装版本从高到低排序 yum list docker-ce --showduplicates | sort -r # 安装指定版本这是我们这套环境验证过的版本 yum -y install docker-ce-18.03.1.ce版本这里要留意 yum 包名的完整形式实际的包名通常是docker-ce-18.03.1.ce-1.el7.centosyum install docker-ce-18.03.1.ce能匹配到就可以匹配不到就用yum list输出里的全名。18.03 这个版本比较老好处是和旧内核、旧镜像兼容性好坏处是有些新镜像的 manifest 格式它不认。如果docker load时报格式相关的错不要硬扛记下报错信息确认镜像能在更新的 Docker 上 load 成功再决定要不要升版本。装完启动并设开机自启systemctl start docker systemctl enable docker # 确认版本Client 和 Server 两段都要有输出 docker versionCentOS 7 上默认存储驱动可能是devicemapper性能和稳定性都不如overlay2。内核 3.10 是支持 overlay2 的建议显式写进配置{ storage-driver: overlay2, log-driver: json-file, log-opts: { max-size: 100m, max-file: 3 } }把这段写进/etc/docker/daemon.json然后systemctl restart docker。日志限制那两行是后悔药不加的话容器日志会把磁盘写满等到no space left on device的时候服务已经挂了。改完存储驱动如果起不来先docker info | grep -i storage看实际生效的驱动必要时把/var/lib/docker清空重来——前提是没有重要镜像所以这一步要在 load 之前做。5.3 上传 tar 包、load 镜像、按 Linux 的路径重跑容器用 SSH 客户端的文件管理把三个 tar 传到 Linux 的自定义目录比如/opt/loadimages然后逐个加载cd /opt/loadimages # -i 指定输入文件执行完 docker images 能看到镜像 docker load -i demo-app.tar docker load -i mysqlimage.tar docker load -i myredisimage.tar # 确认三个镜像都在标签对得上 docker imagesdocker load可能输出Loaded image: demo-app:1.0.0也可能只输出层 ID 的进度最后以docker images的结果为准。容器要按 Linux 的路径重跑不能照抄 Windows 的D:\...。先建目录mkdir -p /data/docker/mysql/{log,data,conf,mysql-files} mkdir -p /data/docker/redis/dataMySQL 和 Redis 的启动命令除了挂载路径其余参数和 Windows 上保持一致docker network create dev_net docker run -p 3307:3306 --restartalways --name mysqldoc \ -v /data/docker/mysql/log:/var/log/mysql \ -v /data/docker/mysql/data:/var/lib/mysql \ -v /data/docker/mysql/conf:/etc/mysql \ -v /data/docker/mysql/mysql-files:/var/lib/mysql-files \ -e MYSQL_ROOT_PASSWORDroot \ -d mysql:8.0.24 docker run -p 6380:6379 --restartalways --name redis \ -v /data/docker/redis/data:/data \ -d redis redis-server --appendonly yes --requirepass redis docker run -d -p 8080:8080 --name demo-app demo-app:1.0.0 docker network connect dev_net mysqldoc docker network connect dev_net redis docker network connect dev_net demo-app顺序上先把中间件起好再起应用不然应用启动时连不上数据库SpringBoot 可能直接启动失败。数据从 Windows 迁过来的话用mysqldump导出的 SQL 在新容器里source一遍别直接拷数据目录。5.4 SELinux 和目录权限CentOS 上特有的两个坑CentOS 7 默认开着 SELinux-v挂载宿主机目录时容器进程可能没有写权限表现是 MySQL 容器启动失败日志里Cant create/write to file或者Permission denied。开发环境图省事可以临时关掉# 查看当前状态Enforcing 表示开着 getenforce # 临时切成宽松模式重启后恢复 setenforce 0更规范的做法是在挂载参数后面加:z或:Z让 Docker 自动打上 SELinux 标签比如-v /data/docker/mysql/data:/var/lib/mysql:z。两种做法选一种别同时上否则排查时根本分不清是哪个改动起的作用。权限本身也要看一眼/data/docker/mysql/data如果被 root 提前占成 700容器内的 mysql 用户写不进去同样起不来。chown -R 999:999 /data/docker/mysql/data把属主对齐到容器内的 mysql uid这是mysql:8.0.24镜像里的固定值。6. 验收load 之后用三条命令确认容器真的在跑最后这步是我现在每次迁移必走的几分钟就能把“看起来起来了”和“真的能对外服务”区分开。第一步看容器状态三个容器都得是Up重启次数是 0docker ps --format table {{.Names}}\t{{.Status}}\t{{.Ports}}第二步验端口和服务。从 Linux 本机curl应用首页curl不通就先看容器日志别急着改配置# 应用返回 200 或者一段 HTML 才算数 curl -I http://127.0.0.1:8080 # 日志只取最后 50 行重点找 Started Application 和异常堆栈 docker logs --tail 50 demo-app # 从应用容器反向验证数据库端口能连上会打印 Open 或空行后挂住 docker exec -it demo-app sh -c nc -zv mysqldoc 3306nc在 alpine 里通常可用不行就用ping加docker exec -it mysqldoc mysql -uroot -p -e select 1从数据库侧验证。第三步是最容易被跳过、也最能暴露问题的一步跑一次真实的读写。打开一个涉及数据库查询的页面或者调一个写接口然后去数据库里select一下确认数据落库了再往 Redis 里写一个 key用客户端查出来。只验证首页能打开是不够的首页往往是静态的连接池根本没被触发。验证项命令或动作通过标准容器存活docker ps三个容器 Up重启次数 0应用可达curl -I http://127.0.0.1:8080返回 200 或 3xx数据库连通页面触发查询返回数据无Connection refused数据落盘写接口后查库数据能查到容器重启后还在Redis 连通写 key 后用客户端读读得到值PING返回PONG开机自启重启机器后docker ps三个容器自动起来那次在 CentOS 上 load 完镜像、docker ps三个容器全是 Up、首页也能打开我直接跟人说好了结果业务同事一点查询就报错——yml里还写着 Windows 上那个127.0.0.1:3307容器里根本没有这个地址。从那以后我每次迁移完都强制走一遍“容器状态 → 端口连通 → 真实读写”这套动作一步都不跳。希望这套流程能帮到你少在黑匣子日志里绕几圈。本文还有配套的精品资源点击获取
延伸阅读

更多相关文章

2026/10/29 0:58:46

Agent系统触达层架构设计:Agent-Reach解决工具调用连不上的问题

做Agent落地的朋友大概率都遇到过这样一个尴尬场景:模型已经能用自然语言规划任务了,工具调用的函数定义也写得清清楚楚,可Agent真正跑起来的时候,有一半时间都耗在"够不到"上——要么连不上内部数据库,要么…

2026/10/29 0:58:46

Python+SQL Server+Tkinter生产级宿舍管理系统实战

简介:这是一套基于PythonSQL ServerTkinter开发的学生宿舍管理系统实战项目,面向高校计算机专业初学者、课程设计学生及小型校园信息化管理者,解决学生信息、管理员权限与核酸检测数据一体化管理的实际需求。资源包共21个文件,含2…

2026/10/29 2:13:50

超立方体Ramsey(openai/math 家族181)H11攻坚日志|D114–D117四轮形式化闭合:高度上包络运输、单点擦除、父子包络桥接与Marking余量+1支付

超立方体Ramsey(openai/math 家族181)H11攻坚日志|D114–D117四轮形式化闭合:高度上包络运输、单点擦除、父子包络桥接与Marking余量1支付 专栏标签:Lean4 形式化审计 Ramsey理论 Burr–Erdős猜想 有限概率 尺度递推 …

2026/10/29 2:13:50

超立方体Ramsey(openai/math 家族181)H11攻坚日志|D110–D113四轮形式化闭合:条件边际保持、过滤接受因子、派生历史核与联合Gate运输

超立方体Ramsey(openai/math 家族181)H11攻坚日志|D110–D113四轮形式化闭合:条件边际保持、过滤接受因子、派生历史核与联合Gate运输 专栏标签:Lean4 形式化审计 Ramsey理论 Burr–Erdős猜想 有限离散概率 条件后验 …

2026/10/29 2:13:50

第2章:Linux 基础,解压缩【.tar.gz】压缩包

专栏导航 上一篇:第2章:Linux 基础,exit 命令 回到目录 下一篇:第2章:Linux 基础,制作【.tar.gz】压缩包文件 本节前言 对于本节所讲解的知识,有可能,你会需要时不时地参考本专栏…

2026/10/29 2:08:50

第 1 篇|路线抉择:奥拓升级,还是换新能源?

前言现在几乎所有 B 端 SaaS 团队,都站在同一个十字路口: 存量系统跑了很多年,业务不能停、付费租户不能下线,同时老板、客户、行业声音都在催着做 AI 原生。 摆在架构师面前,天然只有两条路:路线一&#x…

2026/10/28 14:42:12

全国计算机二级C语言真题PDF高效刷题指南

简介:这份PDF是全国计算机二级C语言考试的试题与答案解析,专为备考二级C语言的考生准备。内容涵盖C语言特点与设计理念、程序基本组成单位、main函数执行流程、函数嵌套调用规则、标识符命名规范、整型实型字符型数据类型、八进制十六进制数合法形式、运…

2026/10/28 15:28:56

requests+BeautifulSoup:爬虫抓取h1标题的入门实战指南

简介:一份以实战为导向的Python爬虫入门资源,面向具备基本编程基础、希望快速掌握网络数据抓取的初学者,可解决从零编写简单爬虫的常见困惑。实例以requests库发送HTTP请求、BeautifulSoup解析HTML文档,完整演示从网页中提取 标题…

2026/10/28 3:32:29

递推最小二乘参数辨识MATLAB编程:二阶系统与渐消记忆实现

简介:这是一篇面向控制系统、信号处理与机器学习等领域学习者的最小二乘参数辨识程序说明文档。资源共包含一个docx格式文档,压缩包大小七十八KB,内容围绕递推最小二乘算法和渐消记忆最小二乘算法展开:先构造一个极点位于单位圆内…

2026/10/29 0:03:42

学生选课系统DFD图绘制指南:边界划分与分层校验实战

简介:文档以顶层与第一层DFD图为核心,完整刻画学生选课系统的逻辑模型,面向软件工程课程设计、系统分析学习及毕设前期建模人群。顶层图界定系统边界,外部实体包括管理员、教师和学生三类角色;第一层图进一步细化用户登…

2026/10/29 0:03:42

JIRA敏捷落地:Scrum角色权限、Sprint与燃尽图避坑指南

简介:围绕“基于JIRA的敏捷开发项目管理”这一主题,面向产品负责人、Scrum Master及研发测试成员,梳理Scrum角色分工、迭代流程与JIRA工具配置的对应关系,适合初、中级团队导入敏捷管理时参考。压缩包共1个docx文件,大…

2026/10/29 0:03:42

SEMI S8人机工程验收实战:从条款拆解到现场实测的完整指南

简介:面向半导体设备设计、制造与运维工程师及安全合规人员,这份资料聚焦SEMI标准体系下的设备安全规范,重点收录SEMI S8-0308《半导体制造设备人体工程学工程安全指南》。内容围绕设备设计原则、错误与事故预防、人体工程学适配三大主线展开…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑