收起左侧

本地 Docker 容器部署的较好实践

2
回复
31
查看
[ 复制链接 ]

1

主题

2

回帖

0

牛值

社区共建团

容器技术是存储、网络、计算的集合体。换言之,要想使用好容器,需要对容器的存储、网络、计算模型有比较丰富的经验。本文介绍在飞牛或其他任何 Linux 系统部署多个容器服务时可以使用的方案。

思考几个问题

首先,在使用容器的过程中,我们先考虑一下有可能遇到的问题。

存储性能

现在大部分容器都使用数据库技术,数据库和普通存储不一样。一般来说,数据库处于文件系统和应用程序之间。

数据库会向文件系统申请较大的单一文件存储自己的所有表。因此数据库的存储粒度是「自行管理」的。虽然看上去 .db 文件很大,但是数据库操作基本上也是小粒度的随机 I/O.

如果底层文件系统的逻辑块大小非常大,每次数据库读写的时候将会带来极大的写放大效应。因此,数据库的底层 I/O 应当和 MP4/MKV 等影音类型有所区别。


图 1. 给不同容器设置不同的 ZFS dataset 或者 btrfs subvolume,并设置不同的 recordsize, 对于数据库,用较小的 recordsize,影音文件可以用更大的/巨大的 recordsize.

如果数据库的 recordsize 被设置的很大,如 128KiB,那么一次 8KiB 的读取,就会「拔出萝卜带出泥」,需要先从硬盘读取 128KiB 左右的数据,然后从里面取出 8KiB. 当然,如果你使用的是 EXT4 这种简单的文件系统就不需要考虑这个问题了,然而,EXT4 的问题更大。

笼统地说,容器的存储应该有以下特征:

  1. 容器使用独立的目录或者 ZFS dataset / BtrFS subvolume. 而且需要对数据库、影音库设置不同的参数,以优化存取带宽,降低延迟。
  2. 容器最好使用 CoW 文件系统,这样会更容易地进行快照操作。

最后讲一下,为什么一个容器的存储要使用一个独立的 ZFS dataset 或 BtrFS subvolume?

我们考虑一个场景,Jellyfin 在升级的过程中,可能需要对数据库做转换,而这是一个非常危险的操作。如果你使用 jellyfin/jellyfin:latest 镜像,而且打开了自动更新,那么下次 docker compose up -d 的时候,就会自动使用最新的镜像,然后触发意料之外的数据库大更新。一旦失败,数据库可能也无法回滚,结果只能是重建数据库,背后的辛酸可想而知。如果可以执行细粒度的快照,这个问题将会不复存在,出问题直接回滚即可。

网络隔离

容器使用的网络命名空间技术也比较复杂。

网络命名空间指的是一个独立的网络堆栈环境,它拥有自己的网卡、IP、路由、iptables,这样会形成比较干净、安全的独立网络环境。即使两个容器在同一台物理机,只要在不同的网络命名空间里,它们就像在不同网络里一样,互不可见。

Docker 的网络是构建在 Linux 网络命名空间之上的:每个容器都有一个 独立的 network namespace,Docker 网络负责把这些 namespace 连接起来

[ Host namespace ]
     |
     |  veth pair (虚拟网线)
     |
+---------------+           +---------------------------+
| docker0 bridge| <-------> |  veth0 (in container)     |
+---------------+           |  Network Namespace        |
                            |  eth0 + IP + Route + FW   |
                            +---------------------------+

使用下列命令,可以创建一个 Docker 网络,并创建一个对应的 Linux 网络 interface.

docker network create --ipv6 --subnet 2001:0DB8::/112 reverse_proxy

并让 hexo 和 nginx 容器挂载到这个网络里:

services:

  # hexo 博客应用,其实就是 web 服务器而已。
  hexo:
    image: littlenewton/hexo:latest
    container_name: hexo
    hostname: hexo
    environment:
      - HEXO_SERVER_PORT=4000
      - GIT_USER=LittleNewton
      - GIT_EMAIL=littlenewton6@gmail.com
      - TZ=Asia/Shanghai
    volumes:
      - ${APPDATA_PATH}/Hexo/blog:/app
    networks:
      - reverse_proxy
    restart: unless-stopped

  # nginx 反向代理
  nginxproxymanager:
    image: "jc21/nginx-proxy-manager:latest"
    container_name: "nginxproxymanager"
    hostname: nginx-proxy-manager
    restart: unless-stopped
    privileged: true
    networks:
      - reverse_proxy
    ports:
      - "80:80"
      - "81:81"
      - "443:443"
    volumes:
      - ${APPDATA_PATH}/NginxProxyManager/data:/data
      - ${APPDATA_PATH}/NginxProxyManager/letsencrypt:/etc/letsencrypt

# 网络定义:此前通过命令行已经定义过了。
networks:
  reverse_proxy:
    name: reverse_proxy
    external: true

由于每次重启,容器都会被分配不同的 IP,甚至其网段也会小有变化。因此如何在容器里做反向代理就非常令人头疼

  • 写 IP 地址会变化,导致反向代理失效;
  • 设置静态 IP,相对比较繁琐。

问题其实很简单:什么都不需要操作,在 Docker 的自定义网络(比如刚才创建的 reverse_proxy)里,容器之间可以通过容器名进行 DNS 解析。

比如,我们在 NginxProxyManager 里,可以通过 hexo 这个容器名字,找到 hexo 容器的 IP 地址。而且,我们不需要手动设置任何 DNS 解析!

[root@docker-nginx-proxy-manager:/app]# nslookup hexo
Server:		127.0.0.11
Address:	127.0.0.11#53

Non-authoritative answer:
Name:	hexo
Address: 172.18.0.4
Name:	hexo
Address: 2001:db8::4


图 2. 在 NginxProxyManager 里,直接使用容器名进行记录添加。

绑定 CPU 核心

考虑到目前很多用户的 CPU 只有 8 核心左右,而且要开十几个甚至几十个容器,这里就暂时不讲了。

收藏
送赞
分享

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x

1

主题

2

回帖

0

牛值

社区共建团

2 小时前 楼主 显示全部楼层

NVIDIA 容器运行时

加速场景

  1. 部署 AI 推理服务
  2. 部署媒体服务器,实现编解码加速

一般来说,最朴素的做法就是把 NVIDIA 的 GPU 设备以文件路径的方式透传给容器。然而这么做有个巨大的弊端:需要在容器里装一遍显卡驱动!这就非常难受了。NVIDIA 的 GPU 驱动非常庞大,安装一遍可能得很久,而且很多容器镜像并没有集成 NVIDIA 驱动。那么怎么处理才好呢?

NVIDIA container-toolkit 解决了这个麻烦!

它的原理大约是(并不准确)把 GPU 驱动目录映射给容器,这样容器里就可以看到驱动文件,自然就省去了安装驱动的步骤。听上去非常简单,但是后面是很多工程师掉了许多头发才最终实现的。核心思路:驱动不进容器,容器访问宿主机的驱动。

安装 toolkit 后,Docker 会出现一个新 runtime: nvidia-container-runtime. 然后执行 docker run --gpus all nvidia/cuda:12.2-base 之后,Toolkit 会做三件事:

  • 自动把 /dev/nvidia* 挂载进容器
  • 自动把驱动的用户态库 /usr/lib/x86_64-linux-gnu/libnvidia-ml.so, /usr/lib/x86_64-linux-gnu/libcuda.so 从宿主机挂载进容器
  • 注入 GPU 相关环境变量。

因此,容器不用安装驱动,只需要 CUDA Runtime(用户空间 API,如 libcudart.so)。如此一来,Toolkit 解决了 user-space driver 注入的路径问题和 runtime 自动挂载问题。

安装命令如下:

sudo apt-get update && sudo apt-get install -y --no-install-recommends \
   curl \
   gnupg2

curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey | sudo gpg --dearmor -o /usr/share/keyrings/nvidia-container-toolkit-keyring.gpg \
  && curl -s -L https://nvidia.github.io/libnvidia-container/stable/deb/nvidia-container-toolkit.list | \
    sed 's#deb https://#deb [signed-by=/usr/share/keyrings/nvidia-container-toolkit-keyring.gpg] https://#g' | \
    sudo tee /etc/apt/sources.list.d/nvidia-container-toolkit.list

sudo apt-get update
export NVIDIA_CONTAINER_TOOLKIT_VERSION=1.18.0-1
  sudo apt-get install -y \
      nvidia-container-toolkit=${NVIDIA_CONTAINER_TOOLKIT_VERSION} \
      nvidia-container-toolkit-base=${NVIDIA_CONTAINER_TOOLKIT_VERSION} \
      libnvidia-container-tools=${NVIDIA_CONTAINER_TOOLKIT_VERSION} \
      libnvidia-container1=${NVIDIA_CONTAINER_TOOLKIT_VERSION}

随后测试能否在容器里使用 GPU:

$ docker run --gpus all -it --rm debian:trixie nvidia-smi
Sat Nov  8 12:24:37 2025
+-----------------------------------------------------------------------------------------+
| NVIDIA-SMI 580.105.08             Driver Version: 580.105.08     CUDA Version: 13.0     |
+-----------------------------------------+------------------------+----------------------+
| GPU  Name                 Persistence-M | Bus-Id          Disp.A | Volatile Uncorr. ECC |
| Fan  Temp   Perf          Pwr:Usage/Cap |           Memory-Usage | GPU-Util  Com** M. |
|                                         |                        |               MIG M. |
|=========================================+========================+======================|
|   0  NVIDIA GeForce RTX 3090        On  |   00000000:AF:00.0 Off |                  N/A |
| 30%   31C    P8             12W /  350W |       4MiB /  24576MiB |      0%      Default |
|                                         |                        |                  N/A |
+-----------------------------------------+------------------------+----------------------+

+-----------------------------------------------------------------------------------------+
| Processes:                                                                              |
|  GPU   GI   CI              PID   Type   Process name                        GPU Memory |
|        ID   ID                                                               Usage      |
|=========================================================================================|
|  No running processes found                                                             |
+-----------------------------------------------------------------------------------------+

OK,搞定

3

主题

72

回帖

0

牛值

初出茅庐

** 虽然看不太懂

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则