1

我正在开发基于 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 和修改主机上的文件)

4

0 回答 0