내 빌드 스크립트 중 일부에서는 스크립트가 종료될 때 마운트를 남기지 않고 마운트를 보호하기 위한 메커니즘으로 마운트 네임스페이스를 사용해 왔습니다. 네임스페이스의 마지막 프로세스가 종료되면 비공유 마운트 지점이 암시적으로 마운트 해제됩니다..
내 스크립트에는 일반적으로 다음과 같은 섹션이 포함됩니다.
#!/bin/bash
self_ns=$(ls -lh /proc/self/ns/mnt)
init_ns=$(ls -lh /proc/$PPID/ns/mnt)
if [ "${self_ns#*mnt:}" = "${init_ns#*mnt:}" ] ; then
unshare --mount $0 "$@"
exit $?
fi
이것은 한동안 잘 작동했지만 최근 Jenkins 빌드 서버에 문제가 발생했습니다.
문제는 빌드 스크립트 자체가젠킨스 chroot 환경. 따라서 스크립트가 실행되면 unshare --mount ...
다음 오류와 함께 실패합니다.
unshare: cannot change root filesystem propagation: Invalid argument
안타깝게도 저는 이 제한 사항이나 이를 해결하는 방법을 잘 이해하지 못합니다. 명령줄에서 chroot를 시도하면 이 오류를 재현할 수 없습니다. 젠킨스 플러그인이 이 문제를 일으키는 원인이 무엇인지 모르겠습니다.
가장 중요한 것은 이러한 마운트 지점이 종료 시 삭제된다는 것입니다.매번 어김없이.
답변1
AB의 의견을 바탕으로 해결 방법을 찾았습니다.
AB는 다음과 같이 썼습니다.
lxc mount 및
unshare --mount bash
.unshare --mount
이것이 무엇을 의미하는지 모르겠지만 이것이 원인이나 해결 방법(파이프라인에 바인드 마운트 추가)을 찾는 데 도움이 되기를 바랍니다.
이를 바탕으로 이것이 작동하지 않는다는 것을 발견했습니다.
unshare --mount bash -c 'echo hello'
하지만 이것은 작동합니다:
mount --bind --make-private / /mnt
chroot /mnt unshare --mount bash -c 'echo hello'
umount /mnt
답변2
문제의 원인은 unshare
마운트 지점에 대해서만 수행할 수 있는 루트 디렉토리에 대한 마운트 전파 플래그를 설정하려고 시도하는 것입니다. Jenkins chroot 환경의 루트 디렉터리는 마운트 지점이 아닙니다.
예를 들어:
$ unshare -rm mount --make-rprivate /opt
mount: /opt: not mount point or bad option.
완전 재현:
#!/bin/bash
try() {
mount -t tmpfs t /mnt
mkdir /mnt/t
for i in /bin /lib* /sbin /usr /home /proc
do
mkdir "/mnt/t$i"
mount --rbind "$i" "/mnt/t$i"
done
chroot /mnt/t unshare -m echo OK
}
export -f try
unshare -rm bash -c try
간단한 해결 방법은 마운트 네임스페이스 외부에 마운트되지 않는다는 것입니다. 마운트 전파를 설정하기 위해 chroot를 이스케이프하고 chroot 외부에서 mount 명령을 사용할 수 있다고 가정합니다.
unshare --propagation unchanged -m sh -c \
'nsenter --mount=/proc/self/ns/mnt mount --make-rslave /; echo Do some mounts'
pivot_root
또는 chroot를 환경 으로 변환하십시오 .
#define _GNU_SOURCE
#include <errno.h>
#include <error.h>
#include <fcntl.h>
#include <sched.h>
#include <stdio.h>
#include <sys/mount.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <unistd.h>
static int pivot_root(const char *new_root, const char *put_old){
return syscall(SYS_pivot_root, new_root, put_old);
}
int main(int argc, char **argv) {
if (unshare(CLONE_NEWNS))
error(1, errno, "unshare");
int root = open("/", O_DIRECTORY | O_PATH | O_CLOEXEC);
if (root < 0) error(1, errno, "open /");
int ns = open("/proc/self/ns/mnt", O_RDONLY | O_CLOEXEC);
if (ns < 0) error(1, errno, "open mount namespace");
if (setns(ns, CLONE_NEWNS))
error(1, errno, "setns");
if (fchdir(root))
error(1, errno, "fchdir");
if (mount("/", "/", 0, MS_REC|MS_SLAVE, 0))
error(1, errno, "mount --make-rslave");
if (mount(".", "proc", 0, MS_REC|MS_BIND, 0))
error(1, errno, "mount --rbind");
if (chdir("proc"))
error(1, errno, "chdir");
if (pivot_root(".", "proc"))
error(1, errno, "pivot_root");
if (umount2("proc", MNT_DETACH))
error(1, errno, "umount");
execvp(argv[1], argv + 1);
error(1, errno, "exec");
}