- 文集信息
- 目录大纲
- 最新文档
- 知识宇宙
文集详情
文集导读
Docker 入门与容器化实践
Docker 入门与容器化实践
1. 容器化时代:Docker 的崛起
在软件开发与部署的历史长河中,我们不断寻求更高效、更可靠的方式来构建、交付和运行应用程序。从物理机到虚拟机,再到今天的容器,技术的发展始终围绕着隔离、可移植性和资源利用率的提升。虚拟机虽然提供了隔离性,但其庞大的体积、启动缓慢以及资源消耗大的缺点,使得在快速迭代和微服务架构流行的今天显得力不从心。
正是在这样的背景下,容器技术应运而生,而 Docker 凭借其简洁的命令行工具、开放的标准和活跃的社区,成为了容器领域的领军者。Docker 提供了一种标准化的方式来打包应用程序及其所有依赖项到一个独立的、可移植的容器中,从而解决了“在我机器上可以运行”的问题,极大地简化了开发、测试和部署流程。
2. 什么是 Docker?
Docker 是一个开源的应用容器引擎,它允许开发者将应用程序及其依赖打包到一个轻便、可移植的容器中,然后发布到任何流行的 Linux、Windows 或 macOS 机器上。容器是完全使用沙箱机制,相互之间不受任何接口影响。
Docker 的核心组件包括:
-
Docker Daemon (Docker 守护进程):运行在主机上的后台服务,负责构建、运行和管理 Docker 容器。
-
Docker Client (Docker 客户端):用户与 Docker Daemon 进行交互的命令行工具(或其他工具)。
-
Docker Registry (Docker 仓库):用于存储和分享 Docker 镜像的地方,最常用的是 Docker Hub。
-
Docker Image (Docker 镜像):一个只读的模板,包含创建 Docker 容器所需的所有文件和设置,如代码、运行时、库、环境变量和配置文件。
-
Docker Container (Docker 容器):镜像的运行实例。容器可以被启动、停止、移动和删除。每个容器都是独立且隔离的。
下面是一个简单的 Docker 架构示意图:
图 2.1 Docker 基本架构示意图
3. 为什么选择 Docker?
使用 Docker 进行容器化实践带来了诸多显著优势:
-
环境一致性:打包应用程序及其所有依赖,确保在任何地方运行环境都完全一致,消除了“环境不匹配”的问题。
-
隔离性:容器之间相互隔离,每个容器都有自己的文件系统、进程空间、网络接口等,互不影响,提高了安全性。
-
可移植性:容器可以在任何支持 Docker 的平台上运行,无需修改,极大地简化了跨环境部署。
-
资源利用率高:与虚拟机不同,容器共享主机的操作系统内核,启动速度快,占用资源少,可以在同一台主机上运行更多应用。
-
快速部署:容器的标准化和轻量级使得应用的构建、测试和部署过程变得非常快速和可靠。
-
易于管理:Docker 提供了丰富的命令行工具和 API,方便对容器进行全生命周期管理。
-
持续集成/持续部署 CI/CD:Docker 容器是 CI/CD 流程中的理想构建和交付单元。
4. Docker 核心概念详解
深入理解 Docker 的核心概念是掌握容器化实践的基础。
4.1 Docker 镜像 Image
镜像是构建容器的基石。它是一个轻量级、可执行的软件包,包含了运行应用程序所需的一切:代码、运行时环境、库、环境变量和配置文件。
镜像采用分层存储的机制。每个镜像都由一系列的只读层组成。当你修改或构建新镜像时,Docker 会在现有层之上添加新的只读层。这种分层机制使得镜像的构建、共享和存储都非常高效,因为不同镜像可以共享相同的底层。
图 2.2 Docker 镜像分层示意图
4.2 Docker 容器 Container
容器是镜像的运行实例。当通过镜像启动一个容器时,Docker 会在镜像的只读层之上创建一个可写的容器层。容器中的所有操作(如创建、修改、删除文件)都发生在这个可写层中,不会影响到底层镜像。因此,多个容器可以共享同一个镜像,但它们各自的状态是独立的。
容器提供了一个隔离的运行环境,包括独立的文件系统、网络配置和进程空间。
图 2.3 镜像与容器关系示意图
4.3 Dockerfile
Dockerfile 是一个文本文件,包含了一系列用于自动化构建 Docker 镜像的指令。每一条指令都对应着镜像中的一个层。通过编写 Dockerfile,我们可以定义镜像的构建过程,实现“基础设施即代码”的理念。
常见的 Dockerfile 指令:
-
FROM: 指定基础镜像。 -
RUN: 在镜像构建过程中执行命令。 -
COPY: 将本地文件或目录复制到镜像中。 -
ADD: 类似于 COPY,但支持解压和远程 URL。 -
WORKDIR: 设置工作目录。 -
EXPOSE: 声明容器运行时监听的端口。 -
ENV: 设置环境变量。 -
CMD: 指定容器启动时默认执行的命令。 -
ENTRYPOINT: 配置容器启动时执行的命令,更适合作为可执行命令。
4.4 Docker Registry
Docker Registry 是集中存储和分发 Docker 镜像的服务。最著名的是 Docker Hub,提供了大量的官方镜像和用户上传的镜像。企业内部也可以搭建私有的 Docker Registry。
通过 docker pull 命令从 Registry 下载镜像,通过 docker push 命令将本地构建的镜像上传到 Registry。
4.5 Docker Volume
容器在运行时产生的数据如果直接存储在容器的可写层,会面临两个问题:一是容器被删除时数据会丢失;二是容器层是临时的,不适合存储持久化数据。
Docker Volume 就是为了解决这个问题而设计的,它提供了独立于容器生命周期的持久化存储能力。卷是主机文件系统中的一个目录或文件,可以被挂载到容器的文件系统中。即使容器被删除或重建,卷中的数据依然保留。
图 2.4 数据卷示意图
4.6 Docker Network
Docker 提供了多种网络模式,允许容器之间以及容器与外部世界进行通信。默认情况下,Docker 会为容器创建一个桥接网络(bridge network),使得同一桥接网络中的容器可以通过容器名或 IP 地址相互通信。通过端口映射(Port Mapping),可以将容器内部的端口映射到主机上的端口,从而允许外部访问容器中运行的应用。
5. Docker 入门实践:构建与运行你的第一个容器
本节将指导你完成 Docker 的基本操作:拉取镜像、运行容器、查看容器和镜像。
前提条件: 你需要在你的机器上安装 Docker Desktop 或 Docker Engine。安装步骤请参考 Docker 官方文档,此处不再赘述。
5.1 拉取第一个镜像
我们将从 Docker Hub 拉取一个官方的 Ubuntu 镜像。
docker pull ubuntu:latest
执行此命令后,Docker 会从 Docker Hub 下载最新版本的 Ubuntu 镜像到你的本地。你可以看到下载的进度和镜像的分层信息。
5.2 查看本地镜像
使用 docker images 命令可以查看本地已经下载或构建的镜像。
docker images
输出会显示镜像的仓库名(REPOSITORY)、标签(TAG)、镜像 ID(IMAGE ID)、创建时间(CREATED)和大小(SIZE)。
5.3 运行第一个容器
现在,我们来运行一个基于 Ubuntu 镜像的容器。我们将让容器执行一个简单的命令并在完成后退出。
docker run ubuntu:latest /bin/echo 'Hello from Docker!'
-
docker run: 运行一个容器的命令。 -
ubuntu:latest: 指定要使用的镜像。 -
/bin/echo 'Hello from Docker!': 指定容器启动后要执行的命令。
执行此命令后,Docker 会根据 ubuntu:latest 镜像创建一个新的容器,在容器中执行 /bin/echo 'Hello from Docker!' 命令,然后容器会自动停止并退出。你会在终端看到输出 Hello from Docker!。
5.4 运行一个交互式容器
很多时候,我们需要进入容器内部进行操作,就像操作一个虚拟机一样。这时可以使用 -it 参数来运行一个交互式容器。
docker run -it ubuntu:latest /bin/bash
-
-i: 保持标准输入打开,即使没有附加终端。 -
-t: 分配一个伪终端 TTY。 -
/bin/bash: 指定容器启动后执行的命令,这里是启动一个 Bash shell。
执行此命令后,你会进入到 Ubuntu 容器的命令行环境中,提示符会变为类似 root@<container-id>:/# 的形式。你可以在里面执行各种 Linux 命令,比如 ls, pwd, apt update 等。
要退出容器,输入 exit 命令即可。退出后,容器会停止运行。
5.5 查看正在运行的容器
使用 docker ps 命令可以查看当前正在运行的容器。
docker ps
如果你刚刚退出了交互式容器,这个命令可能不会显示任何内容,因为容器已经停止了。
5.6 查看所有容器(包括已停止的)
使用 docker ps -a 命令可以查看所有容器,包括正在运行的和已经停止的。
docker ps -a
你会看到刚才运行过的容器列表,包括它们的 ID、镜像、命令、创建时间、状态(Status)等信息。
5.7 停止和删除容器
找到你想停止或删除的容器的 ID(CONTAINER ID),可以使用 docker stop 和 docker rm 命令。
# 停止容器 docker stop <容器ID> # 删除容器 docker rm <容器ID>
例如,如果 docker ps -a 显示一个容器 ID 是 a1b2c3d4e5f6,你可以执行:
docker stop a1b2c3d4e5f6 docker rm a1b2c3d4e5f6
如果容器正在运行,直接使用 docker rm 会失败,需要先停止或使用 -f 参数强制删除(不推荐)。
5.8 删除镜像
如果你不再需要某个镜像,可以使用 docker rmi 命令删除它。
docker rmi <镜像ID或名称>
例如:
docker rmi ubuntu:latest
如果某个镜像正被某个容器使用,你需要先删除使用它的容器才能删除镜像。
6. 使用 Dockerfile 构建自定义镜像
前面我们使用了现有的镜像。但实际应用中,我们通常需要为自己的应用程序构建自定义镜像。这正是 Dockerfile 的用武之地。
假设我们有一个简单的 Python Flask Web 应用,文件名为 app.py:
# app.py from flask import Flask app = Flask(__name__) @app.route('/') def hello_world(): return 'Hello, Docker!' if __name__ == '__main__': app.run(debug=True, host='0.0.0.0')
以及一个列出依赖的 requirements.txt 文件:
Flask==2.0.2
我们将创建一个 Dockerfile 来构建包含这个应用的镜像。在存放 app.py 和 requirements.txt 的同一目录下创建名为 Dockerfile 的文件(注意文件名没有扩展名)。
# 使用官方 Python 基础镜像 FROM python:3.9-slim # 设置工作目录 WORKDIR /app # 将当前目录下的文件复制到容器的 /app 目录 COPY . /app # 安装 Python 依赖 RUN pip install --no-cache-dir -r requirements.txt # 暴露应用监听的端口 EXPOSE 5000 # 定义容器启动时执行的命令 CMD ["python", "app.py"]
6.1 构建镜像
在包含 Dockerfile、app.py 和 requirements.txt 文件的目录下打开终端,执行构建命令:
docker build -t my-flask-app:latest .
-
docker build: 构建镜像的命令。 -
-t my-flask-app:latest: 为构建的镜像指定名称和标签。 -
.: 指定 Dockerfile 所在的上下文路径,.表示当前目录。
Docker 会读取 Dockerfile 中的指令,一步一步地构建镜像。每一步都会生成一个中间层。构建成功后,你可以使用 docker images 命令看到新构建的 my-flask-app 镜像。
6.2 运行容器
使用新构建的镜像运行一个容器,并将容器内部的 5000 端口映射到主机的 8000 端口,以便从外部访问应用。
docker run -d -p 8000:5000 my-flask-app:latest
-
-d: 在后台模式运行容器。 -
-p 8000:5000: 将主机端口 8000 映射到容器端口 5000。
执行命令后,Docker 会启动一个容器并在后台运行。使用 docker ps 命令可以查看正在运行的容器。
现在,在浏览器中访问 http://localhost:8000,你应该能看到 "Hello, Docker!" 的输出,这表明你的 Flask 应用已经在 Docker 容器中成功运行并通过端口映射对外提供服务了。
7. 容器生命周期管理
了解容器的生命周期有助于更好地管理它们。一个容器可能处于以下几种状态:
-
Created:容器已被创建,但尚未启动。
-
Running:容器正在运行。
-
Paused:容器进程已被暂停。
-
Stopped:容器已停止,但其文件系统和状态仍然保留。
-
Dead:容器处于一个不应发生的状态。
-
Removed:容器已被完全移除。
图 2.5 Docker 容器生命周期示意图
常用的容器管理命令:
-
docker start <容器ID>: 启动一个已停止的容器。 -
docker stop <容器ID>: 优雅地停止一个正在运行的容器。 -
docker restart <容器ID>: 重启一个容器。 -
docker pause <容器ID>: 暂停一个正在运行的容器中的所有进程。 -
docker unpause <容器ID>: 取消暂停容器。 -
docker rm <容器ID>: 删除一个已停止的容器。 -
docker logs <容器ID>: 查看容器的日志输出。 -
docker exec -it <容器ID> <命令>: 在运行中的容器内部执行命令。
8. 数据持久化与卷 Volume
在容器中运行的应用通常需要读写数据。如前所述,容器的可写层是临时的。为了实现数据的持久化存储,我们需要使用卷(Volume)。
创建和使用卷的基本步骤:
-
创建卷:
docker volume create mydata -
运行容器并挂载卷:
docker run -d -v mydata:/app/data my-flask-app:latest这个命令创建并运行一个容器,并将名为
mydata的卷挂载到容器内部的/app/data目录。容器内写入/app/data的数据将存储在主机上的 Docker 管理的卷路径下,即使容器被删除,卷和数据仍然存在。 -
检查卷:
docker volume ls docker volume inspect mydata
除了 Docker 管理的卷,还可以使用绑定挂载(Bind Mounts),直接将主机上的某个目录或文件挂载到容器中的指定路径。
# 绑定当前目录下的 data 目录到容器的 /app/data docker run -d -v $(pwd)/data:/app/data my-flask-app:latest
绑定挂载更依赖于主机的文件系统结构,而 Docker 卷更抽象和易于管理,通常推荐使用 Docker 卷进行数据持久化。
9. 容器网络基础
Docker 提供了多种网络驱动来满足不同的网络需求。最常见的是 bridge 驱动,它是默认的网络模式。
当 Docker 启动时,会创建一个默认的 bridge 网络。没有指定网络的容器默认都会连接到这个网络。在同一个 bridge 网络中的容器可以通过 IP 地址相互通信。通过端口映射 -p 参数,可以将容器的端口暴露给主机,从而允许外部网络访问容器内的服务。
例如,-p 8000:5000 的含义是:将主机上的 8000 端口转发到容器内部的 5000 端口。当访问主机的 8000 端口时,流量会被路由到容器的 5000 端口。
对于更复杂的应用(如微服务),通常会创建自定义的桥接网络,使得连接到同一自定义网络的容器可以通过容器名相互发现和通信,而无需依赖端口映射(内部通信)。
# 创建自定义网络 docker network create my-app-network # 运行容器并连接到自定义网络 docker run -d --network my-app-network --name app1 image1 docker run -d --network my-app-network --name app2 image2 # 现在 app1 和 app2 可以通过容器名互相访问
10. 超越单容器:Docker Compose 与容器编排简介
虽然本章主要关注单个容器的入门实践,但在实际应用中,一个完整的应用往往由多个服务组成(如 Web 服务器、数据库、缓存等)。手动管理这些服务对应的容器会非常繁琐。
Docker Compose 是一个用于定义和运行多容器 Docker 应用的工具。通过一个 YAML 文件(通常命名为 docker-compose.yml),你可以一次性定义应用所需的所有服务、网络和卷,然后使用一个命令(docker-compose up)来启动整个应用栈。
对于更大规模、需要高可用性和伸缩性的应用部署,则需要使用容器编排工具,如 Docker Swarm 或 Kubernetes。这些工具可以管理跨多台主机的容器集群,提供服务发现、负载均衡、故障恢复、自动伸缩等能力。
Docker Compose 和容器编排工具是 Docker 容器化实践更进一步的重要方向,也是学习 Docker 后通常会探索的领域。
11. 总结
本章详细介绍了 Docker 的核心概念、优势以及入门级的容器化实践。我们学习了:
-
容器化技术及其解决的问题。
-
Docker 的基本组成部分:镜像、容器、Dockerfile、Registry、Volume、Network。
-
Docker 带来的环境一致性、隔离性、可移植性等优势。
-
如何使用基本的 Docker 命令拉取镜像、运行容器、管理容器和镜像。
-
如何编写 Dockerfile 构建自定义应用镜像,并运行容器对外提供服务。
-
容器的生命周期管理。
-
数据持久化通过卷实现。
-
容器网络的基础概念和端口映射。
-
Docker Compose 和容器编排工具作为未来学习方向的简介。
掌握这些基础知识,你已经迈出了容器化实践的第一步。Docker 极大地改变了软件的开发、交付和运维方式,是现代软件工程不可或缺的工具。继续深入学习 Docker 的高级特性、Docker Compose 以及 Kubernetes 等编排工具,将帮助你在云原生时代更加游刃有余。
目录大纲
最新文档
知识宇宙
正在加载知识图谱...