LinuxヘッドレスLiveBoot(CentOS編)

本稿は前稿の CentOS版だ。要件定義はおよそ同じだが、LiveBootの実現方法の違いにより、構築手順は大きく異なる。


    要件定義

    1. 対象機は x86_64(amd64)とする。
    2. VGAデバイスは物理的に搭載されていない。GUIも使用しない。よって起動する CentOSはコンソールベースとする。
    3. BIOSコンソールリダイレクト機能は対象機材でサポートされているものとする。
    4. シリアルコンソールは baud=115.2kで接続する。1
    5. 成果物は ISOイメージとし、CD-R/DVD-Rに焼いて USB-ODDブート(USB光学ドライブ起動)できるものとする。通常は、再起動毎にあらゆる設定や痕跡は完全に忘却される。
    6. 他の Linuxマシンを必要とすることなく、一般的な Windowsマシンから既成の USBインストーラを用いて、USBフラッシュドライブに変換できるものとする。この際 persistent領域を設定できなければならない。
    7. yum一式を備えている。追加したパッケージや設定は、persistent有効時は維持される。
    8. 既定のログインユーザ名は liveuser とし、パスワードも無しとする。ゆえにパスワード無しで sudoできるものとする。(一般的な LiveBootの流儀)
    9. 既定のネットワーク設定・接続はオフとする。
    10. これらのパスワードやネットワーク設定は persistent有効時には自由に設定変更して永続化することができ、再起動しても設定内容が失われてはならない。

    以後は CentOS-7-x86_64-LiveCD-1503.iso をベースにして話を進める。32bit版や CentOS-6でも同様の手順で構築できる。2

    Ubuntuでは最終的な rootfsを作るのにオンメモリ(2GiB程度)で作業できたが、CentOS用の rootfsを作成するには作業領域が足りないため、起動用 USBメモリの他に Ext4でフォーマットできるフラッシュドライブや HDDを別途用意しなければならない。なお最終的に出来上がるブータブルイメージは CD-Rに充分格納できるサイズ(640MiB以下)になる。

    なお製作時のリファレンス機材には Riava RS670A を使用した。3


    シリアルコンソール対応のインストーラUSBメモリを作る

    まずヘッドレス環境で使用できる CentOSインストーラを LiveCD ISOイメージから作成する。Windows上でこれを行うには Fedora LiveUSB Creator4を使用する。

    次に起動メニューを書き換える。LiveUSB Creatorが作成したベースファイルからの相違点はシリアルコンソール設定の追加が主だ。

    #serial 0 115200
    #console 0
    
    default vesamenu.c32  
    timeout 100  
    menu background  
    menu autoboot Starting CentOS Linux 7 in # second{,s}. Press any key to interrupt.
    
    menu clear  
    menu title CentOS Linux 7  
    menu vshift 4  
    menu rows 12  
    menu margin 8  
    menu helpmsgrow 15  
    menu tabmsgrow 13
    
    menu tabmsg Press Tab for full configuration options on menu items.  
    menu separator  
    menu separator  
    label linux0  
      menu label ^Start CentOS Linux 7 Live
      kernel vmlinuz0
      append initrd=initrd0.img root=live:CDLABEL=LIVE rootfstype=vfat ro rd.live.image quiet rd.luks=0 rd.md=0 rd.dm=0 console=tty0 console=ttyS0,115200n8
      menu default
    menu separator  
    menu begin ^Troubleshooting  
      menu title Troubleshooting
    label check0  
      menu label ^Test this media & start CentOS Linux 7 Live
      kernel vmlinuz0
      append initrd=initrd0.img root=live:CDLABEL=LIVE rootfstype=vfat ro rd.live.image quiet rd.luks=0 rd.md=0 rd.dm=0 rd.live.check console=tty0 console=ttyS0,115200n8
    menu separator  
    label local  
      menu label Boot from ^local drive
      localboot 0xffff
    menu separator  
    label returntomain  
      menu label Return to ^main menu.
      menu exit
    menu end  
    

    このフラッシュドライブで、Troubleshootingサブメニュー内の Test this media & start CentOS Linux 7 Live を選んで起動しよう。しばらく待っているとログインプロンプトが出現する。ここからは root[ENTER]で rootシェルに入ることが出来る。


    rootfsを作成する

    この時点で NetworkManager は起動しているので DHCPでのIP取得は既に済んでいるだろう。作業に必要なパッケージを yumで追加する。

    LANG=C  
    yum install -y squashfs-tools  
    

    作業用の追加ドライブを接続してパーテションをフォーマットし、/mntにマウントしてそこに移動する。ここでは /dev/sdb1とする。

    mkfs.ext4 /dev/sdb1  
    mount /dev/sdb1 /mnt  
    cd /mnt  
    

    起動時のフラッシュドライブは /run/initramfs/liveに ReadOnlyでマウントされているので、これを rwオプションでリマウントして書き換え可能にする。

    mount -o rw,remount /run/initramfs/live  
    cd /run/initramfs/live  
    

    現在起動している rootfsの実体は /run/initramfs/live/LiveOS/squashfs.imgだ。このファイルを差し替えるのが最終目的だが、これは LiveOS/ext3fs.imgという loopbackファイルを squashfsで圧縮した構造になっている。そこでこれを以下のようにして再現する。rootfs容量はここでは8GiBとするが、適宜任意のサイズに変えても良い。

    mkdir -p squashfs-root/LiveOS  
    truncate -s $((2**33)) squashfs-root/LiveOS/ext3fs.img  
    mkfs.ext4 -L _CentOS-7-livecd squashfs-root/LiveOS/ext3fs.img  
    

    このファイルを loopbackマウントして /mnt/chrootでアクセスできるようにする。

    mkdir /mnt/chroot  
    mount -o loop squashfs-root/LiveOS/ext3fs.img /mnt/chroot/  
    

    後は yumのグループインストールコマンド一発で、任意の新しい rootfs環境が構築できる。

    yum --installroot=/mnt/chroot --releasever=7 -y groupinstall Core  
    

    releaseverオプションに指定する CentOSのバージョンは、/etc/os-releaseファイルを参照すると良い。


    rootfsの環境設定

    まず各システム領域を chroot内に bindマウントする。そしてダミーの /etc/fstab(中身は空でも良い)を作成しておく。

    mount -o bind /dev/ chroot/dev/  
    mount -o bind /proc/ chroot/proc/  
    mount -o bind /tmp/ chroot/tmp/  
    mount -o bind /run/ chroot/run/  
    touch chroot/etc/fstab  
    

    initramfsの構築設定ファイルを追加する。これは LiveBoot可能な initramfsを作成するのに必須の設定だ。

    hostonly="no"  
    add_dracutmodules+="dmsquash-live"  
    compress="xz"  
    

    現在起動している LiveCDシステムの、livesysサービスファイルを chroot内にコピーしてサービス登録する。このサービスは初回起動時に liveuserアカウントの作成や rootパスワードの削除処理を行うようになっている。5

    cp -p /etc/init.d/livesys* chroot/etc/init.d/  
    chroot chroot/ chkconfig --add livesys  
    chroot chroot/ chkconfig --add livesys-late  
    

    タイムゾーンとロケール情報を設定し、NetworkManagerが初回起動時は起動しないように修正する。

    ln -sf ../usr/share/zoneinfo/Asia/Tokyo chroot/etc/localtime
    
    echo "LANG=en_US.utf8" > chroot/etc/locale.conf
    
    chroot chroot /usr/bin/systemctl disable NetworkManager  
    

    Linux kernelモジュールの組み込み

    kernelと、その他の追加パッケージをインストールする。

    yum --installroot=/mnt/chroot -y install kernel squashfs-tools dump isomd5sum epel-release  
    

    kernelと作成された initramfsを、フラッシュドライブに移動する。rescue関係のファイルは必要ないので削除する。

    rm -f chroot/boot/*rescue*  
    mv chroot/boot/vmlinuz-* /run/initramfs/live/syslinux/vmlinuz0.new  
    mv chroot/boot/initramfs-* /run/initramfs/live/syslinux/initrd0.img.new  
    

    最後にクリーンアップを行ってアンマウントする。rootfsの umount後は fsckで損傷がないかチェックする。

    yum --installroot=/mnt/chroot clean all  
    find chroot/var/log -type f -exec /bin/truncate -s0 {} \;  
    umount chroot/proc/  
    umount chroot/dev/  
    umount chroot/run/  
    umount chroot/tmp/
    
    du -sh chroot/  
    720M    chroot/
    
    umount chroot/  
    fsck.ext4 squashfs-root/LiveOS/ext3fs.img  
    

    squashfs.img ファイルの作成

    こうして出来た rootfsを mksquashfsで圧縮すれば、LiveBoot可能な新しいシステムファイルになる。ただし Ext4フォーマットした loopbackファイルをそのまま圧縮するため、インストール過程で生じた削除ファイルの痕跡などもそのまま残っていて圧縮率が低下してしまう。

    mksquashfs squashfs-root squashfs.img.new
    
    ls -lh squashfs.img.new  
    -rw-r--r--. 1 root root 474M Jun 24 08:21 squashfs.img.new
    

    これを可能な限り取り除いて圧縮するには、dump/restoreコマンドを経由してファイルシステムを完全に作り直すとよい。ただし dumpコマンドはブロックデバイスしか扱えないので、losetupコマンドを用いて /dev/loopX に loopbackファイルをバインドして指定する。手順は面倒だが、比較するとその効果は絶大だ。

    mv squashfs.img.new squashfs.img.nev
    
    yum install -y dump
    
    loopdev=$(losetup -f)  
    losetup $loopdev squashfs-root/LiveOS/ext3fs.img  
    dump -0z9 -f rootdump $loopdev  
    losetup -d $loopdev
    
    ls -lh rootdump  
    -rw-r--r--. 1 root root 277M Jun 24 08:30 rootdump
    
    rm -f squashfs-root/LiveOS/ext3fs.img  
    truncate -s $((2**33)) squashfs-root/LiveOS/ext3fs.img  
    mkfs.ext4 -L _CentOS-7-livecd squashfs-root/LiveOS/ext3fs.img
    
    mount -o loop squashfs-root/LiveOS/ext3fs.img chroot  
    (cd chroot/; restore -r -f ../rootdump)
    rm -fr chroot/lost+found restoresymtable  
    umount chroot
    
    fsck.ext4 squashfs-root/LiveOS/ext3fs.img  
    mksquashfs squashfs-root squashfs.img.new
    
    ls -lh squashfs.img.ne?  
    -rw-r--r--. 1 root root 474M Jun 24 08:21 squashfs.img.nev
    -rw-r--r--. 1 root root 250M Jun 24 08:38 squashfs.img.new
    
    cp squashfs.img.new /run/initramfs/live/LiveOS/  
    

    新 rootfsでの起動テスト

    こうして作成した rootfsファイルをブートUSBメモリにコピーして shutdownし、Windows(あるいは他のLinux機)で以下の起動用ファイルを差し替える。

    • vmlinuz0.new を syslinux/vmlinuz0 へ
    • initrd0.img.new を syslinux/initrd0.img へ
    • squashfs.img.new を LiveOS/squashfs.img へ

    syslinux/syslinux.cfg は前述のそのままでよいが、今度の起動は通常の Start CentOS Linuxラベルを選択する。ログイン・プロンプトは rootで直接、あるいは liveuser(いずれもパスワード無し)でシェルに入れる。liveuserアカウントは sudoで rootアカウントになれる。

    NetworkManagerは停止状態なので、ネットワークに接続するには dhclientで Link Upするか、nmcli/nmtuiでインタフェース設定を行って NetworkManagerを起動する。

    sudo -s
    
    systemctl enable NetworkManager  
    systemctl start NetworkManager
    
    nmcli connection modify enp2s0 ipv4.method manual ipv4.addresses 192.168.240.101/24 ipv4.gateway 192.168.240.1 ipv4.dns 8.8.8.8
    
    systemctl restart network.service
    
    # cat /etc/sysconfig/network-scripts/ifcfg-enp2s0
    

    ISOイメージを作成する

    元の ISOの squashfs.img等を差し替えた、新しいISOイメージを作成する。まず作業に必要なパッケージをインストールし、作業領域に ISO内のファイルを展開して ReadOnlyを外す。

    mount /dev/sdb1 /mnt  
    cd /mnt
    
    # install mkisofs tools
    yum install -y mkisofs isomd5sum
    
    # mount image: CentOS-7-x86_64-LiveCD-1503.iso
    mkdir loop  
    mount /dev/cdrom loop
    
    # copy iso files and modify attributes
    cp -rf loop files  
    chmod -R +w files/  
    umount loop  
    

    フラッシュドライブから先に作成した新しいシステムファイルをコピーする。このときフラッシュドライブ上では /syslinuxに vmlinuz0と initrd0.img ファイルが置かれているが、ISOイメージでは /isolinuxディレクトリになる。6

    # copy kernel and filesystem
    cp -f /run/initramfs/live/syslinux/vmlinuz0 files/isolinux/  
    cp -f /run/initramfs/live/syslinux/initrd0.img files/isolinux/  
    cp -f /run/initramfs/live/LiveOS/squashfs.img files/LiveOS/  
    

    files/isolinux/isolinux.cfg をシリアルコンソール対応に修正する。最初のシリアルポート設定は BIOSコンソールリダイレクトの有無による。また先に作成した rootfsは SELinuxをサポートするように構築してはいないので、これを無効にする。isolinux/mt86plusについては標準では存在しないが、これについては別稿を参照されたい。

    #serial 0 115200
    #console 0
    
    default vesamenu.c32  
    timeout 100  
    menu background  
    menu autoboot Starting CentOS Linux 7 in # second{,s}. Press any key to interrupt.
    
    menu clear  
    menu title CentOS Linux 7  
    menu vshift 4  
    menu rows 12  
    menu margin 8  
    #menu hidden
    menu helpmsgrow 15  
    menu tabmsgrow 13
    
    menu tabmsg Press Tab for full configuration options on menu items.  
    menu separator  
    menu separator  
    label linux0  
      menu label ^Start CentOS Linux 7 Live
      kernel vmlinuz0
      append initrd=initrd0.img root=live:CDLABEL=CentOS7-liveboot rootfstype=auto ro rd.live.image quiet rd.luks=0 rd.md=0 rd.dm=0 selinux=0 console=tty0 console=ttyS0,115200n8
      menu default
    menu separator  
    menu begin ^Troubleshooting  
      menu title Troubleshooting
    label check0  
      menu label ^Test this media & start CentOS Linux 7 1503 Live
      kernel vmlinuz0
      append initrd=initrd0.img root=live:CDLABEL=CentOS7-liveboot rootfstype=auto ro rd.live.image quiet rd.luks=0 rd.md=0 rd.dm=0 rd.live.check selinux=0 console=tty0 console=ttyS0,115200n8 
    label memtest  
      menu label Test ^memory
      kernel mt86plus
      append console=ttyS0,115200n8
    menu separator  
    label local  
      menu label Boot from ^local drive
      localboot 0xffff
    menu separator  
    label returntomain  
      menu label Return to ^main menu.
      menu exit
    

    mkisofsコマンドで ISOイメージを作成する。ここではもっともシンプルなオプション構成として GRUB(gfxboot)や EFI対応、Macintosh対応は行ってはいない。注意が必要なのは -Vオプションに渡すCDラベルで、これは kernel起動オプションに記述したのと同じものでなければならない。またこのラベルは最大16文字なのでこれを超えないようにしよう。

    find ./files -print | xargs touch -m {} \;  
    LANG=C mkisofs -r -J -l \  
      -V CentOS7-liveboot \
      -cache-inodes \
      -b isolinux/isolinux.bin \n
      -c isolinux/boot.cat \
      -no-emul-boot \
      -boot-load-size 4 \
      -boot-info-table \
      -o CentOS7-liveboot.iso \
      ./files
    

    こうして出来た ISOイメージに、それ自体の改竄検出 MD5チェックサムを implantisomd5コマンドで埋め込む。Ubuntuではファイル単位で MD5をチェックしていたが、CentOSではメディアそのものをチェックする。従ってフラッシュドライブではこの仕組は動かない。一方で CD-R等に焼いた際に Write Errorが有っても、メディアの完全性を確認することが出来る。7

    LANG=C implantisomd5 CentOS7-liveboot.iso  
    

    改竄チェックは checkisomd5コマンドで行える。引数には調べたい ISOファイルか、メディアを挿れた ODDのデバイスファイルを指定すればよい。なお implantisomd5と checkisomd5コマンドは、isomd5sumパッケージに含まれている。8

    checkisomd5 CentOS7-liveboot.iso  
    checkisomd5 /dev/cdrom  
    

    CD-RW/DVD-RWに ISOイメージを焼く

    光学メディアへのライティングは、Ubuntuとおなじく wodimコマンドで行える。

    yum install -y wodim
    
    # erase CD/DVD-RW media
    wodim dev=/dev/sr0 blank=fast
    
    # writing image
    wodim -sao -eject dev=/dev/sr0 CentOS7-liveboot.iso
    
    # check image
    checkisomd5 /dev/sr0  
    

    こうして作成した光学メディアで ODDブートが正常に行えたら、Test this media & start CentOSラベルで起動してみよう。検査が正常に終了するとログイン・プロンプトに進み、失敗した場合は System Haltするはずだ。9


    persistentモードを設定する

    前述の ISOイメージ/光学メディアで ODDブートが正常に行えたなら、次はその ISOイメージを Live USB Creatorでもって、今度は persistent領域を設定したフラッシュドライブを作成しよう。

    persistentモードは kernelオプションの rd.live.overlay=LABEL=LIVEによって有効になる。initramfsは指定された LABELを blkidコマンドで探し、これを /run/initramfs/live/にマウントする。persistent領域ファイルは LiveOSディレクトリ内の overlay-${LABEL}-${UUID}というファイル名で探して、Device Mapperによって snapshotとして /に結合される。これ自体は初期状態では(ファイルシステムではないので)単なる Zero Fillファイルである。

    blkid -L LIVE  
    /dev/sda1
    
    blkid /dev/sda1  
    /dev/sda1: LABEL="LIVE" UUID="0621-6D9B" TYPE="vfat" 
    
    ls -l /run/initramfs/live/LiveOS/  
    total 1299100  
    -rwxr-xr-x 1 root root      20480 Jun 26 05:26 osmin.img
    -rwxr-xr-x 1 root root 1068498944 Jun 30 12:32 overlay-LIVE-0621-6D9B
    -rwxr-xr-x 1 root root  261758976 Jun 30 08:26 squashfs.img
    

    Ubuntuと異なり、Device Mapperを使用しているためもあって実際にあとどの程度データが書き込めるか(保存できるか)は dfコマンドでは判断することができない。dmsetupコマンドの statusサブコマンドで、live-rwボリュームの snapshot消費ブロック数(512byte単位)を知ることはできるから、これを利用するしかない。

    dmsetup status live-rw  
    0 16777216 snapshot 14960/2086912 72
    
    echo | awk '{print 14960/2086912}'  
    0.00716849  
    

    また Ubuntuの場合は、persistentファイルは overlayfsで重ねられた独立したファイルシステムであったから、非起動状態のフラッシュドライブから persistent領域内のファイルを抜き出すことは容易だったが、CentOSではこれは容易なことではない。

    (現在起動しているのとは別の)フラッシュドライブ内の persistent領域にアクセスするには、以下のようにする。

    ## 作業領域の準備
    
    cd /mnt  
    mkdir media squash rootfs
    
    ## フラッシュドライブを作業領域にマウントし、その中の squashfs.imgをマウントする
    
    mount /dev/sdc1 media  
    mount -o loop media/LiveOS/squashfs.img squash
    
    ## ext3fs.img(readonly)と overlayファイルに loopbackデバイスを割り当てる
    ## 空きデバイス名は losetup -fで得られる
    
    losetup -f  
    /dev/loop6
    
    losetup /dev/loop6 squash/LiveOS/ext3fs.img -r  
    losetup /dev/loop7 edia/LiveOS/overlay-LIVE-0621-6D9B
    
    ## ふたつのデバイスを束ねて rootfsを再生する
    
    blockdev -q --getsz /dev/loop6  
    16777216
    
    dmsetup create live-rootfs --table "0 16777216 snapshot /dev/loop6 /dev/loop7 P 8"
    
    dmsetup status live-rootfs  
    0 16777216 snapshot 17312/2086912 80
    
    ## あとはfsckしたり・・・
    
    fsck -f -y /dev/mapper/live-rootfs
    
    ## dumpしたり・・・
    ## (squashfs.img作成以後分だけを抜き出すのに /etc/dumpdatesを利用する例)
    
    echo "/dev/mapper/live-rootfs 0 $(LANG=C \  
      date +"%a %b %d %X %z" \
        -r media/syslinux/ldlinux.sys)" >> /etc/dumpdates
    dump -u1z9 /dev/mapper/live-rootfs -f rootfsdump
    
    ## mountしたり・・・
    
    mount /dev/mapper/live-rootfs rootfs  
    ls -a rootfs/home/liveuser
    
    ## 作業を終えたら後始末してフラッシュドライブを切り離す
    
    umount rootfs  
    dmsetup remove live-rootfs  
    losetup -d /dev/loop6  
    losetup -d /dev/loop7  
    umount squash  
    umount media  
    rmdir media squash rootfs  
    

    /homeや swapパーテションを設定する

    /etc/init.d/livesysを覗いてみると解る10が、フラッシュドライブの /LiveOSディレクトリに、home.imgファイルがあれば /homeに、swap.imgファイルが有れば swapに、それぞれ自動的にマウントするようになっている。これらのボリュームファイルは以下のようにセットアップする。

    ## persistentオフの場合はフラッシュドライブを rwリマウントする 
    mount -o rw,remount /run/initramfs/live
    
    ## 保存領域へcd
    cd /run/initramfs/live/LiveOS
    
    ## home.img ボリュームの作成(サイズは適宜)
    truncate -s $((2**31)) home.img  
    mkfs.ext4 -L "home-vol" home.img
    
    ## swap.img ボリュームの作成(サイズは適宜)
    truncate -s $((2**31)) swap.img  
    mkswap -L "swap-vol" swap.img
    
    ## あとは特に設定変更もなく再起動するだけ
    sync;sync;sync  
    reboot
    
    ## homeボリュームの有無は losetupで確認できる
    ## 容量は dfコマンドで把握可能
    losetup  
    NAME       SIZELIMIT OFFSET AUTOCLEAR RO BACK-FILE  
    /dev/loop0         0      0         0  1 /osmin.img (deleted)
    /dev/loop1         0      0         0  1 /osmin
    /dev/loop2         0      0         0  1 /run/initramfs/live/LiveOS/squashfs.img
    /dev/loop3         0      0         0  1 /LiveOS/ext3fs.img
    /dev/loop4         0      0         0  0 /LiveOS/overlay-LIVE-748B-70C6
    /dev/loop5         0      0         0  0 /run/initramfs/live/LiveOS/home.img
    
    ## swapは freeコマンドで容量が確認できる
    free  
                  total        used        free      shared  buff/cache   available
    Mem:        8162140      178452     7610852       16720      372836     7767880  
    Swap:        262136           0      262136
    

    ダウンロード

    CentOS7-liveboot-20150703.iso 313MiB (md5sum)


    1. USBシリアル変換は FTDI系を前提にしている。PL2303系(特にノーブランドのコピー品)は baud=115.2kではFIFOバッファが足りずに通信不具合が多発してトラブルのもとになる。

    2. centos.org

    3. Riava RS670A 基本スペックは Intel Gigabit NICx6を持つ Intel/Atom C2758 でメモリ8GiB。基本OSは CentOSまたはUbuntu。SSD内蔵だがこれはここでは使用しない(壊さない)。なおフロントパネルのシリアルコンソールポート(COM0)はCisco互換配線(Yost Serial Device Wiring Standard)になっている。

    4. Fedora LiveUSB Creator

    5. persistentモードで初期化済フラグファイルが書けるようになると、これらの初期化処理はスキップされるようになる。

    6. Fedora LiveUSB Creatorが、ISOイメージ中の /isolinux を /syslinux へコンバートしている。

    7. Ubuntuでは USBメモリでも一応改竄チェックが可能だが、ISOイメージ中のブートセクタといった非ファイル領域に生じたライティングエラーを検出できない。

    8. Dracutは、isomd5sumパッケージがインストール済なら initramfsを作成する際にこれを組み込む。initramfsに組み込まれていない場合、rd.live.checkオプションによるメディア検査は正しく実行できない。

    9. Test this media & start CentOSは光学メディア起動時は chkisomd5が走り、検査に成功しなければログイン・プロンプトに達しないが、USBメモリ起動時はメディア自体が検査不能なので、そのまま進んでログイン・プロンプトに達することができる。

    10. 物理パーテションを /homeにしたり、暗号化したりする起動オプションもある。

    RECENT LINKS