☰
Docker实战:SpringBoot镜像从Windows迁移到Linux全流程
2026/10/20 16:06:39 网站建设 项目流程

简介:面向需要在Windows环境完成SpringBoot容器化并迁移到Linux中运行的Java开发与运维人员,文档完整梳理从Dockerfile编写、镜像构建、容器运行,到网络调试、MySQL数据库部署、镜像打包跨平台迁移的流程。内容涵盖基础指令、构建与运行常用参数、共享主机网络模式排查数据库连通性、挂载目录持久化、端口映射及Docker Compose多容器管理等关键知识点,配有逐步截图和命令解释,便于按步骤实操复现。资源为一个docx文档,压缩包大小约2.48MB,已有134人学习浏览。借助这份整理,读者可以掌握将Java应用封装为容器镜像并在不同操作系统间快速迁移部署的完整思路,降低环境配置与重复搭建成本,同时也能获得数据库部署和跨平台迁移中的排错思路,尤其适合初次接触容器化部署、需要快速上手的后端开发与运维人员。

1. 为什么要折腾Docker:SpringBoot镜像跨平台部署这事值得做

做 Java 后端开发,最常见的部署流程是把 SpringBoot 项目打成 jar 包,从 Windows 传到 Linux 服务器,然后java -jar跑起来。这个过程看着简单,实际翻车率不低:本地是 JDK 8,服务器是 JDK 11,启动直接报UnsupportedClassVersionError;或者本机能连的数据库地址,到了服务器上就超时;再或者 8080 端口被其他服务占了,日志刷出几十行异常。后来我改用 Docker,在 Windows 上把 jar 包做成镜像,再把镜像打包搬到 Linux 上运行,整个运行环境都封在镜像里,服务器不需要装 JDK、不需要配置 MySQL 客户端,只需要一个 Docker 引擎。这篇文章就从 Dockerfile 编写,到容器运行,再到把镜像从 Windows 迁移到 Linux 的完整过程,我把自己踩过的坑和验证步骤都记下来。

2. 写一份能用的Dockerfile:从jar包到镜像的三个关键点

2.1 基础镜像选型:openjdk:8-jdk-alpine 有坑但够用

我先把结论放前面:如果你的项目还在用 JDK 8,最省事的做法是选openjdk:8-jdk-alpine这个基础镜像。原因很直接,它体积小,拉取快,构建出来的镜像只有一百多兆,传到 Linux 服务器时很香。但 alpine 是基于 musl libc 的,和常规 CentOS 上的 glibc 不完全一样,如果项目里用了 JNI、本地库或者某些依赖字体,可能会遇到No such file or directory这类玄学错误。我一般建议先用它,跑起来发现缺库再换openjdk:8-jdk也不迟。

确认了基础镜像之后,Dockerfile 的骨架就出来了:

# 使用OpenJDK的基础镜像 FROM openjdk:8-jdk-alpine # 设置工作目录,容器里所有的命令都会在这个目录下执行 WORKDIR /app # 把宿主机target目录下的jar包复制到镜像的/app目录,并重命名为app.jar COPY target/demo-0.0.1-SNAPSHOT.jar app.jar # 声明容器运行时监听的端口,方便使用者和-P参数映射 EXPOSE 8080 # 容器启动后执行java -jar,注意是数组形式,避免被shell解析 ENTRYPOINT ["java", "-jar", "/app/app.jar"]

这里需要注意,我写的是target/demo-0.0.1-SNAPSHOT.jar,实际要改成你自己打出来的 jar 包名。WORKDIR /app的作用是让后续的COPY和ENTRYPOINT有个明确的相对路径参照,建议所有镜像都加,避免路径混乱。EXPOSE 8080只是声明,真正在宿主机上生效的还是要靠后面docker run -p做的端口映射。ENTRYPOINT用数组写法,可以直接拼到java -jar后面,不用再套一层sh -c,遇到 jar 包路径里有空格时不容易翻车。

2.2 一个容易忽略的细节:Dockerfile 的文件名和编码

很多新手把文件建好以后直接保存,然后在docker build时却提示Dockerfile not found,大概率是文件名写错了。Docker 默认找的是当前目录下名为Dockerfile的文件,注意首字母大写、没有扩展名,如果你在 Windows 上建了一个Dockerfile.txt,那构建时一定会报错。更隐蔽的坑是文件结尾的换行符,Windows 记事本保存的 CRLF 有时会影响 Dockerfile 的解析,我现在的习惯是不用记事本,用 VS Code 设置 UTF-8 with LF 再来写。

如果项目里不止一个环境,你也可以用-f指定别的文件名,比如docker build -f Dockerfile-dev -t myapp:dev .。但只有一份 Dockerfile 的时候,直接保持默认名省心。还有一点,COPY的源路径是相对于 Dockerfile 所在目录的,如果你的 Dockerfile 放在项目根目录,而 jar 包在target下,那就写成target/xxx.jar;要是 jar 包在别的位置,你需要先把路径理清楚,否则构建时会报COPY failed: stat ... no such file or directory。

为了不让构建上下文里塞入太多无关文件,我还会在项目根目录建一个.dockerignore,内容大概是:

target/*.jar !target/*.jar .git .idea *.iml logs

等等,这里有个容易误导的写法,严格说.dockerignore的取反规则比较复杂。我实际用的很简单:

.git .idea logs target/classes

这样 Docker 构建时就不会把.git、IDE 配置和编译中间产物都传进守护进程,构建速度会快不少。注意.dockerignore只是减少构建上下文体积,不会影响镜像文件内容。

2.3 构建镜像:docker build 命令里最后一个点不能丢

在项目根目录(就是包含 Dockerfile 的目录)打开 PowerShell,执行下面的命令:

docker build -t demo-app:1.0.0 .

-t给镜像起个名字,格式是名称:标签,标签相当于版本号,不写的话默认是latest。命令最后的.表示构建上下文目录,Docker 会把当前目录里的文件都传给它作为构建上下文。很多新手会把这个点漏掉,或者把目录路径写错,比如写成docker build -t myapp /path,这样如果没有指定 Dockerfile,Docker 会在/path下找 Dockerfile,一般也没错,但通常我们就在当前目录构建。

构建过程中会一条一条执行 Dockerfile 里的指令,如果基础镜像本地没有,会先从仓库拉取。看到Successfully tagged就代表镜像构建成功。如果构建失败,先看是FROM拉取失败还是COPY出错,前者检查网络,后者检查 jar 包路径。构建完之后可以用docker images查看本地镜像列表,确认demo-app:1.0.0已经存在。

这里我踩过一个小坑:COPY的源文件如果不存在,报错信息是COPY failed: file not found in build context or excluded by .dockerignore。如果你已经把 jar 包打包好了还是报这个,去查一下是不是被.dockerignore排除了。另外,如果你经常用 Maven 打包,我习惯在构建前先跑一遍mvn clean package,确保target下有最新的 jar,再执行 docker build。别省这一步,否则镜像里装的可能是旧包。

3. 构建与运行:build、run、logs三连,先把容器跑起来

3.1 运行容器:-d、-p、--name 三个参数必须懂

镜像构建好了,下一步就是把它跑成容器。我用的命令是:

docker run -d -p 8080:8080 --name demo_app demo-app:1.0.0

这里四个部分拆开看。-d是--detach,让容器在后台运行,不会占着你当前的终端。-p 8080:8080表示把宿主机的 8080 端口映射到容器内的 8080 端口,前后两个端口可以不一样,比如宿主机是 9090,容器是 8080,那就写成-p 9090:8080。--name demo_app给容器起一个别名,后面查看日志、停止容器都不用记那一长串容器ID。最后是镜像名。

注意,如果你的宿主机 8080 端口已经被占用,docker run会直接报bind: address already in use。这时要么换一个宿主机端口,比如-p 8081:8080;要么把占用端口的进程停掉。Windows 下可以通过netstat -ano | findstr 8080找到 PID,再用任务管理器结束进程。

3.2 怎么确认跑没跑起来:浏览器、curl、docker logs

启动后,在 Windows 浏览器里访问http://localhost:8080。如果项目本身有登录页或者接口,能看到页面或者返回 JSON,说明容器已经正常工作。但有时候浏览器转圈,不一定代表服务没起来,可能是应用启动慢,或者端口映射没生效。这时用docker ps看容器状态最容易说明问题:

docker ps docker logs -f demo_app

docker ps列出所有运行中的容器,看STATUS列是Up还是Exited。如果刚才的容器 Exited 了,说明启动即崩溃,直接看日志:

docker logs --tail 200 demo_app

日志里如果有Tomcat started on port(s): 8080或Started Application in x.xx seconds,基本说明 SpringBoot 起来了。如果日志停在某个Caused by,那就要针对性地排查。这里有个小技巧:SpringBoot 的进程在容器里是 PID 1,如果应用里执行kill命令或者捕获信号处理不当,可能会导致容器在docker stop后等很久,那是因为 PID 1 没有快速响应 SIGTERM。等你后面用docker run跑复杂应用时,可以加一个--init参数来复用 tini,但这属于后话。

3.3 容器想连数据库:先补网络这一课

到了这一步,项目基本跑起来了,但大概率会发现应用连不上数据库。原因很简单,容器是一个隔离的沙盒,它看不到你宿主机的localhost。比如你在本机 MySQL 端口是 3306,SpringBoot 配置里写的是jdbc:mysql://localhost:3306/db,这个localhost在容器里指向的是容器自己,而不是宿主机。于是一堆人开始怀疑是不是配置有问题,然后各种玄学重启。

我遇到这种情况,第一反应是先测试容器到数据库的网络通不通:

docker exec -it demo_app ping 宿主机IP docker exec -it demo_app telnet 宿主机IP 3306

如果ping通但telnet不通,多半是 MySQL 没开远程访问权限,或者防火墙挡了。如果ping都不通,那就要看看 Docker 默认的桥接网络。一个常见的解决方案是给docker run加--net=host,让容器直接用宿主机的网络栈,这时候容器里的localhost就是宿主机的localhost。另一个思路是改用自定义网络,让多个容器用服务名互相访问,而不是去访问宿主机。我强烈建议走自定义网络,因为--net=host在 Windows 和 macOS 上压根不生效,而且会牺牲端口隔离。我先把结论放在这,下一章把 MySQL 和 Redis 也容器化,你就明白为什么了。

4. 数据库与Redis容器化:MySQL 8.0.24和Redis的挂载、端口、网络一次讲清

4.1 创建挂载目录:数据不落在容器里才能备份和迁移

容器本身是无状态的,一旦容器被删掉,里面写的数据也会跟着消失。为了让 MySQL 和 Redis 的数据可以持久化,我习惯先把宿主机上的挂载目录建好。以 Windows 为例,我创建了这些目录:

mkdir D:\development_sources\docker\mysql\log mkdir D:\development_sources\docker\mysql\data mkdir D:\development_sources\docker\mysql\conf mkdir D:\development_sources\docker\mysql\mysql-files mkdir D:\development_sources\docker\redis\data

目录建好后,后面docker run时用-v把容器内的数据目录映射到这些地方。这样即使容器被删,重新创建一个容器,只要挂载目录不变,数据都还在。这也是后面从 Windows 迁移到 Linux 的一个关键点:镜像只是程序,数据在宿主机目录里,迁移时想保留数据,必须把整个数据目录一起拷过去,而不仅仅是镜像。

4.2 运行MySQL 8.0.24:3307端口映射和root密码设置

我的宿主机 3306 端口已经被一个本地 MySQL 服务占用了,所以这里必须换一个映射端口。我选的是 3307,命令如下:

docker run -p 3307:3306 --restart=always --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_PASSWORD=root \ -d mysql:8.0.24

这条命令是整篇文章里信息量最大的。-p 3307:3306把容器内 MySQL 默认的 3306 映射到宿主机 3307,这样外部可以用宿主机IP:3307来访问,同时也不干扰宿主机原有的 MySQL。--restart=always表示 Docker 守护进程启动时自动重启这个容器,如果容器异常退出也会拉起来,适合作为常驻服务。-v挂载了四个目录:/var/log/mysql日志、/var/lib/mysql数据文件、/etc/mysql配置目录、/var/lib/mysql-files导入导出目录。-e MYSQL_ROOT_PASSWORD=root是初始化 root 密码,第一次启动时设置。-d mysql:8.0.24指定镜像版本并后台运行。

如果启动报错,常见的原因是数据目录D:\development_sources\docker\mysql\data不是空的,或者里面有旧权限信息。第一次启动时,MySQL 会在这个目录初始化数据,如果目录里已有内容,root 密码不会重新设置。你可以清空这个目录再启动,或者直接换一个全新的目录。另外我提醒一句,MYSQL_ROOT_PASSWORD只在数据目录初始化时生效,如果之后想改密码,还是要进容器用ALTER USER改。

4.3 创建自定义网络:让容器用名字互相通信

多个容器都跑起来之后,SpringBoot 容器访问 MySQL 容器时,最优雅的方式不是记住宿主机的 IP,而是给它们建一个自定义网络,让容器之间直接用容器名做主机名。先创建网络:

docker network create dev_net

然后把刚创建的 mysqldoc 容器连上去:

docker network connect dev_net mysqldoc

接下来再跑 SpringBoot 容器时,也要用--network dev_net或者再把它 connect 进去。这样做的好处是:同一个网络里的容器,DNS 自动解析到对方的 IP。比如 SpringBoot 里配置jdbc:mysql://mysqldoc:3306/xx,Docker 会帮你把mysqldoc解析成容器 IP,而且即使容器重启换了 IP,这个名称解析依然有效。对比用 IP 或宿主机 localhost 的方式,这个方案在跨环境迁移时尤其省心。

查看网络和容器 IP 可以用:

docker network ls docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' mysqldoc

docker network ls会列出所有网络,能看到 dev_net 已经存在。docker inspect -f里的模板语法是取 NetworkSettings 下所有网络的 IPAddress,拼接打印出来。这个命令在排错时很有用,比如确认容器是不是真的在同一个网段。

4.4 运行Redis:AOF持久化和密码参数

Redis 容器和 MySQL 类似,也要建挂载目录。我继续用之前建好的D:\development_sources\docker\redis\data,然后执行:

docker run -p 6380:6379 --restart=always --name redis \ -v D:\development_sources\docker\redis\data:/data \ -d redis redis-server --appendonly yes --requirepass redis

这里有几个参数要单独说明。-p 6380:6379是把容器内 Redis 的 6379 映射到宿主机 6380,因为我的 6379 也被占了。-v D:\...\data:/data把数据目录挂进去,Redis 的 AOF 文件和 RDB 文件都会写在这个目录。最后的redis-server是覆盖镜像默认的启动命令,后面跟的--appendonly yes开启 AOF 持久化,--requirepass redis设置连接密码为redis。这样一来,其他容器或本地客户端连接时,必须带上密码。

为什么连接密码要用--requirepass而不是改配置文件?因为使用挂载目录映射conf目录后,配置文件是外置的,需要自己维护。对于快速开发环境,直接在命令行传参数更直观。如果你要上线,建议还是把conf目录下的redis.conf写好,再用-v挂载进去,并启动命令改为redis-server /etc/redis/redis.conf。

启动后,把 Redis 容器也接入 dev_net:

docker network connect dev_net redis

这样 SpringBoot 容器里配置 Redis 地址时可以直接写redis:6379,不需要关心容器 IP 或宿主机映射端口。注意容器间通信走的是容器内端口(6379),不是宿主机映射端口(6380)。宿主机上的 6380 只是给外部工具用的,比如在 Windows 上用 Another Redis Desktop Manager 连接测试,填写127.0.0.1:6380和密码redis。

4.5 SpringBoot的yml配置:把地址改成容器名

现在 MySQL、Redis 都在 dev_net 网络里了,SpringBoot 的配置文件就可以这样写:

spring: datasource: url: jdbc:mysql://mysqldoc:3306/demo?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai username: root password: root redis: host: redis port: 6379 password: redis # 其他业务配置...

注意到数据库地址是mysqldoc:3306,Redis 地址是redis:6379,对应的是容器名称和容器内部端口。SpringBoot 容器自身也要连接到 dev_net 才能解析到这些名字,否则会报UnknownHostException: mysqldoc。所以在运行 SpringBoot 容器时,要么一开始就加--network dev_net,要么用docker network connect dev_net <app容器名>补上。

这里有两个容易踩的坑:第一,如果docker run没有指定--network dev_net,容器默认在bridge网络,它无法解析 dev_net 里的容器名,哪怕两个容器在同宿主机上也不行。第二,如果 MySQL 容器是后面才 connect 进去的,SpringBoot 重启前最好确认一下网络连接是否生效。另外别忘记给 MySQL 创建远程访问账号,root 默认只允许从容器内的 localhost 访问,这个在下一章避坑里详细说。

5. 避坑指南:网络连不上、端口被占、镜像load失败这五个坑

5.1 容器访问MySQL失败:ping得通但连不上

现象:应用容器已经和 MySQL 容器在同一网络,docker exec -it demo_app ping mysqldoc能通,但是 SpringBoot 启动时报Communications link failure或者Access denied for user 'root'@'...'。

原因:网络没问题,问题出在 MySQL 的用户权限。root 用户默认只允许localhost登录,容器里访问 MySQL 时,来源 IP 是容器 IP,不在允许列表。

解决:进入 MySQL 容器,创建一个允许任意主机连接的用户,或者给 root 加上 '%' 主机。我一般在开发环境里用这样的 SQL:

-- 进入容器并登录 docker exec -it mysqldoc mysql -uroot -proot -- 在 MySQL 命令行执行 CREATE USER 'root'@'192.168.%' IDENTIFIED BY 'root'; GRANT ALL PRIVILEGES ON *.* TO 'root'@'192.168.%' WITH GRANT OPTION; FLUSH PRIVILEGES;

如果希望任何 IP 都能连,把192.168.%换成'%'。注意,%不包括localhost,如果本地也要用 root 登录,需要同时保留默认的'root'@'localhost'。然后可以用 Navicat 或其它客户端从宿主机测试连接127.0.0.1:3307,确认密码和权限是否正确。

5.2 宿主机端口被占用:bind: address already in use

现象:执行docker run -p 3306:3306或者-p 6379:6379时,直接报错:

Error response from daemon: driver failed programming external connectivity on endpoint xxx: Error starting userland proxy: listen tcp4 0.0.0.0:3306: bind: address already in use

原因:宿主机该端口已经被其他进程占用了。在 Windows 上可能是你之前安装的 MySQL 或 Redis 服务在跑,在 Linux 上也可能是别的程序。

解决:先查占用端口的进程,然后二选一:停掉旧服务,或者换新端口。

Windows 下查询:

netstat -ano | findstr "3306"

Linux 下查询:

ss -lnp | grep 3306

我一般不想动宿主机已有的服务,所以就改映射端口,比如 MySQL 映射到 3307,Redis 映射到 6380。改完之后,所有连接串里的端口都要同步改,包括代码里的 JDBC 地址、Redis 客户端地址和外部管理工具。改端口虽然简单,但要记得在防火墙上放行对应端口,不然外部依然连不进来。

5.3 Windows上--net=host就是不行

现象:在 Windows 上运行 Docker 容器时,命令加了--net=host,以为容器就能访问宿主机 localhost,结果容器起不来,或者启动后访问不到数据库,报错日志里还写着unknown host之类的。

原因:Docker Desktop for Windows 实际上是跑在一个轻量级虚拟机里的,它支持的网络驱动只有nat、bridge、none等,并不支持 Linux 下的host模式。你写了--net=host,Docker 要么忽略,要么直接报错。这个参数在 Windows 和 macOS 上就是个坑。

解决:放弃 host 模式,改用自定义桥接网络。按前面的做法,创建dev_net,把应用容器、MySQL、Redis 都放进去,然后配置里写容器名。如果确实需要访问宿主机上的某个端口,在 Windows 下可以写宿主机的局域网 IP,但要注意防火墙是否拦截。最稳妥的还是把所有依赖服务都容器化,统一放到同一个网络里管理。如果你是新手,记住一点:跨容器通信用自定义网络,不要纠结 host 模式。

5.4 docker save的镜像load时文件损坏

现象:在 Windows 上执行docker save -o demo-app.tar demo-app:1.0.0,生成的 tar 文件传到 Linux 后,执行docker load -i demo-app.tar时报错:

Error processing tar file: unexpected EOF

原因:最常见的是传输方式不对。有些 FTP 工具默认用文本模式传输,会把二进制 tar 文件里的字节给翻译坏;或者是传输过程中文件不完整,比如用网盘中转后下载下来少了几 KB,也可能磁盘空间不足导致 save 半途中断。

解决:优先用支持二进制传输的工具,比如 FinalShell 的 SFTP 文件传输、scp 命令。传输完成后先对比文件大小或者算一下 MD5:

md5sum demo-app.tar # Linux 端

在 Windows 上用Get-FileHash demo-app.tar算哈希,两边一致再 load。在 Linux 端加载时,我建议用输入重定向:

docker load < demo-app.tar

或者明确指定输入文件:

docker load -i demo-app.tar

这两个等价。如果加载报错,先用tar -tf demo-app.tar看能不能列出内容,列不出来说明文件已经坏了,重新 save 并检查传输方式。顺便说一句,docker save出来的 tar 是平的,不是 gzip 压缩的,有人用file demo-app.tar看到POSIX tar archive是正常的。

5.5 防火墙和SELinux搞鬼:外面访问不到端口

现象:容器已经Up,在服务器本机curl localhost:8080有响应,但从局域网另一台电脑就是访问不到。

原因:Linux 服务器的防火墙没有放行 8080 端口,或者 SELinux 拦截了 Docker 的网络转发。很多教程为了省事直接关防火墙,但生产环境不能这么干。

解决:开发环境图方便可以临时关闭防火墙:

systemctl stop firewalld systemctl disable firewalld

生产环境还是开放端口更稳妥:

firewall-cmd --zone=public --add-port=8080/tcp --permanent firewall-cmd --reload

至于 SELinux,可以在/etc/selinux/config里检查状态,如果docker都正常但网络不通,可以先临时setenforce 0试一下。注意这是临时关闭,重启后失效。我一般会在服务器上部署完所有容器后,从客户端访问一遍,确认端口通,再去收紧防火墙策略,而不是一上来就全关。

6. 装完怎么验证跑通:Windows打镜像,Linux加载启动全流程

6.1 在Windows上把镜像save成tar包

先把要搬的镜像打出来:

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

这一步是在 Windows 的 Docker 环境里执行,确保镜像存在。-o指定输出文件名,后面跟镜像名和标签。一次 save 多个镜像用空格隔开也可以,但单独打便于传输和加载。

6.2 传到Linux并load,重新创建网络和容器

用 FinalShell 或 scp 把这几个 tar 包传到 Linux 上。传输时注意选择二进制模式,传完后docker load < demo-app.tar依次加载。然后创建网络并启动容器:

docker network create dev_net docker run -p 3307:3306 --restart=always --name mysqldoc \ -v /opt/docker/mysql/log:/var/log/mysql \ -v /opt/docker/mysql/data:/var/lib/mysql \ -v /opt/docker/mysql/conf:/etc/mysql \ -e MYSQL_ROOT_PASSWORD=root -d mysql:8.0.24 docker network connect dev_net mysqldoc docker run -p 6380:6379 --restart=always --name redis \ -v /opt/docker/redis/data:/data -d redis redis-server --appendonly yes --requirepass redis docker network connect dev_net redis docker run -d -p 8080:8080 --name demo_app --network dev_net demo-app:1.0.0

注意在 Linux 上我把挂载路径换成了/opt/docker/...,如果你希望数据跟 Windows 那边一致,需要把当初在 Windows 挂载的 data 目录内容拷贝到 Linux 对应目录,再启动,否则就是全新空库。

6.3 最终验证:看容器状态、访问接口、查日志

验证分三步走。第一步看进程:

docker ps

确认三个容器都在Up状态,如果某个挂了,用docker logs <容器名>看原因。第二步在服务器本机访问:

curl -I http://localhost:8080

第三步从开发机访问http://Linux服务器IP:8080,并测试一下带数据库的接口。比如登录接口能返回正常数据,说明应用、MySQL、Redis 三者通过容器网络已经打通。如果登录接口报 Redis 连接异常,优先看 Redis 容器是否在 dev_net 里,以及 SpringBoot 配置里的容器名是否写对。

从那以后,我每次从 Windows 往 Linux 迁移镜像,都会强制按这套流程走一遍:先 save,再 load,然后建网络,最后逐容器启动并验证接口。以前图省事直接拷贝 jar 包,结果花两个小时排查 JDK 版本和数据库连接,后来才发现镜像迁移反而更稳。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询