跳到主要内容

管理容器镜像存储

默认情况下,容器内创建的所有文件都存储在可写的容器层上。这意味着:

  • 当容器不再存在时,数据不会持久保存,如果其他进程需要这些数据,从容器中提取数据可能会很困难。
  • 容器的可写层与容器运行的主机机器紧密耦合。您不能轻易地将数据移动到其他地方。
  • 向容器的可写层写入数据需要一个存储驱动程序来管理文件系统。存储驱动程序提供了一个联合文件系统,使用Linux内核。与直接写入主机文件系统的数据线量相比,这种额外的抽象会降低性能。

我们支持任何存储驱动程序——overlay2是一个很好的选择。

容器有两种选项可以将文件存储在主机机器上,以便即使容器停止后文件也能持久保存:数据线量和绑定挂载。

有关容器存储选项的更多信息,请参见Docker文档中的管理Docker中的数据。

为存储组使用卷

容器镜像为事件代理的存储组(/var/lib/solace)预定义了一个挂载点。如果您在启动容器时未指定storage-group,它将被存储在容器的可写层上。这可能会导致容器在联合文件系统中耗尽空间,并在升级过程中阻止数据被正确迁移。我们强烈建议为storage-group在联合文件系统之外分配存储。

软件事件代理需要中等至高带宽/IOPS和低延迟的存储。有关如何获得最佳存储性能的信息,请咨询您的平台的最佳实践文档。

数据线量是主机文件系统的一部分,由容器运行时(例如Docker Engine)管理,并已挂载在容器文件系统之外的可写层上。我们建议使用数据线量作为持久保存软件事件代理容器数据的手段。

对于作为数据线量挂载的storage-group,我们推荐使用xfs文件系统,因为它的性能优于ext4。如果您不使用xfsext4,您的文件系统必须支持fallocate linux命令。

在生产中使用外部存储设备

对于生产部署,我们建议您将事件代理的storage-group分配给外部存储设备。在容器文件系统中,storage-group存储在目录/var/lib/solace中。

有关Kubernetes存储选项的更多信息,请参见Kubernetes文档中的存储。

有关OpenShift存储选项的更多信息,请参见OpenShift文档中的了解持久存储。

无根容器的目录所有权

如无根容器中所述,容器运行时使用用户命名空间将容器内的UID和GID映射到主机上给定的(可能不同)用户块。这意味着如果您(作为非根用户)将主机目录挂载到容器中,它在容器内由根用户拥有。如果您以容器根用户身份在该目录中创建文件,然后在主机上查看该文件,您会看到它由您的非根主机用户拥有。

以下示例说明了这一点:

> whoami
solly

# 挂载一个空文件夹
host> ls /home/solly/folder
host> podman run -u 0 -v /home/solly/folder:/container/volume mycontainer /bin/bash

# 从容器内部创建文件
root@container> whoami
root
root@container> touch /container/volume/test

# 从容器内部检查文件所有者
root@container> ls -l /container/volume
total 0
-rw-r--r-- 1 root root 0 May 20 21:47 test
root@container> exit

# 在容器外部再次检查
host> ls -l /home/solly/folder
total 0
-rw-r--r-- 1 solly solly 0 May 20 21:47 test

如果容器以根用户身份运行,这不是问题,但从安全角度来看,最好以非根用户身份运行容器。然而,当容器用户是非根用户时,它无法访问由根用户拥有的数据线量。以上述示例为例,如果容器以非根用户身份运行,touch命令将因权限被拒绝而失败。

为了解决这个问题,您可以在podman unshare会话中运行chown来更改目录的所有权:

podman unshare chown -R <container-user>:<container-group> <path>

podman unshare命令允许您在与您的容器相同的用户命名空间中运行命令(在这种情况下是chown)。由于所有由给定用户运行的无根容器都在同一用户命名空间内运行,您只需要运行一次podman unshare chown,就可以让所有用户的容器访问一个目录。

当您第一次启动无根容器时,Podman会重置数据线量挂载的目录和文件的所有权,因此,只需在第一次启动容器后运行podman unshare命令。或者,创建一个空目录并将其绑定挂载——在这种情况下,会自动分配正确的目录/文件所有权。

有关更多信息,请参见无根容器和podman unshare文档。

配置外部存储的示例

以下是一些示例,展示了如何使用Docker和Podman为数据线量和绑定挂载配置外部存储。

示例:Linux Docker(使用数据线量)

要将storage-group分配给专用的外部数据线量,请执行以下操作:

  1. 将磁盘附加到主机。由于执行此任务的具体步骤因环境而异,我们建议您参考您环境的文档以获取说明。

  2. 创建新的storage-group数据线量。有关详细说明,请参考Docker文档中的使用数据线量。

  3. 创建一个新的容器,挂载新的storage-group数据线量,并将其实现在/var/lib/solace上:

docker create --network=host --uts=host --shm-size=1g --ulimit core=-1 --ulimit memlock=-1 --ulimit nofile=2448:42192 \
--env 'username_admin_globalaccesslevel=admin' --env 'username_admin_password=admin' --name=solace \
--mount source=storage-group,target=/var/lib/solace solace-pubsub-enterprise:<version>

如果您使用的是SELinux并需要更改挂载到容器中的主机文件或目录的标签,您必须使用--volume参数。--mount参数不支持用于修改SELinux标签的zZ选项。有关更多信息,请参见Docker文档中的配置SELinux标签。

示例:Windows Docker(使用绑定挂载)

在Windows Docker中扩展软件事件代理容器的默认存储能力,您可以利用主机上的驱动器,但这些驱动器必须与Windows Docker Linux VM共享。共享驱动器在Docker设置菜单中配置。

要使用绑定挂载将主机上的目录分配给storage-group作为外部存储,请在启动软件事件代理时将以下内容添加到docker run命令中,将<host-path>替换为您希望将storage-group挂载到的主机路径:

--mount type=bind,source=<host-path>,target=/var/lib/solace

以下示例使用C:\storage\data作为storage-group的外部存储:

> docker run --mount type=bind,source=C:\storage\data,target=/var/lib/solace -d -p 8080:8080 -p 55555:55555 ^
--shm-size=1g --env 'username_admin_globalaccesslevel=admin' --env 'username_admin_password=admin' ^
--name=solace solace-pubsub-standard:<version>

如果Windows进程正在使用您请求的端口之一,上述命令将因“端口不可用”错误而失败。您可以使用不同的端口,或者您可以预留端口,以便Windows无法使用它们。有关详细信息,请参见Solace社区的相关文章。

示例:Mac Docker(使用绑定挂载)

在Mac Docker中扩展软件事件代理容器的默认存储能力,您可以利用主机上的驱动器,但这些驱动器必须与Mac Docker Linux VM共享。共享驱动器在Docker设置菜单中配置。

要使用绑定挂载将主机上的目录分配给storage-group作为外部存储,请在启动软件事件代理时将以下内容添加到docker run命令中:

--mount type=bind,source=<host-path>,target=/var/lib/solace

以下示例使用/mnt/solace作为storage-group的外部存储:

> docker run --mount type=bind,source=/mnt/solace,target=/var/lib/solace -d -p 8080:8080 -p 55556:55555 \
--shm-size=1g --env 'username_admin_globalaccesslevel=admin' --env 'username_admin_password=admin' \
--name=solace solace-pubsub-standard:<version>

在MacOS Big Sur及更高版本上,端口55555(软件事件代理的默认SMF端口)被阻塞。如果此端口映射到Docker容器的端口,容器将无法启动,要么默默失败,要么出现“端口正在使用”错误。为了避免这个问题,compose模板将主机上的端口55554映射到容器中的端口55555。

示例:Linux无根Podman(使用绑定挂载)

要使用绑定挂载将主机上的目录分配给storage-group作为外部存储,请执行以下操作:

  1. 创建要用作storage-group外部存储的目录:
> mkdir /home/<user-name>/storage-group
  1. 更改目录的所有权,以便容器用户可以访问它(此命令假设UID 1000属于GID 0,但情况不必如此):
$ podman unshare chown 1000:0 -R /home/<user-name>/storage-group
  1. 启动容器:
> podman run -d -u 1000 -p 8080:8080 -p 55555:55555 \
--shm-size=1g --env 'username_admin_globalaccesslevel=admin' --env 'username_admin_password=admin' \
--mount type=bind,source=/home/<user-name>/storage-group,target=/var/lib/solace,relabel=private \
--name=solace docker.io/solace/solace-pubsub-standard:edge

如上所述,当您创建一个空目录并将其绑定挂载时,Podman在启动容器时正确分配目录/文件所有权。

示例:Linux无根Podman(使用数据线量)

要将storage-group分配给专用的外部数据线量,请执行以下操作:

  1. 将磁盘附加到主机。由于执行此任务的具体步骤因环境而异,我们建议您参考您环境的文档以获取说明。
  2. 确保Podman的数据线量路径正确指向外部磁盘。
  3. 创建新的storage-group数据线量。有关详细说明,请参考Podman文档中的Podman数据线量创建。
  4. 创建一个新的容器,挂载新的storage-group数据线量,并将其实现在/var/lib/solace上:
podman create -u 1000 --network=host --uts=host --shm-size=1g \
--ulimit core=-1 --ulimit memlock=-1 --ulimit nofile=2448:42192 \
--env 'username_admin_globalaccesslevel=admin' --env 'username_admin_password=admin' --name=solace \
--mount type=volume,source=storage-group,target=/var/lib/solace,relabel=private docker.io/solace/solace-pubsub-standard:edge

--networkhost模式使容器可以完全访问本地系统服务,如D-bus,因此被认为是不安全的。