Docker实战:构建、运行与管理容器 – wiki词典


Docker实战:构建、运行与管理容器

在现代软件开发中,容器化技术已成为不可或缺的一部分,而 Docker 更是这一领域的领导者。它通过提供一种轻量级、可移植且自给自足的打包机制,彻底改变了应用程序的开发、部署和运行方式。本文将带您深入 Docker 的核心实践,从构建镜像到运行和管理容器,助您高效驾驭这一强大工具。

I. 引言

什么是 Docker?
Docker 是一个开源平台,用于开发、交付和运行应用程序。它利用 Linux 内核的容器化技术(如 Cgroups 和 Namespaces),将应用程序及其所有依赖项(代码、运行时、系统工具、系统库和设置)打包到一个名为容器(Container)的独立单元中。

为何选择 Docker?
* 环境一致性: 解决了“在我的机器上能运行”的问题,确保开发、测试和生产环境的一致性。
* 快速部署: 容器启动速度快,可以在几秒内启动应用程序。
* 资源隔离: 每个容器都是独立的,互不影响,提高了系统的稳定性和安全性。
* 可移植性: 打包好的 Docker 镜像可以在任何支持 Docker 的平台上运行。
* 高效利用资源: 相比传统虚拟机,容器更轻量,启动更快,占用的系统资源更少。

II. Docker 基础安装

在开始实战之前,请确保您的系统已安装 Docker。对于 Windows 和 macOS 用户,可以下载安装 Docker Desktop。对于 Linux 用户,可以安装 Docker Engine。具体安装步骤请参考 Docker 官方文档。

III. 构建 Docker 镜像

3.1 什么是 Docker 镜像?
Docker 镜像(Image)是一个轻量级、独立、可执行的软件包,包含运行应用程序所需的一切:代码、运行时、系统工具、系统库和设置。可以把它看作是容器的“蓝图”或“模板”。

3.2 Dockerfile 深度解析
Dockerfile 是一个文本文件,它包含了一系列指令,Docker 客户端会按照这些指令逐步构建镜像。它是镜像构建的核心。

常用 Dockerfile 指令:
* FROM <基础镜像>: 所有 Dockerfile 都必须以 FROM 指令开始,指定构建镜像所基于的基础镜像。例如:FROM ubuntu:latest
* RUN <命令>: 在当前镜像层上执行命令,并提交结果。常用于安装软件包、创建目录、执行脚本等。
* COPY <源路径> <目标路径>: 将本地文件或目录复制到镜像中的指定路径。
* WORKDIR <路径>: 设置工作目录。后续的 RUN, CMD, ENTRYPOINT 等指令都会在该目录下执行。
* EXPOSE <端口>: 声明容器运行时会监听的端口,这仅仅是文档性质的,并不会实际发布端口。
* CMD ["可执行文件", "参数1", "参数2"]: 提供容器启动时要执行的默认命令。如果 docker run 命令指定了其他命令,CMD 会被覆盖。
* ENTRYPOINT ["可执行文件", "参数1", "参数2"]: 配置一个容器启动时运行的可执行程序。与 CMD 结合使用时,CMD 的内容会作为 ENTRYPOINT 的参数。

Dockerfile 示例 (Node.js 应用):

“`dockerfile

第一阶段:构建阶段 (使用官方 Node.js 18 LTS 镜像作为基础)

FROM node:18-alpine AS builder

设置工作目录

WORKDIR /app

复制 package.json 和 package-lock.json (利用缓存,如果文件不变则直接使用缓存层)

COPY package*.json ./

安装项目依赖

RUN npm install

复制应用程序源代码

COPY . .

如果是前端应用,可以在此执行构建命令,例如:

RUN npm run build

第二阶段:运行阶段 (使用更小的 Node.js 镜像作为基础)

FROM node:18-alpine

设置工作目录

WORKDIR /app

从构建阶段复制安装的依赖和所有应用程序文件

COPY –from=builder /app/node_modules ./node_modules
COPY –from=builder /app .

暴露应用程序监听的端口

EXPOSE 3000

定义容器启动时执行的命令

CMD [“node”, “server.js”]
“`

3.3 镜像构建最佳实践
为了构建高效、安全且体积小的 Docker 镜像,请遵循以下原则:

  • 选择合适的基础镜像: 优先使用官方镜像,并选择最小化的基础镜像(如 Alpine 版本),以减少镜像大小和潜在漏洞。
  • 多阶段构建 (Multi-stage Builds): 在一个 Dockerfile 中使用多个 FROM 语句,将构建环境与最终运行环境分离。这样可以避免将开发和构建工具打包到最终镜像中,显著减小最终镜像的体积。
  • 利用 .dockerignore 文件: 类似于 .gitignore,用于排除构建上下文中不需要的文件和目录(如 node_modules.git、日志文件等),加快构建速度并减小镜像大小。
  • 优化层缓存: Docker 会缓存每个构建步骤的结果。将不常更改的指令放在 Dockerfile 的前面,以便更好地利用缓存,加快后续构建速度。
  • 合并 RUN 指令: 将多个相关的 RUN 命令合并成一个,可以减少镜像层数,从而减小镜像体积。使用 && 连接命令。
  • 避免安装不必要的软件包: 只安装应用程序运行所需的依赖项,保持镜像精简。
  • 非 root 用户运行:Dockerfile 中使用 USER 指令指定一个非 root 用户来运行容器,以增强安全性。

3.4 构建命令
Dockerfile 所在的目录执行以下命令来构建镜像:
bash
docker build -t my-node-app:1.0 .

* -t my-node-app:1.0: 为镜像指定名称 (my-node-app) 和标签 (1.0)。
* .: 指定构建上下文路径,表示 Dockerfile 位于当前目录。

IV. 运行 Docker 容器

4.1 什么是 Docker 容器?
Docker 容器(Container)是 Docker 镜像的一个运行实例。每个容器都是一个隔离的用户空间进程,拥有自己的文件系统、网络接口和进程空间。

4.2 docker run 命令详解
使用 docker run 命令来创建并启动一个容器。
bash
docker run [OPTIONS] IMAGE [COMMAND] [ARG...]

* IMAGE: 要运行的镜像名称(例如 nginx:latestmy-node-app:1.0)。
* COMMANDARG...: 容器启动后要执行的命令及其参数。如果指定,会覆盖 Dockerfile 中定义的 CMD

常用选项:
* -d (或 --detach): 在后台运行容器(分离模式),并打印容器 ID。
* -p <宿主机端口>:<容器端口> (或 --publish): 将容器内部的端口映射到宿主机上的端口,允许外部访问容器内运行的服务。例如:-p 8080:80
* -v <宿主机路径>:<容器路径> (或 --volume): 挂载卷,用于数据持久化或在宿主机与容器之间共享数据。例如:-v /app/data:/var/lib/mysql
* --name <容器名称>: 为容器指定一个易于识别的名称。
* -it (或 --interactive --tty): 以交互模式运行容器,并分配一个伪终端,通常用于进入容器的 shell 进行操作。
* --rm: 容器退出时自动删除容器。
* -e <环境变量名>=<值> (或 --env): 设置容器内的环境变量。

4.3 运行容器示例
* 运行一个 Nginx 容器并在后台运行,将宿主机的 8080 端口映射到容器的 80 端口,并命名为 my-nginx
bash
docker run -d -p 8080:80 --name my-nginx nginx:latest

* 运行之前构建的 my-node-app 容器,映射端口:
bash
docker run -d -p 3000:3000 --name my-web-app my-node-app:1.0

* 以交互模式运行 Ubuntu 容器并进入其 Bash shell:
bash
docker run -it ubuntu:latest /bin/bash

V. 管理 Docker 容器

Docker 提供了丰富的命令来管理容器的生命周期、数据和网络。

5.1 容器生命周期管理
* 列出运行中的容器:
bash
docker ps

* docker ps -a: 列出所有容器,包括已停止的。
* docker ps -q: 只显示容器 ID。
* 启动已停止的容器:
bash
docker start <容器ID或名称>

* 停止运行中的容器:
bash
docker stop <容器ID或名称>

* 重启容器:
bash
docker restart <容器ID或名称>

* 删除容器:
bash
docker rm <容器ID或名称>

* docker rm -f <容器ID或名称>: 强制删除运行中的容器。
* docker rm $(docker ps -aq): 删除所有已停止的容器。
* 在运行中的容器内执行命令:
bash
docker exec -it <容器ID或名称> <命令>

例如,进入 my-web-app 容器的 Bash shell:
bash
docker exec -it my-web-app /bin/bash

docker exec 允许您在不停止容器的情况下运行命令,非常适合调试或执行维护任务。

5.2 容器日志查看
* 查看容器的日志输出:
bash
docker logs <容器ID或名称>

* docker logs -f <容器ID或名称>: 实时跟踪容器日志。
* docker logs --tail 100 <容器ID或名称>: 查看最新的 100 行日志。

5.3 数据持久化:Docker 卷 (Volumes)
Docker 卷 (Volumes) 是用于持久化容器生成和使用的数据的首选机制。它们独立于容器的生命周期,即使容器被删除,数据也能保留。

  • 创建卷:
    bash
    docker volume create my-data-volume
  • 列出所有卷:
    bash
    docker volume ls
  • 使用卷运行容器:
    bash
    docker run -d -v my-data-volume:/app/data --name my-app-with-data my-node-app:1.0

    这会将名为 my-data-volume 的卷挂载到容器内的 /app/data 路径。
  • 删除卷:
    bash
    docker volume rm my-data-volume

    • docker volume prune: 删除所有未使用的本地卷。

5.4 容器网络 (Networks)
Docker 网络允许容器之间以及容器与外部世界进行通信。Docker 提供了多种网络驱动,最常用的是 bridge 模式。

  • 列出所有网络:
    bash
    docker network ls
  • 创建自定义网络:
    bash
    docker network create my-custom-network

    自定义网络可以提供更好的隔离性和服务发现。
  • 将容器连接到网络:
    bash
    docker run -d --name my-app --network my-custom-network my-node-app:1.0
    docker run -d --name my-db --network my-custom-network postgres:latest

    在同一个自定义网络中的容器可以通过名称相互通信(例如,my-app 可以通过 my-db 访问 PostgreSQL 数据库,而无需知道 IP 地址)。
  • 删除网络:
    bash
    docker network rm my-custom-network

5.5 清理 Docker 资源
随着时间的推移,Docker 会积累未使用的镜像、容器、卷和网络。定期清理可以释放磁盘空间。

  • 清理所有未使用的 Docker 资源(容器、网络、镜像、卷):
    bash
    docker system prune

    • docker system prune -a: 清理所有未使用的资源,包括悬空镜像和未被任何容器使用的镜像。

VI. 总结

Docker 已经成为现代软件开发和运维的基石。通过本文的实战指导,您应该已经掌握了构建 Docker 镜像、运行 Docker 容器以及进行日常管理的基本技能。从 Dockerfile 的编写到 docker run 的各种选项,再到数据持久化和网络配置,这些都是您高效利用 Docker 的关键。

未来,您可以进一步探索 Docker Compose 来管理多容器应用,以及 Docker Swarm 或 Kubernetes 等容器编排工具来部署和管理大规模容器集群。持续学习和实践,Docker 将为您的开发工作流带来前所未有的效率和便利。


滚动至顶部