Docker 入门指南:核心概念与基础使用
欢迎来到容器化世界!如果你是一名开发者、运维人员或者只是对新技术充满好奇的IT爱好者,那么你很可能已经听说过 Docker。Docker 已经彻底改变了应用程序的开发、交付和运行方式。本指南将带你深入了解 Docker 的核心概念,并指导你进行最基础的实践操作,助你轻松迈出 Docker 的第一步。
目录
- 引言:Docker 是什么?为什么需要 Docker?
- 核心概念:理解 Docker 的基石
- 容器 (Container)
- 镜像 (Image)
- Dockerfile
- 仓库 (Registry)
- 卷 (Volume)
- 网络 (Network)
- 安装 Docker (简要介绍)
- Docker 基础使用:常用命令详解
- 拉取镜像 (
docker pull
) - 运行容器 (
docker run
) - 查看容器 (
docker ps
) - 停止、启动、重启容器 (
docker stop
,docker start
,docker restart
) - 移除容器 (
docker rm
) - 查看容器日志 (
docker logs
) - 进入容器 (
docker exec
) - 查看镜像 (
docker images
) - 移除镜像 (
docker rmi
)
- 拉取镜像 (
- 构建自己的镜像:Dockerfile 初体验
- Dockerfile 指令介绍 (FROM, RUN, COPY, CMD/ENTRYPOINT, EXPOSE, WORKDIR)
- 构建镜像 (
docker build
)
- 一个小实践:运行一个 Web 服务器容器
- 进阶之路 (简要提及)
- 总结
1. 引言:Docker 是什么?为什么需要 Docker?
在传统的软件开发和部署模式中,我们经常遇到这样的问题:
* “在我的机器上可以运行!”:代码在开发者的环境中运行正常,但在测试、预生产或生产环境中却出现了各种问题,通常是由于操作系统、库版本、依赖项等环境差异造成的。
* 环境配置复杂:搭建一个应用程序运行所需的环境(安装操作系统、配置运行时、安装各种依赖库、设置环境变量等)既耗时又容易出错。
* 资源隔离不足:在同一台服务器上运行多个应用程序时,它们可能会相互影响,比如端口冲突、资源抢占等。
* 部署和扩展困难:将应用程序部署到新的服务器或根据流量增加进行扩展,需要重复繁琐的环境配置过程。
Docker 应运而生!
Docker 是一个开源的应用容器引擎。 它允许开发者将应用程序及其依赖项打包到一个可移植的容器中。这个容器几乎可以在任何 Linux、Windows 或 macOS 机器上运行,而无需担心环境差异。
你可以将 Docker 想象成一个标准化的集装箱运输系统。
* 传统的部署方式就像是将货物(应用程序)散装运输,每次运输到不同港口(服务器)都需要不同的装卸和打包方式,效率低下且容易损坏。
* Docker 就像是引入了标准化的集装箱(容器)。无论货物是什么,无论运往哪个港口,都将其放入标准的集装箱中。集装箱有统一的尺寸和接口,码头(Docker 环境)知道如何处理这些集装箱。这样一来,货物的打包、运输和部署变得极为高效和可靠。
为什么需要 Docker?
- 环境一致性:容器包含了应用程序运行所需的所有东西(代码、运行时、系统工具、系统库等)。无论在何处运行容器,环境都是完全一致的,解决了“works on my machine”的问题。
- 快速部署与扩展:打包好的容器可以快速在任何支持 Docker 的机器上启动,极大地简化了部署过程。当需要扩展时,只需启动更多的容器实例即可。
- 资源隔离:Docker 利用 Linux 内核的技术(如 Namespace 和 Cgroup)实现进程隔离、网络隔离、文件系统隔离等,使得容器之间互不影响,提高了安全性。
- 更高效的资源利用:与虚拟机相比,容器不需要独立的操作系统内核,多个容器共享宿主机的内核,因此启动速度更快,占用的资源更少。
- 简化 CI/CD 流程:Docker 容器是理想的构建和部署单元,可以无缝集成到持续集成/持续部署(CI/CD)流程中。
- 轻量级与可移植性:容器相比虚拟机更轻量,打包后易于传输和分享。
总之,Docker 通过提供一种标准化的方式来构建、打包和运行应用程序,极大地提高了开发效率、简化了部署流程、增强了环境一致性和资源利用率。
2. 核心概念:理解 Docker 的基石
要掌握 Docker,必须先理解其几个核心概念:
2.1 容器 (Container)
- 定义:容器是镜像的运行实例。它是 Docker 运行应用程序的独立环境。
-
特性:
- 隔离:每个容器都有自己的文件系统、网络接口、进程空间,彼此之间相互隔离。
- 轻量:与虚拟机不同,容器共享宿主机的操作系统内核,因此启动速度快,占用的系统资源少。
- 可移植:容器包含了应用运行所需的全部环境,可以在任何支持 Docker 的平台上运行。
- 短暂性 (默认):容器运行时产生的数据(非卷数据)通常不会持久化,容器销毁后这些数据也会丢失。
-
类比:如果说镜像是一个蓝图或模板,那么容器就是根据这个蓝图建造出来的活生生的房子。你可以启动、停止、重启、删除这个房子。
2.2 镜像 (Image)
- 定义:镜像是一个只读模板,用于创建容器。它包含了运行应用程序所需的所有文件、代码、运行时、库、环境变量和配置文件。
- 特性:
- 分层存储 (Layered Storage):镜像是通过一系列的只读层构建起来的。每层都代表了对上一层的修改(比如添加文件、运行命令)。这种分层机制使得镜像的构建、共享和更新非常高效。例如,多个镜像可以共享同一个基础层。
- 不可变 (Immutable):镜像一旦构建完成,就不能被修改。当你运行一个镜像时,会在顶部添加一个可写层,所有的修改都发生在这个可写层上。
- 类比:镜像就像是建造房子的蓝图或者模板。它描述了房子应该是什么样子,包含了所有的设计细节和所需的材料列表(虽然材料本身不包含在蓝图中)。
2.3 Dockerfile
- 定义:Dockerfile 是一个文本文件,包含了一系列用来构建镜像的指令。
- 作用:通过编写 Dockerfile,你可以定义镜像的构建过程,指定使用哪个基础镜像、复制哪些文件、安装哪些依赖、运行哪些命令、暴露哪些端口等等。
- 类比:Dockerfile 就像是建造房子的施工手册。它一步一步指导 Docker 如何根据基础蓝图(基础镜像)添加新的结构、安装水电(安装依赖)、粉刷墙壁(复制文件)、设置门窗(暴露端口),最终构建出完整的房子蓝图(新的镜像)。
2.4 仓库 (Registry)
- 定义:仓库是存放 Docker 镜像的地方。你可以将自己构建的镜像上传到仓库,也可以从仓库下载别人共享的镜像。
- 类型:
- 公共仓库:最著名的是 Docker Hub (hub.docker.com),是 Docker 官方提供的公共仓库,包含了大量官方镜像和社区上传的镜像。
- 私有仓库:企业或个人可以搭建自己的私有仓库,用于存放内部镜像,保证安全性和控制权。
- 类比:仓库就像是一个巨大的图书馆或者商品仓库,里面存放着各种各样的镜像(图书或商品)。你可以去那里借阅(拉取/下载)需要的镜像,也可以将自己制作好的镜像(你写的书或生产的商品)贡献(推送/上传)到仓库中。
2.5 卷 (Volume)
- 定义:卷是用于持久化容器数据的方式。
- 问题:容器的文件系统是短暂的,容器删除后,容器内部的数据也会随之消失。对于需要持久化存储的数据(如数据库文件、日志文件、用户上传的文件等),就需要使用卷。
- 作用:卷允许将容器文件系统中的特定目录映射到宿主机文件系统的一个目录或 Docker 管理的一个存储区域,从而实现数据在容器生命周期之外的持久化。
- 类比:卷就像是房子外面单独建立的一个储藏室。房子的内部装修(容器文件系统)可能会拆掉重建,但储藏室(卷)里的东西会一直保留,并且可以挂载到新的房子上。
2.6 网络 (Network)
- 定义:Docker 提供了多种网络模式,用于管理容器之间以及容器与宿主机之间的通信。
- 作用:通过 Docker 网络,你可以控制容器如何访问外部网络,以及容器如何相互发现和通信。
- 常见模式:bridge (桥接模式,默认)、host (宿主机模式)、none (无网络)、overlay (跨主机通信) 等。
- 类比:网络就像是小区里的道路和通信设施。它决定了小区里的房子(容器)之间如何互相拜访,以及如何与小区外面(外部网络)联系。
理解了这六个核心概念,你就掌握了 Docker 的基本原理。接下来,我们将进行一些基础实践。
3. 安装 Docker (简要介绍)
在开始实践之前,你需要先在你的操作系统上安装 Docker。Docker 提供了适用于 Windows, macOS 和各种 Linux 发行版的安装包和详细安装指南。
- Windows/macOS:安装 Docker Desktop,它提供了一个图形化界面和命令行工具,并且包含了运行 Docker 所需的虚拟机环境。
- Linux:通过包管理器安装 Docker Engine。
推荐做法:直接访问 Docker 官方网站 (https://www.docker.com/get-started/),查找对应你操作系统的详细安装步骤。官方文档是最新、最准确的资源。
安装完成后,打开终端或命令行工具,运行以下命令检查 Docker 是否安装成功:
bash
docker --version
docker info
如果能看到 Docker 版本信息和系统信息,说明安装成功。
4. Docker 基础使用:常用命令详解
现在我们开始学习如何使用 Docker 命令与容器和镜像进行交互。
4.1 拉取镜像 (docker pull
)
在使用容器之前,你需要先从仓库中获取镜像。
-
命令:
docker pull [OPTIONS] NAME[:TAG]
NAME
: 镜像名称 (如ubuntu
,nginx
,mysql
)TAG
: 镜像标签 (如latest
,18.04
,1.21
). 如果不指定标签,默认拉取latest
版本。
-
示例:拉取官方的 Ubuntu 镜像最新版
bash
docker pull ubuntu这个命令会连接到默认的 Docker Hub 仓库,下载 Ubuntu 镜像及其所有依赖的分层。
-
示例:拉取 Nginx 镜像的 1.21 版本
bash
docker pull nginx:1.21
4.2 运行容器 (docker run
)
docker run
命令是 Docker 中最常用的命令,它根据指定的镜像创建一个新的容器并运行它。
-
命令:
docker run [OPTIONS] IMAGE [COMMAND] [ARG...]
IMAGE
: 用于创建容器的镜像名称或 ID。COMMAND
和ARG...
:在容器启动后要执行的命令和参数 (可选)。
-
常用选项 (OPTIONS):
-d
,--detach
: 后台运行容器,并打印容器 ID。-p
,--publish <host_port>:<container_port>
: 将宿主机的端口映射到容器的端口,用于外部访问容器提供的服务。-v
,--volume <host_path>:<container_path>
: 将宿主机的文件或目录挂载到容器中的指定路径,实现数据持久化或共享。--name <container_name>
: 为容器指定一个唯一的名称,方便管理。如果不指定,Docker 会自动生成一个随机名称。-it
: 交互式运行容器。-i
保持标准输入打开,-t
分配一个伪终端。常用于进入容器进行交互操作或运行需要终端的应用。--rm
: 容器停止后自动删除容器。
-
示例 1:运行一个简单的 hello-world 容器
bash
docker run hello-world这个命令会查找本地是否有
hello-world
镜像,如果没有,就会从 Docker Hub 下载。然后根据镜像创建一个容器并运行。这个容器只是打印一条消息然后退出。 -
示例 2:以后台模式运行一个 Nginx Web 服务器,并将宿主机的 8080 端口映射到容器的 80 端口
bash
docker run -d -p 8080:80 --name mynginx nginx-d
: 让容器在后台运行。-p 8080:80
: 将宿主机的 8080 端口映射到容器内部 Nginx 监听的 80 端口。现在你可以通过http://localhost:8080
访问运行在容器里的 Nginx 服务了。--name mynginx
: 给这个容器起名为mynginx
。nginx
: 使用nginx
镜像来创建和运行容器。
-
示例 3:交互式运行一个 Ubuntu 容器,并进入其 bash 终端
bash
docker run -it ubuntu bash-it
: 开启交互模式并分配一个伪终端。ubuntu
: 使用 Ubuntu 镜像。bash
: 在容器启动后执行bash
命令,进入 Ubuntu 系统的终端。你可以在里面执行各种 Linux 命令,就像操作一个独立的 Ubuntu 系统一样。退出容器终端输入exit
即可。
4.3 查看容器 (docker ps
)
docker ps
命令用于查看当前正在运行的容器。
-
命令:
docker ps [OPTIONS]
- 默认只显示运行中的容器。
-a
,--all
: 显示所有容器,包括运行中、已停止、已退出的容器。
-
示例:查看所有正在运行的容器
bash
docker ps -
示例:查看所有容器 (包括已停止的)
bash
docker ps -a
命令输出通常包含容器 ID (CONTAINER ID)、使用的镜像 (IMAGE)、执行的命令 (COMMAND)、创建时间 (CREATED)、状态 (STATUS)、端口映射 (PORTS) 以及容器名称 (NAMES)。
4.4 停止、启动、重启容器 (docker stop
, docker start
, docker restart
)
你可以根据容器 ID 或容器名称来管理容器的生命周期。
-
命令:
docker stop <container_id_or_name>
docker start <container_id_or_name>
docker restart <container_id_or_name>
-
示例:停止名为
mynginx
的容器bash
docker stop mynginx -
示例:启动之前停止的容器
mynginx
bash
docker start mynginx
4.5 移除容器 (docker rm
)
移除不再需要的容器。注意:只能移除已停止的容器。要移除运行中的容器,需要先停止它,或者使用 -f
强制删除 (不推荐)。
-
命令:
docker rm [OPTIONS] <container_id_or_name> [<container_id_or_name>...]
-f
,--force
: 强制删除运行中的容器 (危险操作)。
-
示例:移除名为
mynginx
的容器bash
docker rm mynginx -
示例:移除所有已停止的容器 (结合
docker ps -a -q
)docker ps -a -q
会列出所有容器的 ID (静默模式,只输出 ID)。
bash
docker rm $(docker ps -a -q)
* 注意:执行此命令前请确保你真的想移除所有已停止的容器!
4.6 查看容器日志 (docker logs
)
查看容器的标准输出和标准错误日志。对于后台运行的容器,这是排查问题的重要方式。
-
命令:
docker logs [OPTIONS] <container_id_or_name>
-f
,--follow
: 持续输出日志,类似于tail -f
。--tail <number>
: 显示最后 N 行日志。--since <timestamp>
: 显示某个时间点之后的日志。
-
示例:查看
mynginx
容器的日志bash
docker logs mynginx -
示例:持续查看
mynginx
容器的日志bash
docker logs -f mynginx
4.7 进入容器 (docker exec
)
在运行中的容器内部执行命令。这对于调试非常有用。
-
命令:
docker exec [OPTIONS] <container_id_or_name> COMMAND [ARG...]
-it
: 交互式进入终端 (最常用)。
-
示例:进入运行中的
mynginx
容器的 bash 终端bash
docker exec -it mynginx bash执行后,你就进入了 Nginx 容器的环境,可以在里面执行
ls
,cd
,cat /etc/nginx/nginx.conf
等命令来检查容器内部的文件和配置。输入exit
退出容器终端,但容器本身不会停止。
4.8 查看镜像 (docker images
)
列出本地已下载或构建的所有镜像。
-
命令:
docker images [OPTIONS]
-
示例:查看本地所有镜像
bash
docker images
命令输出通常包含仓库名 (REPOSITORY)、标签 (TAG)、镜像 ID (IMAGE ID)、创建时间 (CREATED) 和大小 (SIZE)。
4.9 移除镜像 (docker rmi
)
移除本地的镜像。注意:如果要移除的镜像已经被某个容器使用(即使是已停止的容器),需要先移除使用它的容器,或者使用 -f
强制删除 (不推荐)。
-
命令:
docker rmi [OPTIONS] <image_id_or_name> [<image_id_or_name>...]
-f
,--force
: 强制删除镜像 (可能会移除相关的容器)。
-
示例:移除本地的 Ubuntu 镜像 (如果
latest
标签存在)bash
docker rmi ubuntu -
示例:根据镜像 ID 移除镜像
bash
docker rmi <image_id> -
示例:移除所有未被任何容器使用的镜像 (清理空间)
docker image prune
可以更安全地清理不再使用的镜像层。
bash
docker image prune -a # 删除所有悬挂的镜像和未被使用的镜像
* 注意:执行此命令前请确保你理解其作用!
5. 构建自己的镜像:Dockerfile 初体验
虽然我们可以直接使用 Docker Hub 上的官方镜像,但更多时候我们需要将自己的应用程序打包成镜像。这就需要编写 Dockerfile。
一个 Dockerfile 是一系列指令的集合,每条指令都创建镜像的一个新层。
常用 Dockerfile 指令:
FROM <base_image>[:<tag>]
: 指定基础镜像,你的新镜像将在此基础上构建。这是 Dockerfile 的第一条指令。RUN <command>
: 在镜像构建过程中执行命令。比如安装软件包、创建目录等。COPY <src> <dest>
: 将宿主机的文件或目录复制到镜像中的指定路径。ADD <src> <dest>
: 类似于COPY
,但ADD
还可以处理 tar 文件自动解压和远程 URL。通常推荐使用COPY
,因为它更透明。WORKDIR <directory>
: 设置工作目录。后续的RUN
,CMD
,ENTRYPOINT
等指令都会在这个目录下执行。EXPOSE <port> [<port>...]
: 声明容器运行时会监听的端口。这只是一个文档说明,并不会自动发布端口,发布端口需要在docker run
时使用-p
选项。CMD <command> [<param>...]
或CMD ["executable", "param1", "param2"]
: 指定容器启动时默认执行的命令。如果docker run
命令后面指定了其他命令,则会覆盖CMD
。一个 Dockerfile 只能有一个CMD
。ENTRYPOINT <command> [<param>...]
或ENTRYPOINT ["executable", "param1", "param2"]
: 指定容器启动时执行的命令。ENTRYPOINT
的命令不会被docker run
后面的命令覆盖,docker run
后面的参数会被作为ENTRYPOINT
命令的参数。常用于将容器作为可执行程序使用。如果同时定义了CMD
和ENTRYPOINT
,CMD
的内容会作为ENTRYPOINT
的默认参数。
构建镜像 (docker build
)
-
命令:
docker build [OPTIONS] <PATH | URL | -]
<PATH>
: Dockerfile 所在的目录路径。Docker 会查找该目录下的Dockerfile
文件。构建过程中的上下文 (Context) 也会包含该目录下的所有文件。-t
,--tag <image_name>[:<tag>]
: 为构建的镜像指定名称和标签。
-
示例:假设你在一个目录
/app
下创建了一个名为Dockerfile
的文件,并且想构建一个名为my-app
的镜像。bash
cd /app
docker build -t my-app:1.0 . # 注意最后的那个点 '.' 表示 Dockerfile 在当前目录下这个命令会读取当前目录下的
Dockerfile
,并根据其中的指令一步步构建镜像,最终将其命名为my-app
,标签为1.0
。
6. 一个小实践:运行一个 Web 服务器容器
让我们结合前面学到的知识,通过 Dockerfile 构建一个简单的 HTML 页面,并使用 Nginx 容器来提供服务。
-
创建项目目录和文件
创建一个新的目录,比如
my-web-app
:bash
mkdir my-web-app
cd my-web-app在该目录下创建一个简单的 HTML 文件
index.html
:html
<!-- index.html -->
<!DOCTYPE html>
<html>
<head>
<title>Hello Docker!</title>
</head>
<body>
<h1>Hello, Docker!</h1>
<p>This page is served by Nginx inside a Docker container.</p>
</body>
</html>在该目录下创建一个名为
Dockerfile
的文件 (注意文件名大小写):“`Dockerfile
Dockerfile
使用官方 Nginx 镜像作为基础镜像
FROM nginx:latest
将本地的 index.html 文件复制到容器中 Nginx 的默认网页根目录
COPY index.html /usr/share/nginx/html/
声明容器暴露 80 端口 (Nginx 默认监听的端口)
EXPOSE 80
容器启动时执行 Nginx 的启动命令 (这是 Nginx 镜像默认的 CMD,这里写出来作为示例)
CMD [“nginx”, “-g”, “daemon off;”]
“` -
构建镜像
在
my-web-app
目录下,执行构建命令:bash
docker build -t my-nginx-app:1.0 .你会看到 Docker 根据 Dockerfile 的指令一步步执行构建过程。构建完成后,你可以使用
docker images
命令查看本地是否生成了my-nginx-app:1.0
镜像。 -
运行容器
现在,运行刚刚构建的镜像,将容器的 80 端口映射到宿主机的 8080 端口:
bash
docker run -d -p 8080:80 --name my-web-container my-nginx-app:1.0 -
验证
打开你的浏览器,访问
http://localhost:8080
。如果一切顺利,你应该能看到 “Hello, Docker!” 的网页内容。使用
docker ps
查看正在运行的容器,你应该能看到名为my-web-container
的容器。使用
docker logs my-web-container
查看 Nginx 的日志。 -
清理
停止并移除容器:
bash
docker stop my-web-container
docker rm my-web-container移除镜像:
bash
docker rmi my-nginx-app:1.0
通过这个简单的实践,你已经完成了:编写 Dockerfile -> 构建镜像 -> 运行容器 -> 访问应用 -> 清理资源 的全过程。
7. 进阶之路 (简要提及)
掌握了 Docker 的核心概念和基础使用后,你可以进一步学习:
- Docker Compose:用于定义和运行多容器 Docker 应用的工具。通过一个 YAML 文件来配置应用的服务、网络和卷。
- Docker 网络进阶:了解桥接、Host、Overlay 等不同网络模式的详细工作原理。
- Docker 存储进阶:深入了解卷 (Volume)、绑定挂载 (Bind Mount) 以及存储驱动。
- Docker Swarm 或 Kubernetes:容器编排工具,用于大规模部署、管理和扩展容器化应用。
- CI/CD 集成:将 Docker 集成到自动化构建、测试和部署流程中。
- 安全:了解 Docker 的安全特性和最佳实践。
- 优化 Dockerfile:学习如何编写更高效、更小巧、更安全的 Dockerfile。
8. 总结
恭喜你!通过本指南的学习,你已经对 Docker 的核心概念有了清晰的认识,并掌握了最基础的 Docker 命令和构建镜像的方法。
Docker 是一个强大且不断发展的工具,容器化已经成为现代软件开发和运维不可或缺的一部分。掌握 Docker,不仅能提高你的工作效率,也能为学习微服务、DevOps、云计算等领域打下坚实的基础。
理论学习是基础,实践才是王道。强烈建议你多动手操作,尝试打包自己的应用程序,体验 Docker 带来的便利。如果在学习过程中遇到问题,可以查阅 Docker 官方文档或在线社区资源。
从这里开始,你的容器化之旅才刚刚启程!祝你学习顺利!