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


11

컴퓨터가 동일한 파일 시스템에 여러 개의 Linux 설치를 갖도록 컴퓨터를 설정하려고합니다. 예를 들어, 적 파일 시스템은 3 개 폴더를했을 : /Ubuntu_Precise, /Ubuntu_Oneiric,와 /Ubuntu_Natty.

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

나는 한 번 BTRFS를 사용하여 여러 배포판을 여러 번 설치했으며 그 작동을 통해 Grub이 vmlinuz와 initrd 이미지를 '비표준'경로로 부팅하면 잘 작동한다는 것을 알고 있습니다. 그러나 BTRFS 작업을 수행 할 때 rootflags=subvol=@<subvolume_name>커널이 파일 시스템에서 해당 하위 볼륨을 /로 마운트하도록 지시했습니다. 커널을 전달하여 파티션의 하위 폴더를 /로 마운트 한 다음 부팅하도록하는 인수가 있습니까?

나는 다른 부분을 생각한다. 나는 상당히 가깝다. 에서 바인드 마운트를 지정하는 방법을 알고 /etc/fstab있습니다. 또한 BTRFS 하위 볼륨에 여러 개의 Linux 설치로 시스템을 설정할 때 VM에 배포판을 설치 한 다음 rsync를 사용하여 마이그레이션하는 데 익숙하므로 수행해야 할 작업에 대해 너무 걱정하지 않습니다. 올바른 구성을 얻으려면 올바른 구성이 무엇인지 알아 내려고 노력하고 있습니다. 일단 알고 나면 하위 폴더로 마이그레이션하고 파일을 쉽게 편집 할 수 있어야합니다.

가상화 및 파티션에 대해 이미 알고 있지만 이것이 내가 원하는 것은 아닙니다. 대상 컴퓨터에 가상화를 수행 할 충분한 전원이없고 파티션이 여유 공간을 공유하지 않습니다. 듀얼 / 트리플 / 쿼드 / 등이 리눅스 배포판을 부팅하는 시스템을 설정하려고하는데, 하나의 파일 시스템으로이를 수행하므로 "사용 가능한 공간이 있지만 잘못된 파티션에 있습니다!"

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


1
시스템에 빌드 된 AFAIK가 없습니다. 아마도 여러분이해야 할 일은 init를 실행하기 전에 다른 bootparameter를 추가하고 initramfs를 수정하여 하위 디렉토리에 chroot하도록하는 것입니다
Ulrich Dangel

@UlrichDangel 그게 내가 제안하려고하는 것입니다. 답을 만드세요!
Nils

@ Nils ok 방금 답변을 제공했습니다. 패치 / 스크립트를 제공하고 싶지 않아서 처음에 하나를 작성하고 싶지 않았습니다
Ulrich Dangel

답변:


10

짧은 대답-특정 요구 사항에 대한 즉시 사용 가능한 솔루션은 없습니다. 특정 요구 사항을 지원하기 위해 각 배포판의 각 initramfs를 조정해야합니다.

긴 대답-가능합니다. 오늘날 대부분의 Linux 배포판은 부트 로더가 메모리에로드 한 다음 커널에 의해 압축을 해제하는 initramfs를 사용합니다. /sbin/init초기 사용자 공간 (udev 실행, 모듈로드, plymouth 시작, 암호 암호 요구, 네트워크 마운트를위한 네트워크 설정 등)을 담당하는 곳이 실행됩니다 ... 자신 만의 스크립트를 실행하고 사용자 정의 부팅 매개 변수를 평가할 수 있습니다.

데비안 예제

데비안을 사용하는 경우 (우분투와 동일해야 함) /etc/initramfs-tools/scripts/init-bottom/init가 시작되기 전에 실행될 스크립트를 배치 할 수 있어야합니다 . 스크립트에 대한 자세한 내용은 다른 디렉토리와 레이아웃에서 man initramfs-tools를 참조하십시오 . 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

아이디어는 rootmnt initramfs init스크립트 에서 사용되는 것을 조정 하여 실제 초기화를 시작 / 실행하는 것입니다. 루트 디바이스가 이미 init-bootom스테이지에 마운트되었으므로 대상 디렉토리를 조정 / 변경할 수 있습니다.

이 스크립트를 사용하려면 새 부팅 매개 변수를 추가하고 스크립트를 복사하여 실행 가능하게 만들고 initramfs를 재생성하고 Linux 배포를위한 부팅 매개 변수를 추가하십시오 (예 :) rootdir=/Ubuntu_Precise.


또한 실제 루트를 os 루트의 하위 디렉토리에 바인드하여 부팅 한 OS 파일에서 다른 OS 파일을 볼 수도 있습니다.
psusi

@psusi fstab을 통해이 작업을 수행하거나 mount /dev/rootdevice /mountpoint시스템이 실행 된 후 바로 수행 할 수 있습니다
Ulrich Dangel

언제 바뀌 었는지 궁금 하신가요? 동일한 블록 장치를 다시 마운트 할 수 없었습니다. 당신은 EBUSY를 얻을 것입니다.
psusi

1
@psusi 확실하지 않지만 아마도 바인드 마운트의 도입과 함께
Ulrich Dangel

@UlrichDangel (아주) 자세한 답변 감사합니다!
Azendale

3

우분투 바이오닉 (그리고 다른 곳에서)에서 작동하는 두 가지 방법이 있습니다. 의견을 말할 충분한 담당자가 없지만 bionic : / usr / share / initramfs-tools / init는 / etc / fstab에서 mountroot를 호출 한 직후와 * -bottom 스크립트를 호출하기 전에 / usr을 찾은 다음 init- 맨 아래 스크립트 (여기 다른 답변에서 제안 된 바와 같이)는 "너무 늦습니다". 대신 나는 이것을 추천한다 :

#!/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:  requires bin/bash in the partition root executable by $sub/vmlinux (ie $sub same or newer than partition root)
#   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

이것은 나를 위해 치료를했다
paultop6

1

파티션 테이블을 망치지 않고 다른 리눅스를 부팅하는 것은 다른 목적으로 흥미 롭습니다. 공유 파일 시스템의 대안은 루프 볼륨을 사용하는 것입니다. 여기서 / debian 루프 파일 / 볼륨이 / dev / sdb1 파일 시스템에 있다고 가정하면 몇 가지 변경 사항이 필요합니다. (저는 main 및 loop os 모두에 현재 GNU / Debian sid / stable을 사용하고 있습니다).

/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
}

리눅스 명령 행으로 grub에 정의 된 인자는 initrd / init에 의해 env로 설정됩니다 :

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

루프는 "자체"를 통해 볼륨을 마운트 할 수 있도록합니다. 기본 스크립트 흐름은 mount /dev/sdb1 /root/ dev / sdb1이 rw 인 경우 선택적으로 rw로 다시 마운트 한 다음 항상 a를 추가합니다 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를 마운트하면 파일 시스템 오류의 확률이 두 배가 될지 궁금하지만 일부 튠업을 수행 할 수 있다고 생각합니다. 어쩌면 내가 찾지 못했기 때문에 알려 주시면 루프를 사용하고 해 키시를 덜 사용하는 더 좋은 방법이 있습니다.


0

이것은 답변이 아니지만 Ulrich의 답변과 의견에 대해 명확하게 설명하고 싶습니다 (위에서 언급 할 수 없음).

Ulrich 솔루션은 "아마도"작동 할 것을 제안하지만 ( 그것이 아직 평가되지 않았지만) 다시 마운트 할 수 없는 파일 시스템을 얻게 됩니다. 해결 방법 (IMHO 추악한)으로 chroot하기 전에 fs를 rw로 마운트 할 수 있지만 ( 여기에서 제안한대로 ) init 스크립트가 깨지는 것을 조심 하십시오 . 이 해결 방법에 더 많은 부작용이 있다고 생각합니다 (예 : 깨진 fs ro를 다시 마운트하려고 시도하고 실패).

나는 ext4와 함께 커널 3.2를 사용하고 있으며 chroot 안에 이미 마운트 된 dev를 마운트하면 여전히 의사가 언급 한대로 EBUSY를 제공합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.