Ubuntu上安装Docker全指南:从基础概念到容器化实践
2026/9/18 8:53:27 网站建设 项目流程

1. 为什么选择在Ubuntu上学习Docker

1.1 Ubuntu与Docker的天然亲和力

我最早接触容器技术是在一个云服务器上,当时跑的是CentOS 7,折腾了整整一个下午才把Docker环境弄利索。后来换到Ubuntu之后发现,Docker官方对Ubuntu的支持几乎可以称得上是“亲儿子”级别,内核版本新、依赖库齐全、社区文档完备,遇到问题一搜基本都有答案。如果你正准备入门容器技术,我强烈建议直接从Ubuntu开始,不管是实体机、虚拟机还是云服务器,这套流程都通用。

选Ubuntu作为学习Docker的载体,背后有几个很实际的原因。首先是内核版本够新,Docker依赖的cgroup、namespaces等内核特性在Ubuntu 20.04以上的默认内核中都得到了很好的支持,不需要额外编译内核模块。其次是软件包管理体系成熟,apt源里的依赖处理非常干净,安装Docker时不会遇到那种“缺了libxxx又要手动编译”的尴尬局面。还有一个容易被忽略的点是,Ubuntu的用户基数大,你在学习过程中踩到的坑,大概率已经被别人踩过并且发到了Stack Overflow上。

我自己这几年的经验是,学习容器技术的过程中,环境安装环节往往是劝退新手的第一道坎。Windows上装Docker要处理Hyper-V或WSL2的兼容性问题,macOS上要面对Apple Silicon的架构适配问题,而Ubuntu上的安装路径相对平直很多。这也是为什么很多Docker官方教程和书籍都默认以Ubuntu作为演示环境的原因。

1.2 学习Docker之前需要理解的几个核心概念

在动手敲命令之前,我建议你先花半小时把几个核心概念弄明白。不是说你要背诵每个底层实现细节,而是至少搞清楚它们之间的关系,否则后面操作的时候会产生很多困惑。

Docker本质上是一个容器运行时管理工具,它利用Linux内核的namespace做资源隔离、用cgroup做资源限制,再通过联合文件系统(UnionFS)实现镜像的分层存储。这一整套机制使得容器看起来像一个轻量级的虚拟机,但相比虚拟机少了对硬件资源的模拟,所以启动速度可以达到毫秒级,单台机器上能跑几十上百个容器。

镜像(Image)和容器(Container)的关系,可以理解为“类”与“实例”的关系。镜像是只读的模板,里面包含了运行某个应用所需的一切内容:代码、运行时环境、系统库、配置等。当你用docker run命令运行一个镜像时,Docker会在镜像层之上添加一个可写层,这个运行中的实例就是容器。你对容器做的所有修改都只存在于这个可写层中,一旦容器被删除,这些修改也就随之消失。

数据卷(Volume)是容器持久化数据的方式。因为镜像层是只读的,容器删除后数据就会丢失,所以你需要把容器内的重要目录挂载到宿主机上。这个在后面实战部分我会详细演示。

网络方面,Docker默认提供bridge、host、none三种网络模式,默认的bridge模式会让容器通过一个虚拟网桥与宿主机通信,从外部访问容器内的服务则需要做端口映射。理解这些概念,你就能读懂绝大部分Docker命令的用途了。

2. Ubuntu上安装Docker的三种实战方式

2.1 方式一:使用官方APT仓库安装(推荐)

这是我最推荐的一种方式,也是生产环境中用得最多的安装方式。相比直接apt install docker.io,添加Docker官方APT源能够确保你安装的是最新稳定版,而且之后的升级也只需要apt upgrade就能搞定。

先说明一下,很多人会在教程里看到apt install docker.io这种写法,这是Ubuntu官方仓库内置的Docker版本。问题在于这个版本的更新往往滞后,可能落后官方好几个大版本。在学习和使用过程中,你可能会遇到一些新特性不生效的情况,所以还是建议走官方源。

安装前先更新一下软件包索引,然后安装一些必要的依赖:

sudo apt update sudo apt install -y apt-transport-https ca-certificates curl gnupg lsb-release

接下来添加Docker官方的GPG密钥和APT仓库:

curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

注意,上面命令中的$(lsb_release -cs)会自动获取你当前Ubuntu的版本代号(比如focal、jammy、noble)。如果你在较老的Ubuntu版本上执行,可能会提示lsb_release命令不存在,那就先执行sudo apt install lsb-release装一下。

最后执行安装:

sudo apt update sudo apt install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin

这里我额外安装了docker-compose-plugin,它提供了docker compose子命令(注意是带空格的子命令,跟独立的docker-compose可执行文件不同)。后面编排多容器应用时会用到,建议一起装好。

安装完成后启动Docker服务并设置开机自启:

sudo systemctl enable docker --now

sudo systemctl status docker或者sudo docker version验证一下安装结果。看到Client和Server两段版本信息都正常输出,就说明Docker已经跑起来了。

2.2 方式二:使用官方脚本快速安装

如果你只是想快速搭个环境做实验,不太在意版本管理的精细度,可以使用Docker官方提供的自动化安装脚本:

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

这个脚本会检测你的操作系统版本,自动配置好APT源并安装所有依赖。整个过程基本不需要人工干预,几分钟就能装完。脚本执行结束后,同样用sudo systemctl enable docker --now启动服务。

不过坦白讲,我不太推荐在生产环境或正式服务器上直接用脚本安装,因为你不知道脚本具体做了什么操作、改写了哪些配置文件。在虚拟机或者自己折腾的测试机上用脚本无所谓,出了问题重装系统就行。生产环境还是老老实实按方式一来,每一步都在自己掌控中。

2.3 方式三:离线环境下的二进制安装

有些时候你的Ubuntu机器处于内网环境,无法访问外网下载软件包。这种场景在政企项目里很常见。这时候可以在一台能联网的机器上下载Docker的静态二进制包,然后拷贝到内网机器上解压使用。

Docker官方提供了静态二进制包,下载地址是:

https://download.docker.com/linux/static/stable/x86_64/

选择合适版本,比如docker-24.0.7.tgz,下载后解压:

tar xzvf docker-24.0.7.tgz sudo cp docker/* /usr/bin/

然后编写一个简单的systemd服务文件/etc/systemd/system/docker.service,内容大致是:

[Unit] Description=Docker Daemon After=network-online.target [Service] Type=notify ExecStart=/usr/bin/dockerd ExecReload=/bin/kill -s HUP $MAINPID LimitNOFILE=1048576 LimitNPROC=infinity LimitCORE=infinity [Install] WantedBy=multi-user.target

保存后执行:

sudo systemctl daemon-reload sudo systemctl enable docker --now

这种方式适合特殊场景,对新手来说了解即可,大部分情况下用前两种方式就够了。

2.4 安装后的环境检查与用户权限配置

安装完成不等于万事大吉,我习惯性会做两个额外操作。第一个是验证Docker能否正常运行一个测试容器:

sudo docker run hello-world

如果看到Hello from Docker!的输出,说明整个链路是通的。这个命令会从Docker Hub拉取一个极小的测试镜像并在容器中运行,是验证安装是否成功最直接的方式。

第二个操作是配置用户权限。Docker守护进程默认绑定在/var/run/docker.sock这个Unix套接字上,只有root用户和docker组的成员才能访问。每次敲命令都带sudo很烦,把自己加入docker组可以免去这一步:

sudo usermod -aG docker $USER newgrp docker

退出重新登录后,你就可以直接执行docker ps而不需要加sudo了。

注意:把用户加入docker组实际上等同于授予该用户root权限,因为可以通过挂载宿主机的/var/run/docker.sock来操控宿主机。个人开发机这么做没问题,但团队共享的服务器上要慎重。

3. Docker核心操作:构建、运行与排错

3.1 镜像管理:拉取、查看、删除与导出

镜像在Docker中的地位就像虚拟机中的模板文件。Docker Hub是官方的镜像仓库,里面存放着海量的公共镜像,比如Ubuntu、Nginx、MySQL、Redis等。

拉取一个镜像的命令是:

docker pull ubuntu:22.04

这里ubuntu是镜像名,22.04是标签(Tag),用来区分不同版本。如果不写标签,默认拉取latest标签的镜像。

查看本地已有的镜像列表:

docker images

这个命令会显示镜像的仓库名、标签、镜像ID、创建时间、大小。镜像ID是一个64位的十六进制字符串,通常我们在命令中可以只用前几位来指代。

删除镜像的命令是:

docker rmi ubuntu:22.04

需要注意的是,如果某个镜像还有正在运行或已退出但未删除的容器引用,删除会失败。这时候要么先删除对应容器,要么用docker rmi -f强制删除(不建议,容易留下悬空镜像)。

镜像导出和导入也是经常用到的操作,尤其是离线环境下传输镜像时:

docker save -o ubuntu.tar ubuntu:22.04 docker load -i ubuntu.tar

saveload是用来打包镜像的,而exportimport则是针对容器的,两者不要搞混。

还有一个小命令docker search,可以用来在命令行搜索Docker Hub上的镜像。实际使用中我倒是很少用,因为直接在网页端搜索看排名和描述更直观,还能看到官方认证和star数量。

3.2 容器生命周期管理

容器管理是日常操作最频繁的部分。首先是运行一个容器:

docker run -it --name my_ubuntu ubuntu:22.04 /bin/bash

这个命令拆开来看:-it是以交互模式并分配一个伪终端,--name给容器起名字,ubuntu:22.04指定镜像,/bin/bash是容器启动后要执行的命令。执行后你会直接进入容器的shell,可以像操作一台新装的Ubuntu系统一样敲命令。

退出容器时,如果直接输入exit,容器会停止运行,因为它的主进程是bash,bash退出后容器也就没有存在的意义了。如果只想退出终端但让容器继续在后台运行,可以按Ctrl+P再按Ctrl+Q

对于已经存在的容器,有几个常用操作:

docker ps # 查看正在运行的容器 docker ps -a # 查看所有容器,包括已停止的 docker start my_ubuntu # 启动已停止的容器 docker stop my_ubuntu # 停止运行的容器 docker restart my_ubuntu # 重启容器 docker rm my_ubuntu # 删除已停止的容器

如果你希望容器在后台保持运行,又不直接进入交互终端:

docker run -d --name nginx_demo -p 8080:80 nginx

-d参数表示daemon模式,容器在后台运行,命令执行完只会返回一个容器ID。-p 8080:80的意思是把宿主机的8080端口映射到容器内的80端口。这样你在浏览器访问http://宿主机IP:8080就能看到Nginx的欢迎页面了。

查看容器日志是排查问题最常用的手段:

docker logs -f nginx_demo

-f参数表示实时跟随日志输出,类似tail -f。加--tail 200能只看最近200行,日志量大时有用的。

3.3 数据持久化:数据卷与绑定挂载

前面提到过,容器删除后数据就没了。在真实场景中,数据库的数据文件、应用生成的日志都不应该存在容器可写层里,必须做持久化。

Docker提供了三种挂载方式,但日常用到的其实就两种:数据卷(Volume)和绑定挂载(Bind Mount)。

数据卷是Docker自己管理的一块存储区域,使用方式:

docker volume create mydata docker run -d --name mysql_demo -v mydata:/var/lib/mysql mysql:8.0

这里-v mydata:/var/lib/mysql的意思是把名为mydata的卷挂载到容器内的/var/lib/mysql目录。删除容器时卷不会自动删除,下次再创建一个容器挂载同一个卷,数据还在。

绑定挂载则是直接把宿主机的某个目录映射到容器里:

docker run -d --name nginx_demo -p 8080:80 -v /home/user/html:/usr/share/nginx/html nginx

这样你直接在宿主机上修改/home/user/html里的文件,容器内的Nginx就会立刻响应新的内容,非常适合开发调试场景。

注意:绑定挂载时,如果宿主机目录不存在,Docker会自动创建,但目录的所有者可能是root。如果你遇到“Permission denied”之类的权限问题,多半就是目录所有者不对,用sudo chown -R 用户:组 目录调整一下即可。

3.4 网络模式与端口映射

Docker的网络模型对新手来说有一点门槛,但理解之后排查问题会顺畅很多。

默认的bridge模式下,Docker会在宿主机上创建一个名为docker0的虚拟网桥,并为每个容器分配一个内网IP(通常是172.17.0.x段)。容器与容器之间可以通过这个内网IP互相通信,但容器无法被宿主机外部直接访问,必须通过端口映射。

端口映射的格式是宿主机IP:宿主机端口:容器端口,通常写宿主机端口:容器端口就行,宿主机IP默认绑定0.0.0.0即所有网卡:

docker run -d --name web -p 8080:80 nginx

这个命令将容器的80端口映射到宿主机的8080端口。外部用户访问http://宿主机IP:8080,请求会被Docker的iptables规则转发到容器的80端口。

host网络模式下,容器不会做网络隔离,直接使用宿主机的网络栈。这种模式性能损耗最低,但容器内端口会直接占用宿主机端口,且不支持端口映射。

还有一个在开发中很有用的自定义网络:

docker network create mynet docker run -d --name db --network mynet mysql:8.0 docker run -d --name app --network mynet myapp

同一个自定义网络里的容器可以通过容器名直接互相访问。比如在app容器里连接数据库,完全不用关心数据库容器的IP是多少,直接用db:3306就能连上。这个特性在多容器编排时特别实用。

4. 常用Docker实践:从单容器到多容器

4.1 实战:在Docker中运行MySQL

光说理论记不住,还是得动手跑几个服务。我拿MySQL举例,因为这是大家最熟悉的数据库,而且踩坑点比较有代表性。

运行一个MySQL 8.0容器的命令:

docker run -d \ --name mysql8 \ -p 3306:3306 \ -e MYSQL_ROOT_PASSWORD=123456 \ -e MYSQL_DATABASE=testdb \ -v mysql_data:/var/lib/mysql \ mysql:8.0

-e参数是传递环境变量,MySQL镜像会根据这些变量来初始化root密码和创建的默认数据库。-v mysql_data:/var/lib/mysql挂载数据卷,保证容器删除重建后数据不丢。

等待几秒让MySQL完成初始化,然后查看日志确认启动成功:

docker logs mysql8

看到ready for connections就说明已经起来了。用容器内的MySQL客户端连上去测一下:

docker exec -it mysql8 mysql -uroot -p

这里docker exec是在运行中的容器内执行命令。输完密码进入MySQL交互界面后,show databases;如果能看到testdb,说明一切正常。

有两个坑我想提醒一下。第一个是MySQL 8.0的默认认证插件是caching_sha2_password,老客户端(比如Python的mysqlclient库、旧版Navicat)会连不上,报Authentication plugin 'caching_sha2_password' cannot be loaded。解决办法是在运行容器时加一个参数:

docker run -d --name mysql8 -p 3306:3306 \ -e MYSQL_ROOT_PASSWORD=123456 \ -v mysql_data:/var/lib/mysql \ mysql:8.0 --default-authentication-plugin=mysql_native_password

第二个坑是容器内的MySQL默认只监听3306端口,并且root用户只允许localhost登录。如果你用宿主机或者外部工具连不上,先检查docker ps确认端口映射生效没,再进容器里看看MySQL用户配置:

SELECT user, host FROM mysql.user;

如果发现root的host不是%,需要手动创建远程用户或者改host。

4.2 实战:构建自己的第一个镜像

拉别人的镜像只是入门,学会构建自己的镜像才是真正的转折点。Dockerfile是描述镜像构建步骤的文本文件,在里面写好一系列指令,Docker会按顺序执行并生成一个镜像。

看一个最简单的Python Web服务Dockerfile:

FROM python:3.11-slim WORKDIR /app COPY requirements.txt . RUN pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple COPY . . EXPOSE 8000 CMD ["python", "app.py"]

逐行解释一下:

  • FROM指定基础镜像,这里用的是Python 3.11的slim版本(精简版,体积更小)。
  • WORKDIR设置工作目录,后续的COPY、RUN、CMD都会在这个目录下执行。
  • COPY把宿主机上的文件复制到镜像里。要注意的是,COPY的源路径是相对于构建上下文的,所以一会儿构建时指定的目录很关键。
  • RUN在镜像构建过程中执行的命令,通常用来安装依赖。
  • EXPOSE声明容器运行时监听的端口,这只是文档性质的声明,并不代表真的会映射端口。
  • CMD指定容器启动时执行的命令。一个Dockerfile只能有一个有效的CMD指令,如果有多个,只有最后一个生效。

写好后,在Dockerfile所在目录执行构建:

docker build -t my-python-app:v1 .

注意命令最后有一个点,这个点代表构建上下文是当前目录。构建上下文里的文件都会被发送到Docker守护进程,所以尽量避免把不需要的大文件放在构建目录里,否则构建会变慢。我见过有人把整个node_modules目录放在项目根目录然后直接docker build .,构建过程卡到怀疑人生。正确做法是用.dockerignore文件排除掉这些目录,写法类似.gitignore

构建完成后用docker run my-python-app:v1启动,访问一下就能看到你的服务跑在容器里了。这里有个技巧,本地调试时可以不用-d直接前台运行,方便看日志输出。

4.3 使用Docker Compose编排多容器应用

当应用开始依赖多个服务时,比如一个Web项目同时用到Nginx、后端应用和数据库,逐个docker run就变得很不现实。这时候就用到了Docker Compose。

Docker Compose的核心是一个docker-compose.yml文件,用YAML格式描述整个应用包含哪些服务、每个服务用什么镜像、端口如何映射、环境变量如何配置、依赖关系如何定义。

我举个例子,一个简单的Web应用需要MySQL和Redis:

version: '3.8' services: db: image: mysql:8.0 environment: MYSQL_ROOT_PASSWORD: 123456 MYSQL_DATABASE: appdb volumes: - db_data:/var/lib/mysql ports: - "3306:3306" redis: image: redis:7-alpine app: build: . depends_on: - db - redis environment: DB_HOST: db REDIS_HOST: redis ports: - "8000:8000"

写了这个文件之后,在同一个目录下执行:

docker compose up -d

Docker就会按照配置把三个服务都拉起来。-d后台运行,--build参数表示启动前先构建镜像。查看所有服务状态用docker compose ps,查看某个服务日志用docker compose logs app,停止并删除所有资源用docker compose down

注意,depends_on只控制启动顺序,不保证依赖服务已经就绪。比如app依赖db,但db可能还要十几秒才能初始化完成。如果你在app里一启动就要连数据库,可能会连接失败。解决办法是应用层面做重试,或者使用healthcheck机制让Compose等数据库健康后再启动app。这个属于中高级玩法,新手先了解有这回事就行。

Compose还有一个我觉得特别实用的功能是docker compose exec,它让你在运行中的服务容器里执行命令,比如:

docker compose exec app python manage.py migrate

不用记容器ID,直接用服务名就可以了。

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

5.1 权限问题排查

Docker相关的权限问题,我遇到最多的就是permission denied while trying to connect to the Docker daemon socket。这个报错的字面意思是“尝试连接Docker守护进程套接字时权限被拒绝”。

遇到这个报错,先做两件事。第一,确认当前用户是不是在docker组里,groups命令能查看;第二,确认docker.sock的文件权限,ls -l /var/run/docker.sock看属主和属组。

解决办法就是把用户加入docker组,然后重新登录。有些教程会让你执行sudo chmod 666 /var/run/docker.sock来开放权限,这个做法千万别学,等于把Docker的完全控制权开放给所有用户,安全风险非常大。

5.2 容器网络不通

容器启动后宿主机访问不了服务,这是新手最容易卡住的点之一。排查思路按照从外到内的顺序来:

先看端口映射是否生效:

docker ps

看PORTS那一列,如果是0.0.0.0:8080->80/tcp说明映射成功了。如果只有80/tcp说明没有映射端口,需要删掉重建容器或者在启动时加上-p参数。

再看容器内部的服务是否正常:

docker exec -it 容器名 /bin/bash curl localhost:80

容器内能通但外部不能通,问题出在防火墙。检查一下系统防火墙是否拦截了对应端口。Ubuntu默认防火墙是ufw,可能没有开放端口:

sudo ufw status sudo ufw allow 8080/tcp

如果这些都没问题,最后检查一下监听的IP地址。有些服务默认只监听127.0.0.1,比如Redis默认配置。在容器内再怎么配,外部都访问不了,必须在启动命令或配置文件里改成0.0.0.0。

5.3 磁盘空间被镜像占满

Docker用久了会发现磁盘空间越来越小,这是镜像、容器、数据卷和构建缓存共同膨胀的结果。几个常用命令帮你清理:

docker system df

这条命令会列出镜像、容器、卷和构建缓存分别占用了多少磁盘。接下来针对性清理:

docker system prune

这个命令会删除所有已停止的容器、所有未被使用的网络、所有悬空镜像(没有标签且没有被容器引用的镜像)和构建缓存。加-a参数会更激进,所有未被容器使用的镜像都会被删除,包括那些你想保留下来的。我的习惯是先不带-a跑一次,过一段时间看情况再彻底清理。

如果只是清理构建过程中的临时缓存,用:

docker builder prune

这个指令删除的是BuildKit构建缓存,有些镜像构建过程会产生非常多的中间层缓存,占几个GB都有可能。

5.4 与Ubuntu版本相关的坑

Ubuntu版本不同,踩的坑确实有差异。有一个经典的坑:Ubuntu 22.04的iptables默认是nftables架构,Docker在设置端口转发时偶尔会报类似iptables: No chain/target/match by that name的错误。

解决办法是切换成传统的iptables:

sudo update-alternatives --set iptables /usr/sbin/iptables-legacy sudo update-alternatives --set ip6tables /usr/sbin/ip6tables-legacy sudo systemctl restart docker

还有一个坑是在旧版Ubuntu(18.04及以下)上安装新版Docker时,可能会遇到libcgroup或者overlayfs相关的依赖问题。旧系统的内核可能不支持Docker新版要求的overlay2存储驱动,这时候要么升级系统,要么在/etc/docker/daemon.json里显式指定存储驱动为vfs(不推荐,性能差很多)。

6. 个人学习建议与后续进阶方向

6.1 我的学习路径建议

学Docker这件事,我觉得最忌讳的就是只看教程不实操。很多概念光看文字觉得理解了,一上手操作就原形毕露。我建议你拿到这篇文章后,照着从安装到运行的流程完整走一遍,别跳步。等基础命令都熟悉了,可以尝试自己搭建一个简单的个人博客或者API服务,用Docker跑起来,这个过程中你自然就会遇到数据持久化、环境变量配置这些真实问题。

一个比较靠谱的学习路径是:先把docker run、docker ps、docker exec、docker logs这几个命令用到熟练,然后学习Dockerfile的编写,再去了解数据卷和网络,最后上Compose编排。不要一上来就去研究Kubernetes、Service Mesh这些,万丈高楼从地起,容器基础没有打牢就去追热点,很容易学得一头雾水。

另外我强烈建议在本地装一个Ubuntu虚拟机来练习,特别是只用Windows的同学。WSL2其实也可以跑Docker,但它在systemd支持和网络处理上跟原生Linux有些细微差别。如果你遇到“怎么跟教程里不太一样”的情况,检查一下是不是运行环境的差异导致的。

6.2 几个值得深入的方向

如果基础操作已经熟练了,接下来可以往这几个方向深入:

第一个是Dockerfile优化。比如使用多阶段构建来减小最终镜像体积,理解层缓存机制来加速构建,合理使用COPYRUN顺序来充分利用缓存。一个几百MB的镜像优化到几十MB是常态,这对部署速度和存储成本的影响是非常明显的。

第二个是容器的资源限制。用--memory--cpus参数限制容器可以使用的内存和CPU,避免某一个容器把整台机器吃垮。在docker-compose.yml里也有对应的配置项deploy.resources.limits

第三个是容器化应用的日志管理。默认情况下容器日志会输出到宿主机的/var/lib/docker/containers/<容器ID>/目录下。可以配置json-file日志驱动的轮转策略,或者把日志收集到集中式日志平台。

第四个是Docker与CI/CD的结合。现在主流的GitLab CI、GitHub Actions都提供了Docker相关的Runner和Action,学会用Docker镜像来封装构建环境,能让持续集成的流水线更干净、更可复现。

最后再分享一个小技巧:写Dockerfile的时候,记得把COPY的文件尽可能缩小到最小范围,然后利用好层缓存。我见过很多人在改了源码之后重新build,因为Dockerfile里写的是COPY . .,导致每次都把整个上下文重新打进镜像。正确的做法是把依赖文件和源码分开拷贝,这样改源码的时候不会把已经装好的依赖层全部推翻重来。这个小习惯能帮你省下大量的构建时间和网络流量。

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

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

立即咨询