写点什么

全面图解 Docker 架构设计:掌握 Docker 全链路思维 / 实战 / 优化 (小白到大师篇 [2])

作者:肖哥弹架构
  • 2024-10-04
    河北
  • 本文字数:5491 字

    阅读完需:约 18 分钟

全面图解Docker架构设计:掌握Docker全链路思维/实战/优化(小白到大师篇[2])


Docker 是一个革命性的开放平台,用于开发、交付和运行应用程序。通过使用 Docker,开发者可以打包他们的应用以及依赖包到一个轻量级、可移植的容器中,然后发布到任何支持 Docker 的环境中,在不同环境中实现一致的运行。无论是在虚拟机、物理服务器、数据中心还是云平台,Docker 都能确保应用的快速、可靠地部署和运行。


Docker 提供的不仅仅是容器,它还构建了一个庞大的生态系统,包括 Docker Hub、Docker Compose、Docker Swarm 等工具,这些工具涵盖了从开发到生产、从单一容器到容器编排的全方位需求。Docker 还支持多种编程语言、框架和中间件,使其成为现代应用开发和部署的首选工具。


肖哥弹架构 跟大家“弹弹” 高并发锁, 关注公号回复 'mvcc' 获得手写数据库事务代码

欢迎 点赞,关注,评论。

关注公号 Solomon 肖哥弹架构获取更多精彩内容

历史热点文章

本节内容

5、Docker 与 VM 对比


以下是 Docker 容器与虚拟机(VM)的对比,概括了它们在不同方面的特点和差异:


选择建议:

  • 选择 Docker 容器

  • 如果你正在构建微服务架构的应用。

  • 如果你需要快速迭代开发和部署应用。

  • 如果你希望在开发、测试和生产环境中保持一致性。

  • 如果你想要提高资源的利用率和减少成本。

  • 选择虚拟机

  • 如果你需要运行具有不同操作系统的应用。

  • 如果你要求有强烈的隔离性和安全性。

  • 如果你正在运行对系统资源有特别要求的大型应用。

  • 如果你已经投资了虚拟化管理工具和基础设施。

6、Docker 镜像处理


Docker 镜像是 Docker 容器运行的基础。它们是轻量级的、可执行的软件包,包含了运行应用所需的所有内容——代码、运行时、库、环境变量和配置文件。以下是 Docker 镜像处理的详细说明:

6.1. 基础概念

  • 镜像(Image) :一个只读的模板,其中包含了运行应用所需的所有内容。

  • 容器(Container) :镜像的运行实例。容器是镜像的可写层的直接体现。

6.2. 创建镜像

  • 使用 Dockerfile

  • Dockerfile 是一个文本文件,包含了用于构建镜像的一系列指令。

  • 基于基础镜像,通过 Dockerfile 定义的指令逐步构建新的镜像。

  • 提交容器为镜像

  • 运行中的容器可以通过 docker commit 命令保存为新的镜像。

6.3. 镜像分层

分层存储


  • Docker 镜像是由多个文件系统层组成的,这些层是只读的。每个层代表 Dockerfile 中的一个指令,比如 RUN, COPY, ADD, CMD 等。当 Docker 根据 Dockerfile 构建镜像时,每执行一个指令就会创建一个新的层。

  • 这种分层设计有利于复用和加速构建过程。


解释:


  • Docker 镜像分层:

  • 基础镜像层: 基础操作系统镜像层,比如 Ubuntu 或 Alpine。

  • 操作系统层: 包含操作系统的基础环境。

  • 软件安装层: 安装应用运行所需的软件包,比如数据库、依赖库等。

  • 应用代码层: 包含应用的代码文件。

  • 配置文件层: 包含应用的配置文件,如环境变量、启动脚本等。

  • 最终镜像: 由上述所有层叠加形成的最终镜像,用于生成容器。

  • 容器:

  • 容器 1, 容器 2: 基于同一个镜像运行的多个容器实例。

  • 容器 1 可写层, 容器 2 可写层: 容器的可写层,用于存储容器运行时产生的数据,如应用生成的日志、数据库文件等。


Docker 镜像分层存储的优点:


  1. 共享和重用: 多个容器可以共享和重用相同的镜像层,节省存储空间。

  2. 快速构建: 利用缓存可以避免重复工作,加快构建速度。

  3. 快速分发: 层可以独立分发,只更新变化的部分,节省带宽。

  4. 快速部署: 容器启动时叠加层的过程非常快,提高部署效率。


分层存储的操作


  • 构建缓存

  • 在构建过程中,Docker 会检查每个指令的缓存。如果发现之前的构建层没有变化,Docker 会跳过该指令的执行,直接使用缓存的层。

  • 清理无用层

  • 使用 docker system prune 命令可以清理悬空的镜像层,释放磁盘空间。

  • 查看镜像层

  • 使用 docker history 命令可以查看镜像的每一层以及对应的构建指令和元数据。


案例


Dockerfile 如下:


FROM ubuntuRUN apt-get updateRUN apt-get install -y nginxCMD ["nginx", "-g", "daemon off;"]
复制代码


这个 Dockerfile 会产生三个层:一个基础层 ubuntu,一个包含更新包的层,和一个安装了 nginx 的层。

6.4. 获取镜像

  • 拉取官方镜像

  • 使用 docker pull 命令从 Docker Hub 或其他私有仓库拉取官方镜像。

  • 私有镜像

  • 用户可以创建私有镜像,并将其推送到 Docker Hub 或其他私有仓库。

6.5. 构建镜像

  • 执行 docker build

  • 使用 docker build 命令根据 Dockerfile 构建新的镜像。

6.6. 管理镜像

  • 列出镜像

  • 使用 docker images 命令列出本地主机上的镜像。

  • 删除镜像

  • 使用 docker rmi 命令删除一个或多个镜像。

  • 清理镜像

  • 使用 docker system prune 命令清理未使用的镜像。

6.7. 分发镜像

  • 推送镜像

  • 使用 docker push 命令将镜像推送到远程仓库。

  • 拉取镜像

  • 使用 docker pull 命令从远程仓库拉取镜像。

6.8. 构建缓存

  • 利用缓存

  • Docker 会利用之前的构建缓存来加速构建过程。如果 Dockerfile 没有变化,Docker 会复用之前的构建层。

6.9. 多阶段构建

多阶段构建是 Docker 17.05 及更高版本引入的一项非常有用的功能,它允许在同一个 Dockerfile 中通过多个阶段构建镜像,并在每个阶段使用不同的基础镜像。这种构建方式不仅可以减小最终镜像的大小,还可以增强安全性。以下是多阶段构建的详细说明:

基本概念

在多阶段构建中,每个阶段都是独立的,并且可以基于一个不同的基础镜像。每个阶段中的指令(如 RUN, COPY, ADD 等)只会影响当前阶段的镜像层。最终的镜像将只包含你明确复制到新阶段的文件。

使用场景
  • 减小镜像大小:通过在一个阶段中编译应用,并在后续阶段中仅复制编译产物到新的基础镜像,可以显著减小最终镜像的大小。

  • 增强安全性:你可以在一个阶段中安装和运行编译工具,而在后续阶段中使用一个更小、更受限制的基础镜像运行编译后的应用。

案例


以下是一个多阶段 Dockerfile 的案例:


# 第一阶段: 构建阶段# 使用带有Node.js环境的官方镜像FROM node:16 AS build-stage# 设置工作目录WORKDIR /app# 复制package.json和package-lock.jsonCOPY package*.json ./# 安装项目依赖RUN npm ci# 复制项目文件到工作目录COPY . .# 构建应用,输出路径为/distRUN npm run build
# 最终阶段: 生产环境# 使用一个轻量级的base镜像FROM nginx:alpine# 将构建阶段的静态文件复制到nginx服务中COPY --from=build-stage /app/dist /usr/share/nginx/html# 暴露80端口EXPOSE 80# 设置启动命令,启动nginx服务CMD ["nginx", "-g", "daemon off;"]
复制代码


详细解释


构建阶段 (build-stage):


  1. 基础镜像: node:16,选择一个带有 Node.js 环境的官方镜像作为构建环境。

  2. 工作目录: 设置容器内的工作目录为 /app

  3. 复制依赖文件: 先将 package.jsonpackage-lock.json 复制到工作目录中。这允许 npm ci 命令仅安装必要的依赖,提高构建性能。

  4. 安装依赖: 运行 npm ci 安装项目依赖。ci 命令是持续集成环境下推荐的方式,因为它会根据 package-lock.json 精确安装依赖。

  5. 复制项目文件: 复制所有项目文件到工作目录,这样我们就可以在容器内进行构建。

  6. 构建应用: 执行 npm run build 命令来构建应用。这里假设项目中有一个 build 脚本,它会将应用构建为静态文件,输出到 /dist 目录。


生产环境阶段:


  1. 基础镜像: nginx:alpine,使用基于 Alpine Linux 的 Nginx 镜像,它比标准的 Nginx 镜像更小,因为它不包含许多默认的模块和文档。

  2. 复制静态文件: 从构建阶段的 /app/dist 目录复制静态文件到 Nginx 的静态文件目录 /usr/share/nginx/html

  3. 端口暴露: 暴露容器的 80 端口,这是 Web 服务的标准端口。

  4. 启动命令: 设置容器启动时执行的命令,这里使用 nginx 的参数 -g "daemon off;" 来确保 Nginx 在前台运行。

构建和运行

构建镜像:


docker build -t my-web-app .
复制代码


运行容器:


docker run -p 80:80 my-web-app
复制代码


通过以上步骤,我们利用多阶段构建的优势,先在具有完备工具链的环境下完成应用的构建,然后将构建产物部署到一个轻量级的运行时环境中。这样既保证了构建的便利性和最终镜像的小巧性,又提升了运行时的安全性。

6.10. 安全扫描

  • 扫描镜像

  • 使用 Docker Scanner 或其他工具扫描镜像中的安全漏洞。

7、Docker 容器与业务数据关系

容器设计为无状态的运行实例,但业务应用通常需要持久化数据以进行读写操作

7.1 数据存储策略

1. 临时文件系统(tmpfs)

容器内部的某些目录可以被设置为 tmpfs(内存中的临时文件系统),这样数据将在容器重启时消失。

2. 挂载(bind)

挂载是将宿主机的文件系统目录挂载到容器内部的技术。任何在挂载点的读写操作都会直接影响宿主机的文件系统。

3. Docker 卷(volume)

Docker 卷是专门设计用于持久化容器数据的。它们可以独立于容器生命周期,并且可以在多个容器之间共享数据。

4. 文件系统(Filesystem)

容器内部的文件系统是只读的,但 Docker 允许在特定目录(如 /app)中进行写操作。这些更改在容器重启后会丢失,除非使用卷或挂载。

5. 内存(Memory)

容器内的内存管理与业务数据的关系体现在容器可以使用的内存限制上。如果容器消耗的内存超出了限制,它可能会被宿主机的 Docker 守护进程终止。

7.2 容器业务数据存储方式

解释:
  • Docker:

  • 容器: Docker 容器,运行业务应用的实例,使用橙色表示。

  • Docker 卷: Docker 卷,用于持久化容器数据,确保数据在容器生命周期之外持久保存,使用绿色表示。

  • 宿主机文件系统: 通过挂载可以被容器访问的宿主机文件系统,使用浅黄色表示。

  • 容器文件系统: 容器内部文件系统,用于应用运行时的读写操作,通常需要配合 Docker 卷使用以实现数据持久化,使用浅黄色表示。

  • 内存: 容器可以使用的内存资源,Docker 可以对容器的内存使用进行限制,使用浅黄色表示。

  • 数据管理:

  • 业务数据: 业务应用生成的数据,需要持久化的数据,使用绿色表示。

  • 持久化数据: Docker 卷用于持久化容器产生的业务数据。

  • 共享数据: 宿主机文件系统可以被多个容器挂载,实现数据的共享。

Docker 卷的优点:
  1. 数据持久性: 即使容器被删除,卷中的数据仍然存在。

  2. 数据共享: 多个容器可以同时挂载同一个卷,实现数据共享。

  3. 数据备份: 可以对卷进行备份和恢复操作。

7.3 数据存储案例

案例 1: 使用 Docker 卷进行数据持久化

场景: 一个多容器的 WordPress 应用,需要持久化 WordPress 数据库和文件。Docker Compose 文件:


version: '3.8'  # 指定 Docker Compose 文件使用的版本
services: # 定义服务的根节点 db: # 定义一个名为 db 的服务,用于运行 MySQL 数据库 image: mysql # 使用 MySQL 官方镜像 volumes: # 定义挂载卷 - db_data:/var/lib/mysql # 将名为 db_data 的卷挂载到容器的 MySQL 数据目录 environment: # 设置环境变量 MYSQL_ROOT_PASSWORD: example # 设置 MySQL 根用户密码 MYSQL_DATABASE: wordpress # 设置默认创建的数据库名称 MYSQL_USER: wordpress # 设置数据库用户 MYSQL_PASSWORD: wordpress # 设置数据库用户密码
wordpress: # 定义一个名为 wordpress 的服务,用于运行 WordPress 应用 image: wordpress # 使用 WordPress 官方镜像 ports: # 定义端口映射 - "8000:80" # 将容器的 80 端口映射到宿主机的 8000 端口 depends_on: # 定义服务依赖 - db # wordpress 服务依赖于 db 服务 volumes: # 定义挂载卷 - wp_data:/var/www/html # 将名为 wp_data 的卷挂载到容器的 WordPress 安装目录
volumes: # 定义命名卷 db_data: # 定义一个名为 db_data 的命名卷,用于持久化 MySQL 数据 wp_data: # 定义一个名为 wp_data 的命名卷,用于持久化 WordPress 文件
复制代码


说明:


  • 使用 Docker 卷 db_datawp_data 来持久化 MySQL 数据库和 WordPress 文件。

  • volumes 定义在 docker-compose.yml 文件中,Docker 会自动在宿主机上创建这些卷。

案例 2: 挂载宿主机文件系统

场景: 开发环境中,开发者希望将本地代码挂载到容器中,以便进行快速迭代。命令:


docker run -it -v $(pwd):/app code_editor
复制代码


说明:


  • 使用 Docker 命令行 -v 参数将当前目录 ($(pwd)) 挂载到容器内的 /app 目录。

  • 这种方式使得容器内的应用程序可以使用宿主机的文件系统。

案例 3: 使用 tmpfs 进行高速缓存

场景: 一个需要快速读写缓存的 PHP 应用。Dockerfile:


# 使用官方 PHP 镜像作为基础镜像FROM php:7.4-apache
# 更新包索引并安装必要的扩展RUN docker-php-ext-install mysqli gd pdo_mysql
# 安装 ComposerRUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
# 设置工作目录WORKDIR /var/www/html
# 复制 Composer 配置和认证文件(如果有)COPY composer.* ./RUN composer install
# 复制应用代码到容器中COPY . .
# 暴露端口EXPOSE 80
# 启动 Apache 服务CMD ["apache2-foreground"]
复制代码


说明:


  • 设置环境变量 OPCACHE_PATH 指向 /tmp/opcache

  • 使用 VOLUME 指令创建一个临时文件系统(tmpfs),用于缓存加速。

案例 4: 限制容器内存

场景: 运行一个内存密集型应用,需要限制容器的内存使用。命令:


docker run -it -m 512m my_memory_intensive_app
复制代码


说明:


  • 使用 Docker 命令行 -m 参数限制容器的内存使用为 512MB。

  • 这种方式有助于防止单个容器占用过多宿主机资源。


其他内容在第二篇文章《全面图解 Docker 架构设计:掌握 Docker 全链路思维与优化(小白到大师篇[3])》中。。。

发布于: 刚刚阅读数: 4
用户头像

智慧属心窍之锁 2019-05-27 加入

擅长于通信协议、微服务架构、框架设计、消息队列、服务治理、PAAS、SAAS、ACE\ACP、大模型

评论

发布
暂无评论
全面图解Docker架构设计:掌握Docker全链路思维/实战/优化(小白到大师篇[2])_Docker_肖哥弹架构_InfoQ写作社区