📢 转载信息
原文链接:https://www.kdnuggets.com/10-essential-docker-concepts-explained-in-under-10-minutes
原文作者:Bala Priya C
图片由作者提供
# 引言
Docker 极大地简化了我们构建和部署应用程序的方式。但是,在您开始学习 Docker 时,术语可能会让人感到困惑。您可能会听到“镜像”、“容器”和“卷”等术语,但并不真正了解它们是如何组合在一起的。本文将帮助您理解需要了解的核心 Docker 概念。
让我们开始吧。
# 1. Docker 镜像 (Docker Image)
Docker 镜像是包含应用程序运行所需所有内容的制品:代码、运行时、库、环境变量和配置文件。
镜像(Images)是不可变的。一旦创建了镜像,它就不会改变。这保证了您的应用程序在您的笔记本电脑、同事的机器以及生产环境中运行方式完全相同,从而消除了环境特定的错误。
以下是如何从 Dockerfile 构建镜像。Dockerfile 是一个定义如何构建镜像的配方:
docker build -t my-python-app:1.0 .
-t 标志用于为您的镜像添加名称和版本标签。. 告诉 Docker 在当前目录中查找 Dockerfile。构建完成后,该镜像就成为应用程序的可重用模板。
# 2. Docker 容器 (Docker Container)
容器是运行镜像时得到的结果。它是一个隔离的环境,您的应用程序实际在此环境中执行。
docker run -d -p 8000:8000 my-python-app:1.0
-d 标志使容器在后台运行。-p 8000:8000 将主机上的端口 8000 映射到容器内的端口 8000,使得您的应用程序可以通过 localhost:8000 访问。
您可以从同一个镜像运行多个容器。它们独立运行。这就是您如何同时测试不同版本或通过运行十个相同的应用程序实例来进行水平扩展的方式。
容器非常轻量级。与虚拟机不同,它们不需要启动完整的操作系统。它们在几秒钟内启动,并共享主机的内核。
# 3. Dockerfile
Dockerfile 包含构建镜像的指令。它是一个文本文件,确切地告诉 Docker 如何设置您的应用程序环境。
这是一个用于 Flask 应用程序的 Dockerfile:
FROM python:3.11-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
EXPOSE 8000
CMD ["python", "app.py"]
我们来分解每条指令:
FROM python:3.11-slim— 从一个安装了 Python 3.11 的基础镜像开始。slim 变体比标准镜像更小。WORKDIR /app— 将工作目录设置为 /app。所有后续命令都从这里运行。COPY requirements.txt .— 首先只复制需求文件,而不是所有代码。RUN pip install --no-cache-dir -r requirements.txt— 安装 Python 依赖项。--no-cache-dir标志可以使镜像体积更小。COPY . .— 现在复制应用程序代码的其余部分。EXPOSE 8000— 说明应用程序使用端口 8000。CMD ["python", "app.py"]— 定义容器启动时要运行的命令。
这些指令的顺序对于构建所需的时间很重要,这也是我们需要理解镜像层(Layers)的原因。
# 4. 镜像层 (Image Layers)
Dockerfile 中的每条指令都会创建一个新层。这些层堆叠在一起,形成了最终的镜像。
Docker 会缓存每一层。当您重建镜像时,Docker 会检查是否需要重新创建每一层。如果未发生更改,它会重用缓存的层而不是重新构建。
这就是我们先复制 requirements.txt 而不是复制整个应用程序的原因。您的依赖项更改的频率低于代码。当您修改 app.py 时,Docker 会重用安装了依赖项的缓存层,并且只重建代码复制之后的层。
以下是我们 Dockerfile 中的层结构:
- 基础 Python 镜像 (
FROM) - 设置工作目录 (
WORKDIR) - 复制
requirements.txt(COPY) - 安装依赖项 (
RUN pip install) - 复制应用程序代码 (
COPY) - 关于端口的元数据 (
EXPOSE) - 默认命令 (
CMD)
如果您只更改了 Python 代码,Docker 只会重建第 5-7 层。第 1-4 层来自缓存,使构建速度快得多。了解分层有助于您编写高效的 Dockerfiles。将经常更改的文件放在最后,将稳定的依赖项放在开头。
# 5. Docker 卷 (Docker Volumes)
容器是临时的。当您删除容器时,容器内部的所有内容都会消失,包括应用程序创建的数据。
Docker 卷解决了这个问题。它们是存在于容器文件系统外部并能在容器删除后保留的目录。
docker run -d \
-v postgres-data:/var/lib/postgresql/data \
postgres:15
这会创建一个名为 postgres-data 的命名卷,并将其挂载到容器内的 /var/lib/postgresql/data。您的数据库文件可以在容器重启和删除后继续存在。
您也可以挂载主机机器上的目录,这在开发期间非常有用:
docker run -d \
-v $(pwd):/app \
-p 8000:8000 \
my-python-app:1.0
这会将您当前的目录挂载到容器内的 /app。您在主机上对文件所做的更改会立即反映在容器中,从而无需重建镜像即可实现实时开发。
有三种类型的挂载:
- 命名卷 (
postgres-data:/path) — 由 Docker 管理,最适合生产数据 - 绑定挂载 (
/host/path:/container/path) — 挂载任何主机目录,适用于开发 - tmpfs 挂载 — 仅将数据存储在内存中,适用于临时文件
# 6. Docker Hub
Docker Hub 是一个公共仓库,人们可以在其中共享 Docker 镜像。当您编写 FROM python:3.11-slim 时,Docker 会从 Docker Hub 拉取该镜像。
您可以搜索镜像:
docker search redis
并将它们拉取到您的机器上:
docker pull redis:7-alpine
您也可以推送自己的镜像以供他人共享或部署到服务器:
docker tag my-python-app:1.0 username/my-python-app:1.0
docker push username/my-python-app:1.0
Docker Hub 托管了流行的软件(如 PostgreSQL、Redis、Nginx、Python 等)的官方镜像,还有数千个。这些由软件创建者维护并遵循最佳实践。
对于私有项目,您可以在 Docker Hub 上创建私有仓库,或使用其他注册表,如 Amazon Elastic Container Registry (ECR)、Google Container Registry (GCR) 或 Azure Container Registry (ACR)。
# 7. Docker Compose
真正的应用程序需要多个服务。典型的 Web 应用包含一个 Python 后端、一个 PostgreSQL 数据库、一个 Redis 缓存,或许还有一个工作进程。
Docker Compose 允许您在一个 Yet Another Markup Language (YAML) 文件中定义所有这些服务并将它们作为一个整体进行管理。
创建一个 docker-compose.yml 文件:
version: '3.8'
services:
web:
build: .
ports:
- "8000:8000"
environment:
- DATABASE_URL=postgresql://postgres:secret@db:5432/myapp
- REDIS_URL=redis://cache:6379
depends_on:
- db
- cache
volumes:
- .:/app
db:
image: postgres:15-alpine
volumes:
- postgres-data:/var/lib/postgresql/data
environment:
- POSTGRES_PASSWORD=secret
- POSTGRES_DB=myapp
cache:
image: redis:7-alpine
volumes:
- postgres-data:/var/lib/postgresql/data
volumes:
postgres-data:
现在,只需一个命令即可启动整个应用程序堆栈:
docker-compose up -d
这会启动三个容器:web、db 和 cache。Docker Compose 会自动处理网络:web 服务可以通过主机名 db 连接到数据库,通过主机名 cache 连接到 Redis。
要停止所有服务,请运行:
docker-compose down
在代码更改后重建:
docker-compose up -d --build
Docker Compose 对开发环境至关重要。您无需在本地安装 PostgreSQL 和 Redis,只需通过一个命令即可在容器中运行它们。
# 8. 容器网络 (Container Networks)
当您运行多个容器时,它们需要相互通信。Docker 会创建虚拟网络来连接容器。
默认情况下,Docker Compose 会为 docker-compose.yml 中定义的所有服务创建一个网络。容器使用服务名称作为主机名。在我们的示例中,web 容器通过 db:5432 连接到 PostgreSQL,因为 db 是服务名称。
您也可以手动创建自定义网络:
docker network create my-app-network
docker run -d --network my-app-network --name api my-python-app:1.0
docker run -d --network my-app-network --name cache redis:7
现在 api 容器可以通过 cache:6379 连接到 Redis。Docker 提供了几种网络驱动程序,您经常会用到以下几种:
- bridge — 单台主机上容器的默认网络
- host — 容器直接使用主机的网络(无隔离)
- none — 容器没有网络访问权限
网络提供了隔离性。不同网络中的容器无法通信,除非明确连接。这有助于安全,因为您可以隔离前端、后端和数据库网络。
要查看所有网络,请运行:
docker network ls
要检查网络以及连接到该网络的容器,请运行:
docker network inspect my-app-network
# 9. 环境变量和 Docker 机密 (Docker Secrets)
硬编码配置是不可取的。您的数据库密码在开发和生产环境中不应该是相同的。您的 API 密钥绝对不应该存在于代码库中。
Docker 通过环境变量来处理这个问题。在运行时使用 -e 或 --env 标志传入它们,容器就能获得所需的配置,而无需将值“烘焙”到镜像中。
Docker Compose 使这更清晰。指向一个 .env 文件,并将您的机密信息排除在版本控制之外。部署时切换到 .env.production,或者如果变量不敏感,直接在 Compose 文件中定义环境变量。
Docker Secrets 在生产环境中(尤其是在 Swarm 模式下)更进一步。与环境变量(可能出现在日志或进程列表中)不同,机密在传输和静止时都是加密的,然后作为文件挂载到容器中。只有需要它们的服务才能访问它们。它们专为密码、令牌、证书以及任何泄露将是灾难性的内容而设计。
模式很简单:将代码与配置分离。使用环境变量进行标准配置,使用机密数据进行敏感数据。
# 10. 容器注册表 (Container Registry)
Docker Hub 对于公共镜像来说很方便,但您不希望公司的应用程序镜像公开可见。容器注册表是私有存储容器镜像的地方。流行的选择包括:
- Docker Hub(私有仓库,免费层有限)
- ECR
- GCR
- ACR
- 自托管注册表,如 Harbor 或 GitLab 容器注册表
对于上述所有选项,您可以遵循类似的过程来发布、拉取和使用镜像。例如,您将对 ECR 执行以下操作。
您的本地机器或持续集成/持续部署 (CI/CD) 系统首先向 ECR 证明其身份。这使得 Docker 能够安全地与您的私有镜像注册表而不是公共注册表进行交互。本地构建的 Docker 镜像会获得一个完全限定的名称,其中包括:
- AWS 账户注册表地址
- 仓库名称
- 镜像版本
此步骤告诉 Docker 镜像将在 ECR 中的哪个位置存储。然后将镜像上传到私有 ECR 仓库。一旦推送,镜像就会集中存储、版本化,并可供授权系统使用。
生产服务器向 ECR 进行身份验证,并从私有注册表下载镜像。这保证了您的部署流程快速且安全。不是在生产服务器上构建镜像(这很慢且需要源代码访问权限),而是构建一次,推送到注册表,然后在所有服务器上拉取。
许多 CI/CD 系统与容器注册表集成。您的 GitHub Actions 工作流程构建镜像,将其推送到 ECR,然后您的 Kubernetes 集群会自动拉取它。
# 总结
这十个概念构成了 Docker 的基础。它们在典型的工作流程中是这样连接的:
- 编写一个包含应用程序指令的
Dockerfile,并从Dockerfile构建一个镜像 - 从镜像运行一个容器
- 使用卷来持久化数据
- 设置环境变量和机密信息以进行配置和安全处理
- 为多服务应用程序创建一个
docker-compose.yml文件,让 Docker 网络连接您的容器 - 将您的镜像推送到注册表,然后在任何地方拉取并运行它
从小处着手,容器化一个简单的 Python 脚本。使用 requirements.txt 文件添加依赖项。然后使用 Docker Compose 引入数据库。每一步都建立在前面的概念之上。一旦理解了这些基本原理,Docker 就没那么复杂了。它只是一个用于一致地打包应用程序并在隔离环境中运行它们的一个工具。
祝您探索愉快!
Bala Priya C 是来自印度的开发人员和技术作家。她喜欢在数学、编程、数据科学和内容创作的交叉点工作。她的兴趣和专长领域包括 DevOps、数据科学和自然语言处理。她喜欢阅读、写作、编码和喝咖啡!目前,她正致力于通过撰写教程、操作指南、观点文章等来学习并与开发者社区分享她的知识。Bala 还创建引人入胜的资源概览和编码教程。
🚀 想要体验更好更全面的AI调用?
欢迎使用青云聚合API,约为官网价格的十分之一,支持300+全球最新模型,以及全球各种生图生视频模型,无需翻墙高速稳定,文档丰富,小白也可以简单操作。
评论区