파티션의 하위 디렉터리에서 Linux 시스템을 부팅하시겠습니까?

파티션의 하위 디렉터리에서 Linux 시스템을 부팅하시겠습니까?

동일한 파일 시스템에 여러 개의 Linux를 설치하도록 컴퓨터를 설정하고 싶습니다. 예를 들어, 파일 시스템에는 /Ubuntu_Precise, /Ubuntu_Oneiric및 3개의 폴더가 있습니다 /Ubuntu_Natty.

(BTRFS와 하위 볼륨을 사용하여 이 작업을 수행할 수 있다는 것을 알고 있지만 속도를 위해 EXT4를 사용하고 싶습니다).

저는 BTRFS를 사용하여 다양한 배포판의 여러 설치를 설정했으며 이를 작동시킴으로써 Grub이 "비표준" 경로에서 vmlinuz 및 initrd 이미지를 부팅할 수 있다는 것을 알고 있습니다. 그런데 BTRFS를 할 때 rootflags=subvol=@<subvolume_name>파일 시스템에서 하위 볼륨을 /로 마운트하라고 커널에 지시하는 명령이 있었습니다. 파티션의 하위 폴더를 /로 바인드 마운트한 다음 부팅하도록 커널에 전달할 수 있는 매개 변수가 있습니까?

다른 부분에 있어서는 거의 비슷하다고 생각해요. /etc/fstab또한 BTRFS 하위 볼륨에 여러 개의 Linux가 설치된 시스템을 설정할 때부터 가상 머신에 배포판을 설치한 다음 rsync를 사용하여 마이그레이션하는 데 익숙했기 때문에 크게 걱정하지 않습니다 . 올바른 구성을 얻기 위해 수행해야 할 작업에 대해 올바른 구성이 무엇인지 찾으려고 노력하고 있습니다. 이 사실을 알게 되면 하위 폴더로 쉽게 마이그레이션하고 파일을 편집할 수 있을 것입니다.

나는 이미 가상화와 파티셔닝에 대해 알고 있지만 그것은 내가 원하는 것이 아닙니다. 대상 컴퓨터에 가상화를 위한 충분한 전력이 없으며 파티션이 여유 공간을 공유하지 않습니다. Linux 배포판을 듀얼/트리플/쿼드/등 부팅하도록 시스템을 설정하려고 하는데 "여유 공간이 있지만 잘못된 파티션에 있습니다!"라는 문제가 발생하지 않도록 파일 시스템을 사용하여 수행합니다.

누구든지 내 질문이나 제목을 더 명확하게 편집하는 방법에 대한 제안이 있으면 귀를 기울일 것입니다.

답변1

짧은 대답 - 제가 아는 한 귀하의 특정 요구 사항에 맞는 즉시 작동하는 솔루션은 없습니다. 특정 요구 사항을 지원하려면 각 배포판의 각 initramfs를 조정해야 합니다.

긴 답변 - 예, 가능합니다. 오늘날 대부분의 Linux 배포판은 부트로더에 의해 메모리에 로드된 다음 커널에 의해 압축이 풀리는 initramfs를 사용합니다. 그곳에서 실행되어 /sbin/init초기 사용자 공간 설정(udev 실행, 모듈 로드, plymouth 시작, 암호화 비밀번호 요청, 네트워크 설치를 위한 네트워크 설정 등)을 담당합니다. 자체 스크립트를 실행하고 사용자 정의 시작 매개변수를 평가할 수 있기 때문입니다.

데비안 예

Debian을 사용하는 경우(Ubuntu와 동일해야 함) /etc/initramfs-tools/scripts/init-bottom/init가 시작되기 전에 실행될 스크립트를 배치할 수 있어야 합니다. 스크립트, 다양한 디렉토리 및 레이아웃에 대한 자세한 내용은 다음을 확인하세요.남자 initramfs-도구. rootmnt대상 디렉터리를 조정하고 추가해야 합니다 .

/etc/initramfs-tools/scripts/local-bottom/00-myroot예제(테스트되지 않은) 스크립트는 또는 다음 과 같이 설치되어야 합니다 /usr/share/initramfs-tools/scripts/init-top/00-myroot.

#!/bin/sh -e

PREREQS=""

prereqs() { echo "$PREREQS"; }

case "$1" in
  prereqs)
  prereqs
  exit 0
;;
esac

for opt in $(cat /proc/cmdline); do
  case $opt in
    rootdir=*)
      new_mntdir="${opt#rootdir=}"
      ;;
    esac
done

if [ -n "$new_mntdir" ] ; then
  echo rootmnt="$rootmnt/$new_mntdir" >> /conf/param.conf
fi

아이디어는 실제 init를 시작/실행하는 데 rootmnt 사용되는 initramfs 스크립트를 조정하는 것입니다. init루트 장치는 이미 init-bootom스테이지에 설치되어 있으므로 대상 디렉터리만 조정/변경하면 됩니다.

이 스크립트를 사용하려면 새 부팅 매개변수를 추가하고, 스크립트를 복사하고, 실행 가능하게 만든 다음, initramfs를 다시 빌드하고 Linux 배포판에 대한 부팅 매개변수(예: rootdir=/Ubuntu_Precise.

답변2

Ubuntu Focus&Bionic(그리고 아마도 다른 곳에서도)에서 작동하는 두 가지 방법은 다음과 같습니다. 의견을 제시할 담당자가 충분하지 않지만 bionic:/usr/share/initramfs-tools/init는 mountroot를 호출한 후 *-bottom 스크립트를 호출하기 전에 /etc/fstab에서 /usr을 찾습니다. 따라서 init-bottom을 추가합니다. (다른 답변에서 제안한 대로) 스크립트가 "너무 늦었습니다". 대신 다음을 권장합니다.

#!/bin/bash -f
#copyleft 2018 greg mott

#set a subdirectory as root (so multiple installs don't need partitions)
#these work in ubuntu bionic, might need tweaking to work elsewhere
#1st choice:  tweak initramfs-tools/scripts/local
#   pro:  $sub becomes root directly, nothing gets any chance to see the partition root
#   con:  requires the subdirectory's initramfs/initrd to be tweaked and rebuilt
#2nd choice:  specify this scriptfile as init= on the kernel commandline
#   pro:  no need to rebuild initramfs
#   con:  bin/bash in partition root must be executable by $sub/vmlinux (partition root older than $sub likely will work)
#   con:  if the partition root etc/fstab mounts /usr, the $sub initramfs will mount the partition root /usr
#   con:  additional initramfs scripts might also look in the partition root rather than $sub

#for either choice copy /etc/grub.d/40_custom to /etc/grub.d/07_custom and add one or more menuentries that specify subroot:
#menuentry "subroot foo" {
#     echo "subroot foo"
#              sub=/foo
#             uuid=22e7c84a-a416-43e9-ae9d-ee0119fc3894         #use your partition's uuid
#     search --no-floppy --fs-uuid --set=root $uuid
#            linux $sub/vmlinuz ro root=UUID=$uuid subroot=$sub
#     echo "initrd $sub/initrd.img"
#           initrd $sub/initrd.img      #works in recent releases where the /initrd.img softlink is relative
#}

#for the 2nd choice, in addition to subroot= on the kernel commandline also specify:
#   init=/path/to/script        #pathname from partition root to this scriptfile (chmod 744)

#for the 1st choice, the tweak for bionic:/usr/share/initramfs-tools/scripts/local is replace:
#          mount ${roflag} ${FSTYPE:+-t ${FSTYPE} }${ROOTFLAGS} ${ROOT} ${rootmnt}
#          mountroot_status="$?"
#with:
#          set -x
#          karg=" $(cat<proc/cmdline) " m=${karg#* subroot=}
#          [ "$m" = "$karg" ]||subroot=${m%% *}                                  #extract subroot from kernel commandline
#          [ $subroot ]&&part=part||part=$rootmnt                                #no subroot, just mount partition as root
#          mkdir part
#          mount ${roflag} ${FSTYPE:+-t ${FSTYPE} }${ROOTFLAGS} ${ROOT} $part&&  #mount partition
#             if [ "$subroot" ]
#             then mount --bind part/$subroot $rootmnt&&                         #mount subroot
#                  umount part                       #&&sleep 15                 #unmount partition root (uncomment &&sleep for time to watch)
#             fi
#          mountroot_status="$?"
#          [ $mountroot_status = 0 ]||sleep 90                                   #if error pause to see it
#          set +x
#once you've edited /usr/share/initramfs-tools/scripts/local, update-initramfs -u will rebuild for the current kernel,
#and it will automatically build into every new initrd/initramfs installed thereafter

subroot(){ karg=" $(cat<proc/cmdline) " m=${karg#* subroot=}
           [ "$m" = "$karg" ]||subroot=${m%% *}                 #extract subroot from kernel commandline
           [ $subroot ]||return 0                               #no subroot, just proceed in partition root
           while read -r m r m
           do for m in $M x                                     #build list of what's already mounted
              do    [[ $r = $m* ]]&&break                       #exclude subtrees (eg dev/**)
              done||[[ $r = /   ]]||M=$M\ $r                    #exclude /
           done<proc/mounts
           (set -x;mount --bind $subroot mnt)||{ set -x         #mount subroot
                                                 sleep 30          #if not found pause to see error
                                                 return 0;}        #then reincarnate as partition root init
           for m in $M
           do (set -x;mount -n --move $m mnt$m)||return         #move listed mounts to subroot
           done
           set -x
           cd           mnt&&
           pivot_root . mnt&&                                   #subroot becomes root
           umount -l    mnt&&                                   #unmount partition root
          #sleep 15        &&                                   #so far so good?  uncomment for time to look
           exec chroot . init "$@"                              #reincarnate as subroot init
}
subroot "$@"&&exec init "$@"||exec bash                         #land in a shell if moves or pivot fail

답변3

다른 목적으로 파티션 테이블을 건드리지 않고 다른 Linux를 부팅하는 것은 흥미로울 것입니다. 공유 파일 시스템을 위한 또 다른 해결책은 순환 볼륨을 사용하는 것입니다. 여기에 /debian 순환 파일/ 볼륨이 있다고 가정해 보겠습니다. /dev/sdb1 파일 시스템(메인 OS 및 루프 OS에 현재 GNU/Debian sid/unstable을 사용하고 있습니다).

/etc/grub.d/40_custom: # outside from loop volume
menuentry 'label' --class gnu-linux --class gnu --class os {
    ...
    loopback loop (hd2,msdos1)/debian
    linux   (loop)/boot/vmlinuz root=/dev/sdb1 loop=/debian ro
    initrd  (loop)/boot/initrd
}

Linux 명령줄로 grub에 정의된 매개변수는 initrd /init에 의해 env로 설정됩니다. 따라서 다음과 같습니다.

ROOT=/dev/sdb1
rootmnt=/root
loop=/debian 

루프를 사용하면 볼륨을 "자체적으로" 마운트할 수 있습니다. 기본 스크립트 흐름 실행에서는 mount /dev/sdb1 /root/dev/sdb1을 rw(ro인 경우)로 다시 마운트한 다음 항상 mount -o loop /root/debian /root.

/etc/initramfs-tools/scripts/local-bottom/loop: # inside the loop volume
#!/bin/sh

[ "$1" = "prereqs" ] && echo && exit 0

if [ -n "${loop}" ]; then
        if [ "${readonly}" = "y" ]; then
                roflag=-r
                mount -o remount,rw ${ROOT} ${rootmnt}
        else
                roflag=-w
        fi
        mount ${roflag} -o loop ${rootmnt}${loop} ${rootmnt}
fi

또한 일부 모듈을 initram에 미리 로드해야 합니다(그런 다음 update-initramfs를 실행하는 것을 잊지 마십시오).

/etc/initramfs-tools/modules: # inside the loop volume
...
loop
ext4

루프 사용이 성능이나 리소스 낭비에 얼마나 많은 영향을 미치는지 잘 모르겠지만 ext4 위에 ext4를 설치하면 파일 시스템 오류 가능성이 두 배로 높아지는지 궁금하지만 약간의 조정이 있을 수 있다고 추측합니다. 아마도 루프를 덜 해킹적으로 사용하는 더 좋은 방법이 있을 것입니다. 만약 있다면 아직 찾지 못했기 때문에 알려주시기 바랍니다.

답변4

이것은 답변은 아니지만 Ulrich의 답변과 의견에 대한 몇 가지 사항을 명확히하고 싶었습니다 (위에 언급할 수 없습니다).

Ulrich가 제안한 솔루션은 "작동할 수 있습니다"(아직 테스트되지 않음).파일 시스템을 다시 설치할 수 없습니다.. 해결 방법(IMHO 추악함)으로 chroot 전에 fs를 rw로 마운트할 수 있습니다(여기에 제안된 대로) 하지만 깨진 초기화 스크립트에 주의하세요. 이 해결 방법에는 더 많은 부작용이 있는 것 같습니다(예: 손상된 fs가 ro를 다시 설치하려고 시도하고 실패하는 것과 같은).

저는 ext4와 함께 커널 3.2를 사용하고 있으며 chroot 내부에 개발을 설치했지만 psusi가 언급한 대로 여전히 EBUSY를 제공합니다.

관련 정보