十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Docker零基础入门:镜像、容器与安装实战指南

Docker零基础入门:镜像、容器与安装实战指南 刚接触 Docker 的时候我也被那一堆概念弄得晕头转向镜像、容器、仓库、Dockerfile、docker-compose……每个词都认识连起来不知道在说什么。尤其是别人跟我说Docker 就是一个集装箱的时候我内心是崩溃的——集装箱跟我部署项目有什么关系后来真正用起来才明白Docker 解决的是软件交付和运行环境里最让人头疼的问题环境不一致。这篇内容就是写给还没入门的你不讲虚的用最直白的话把 Docker 是什么、为什么现在大家都用它讲清楚然后带你把 Docker 装好、跑起第一个容器。文章尽量控制在一篇的篇幅内但该有的细节和坑一个都不会少。1. Docker 是什么不是虚拟机是标准集装箱思想1.1 最通俗的理解把应用连同环境一起装进盒子先忘掉所有技术名词想象一个场景你要把一个生鸡蛋安全地运到另一个城市。最笨的办法是拿着鸡蛋坐车但路上颠簸一下可能就碎了。聪明的办法是把鸡蛋放进泡沫盒里盒子里面还有缓冲垫外面贴上标签易碎、轻拿轻放。这就是集装箱的思路——把货物连同保护它的包装一起标准化。Docker 做的事情类似它把你的应用程序连同这个程序运行所需要的全部依赖代码、运行时环境、系统库、配置文件一起打包成一个标准化的盒子。这个盒子就叫镜像Image。盒子在 Docker 里跑起来之后就叫容器Container。为什么这个思路能解决问题因为传统部署模式下你的程序依赖的是某一台具体机器上的环境而机器和机器之间总有差异这台机器是 CentOS 7那台是 Ubuntu 20.04这台已经装了 Python 3.9那台还是 3.6。你的程序在这台机器上跑得好好的换一台机器就报错。Docker 把环境和应用一起打包那么不管底层是什么操作系统、什么硬件只要它能运行 Docker你的程序就能以完全相同的方式运行。这就是 Docker 最核心的价值一次构建到处运行。打个更接地气的比方以前你给别人分享一个 Python 项目要写一长串先安装 Python 3.9、再执行 pip install -r requirements.txt、还要改系统 PATH、可能还需要装 Redis、MySQL……——对方照着做十有八九还会踩坑。现在你只需要给他一个镜像他用 Docker 拉取后一行命令跑起来所有依赖都在盒子里环境一致性直接拉满。1.2 Docker 和虚拟机的本质区别不是开一个完整系统很多人第一次了解 Docker 时会问这不就是虚拟机吗确实两者目的相似但实现原理完全不同这是理解 Docker 的关键分水岭。虚拟机Virtual Machine的模型是虚拟化硬件。它通过 Hypervisor 在物理机上模拟出一台完整的计算机虚拟 CPU、虚拟内存、虚拟硬盘、虚拟网卡然后在这台虚拟机上安装一个完整的操作系统Guest OS。所以一台跑着 3 个虚拟机的物理机实际上要运行 4 套操作系统。这意味着磁盘占用大每个虚拟机都是几个 GB 起步启动速度慢要从 BIOS 自检开始启动整个操作系统资源损耗高每台虚拟机都要保留一部分 CPU、内存给自身的系统进程。Docker 的模型是共享内核。Docker 容器不是一个完整的操作系统它只是一个被隔离的进程集合。所有容器共用宿主机Host的操作系统内核只是通过 Linux 的 Namespace命名空间做资源隔离、通过 Cgroups控制组做资源限制。所以容器的本质是宿主机上的普通进程只不过这个进程被关在了一个独立的小房间里看不到房间外的其他进程和文件。我画一个简化对比表方便你记住对比项虚拟机Docker 容器是否包含完整 OS包含独立的 Guest OS不包含共享宿主机内核磁盘占用数 GB 起步甚至几十 GB通常几十 MB 到几百 MB启动时间分钟级秒级甚至毫秒级资源开销CPU、内存被系统本身吃掉很大一部分极低几乎等同于直接跑进程隔离级别硬件级隔离更强进程级隔离够用但弱于虚拟机适用场景需要强隔离、要跑整套系统微服务、应用打包、CI/CD这里要说一个很重要的常识Windows 上装 Docker Desktop它默认用的其实是 WSL2Windows Subsystem for Linux或者 Hyper-V 虚拟机来提供一个 Linux 内核。因为 Docker 容器本质依赖 Linux 内核特性在 Windows 上跑容器实际上是在 Windows 内置的轻量虚拟机里运行的。这一点新手不用深究但下载镜像、启动报错相关的很多问题都跟这个底层机制有关后面讲踩坑时会提到。1.3 三个核心概念先记住它们的关系Docker 体系里有三个基础概念几乎所有操作都围绕着它们展开。镜像Image可以理解为一个只读的模板一个装箱图。镜像里包含了应用代码、运行环境、配置等完整信息。镜像本身不会变。在 Docker Hub 这样的仓库里可以找到别人做好的现成镜像比如 MySQL、Redis、Nginx、Python、Ubuntu 等。容器Container镜像运行起来之后的实例是一个正在工作的盒子。同一个镜像可以创建出多个容器它们之间互不干扰。容器是可以写的你可以在容器里创建文件、安装软件但这些改动只存在于这一个容器中。仓库Repository/Registry存放大米的地方相当于 Git 与 GitHub 的关系。Docker Hub 是官方默认的公共仓库你可以从中拉取pull镜像也可以把自己做的镜像推送push上去。记住一条最简单的关系链仓库里拉镜像 → 镜像运行成容器 → 容器就是应用在跑。后面第 4 节实际操作时你就知道这条链怎么走通了。2. 为什么要用 Docker五个痛点每一个都真实扎心2.1 痛点一我这明明是好的怎么到你那就不行这是开发、测试、运维之间最常见的一句对话。原因各执一词开发用的 Windows测试用的 Mac服务器用的 CentOS三台机器的系统库版本、环境变量、默认 shell 都不一样。你的代码在本地依赖了一个系统库可项目文档里压根没写测试那边一跑就崩。Docker 的解法很彻底开发把应用连同环境一起打成镜像测试和运维拿到这个镜像直接运行效果完全一致。以后出了问题不用再排查环境差异——大家的生产环境就是那个容器的内部环境里外都同一套。我自己在团队里推广 Docker 后最明显的变化是跨环境的 bug 报告数量减少了一大半。2.2 痛点二一台服务器上装多个应用互相打架传统做法是在同一台服务器上直接部署多个应用这时你经常会遇到版本冲突应用 A 需要 Python 2应用 B 需要 Python 3应用 C 需要 OpenSSL 1.0应用 D 需要 1.1。升级一个可能要连带升级另一个系统的组件然后另一个应用就罢工了。Docker 的解法是隔离每个应用和它所依赖的库都在各自的容器里互不干扰。你可以让容器 A 用 Python 2容器 B 用 Python 3它们各自运行在自己的小世界里不冲突。这相当于给每个应用开了一间独立的小隔间而不是让所有应用挤在大通铺上。2.3 痛点三服务器配置和迁移流程又臭又长以前新入职一台服务器要经历装系统、配用户、装 JDK/Node/Python、装数据库、配置环境变量、部署应用、开放端口……这套流程手写文档的话动辄几十步漏一步就要折腾好几个小时。而且换一台新服务器还得从头再来一遍。Docker 把这个流程压缩成了几句话写好 Dockerfile或者直接用现成镜像执行 docker run 或者 docker compose up。新机器上只要装了 Docker一样的命令同样的环境就起来了。我现在迁移一个服务从一台服务器到另一台平均只需十几分钟其中大部分时间还花在等镜像下载上。2.4 痛点四资源利用率太低了服务器是有成本的。虚拟机方案虽然隔离性好但每台虚拟机都要带走几个 GB 磁盘、几百 MB 内存给系统自己用。一台 8GB 内存的服务器跑 3 个虚拟机可能就紧张了。但同样的机器跑容器因为容器共用宿主系统内核、几乎无额外开销跑几十个容器都不在话下。这是当下微服务架构这么流行的重要基础——否则你根本不敢把服务拆那么细一台机器拆不了几个就资源告急了。2.5 痛点五团队协作新成员上手太慢团队里来了新人以前要花半天到一天搭建开发环境装数据库、装消息队列、装缓存、初始化数据、配 IDE 连接……有 Docker 之后新人拉下一个 docker-compose.yml一条命令依赖环境就齐了。我在接手过的项目里最夸张的一次是一个包含 MySQL、Redis、RabbitMQ、Elasticsearch 的微服务项目以前搭建环境需要三小时用 Docker Compose 三分钟全部启动完成。所以 Docker 不是锦上添花的新技术它是实实在在解决软件工程中环境一致性和交付效率问题的基础工具。这也是为什么现在的招聘 JD 里Docker/Kubernetes 几乎成了后端工程师的标配要求。3. 装好 DockerWindows、macOS、Linux 的操作细节与常见安装报错3.1 Windows 安装Docker Desktop 与 WSL2 的前置条件Windows 上目前官方推荐的方案是安装 Docker Desktop。安装过程本身很简单下载安装包、一路 Next但新手遇到最多的问题其实出在安装之前的两项前置条件上。第一项是必须开启 Windows 虚拟化功能。因为 Docker Desktop 运行容器依赖 WSL2Linux 子系统或者 Hyper-V而这两者都需要 CPU 的虚拟化能力。开机时进入 BIOS/UEFI找到类似 Intel Virtualization Technology 或 SVM ModeAMD 平台的选项把它设为 Enabled。这一步不做装完 Docker Desktop 启动时会直接报错最常见的就是那句Docker Desktop failed to start because virtualisation support wasnt detected意思是检测不到虚拟化支持。很多新手一看到这个报错就以为是 Docker 坏了实际上十有八九是 BIOS 里的虚拟化开关没打开。你可以用命令行验证虚拟化是否已开启按 WinR输入systeminfo在输出里找Hyper-V 要求那一项如果四个条件都是是说明虚拟化可用。第二项是安装并启用 WSL2。现在 Docker Desktop 默认走 WSL2 后端所以你要先装好 WSL2 的 Linux 内核。用管理员身份打开 PowerShell执行wsl --install重启电脑然后设置 WSL 默认版本为 2wsl --set-default-version 2如果你提前安装了某个发行版比如 Ubuntu可以手动转换wsl --set-version Ubuntu-20.04 2。之后再去 Docker 官网下载安装 Docker Desktop for Windows双击安装包完成安装。安装完成后启动如果一切正常托盘区会有一个鲸鱼图标命令行里输入docker version能正常输出服务端和客户端版本。3.2 macOS / Linux 安装命令相对简单但注意架构差异macOS 用户同样是安装 Docker Desktop从官网下载 .dmg 安装包拖入 Applications 即可。唯一需要注意的是老款 Intel Mac 和新款 Apple SiliconM 系列芯片的安装包不同请在官网选择对应架构的版本。M 系列芯片的 Mac 建议开启 Docker Desktop 设置里的 Use Rosetta for x86/amd64 emulation 选项这样在跑一些还没有适配 arm64 的旧镜像时兼容性更好。Linux 安装就没有统一安装包了各发行版都有自己的包管理器。以 Ubuntu/Debian 为例最省事的方式是使用 Docker 官方提供的安装脚本需要 root 权限适用于快速体验curl -fsSL https://get.docker.com | sh这个脚本会自动配置官方 apt 源并安装 Docker Engine。安装完成后执行sudo systemctl start docker启动服务再用sudo systemctl enable docker设置开机自启。如果你不想每次敲 docker 命令都加 sudo把当前用户加入 docker 用户组sudo usermod -aG docker $USER注意这个命令执行后需要重新登录终端或者重启否则用户组不会生效。而且你要清楚加入 docker 用户组后这个用户相当于拥有了操作 Docker 的高权限等价于在宿主机上有了 root 权限所以在团队服务器上要不要给普通用户加这个组需要谨慎评估。3.3 安装完成后的验证与基本自检不管在哪个平台安装完成后都建议做一次完整的自检。打开终端执行三件事# 查看版本 docker version # 查看当前运行的容器 docker ps # 跑一个测试容器会从仓库拉取 hello-world 镜像 docker run hello-world第一条命令确认客户端和服务端版本号是否都正常显示。如果服务端失败多半是 Docker 服务没起来Windows 上重启 Docker DesktopLinux 上检查 systemd 服务。第二条命令确认权限没有问题如果报 Cannot connect to the Docker daemonLinux 下最可能是当前用户不在 docker 组里Windows 下最可能是 Docker Engine 还没就绪等几秒再试。第三条命令docker run hello-world是一个经典自检测试。如果终端里打印出一段 Hello from Docker! 的英文说明并显示 your installation appears to be working correctly恭喜你Docker 已经装好了。4. 跑起第一个真正的应用镜像、容器、命令一次搞通4.1 拉取镜像并启动容器以 Nginx 为例装好 Docker 之后最重要的不是背命令而是跑通一个真实项目。我建议第一次用 Nginx 练手因为 Nginx 镜像小、依赖少、启动快而且访问结果用浏览器就能直观看到。# 拉取 Nginx 最新镜像 docker pull nginx # 以后台模式运行一个名为 web1 的容器把宿主机 8080 端口映射到容器内的 80 端口 docker run -d --name web1 -p 8080:80 nginx执行完docker run之后打开浏览器访问http://localhost:8080如果你能看到 Nginx 的欢迎页面说明整个链路已经通了。这一步背后的逻辑值得理解一下Nginx 容器内部默认监听 80 端口但容器有自己独立的网络栈宿主机不能直接访问容器的 80 端口。-p 8080:80的含义叫做端口映射前面是你宿主机的端口后面是容器内部的端口它把宿主机 8080 端口的流量转交给容器内 80 端口的 Nginx 进程。访问localhost:8080就相当于访问了容器里的 Nginx。这种设计其实是刻意的隔离宿主机上可以同时跑多个 Nginx 容器只要端口映射到宿主机的不同端口即可容器之间永远不会因为端口冲突而互相影响。而且每个容器就是一台微型服务器可以独立启停、独立删除。4.2 最常用的几个 Docker 命令边查边记忆入门阶段不用背全所有命令但下面这几个几乎每天都在用建议熟记# 查看本地有哪些镜像 docker images # 查看正在运行的容器 docker ps # 查看所有容器含已停止的 docker ps -a # 进入容器的交互式 shell进入后可以查看容器内的文件和配置 docker exec -it web1 bash # 查看容器日志应用报错先看这里 docker logs web1 # 停止容器 docker stop web1 # 启动已停止的容器 docker start web1 # 删除容器必须先停止 docker rm web1 # 删除镜像 docker rmi nginx这些命令就像手机上的常用按钮熟练了就形成肌肉记忆了。新手最容易混淆的是docker exec和docker attach。这里我建议直接用docker exec -it 容器名 bash进入容器它是在容器里新开一个 shell 进程退出后不影响容器本身运行。docker attach则是直接连接到容器的主进程用 CtrlC 退出时可能会把容器也停掉新手不要轻易用。4.3 容器的数据保存问题为什么容器会被重置这是新手最容易踩的大坑。很多人在容器里安装软件、改配置一切正常可是docker stop再docker start之后发现改动全丢了或者删除重跑一个容器之前的数据完全消失了。原因在于容器的工作层是临时的。容器运行时的所有写操作都发生在一个可写层而这个可写层随着容器被删除而消失。即使容器只是停止再启动虽然可写层还在但一旦你执行docker rm把容器删了所有未持久化的数据就全部灭了。加之生产环境中最常见的场景是把容器当成了可以随时创建、销毁的员工而数据库这类需要持久化保存数据的内容也必须通过数据卷Volume挂载出来。# 创建带数据卷的 MySQL 容器把宿主机 /my-data 挂载到容器内 /var/lib/mysql docker run -d --name mysql-test -v /my-data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD123456 mysql:8.0-v /宿主机路径:/容器内路径的含义是把宿主机的/my-data目录和容器内的/var/lib/mysql目录相互共享。容器内通过这个目录写入的所有文件实际上都写到了宿主机上所以哪怕容器被删除数据依然保存在宿主机里。这就像你搬临时宿舍容器但贵重物品放进了银行保险柜数据卷宿舍拆了也不怕。上面创建的 MySQL 容器数据库文件就直接写到宿主机磁盘上容器删了重建一个数据照样在。注意挂载目录的路径必须写全。挂载之后宿主机目录里的文件会覆盖容器目录里的初始文件所以不要挂载一个空目录到应用的关键数据目录除非你本来就想要空数据初始化。5. 入门过程中至少会遇到一次的报错与解决方案5.1 镜像下载慢 / 超时配置镜像加速器从 Docker Hub 拉取大镜像比如 Python、Node、MySQL在国内网络环境下经常慢到怀疑人生docker pull卡在那里几分钟没动静最后直接报Get https://registry-1.docker.io/v2/: net/http: request canceled超时。这是新手问得最多的问题之一。解决思路很简单配置一个镜像加速器。Docker 支持在配置文件中设置 registry-mirrors。代码平台如果不是企业版一般都有自己的镜像源地址或可参考一些公共镜像站这里给你一个通用的配置流程。打开 Docker Desktop 设置找到 Docker Engine 标签在配置 JSON 中加入{ registry-mirrors: [ https://自己可用的镜像加速地址 ] }Linux 下则是修改/etc/docker/daemon.json没有这个文件就新建一个sudo mkdir -p /etc/docker sudo tee /etc/docker/daemon.json -EOF { registry-mirrors: [https://自己可用的镜像加速地址] } EOF sudo systemctl daemon-reload sudo systemctl restart docker注意公共镜像源的可用性可能会变化如果某个加速地址失效可以多换几个试试。配置完成并重启 Docker 后再用docker pull nginx测一下速度通常会快很多。5.2 Windows 下启动 Docker Desktop 直接失败先查三个地方如果你在 Windows 上遇到 Docker Desktop 启动后闪退或者一直停留在 Docker Engine starting 状态按顺序排查这三个地方第一确认虚拟化已经在 BIOS 中开启并用之前说过的systeminfo命令验证。第二确认 WSL2 的内核已安装。第三确认没有与 Hyper-V 冲突的老版本虚拟机软件比如虚拟机软件 VMware Workstation 和 Hyper-V 同时启用时有时候会打架导致 Docker 无法启动引擎。还有一个非常隐蔽的坑如果你公司的电脑受 IT 安全策略管控组策略里禁用了 Hyper-V 相关组件Docker Desktop 也会无法启动。这种环境下通常要用一种特殊方式安装 Docker Desktop——官网的 Windows 安装包一般是按 WSL2 或 Hyper-V 模式安装可能触发策略限制。你需要在命令行里手动执行安装程序并指定必需的特性例如Docker Desktop Installer.exe install --backendhyper-v。但具体参数和策略限制因企业而异务必先向 IT 确认虚拟化权限。5.3 Linux 下提示权限被拒docker 分组没生效Linux 安装 Docker 后直接执行docker ps报错Got permission denied while trying to connect to the Docker daemon socket原因几乎都是你的用户不在 docker 组里或者还在 docker 组里但未重新登录。解决方案# 添加当前用户到 docker 组 sudo usermod -aG docker $USER # 重启 docker 服务 sudo systemctl restart docker # 重新登录终端或者执行下面的命令使组立即生效 newgrp docker使组生效后docker ps应该就能正常使用了。如果你加入 docker 组之后还是提示权限被拒那就再重启一次终端或重启电脑。5.4 镜像存在却不能用架构不匹配有一类报错不常见但一遇到就会卡很久——启动镜像时直接报执行格式错误exec format error或者容器秒退。排查思路先看镜像平台架构docker images会列出每张镜像的架构docker info可以查看当前运行环境的架构。如果你在 x86_64 机器的 Docker 上 force 拉取了 arm64 的镜像比如某些在 ARM 设备上导出的镜像或者反过来在 Apple Silicon 上跑了纯 x86 的老镜像就可能出现这类错误。解决方式尽量选用官方镜像官方镜像会按平台自动选择正确版本手动指定平台docker run --platformlinux/amd64 ...确认你所用的 Linux 发行版架构与镜像一致。6. 入门之后下一步学什么跑通了容器、理解了镜像和仓库之后后面的学习路径就比较清晰了。第一步学Dockerfile。它是用文本文件定义如何构建一个镜像核心动作是FROM基于哪个基础镜像、COPY复制文件进镜像、RUN构建时执行命令、CMD容器启动时执行的命令。举个最简单例子把一个 Python 应用打成镜像# 基于官方 Python 3.11 镜像 FROM python:3.11-slim # 设置工作目录 WORKDIR /app # 复制依赖清单并安装 COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt # 复制应用代码 COPY . . # 容器启动时运行 app.py CMD [python, app.py]然后在同一目录执行docker build -t my-app .就会构建出一个名为 my-app 的镜像。这个能力是 Docker 从会用到会造的转折点。第二步学Docker Compose。当应用包含多个服务如后端 MySQL Redis Nginx时你不想一个个手动启动容器Compose 允许你用一个 YAML 文件定义全部服务然后一条命令docker compose up -d全部启动。这是开发环境里效率提升最明显的工具。第三步了解容器编排Kubernetes/K8s。当你的容器要跨越很多台服务器、要自动扩容、要处理服务发现和负载均衡的时候就需要 K8s。但 K8s 学习曲线陡峭建议等你把 Docker 本身用得足够熟练之后再开始。从 Docker 到 Kubernetes核心思路是相通的镜像带来的环境一致性、容器带来的资源隔离、声明式配置带来的可复现性所有这些底层理念都没有变。把 Docker 的基础概念和命令搞扎实后面学任何容器相关工具都会顺畅得多。我自己的体会是Docker 这个工具最妙的地方在于它的学习曲线前期很平缓——安装好、跑起来、看日志半天就能上手但它的知识深度又足够支撑你走很远——从 Dockerfile 优化到多阶段构建从 Compose 编排到 K8s 集群治理。入门阶段别追求一次吃透所有概念先亲手把容器跑起来让它成为你日常工作里的常规工具那些之前看不懂的概念很多都会在使用过程中自己变得清晰起来。
返回列表