新闻详情

新闻详情

首页 / 资讯中心 / 详情

Docker容器化实战指南:从镜像构建到Compose编排

发布时间:2026/9/15 4:05:33来源:尧图网络
Docker容器化实战指南:从镜像构建到Compose编排
1. 项目整体思路为什么把 Docker 比作房地产开发我第一次跟团队讲 Docker 的时候发现新人最容易卡住的地方不是命令记不住而是脑子里没有一张完整的图。装个 MySQL 要敲 docker run部署个项目要写 Dockerfile上了规模又冒出 docker compose每个概念单独看都能懂连起来就不知道谁跟谁是一伙的。后来我琢磨出一个比喻一直用到现在Docker 就是搞房地产开发。镜像文件就是施工图纸容器就是盖好的房子Docker Hub 是建材市场数据卷是你装修时自己打的柜子docker compose 则是整个小区的物业管理方案。这套类比一出来新同事上手速度明显快了很多报错自己都能猜到大概是什么环节出了问题。为什么这个比喻成立因为容器化的本质就是把一套应用连同它的运行环境一起打包、交付、运行这个过程和房地产从设计到交付再到物业维护的链路几乎一一对应。你画图纸构建镜像照着图纸盖楼创建容器楼盖好了业主入住容器运行业主对户型有要求就打隔断改格局挂载数据卷、改配置小区人多了要统一管理docker compose 编排房子漏水停电要找物业日志、监控、重启策略。理解了这个对应关系你就知道每个 Docker 概念应该在什么场景下用而不是死记命令。这篇文章不是从零开始的 Docker 入门教程那玩意网上一抓一大把。我想做的是把容器化这件事从开发到落地的主线捋清楚按照房地产开发的全流程来讲每个环节给你能直接抄的配置和命令再把我踩过的坑、排查问题的方法一并交代清楚。适合已经会敲 docker run 但对整体架构没感觉的人也适合被容器化部署折腾过几次、想系统补一课的人。2. 施工图纸阶段镜像构建与分层存储2.1 镜像不是装好的系统盘而是一份可复制的完整图纸很多人第一次接触 Docker 都会有个误解镜像差不多就是打包好的操作系统把整个系统盘复制一份出来用。这个理解不算全错但会误导你对镜像体积和构建方式的判断。真实情况是镜像是一套分层存储的只读模板。每一层对应 Dockerfile 里的一条指令多个镜像如果底层相同这些层是可以共享的。你本地拉了一个 ubuntu 镜像又拉了一个基于 ubuntu 的 mysql 镜像后者并不会把整个 ubuntu 再复制一遍而是直接复用已有的底层这就是为什么 Docker 占用的磁盘空间往往比你想的小得多。理解分层对写 Dockerfile 特别重要。一条指令形成一个层层是缓存的基本单位。你改了 Dockerfile 里某一层的内容这一层之后的所有层缓存都会失效需要重新构建。所以经验丰富的开发者会把变化频繁的内容往后放把不常变的基础依赖往前放这样每次改代码重新构建镜像时大部分时间都花在最上层的代码拷贝上几分钟的构建能省到几十秒。我见过不少人图省事把整个项目文件 COPY 进去然后在容器里装依赖、跑编译。这么做镜像能跑但每次代码一变依赖层缓存全废构建时间成倍上涨传到仓库也慢。正确做法是先 COPY 依赖声明文件比如 package.json、requirements.txt装好依赖再 COPY 源码。这样源码变化不会触发依赖层重建和房地产里先把标准户型图纸定下来、再改软装方案是一个逻辑承重墙和管线依赖不动只换家具摆设业务代码。2.2 多阶段构建把毛坯房和精装修分开再往上走一步就是多阶段构建。早期大家用 Docker 部署 Java 或前端项目经常遇到一个尴尬构建环境和运行环境的需求完全相反。编译 Java 需要 JDK 和 Maven跑起来只要 JRE前端打包需要 Node.js跑起来只需要一个静态文件服务器。如果强行塞进一个镜像体积轻则几百兆重则一两个 G而且里面塞满了构建工具全是潜在的攻击面。多阶段构建的思路就四个字各取所需。用第一个阶段装着完整工具链把编译做完然后把编译产物复制到第二个阶段第二个阶段只装运行时要的东西。写法也不复杂# 阶段一构建 FROM golang:1.21 AS builder WORKDIR /app COPY go.mod go.sum ./ RUN go mod download COPY . . RUN CGO_ENABLED0 go build -o app . # 阶段二运行 FROM alpine:3.19 WORKDIR /root/ COPY --frombuilder /app/app . EXPOSE 8080 ENTRYPOINT [./app]这段 Dockerfile 最有价值的点在于 COPY --frombuilder它直接把第一阶段构建好的二进制文件拿过来用没有把构建工具链带进最终镜像。我实测下来一个 Go 项目用这种方法从 800 多兆压到 20 兆出头部署速度天差地别。前端项目也是同理老老实实在 node 镜像里 npm run build产物放到 nginx 镜像里整个镜像能保持在 50 兆以内。多阶段构建还顺便解决了一个烦人的问题不用再手动清理构建缓存了。以前单阶段构建你得在 Dockerfile 里专门 RUN 一些清理命令删了系统包缓存、npm 缓存什么的。现在根本不用管构建阶段产生的东西在 COPY 之后就被 Docker 丢弃了干净得很。这就好比你装修毛坯房的时候材料堆得满地都是交房前全拉走业主看到的就是清爽整洁的成品房。2.3 镜像仓库建材市场与私有仓库的取舍镜像构建完要分发才能用这就轮到仓库登场。Docker Hub 是公共建材市场什么货都有但也意味着拉取速度不稳定、有被限流的风险。国内团队做生产项目我建议至少平时用国内公共仓库做加速公司的私有镜像放私有仓库。搭建一个私有镜像仓库没有想象的复杂。跑一个 registry 容器就行docker run -d -p 5000:5000 --name registry \ -v /opt/registry/data:/var/lib/registry \ -e REGISTRY_STORAGE_DELETE_ENABLEDtrue \ --restartunless-stopped \ registry:2这里特别注意 REGISTRY_STORAGE_DELETE_ENABLEDtrue不开这个registory 的 Web API 默认禁止删除镜像你调删除接口会报 405磁盘满了只能手动进容器删文件非常狼狈。我踩过一次这个坑半天没查出为什么 API 删不掉最后看官方文档才发现是这个开关的问题。推送和拉取私有仓库镜像时Docker 默认要求 HTTPS本地测试或者内网环境没有证书的话得在 /etc/docker/daemon.json 里把对应地址加到 insecure-registries 列表。改完这个文件一定要重启 docker 服务而不是 reload因为守护进程读取的参数有些是 reload 不生效的。这个问题后来在很多生产环境排查记录里都见过非常典型。3. 盖楼阶段容器运行时的核心实操3.1 从镜像到容器run 命令背后的资源隔离镜像有了接下来就是照着图纸盖楼也就是 docker run。容器是镜像的运行实例它和镜像是两个层次的东西。镜像可以无限次创建容器容器之间互不影响改一个容器的环境变量也不会污染镜像。多个容器同时跑同一个镜像就像用同一套图纸盖了很多栋相同户型的楼每栋楼的业主是谁互不相干。docker run 最核心的几个参数说来说去就这几个-d 后台运行-p 端口映射-v 数据卷挂载-e 环境变量--name 指定名字--restart 设置重启策略。我建议新手把这条命令反复抄十遍把每个参数理解透docker run -d \ --name mysql-dev \ -p 3306:3306 \ -e MYSQL_ROOT_PASSWORDyour_password \ -e MYSQL_DATABASEtestdb \ -v mysql_data:/var/lib/mysql \ -v /etc/localtime:/etc/localtime:ro \ mysql:8.0 --character-set-serverutf8mb4 --collation-serverutf8mb4_unicode_ci-p 3306:3306 的含义是宿主机 3306 端口映射到容器 3306 端口。左边是宿主机右边是容器这个顺序有人经常搞反结果发现访问端口不通排查半天。如果宿主机端口冲突可以把左边的改成别的比如 -p 33061:3306容器内部逻辑完全不用动。-e 是环境变量MYSQL_ROOT_PASSWORD 和 MYSQL_DATABASE 都是 MySQL 官方镜像约定好的初始化变量第一次启动数据目录为空时自动生效。容器里改配置不方便时用环境变量注入是最干净的方式。但注意环境变量只对容器内的进程可见docker inspect 能看到安全性一般真正的密钥还是得用 Docker secrets 或专门的管理方案。-v mysql_data:/var/lib/mysql 是具名数据卷这个和后面 -v /etc/localtime:/etc/localtime:ro 有点不一样。冒号前面是宿主机路径的叫绑定挂载直接映射宿主机某个目录不带路径的 mysql_data 是 Docker 自己管理的具名卷存放在 /var/lib/docker/volumes/ 下面。生产环境我倾向于具名卷因为数据目录由 Docker 管理备份恢复都方便也不容易因为宿主机路径权限问题出错。mysql:8.0 后面的那串 --character-set-serverutf8mb4 不是 docker run 的参数而是传给容器内 mysqld 的命令行参数。docker run 镜像名后面的一切内容都会作为容器入口命令的参数传进去。这是新手最容易懵的点为什么同样一条 docker run别人镜像名后面能跟这么多东西。搞清楚入口点和参数传递机制之后很多自定义配置都能用这种方式做不用专门写配置文件。3.2 数据卷和容器文件的生存周期容器是临时性的rm 一下就没了但数据不能跟着没。数据卷就是解决这个问题的。从设计哲学上说容器应该是无状态的任何需要持久化的东西都必须放到外部存储这是 Docker 部署的铁律。数据和配置分开管理是必须养成的习惯。数据用数据卷配置用挂载文件或者环境变量。我在生产环境部署的时候要求所有微服务的配置文件都通过挂载方式注入镜像本身不携带任何环境特定配置。这样同一个镜像在测试环境和生产环境跑起来行为一致只是挂载的配置不同这才能做到真正意义上的一次构建到处运行。实际运维中最容易出问题的就是文件权限。官方镜像很多以普通用户运行但宿主机挂载目录的属主往往和容器内用户不一致。比如 nginx 镜像默认用 nginx 用户你宿主机挂载目录是 root 所有的nginx 容器就没法写日志或缓存。解决方案要么建目录时把属主改成容器内用户 UID要么在 compose 文件里指定 user 参数。没有统一标准哪个镜像的官方文档怎么写就怎么来但一定要在部署脚本里把这个地方显式写出来别留给后人猜。临时文件如果用 -v 挂载到宿主机是性能浪费容器内部的文件系统虽然也是磁盘但 Docker 默认给了 overlay2 存储驱动读写临时文件和目录的开销比跨宿主机挂载小得多。如果你的应用写日志很频繁优先考虑让应用写 stdout由 Docker 日志驱动统一收集效率比写文件再挂载出来高一截。3.3 网络模式小区里的几种入户方式容器要对外提供服务和容器之间互相通信都得靠网络。Docker 默认提供几种网络模式用下来其实不需要全部精通但 bridge 和 host 必须理解清楚。bridge 是默认模式相当于小区里面的公用路网。每个容器拿到一个独立的虚拟 IP通过端口映射把容器端口暴露到宿主机。这种模式隔离性好端口不冲突适合大多数场景。但这里有个坑容器重新创建后 IP 会变。容器内应用如果写死了别的容器的 IP一旦重建服务就断。正确做法是用 --link 或加入同一个自定义 bridge 网络让容器之间通过服务名互访。自定义 bridge 网络是你真正该用的东西docker network create app-net docker run -d --name web --network app-net -p 8080:80 nginx docker run -d --name api --network app-net my-api这样 web 容器里直接访问 http://api:8080Docker 内置的 DNS 会解析到 api 容器当前的实际 IP。重建 api 容器web 不需要任何变更。这就像小区业主不用记每家每户的门牌号报物业名字物业直接帮你转接。跨集群的服务发现有更复杂的方案但单机或者小规模部署这个用法已经能解决绝大多数问题了。host 模式是直接用宿主机网络栈没有独立 IP也不做端口映射容器监听什么端口宿主机就监听什么端口。好处是性能好没有 NAT 转发损耗适合对网络性能敏感的服务。坏处是端口隔离没了两个 host 模式的容器不能监听同一端口。我一般只在跑性能压测或者某些对网络特别敏感的应用时用 host 模式默认还是 bridge。4. 物业阶段docker compose 与服务编排4.1 compose 到底解决了什么问题单容器用 docker run 没问题但真实项目很少有只跑一个容器的。前端一个容器后端一个容器数据库一个容器缓存一个容器日志再来一个收集器。这时候你用 docker run 一个个敲先不说效率容器之间的网络、启动顺序、依赖关系就够让人头疼。docker compose 的核心价值是把多容器应用的定义集中到一个 docker-compose.yml 文件里用一条 docker compose up -d 全部拉起来。它不只是简化命令更重要的是把整个应用架构以代码的形式固化下来。这个文件和 Dockerfile 一样要提交到版本库新同事拉下来就能起一套一模一样的环境这就是可复现性——和房地产开发里的标准化施工手册差不多的意思。compose 文件还能解决容器间的依赖顺序问题用 depends_on 声明依赖。新版 compose 还支持 healthcheck 条件可以等到依赖服务健康了再启动下游服务services: db: image: mysql:8.0 healthcheck: test: [CMD, mysqladmin, ping, -h, localhost] interval: 5s timeout: 3s retries: 10 app: build: . depends_on: db: condition: service_healthy写依赖的时候注意depends_on 只控制启动顺序不保证依赖服务已经准备好对外服务。MySQL 启动到可以接受连接还有一段初始化时间直接靠 depends_on 不够必须配合 healthcheck 或者应用侧的重试机制。这个坑我亲眼见过多次明明启动了但应用连不上数据库反复重启最后加了健康检查才解决。4.2 实际部署MySQL、Redis 微服务一套带走光说不练假把式我拿一个典型场景来展示完整的 compose 文件业务后端需要 MySQL 存数据、Redis 做缓存和主从读写分离。这是我在多个项目里实际用过的方案直接改名字就能用。version: 3.8 services: mysql: image: mysql:8.0 container_name: app-mysql restart: unless-stopped environment: MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD} MYSQL_DATABASE: ${MYSQL_DATABASE} MYSQL_USER: ${MYSQL_USER} MYSQL_PASSWORD: ${MYSQL_PASSWORD} command: - --character-set-serverutf8mb4 - --collation-serverutf8mb4_unicode_ci volumes: - mysql_data:/var/lib/mysql - ./mysql/init:/docker-entrypoint-initdb.d:ro ports: - 3306:3306 networks: - app-net healthcheck: test: [CMD, mysqladmin, ping, -h, localhost, -u${MYSQL_USER}, -p${MYSQL_PASSWORD}] interval: 10s timeout: 5s retries: 5 redis-master: image: redis:7 container_name: app-redis-master restart: unless-stopped command: [redis-server, --appendonly, yes, --requirepass, ${REDIS_PASSWORD}] volumes: - redis_master_data:/data ports: - 6379:6379 networks: - app-net redis-slave: image: redis:7 container_name: app-redis-slave restart: unless-stopped depends_on: - redis-master command: [redis-server, --slaveof, redis-master, 6379, --masterauth, ${REDIS_PASSWORD}, --requirepass, ${REDIS_PASSWORD}] volumes: - redis_slave_data:/data ports: - 6379:6380 networks: - app-net app: build: ./app container_name: app-server restart: unless-stopped depends_on: mysql: condition: service_healthy redis-master: condition: service_started environment: DB_HOST: mysql DB_PORT: 3306 DB_USER: ${MYSQL_USER} DB_PASSWORD: ${MYSQL_PASSWORD} DB_NAME: ${MYSQL_DATABASE} REDIS_HOST: redis-master REDIS_PORT: 6379 REDIS_PASSWORD: ${REDIS_PASSWORD} ports: - 8080:8080 networks: - app-net networks: app-net: driver: bridge volumes: mysql_data: redis_master_data: redis_slave_data:这个文件里有几个细节值得专门讲。首先MYSQL_USER 和 MYSQL_PASSWORD 这些来自 .env 文件compose 会自动读取当前目录下的 .env 文件里的变量替换到配置中。这样 docker-compose.yml 本身可以提交到代码库而 .env 加入 .gitignore不同的环境只需要维护不同的 .env。其次MySQL 的 ./mysql/init 目录挂载。这个目录下的 .sql 或 .sh 文件会在容器首次初始化数据目录时按顺序执行适合初始化表结构、导入基础数据非常实用。但注意只在数据目录为空的时候执行一旦数据卷有了数据再改 init 脚本不会重新执行。改了初始化脚本想重建环境得 docker compose down -v 把卷一起删了再 up这个操作会清空数据生产环境千万谨慎。Redis 主从配置我用的是启动参数直接传没走 redis.conf 文件好处是配置看得见摸得着环境变量驱动不用维护一堆配置文件。新版本的 Redis 里 slaveof 已经改名 replicaof但目前两个都兼容。生产环境要求高的话需要给主库加一个固定 IP 或者在 compose 里指定主库容器名从库配置 slaveof 时直接用服务名 redis-master这就是前面说的自定义网络 DNS 解析发挥作用的地方。4.3 环境一致性开发、测试、生产用同一套 Compose团队协作中最大的隐性成本是环境不一致。A 同事的电脑上好好的B 同事跑不起来最后发现是本机装的 MySQL 版本不一样依赖的时区配置不一样系统库缺了一个编译依赖。Compose 文件提交到代码库这个问题能大幅度缓解。我建议团队在项目根目录维护三套 compose 相关文件docker-compose.yml 放公共定义docker-compose.override.yml 放开发环境的覆盖配置比如开发时挂载源码实现热更新开放所有端口方便调试生产环境用 docker-compose.prod.yml 覆盖资源限制和副本数等参数。启动时指定docker compose -f docker-compose.yml -f docker-compose.prod.yml up -ddocker compose 支持多个 -f 文件叠加后面的文件会覆盖前面的同名配置。这个机制给了你很大的灵活性。默认情况下 compose 会自动读取 docker-compose.override.yml所以开发环境直接 docker compose up 就行生产环境显式指定 prod 文件。一套代码三种环境行为一致但配置分离这才是容器化部署落地的正确姿势。还需要提一下环境变量文件的管理。.env 文件虽然不入库但我一般会在代码库提交一个 .env.example把需要的变量列全每个变量给一个示例值或者格式说明。新同事拿到项目先把 .env.example 复制成 .env 再改步骤固定不容易漏。业务环境里很多配置错乱问题最终排查下来都是 .env 里某个变量没定义compose 传空字符串进去各种诡异现象就来了。5. 常见问题与排查技巧实录5.1 镜像拉取慢与配置仓库加速器国内拉公共镜像慢是常态这个问题很多人都会遇到。解决办法是配置镜像仓库加速器在 /etc/docker/daemon.jsonWindows 是 Docker Desktop 的设置界面里填入国内可用的镜像加速地址。填好后重启 Dockerdocker info 就能看到生效的 Registry Mirrors。这个文件要写成合法 JSON我见过有人把多个配置项写成一行导致整个 Docker 服务起不来的情况。改这个文件要特别小心改坏了可以先 docker rm -f 跑着的容器吗不行Docker 守护进程本身起不来了所有容器都跟着遭殃。稳妥的做法是改动前先备份原文件改完用 python 或 jq 工具校验一下 JSON 合法性再重启服务。Windows 版的 Docker Desktop 直接在设置界面点选就行不用手动改文件。另外 docker pull 特别慢的时候镜像体积大往往也是主因。这时候多阶段构建的威力就体现出来了把最终镜像控制在最小体积拉取时间自然就下来了。很多团队的 docker pull 慢是垃圾大镜像造成的不全是网络问题。5.2 Windows 和 Docker Desktop 的虚拟化问题Docker Desktop 在 Windows 上最常见的启动报错是 failed to start because virtualisation support wasnt detected很多新装 Docker 的人都会被这句报错卡住。这个提示翻译过来就是Windows 没有开启硬件虚拟化功能。排查路径有三步。第一步检查 BIOS/UEFI 里的 Intel VT-x 或 AMD SVM 是否开启这块需要在开机时进 BIOS 设置不同品牌主机入口不同一般是 F2、Del、F12 这类的键开启后保存重启。第二步确认 Windows 功能里 Hyper-V 和虚拟机平台这两个功能是否已启用可以在控制面板的启用或关闭 Windows 功能里勾选也可以用管理员 PowerShell 执行 Enable-WindowsOptionalFeature -Online -FeatureName Microsoft-Hyper-V -All 和 Enable-WindowsOptionalFeature -Online -FeatureName VirtualMachinePlatform。第三步检查是否安装了适用于 Linux 的 Windows 子系统WSL 2新版 Docker Desktop 默认依赖 WSL 2 后端。还要注意一种情况机器上装了别的虚拟机软件比如 VMware 或 VirtualBox它们和 Hyper-V 可能冲突。老版本 VMware 和 Hyper-V 确实不能共存新版本 VMware 15.5 以上已经在很多场景下兼容了但如果你遇到奇怪的问题可以考虑关闭 Hyper-V 或者改用 WSL 2 后端。这个问题没有统一的解得根据你本机环境实测。Windows 下还有一个高频坑Docker Desktop 启动成功了但容器里挂载的本机目录访问权限不对。这是因为 WSL 2 的权限模型和 Windows 不完全一致挂载的 Windows 路径在容器内显示为 /run/desktop/mnt/host/c/...Nginx 之类的容器写这些目录经常被拒。方案是尽量用 Docker 管理的卷或者把文件路径换成 Linux 子系统的路径再或者在容器内用 user root 运行命令绕过但后者不建议作为长期方案。5.3 容器内服务启动失败的常规排查流程容器起不来是另一个高频问题。docker run 之后什么叫起不来一种是 docker ps 看不到容器一种是容器在但应用没正常提供服务。这两种情况排查路径不一样。容器直接退出的先用 docker logs 容器名 看日志。很多启动脚本的执行错误都会打印在这个日志里。如果日志是空的或者 Docker 层面就报错用 docker inspect 容器名 看 State 和 ExitCode。ExitCode 非零说明主进程异常退出常见的如 shell 脚本权限问题、依赖服务不可达、配置解析失败。有时候 restart 策略设成了 always容器一直在重启循环docker ps 能看到一个 Up X seconds 的状态反复变化这时候用 docker logs 看最近一版日志往往就能定位。容器在跑但服务访问不通优先查端口映射。docker port 容器名 能显示当前实际的端口映射关系。如果是 bridge 网络检查 -p 有没有指定对宿主机端口被占用也会导致映射失败但这种情况 docker run 通常会直接报错。如果访问的是 127.0.0.1:8080检查应用有没有监听 0.0.0.0很多应用默认只监听 localhost容器外就访问不到。最后再分享一个我常用的组合拳docker exec -it 容器名 sh 进容器内部用 curl 或 wget 测试服务自身是否正常。如果容器内能访问但宿主机不能问题在端口映射或网络如果容器内也不能问题在应用本身的监听地址或防火墙。这一步能快速缩小排查范围省去很多瞎折腾的时间。我把这些高频问题整理成一张表方便你直接对照排查。症状可能原因处理方式docker pull 很慢镜像源未配置或网络限制配置镜像加速重启 Docker 服务Docker Desktop 启动失败提示虚拟化不支持BIOS 未开虚拟化、Hyper-V/WSL2 未启用进 BIOS 开启 VT-x/AMD SVM启用相关 Windows 功能容器启动后秒退主进程异常退出、配置或依赖错误docker logs 看日志docker inspect 看 ExitCode容器在跑但端口访问不通端口映射错误、应用监听 127.0.0.1检查 docker port容器内 curl 自测改监听 0.0.0.0容器内写文件报权限错误挂载目录属主与容器用户不一致调整目录属主或使用 Docker 管理卷容器重建后 IP 变了导致访问异常容器间写死 IP 地址使用自定义网络通过服务名互访Docker 服务本身启动失败daemon.json JSON 格式出错检查 JSON 合法性恢复备份配置6. 生产环境落地的最后几件小事到这里整套流程已经能跑通了但真正拿到生产环境用还有几个细节会影响稳定性我单独拿出来讲讲。容器的资源限制不是可选项是必选项。一个 Java 服务内存泄漏直接能把整台机器搞垮其他容器全部陪葬。在 compose 文件里给每个服务都加上资源限制deploy: resources: limits: cpus: 1.0 memory: 512M reservations: cpus: 0.25 memory: 128M单机用 docker compose 时 deploy 段也能被识别无需非得在 swarm 模式下才能用。limits 是硬上限超过会被 cgroup 直接杀掉进程reservations 是预留值调度和亲和性相关。内存限制务必设置写 Java 应用尤其要注意堆内存配置和容器内存限制匹配否则容易 OOM 被系统杀掉。重启策略统一用 unless-stopped 而不是 always这是个人经验。unless-stopped 表示除非手动停止否则自动重启always 则不管什么原因停止都会拉起来包括你手动 docker stop 之后重启 Docker 服务又给你拉起来了如果你是想临时停一个容器维护这个行为会很烦人。日志管理也不能忽视。容器默认的日志驱动没有任何轮转策略一个高并发的服务写几天日志磁盘就能被撑爆。在 daemon.json 或 compose 文件里加上 log 配置限制每容器的日志大小logging: driver: json-file options: max-size: 10m max-file: 3这样单容器日志最多保留三份 10MB 的文件总共 30MB不会再无限制增长。如果你们有集中式日志系统比如 ELK 或 Loki可以换相应的日志驱动但在这之前 json-file 加上轮转参数是最稳妥的起步方案先把磁盘撑爆这种事故从根上杜绝。关于镜像的版本管理我强烈建议生产环境固定镜像 tag不要用 latest。latest 在本地开发很方便但生产环境一旦拉到新版本行为就可能发生变化而且 docker pull 的时候不会让你知道拉到了新版。正确的玩法是构建镜像时打版本号 tag比如 myapp:v1.2.3compose 文件里写死这个版本。镜像仓库里保留最近几个版本老的及时清理这样不管是回滚还是排查问题都有清晰的记录。安全方面的几个基本习惯也顺带提一下容器尽量不用 root 用户运行基础镜像优先选官方发布且定期更新的版本敏感信息比如数据库密码不要直接写进 compose 文件用 .env 文件管理并做好权限控制。外人看来这些都是小事但生产环境的安全事故绝大多数都是从这些小细节被突破的。从我这些年的实际经验来看Docker 这套工具链本身不复杂复杂的是把它用好需要建立一套完整的运维思维。镜像分层、数据持久化、服务编排、日志管理、资源限制每个环节都像房地产开发里的一道工序单独看都不难串起来才能形成一套稳定可靠的应用交付体系。希望这篇用房地产开发串起来的容器化指南能帮你把整个链路在脑子里建立起来下次再遇到问题至少能判断出是哪一个环节出了岔子而不是像无头苍蝇一样到处查。
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

OpenVINO加速YOLOv8四大任务实战指南 2026/9/15 4:59:36

OpenVINO加速YOLOv8四大任务实战指南

简介:本资源是一套面向计算机、电子信息工程及数学等专业学生的YOLOv8多任务OpenVINO推理实践方案,覆盖图像分类、目标检测、实例分割与人体姿态估计四大核心视觉任务,适用于课程设计、期末大作业或毕业设计中的模型部署环节。压缩包共11个文…

阅读更多 →
Sonarr全攻略:从零搭建自动化剧集管理与追更系统 2026/9/15 4:59:36

Sonarr全攻略:从零搭建自动化剧集管理与追更系统

玩转 Sonarr:从零搭建自动化剧集管理与追更系统先聊个场景:你手上有 NAS,有 PT 站或各类下载工具,每次追新剧都得自己手动去站点搜资源、下载、等文件分类命名,再手动整理到媒体库目录里。前几集还行,追到十…

阅读更多 →
飞书与腾讯会议对接实战:SSO+Webhook+Docker中间件设计 2026/9/15 4:59:36

飞书与腾讯会议对接实战:SSO+Webhook+Docker中间件设计

1. 为什么“飞书—腾讯会议对接”不是简单配个Webhook就能跑通?飞书和腾讯会议,这两个国内企业协同工具的头部玩家,在实际办公场景里经常被同时部署——市场团队用飞书做项目管理与知识沉淀,销售团队用腾讯会议开客户演示&#xf…

阅读更多 →
微信小程序健康菜谱源码解析与工程实践 2026/9/15 4:59:36

微信小程序健康菜谱源码解析与工程实践

简介:本资源是一套完整可运行的微信小程序健康菜谱项目源码,面向前端初学者及小程序开发入门者,解决从零构建功能完备的饮食类应用的学习与实践需求。压缩包共142个文件,包含16个JS逻辑文件(如index.js、search.js、li…

阅读更多 →
鸿蒙人脸识别门禁项目验收评测:从端侧性能到数据安全的完整指南 2026/9/15 4:59:36

鸿蒙人脸识别门禁项目验收评测:从端侧性能到数据安全的完整指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
内容规划的核心:从场景匹配到内容体系搭建的实操指南 2026/9/15 4:56:36

内容规划的核心:从场景匹配到内容体系搭建的实操指南

很多人以为做内容规划就是拿张表格把未来一个月的推送排满,我曾经也这么干过,结果看着日历上密密麻麻的选题,后台数据却一片惨淡。后来我才慢慢意识到,内容规划的本质不是"这个月发什么",而是"用户在什…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞