我正在开发基于 LXC 构建的软件。除其他外,我们希望在运行时将主机中的文件夹挂载到 LXC 容器中,因此我们不能将挂载点放入我们的lxc.conf
(我们为静态挂载点所做的)。
在安装工作时,重新安装只读不起作用。在主机中重新挂载成功,但挂载点在容器中仍显示为读/写。
示例程序
我创建了一个扩展 LXC API 示例(https://linuxcontainers.org/lxc/documentation/)的小程序,它显示了这种行为。我希望你能原谅代码中缺乏令人敬畏的东西。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/mount.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <lxc/lxccontainer.h>
int do_unmount(char *dir) {
printf("Un-mounting %s\n", dir);
if(umount(dir) == -1) {
fprintf(stderr, "Failed to unmount %s\n", dir);
return 1;
}
return 0;
}
int container_test(struct lxc_container *c, char *mountName) {
if (c->is_defined(c)) {
fprintf(stderr, "Container already exists\n");
return 1;
} else {
printf("Container now exists, good\n");
}
/* Create the container */
if (!c->createl(c, "busybox", NULL, NULL, LXC_CREATE_QUIET, NULL)) {
fprintf(stderr, "Failed to create container rootfs\n");
return 2;
} else {
printf("Created container rootfs\n");
}
/* Start the container */
if (!c->start(c, 0, NULL)) {
fprintf(stderr, "Failed to start the container\n");
return 3;
} else {
printf("Started the container\n");
}
/* Query some information */
printf("Container state: %s\n", c->state(c));
printf("Container PID: %d\n", c->init_pid(c));
char *rootfs = c->get_running_config_item(c, "lxc.rootfs");
printf("Container rootfs: %s\n", rootfs);
// Set up mount point directory
const char *mount_relative_dir = "/mount_test";
size_t rootfs_path_size = strlen(rootfs);
size_t relative_dir_size = strlen(mount_relative_dir);
char mount_dir[rootfs_path_size + relative_dir_size + 1];
strncpy(mount_dir, rootfs, rootfs_path_size + 1);
strcat(mount_dir, mount_relative_dir);
// Create the mount point directory
int dir_status = mkdir(mount_dir, S_IRWXU);
if (dir_status == -1) {
fprintf(stderr, "Failed to create directory %s, error: %s\n", mount_dir, strerror(errno));
}
printf("Going to mount into: %s\n", mount_dir);
if (mount(".", mount_dir, NULL, MS_BIND, NULL) == -1) {
fprintf(stderr, "Failed to mount ./ into %s\n", mount_dir);
do_unmount(mount_dir);
return 4;
}
printf("Going to re-mount %s read-only\n", mount_dir);
if (mount(NULL, mount_dir, NULL, MS_BIND | MS_REMOUNT | MS_RDONLY, NULL) == -1) {
fprintf(stderr, "Failed to re-mount %s read-only\n", mount_dir);
do_unmount(mount_dir);
return 5;
}
/* Check the mount point from within the container */
system("lxc-attach -n apicontainer -- /bin/ls -ahl /");
system("lxc-attach -n apicontainer -- /bin/mount");
/* We are done with the mount stuff now */
do_unmount(mount_dir);
/* Has to be freed, allocated by LXC */
free(rootfs);
printf("Stopping the container\n");
/* Stop the container */
if (!c->shutdown(c, 30)) {
printf("Failed to cleanly shutdown the container, forcing.\n");
if (!c->stop(c)) {
fprintf(stderr, "Failed to kill the container.\n");
return 6;
}
}
printf("Destroying the container\n");
/* Destroy the container */
if (!c->destroy(c)) {
fprintf(stderr, "Failed to destroy the container.\n");
return 7;
}
return 0;
}
int main(int argc, char **argv) {
struct lxc_container *c;
if(argc < 2) {
printf("Usage: %s <source> \n", argv[0]);
return 1;
}
/* Setup container struct */
c = lxc_container_new("apicontainer", NULL);
if (!c) {
fprintf(stderr, "Failed to setup lxc_container struct\n");
} else {
printf("Created lxc_container struct\n");
}
char *source_dir = argv[1];
int status = container_test(c, source_dir);
if(status != 0) {
fprintf(stderr, "*** Container test FAILED with status %i ***\n", status);
}
lxc_container_put(c);
}
运行示例
为了便于阅读,我添加了一些换行符和注释。
➜ mount-test git:(master) ✗ gcc -o mount-test -llxc -g main.c
➜ mount-test git:(master) ✗ sudo ./mount-test ./
Created lxc_container struct
Container now exists, good
Created container rootfs
Started the container
Container state: RUNNING
Container PID: 27763
Container rootfs: /var/lib/lxc/apicontainer/rootfs
Going to mount into: /var/lib/lxc/apicontainer/rootfs/mount_test
Going to re-mount /var/lib/lxc/apicontainer/rootfs/mount_test read-only
容器内 ls -ahl / 的输出
total 60
drwxr-xr-x 18 root root 4.0K Jun 30 10:55 .
drwxr-xr-x 18 root root 4.0K Jun 30 10:55 ..
drwxr-xr-x 2 root root 4.0K Jun 30 10:55 bin
drwxr-xr-x 3 root root 340 Jun 30 10:55 dev
drwxr-xr-x 3 root root 4.0K Jun 30 10:55 etc
drwxr-xr-x 2 root root 4.0K Jun 30 10:55 home
drwxr-xr-x 25 root root 4.0K Jun 8 18:26 lib
drwxr-xr-x 2 root root 4.0K May 31 08:42 lib64
drwxr-xr-x 2 root root 4.0K Jun 30 10:55 mnt
drwxr-xr-x 2 1000 1000 4.0K Jun 30 10:55 mount_test
dr-xr-xr-x 300 root root 0 Jun 30 10:55 proc
drwxr-xr-x 2 root root 4.0K Jun 30 10:55 root
drwxr-xr-x 2 root root 4.0K Jun 30 10:55 sbin
drwxr-xr-x 2 root root 4.0K Jun 30 10:55 selinux
dr-xr-xr-x 13 root root 0 Jun 30 10:55 sys
drwxr-xr-x 2 root root 4.0K Jun 30 10:55 tmp
drwxr-xr-x 7 root root 4.0K Jun 30 10:55 usr
drwxr-xr-x 3 root root 4.0K Jun 30 10:55 var
容器内 /bin/mount 的输出
/dev/md0 on / type ext4 (rw,relatime,errors=remount-ro,stripe=256,data=ordered)
*snip*
/dev/md0 on /mount_test type ext4 (rw,relatime,errors=remount-ro,stripe=256,data=ordered)
Un-mounting /var/lib/lxc/apicontainer/rootfs/mount_test
Stopping the container
Destroying the container
所以挂载成功了,但如上所示,它仍然显示rw
在容器中。但是,它在我的主机系统中显示为只读。
半解决方案
我知道如果需要,我当然可以从容器内部重新挂载挂载点,但出于安全原因,我宁愿让容器用户没有挂载权限(否则用户可以将现有的只读挂载重新挂载到 rw 和修改主机上的文件)