Могу ли я смонтировать файловую систему только для чтения в контейнер LXC?
Я работаю над программным обеспечением, созданным поверх LXC. Помимо прочего, мы хотим монтировать папки с хоста в контейнер LXC во время выполнения, поэтому мы не можем поместить наши точки монтирования в нашу lxc.conf
(что мы делаем для статических точек монтирования).
Во время монтажа повторная установка только для чтения не работает. Повторное монтирование успешно выполняется на хосте, но точка монтирования по-прежнему отображается как чтение / запись в контейнере.
Пример программы
Я создал небольшую программу, расширяющую пример API LXC ( 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 и изменить файлы на хосте)