当我开始使用Docker时,我迅速意识到它是多么强大。想象一下,您可以在几分钟内设置开发环境,而不是几个小时,或者在不同的机器上运行应用程序,而不再有经典的“它在我的机器上可以运行”的问题。
Docker通过将应用程序打包成轻量级、可移植的容器,简化了我们构建、交付和运行应用程序的方式。无论您是开发人员、数据科学家还是系统管理员,掌握Docker都可以为您节省麻烦,并使您的工作流程更加高效。
在本教程中,我将带您了解基础知识——安装Docker、理解关键概念以及运行您的第一个容器化应用程序。到最后,您不仅会知道Docker是如何工作的,还会获得实际操作经验,为更高级的主题打下坚实的基础。让我们开始吧!
什么是Docker?
Docker是一个开源的容器化平台,通过将软件及其依赖项打包成一个标准化的单元——容器,简化了应用程序的部署。与传统的虚拟机不同,Docker容器共享主机操作系统内核,使它们更加高效和轻量。
容器确保应用程序在开发、测试和生产环境中以相同方式运行。这减少了兼容性问题,并增强了在各种平台之间的可移植性。由于其灵活性和可扩展性,Docker 已成为现代 DevOps 和云原生开发工作流程中的重要工具。
Docker 官方标志。
安装 Docker
Docker 可以在各种操作系统上安装,包括 Windows、macOS 和 Linux。尽管核心功能在所有平台上保持一致,但安装过程根据系统略有不同。以下是针对您选择的操作系统安装 Docker 的分步说明。
在 Windows 上安装 Docker
下载适用于 Windows 的 Docker Desktop 安装程序
- 运行安装程序并按照设置说明进行操作。
在Windows上安装Docker Desktop
- 如果提示,请启用WSL 2集成。
- 在PowerShell中运行
docker –version
以验证安装。
通过PowerShell检查安装后的Docker版本
5. 从运行菜单启动Docker Desktop应用程序。
在Windows上启动Docker Desktop应用程序
在macOS上安装Docker
下载Mac的Docker Desktop安装程序
- 打开下载的
.dmg
文件并将Docker拖动到应用程序文件夹中。 - 启动Docker并完成设置。
- 在终端中使用
docker –version
命令验证安装。
在 Linux(Ubuntu)上安装 Docker
- 更新软件包列表:
sudo apt update
- 安装依赖项:
sudo apt install apt-transport-https ca-certificates curl software-properties-common
- 添加 Docker 的官方 GPG 密钥:
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
- 添加 Docker 的存储库:
sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
- 安装 Docker:
sudo apt install docker-ce
- 验证安装:
docker –version
基本 Docker 概念
现在您已经安装了 Docker,您可能迫不及待地想要开始运行容器。但在我们开始之前,了解 Docker 工作的一些关键概念非常重要。这些概念将帮助您更有效地使用 Docker,并避免常见的初学者陷阱。
Docker 的核心是 镜像,它们作为容器的蓝图;容器,是这些镜像的运行实例;以及 Docker Hub,一个用于分享和管理镜像的集中式仓库。
让我们更详细地探讨这些概念。
Docker镜像
Docker镜像是容器的基本构建块。它们是不可变的只读模板,包含运行应用程序所需的一切,包括操作系统、应用程序代码、运行时和依赖项。
镜像是使用Dockerfile
构建的,它定义了逐层创建镜像的指令。
镜像可以存储在容器注册表中,并且可以从中检索,比如Docker Hub。
以下是一些处理镜像的示例命令:
docker pull nginx
:从Docker Hub获取最新的Nginx镜像。docker images
:列出本地计算机上所有可用的镜像。docker rmi nginx
:从本地计算机中删除一个镜像。
Docker容器
Docker容器是Docker镜像的运行实例。容器提供了一个隔离的运行环境,应用程序可以在其中运行而不会相互干扰或影响主机系统。每个容器都有自己的文件系统、网络和进程空间,但共享主机内核。
容器遵循一个简单的生命周期,涉及创建、启动、停止和删除。以下是常见容器管理命令的详细介绍:
- 创建一个容器:
docker create
或docker run
- 启动一个容器:
docker start
- 停止一个容器:
docker stop
- 重新启动一个容器:
docker restart
- 删除一个容器:
docker rm
让我们看一个实际的例子。以下命令在后台模式下运行一个 Nginx 容器,将容器内的端口 80 映射到主机的端口 8080:
docker run -d -p 8080:80 nginx
运行此命令后,Docker 将拉取 Nginx 镜像(如果尚未可用),创建一个容器并启动它。
要检查所有正在运行和停止的容器:
docker ps -a
这将显示所有容器的列表以及它们的状态和分配端口等详细信息。
Docker Hub
Docker Hub是一个基于云的注册服务,用于查找、存储和分发容器镜像。用户可以将自定义镜像推送到 Docker Hub,并选择公开或私下共享它们。
以下是一些与 Docker Hub 交互的命令:
docker login
:与 Docker Hub 进行身份验证。docker push my-image
:将自定义构建的镜像上传到 Docker Hub。docker search ubuntu
:搜索官方和社区镜像。docker pull ubuntu
:从 Docker Hub 下载 Ubuntu 镜像。
对容器化不太熟悉?通过容器化与虚拟化概念课程打下坚实基础。
运行您的第一个 Docker 容器
现在我们已经涵盖了 Docker 的核心概念,是时候将它们付诸实践了!让我们开始运行第一个容器,以确保 Docker 正确安装并按预期工作。
要测试您的 Docker 安装,请打开 PowerShell(Windows)或终端(Mac 和 Linux),并运行:
docker run hello-world
这将从 DockerHub 拉取hello-world
镜像并在容器中运行它。
Docker hello-world 镜像示例
现在,让我们更进一步,运行一个真实的应用程序——Nginx 网络服务器。执行以下命令:
docker run -d -p 8080:80 nginx
上述命令执行以下操作:
-d
标志使容器在分离模式下运行,这意味着它在后台运行。-p 8080:80
标志将容器内的 80 端口映射到您本地机器的 8080 端口,从而允许您访问网络服务器。
命令成功运行后,打开浏览器并访问:http://localhost:8080
在 localhost:8080 访问网络服务器
您应该会看到默认的 Nginx 欢迎页面,确认您的网络服务器正在容器内运行!
您还会在 Docker Desktop 中看到一个正在运行的容器:
Nginx 容器正在 8080 端口上运行
构建您的第一个 Docker 镜像
到目前为止,我们一直在使用来自 Docker Hub 的预构建镜像。但是如果你需要一个针对你的应用程序定制的环境呢?这就是构建你自己的 Docker 镜像的意义所在。。
创建 Docker 镜像涉及编写一个 Dockerfile
,这是一个自动化构建镜像的脚本。这确保了在不同环境之间的一致性和可移植性。一旦镜像构建完成,它可以作为容器运行,以在隔离的环境中执行应用程序。
在这一部分中,我们将学习编写 Dockerfile 的基本知识、构建自定义镜像以及将其作为容器运行。
Dockerfile 基础知识
A Dockerfile
是一个包含一系列指令的脚本,用于定义如何构建 Docker 镜像。它自动化了镜像创建过程,确保环境之间的一致性。每条指令在 Dockerfile
中都会在镜像中创建一个新的层。以下是一个简单的 Python Flask 应用程序的示例 Dockerfile 的分解:
# 包含 Python 运行时的基础镜像 FROM python:3.9 # 设置容器内的工作目录 WORKDIR /app # 将应用程序文件从主机复制到容器 COPY . /app # 安装 requirements.txt 中列出的依赖项 RUN pip install -r requirements.txt # 定义容器启动时运行 Flask 应用程序的命令 CMD ["python", "app.py"]
在上述命令中:
-v my-volume:/app/data
将my-volume
存储挂载到容器内的/app/data
目录。- 任何存储在
/app/data
中的数据,即使容器停止或被删除也会保持不变。
对上述 Dockerfile 的分解:
FROM python:3.9
: 指定具有预安装Python 3.9的基础镜像。WORKDIR /app
: 将/app
设置为容器内的工作目录。COPY . /app
: 将所有文件从主机的当前目录复制到容器中的/app
。RUN pip install -r requirements.txt
: 在容器内安装所有必需的依赖项。CMD ["python", "app.py"]
: 定义容器启动时要执行的命令。
构建和运行镜像
一旦定义了Dockerfile,就可以使用以下命令构建和运行镜像:
步骤 1:构建镜像
docker build -t my-flask-app .
上述命令:
- 将当前目录(
.
)作为构建上下文。 - 读取
Dockerfile
并执行其指令。 - 将生成的镜像标记(
-t
)为my-flask-app
。
步骤 2:将镜像作为容器运行
docker run -d -p 5000:5000 my-flask-app
上述命令:
- 以分离模式运行容器(
-d
)。 - 将容器内部端口5000映射到主机的端口5000(
-p 5000:5000
)。
运行后,您可以通过浏览器访问Flask应用程序,网址为http://localhost:5000
。
Docker卷和持久性
默认情况下,Docker容器内的数据是临时的——一旦容器停止或被删除,数据就会消失。为了跨容器重启持久化数据并在多个容器之间共享数据,Docker提供了卷,这是一种管理持久存储的内置机制。
与将数据存储在容器的文件系统内不同,卷由Docker单独管理,使其更高效,灵活且更易于备份。
在接下来的部分中,我们将探讨如何创建和使用Docker卷以确保容器中的数据持久性。
创建和使用Docker卷
第1步:创建卷
在使用卷之前,我们需要创建一个。运行以下命令:
docker volume create my-volume
这将创建一个名为my-volume
的卷,Docker将单独管理它,而不与任何特定容器关联。第2步:在容器中使用卷
现在,让我们启动一个容器并在其中挂载卷:
docker run -d -v my-volume:/app/data my-app
在上述命令中:
-v my-volume:/app/data
将my-volume
存储挂载到容器内的/app/data
目录。- 存储在
/app/data
中的任何数据即使在容器停止或被删除后也会持久保留。
用于多容器应用的 Docker Compose
到目前为止,我们一直在使用单容器应用,但许多现实世界的应用需要多个容器协同工作。例如,一个 Web 应用可能需要一个后端服务器,一个数据库和一个缓存层——每个都在自己的容器中运行。手动使用单独的 docker run
命令管理这些容器很快就会变得乏味。
这就是 Docker Compose 的用武之地。
什么是 Docker Compose?
Docker Compose 是一个简化多容器应用程序管理的工具。您可以通过定义一个 docker-compose.yml
文件来定义整个应用程序堆栈,并使用单个命令部署,而不是运行多个 docker run
命令。
编写 Docker Compose 文件
现在,让我们创建一个真实世界的示例——一个简单的连接到 MongoDB 数据库 的 Node.js 应用程序。我们将在一个 docker-compose.yml
文件中定义它们,而不是分别管理这两个容器。
以下是我们在 Docker Compose 中定义多容器设置的方式:
version: '3' services: web: build: . ports: - "3000:3000" depends_on: - database database: image: mongo volumes: - db-data:/data/db volumes: db-data:
解析上面的文件:
version: '3'
:指定 Docker Compose 版本。services:
:定义单独的服务(容器)。web:
:定义 Node.js web 应用程序。database:
:定义 MongoDB 数据库容器。volumes:
:为 MongoDB 数据持久性创建一个命名卷(db-data
)。
运行多容器应用程序
一旦 docker-compose.yml
文件准备好,我们可以使用单个命令启动整个应用程序堆栈:
docker-compose up -d
上一个命令以分离模式(-d
)启动 web 和数据库容器。
要停止所有服务,请使用:
docker-compose down
这将停止并移除所有容器,同时保留卷和网络设置。
Docker 网络基础知识
到目前为止,我们专注于运行容器和管理存储,但当容器需要相互通信时会发生什么?在大多数实际应用中,容器不是孤立运行的,它们需要交换数据,无论是 Web 服务器与数据库通信,还是微服务之间互相交互。
Docker 提供了一系列网络选项,以适应不同的使用情况,从隔离的内部网络到外部可访问的配置。
准备提升您的 Docker 技能了吗?立即报名 中级 Docker,探索多阶段构建、高级网络等内容!
什么是 Docker 网络?
Docker 网络是一项内置功能,允许容器相互通信,无论是在同一主机上还是在分布式环境中跨多个主机。它提供了适用于不同部署场景的网络隔离、分段和连接选项。
Docker 支持多种网络类型,每种类型都适用于不同的用例:
- 桥接(默认):同一主机上的容器通过内部虚拟网络进行通信。每个容器在桥接网络中都有自己的私有 IP 地址,它们可以通过容器名称相互访问。
- 示例:
docker network create my-bridge-network
- 适用于在单个主机上运行多个容器,这些容器需要安全通信而不暴露服务给外部。
- 主机:容器共享主机的网络堆栈,并直接使用主机的IP地址和端口。
- 示例:
docker run --network host nginx
- 在需要高性能且不需要网络隔离的情况下非常有用,例如运行监控代理或低延迟应用程序。
- 叠加:通过创建分布式网络,在不同主机上启用容器通信。
- 示例:
docker network create --driver overlay my-overlay-network
- 适用于像Docker Swarm这样的编排部署,其中服务跨越多个节点。
- Macvlan:为每个容器分配一个唯一的MAC地址,使其在网络上看起来像一个物理设备。
- 示例:
docker network create -d macvlan --subnet=192.168.1.0/24 my-macvlan
- 用于容器需要直接网络访问时,比如集成传统系统或与物理网络交互时。
在自定义网络上运行容器
让我们来看看如何设置和使用自定义桥接网络以进行容器通信。
步骤1:创建自定义网络
在运行容器之前,我们首先需要创建一个专用网络:
docker network create my-custom-network
此命令创建一个隔离网络,容器可以加入以进行容器间通信。
步骤2:在网络上运行容器
现在,让我们启动两个容器并将它们连接到我们新创建的网络:
docker run -d --network my-custom-network --name app1 my-app docker run -d --network my-custom-network --name app2 my-app
- 使用
--network my-custom-network
标志将容器连接到指定的网络。 - 使用
--name
标志分配一个唯一的容器名称,使得更容易引用。
app11
和app2
现在可以使用它们的容器名称进行通信。您可以在其中一个容器内部使用ping
命令来测试连接性:
docker exec -it app1 ping app2
如果一切设置正确,您将看到一个确认容器可以通信的响应。
检查Docker网络
要验证网络配置和连接的容器,请使用:
docker network inspect my-custom-network
此命令提供有关网络的详细信息,包括IP范围、连接的容器和配置。
暴露和发布端口
运行需要从外部访问的容器时,可以暴露特定端口。
例如,要运行一个Nginx Web服务器并将其暴露在本地机器的8080端口上,请使用:
docker run -d -p 8080:80 nginx
这将容器内部的80端口映射到主机上的8080端口,使服务可以通过http://localhost:8080访问。
Docker网络的最佳实践
- 使用自定义网络:避免在生产部署中使用默认的桥接网络,以减少容器之间的意外访问。
- 利用基于DNS的发现:不要硬编码IP地址,使用容器名称实现动态服务发现。
- 限制外部暴露:使用防火墙或网络策略控制服务访问。
- 监控流量:使用诸如
docker network inspect
、Wireshark或Prometheus等工具分析网络流量并检测异常。 - 优化覆盖网络:如果在分布式环境中部署,通过利用主机本地路由选项来调整覆盖网络,以减少延迟。
Docker最佳实践和下一步
现在您已经学习了Docker的基本知识,是时候提升您的技能并采用最佳实践,以帮助您构建安全、高效和易于维护的容器化应用程序。
以下最佳实践将帮助您简化Docker工作流程并避免常见陷阱。
- 使用官方基础镜像: 始终优先选择官方和维护良好的基础镜像,以确保安全性和稳定性。官方镜像经过优化,定期更新,并且不太可能包含漏洞。
- 保持镜像小巧: 通过选择最小化的基础镜像(例如,
python:3.9-slim
而不是python:3.9
)来减小镜像大小。去除不必要的依赖和文件,以优化存储和拉取时间。 - 使用多阶段构建: 通过分离构建和运行时依赖来优化 Dockerfile。多阶段构建确保只有必要的工件被包含在最终镜像中,从而减小大小和攻击面。
- 正确标记镜像:始终使用版本标签(例如,
my-app:v1.0.0
),而不是latest
,以避免在拉取镜像时出现意外更新。 - 扫描镜像以查找漏洞:使用安全扫描工具,如
docker scan
、Trivy
或Clair
,在部署之前识别和修复镜像中的安全漏洞。 - 安全管理环境变量:避免将敏感凭证存储在镜像内部。使用Docker秘密、环境变量或外部秘密管理工具,例如AWS Secrets Manager或HashiCorp Vault。
- 使用 .dockerignore 文件: 排除不必要的文件(例如,
.git, node_modules
,venv
),以减小构建上下文大小,并防止意外包含敏感文件在镜像中。 - 启用日志记录和监控: 使用 Prometheus、Grafana 和 Fluentd 等工具进行容器日志和监控。使用
docker logs
检查日志,并启用结构化日志以实现更好的可观测性。
一旦掌握了 Docker 的基础知识,就有许多高级主题可以探索。以下是一些值得进一步探索的领域:
- Docker Swarm & Kubernetes: 探索 Docker Swarm(内置集群)和 Kubernetes(具有自动扩展和服务发现的企业级编排)用于生产级编排。
- 容器安全最佳实践: 要保护容器化应用程序,请遵循 CIS Docker Benchmark 指南并实施基于角色的访问控制(RBAC)。
- 使用Docker构建CI/CD流水线:使用GitHub Actions、GitLab CI或Jenkins自动化镜像构建、安全扫描和部署。
- 云原生开发:利用Docker与AWS ECS、Azure Container Instances和Google Cloud Run等云平台进行可伸缩和托管部署。
- 数据持久化策略:为了实现最佳存储管理,了解Docker卷、绑定挂载和tmpfs之间的区别。
结束
Docker 已经彻底改变了开发人员构建、发布和运行应用程序的方式,使其成为现代软件开发的重要工具。
在本教程中,我们涵盖了:
- Docker 是什么以及为什么它很重要
- 如何安装和运行您的第一个容器
- 像镜像、容器和网络等关键概念
- 使用 Docker 卷进行持久存储
- 使用Docker Compose构建多容器应用
- 安全性、性能和可伸缩性的最佳实践
但这只是一个开始!如果您想深入了解Docker,您可以参加 入门级 Docker入门课程。想要更深入的知识,可以学习 中级Docker课程,涵盖多阶段构建、Docker网络工具和Docker Compose。最后,您也可以考虑Docker认证,感兴趣的话可以查看2025年完整的Docker认证(DCA)指南!