Java 项目部署之 Docker工具快速入门: 学习路径与命令速查导引

概述

微服务拆完之后,代码写得再漂亮也会卡在最后一步:怎么把十几个服务、MySQL、Nacos、Redis 一起塞到服务器上跑起来。Docker 这一章就是解决这个问题的,本文是整章的导引,先把地图摊开,再一站一站走。

纲要

  • 为什么后端工程师躲不开 Docker:环境一致性、交付形态、微服务部署三笔账
  • 本章知识地图:初识 Docker → 基本操作 → 自定义镜像 → DockerCompose → 镜像仓库
  • 每一站解决什么问题、对应哪些命令
  • 按阶段分组的命令速查表(后续各篇的索引)
  • 学习建议:哪些必须动手跑一遍,哪些可以先理解后补

为什么后端必须会 Docker

先看一个几乎每个人都遇到过的场景。本地 mvn package 打出来的 xxx.jar,在自己机器上 java -jar 跑得好好的,扔到测试服务器上直接报错:

text 复制代码
Exception in thread "main" java.lang.NoClassDefFoundError: javax/xml/bind/DatatypeConverter
Caused by: java.lang.ClassNotFoundException: javax.xml.bind.DatatypeConverter

代码一行没动。差别在于本地是 JDK 8,服务器上是 JDK 11,javax.xml.bind 在 9 之后被移出 JDK 了。这就是依赖兼容问题:同一个 jar,换一套 JDK、换一套 MySQL 客户端库、换一个 glibc 版本,就活了或者死了。

第二笔账是操作系统环境差异 。运维给你的机器装了什么内核参数、时区设成 UTC 还是 Asia/Shanghai、有没有那个特定的 .so 动态库,你控制不了。出了问题排查链路长得离谱,最后发现是服务器 locale 不是 UTF-8,日志里中文全是问号。

第三笔账是部署成本。SpringCloud 里一个业务拆成三四份服务,加上注册中心、网关、数据库,手动部署的流程是:装 JDK、装 MySQL、传 jar、写启动脚本、配开机自启......每台机器来一遍,新同学入职配环境一天就没了。

Docker 的思路很直接:把应用和它需要的一切依赖打包成一个标准单元,从开发机到测试机到生产机,跑的都是同一个东西。环境差异被关进容器里,交付物从"一堆 jar + 一份部署文档"变成"一个镜像"。
#mermaid-svg-cEAIQG7PFzVb3Nt6{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-cEAIQG7PFzVb3Nt6 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-cEAIQG7PFzVb3Nt6 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-cEAIQG7PFzVb3Nt6 .error-icon{fill:#552222;}#mermaid-svg-cEAIQG7PFzVb3Nt6 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-cEAIQG7PFzVb3Nt6 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-cEAIQG7PFzVb3Nt6 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-cEAIQG7PFzVb3Nt6 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-cEAIQG7PFzVb3Nt6 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-cEAIQG7PFzVb3Nt6 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-cEAIQG7PFzVb3Nt6 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-cEAIQG7PFzVb3Nt6 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-cEAIQG7PFzVb3Nt6 .marker.cross{stroke:#333333;}#mermaid-svg-cEAIQG7PFzVb3Nt6 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-cEAIQG7PFzVb3Nt6 p{margin:0;}#mermaid-svg-cEAIQG7PFzVb3Nt6 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-cEAIQG7PFzVb3Nt6 .cluster-label text{fill:#333;}#mermaid-svg-cEAIQG7PFzVb3Nt6 .cluster-label span{color:#333;}#mermaid-svg-cEAIQG7PFzVb3Nt6 .cluster-label span p{background-color:transparent;}#mermaid-svg-cEAIQG7PFzVb3Nt6 .label text,#mermaid-svg-cEAIQG7PFzVb3Nt6 span{fill:#333;color:#333;}#mermaid-svg-cEAIQG7PFzVb3Nt6 .node rect,#mermaid-svg-cEAIQG7PFzVb3Nt6 .node circle,#mermaid-svg-cEAIQG7PFzVb3Nt6 .node ellipse,#mermaid-svg-cEAIQG7PFzVb3Nt6 .node polygon,#mermaid-svg-cEAIQG7PFzVb3Nt6 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-cEAIQG7PFzVb3Nt6 .rough-node .label text,#mermaid-svg-cEAIQG7PFzVb3Nt6 .node .label text,#mermaid-svg-cEAIQG7PFzVb3Nt6 .image-shape .label,#mermaid-svg-cEAIQG7PFzVb3Nt6 .icon-shape .label{text-anchor:middle;}#mermaid-svg-cEAIQG7PFzVb3Nt6 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-cEAIQG7PFzVb3Nt6 .rough-node .label,#mermaid-svg-cEAIQG7PFzVb3Nt6 .node .label,#mermaid-svg-cEAIQG7PFzVb3Nt6 .image-shape .label,#mermaid-svg-cEAIQG7PFzVb3Nt6 .icon-shape .label{text-align:center;}#mermaid-svg-cEAIQG7PFzVb3Nt6 .node.clickable{cursor:pointer;}#mermaid-svg-cEAIQG7PFzVb3Nt6 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-cEAIQG7PFzVb3Nt6 .arrowheadPath{fill:#333333;}#mermaid-svg-cEAIQG7PFzVb3Nt6 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-cEAIQG7PFzVb3Nt6 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-cEAIQG7PFzVb3Nt6 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-cEAIQG7PFzVb3Nt6 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-cEAIQG7PFzVb3Nt6 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-cEAIQG7PFzVb3Nt6 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-cEAIQG7PFzVb3Nt6 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-cEAIQG7PFzVb3Nt6 .cluster text{fill:#333;}#mermaid-svg-cEAIQG7PFzVb3Nt6 .cluster span{color:#333;}#mermaid-svg-cEAIQG7PFzVb3Nt6 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-cEAIQG7PFzVb3Nt6 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-cEAIQG7PFzVb3Nt6 rect.text{fill:none;stroke-width:0;}#mermaid-svg-cEAIQG7PFzVb3Nt6 .icon-shape,#mermaid-svg-cEAIQG7PFzVb3Nt6 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-cEAIQG7PFzVb3Nt6 .icon-shape p,#mermaid-svg-cEAIQG7PFzVb3Nt6 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-cEAIQG7PFzVb3Nt6 .icon-shape .label rect,#mermaid-svg-cEAIQG7PFzVb3Nt6 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-cEAIQG7PFzVb3Nt6 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-cEAIQG7PFzVb3Nt6 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-cEAIQG7PFzVb3Nt6 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 微服务拆得越多
部署越麻烦
依赖兼容问题

JDK/库版本不一致
操作系统差异

内核/时区/locale
部署流程重复

每台机器手工装环境
Docker: 应用+依赖一起打包
镜像作为标准交付物

一次构建, 到处运行

本章知识地图

整章是一条从"认识"到"用起来"再到"管起来"的线,五站走完就能自己部署一套微服务集群:
#mermaid-svg-SMadyRrVyEG0BgRQ{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-SMadyRrVyEG0BgRQ .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-SMadyRrVyEG0BgRQ .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-SMadyRrVyEG0BgRQ .error-icon{fill:#552222;}#mermaid-svg-SMadyRrVyEG0BgRQ .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-SMadyRrVyEG0BgRQ .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-SMadyRrVyEG0BgRQ .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-SMadyRrVyEG0BgRQ .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-SMadyRrVyEG0BgRQ .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-SMadyRrVyEG0BgRQ .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-SMadyRrVyEG0BgRQ .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-SMadyRrVyEG0BgRQ .marker{fill:#333333;stroke:#333333;}#mermaid-svg-SMadyRrVyEG0BgRQ .marker.cross{stroke:#333333;}#mermaid-svg-SMadyRrVyEG0BgRQ svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-SMadyRrVyEG0BgRQ p{margin:0;}#mermaid-svg-SMadyRrVyEG0BgRQ .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-SMadyRrVyEG0BgRQ .cluster-label text{fill:#333;}#mermaid-svg-SMadyRrVyEG0BgRQ .cluster-label span{color:#333;}#mermaid-svg-SMadyRrVyEG0BgRQ .cluster-label span p{background-color:transparent;}#mermaid-svg-SMadyRrVyEG0BgRQ .label text,#mermaid-svg-SMadyRrVyEG0BgRQ span{fill:#333;color:#333;}#mermaid-svg-SMadyRrVyEG0BgRQ .node rect,#mermaid-svg-SMadyRrVyEG0BgRQ .node circle,#mermaid-svg-SMadyRrVyEG0BgRQ .node ellipse,#mermaid-svg-SMadyRrVyEG0BgRQ .node polygon,#mermaid-svg-SMadyRrVyEG0BgRQ .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-SMadyRrVyEG0BgRQ .rough-node .label text,#mermaid-svg-SMadyRrVyEG0BgRQ .node .label text,#mermaid-svg-SMadyRrVyEG0BgRQ .image-shape .label,#mermaid-svg-SMadyRrVyEG0BgRQ .icon-shape .label{text-anchor:middle;}#mermaid-svg-SMadyRrVyEG0BgRQ .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-SMadyRrVyEG0BgRQ .rough-node .label,#mermaid-svg-SMadyRrVyEG0BgRQ .node .label,#mermaid-svg-SMadyRrVyEG0BgRQ .image-shape .label,#mermaid-svg-SMadyRrVyEG0BgRQ .icon-shape .label{text-align:center;}#mermaid-svg-SMadyRrVyEG0BgRQ .node.clickable{cursor:pointer;}#mermaid-svg-SMadyRrVyEG0BgRQ .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-SMadyRrVyEG0BgRQ .arrowheadPath{fill:#333333;}#mermaid-svg-SMadyRrVyEG0BgRQ .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-SMadyRrVyEG0BgRQ .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-SMadyRrVyEG0BgRQ .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-SMadyRrVyEG0BgRQ .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-SMadyRrVyEG0BgRQ .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-SMadyRrVyEG0BgRQ .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-SMadyRrVyEG0BgRQ .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-SMadyRrVyEG0BgRQ .cluster text{fill:#333;}#mermaid-svg-SMadyRrVyEG0BgRQ .cluster span{color:#333;}#mermaid-svg-SMadyRrVyEG0BgRQ div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-SMadyRrVyEG0BgRQ .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-SMadyRrVyEG0BgRQ rect.text{fill:none;stroke-width:0;}#mermaid-svg-SMadyRrVyEG0BgRQ .icon-shape,#mermaid-svg-SMadyRrVyEG0BgRQ .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-SMadyRrVyEG0BgRQ .icon-shape p,#mermaid-svg-SMadyRrVyEG0BgRQ .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-SMadyRrVyEG0BgRQ .icon-shape .label rect,#mermaid-svg-SMadyRrVyEG0BgRQ .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-SMadyRrVyEG0BgRQ .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-SMadyRrVyEG0BgRQ .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-SMadyRrVyEG0BgRQ :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} ① 初识 Docker

是什么 / 与虚拟机差别

架构 / 安装
② 基本操作

镜像命令 / 容器命令

数据卷
③ 自定义镜像

镜像结构 / Dockerfile
④ DockerCompose

一键部署多容器
⑤ 镜像仓库

私有仓库 / 推送拉取

阶段 解决什么问题 学完能做什么 代表命令
初识 Docker 搞清楚镜像、容器、仓库三者的关系,明白它和虚拟机不是一回事 在自己的机器或服务器上把 Docker 装起来并验证 docker -v、systemctl start docker
基本操作 会找镜像、会跑容器、会管理容器里的数据 用几条命令把 MySQL、Nginx 跑起来并改配置 docker pull、docker run、docker exec、docker volume
自定义镜像 把写好的 jar 变成可分发的镜像 手写 Dockerfile,把微服务打成镜像 docker build、FROM、COPY、ENTRYPOINT
DockerCompose 十几个容器一个个 run 太痛苦 写一个 docker-compose.yml,一条命令拉起整个集群 docker compose up -d
镜像仓库 镜像越来越多,需要统一存放和分发 搭私有仓库,团队内推送、拉取镜像 docker tag、docker push、docker pull

第一站:初识 Docker

要回答的问题只有三个------它是什么、它和虚拟机差在哪、它是怎么组织起来干活的。镜像 是只读的模板,容器 是镜像跑起来的实例,DockerHub 是公共的镜像仓库,这三者构成了 Docker 的骨架。另外要理解 Docker 采用 C/S 架构:客户端发指令,dockerd 守护进程负责干活。

和虚拟机的差别是面试高频点,也是理解性能的关键。虚拟机靠 Hypervisor 模拟出一套完整的硬件,每台虚机里跑一个完整的操作系统内核;容器只是宿主机上被 Namespace 隔离、Cgroups 限制的一组进程,共享宿主内核。所以容器启动是秒级甚至毫秒级,虚机是分钟级。

这一站的核心是先把环境装好。装不上的话后面全是空谈。

第二站:基本操作

三块内容,按依赖顺序学:

镜像命令 ------docker pull 拉取、docker images 查看、docker save/docker load 在离线环境里搬运、docker rmi 删除。镜像名的格式要记住:[repository]:[tag],不写 tag 默认是 latest。

容器命令 ------docker run 创建并启动、docker exec 进入容器改文件、docker ps 看运行状态、docker logs 排错、docker stop/start/rm 管理生命周期。容器有三个状态:运行、暂停(进程挂起但内存不释放)、停止(资源回收)。

数据卷 ------这是最容易踩坑的一站。容器删了,里面写的数据也就没了;而且配置文件每次都要 exec 进去手改,改完重启又还原。数据卷把宿主机的目录挂载到容器内路径,解决两件事:数据持久化和配置的灵活修改。

bash 复制代码
# 关键就是 -v 这一项,宿主机路径:容器内路径
docker run -d --name mysql -p 3306:3306 \
  -e MYSQL_ROOT_PASSWORD=123 \
  -v $PWD/mysql/conf:/etc/mysql/conf.d \
  -v $PWD/mysql/data:/var/lib/mysql \
  mysql:5.7.25

第三站:自定义镜像

官方镜像只能解决"跑现成的软件",我们自己的微服务 jar 得自己打包。这一站先讲镜像结构:镜像由一层层的 Layer 堆叠而成,BaseImage 在最底下,每次指令在上面加一层。理解了分层,才能理解为什么 Dockerfile 里命令的顺序会影响构建缓存。

然后学 Dockerfile 语法,把 jar 变成镜像其实只要三行:

dockerfile 复制代码
FROM java:8-alpine
COPY ./app.jar /tmp/app.jar
ENTRYPOINT java -jar /tmp/app.jar

docker build 一跑,镜像就有了。这一站是整章的转折点------从"用别人的东西"变成"造自己的东西"。

第四站:DockerCompose

有了镜像不代表部署轻松。网关、用户服务、订单服务、Nacos、MySQL 五个容器,每个都要写一长串 docker run 参数,端口、网络、卷挂载都不能错,还得按顺序启动。Compose 的做法是把这些参数写进一个 yml 文件,一条命令全部拉起:

yaml 复制代码
version: "3.2"

services:
  mysql:
    image: mysql:5.7.25
    environment:
      MYSQL_ROOT_PASSWORD: 123
    volumes:
      - "$PWD/mysql/data:/var/lib/mysql"
      - "$PWD/mysql/conf:/etc/mysql/conf.d/"
  userservice:
    build: ./user-service
  orderservice:
    build: ./order-service
  gateway:
    build: ./gateway
    ports:
      - "10010:10010"

build 表示现场用 Dockerfile 构建,image 表示直接用现成镜像。注意微服务连 MySQL、Nacos 时要把地址从 localhost 改成服务名(比如 mysql、nacos),因为 Compose 会创建一个自定义网络,容器之间用服务名互相解析------这一步十有八九会配错,报 UnknownHostException。

第五站:镜像仓库

最后一站是管理问题。服务镜像越攒越多,总不能每台服务器都 docker save 成 tar 包手动拷。镜像仓库的作用和 Maven 私服一样:统一存放、版本管理、按需拉取。企业里通常搭一个私有的 registry,推送拉取走 docker tag + docker push + docker pull 三步。

命令速查表

把本章涉及的命令按阶段列出来,后续各篇都从这里检索:

text 复制代码
① 初识 Docker
   docker -v                     查看版本,验证安装
   docker info                   查看 daemon 配置(镜像源、存储驱动)
   systemctl start/stop docker   启停守护进程

② 镜像操作
   docker pull [repository]:[tag]   拉取镜像
   docker images                    查看本地镜像
   docker save -o xx.tar 镜像名      导出为 tar
   docker load -i xx.tar            从 tar 导入
   docker rmi 镜像名                 删除镜像
   docker push                      推送(配合镜像仓库)

③ 容器操作
   docker run -d --name n -p 80:80 镜像   创建并运行
   docker ps / ps -a                        查看容器
   docker exec -it 容器名 bash              进入容器
   docker logs 容器名                       查看日志
   docker stop / start / restart 容器名     停止 / 启动 / 重启
   docker rm / rm -f 容器名                 删除(-f 强删)
   docker pause / unpause 容器名            暂停 / 恢复

④ 数据卷
   docker volume create / ls / inspect / rm / prune
   docker run -v 宿主机路径:容器路径 ...

⑤ 自定义镜像
   docker build -t 镜像名:tag .            构建镜像
   docker history 镜像名                    查看分层

⑥ DockerCompose
   docker compose up -d / down              启动 / 停止整个集群
   docker compose logs -f 服务名            跟踪日志

⑦ 镜像仓库
   docker tag 原镜像名 仓库地址/镜像名:tag
   docker login 仓库地址
   docker push / pull 仓库地址/镜像名:tag

学习建议

分成两批对待,效率差别很大。

必须先动手跑一遍的 :镜像命令和容器命令。这两块是肌肉记忆,光看讲义没有用。docker pull nginx、docker run 起来、docker exec -it 进去改个 index.html、docker ps 看状态、docker rm 删掉,这一套走完,后面所有内容都顺。数据卷也要动手,重点是亲手验证容器删了数据还在,否则挂载路径写错都发现不了。

可以先理解、用到再补的:DockerCompose 和镜像仓库。这两个是工程化能力,语法不难,难在真实项目里的网络和配置。先知道它们解决什么问题、yml 大概长什么样,等真正部署集群时再回来细看。

另外,Dockerfile 部分建议自己写一遍而不是复制。把 FROM、COPY、ENTRYPOINT 换成 ADD、CMD、RUN 分别试试,看构建结果和分层有什么变化,比读十遍文档管用。

官方文档

总结

  • 这一章解决的是微服务的部署难题,起因是拆得越细,环境差异和重复部署的成本越高。
  • 路径是五站:先认识(初识 Docker),再用起来(基本操作),然后造自己的东西(自定义镜像),接着批量部署(Compose),最后管起来(镜像仓库)。
  • 前两站必须动手,后两站可以先建立概念,真实项目里自然会补上。
  • 本文是整章导引,每个主题的具体命令、案例和坑都在后续各篇里展开。下一篇从最基础的问题开始:什么是 Docker,它到底比虚拟机强在哪。
相关推荐
程序猿阿森1 小时前
Warmup 学习率预热详解:为什么训练初期要“先热身再加速”?
深度学习·学习·语言模型
lisw051 小时前
人类认知和语言学习中的控制论!
人工智能·学习·数学建模
鱼很腾apoc1 小时前
【MySQL】 第1期 从核心概念到表约束全解析
linux·c语言·数据库·学习·mysql
Wang's Blog1 小时前
Java 项目部署之 Docker工具快速入门: Docker 镜像仓库
java·docker
企智汇-项目管理软件2 小时前
离散制造管理系统怎么选?一套系统管住从研发到交付的全周期
java·人工智能·制造·项目经理·项目管理软件·项目管理系统·项目管理软件工程
妖精的羽翼2 小时前
Web3D(Three.js)应用分级 + 学习路线规划(由浅入深,贴合接单 + 求职)
学习·three.js
JavaEdge.2 小时前
Docker Compose部署Dify
运维·docker·容器
IT研究室2 小时前
最新计算机毕业设计选题推荐-基于spring boot的幼儿园管理系统-网站-文档指导-Java-springboot
java·spring boot·课程设计
会编程的吕洞宾2 小时前
Spring Cloud Gateway限流实战 Redis令牌桶算法+熔断降级
java·后端·spring