我正在将现有应用程序从在裸 EC2 实例上运行迁移到使用 ECS 的容器化设置。我有两种需要在容器之间共享数据的情况。一种是存储一些静态和媒体文件的 EFS 共享,另一种是日志目录,以便我可以使用 sidecar 容器中的 Cloudwatch Logs 代理将日志推送到 Cloudwatch。
网络服务器需要能够将数据写入这两个位置,但到目前为止我还没能做到这一点。日志目录是一个本地卷,归所有root:root
。我设置的 EFS 共享如下这些指令,归1000:xfs
(无用户名) 所有。在任何情况下,我的网络用户 ( www-data
) 都无法写入这些位置。
如何告诉 ECS 在具有给定所有者和/或组的容器内安装卷?
答案1
编辑:事实证明这比我做的要简单得多。
当您在 ECS 上创建卷时,它会要求您输入卷的名称和“源路径”。当被要求解释时,它会指定源路径是“主机容器实例上呈现给此卷的容器的路径。如果省略,则 Docker 守护程序会为您分配主机路径。”
一切都很好,但事实证明,区别不仅仅是“指定目录”与“Docker 为您选择目录”。这是docker 卷和一个绑定挂载,实际上如果你docker inspect
查看容器,你会看到你为 ECS 指定“源路径”的卷会得到"Type": "bind"
,而未指定的卷则会得到"Type": "volume"
。
绑定挂载和卷之间的一个关键区别是,绑定挂载从主持人文件系统,卷从继承其所有权容器文件系统。因此,解决我的问题的简单方法就是确保目录存在于具有正确所有权的映像中,然后在 ECS 中创建卷没有指定源路径。
顺便说一句,如果你的应用程序涉及多个容器共享同一个卷,那么无论哪个容器启动并运行,该卷都将从现有的目录结构中获取其权限第一的。因此,您需要确保 a) 该目录存在于将要挂载卷的所有容器中,或者 b) 始终首先启动具有该目录的容器。
我将在下面保留我原来的解决方案,以便它对任何人都有用。
原方案1:tmpfs mounts
Docker 卷接受一个driver_opts
参数,其工作方式与 Linux 系统上的命令类似mount
。因此,一种选择是使用tmpfs
挂载,它允许设置结果文件的所有者和组的选项。在 ECS 上,这可以这样实现:
{
"name": "myvolume",
"dockerVolumeConfiguration": {
"scope": "task",
"driver": "local",
"driverOpts": {
"type": "tmpfs",
"device": "tmpfs",
"o": "uid=1000,gid=1000"
}
}
}
这将在容器内创建一个由用户和组 1000 拥有的卷。
这种方法的缺点是,tmpfs
它将文件存储在主机内存中。根据您的使用情况,这可能是或可能不可接受的 - 对我来说这不是理想的,因为我需要存储可能变得非常大的日志文件。
(请注意,此处的type
和device
参数driverOpts
相当于type
device
Linuxmount
命令。我花了相当多的时间和精力才弄明白这一点。)
原始解决方案 2:通过 NFS 匹配 UID
NFS 只是将文件的所有者/组存储为数字 ID。组之所以显示为xfs
我,是因为作为重新部署的一部分,我将从 Ubuntu 迁移到 Alpine。在这两种情况下,我都想使用www-data
该组,但www-data
在 Ubuntu 上是用户/组 33,在 Alpine 上是 82。在 Alpine 上,33 已经作为“X 字体服务器”用户存在,因此xfs
。
对于非持久性、共享的“临时工作”目录,我仍没有一个完美的解决方案,可以在日志等待发送到 Cloudwatch 时将其转储到其中。我可能最终会使用 tmpfs 解决方案,然后使用一组非常激进的参数运行 logrotate,这样日志文件消耗的内存就不会超过几 MB。