Docker 介绍与入门
Docker 入门指南:安装、核心概念与常见容器操作。

Docker 是一个用于构建和运行容器的平台。它将源代码及其依赖打包到隔离环境中,让应用可以作为一个独立的软件单元运行。
容器通常是短暂的。容器停止后,其文件系统中的内容也会被处理掉;如果需要保留数据,可以使用卷将数据持久化。
只要环境中存在 OCI 容器运行时,同一个容器既可以运行在开发工作站上,也可以部署到由 Kubernetes 等编排工具管理的云环境中。这让开发环境与生产环境更容易保持一致。
本文将从安装 Docker 开始,介绍镜像与容器的基本概念,并通过示例演示常见的容器管理操作。
Docker 入门
Docker 主要提供 Docker Engine 和 Docker Desktop 两种使用方式。Docker Engine 包含运行在 Linux 上的守护进程和 CLI;Docker Desktop 则通过虚拟化技术,在 Windows、Mac 和 Linux 上提供一致的 Docker 环境。
Docker Desktop 除了包含 Engine 的 CLI,还提供了用于管理容器的图形界面。本文会使用传统的 CLI,但你也可以在 Docker Desktop 中完成相同的操作。
如果你使用 Windows 或 Mac,安装 Docker Desktop 是最简单的方式。前往官方文档的安装页面,下载对应系统的软件包并运行安装程序。
启动 Docker Desktop 后,你就可以在终端中执行 Docker 命令。
在 Linux 上,你可以下载预编译的静态二进制文件,也可以按照官方文档,通过发行版的软件包管理器安装 Docker Engine。
在 Ubuntu 上安装 Docker Engine
首次安装 Docker Engine 时,需要先配置 Docker 的软件仓库。完成配置后,你就可以通过该仓库安装和更新 Docker。
首先,设置 Docker 的 apt 仓库:
# Add Docker's official GPG key:sudo apt-get updatesudo apt-get install ca-certificates curlsudo install -m 0755 -d /etc/apt/keyringssudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.ascsudo chmod a+r /etc/apt/keyrings/docker.asc# Add the repository to Apt sources:echo \"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \$(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \sudo tee /etc/apt/sources.list.d/docker.list > /dev/nullsudo apt-get update
注意:如果你使用 Linux Mint 等 Ubuntu 衍生发行版,可能需要将 VERSION_CODENAME 替换为 UBUNTU_CODENAME。
接下来,安装 Docker 所需的软件包:
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
这些软件包分别负责不同的功能:
- docker-ce:用于管理容器的 Docker 守护进程。
- docker-ce-cli:与 Docker 守护进程交互的命令行工具。
- containerd.io:Containerd 容器运行时。它封装了 cgroups 等操作系统功能,并根据 Docker 守护进程的请求启动和运行容器。
- docker-buildx-plugin:使用 BuildKit 扩展镜像构建能力的 CLI 插件。
- docker-compose-plugin:用于定义和运行多容器应用的插件。
检查 Docker 是否正常工作
安装完成后,可以运行一个简单的容器来检查 Docker 是否正常工作。这里使用 Docker Hub 提供的 hello-world 镜像:
sudo docker run hello-world:latestUnable to find image 'hello-world:latest' locallylatest: Pulling from library/hello-world2db29710123e: Pull completeDigest: sha256:c77be1d3a47d0caf71a82dd893ee61ce01f32fc758031a6ec4cf1389248bb833Status: Downloaded newer image for hello-world:latestHello from Docker!This message shows that your installation appears to be working correctly.To generate this message, Docker took the following steps:1. The Docker client contacted the Docker daemon.2. The Docker daemon pulled the "hello-world" image from the Docker Hub.(amd64)3. The Docker daemon created a new container from that image which runs theexecutable that produces the output you are currently reading.4. The Docker daemon streamed that output to the Docker client, which sent itto your terminal.
Docker 会下载镜像、启动容器,并在终端中打印确认信息。随后,容器会自动退出。
看到上面的输出,说明 Docker Engine 已经可以正常运行。
Docker 基础知识
开始使用 Docker 之前,你需要先理解镜像和容器的区别:
- image(镜像):所有容器都从镜像启动。镜像定义了容器文件系统的初始状态,类似于传统虚拟机的安装介质。你可以从 Docker Hub 等公共仓库获取预构建镜像,其中包括常用的操作系统和应用程序。
- container(容器):容器是镜像的运行实例。它作为独立进程运行,与其他容器和主机上的现有进程隔离。你可以从同一个镜像启动多个容器,每个容器都会在镜像之上拥有一个可写的文件系统层。
简单来说,镜像是可以重复使用的模板,容器则是由这个模板启动的运行进程。
使用 Docker
将软件打包成容器,可以减少不同环境之间的差异。同一个容器既能运行在个人主机上,也能用于生产环境和 CI/CD 基础设施。
理解这些概念后,我们可以开始使用 Docker CLI 完成常见操作。
运行容器
docker run 命令用于从镜像启动容器。在检查 Docker 安装时,你已经运行过下面的命令:
docker run hello-world:latest
docker run 接收镜像名称作为参数。镜像名称中冒号后面的部分是标签,用于区分不同版本和变体。
latest 通常代表镜像的最新版本,但这不是强制标准,而且新版本可能带来破坏性更改。因此,最好使用 1.0.0 这类更精确的标签。
后台运行容器
hello-world 镜像只会运行一个进程,然后立即退出。实际应用中的容器通常会运行服务器等长期进程,直到容器被停止。
添加 -d 标志后,Docker CLI 会与容器分离,让进程在后台继续运行,并将终端控制权交还给你:
docker run -d nginx:latest
创建镜像
镜像通常通过 Dockerfile 创建。Dockerfile 是一个文本文件,其中包含组装镜像文件系统所需的指令。
新建一个目录,并将下面的内容保存到其中的 Dockerfile:
FROM node:latestCOPY app.js .ENTRYPOINT ["node"]CMD ["app.js"]
然后,在同一目录中创建 app.js:
console.log('It works!');
现在,运行下面的命令构建镜像:
docker build -t demo-image:latest ....Successfully built 80890ed154faSuccessfully tagged demo-image:latest
这条命令会使用当前工作目录中的 Dockerfile 构建镜像,并将结果标记为 demo-image:latest。构建过程包含以下步骤:
- 第一条语句指定以 node:latest 镜像作为新镜像的基础,后续指令会应用在它的文件系统之上。
- COPY 语句将应用源代码从工作目录复制到容器中。
- 镜像会在容器启动时运行 node,并将应用代码作为参数传入。
构建完成后,使用这个镜像启动一个容器:
docker run demo-image:latest
此时,代码会在容器化的 Node.js 环境中运行。
推送镜像到注册表
当前构建的镜像只存在于本地主机。将镜像推送到注册表后,团队成员和其他用户就可以获取并运行它。
Docker Hub 是最大的镜像注册中心,你可以免费注册。推送镜像之前,先运行 docker login,然后按照提示完成 Docker CLI 身份验证:
docker login
接下来,为镜像添加一个包含 Docker Hub 用户名的标签。将 <DOCKER_HUB_USERNAME> 替换为你的真实用户名:
docker tag demo-image:latest <DOCKER_HUB_USERNAME>/demo-image:latest
使用 docker push 上传镜像。Docker CLI 会根据镜像标签自动推导注册表 URL:
docker push <DOCKER_HUB_USERNAME>/demo-image:latest
镜像上传后,其他用户即使没有在本地主机上构建过它,也可以直接启动容器:
docker run <DOCKER_HUB_USERNAME>/demo-image:latest
查看主机上的容器
使用 docker ps 可以查看主机上的容器。默认情况下,它只显示正在运行的容器:
docker psCONTAINER ID IMAGE COMMAND CREATED STATUS0000ac4e7eba nginx:latest "/docker-entrypoint...." 3 seconds ago Up 1 minute
添加 -a 标志后,可以查看包括已停止和已退出容器在内的全部容器:
docker ps -aCONTAINER ID IMAGE COMMAND CREATED STATUS0000ac4e7eba nginx:latest "/docker-entrypoint...." 3 seconds ago Up 1 minute8cf6ed7f95fe hello-world:latest "/hello" 2 minutes ago Exited (0) 2 minutes agoa45b50521fc0 hello-world:latest "/hello" 2 minutes ago Exited (0) 2 minutes ago
输出中包含每个容器的 ID 和当前状态。如果需要查看某个容器的详细信息,可以将它的 ID 或名称传给 docker inspect:
docker inspect 8cf6ed7f95fe
该命令会输出一段 JSON,其中包含与这个容器相关的详细数据。
启动、停止和删除容器
对于运行长期进程的容器,可以将容器 ID 或名称传给 docker stop 来停止它:
docker run --name nginx -d nginx:latest87a116e59f1815fda7dd666f136e5f9f3d085bbd80889c0e0e5836e95e9511eddocker stop nginxnginx
使用 docker start 可以按照相同配置重新启动容器。需要注意,容器上一次运行时对文件系统所做的修改会丢失。
docker start nginx
如果不再需要某个容器,可以将它的 ID 或名称传给 docker rm:
docker rm nginx
正在运行的容器无法直接删除。此时需要添加 --force 标志,确认强制删除:
docker rm nginx --force
查看和删除镜像
使用 docker images 可以查看主机上的镜像,以及它们的创建时间和大小:
docker imagesREPOSITORY TAG IMAGE ID CREATED SIZEnginx latest 3964ce7b8458 6 days ago 142MBhello-world latest feb5d9fea6a5 15 months ago 13.3kB
要删除镜像,将它的 ID 或名称传给 docker rmi:
docker rmi hello-world:latest
如果某个容器正在使用该镜像,Docker 不会删除它。你需要先删除容器,再删除镜像。
高级主题
掌握基本操作后,可以继续了解端口映射、数据持久化、日志查看和容器内命令执行。
端口映射
端口映射让你可以通过主机的网络接口访问容器中的应用。前面的示例使用 nginx:latest 启动了一个 Nginx Web 服务器,但由于没有映射端口,你无法从 Docker 主机外部访问它。
启动容器时添加 -p 标志,即可建立端口映射:
docker run --name nginx -p 8800:80 -d nginx:latest
这个示例将主机的 8800 端口映射到容器内 Nginx 监听的 80 端口。
现在,向 localhost:8800 发送请求,就能获得容器中 Web 服务器的响应:
curl localhost:8800<!DOCTYPE html><html><head><title>Welcome to nginx!</title>...
使用卷来存储容器数据
容器是短暂的。虽然容器文件系统可以写入数据,但容器停止后,这些修改也会丢失。应用崩溃或主机重启都可能导致容器停止,因此不应该假设容器会一直运行。
卷用于持久化容器中的数据。它会作为存储单元挂载到容器文件系统中,而实际数据存储在容器之外。
因此,即使原容器已经停止,你仍然可以将同一个卷连接到替换容器。
使用 docker run 的 -v 标志可以挂载卷:
docker run -v my_volume:/container/mount/point my-image:latest
你也可以将主机文件系统中的目录直接绑定到容器中:
docker run -v $PWD:/container/mount/point my-image:latest
这种方式适合开发阶段。绑定源代码目录后,你对主机文件所做的修改会立即反映到容器中。
查看容器日志
Docker 会自动收集容器前台进程的标准输出和错误流。将容器 ID 或名称传给 docker logs,即可查看这些日志:
docker logs nginx172.17.0.1 - - [20/Dec/2022:21:01:52 +0000] "GET / HTTP/1.1" 200 615 "-" "curl/7.81.0" "-"172.17.0.1 - - [20/Dec/2022:21:10:02 +0000] "GET /about HTTP/1.1" 404 153 "-" "curl/7.81.0" "-"172.17.0.1 - - [20/Dec/2022:21:10:04 +0000] "GET /demo HTTP/1.1" 404 153 "-" "curl/7.81.0" "-"172.17.0.1 - - [20/Dec/2022:21:10:06 +0000] "GET / HTTP/1.1" 200 615 "-" "curl/7.81.0" "-"
通过这些日志,你可以了解应用的运行情况并定位错误。
如果需要持续接收新日志,可以添加 --follow 标志:
docker logs nginx --follow
按 Ctrl + C 即可停止跟踪日志。
容器内执行命令
调试问题或运行镜像中的管理工具时,你可能需要在容器内部执行命令。docker exec 可以在已经运行的容器中启动一个新进程:
docker exec <CONTAINER> <COMMAND>
将容器 ID 或名称填写到 <CONTAINER>,将要运行的命令及参数填写到 <COMMAND>。如果命令是一个 shell,就可以在容器内开启交互式终端会话。
此时还需要传入 -i 和 -t 标志,用于连接终端的标准输入流并设置 TTY:
docker exec -it nginx bashroot@58661670f1ad:/#
进入容器后,你就可以检查它的文件系统并执行所需命令。
要点
Docker 提供了一套完整的容器构建和运行工具。你可以使用 Docker CLI 运行容器、构建镜像并管理相关资源,也可以通过 Docker Desktop 的图形界面完成这些操作。
Docker 创建的镜像遵循 OCI 标准,因此也可以在 Podman 或 Kubernetes 等兼容 OCI 的容器环境中使用。