Network Manager と仲良くなれないやら modprobe.conf がなくなったやら諸々の悩みを解決するお手伝いをいたします。(この記事は、不定期にアップデートする予定です。)
Red Hat 公式ガイドはこちらを参照
※ RHEL5もまだまだ現役という貴兄には、プロのためのLinuxシステム構築・運用技術もよろしくお願いします。
システムコンソールの切り替え
Ctrl + Alt + F1 が X Window になってます。コンソールでテキストログインしたい時は、Ctrl + Alt + F2 〜 F6 を使います。
NetworkManager
デフォルトで NetworkManager サービスが起動するため /etc/sysconfig/network-scripts/ifcfg-XXX の書式が従来と変わっています。
従来の書式で設定ファイルを書く場合は、設定ファイルに下記の1行を追加します。
NM_CONTROLLED=no
もしくは NetworkManager サービスを停止します。
# chkconfig NetworkManager off # service NetworkManager stop
特に KVM 環境で Bridge デバイスを作る場合は、NetworkManager を使用することができませんので、サーバ環境では NetworkManager サービスを止めておくのがよいと思います。
ethX と MAC Address の紐付け
/etc/udev/rules.d/70-persistent-net.rules で指定します。
# cat /etc/udev/rules.d/70-persistent-net.rules # This file was automatically generated by the /lib/udev/write_net_rules # program, run by the persistent-net-generator.rules rules file. # # You can modify it, as long as you keep each rule on a single # line, and change only the value of the NAME= key. # PCI device 0x14e4:0x164c (bnx2) (custom name provided by external tool) SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", ATTR{address}=="00:14:5e:fa:98:a2", ATTR{type}=="1", KERNEL=="eth*", NAME="eth1" # PCI device 0x14e4:0x164c (bnx2) (custom name provided by external tool) SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", ATTR{address}=="00:14:5e:fa:98:a0", ATTR{type}=="1", KERNEL=="eth*", NAME="eth0"
が、相変わらず、/etc/sysconfig/network-scripts/ifcfg-ethX にも HWADDR 指定があるので、両方を合わせないといけない。ifcfg-ethX の HWADDR は削除した方が幸せになれるかも知れません。
/etc/modprobe.conf
/etc/modprobe.conf が無くなりました。目的別に対応を説明します。
(1) initrdに投入する内蔵ディスク用のデバイス・ドライバの指定(alias scsi_hostadapterXX)
RHEL5 までは、mkinitrd コマンドは /etc/modporbe.conf をみて、そのサーバを起動するために必要なドライバを含む initrd を作成しました。initrd に含まれる初期化スクリプト init では、下記の例のように必要なドライバを直接 insmod しています。
echo "Loading ehci-hcd.ko module" insmod /lib/ehci-hcd.ko echo "Loading ohci-hcd.ko module" insmod /lib/ohci-hcd.ko echo "Loading uhci-hcd.ko module" insmod /lib/uhci-hcd.ko mount -t usbfs /proc/bus/usb /proc/bus/usb echo "Loading jbd.ko module" insmod /lib/jbd.ko echo "Loading ext3.ko module" insmod /lib/ext3.ko echo "Loading scsi_mod.ko module" insmod /lib/scsi_mod.ko echo "Loading sd_mod.ko module" insmod /lib/sd_mod.ko echo "Loading scsi_transport_sas.ko module" insmod /lib/scsi_transport_sas.ko echo "Loading mptbase.ko module" insmod /lib/mptbase.ko echo "Loading mptscsih.ko module" insmod /lib/mptscsih.ko echo "Loading mptsas.ko module" insmod /lib/mptsas.ko echo "Loading shpchp.ko module" insmod /lib/shpchp.ko echo "Loading libata.ko module" insmod /lib/libata.ko echo "Loading ata_piix.ko module" insmod /lib/ata_piix.ko ...
RHEL6 では、initrd の作成が dracut に変わって、サーバ個別の initrd ではなく、汎用的な initrd が作成されるようになったので、/etc/modprobe.conf による指定は不要になりました。dracut が作成する initrd では、udev によって、サーバに接続されたデバイスに応じたドライバを自動判別してロードします。
具体的には、initrd に含まれる etc/udev/rules.d/80-drivers.rules のルールから modprobe が呼び出されます。
# cat 80-drivers.rules # do not edit this file, it will be overwritten on update ACTION!="add", GOTO="drivers_end" DRIVER!="?*", ENV{MODALIAS}=="?*", RUN+="/sbin/modprobe -b $env{MODALIAS}" SUBSYSTEM=="tifm", ENV{TIFM_CARD_TYPE}=="SD", RUN+="/sbin/modprobe -b tifm_sd" SUBSYSTEM=="tifm", ENV{TIFM_CARD_TYPE}=="MS", RUN+="/sbin/modprobe -b tifm_ms" SUBSYSTEM=="memstick", RUN+="/sbin/modprobe -b --all ms_block mspro_block" SUBSYSTEM=="i2o", RUN+="/sbin/modprobe -b i2o_block" SUBSYSTEM=="scsi", ENV{DEVTYPE}=="scsi_device", TEST!="[module/sg]", RUN+="/sbin/modprobe -b sg" SUBSYSTEM=="module", KERNEL=="parport_pc", RUN+="/sbin/modprobe -b ppdev" LABEL="drivers_end"
そうは言っても特定のドライバを特定の順序で読み込ませたい場合は、カーネルオプション rdloaddriver にドライバを読み込む順に記載します。具体的には、init スクリプトから下記のスクリプトが実行されて、指定のドライバがロードされます。
# cat cmdline/01parse-kernel.sh #!/bin/sh for p in $(getargs rdloaddriver=); do modprobe $p done
dracut が標準で initrd に含めないドライバを使用する際は、dracut の -d オプションで強制的に initrd に入れておきます。dracut については、レッドハットニュースレター:vol.53 - dracut もどうぞ。
(2) NIC用のデバイス・ドライバの指定(alias ethXX)
サーバ起動後の追加のドライバのロードは、すべて udev で処理されるようになっています。具体的には、rc.sysinit から start_udev したタイミングで、/lib/udev/rules.d/80-drivers.rules に従って自動的に modprobe されます。(dracut 内部の動作と基本的には同じです。)
# cat /lib/udev/rules.d/80-drivers.rules # do not edit this file, it will be overwritten on update ACTION!="add", GOTO="drivers_end" DRIVER!="?*", ENV{MODALIAS}=="?*", RUN+="/sbin/modprobe -b $env{MODALIAS}" SUBSYSTEM=="tifm", ENV{TIFM_CARD_TYPE}=="SD", RUN+="/sbin/modprobe -b tifm_sd" SUBSYSTEM=="tifm", ENV{TIFM_CARD_TYPE}=="MS", RUN+="/sbin/modprobe -b tifm_ms" SUBSYSTEM=="memstick", RUN+="/sbin/modprobe -b --all ms_block mspro_block" SUBSYSTEM=="i2o", RUN+="/sbin/modprobe -b i2o_block" SUBSYSTEM=="scsi", ENV{DEVTYPE}=="scsi_device", TEST!="[module/sg]", RUN+="/sbin/modprobe -b sg" SUBSYSTEM=="module", KERNEL=="parport_pc", RUN+="/sbin/modprobe -b ppdev" LABEL="drivers_end"
ちなみに、udev が必要なドライバを判別する方法は次のとおりです。まず、PCI デバイスなどは、/sys に登録されるとカードに固有の modalias 情報が登録されます。
# cat /sys/devices/pci0000\:00/0000\:00\:06.0/0000\:03\:00.0/0000\:04\:00.0/modalias pci:v000014E4d0000164Csv00001014sd00000342bc02sc00i00
一方、各ドライバは、サポートするデバイスの modalias 情報を持ちます。下記の alias: 部分です。
# modinfo bnx2 filename: /lib/modules/2.6.32-71.el6.x86_64/kernel/drivers/net/bnx2.ko firmware: bnx2/bnx2-rv2p-09ax-5.0.0.j10.fw firmware: bnx2/bnx2-rv2p-09-5.0.0.j10.fw firmware: bnx2/bnx2-mips-09-5.0.0.j15.fw firmware: bnx2/bnx2-rv2p-06-5.0.0.j3.fw firmware: bnx2/bnx2-mips-06-5.0.0.j6.fw version: 2.0.8-j15 license: GPL description: Broadcom NetXtreme II BCM5706/5708/5709/5716 Driver author: Michael Chan <mchan@broadcom.com> srcversion: 8CDA41B3E0DF70A112FBA80 alias: pci:v000014E4d0000163Csv*sd*bc*sc*i* alias: pci:v000014E4d0000163Bsv*sd*bc*sc*i* alias: pci:v000014E4d0000163Asv*sd*bc*sc*i* alias: pci:v000014E4d00001639sv*sd*bc*sc*i* alias: pci:v000014E4d000016ACsv*sd*bc*sc*i* alias: pci:v000014E4d000016AAsv*sd*bc*sc*i* alias: pci:v000014E4d000016AAsv0000103Csd00003102bc*sc*i* alias: pci:v000014E4d0000164Csv*sd*bc*sc*i* alias: pci:v000014E4d0000164Asv*sd*bc*sc*i* alias: pci:v000014E4d0000164Asv0000103Csd00003106bc*sc*i* alias: pci:v000014E4d0000164Asv0000103Csd00003101bc*sc*i* depends: vermagic: 2.6.32-71.el6.x86_64 SMP mod_unload modversions parm: disable_msi:Disable Message Signaled Interrupt (MSI) (int)
これらの情報は、depmod がまとめて /lib/modules/$(uname -r)/modules.alias に記録しており、「modporbe
KVM に関連する iptables
/etc/sysconfig/iptables に下記のエントリが勝手に追加される場合があります。
-A FORWARD -m physdev --physdev-is-bridged -j ACCEPT
これは、ブリッジデバイスを出入りするパケットに対する iptables の設定で、KVM の仮想ネットワークを意識した設定です。(詳細は、iptablesのmanページをどうぞ。)
なのですが、同時に、/etc/sysctl.conf にデフォルトで下記が設定されます。
# Disable netfilter on bridges. net.bridge.bridge-nf-call-ip6tables = 0 net.bridge.bridge-nf-call-iptables = 0 net.bridge.bridge-nf-call-arptables = 0
これは、ブリッジデバイスを出入りするパケットに対する iptables の適用を行わないという設定で、前述の iptables の設定が無意味になります。結論としては、iptables の設定が勝手に追加されるという動きがおかしい、ということで、RHEL6.1 では前述の iptables の設定追加はなくなる予定です。こちらの Bugzilla を参照。
Upstart
カーネルが最初に起動するプロセス /sbin/init の動きがそっくり新しくなっています。init に関連するコマンドは upstart パッケージが提供します。
# rpm -ql upstart /etc/dbus-1/system.d/Upstart.conf /etc/init /etc/init/init-system-dbus.conf /sbin/halt /sbin/init /sbin/initctl /sbin/poweroff /sbin/reboot /sbin/reload /sbin/restart /sbin/runlevel /sbin/shutdown /sbin/start /sbin/status /sbin/stop /sbin/telinit (以下省略)
もともと init は、ジョブコントローラ的な性質がありました。たとえば、従来の init は、/etc/inittab で定義された「ジョブ」を「ランレベルの変更」という「イベント」に応じて実行します。実行中のジョブが異常終了すると再実行する(respawn)というジョブトラッキングも行います。
Upstart はより高度なイベントベースのジョブコントローラとして init を再実装したものとみることができます。「任意の文字列で表されるイベント」に応じて、事前に定義したさまざまなジョブを実行・停止するという機能を持ちます。
事前定義された主なイベントは次のとおりです。
イベント | 説明 |
---|---|
startup | init の起動時に発生 |
starting |
|
started |
|
stopping |
|
stopped |
|
runlevel X | telinit コマンドでランレベルを変更した際に発生 |
これ以外にも任意の文字列をユーザ定義イベントとして使用可能です。次のコマンドでユーザレベルでイベントを発生することもできます。
# initctl emit <イベント>
イベントに反応するジョブの定義は、/etc/init/ 以下の
# initctl start <ジョブ> # initctl stop <ジョブ> # initctl restart <ジョブ> # initctl reload <ジョブ> # initctl status <ジョブ> # initctl list
ジョブ定義の詳細は、init(5)の man ページ(英語版)を参照してください。ここでは、デフォルトで用意されたジョブをみながら起動時の処理の流れを確認します。
まず、init 起動時に発生する startup イベントに反応して、rcS ジョブが走ります。(下記の日本語コメントは筆者が追記)
# cat /etc/init/rcS.conf # rcS - runlevel compatibility # # This task runs the old sysv-rc startup scripts. start on startup # startup イベントに反応して起動 stop on runlevel # 実行中に runlevel イベントが発生するとジョブの実行を中止 task # 1回実行したら終わりの task 型のジョブ(exit 0 で終了したら respawn はしない) console output exec /etc/rc.d/rc.sysinit # /etc/rc.d/rc.sysinit をジョブとして実行する post-stop script # ジョブの実行が終わって "stopped rcS" イベントを発生した後にこのスクリプトを実行 if [ "$UPSTART_EVENTS" = "startup" ]; then [ -f /etc/inittab ] && runlevel=$(/bin/awk -F ':' '$3 == "initdefault" && $1 !~ "^#" { print $2 }' /etc/inittab) [ -z "$runlevel" ] && runlevel="3" for t in $(cat /proc/cmdline); do case $t in -s|single|S|s) runlevel="S" ;; [1-9]) runlevel="$t" ;; esac done exec telinit $runlevel # telinit コマンドで "runlevel X" イベントを発生(X は /etc/inittab もしくはカーネルオプションで指定) fi end script
ここで rc.sysinit が実行されます。post-stop script で発生する "runlevel X" イベントに反応するのは、rc ジョブです。
# cat /etc/init/rc.conf # rc - System V runlevel compatibility # # This task runs the old sysv-rc runlevel scripts. It # is usually started by the telinit compatibility wrapper. start on runlevel [0123456] # runlevel X イベントに反応してジョブを開始 stop on runlevel [!$RUNLEVEL] # 異なる runlevel のイベントが発生したらジョブを中止 # (RUNLEVEL 環境変数は telinit コマンドが設定している。) task # 1回実行したら終わりの task 型のジョブ(exit 0 で終了したら respawn はしない) export RUNLEVEL console output exec /etc/rc.d/rc $RUNLEVEL # /etc/rc.d/rc X を実行。ここで、昔ながらの runlevel に応じた init.d スクリプトが実行される
rc ジョブが完了して、"stopped rc" イベントが発生すると、これに反応して、start-ttys ジョブが実行されます。
# cat /etc/init/start-ttys.conf # # This service starts the configured number of gettys. start on stopped rc RUNLEVEL=[2345] # "stopped rc" イベントに反応してジョブを開始 env ACTIVE_CONSOLES=/dev/tty[1-6] env X_TTY=/dev/tty1 task # 1回実行したら終わりの task 型のジョブ(exit 0 で終了したら respawn はしない script . /etc/sysconfig/init for tty in $(echo $ACTIVE_CONSOLES) ; do [ "$RUNLEVEL" = "5" -a "$tty" = "$X_TTY" ] && continue initctl start tty TTY=$tty # "tty" ジョブを実行 done end script
これは tty ジョブを実行するためのラッパーでした。tty ジョブの実体は次のとおり。
# cat /etc/init/tty.conf # tty - getty # # This service maintains a getty on the sepcified device. stop on runlevel [016] respawn # 停止したら即座に respawn instance $TTY # 同名のジョブを複数実行する際は、個別に inistance 名を設定します。 exec /sbin/mingetty $TTY # migetty を起動
これで migetty が respawn 指定で起動します。
従来 /etc/inittab に記載されていた内容がきれいにジョブに置き換えられていることが分かります。現在は、旧来の init との互換性を考えて、このようなジョブ定義がなされていますが、将来的には、起動処理を高速化するために、より並列度の高いジョブ実行ができるように定義が変わっていくと予想されます。
KVM ゲスト OS のシリアルコンソール
RHEL60 を KVM ゲストとする際に、virsh console
まず、GRUB の画面出力と Kernel メッセージの出力先を仮想シリアル端末に設定します。
/etc/grub.conf
# grub.conf generated by anaconda # # Note that you do not have to rerun grub after making changes to this file # NOTICE: You have a /boot partition. This means that # all kernel and initrd paths are relative to /boot/, eg. # root (hd0,0) # kernel /vmlinuz-version ro root=/dev/vda2 # initrd /initrd-[generic-]version.img #boot=/dev/vda default=0 timeout=5 splashimage=(hd0,0)/grub/splash.xpm.gz hiddenmenu serial --speed=115200 --unit=0 --word=8 --parity=no --stop=1 # GRUB の出力先を terminal --timeout=5 serial console # 仮想シリアルに設定 title Red Hat Enterprise Linux (2.6.32-71.el6.x86_64) root (hd0,0) # kernel /vmlinuz-2.6.32-71.el6.x86_64 ro root=UUID=807c23e0-693b-46bb-9485-7db5d665e303 rd_NO_LUKS rd_NO_LVM rd_NO_MD rd_NO_DM LANG=ja_JP.UTF-8 KEYBOARDTYPE=pc KEYTABLE=jp106 crashkernel=auto rhgb quiet kernel /vmlinuz-2.6.32-71.el6.x86_64 ro root=UUID=807c23e0-693b-46bb-9485-7db5d665e303 rd_NO_LUKS rd_NO_LVM rd_NO_MD rd_NO_DM LANG=ja_JP.UTF-8 KEYBOARDTYPE=pc KEYTABLE=jp106 crashkernel=auto console=ttyS0,115200n8 console=tty0 initrd /initramfs-2.6.32-71.el6.x86_64.img # ↑ Kernel メッセージの出力先を仮想シリアルに設定
続いて、仮想シリアルコンソールからのログインを受け付けます。先に説明した upstart による mingetty 起動スクリプトに agetty の起動を追加します。
/etc/init/start-ttys.conf
# # This service starts the configured number of gettys. start on stopped rc RUNLEVEL=[2345] env ACTIVE_CONSOLES=/dev/tty[1-6] env X_TTY=/dev/tty1 task script . /etc/sysconfig/init for tty in $(echo $ACTIVE_CONSOLES) ; do [ "$RUNLEVEL" = "5" -a "$tty" = "$X_TTY" ] && continue initctl start tty TTY=$tty done initctl start serial DEV=ttyS0 SPEED=115200 # 仮想シリアルコンソールからのログインを受け付け end script
loop デバイスの追加方法
/etc/udev/makedev.d/50-udev.nodes が無くなっているので道に迷った気分になりますが・・・。まず、デフォルトの loop0 〜 loop7 は、50-udev.nodes ではなく、start_udev の中で直接作成されるようになっています。
/sbin/start_udev から抜粋
for i in 0 1 2 3 4 5 6 7; do [ -b /dev/loop$i ] || /bin/mknod -m 0640 /dev/loop$i b 7 $i /bin/chown root:disk /dev/loop$i done
start_udev の中に 50-udev.nodes を参照して追加のデバイスを作成する仕組みは残っていますので、loop8 以降については、これまで同様に 50-udev.nodes で指定することができます。下記は、loop8 〜 loop511 を追加しています。
# for i in $(seq 8 511); do echo "loop$i" >> /etc/udev/makedev.d/50-udev.nodes
ただし、256 個以上の loop デバイスを作成する場合は、/etc/makedev.d/01linux-2.6.x で指定される最大値も修正しておきます。
/etc/makedev.d/01linux-2.6.x
#b $STORAGE 7 0 1 256 loop%d # デフォルトは最大 256 個 b $STORAGE 7 0 1 2046 loop%d # 最大 2046 個に変更