ISC dhcpd で IP アドレスに基いてホスト名を自動設定

AWS EC2 のインスタンスを立ち上げたとき、(AMI によるかもしれませんが)DHCP で付与された IP アドレスに基いて ip-10-11-12-13 のようにホスト名が設定されるのを見て、さすが AWS は不思議なチカラでよくわからんことをしよる、と思いました。

と、思ったら ISC DHCP でも普通にできました。

使用した dhcpd のバージョンは次の通りです。

CentOS 7.0.1406 / dhcp-4.2.5-27.el7.centos.x86_64

man dhcp-eval すると色々でてきます。

dhcpd.conf

log-facility daemon;
not authoritative;

ddns-updates on;
ddns-update-style interim;
ignore client-updates;

subnet 10.1.1.0 netmask 255.255.255.0 {
    default-lease-time          21600;
    max-lease-time              43200;
    range dynamic-bootp         10.1.1.100 10.1.1.200;
    option routers              10.1.1.1;
    option subnet-mask          255.255.255.0;
    option domain-name-servers  10.1.1.10;
    option domain-name          "test";
    option domain-search        "test";
    ddns-domainname             "test";
    ddns-ttl                    3600;

    zone test. {
        primary 10.1.1.10;
    }

    zone 1.1.10.in-addr.arpa. {
        primary 10.1.1.10;
    }

    if not exists host-name {
        option host-name = concat("ip-" , binary-to-ascii(10, 8, "-", leased-address), ".", config-option domain-name);
        ddns-hostname = concat("ip-" , binary-to-ascii(10, 8, "-", leased-address));
    } else {
        option host-name = concat(lcase(option host-name), ".", config-option domain-name);
    }
}

上の設定では・・・

  • クライアントがホスト名を送ってきている場合(仮に oreore とすると)
    • oreore.test というホスト名をクライアントに返します
  • クライアントがホスト名を送ってこない場合
    • ip-10.11.12.13.test のようにリースした IP アドレスに基づいたホスト名を返します

となります。ついでに同じ名前で DDNS でネームサーバに更新もかけます。

CentOS 7 の dhcpd で DDNS が失敗する

次のような感じで、リースした IP アドレスを Dynamic DNS でネームサーバに登録する DHCP サーバを CentOS 6 で作っていたのですが、なぜか CentOS 7 にすると同じような設定でも DDNS での更新が失敗するようになりました。

dhcpd.conf

log-facility daemon;
not authoritative;

ddns-updates on;
ddns-update-style interim;
ignore client-updates;

subnet 10.1.1.0 netmask 255.255.255.0 {
    default-lease-time          21600;
    max-lease-time              43200;
    range dynamic-bootp         10.1.1.100 10.1.1.200;
    option routers              10.1.1.1;
    option subnet-mask          255.255.255.0;
    option domain-name-servers  10.1.1.10;
    option domain-name          "test";
    option domain-search        "test";
    ddns-domainname             "test";
    ddns-ttl                    3600;
}

CentOS 6 で成功していたときは次のようなログが記録されていました。

dhcpd: Added new forward map from aaa.test to 10.1.1.100
dhcpd: added reverse map from 100.1.1.10.in-addr.arpa. to aaa.test

CentOS 7 で失敗したときには次のようなログが記録されていました。

dhcpd: Unable to add forward map from aaa.test to 10.1.1.100: not found

各バージョンは次の通りです。

CentOS 6.5 / dhcp-4.1.1-38.P1.el6.centos.x86_64
CentOS 7.0.1406 / dhcp-4.2.5-27.el7.centos.x86_64

試行錯誤の結果、CentOS 7 でも dhcpd.conf で zone でネームサーバを明示すれば大丈夫でした。

log-facility daemon;
not authoritative;

ddns-updates on;
ddns-update-style interim;
ignore client-updates;

subnet 10.1.1.0 netmask 255.255.255.0 {
    default-lease-time          21600;
    max-lease-time              43200;
    range dynamic-bootp         10.1.1.100 10.1.1.200;
    option routers              10.1.1.1;
    option subnet-mask          255.255.255.0;
    option domain-name-servers  10.1.1.10;
    option domain-name          "test";
    option domain-search        "test";
    ddns-domainname             "test";
    ddns-ttl                    3600;

    zone test. {
        primary 10.1.1.10;
    }

    zone 1.1.10.in-addr.arpa. {
        primary 10.1.1.10;
    }
}

CentOS 7 で zone を書いて成功したときは次のようなログが記録されました(CentOS 6 で成功していたときのログと同じです)。

dhcpd: Added new forward map from aaa.test to 10.1.1.100
dhcpd: Added reverse map from 100.1.1.10.in-addr.arpa. to aaa.test

CentOS 6 の dhcpd だと zone を記述していなくても SOA レコードから権威サーバを探して更新先のネームサーバを特定しているっぽいのだけど (nsupdate も同じような動作するよね?)、CentOS 7 の dhcpd だと SOA レコードの検索はせずに、zone で指定されたネームサーバに直接更新を掛けているようでした。

実際、SOA レコードとか NS レコードを適当に書いても更新に成功しました。

dhcpdns も本職ではなく詳しくないので、なにか根本的なところで間違っているのかもしれません。

CentOS 7 を KickStart でインストールする ISO を作る

最近は開発用の VM の構築には Packer や Vagrant が流行っているようですが、自社では諸事情で VirtualBoxVMware で個別に VM を作るのが主流です。

が、VM を作るたびに CentOSインストーラーの GUI をぽちぽちするのは苦痛なので、KickStart で一発でインストールできる ISO を作っています。

先日 CentOS 7 がリリースされたので CentOS 7 用の ISO も作ってみました。

作り方

手順の中の ftp://example.com/centos/7/os/x86_64/ は適当な CentOS 7 のミラーに変更してください。 自社とかでミラーしているならそれを使うのが良いと思います。

.

ISO を作るために mkisofs が必要なのでインストールします。CentOS 6 なら genisoimage パッケージに含まれています。

$ yum install genisoimage

作業用のディレクトリを作成します。

$ mkdir -p iso/{isolinux,ks}
$ cd iso

適当な CentOS のミラーから centos/7/os/x86_64/isolinux/ をダウンロードします。

$ rsync -avz rsync://ftp.iij.ad.jp/centos/7/os/x86_64/isolinux/ isolinux/

isolinux.cfg を編集します。

$ vi isolinux/isolinux.cfg

"label linux" という行から最後までをざくっと削除して下記の内容を追記します。

label centos7
  menu label ^Install CentOS 7
  menu default
  kernel vmlinuz
  append initrd=initrd.img inst.stage2=ftp://example.com/centos/7/os/x86_64/ ks=cdrom:/ks/centos7.cfg

ついでに先頭の方にある timeout の値を短くしておきます。

timeout 50

KickStart のコンフィグを作成します。

$ vi ks/centos7.cfg

次のように作成します。

ks/centos7.cfg

#version=RHEL7

cmdline
install
url --url=ftp://example.com/centos/7/os/x86_64/

lang en_US.UTF-8
keyboard --vckeymap=jp106 --xlayouts=jp
timezone Asia/Tokyo --isUtc --nontp

network --bootproto=dhcp --ipv6=auto --activate --hostname=unknown

#rootpw --plaintext password
rootpw --iscrypted $1$2c5VfLZS$WKO3i5/aJrKMDe9fudZ/p0

zerombr
bootloader --location=mbr

clearpart --all --initlabel
part / --fstype=xfs --grow --asprimary --size=1

auth --enableshadow --passalgo=sha512
firstboot --disabled
selinux --disabled
firewall --disabled

poweroff

%packages --nobase
%end

%pre
mkdir /mnt/cdrom
mount -o ro /dev/cdrom /mnt/cdrom
%end

%post --log=/root/ks-post.log
set -x
%include /mnt/cdrom/ks/post.sh
%end

インストール後になにか後処理を入れたいなら ks/post.sh に書きます。

$ vi ks/post.sh

例えばブート時のカーネルパラメータから rhgb を削除するようにしてみます。

ks/post.sh

# [grub] remove rhgb
sed -i.orig -r '/^GRUB_CMDLINE_LINUX=/s/\s+rhgb//' /etc/default/grub
grub2-mkconfig -o /boot/grub2/grub.cfg

ISO を作ります。

$ mkisofs \
    -o ../centos7-x86_64.iso \
    -b isolinux/isolinux.bin \
    -c isolinux/boot.cat \
    -no-emul-boot -boot-load-size 4 -boot-info-table -r -J -v ./

centos7-x86_64.iso が作成されます。この ISO からブートすると KickStartCentOS 7 が自動でインストールされます。

注意点

なお、↑の centos7.cfg ままだと・・・

  • root のパスワードが password です
    • 次の手順で変更できます
      • openssl passwd -1 で好きなパスワードを入力して暗号化します
      • centos7.cfgrootpw --iscrypted ... のところを暗号化されたパスワードで書き換えます
  • 問答無用でディスクのパーティションを削除します
    • この ISO を挿入してブートすると既存のシステムは破壊されます
  • ディスク全体を "/" にします
    • swap が必要なら後で追加してください
  • インストールされるパッケージは最小構成です
    • Base すらありません
    • インストール後に yum groupinstall base してください
  • firewall は無効です
    • 必要ならセットアップ後に有効にしてください
  • selinux は無効です
    • すみません

ハマったところ

isolinux.cfgカーネルパラメータで inst.stage2 でインストールソースを指定しないと次のようなメッセージが表示されてインストールが止まりました。

dracut-initqueue: Warning: Could not boot
dracut-initqueue: Warning: /dev/root does not exist 

CentOS 6 のころは無くても大丈夫だったのになぜだろう?

CentOS6 で libvirt で LXC を使ってみる

少し前に CentOS6 で LXC を使ってみたので、次は libvirt を絡めて LXC を使ってみます。

なお、今回もほとんど参考サイトの写経です。

参考にしたサイト

前提

  • CentOS 6.5 を Base パッケージグループのみでセットアップ
    • 前回は CentOS 6.4 だったのですがつい先日 6.5 がリリースされたので 6.5 を使います
  • IPv6 は有効にしています
    • なぜか有効にしないと sshX11 転送ができなかったからです
    • この記事では X11 転送は出てきません
  • SELinux は無効にしています
    • SELinux とかよくわからないです

libvirt のインストールと設定

libvirt をインストールします。

# yum install libvirt libvirt-client python-virtinst

前回の手順でインストールしていた rpmforge の lxc は必要ありません。libvirt に含まれる /usr/libexec/libvirt_lxc その代わりです。

次に virsh コマンドや virt-install コマンドのデフォルトの接続先を lxc にします。これが無いと毎回 virsh --connect lxc:/// のように指定しなければならず、面倒です。

# cat >> /etc/libvirt/libvirt.conf <<EOS
uri_default = "lxc:///"
EOS

再起動しておきます。

reboot

ゲストの rootfs を作成

ゲストの rootfs のディレクトリを作成して必要なパッケージをインストールします。

参考サイトの手順で core パッケージグループをインストールしていたので同じようにします。

# mkdir /var/lib/libvirt/lxc/vm01
# yum --installroot=/var/lib/libvirt/lxc/vm01 --releasever=6 -y groupinstall core
# yum --installroot=/var/lib/libvirt/lxc/vm01 --releasever=6 -y install plymouth libselinux-python

chroot します。

# chroot /var/lib/libvirt/lxc/vm01

空の fstab と mtab を作成します。これらのファイルが無いとコンテナの最初の起動時に妙なことになります。

どんな風に妙なのかはちょっと言葉にはしにくいですが、コンテナのコンソールに接続してもまともに表示されなかったり、ホスト側の SSH が突然切れたりします。

この2つのファイルを作ることで改善される理由は・・・わかりません! 直感です。

# touch /etc/fstab /etc/mtab

/etc/sysconfig/network を作ります。

# cat > /etc/sysconfig/network <<EOS
NETWORKING=yes
HOSTNAME=localhost
EOS

I/F 設定を作ります。

# cat > /etc/sysconfig/network-scripts/ifcfg-eth0 <<EOS
DEVICE=eth0
ONBOOT=yes
TYPE=Ethernet
BOOTPROTO=dhcp
DEFROUTE=yes
PEERDNS=yes
PEERNTP=no
EOS

root のパスワードを設定します。

# echo password | passwd --stdin root

/etc/securetty に pts/0 を追記します。これが無いと virsh console でコンソールに接続したときに root でログインできません。

# echo "pts/0" >> /etc/securetty

pam の設定ファイルから session required pam_loginuid.so という行をコメントアウトします。 これをやっておかないとゲストにログインできません。なお、理由はわかりません。

# cp -p /etc/pam.d/login /etc/pam.d/login.orig
# cp -p /etc/pam.d/sshd  /etc/pam.d/sshd.orig

# sed -i 's/^\(session  *required  *pam_loginuid.so\)/#\1/' /etc/pam.d/login
# sed -i 's/^\(session  *required  *pam_loginuid.so\)/#\1/' /etc/pam.d/sshd

SELinux を無効にします。

# sed -i '/^SELINUX=/c SELINUX=disabled' /etc/selinux/config

chroot を抜けます。

# exit

ホストの SELinux

ホストの /selinux を削除して reboot します。

# rmdir /selinux
# reboot

これをやっておかないと後の手順でコンテナの開始に失敗します。

# virsh start vm01
エラー: ドメイン vm01 の起動に失敗しました
エラー: internal error guest failed to start: PATH=/bin:/sbin TERM=linux container=lxc-libvirt container_uuid=85dea966-d430-c06b-67f3-9a02fdf23b19 LIBVIRT_LXC_UUID=85dea966-d430-c06b-67f3-9a02fdf23b19 LIBVIRT_LXC_NAME=vm01 /sbin/init
error receiving signal from container: Input/output error

これまた理由はわかりませんが、下記あたりが関係していると思います。

ゲストの作成と起動

再起動が終わったら virt-install で lxc コンテナを作成します。

# virt-install --name vm01 --ram 512 --vcpu 1 --filesystem /var/lib/libvirt/lxc/vm01/,/ --noautoconsole --noreboot

virsh start でコンテナを開始します。

# virsh start vm01

virsh でコンソールに接続します。コンソールを抜けるときは Ctrl + [ です

# virsh console vm01

ssh でも接続してみます。まずはホストで IP アドレスを調べます。

# cat /var/lib/libvirt/dnsmasq/default.leases

ssh で接続します。

# ssh 192.168.122.182

接続を抜けるときは exit です。そんなの誰でも知ってます。

# exit

virsh destroy で停止します(virsh shutdown では停止できませんでした)。

強制終了になるので安全に停止したかったらゲストにログインしてシャットダウンしてください。

# virsh destroy vm01

さいごに

よくわからずに試行錯誤で構築したので、実運用はもとより開発環境とかでも使うのはコワイですね・・・

最近は Docker というのが流行っているらしいのでそっちの方が良いかもしれません(CentOS で動くかどうかは知りませんが)。

CentOS6 で LXC を使ってみる

下記の記事で Docker というものを知って少し気になったのですが、Docker を試してみる前に LXC がどんなものなのか試してみたほうがいいかなーと思ったので、手元の CentOS6 で使ってみました。

他のブログやWikiから切り貼りしただけですが、自分で見返したときに意味がわかるようにそれなりに説明も書きました。

参考にしたサイト

前提

  • CentOS 6.4 を Base パッケージグループのみでセットアップ
  • IPv6 は無効にしています
  • SELinux は無効にしています

LXC のインストールとホストの設定

epel と rpmforge を追加

rpmforge に lxc の rpm があるようなので rpmforge を追加します。

$ yum localinstall -y http://pkgs.repoforge.org/rpmforge-release/rpmforge-release-0.5.3-1.el6.rf.x86_64.rpm

また、lxc-templates が依存している debootstrap が epel にあるので、これも追加します。

$ yum localinstall -y http://ftp-srv2.kddilabs.jp/Linux/distributions/fedora/epel/6/x86_64/epel-release-6-8.noarch.rpm

どちらもデフォルトで無効にしておきます。

$ sed -i.bak '/^enabled/c enabled=0' /etc/yum.repos.d/epel.repo
$ sed -i.bak '/^enabled/c enabled=0' /etc/yum.repos.d/rpmforge.repo

LXC をインストール

yum で LXC をインストールします。

$ yum --enablerepo=epel,rpmforge -y install lxc lxc-templates lxc-doc lxc-libs

ブリッジ作成

ホスト~ゲスト間のためのブリッジを作成します。NAT を使うようにするので実 I/F には繋ぎません。

$ cat > /etc/sysconfig/network-scripts/ifcfg-lxcbr0 <<EOS
DEVICE=lxcbr0
ONBOOT=yes
TYPE=Bridge
BOOTPROTO=none
IPADDR=10.12.128.1
PREFIX=24
DEFROUTE=no
EOS

$ ifup lxcbr0

cgroup をマウントします。

$ cat >> /etc/fstab <<EOS
cgroup                  /cgroup                 cgroup  defaults        0 0
EOS

$ mkdir -p /cgroup
$ mount -a

dnsmasq インストール

ゲストの IP を DHCP で割り当てるために dnsmasq をインストールします。固定で割り当てるなら必要ありません。

$ yum install -y dnsmasq
$ mv /etc/dnsmasq.conf /etc/dnsmasq.conf.orig

$ cat > /etc/dnsmasq.conf <<EOS
domain-needed
bogus-priv
interface=lxcbr0
listen-address=127.0.0.1
listen-address=10.12.128.1
expand-hosts
domain=lxc
dhcp-range=10.12.128.100,10.12.128.200,1h
EOS

$ service dnsmasq start
$ chkconfig dnsmasq on

IP Forwarding と NAT

ゲスト→ホスト で NAT するために IP Forwarding を有効にして iptables で NAT を設定します。 ホストの実 I/F が DHCP だったので MASQUERADE です。

$ sed -i.bak '/^net\.ipv4\.ip_forward/c net.ipv4.ip_forward = 1' /etc/sysctl.conf
$ sysctl -p

$ service iptables start
$ chkconfig iptables on

$ iptables -t nat -A POSTROUTING -s 10.12.128.0/24 -o eth0 -j MASQUERADE

$ service iptables save

ゲストの rootfs 作成

ゲストの rootfs を作成します。

作業用のディレクトリとして /t を使います。

$ mkdir /t
$ cd /t

chroot で yum を動かすために必要な最小限のパッケージをインストールします。

  • --installroot=/t で /t をルートとしてインストールします
  • --releasever=6 がないと $releasever が未定義 とか言われてエラーになります
$ yum --installroot=/t --releasever=6 -y install centos-release rootfiles yum

resolv.conf をコピーします。

$ cp /etc/resolv.conf /t/etc/

chroot します。

$ chroot /t

デバイスファイルを作成します。

$ rm -f /dev/null
$ mknod -m 666 /dev/null c 1 3
$ mknod -m 666 /dev/zero c 1 5
$ mknod -m 666 /dev/urandom c 1 9
$ ln -s /dev/urandom /dev/random
$ mknod -m 600 /dev/console c 5 1
$ mknod -m 660 /dev/tty1 c 4 1
$ chown root:tty /dev/tty1

$ mkdir -p /dev/shm
$ chmod 1777 /dev/shm
$ mkdir -p /dev/pts
$ chmod 755 /dev/pts

その他に必要そうなパッケージをインストールします。

$ yum -y install dhclient passwd openssh-server

/etc/sysconfig/network を作ります。

$ cat > /etc/sysconfig/network <<EOS
NETWORKING=yes
HOSTNAME=localhost
EOS

I/F 設定を作ります。

$ cat > /etc/sysconfig/network-scripts/ifcfg-eth0 <<EOS
DEVICE=eth0
ONBOOT=yes
TYPE=Ethernet
BOOTPROTO=dhcp
DEFROUTE=yes
PEERDNS=yes
PEERNTP=no
EOS

/etc/fstab を作ります。これはコンテナの起動時にマウントされます。

$ cat > /etc/fstab <<EOS
/dev/root               /                       rootfs   defaults        0 0
tmpfs                   /dev/shm                tmpfs    nosuid,nodev    0 0
EOS

lxc-sysinit.conf を作ります。コンテナの起動時に init から upstart で実行されます。

$ cat > /etc/init/lxc-sysinit.conf <<EOS
start on startup
env container
pre-start script
        if [ "x$container" != "xlxc" -a "x$container" != "xlibvirt" ]; then
                stop;
        fi
        telinit 3
        initctl start tty TTY=console
        exit 0;
end script
EOS

root のパスワードを設定します。

$ passwd

udev-post はたぶん不要なので off にします。

$ chkconfig udev-post off

chroot を抜けます。

$ exit

作成した rootfs をゲストの作成時に使いまわすために tar で固めます。

$ cd /t
$ tar cvzf /centos6-lxc-root.tgz .

ゲストの作成

ゲストのディレクトリを作成します。この位置に作成すれば lxc-create しなくても認識されます。

$ mkdir -p /var/lib/lxc/vm01/rootfs

rootfs のアーカイブを展開します。

$ cd /var/lib/lxc/vm01/rootfs
$ tar xvzf /centos6-lxc-root.tgz --numeric-owner

lxc の config を作成します。cgroup でリソース制限ができるようですがとりあえず必要最小限にします。

$ cat > /var/lib/lxc/vm01/config <<EOS
lxc.utsname = vm01
lxc.network.type = veth
lxc.network.flags = up
lxc.network.link = lxcbr0
lxc.network.name = eth0
lxc.network.veth.pair = veth-vm01
lxc.tty = 6
lxc.pts = 1024
lxc.rootfs = /var/lib/lxc/vm01/rootfs
lxc.mount  = /var/lib/lxc/vm01/fstab
lxc.cap.drop = sys_module mac_admin
EOS

fstab を作成します。これはたぶんゲストの init の前の chroot の前にマウントされます。

$ cat > /var/lib/lxc/vm01/fstab <<EOS
proc            /var/lib/lxc/vm01/rootfs/proc           proc    nodev,noexec,nosuid     0 0
sysfs           /var/lib/lxc/vm01/rootfs/sys            sysfs   defaults                0 0
EOS

ゲストの起動

ゲストの準備はできたので起動してみます。-d はデーモンとして起動するオプションです。 -o でログの出力先の指定、-l でログレベルの指定もできます。

$ lxc-start -n vm01 -d

ゲストのコンソールに接続します。

$ lxc-console -n vm01

ログインのプロンプトが表示されるので、↑の方で設定した root のパスワードでログインします。

コンソールからの切断は Ctrl+a → q です。

SSH で接続する

ホストの dnsmasq が DHCP でゲストに割り当てた IP アドレスを確認します。

$ cat /var/lib/dnsmasq/dnsmasq.leases

あるいは messages から探します。

$ grep dnsmasq-dhcp /var/log/messages

SSH でゲストにログインします。

$ ssh root@10.12.128.197

ゲストの停止

$ lxc-stop -n vm01

疑問点

  • lxc の config の lxc.mount がなくでも動作したけど必要?
    • proc や sysfs はなくてもマウントされている
    • rootfs 以外のホストのディレクトリをゲストに見せたいときに使うのでは?
  • ゲストの中の fstab がなくても動作したけど必要?
    • rootfs はなくてもマウントされている
    • tmpfs もなくてもマウントされている
      • しかもゲストの中の fstab に書いていると2重にマウントされているように見える
  • lxc-start -n vm01 としてもブートのメッセージが見えない
    • lxc-sysinit.conf を弄ると表示されるようになった
    • が、コンソールにログインプロンプトが表示されなくなった
  • lxc-stop -n vm01 で止めると次回起動時にネットワークとかが自動で始動しない?
    • /var/lock/subsys/ にいろいろ残るため?
    • lxc-sysinit.conf で消し去る?

virt-install と Kickstart で KVM に CentOS をインストールする

はじめに

virt-install と Kickstart を使って X Window なしで KVMCentOS をインストールします。

Kickstart 定義ファイル

Kickstart 定義ファイルを作成します。

RHELCentOS を普通にインストールすると /root/anaconda-ks.cfg に Kickstart 定義ファイルが作成されるので、そのファイルを参考に作成します。

ks.cfg

cmdline
install
lang en_US.UTF-8
keyboard jp106

network --device eth0 --onboot yes --bootproto dhcp --noipv6 --hostname hoge

zerombr
bootloader --location=mbr --append="crashkernel=auto rhgb quiet"

clearpart --all --initlabel
part / --fstype=ext4 --grow --asprimary --size=1

rootpw --plaintext password
authconfig --enableshadow --passalgo=sha512
selinux --disabled
firewall --disabled
firstboot --disabled
timezone --utc Asia/Tokyo
reboot

%packages
@core
@base
@japanese-support
%end

この定義ファイルだと概ね次のようにインストールされます。詳しい説明は省略です。

  • シリアルコンソールにインストーラーのメッセージを流すために cmdline を指定
  • ディスクはすべてルートパーティションに割り当て(swap なし)
  • root のパスワードは "password"
    • インストール後に変更!!!
  • I/F は DHCP
    • 固定IPが必要ならインストール後に変更する
  • selinux や iptables は無効
    • 必要ならインストール後に設定する
  • パッケージは Minimum に Base と日本語サポートだけ追加
    • 必要なものはインストール後に追加する

virt-installCentOS をインストール

# virt-install \
    --name hoge \
    --hvm \
    --virt-type kvm \
    --ram 1024 \
    --vcpus 1 \
    --arch x86_64 \
    --machine rhel6.4.0 \
    --os-type linux \
    --os-variant rhel6 \
    --boot hd \
    --disk path=/dev/vg0/vm.hoge \
    --network bridge=br0 \
    --graphics vnc \
    --serial pty \
    --console pty \
    --location http://ftp.riken.jp/Linux/centos/6.4/os/x86_64/ \
    --initrd-inject ks.cfg \
    --extra-args "ks=file:/ks.cfg console=ttyS0,115200" \
    --noautoconsole

# virsh console hoge

ざっくり要点だけを説明すると・・・、

--location http://ftp.riken.jp/Linux/centos/6.4/os/x86_64/
インストールのソースに ftp.riken.jp を使います(リポジトリのミラーがどこかにあるならその方が良いです)。

--initrd-inject ks.cfg
インストーラーの initrd に ks.cfg を突っ込みます。

--extra-args "ks=file:/ks.cfg console=ttyS0,115200"
インストーラーのブートパラメータに Kickstart 定義ファイルを指定します、さらにシリアルコンソールにメッセージを流すために console も指定します。

--noautoconsole
自動的に virt-viewer が起動しないようにします。KVM ホストに X サーバは入れていないしそもそも virt-viewer 自体入れてません。

virsh console hoge
ゲストのシリアルコンソールに接続します(インストーラーのメッセージが表示されます)。

--graphics vnc--graphics none に変えれば virt-viewer の代わりに自動的にゲストのシリアルコンソールに繋がるのですが、いざと言う時のために通常のコンソールは残しておきたいのでこのようにしています(Windows で Xming を起動して virt-managerPuTTy の X forwarding で転送できるようにするため)。

インストール後にスクリプトを実行

Kickstart は %pre や %post でインストール前後にスクリプトを実行することができるので、頑張ればちょっとしたプロビジョニングもできなくはないです。

例えばこんな感じで言語設定をインストール後に日本語に変更することもできます(はじめから日本語にしておけばいいだけですが)。

...snip...

%packages
@core
@base
@japanese-support
%end

%post --log=/root/ks-post.log
set -vx
sed -e '/LANG/cLANG="ja_JP.UTF-8"' -i.orig /etc/sysconfig/i18n
%end

最小のパッケージでインストール

Kickstart をテスト的に試す場合は %packages を次のようにしておくと最小のパッケージしかインストールされません。

%packages --nobase
%end

@core と @base は %packages に記述しなくてもデフォルトで選択されます。--nobase を指定することで @base は除外することが出来ます。

インストール後のカーネルパラメータの調整

インストール後に grub.conf の kernel の行に console=tty0 を追記しておきます。追加する位置は console=ttyS0,115200 の直前がオススメです。

/boot/grub/grub.conf

kernel ...snip... console=tty0 console=ttyS0,115200 ...snip...

これをやっておかないと通常のコンソールの方にブート時のメッセージなどが表示されません。

Kickstart 定義ファイルの bootloader の --append に書いておけば自動的に追記することもできるのですが、それだと ttyS0 より tty0 の方が後に来てしまってちょっと面倒だからです。

CentOS 6 なら inittab や securetty を修正しなくても grub.conf でカーネルパラメータを指定するだけでシリアルコンソールが使えるようになりますが、console が複数指定されている場合は最後の console がシリアルコンソールでなければダメっぽいからです。

さいごに

まいどまいど virt-managerGUI でぽちぽちやるのは非常に面倒だったので、これでだいぶカジュアルに KVMCentOS をインストールできるようになりました!

・・・KVM をカジュアルに使うことはあんまりないですがね・・・

CentOS で GitLab を 5.3 から 6.1 にバージョンアップ

CentOS で GitLab を 5.3 から 6.1 にバージョンアップしたのでそのときの手順を残しておきます。

参考

はじめに

すべての作業は git アカウントで行います。root が必要な作業は sudo しています。基本的に参考URLの手順通りです。

5.3 から 6.1 に一気にバージョンアップしようかとも思ったのですが、6.0 から 6.1 のバージョンアップ手順 に「6.1 の前に 6.0 にしておくべし」とあったので、面倒ですが順番にバージョンアップしました。

おそらく、5.4 は飛ばしたり、gitlab-shell は 5.3 から 6.1 まで一気にバージョンアップしても大丈夫だと思いますが、失敗すると面倒なので1つ1つ順番にやりました。

Backup

$ cd /home/git/gitlab
$ RAILS_ENV=production bundle exec rake gitlab:backup:create

Stop server

$ sudo service gitlab stop

From 5.3 to 5.4

Get latest code(5.4)

$ cd /home/git/gitlab
$ git fetch
$ git checkout 5-4-stable

Update gitlab-shell

$ cd /home/git/gitlab-shell
$ git fetch
$ git checkout v1.5.0

Install libs, migrations, etc.

$ cd /home/git/gitlab
$ bundle install --without development test postgres --deployment
$ bundle exec rake db:migrate RAILS_ENV=production
$ bundle exec rake assets:precompile RAILS_ENV=production

From 5.4 to 6.0

Get latest code(6.0)

$ cd /home/git/gitlab
$ git checkout 6-0-stable
error: Your local changes to the following files would be overwritten by checkout:
        db/schema.rb
Please, commit your changes or stash them before you can switch branches.
Aborting

エラーになりました。db/schema.rb がローカル側で変更されているようです。

$ git diff
diff --git a/db/schema.rb b/db/schema.rb
index 348272e..585264e 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -203,14 +203,14 @@ ActiveRecord::Schema.define(:version => 20130614132337) do

   create_table "snippets", :force => true do |t|
     t.string   "title"
-    t.text     "content"
-    t.integer  "author_id",                    :null => false
+    t.text     "content",    :limit => 2147483647
+    t.integer  "author_id",                                          :null => false
     t.integer  "project_id"
-    t.datetime "created_at",                   :null => false
-    t.datetime "updated_at",                   :null => false
+    t.datetime "created_at",                                         :null => false
+    t.datetime "updated_at",                                         :null => false
     t.string   "file_name"
     t.datetime "expires_at"
-    t.boolean  "private",    :default => true, :null => false
+    t.boolean  "private",                          :default => true, :null => false
     t.string   "type"
   end

大丈夫そうなので -f で上書きします。

$ git checkout -f 6-0-stable

Update gitlab-shell

$ cd /home/git/gitlab-shell
$ git checkout v1.7.0

Install additional packages

$ sudo yum install python-docutils

Install libs, migrations, etc.

$ cd /home/git/gitlab
$ bundle install --without development test postgres --deployment
$ bundle exec rake db:migrate RAILS_ENV=production

次の手順で yes/no プロンプトが表示されるので yes と入力します。

6.0 の変更で Team が無くなり Group がメンバーを持つようになったため、Group の所有者をメンバーに追加するかどうかのプロンプトだと思います。

$ bundle exec rake migrate_groups RAILS_ENV=production
This will add group owners to group membership
Do you want to continue (yes/no)? yes

次の手順でグローバルプロジェクトがプロジェクトの所有者の名前空間に移動されるのだと思いますが、グローバルプロジェクトを使っていなかったので関係ありませんでした。

$ bundle exec rake migrate_global_projects RAILS_ENV=production
No global projects found. Proceed with update.

次の手順で yes/no プロンプトが表示されるので yes と入力します。

表示された Issue によると、6.0 からSSH公開鍵の一意性が公開鍵のコメントを除いて行われるようになったため、それが原因で重複してしまう公開鍵を削除するかどうかのプロンプトのようです。

$ bundle exec rake migrate_keys RAILS_ENV=production
This will add fingerprint to ssh keys in db
If you have duplicate keys https://github.com/gitlabhq/gitlabhq/issues/4453 all but the first will be deleted
Do you want to continue (yes/no)? yes

作業を進めます。

$ bundle exec rake migrate_inline_notes RAILS_ENV=production
$ bundle exec rake gitlab:satellites:create RAILS_ENV=production
$ bundle exec rake cache:clear RAILS_ENV=production
$ bundle exec rake assets:clean RAILS_ENV=production
$ bundle exec rake assets:precompile RAILS_ENV=production

From 6.0 to 6.1

Get latest code(6.1)

$ cd /home/git/gitlab
$ git checkout 6-1-stable

Update gitlab-shell

$ cd /home/git/gitlab-shell
$ git checkout v1.7.1

Install libs, migrations, etc.

$ cd /home/git/gitlab
$ bundle install --without development test postgres --deployment
$ bundle exec rake db:migrate RAILS_ENV=production

次の手順で Issues/Merge Requests/Milestones の id がプロジェクト毎の連番になるようにリナンバリングされます。

$ bundle exec rake migrate_iids RAILS_ENV=production

作業を進めます。

$ bundle exec rake assets:clean RAILS_ENV=production
$ bundle exec rake assets:precompile RAILS_ENV=production
$ bundle exec rake cache:clear RAILS_ENV=production

Update config files

gitlab.yml を修正します。あらかじめ 5.3 でどのように修正していたかを確認し、それを参考に 6.1 の gitlab.yml.example をコピペ修正します。

$ cd /home/git/gitlab/config/
$ git diff --color 5-3-stable:config/gitlab.yml.example gitlab.yml
$ cp gitlab.yml.example gitlab.yml
$ vi gitlab.yml

production の gitlab/hostgitlab/email_fromgitlab/support_emailgit/bin_path 辺りが要修正箇所です。

@@ -17,3 +17,3 @@ production: &base
     ## Web server settings
-    host: localhost
+    host: gitlab.ore.example.jp
     port: 80
@@ -35,6 +35,6 @@ production: &base
     # Email address used in the "From" field in mails sent by GitLab
-    email_from: gitlab@localhost
+    email_from: gitlab@ore.example.jp

     # Email address of your support contact (default: same as email_from)
-    support_email: support@localhost
+    support_email: support@ore.example.jp

@@ -171,3 +171,3 @@ production: &base
   git:
-    bin_path: /usr/bin/git
+    bin_path: /usr/local/bin/git
     # Max size of a git object (e.g. a commit), in bytes

アプリケーションサーバが puma から unicorn に変わった(戻った)ので unicorn.rb.example をコピーして unicorn.rb を作成します(内容は修正していません)。

$ cp unicorn.rb.example unicorn.rb

gitlab-shell が GitLab にアクセスするURLを修正します。

$ cd /home/git/gitlab-shell
$ cp config.yml.example config.yml
$ vi config.yml

次のように修正しました。

@@ -4,3 +4,3 @@
 # Url to gitlab instance. Used for api calls. Should end with a slash.
-gitlab_url: "http://localhost/"
+gitlab_url: "http://localhost:8080/"

Update Init script

CentOS 用の init スクリプトと Apache 用の conf を差し替えます。

$ sudo rm /etc/init.d/gitlab
$ sudo rm /etc/httpd/vhost.d/gitlab.conf
$ sudo curl --output /etc/init.d/gitlab https://raw.github.com/gitlabhq/gitlab-recipes/master/init/sysvinit/centos/gitlab-unicorn
$ sudo curl --output /etc/httpd/vhost.d/gitlab.conf https://raw.github.com/gitlabhq/gitlab-recipes/master/web-server/apache/gitlab.conf
$ sudo chmod +x /etc/init.d/gitlab

ruby は GitLab 用にソースからインストールしているので init スクリプトにパスを記述します。

$ sudo vi /etc/init.d/gitlab

RVM を使っているわけではありませんが、RVM_PATH にパスを書いておけばよさそうなのでそうしました。

RVM_PATH="/home/git/ruby-versions/2.0.0-p247/bin"

Apache でモジュールが足りなかったので追加します。

$ sudo vi /etc/httpd/conf/httpd.conf

mod_rewritemod_proxy_balancer を追加しました。

LoadModule rewrite_module modules/mod_rewrite.so
LoadModule proxy_balancer_module modules/mod_proxy_balancer.so

Apache のバーチャルホスト設定を修正します。

$ sudo cp /etc/httpd/vhost.d/gitlab.conf /etc/httpd/vhost.d/gitlab.conf.orig
$ sudo vi /etc/httpd/vhost.d/gitlab.conf

サーバ名とログファイル名を変更しました。

@@ -7,5 +7,5 @@
 #  mod_proxy_http
 <VirtualHost *:80>
-  ServerName gitlab.example.com
+  ServerName gitlab@ore.example.jp
   ServerSignature Off

@@ -24,5 +24,5 @@
     BalancerMember http://127.0.0.1:8080
     ProxyPassReverse http://127.0.0.1:8080
-    ProxyPassReverse http://gitlab.example.com:8080
+    ProxyPassReverse http://gitlab@ore.example.jp:8080
   </Proxy>

@@ -41,9 +41,6 @@
   </Location>

-  LogFormat "%{X-Forwarded-For}i %l %u %t \"%r\" %>s %b" common_forwarded
-  ErrorLog  /var/log/httpd/logs/gitlab.example.com_error.log
-  CustomLog /var/log/httpd/logs/gitlab.example.com_forwarded.log common_forwarded
-  CustomLog /var/log/httpd/logs/gitlab.example.com_access.log combined env=!dontlog
-  CustomLog /var/log/httpd/logs/gitlab.example.com.log combined
+  ErrorLog  logs/gitlab-error_log
+  CustomLog logs/gitlab-access_log combined

 </VirtualHost>

Start application

GitLab の起動と Apache の再起動を行います。

$ sudo service gitlab start
$ sudo service httpd restart

Check application status

GitLab のステータスを確認します。

$ cd /home/git/gitlab
$ bundle exec rake gitlab:env:info RAILS_ENV=production
$ bundle exec rake gitlab:check RAILS_ENV=production

gitlab:check で「Init script up-to-date?」が no になりますが Ubuntu/Debian の手順にある lib/support/init.d/gitlab を使わない限りそうなるので無視します。

さいごに

ブラウザで閲覧したり、Git で fetch/Push できればバージョンアップ成功です!

幾つか互換性の無い変更点があるので注意が必要です。

Global projects

グローバルプロジェクトがなくなり、すべてのプロジェクトはなんらかの(user or group)名前空間に属することになります。

バージョンアップ作業時にグローバルプロジェクトが存在する場合、そのプロジェクトのオーナーの名前空間に移動されます。

Teams

Team がなくなって、代わりに Group がメンバーを持つようになりました。

バージョンアップ作業時に Team が削除され、Group のオーナーが Group の最初のメンバーになります。

Global issue numbers

Issue 番号がプロジェクト毎に採番されるようになりました(たぶん MR と Milestone も)。

バージョンアップ作業時にリナンバリングされます。 古い番号の URL は新しい番号の URL にリダイレクトされますが、古い方の番号が別のチケットの番号に使われるとリダイレクトされません。