☰
Docker实战指南:从镜像容器到MySQL/Redis部署与高频问题排查
2026/9/29 15:14:22 网站建设 项目流程

Docker这玩意儿,刚接触的时候,我还真把它当成一个轻量级虚拟机来用。后来踩了不少坑才明白,它解决的核心问题就是一句话:让应用连同运行环境一起打包、分发、运行。不管你是后端开发、运维,还是想自己部署点服务的普通用户,只要你受够了“在我电脑上明明好的,怎么到你电脑上就挂了”这种破事,Docker就是那个能把环境差异摁死的工具。这篇文章我会从零开始讲安装、镜像、数据卷、网络,再带你把MySQL 8.0、Redis主从、青龙面板这些常见场景跑起来,最后把启动失败、网络不通、权限错误这些高频坑全部过一遍。

1. 先说清楚:Docker到底解决了什么问题

1.1 从“在我电脑上好好的”说起

我在刚接触Docker的时候,最直观的感受就是环境这玩意儿太脆弱了。早期部署一个Java项目,要先装JDK,版本还得对;再装MySQL,编码得调;再装Redis,密码得改。好不容易在本机跑通了,到了服务器上,系统不一样、依赖库缺了好几个、路径对不上,又得花半天时间重新折腾。Docker把这一套全给打包了,你的JDK、Tomcat、代码、配置文件、操作系统依赖,全部塞进一个镜像里,别人拿到这个镜像,一条docker run就能起一个一模一样的环境。

从技术底层看,Docker不是一个真正的虚拟机。虚拟机是在硬件层面做虚拟化,每个虚拟机里都要跑一个完整的操作系统,所以启动慢、占用大。Docker则直接复用宿主机的Linux内核,通过命名空间做隔离,通过cgroups做资源限制。你可以把它理解成一个大楼里的独立房间:房间之间有墙隔开,但共享水电暖,不用每个房间都配一套锅炉房。正因为这样,Docker容器启动通常只要几百毫秒,一个普通服务器能同时跑几十个容器。

对于不同基础的人,我的建议是这样的:如果你是纯小白,先别管什么内核、命名空间,先把“镜像就是安装包,容器就是运行中的程序”这个印象刻在脑子里。等你把常用命令玩熟了,再回头去看底层原理,会发现顺理成章。如果你是开发,那你更应该重视镜像的制作和依赖的管理,后面讲青龙面板的依赖管理时会具体说明。

1.2 镜像、容器、仓库,先把这三件事记牢

用一句话概括三者的关系:镜像是一个只读模板,容器是镜像运行后的实例,仓库是存放镜像的地方。再打个比方,镜像就像一张披萨的配方,容器是按配方做出来的一份披萨,仓库则是存放各种配方的菜谱市场。你可以从市场拉一份配方回来,烤出一份披萨,吃完扔掉,再烤一份,配方始终还在。

命令行里最关键的就是这几个:docker pull从仓库拉镜像,docker images查看本地镜像,docker run根据镜像启动容器,docker ps查看运行中的容器,docker exec -it 容器名 bash进入容器内部,docker logs 容器名看日志。我这几年用下来,80%的日常操作就那么几个命令,不用一上来背一大堆。

另外要纠正一个常见误区:容器不是把镜像解压出来的文件夹,容器是基于镜像分层创建出来的可写层。所有对容器内部文件系统的修改都发生在这个可写层里,所以容器一旦删除,修改就没了。这也是为什么后面我强烈建议你一定要用数据卷,不然MySQL容器删掉,你的数据库就没了,到时候哭都来不及。

2. 安装篇:Linux和Windows桌面端怎么装

2.1 Linux安装Docker的完整步骤(Ubuntu/CentOS)

Linux是Docker的“主场”,安装方式基本分两种:一种是用官方脚本一键装,另一种是用系统包管理器装。官方脚本在Ubuntu和CentOS上都能用,命令是:

curl -fsSL https://get.docker.com -o get-docker.sh sudo sh get-docker.sh

这个脚本会帮你配置好软件源、安装Docker Engine和CLI,装完直接跑sudo systemctl enable --now docker开机自启。不过有些公司内网环境访问外网受限,这时候就得走系统仓库。Ubuntu上最省事的是sudo apt install docker.io,版本可能旧一点,但对入门和大部分生产场景足够了。CentOS 7上如果已经有旧版Docker,建议先卸载干净再装,否则容易遇到dockerd启动冲突的怪问题。

很多人问CentOS 7怎么升级Docker,我的建议是先备份好现有容器数据,然后yum remove docker docker-client docker-common docker-engine,再安装yum-utils,配置官方或云厂商的镜像源。装完以后验证是否正常,跑一下最经典的:

sudo docker run hello-world

看到一句“Hello from Docker!”就说明环境OK。这里还有个新手必踩的权限坑:每次都要sudo很烦,你可以执行sudo usermod -aG docker $USER,然后退出终端重新登录,之后就直接用docker命令了。如果你加了用户组还是报permission denied,八成是你没重新登录,或者当前shell还留着旧的用户会话。

2.2 Windows安装Docker Desktop与Virtualization检测

Windows上现在主流就是装Docker Desktop,它依赖WSL2或者Hyper-V。装完之后最常见的失败就是弹窗提示virtualization support not detected。这句话的意思是Windows检测不到虚拟化功能,但你电脑不一定不支持,多半是没打开。

排查步骤我建议按这个顺序来:先打开任务管理器,切到“性能”选项卡,看CPU那一栏右下角有没有“虚拟化: 已启用”。如果显示“已禁用”,就需要进BIOS把Intel VT-x或者AMD-V打开。不同主板入口不同,一般是开机时按F2/F10/Del,进入Advanced或Processor设置,找到虚拟化技术选项,改成Enabled,保存重启。如果任务管理器那里显示已启用,但Docker Desktop还是报同样的错,那就去“启用或关闭Windows功能”里把“适用于Linux的Windows子系统”和“虚拟机平台”勾上,重启后再试。

另一个高频报错是failed to connect to the docker api at npipe:////./pipe/dockerDesktopLinuxEngine。看到这个,基本就是Docker引擎根本没起来。先点Docker Desktop托盘图标看状态,如果一直卡在“Starting”,直接右键退出再重新启动,很多情况是WSL2卡住了。还不行就在PowerShell里执行wsl --shutdown,把WSL彻底关掉,再重启Docker Desktop。另外,社区有第三方汉化包,比如网上常见的asxez/dockerdesktop-cn这类项目,不过Docker Desktop版本更新很快,汉化包容易失效。我的建议是直接用英文版,其实常用界面就那几个按钮,用熟了没区别。

3. 镜像、仓库与下载慢的解法

3.1 镜像和容器到底什么关系

刚开始用Docker时,我总搞不清docker pull下来的镜像和容器是不是同一个东西。理论上,镜像是静态的,它由多层只读文件系统组成,每一层对应Dockerfile里的一条指令。比如安装MySQL的镜像,底层可能是Debian系统,往上加了MySQL的程序文件、配置文件、初始化脚本等。容器启动时,Docker在镜像最上面加一个可写层,所有运行时写入的文件都在这层里。

镜像的分层设计有个明显好处:多个镜像可以共享底层。比如你本地有Ubuntu的镜像,又有MySQL、Redis这些基于Ubuntu的镜像,它们会共享相同的系统层,不会重复下载,也节省磁盘。但也正是因为分层,镜像偶尔会出现奇怪的“虚拟”大小,因为共享层计算方式不同,不用太在意。

从Docker Hub上能拉到的常用镜像很多,比如mysql:8.0、redis:7、nginx:latest、ubuntu:22.04、python:3.11、node:20。还有一类是企业级应用镜像,比如GitLab社区版、Metabase、Joplin笔记、KodBox网盘、MediaMTX流媒体服务,甚至人大金仓数据库也有Docker版本。同一类解决方案,之前我部署微服务项目时习惯把所有服务做成镜像,再用docker-compose统一编排,整个测试环境几分钟就能搭出来。

3.2 镜像下载慢?先配置镜像加速器

在国内用Docker,最让人烦躁的就是docker pull卡在Waiting或者下载速度只有几十KB。原因是Docker默认从Docker Hub拉镜像,跨境网络链路不稳定太常见了。解决思路是配置镜像加速器,也就是registry mirror,它相当于在本地做一个Docker Hub的缓存代理。

具体操作很简单,Linux上修改/etc/docker/daemon.json:

{ "registry-mirrors": ["https://你的专属加速器地址"] }

然后执行sudo systemctl daemon-reload && sudo systemctl restart docker。注意,网上确实很多公开加速地址,但稳定性参差不齐,今天能用明天就失效。我建议你去主流云厂商的控制台里搜索“容器镜像加速器”,注册后一般会给你一个专属地址,这个地址只关联你的账号,稳定性和速度都有保障。因为这类地址会变,我就不在这里写具体网址了,免得误导你。

如果是Docker Desktop,可以在设置界面里找到Docker Engine选项,直接把上述JSON粘贴进去,然后点击Apply & Restart。这里有两个容易踩的坑:一是daemon.json格式写错,会导致Docker服务直接起不来;二是加速器只对Docker Hub生效,如果你拉的是ghcr.io/xxx这类第三方镜像,加速器管不了,得用完整镜像名去拉。判断是否生效,可以docker info,看输出里的Registry Mirrors列表。

3.3 私有仓库:自己搭一个 registry

镜像下载慢的问题解决后,很多人还会遇到另一个问题:公司内网部署服务不能随便拉外网镜像。这时候就需要私有仓库,最轻量的方案是直接用Docker官方registry镜像。一条命令就能起一个供测试用的仓库:

docker run -d --name registry --restart=always -p 5000:5000 registry:2

打个标签再推送,比如把本地ubuntu:22.04打上localhost:5000/my-ubuntu:1.0,然后docker push localhost:5000/my-ubuntu:1.0。如果是在其他机器上拉这个仓库的镜像,需要在该机器的Docker配置里把localhost:5000加入insecure-registries,否则Docker默认走HTTPS,会报证书错误。

当然,生产环境我更推荐用Harbor,它带Web界面、权限管理、镜像清理和漏洞扫描,部署稍微复杂点,但物超所值。对入门阶段来说,先能用官方registry跑通push/pull流程,理解镜像仓库的交互逻辑,对你后面用Harbor会轻松很多。

4. 数据卷与网络:让容器真正可运维

4.1 数据卷:容器删了数据不能跟着丢

我说过容器删除后可写层就没了,那数据库这种要持久化状态的应用怎么搞?答案就是数据卷(Volume)。数据卷是Docker管理的一块存储,挂载到容器内的某个路径,写入这个路径的数据会落在宿主机上,即使容器删了,卷还在。我用MySQL举过一个例子:如果直接docker run mysql,删掉容器后数据库内容全部消失;正确做法是挂载一个命名卷:

docker volume create mysql-data docker run -d --name mysql8 \ -v mysql-data:/var/lib/mysql \ -e MYSQL_ROOT_PASSWORD=YourPass123 \ mysql:8.0

这里mysql-data:/var/lib/mysql的含义是:容器里/var/lib/mysql目录的数据,都会存到宿主机上名为mysql-data的卷里去。以后即使容器出问题,只要重新用同一个卷启动镜像,数据就还在。命名卷比路径挂载好的一点是,你不用关心它具体在宿主机哪个目录,Docker会帮你统一管理,备份时只需docker run --rm -v mysql-data:/volume -v $(pwd):/backup alpine tar czf /backup/mysql-data.tar.gz -C /volume .。

数据卷还有一个常见坑:权限。宿主机上的目录权限和容器内用户UID不一致时,容器可能会报Permission denied。遇到这种情况,先docker exec -it 容器名 id看看容器内用户是什么,然后用chown调整对应目录属主,或者启动时指定--user。别一上来就把整个目录chmod 777,除非你只是在玩,生产环境那样搞会出安全事故。

4.2 网络不通?先按这个顺序排查

Docker网络问题排名第二,仅次于权限问题。最常见的现象是:容器起来了,但容器之间互相ping不通,或者宿主机访问不到容器端口。先说结论:容器之间通信不要用--link,那是老古董,现在应该用自定义网络。

创建一个用户自定义网络:

docker network create app-net

启动容器时指定--network app-net,同一网络里的容器就能直接用容器名互相访问。比如Redis主从部署,从节点容器里可以直接使用redis-master这个主机名去连接主节点,而不需要拿IP地址,因为Docker内置DNS解析。如果容器不在同一个网络,你需要用docker network connect app-net 容器名把它加进来。

宿主机访问容器靠端口映射,比如-p 8080:80表示把容器的80端口映射到宿主机的8080端口。如果映射了却访问不通,按这个顺序排查:先docker ps看容器是否在运行;再docker logs 容器名看应用是否正常监听;然后curl 127.0.0.1:8080测本机;最后看防火墙,Ubuntu的ufw或CentOS的firewalld有没有放行对应端口。很多情况下,容器内部服务绑定的是localhost而不是0.0.0.0,导致端口映射失效,这种问题看容器日志和docker inspect最能发现。

有个容易踩的坑:在容器内部访问宿主机上的服务。比如容器内跑应用要连宿主机上的MySQL,如果你在容器内用localhost连的是容器自己,而不是宿主机。这时候可以用host.docker.internal(Docker Desktop支持),Linux上可以用ip route show查宿主机网关IP,或者启动容器时用--add-host=host.docker.internal:网关IP。公司办公环境下,有些安全软件也会干扰Docker虚拟网卡,导致docker网络不通,这种问题通常只能关掉安全软件或者让网络管理员开白名单。

4.3 多容器编排:从手敲命令到docker-compose

当你需要部署一个微服务项目,或者Dify这种由前端、后端、数据库多个组件组成的系统时,再一条条docker run就太折磨了。docker-compose就是用来声明式编排的:把所有服务写进一个docker-compose.yml,一条命令完成启动、停止和日志查看。

一个最简例子:

services: web: image: nginx:latest ports: - "8080:80" volumes: - ./html:/usr/share/nginx/html db: image: mysql:8.0 environment: MYSQL_ROOT_PASSWORD: rootpass volumes: - db-data:/var/lib/mysql volumes: db-data:

然后在项目目录执行docker compose up -d,Docker就会自动建网络、拉镜像、挂载数据卷。我个人的习惯是,凡是超过一个容器的场景,一律用compose,哪怕只是本地测试。这样环境配置可以作为文件保存下来,换台机器复制过去就能跑,这才是Docker“可移植”的真正价值。

5. 实战一:使用Docker部署MySQL 8.0并做数据持久化

5.1 部署并验证服务

我这里直接给你一个能用的MySQL 8.0部署命令,别急着复制,先看参数:

docker run -d \ --name mysql8 \ -p 3306:3306 \ -e MYSQL_ROOT_PASSWORD=YourPass123 \ -e MYSQL_ROOT_HOST=% \ -v mysql-data:/var/lib/mysql \ --restart=always \ mysql:8.0

-e MYSQL_ROOT_PASSWORD是初始化时设置root密码,MYSQL_ROOT_HOST=%表示允许root从任意主机登录,-v挂数据卷,--restart=always让容器挂了自动重启。部署完后,用docker ps确认状态为Up,然后进容器验证:

docker exec -it mysql8 mysql -uroot -p -e "select version();"

能返回8.0.x就说明成功了。如果外面要用Navicat或DataGrip连,就是宿主机IP加3306端口,密码用你设置的。这时候你可能会遇到两个经典问题:一是3306端口被宿主机已有MySQL占用,改成-p 3307:3306就行;二是容器启动后状态一直在Restarting,通常是用docker logs mysql8能看到报错,比如数据目录权限不对、内存不够,或者密码环境变量没传进去。

有人还会问我:能不能直接用Docker镜像里的默认配置?能用,但不建议。MySQL 8默认字符集是utf8mb4,基本够用,但你如果部署的是老项目,可能需要改collation。更稳妥的方式是把宿主机上的my.cnf挂载到容器/etc/my.cnf里,改动配置后重启容器即可。这样做的最大好处是,你不需要进容器改文件,因为容器一重建改了的东西就没了。

5.2 为什么这些参数是这么定的

先说-v mysql-data:/var/lib/mysql。MySQL的数据文件默认放在容器的/var/lib/mysql目录,如果你不挂卷,容器重启数据还在,但容器一旦被删除,整个数据目录就跟着没了。我之前有个同事就在测试环境吃了一次这个亏,删容器顺手清环境,结果测试库全没了。用命名卷之后,就算容器被删,只要重新docker run时挂同一个卷,数据就回来了。

再说MYSQL_ROOT_HOST和MYSQL_ROOT_PASSWORD。MySQL官方镜像在首次初始化时会自动执行一些SQL,其中包括创建root用户。如果你不设置MYSQL_ROOT_HOST,默认root只允许localhost连接,那样外部工具根本连不上,只能每次docker exec进去操作。所以开发测试场景我建议直接改成%,生产环境就别这样了,改成固定IP段更安全。

容器的资源限制也是一个隐藏问题。MySQL启动时如果可用的内存或者open files限制过低,会初始化失败。我跑docker run mysql失败过好多次,最后发现是容器默认的/proc/sys/kernel/threads-max或者宿主机ulimit -n到了瓶颈。解决办法是启动时加--ulimit nofile=65535:65535,或者用docker update --memory 2g mysql8来调整。容器看起来轻量,但底层还是Linux,该调的内核参数一个也不能少。

6. 实战二:用Docker搭建Redis主从

6.1 主从部署,容器名就是通信地址

Redis主从复制也是最常见的Docker练习之一,它比MySQL简单,但一样能体现Docker网络编排的价值。我们的目标是启动两个Redis实例,一个主节点,一个从节点,从节点自动复制主节点数据。

先建一个自定义网络,然后启动主节点:

docker network create redis-net docker run -d \ --name redis-master \ --network redis-net \ -p 6379:6379 \ redis:7 \ redis-server --appendonly yes

再启动从节点,注意--network必须一样,replicaof参数指定主节点:

docker run -d \ --name redis-slave \ --network redis-net \ -p 6380:6379 \ redis:7 \ redis-server --replicaof redis-master 6379

验证是否主从同步:

docker exec -it redis-slave redis-cli info replication

看到role:slave和master_link_status:up,就说明从节点已经连上主节点。如果master_link_status:down,第一反应不是去查Redis配置,而是检查这个容器能不能通过容器名ping到主节点。这里就是之前说的自定义网络的作用:没有网络隔离,只用IP地址启动的容器,IP一变主从就断了。用容器名作为地址,重启后依然能互相解析。

6.2 主从部署里的几个大坑

第一个坑是Redis版本差异。Redis 5以前用slaveof,Redis 5以后虽然兼容,但从Redis 7开始官方推荐replicaof。如果你用redis:7镜像然后写--slaveof,也不是不行,但日志里会有deprecation提示,最好直接写replicaof。第二个坑是从库默认是只读的,你在从库上set会报错,这是正常现象,不用慌。第三个坑是数据持久化,Redis可以做RDB快照也可以做AOF日志。上面我用了--appendonly yes,就是开启AOF,把写操作追加到文件里,恢复时比RDB更安全。如果为了性能可以关掉,但主从架构一般建议至少主节点开AOF。

还有一点,很多人喜欢把配置文件挂载进去,这没问题,但要注意容器里的Redis默认是没有配置文件的,用命令行参数和用配置文件效果一样。我更推荐命令行参数,因为一条命令就能看明白配置项,不用额外创建配置文件。当然,生产环境配置项多,还是挂一个redis.conf更清晰。主从复制本身不能替代Redis Cluster,它只解决读扩展和冷备,不解决自动故障转移。要做高可用,还得加哨兵或Cluster,那就是另一个主题了。

7. 实战三:Docker部署青龙面板与容器依赖管理

7.1 一条命令跑起来

青龙面板是很多人在服务器上部署定时任务管理工具时首选的面板,它提供Web界面,能管理脚本、依赖、定时规则和运行日志。用Docker部署非常快:

docker run -d \ --name qinglong \ -p 5700:5700 \ -v ql-data:/ql/data \ --restart=unless-stopped \ whyour/qinglong:latest

启动后访问http://服务器IP:5700,第一次打开会让你初始化账号密码。数据卷ql-data:/ql/data对应面板的配置、脚本、日志、数据库文件。这里我要强调一句:青龙的依赖管理比脚本本身还重要,很多人容器跑了几天,脚本一更新就报ModuleNotFoundError,就是依赖没管好。

7.2 依赖管理为什么要放在面板里

先说清楚一个概念:你在容器里手动执行的pip install、npm install,都写在了容器可写层里。容器重建后,这些安装的包全部丢失。所以正确做法是,把依赖安装交给青龙面板的“依赖管理”模块。它在Web界面里操作,会把依赖列表持久化到数据卷中,每次容器重建后,你再点一次安装就能恢复环境。

具体操作是:登录青龙面板,找到依赖管理,添加要安装的依赖,比如Python脚本常用requests、aiohttp、pandas,Node脚本常用axios、crypto-js、ts-node。有些脚本需要系统级依赖,比如build-essential,那在面板里可能装不了,你还得docker exec -it qinglong bash进去用包管理器装,但记住这只是临时方案,后续重建又会丢。所以核心思路是:一切能放进面板依赖管理里的,就尽量用面板装,不要图省事直接进容器。

我还遇到过一种情况:面板里已经显示某个依赖装好了,但脚本运行还是报找不到模块。这时候先看安装日志,青龙对依赖原包名和实际安装名有映射,有些包名带版本号时必须写完整。确认无误后,在面板里卸载再重装,一般就好了。我自己踩过的坑是给Node环境装了Python包的依赖,导致一堆冲突,后来全部清空,按脚本作者说明重新一个个装,问题瞬间解决。

8. 常见问题与排查技巧实录

8.1 Windows Docker Desktop启动失败排查

前面安装篇提到了两个报错,我再汇总一下排查步骤。遇到virtualization support not detected时,请依次检查BIOS虚拟化、Windows功能面板的“虚拟机平台”和“适用于Linux的Windows子系统”、以及是否安装了WSL2内核更新包。很多人的电脑明明是i7/锐龙,性能完全够了,但BIOS里虚拟化就是默认关闭,买回来一直没开过,所以第一步一定是看任务管理器的“虚拟化”状态。

遇到failed to connect to the docker api at npipe:////./pipe/dockerDesktopLinuxEngine,核心是Docker引擎没起来。先看托盘图标是红还是绿,红色就右键Restart;如果Restart没用,就到命令行执行wsl --shutdown然后重新启动Docker Desktop。如果连WSL本身都挂了,可以试试wsl --update。这个方法能治好绝大多数桌面版抽风问题。另外建议不要在Docker Desktop设置里乱改Experimental特性,有时候改了之后引擎反而不稳定,我遇到过好几次改完开关再也没起来的情况。

8.2 Docker服务启动失败与权限错误

Linux上Docker服务启动失败,第一步永远是看日志:

systemctl status docker journalctl -u docker -n 50

常见原因是daemon.json配置格式错误,你可以在终端执行dockerd看它直接报什么错,如果提示JSON parse error,就去把/etc/docker/daemon.json修好。还有是磁盘空间不足,Docker需要至少几十MB来跑,但镜像和容器多了之后,磁盘满会导致pull和run都失败,用docker system prune -a清一波。

权限错误也是一大高频问题,报错通常长这样:

dial unix /var/run/docker.sock: connect: permission denied

这代表你当前用户没有权限访问Docker守护进程的socket。解决办法是把用户加入docker组,然后重新登录或者执行newgrp docker。不过要提醒一下:能加入docker组的用户,基本等同于能拿到宿主机root权限,因为Docker本身提供了挂载宿主机目录和逃逸的风险,所以生产环境不要随便给人加docker组。

8.3 容器跑起来但连不上/数据不对

我整理了一个速查表,你在排错时对照着看会省很多时间:

症状可能原因解决办法
宿主机访问容器端口失败端口映射没写或防火墙拦截检查-p参数,放行宿主机端口
容器之间网络不通不在同一个自定义网络docker network connect加入同一网络
容器内访问宿主机服务失败localhost指的是容器自己使用host.docker.internal或宿主机IP
容器重启后数据丢失没挂数据卷使用-v或--mount挂载卷
容器启动后一直Restarting配置错误或资源不足docker logs查看具体报错
MySQL/Redis连不上容器内服务绑定127.0.0.1修改容器内配置监听0.0.0.0

这里有个通用技巧:不要光盯着命令,要养成看日志的习惯。docker logs -f 容器名是排错第一入口,很多问题在日志里已经写得明明白白了。比如Redis从节点连不上主节点,日志会直接告诉你Unable to connect to redis-master:6379,这时候99%是网络问题,剩下的1%是DNS解析问题。

8.4 镜像构建与微服务部署的通用技巧

最后聊聊镜像构建,因为前面都在讲拉现成镜像,真正实际的微服务项目一定涉及自己打镜像。一个最基础的Node服务Dockerfile长这样:

FROM node:20-alpine WORKDIR /app COPY package*.json ./ RUN npm install COPY . . CMD ["node", "server.js"]

构建镜像用docker build -t my-app:1.0 .。注意RUN和CMD的区别:RUN是构建阶段执行的,用来装依赖、编译代码;CMD是容器启动后才执行的,指定默认启动命令。还有ENTRYPOINT,它和CMD容易搞混。简单说,ENTRYPOINT是固定的入口命令,很难被覆盖;CMD是默认参数,可以在docker run后面覆盖。如果只想提供一个默认启动命令,用CMD就够了;如果想确保容器一定执行某个初始化脚本,用ENTRYPOINT更稳。

在IDEA里你可以装Docker插件,直接在代码目录右键“Build Image”,也可以在pom.xml里配置Spotify或fabric8插件,Maven构建时顺手把镜像推送仓库。部署微服务项目时,用docker-compose把所有服务聚在一起,上线时在服务器上docker compose up -d,回滚时docker compose pull再up -d,比手动一个个启停靠谱得多。

最后还有个小提醒,也是我踩过几次坑之后养成的新习惯:不管是用Docker Desktop还是Linux服务器,遇到莫名其妙的问题,先重启Docker服务再排查。这个操作能治好一半的抽风问题,尤其是网络和管道连接类的异常。启动时如果遇到daemon.json改过,先验证JSON格式;运行中遇到权限错误,先看用户组和日志。Docker的门槛不高,但细节非常多,把这些高频问题记心里,你就能少熬很多夜。

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

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

立即咨询