カテゴリー別アーカイブ: インストール・アップグレード

DHCPv6-PDでIPv6のサブネットワークを作成

フレッツ光ネクストは、ひかり電話契約をすると/64よりも小さなプレフィックスを使用できます。このプレフィックスを使用すると、ひかり電話ルータの下に別のルータを置いて自分のネットワークを持つことができます。今回はこの方法で自分のネットワークをIPv6の世界に接続してみます。

ひかり電話契約をしていない場合は、IPv6とIPv4のデュアルスタックで接続のようにNAPT(マスカレード)を使用してネットワークを接続します。

ここでの設定は、ZOOT NATIVE (DS-Lite)でネット接続の状態になっている前提での説明です。追加で必要なradvdのインストール方法は、IPv6とIPv4のデュアルスタックで接続を参照して下さい。

サイト構成

Raspberry Piのインターフェイスは、次のように使用します。

インターフェイス ネットワーク アドレス
eth0 自分のネットワーク/64 DHCPv6-PDで自動設定
eth1 Internet(IPoE) DHCPv6で自動設定

自分のネットワーク内の端末は、Raspberry Piが送信するRAで自動的にIPv6アドレスやデフォルトルータが設定されます。

DHCPv6-PDによるプレフィックスの委譲

自分のネットワークを上位のネットワークへ接続するためには、プレフィックス委譲を受けます。この委譲を受けるのに使われるのがDHCPv6-PDです。上位のルータは、DHCPv6-PDによるやりとりでプレフィックスの払い出しと同時に、払い出したプレフィックスに相当するIPv6パケットをどこに送ったらよいかを記録しています。

DHCPはIPv4でIPアドレスなどネット接続に必要な情報を自動設定する時にお馴染みですが、IPv6用のDHCP(DHCPv6)は名前は同じでも全く別のプロトコールです。もっともIPv4で使ったDHCPクライアントは、DHCPv6クライアントとしても機能します。

DHCPv6対応クライアントには何種類かありますが、今回はRaspbian(jessie)に標準でインストールされているdhcpcdを使用します。他のDHCPv6クライアントを使用してプレフィックスの委譲を受ける時は、IPv6 プレフィックス委譲 (DHCPv6-PD) – Archlinuxを参照して下さい1

dhcpcdを有効に

dhcpcdは、ZOOT NATIVE (DS-Lite)でネット接続で無効にしているので、次のコマンドでシステムが起動時する時に自動的に実行開始されるようにします。

$ sudo systemctl enable dhcpcd.service

dhcpcdの設定

dhcpcdの設定は、/etc/dhcpcd.confに書きます。

# この上はデフォルトのまま

# IPv4は設定しない
ipv6only

# LANのIPv4用
# /etc/network/interfacesで設定される。
interface eth0
noipv6

# https://wiki.archlinuxjp.org/index.php/IPv6#.E3.83.97.E3.83.AC.E3.83.95.E3.82.A3.E3.83.83.E3.82.AF.E3.82.B9.E5.A7.94.E8.AD.B2_.28DHCPv6-PD.29
duid
noipv6rs
waitip 6

# WANのIPv6用 DHCPv6-DP
interface eth1
ipv6rs
iaid 1
# use the interface connected to your LAN
ia_pd 1 eth0

ひかり電話ルータはIPv4のDHCPサーバ機能を持っているので、ip6only(noipv4)をしないとDHCPによりIPv4のアドレスがeth1に割り当てられます。

interface設定を削除

dhcpcdでインターフェイスを設定するので/etc/network/interfacesにあるeth1の設定は不要です。そこでeth1に関する部分は全て削除してしまいます。

eth0もdhcpcdで設定できるので不要な気がしますが、これを削除するとシステムを起動する時にDHCPサーバがエラーで実行開始できなくなってしまいます。またDHCPv6-PDでプレフィックスの委譲を受ける時に/etc/resolv.confの内容がひかり電話ルータからのものになってしまいます。そのためeth0はinterfacesで設定します。

ufwの設定

プレフィックス委譲を使って自分のネットワークを接続すると、ネットワーク内の全ての端末にグローバルなIPv6が割り振られます。そのためアドレスが分かればほとんど何の制限もなしに世界中からアクセスすることが可能となります。

その裏返しとして想定外の端末が世界に公開されてしまうなど、NAPT(マスカレード)を使ったIPv6とIPv4のデュアルスタックで接続より各端末がより危険な状態に置かれ、世界中から自分のネットワーク内の端末が攻撃される危険性にさらされます。

この危険性を少しでも小さくするには、ルータを通過するパケットの選別が非常に大切です。

と言っても今回は実験なので必要最小限の制限とし、次のような一般的な最小限のポリシーとしました。

  • 自分のネットワークから外へは無制限に出ていける。
  • 自分のネットワークへは、出て行ったパケットに関連するパケットのみが入れる。

そこで/etc/default/ufwを次のように変更し、許可されたパケット以外は全て破棄するようにします。

DEFAULT_FORWARD_POLICY="DROP"
DEFAULT_INPUT_POLICY="DROP"
DEFAULT_OUTPUT_POLICY="ACCEPT"

許可するパケットのルールは、ufwの設定ファイルに追加します。

/etc/ufw/before.rules(IPv4用)

# 以下を追加する。
# accept all from LAN and returned RELATED or ESTABLISHED packets
-A ufw-before-forward -i eth0 -j ACCEPT
-A ufw-before-forward -m state --state RELATED,ESTABLISHED -j ACCEPT

/etc/ufw/before6.rules(IPv6用)

# 以下を追加する。
# https://www.cert.org/downloads/IPv6/ip6tables_rules.txt
# accept from LAN
-A ufw6-before-input -i eth0 -j ACCEPT

# allow DHCPv6-PD
#-A ufw6-before-input -p udp -s fe80::/10 --sport 547 -d fe80::/10 --dport 546
 -j ACCEPT
-A ufw6-before-input -p udp -s fe80::/10 -d fe80::/10 --dport 546 -j ACCEPT

-A ufw6-before-input -p icmpv6 -s fe80::/10 --icmpv6-type 130 -j ACCEPT

# accept all from LAN and returned RELATED or ESTABLISHED packets
-A ufw6-before-forward -i eth0 -j ACCEPT
-A ufw6-before-forward -m state --state RELATED,ESTABLISHED -j ACCEPT

ufwに元からあったルールを少し緩めて宛先ポート番号だけで許可するようにしているのは、DHCPv6-PDによるプレフィックスの委譲を受けるためです。

DHCPv6の通信を許可するルールがbefore6.rulesに入っていたので大丈夫だと思ったのですが、最初はDHCPv6-PDによるプレフィックスの委譲を受けることができませんでした。そこで原因を探るために捨てているパケットを見ていたら、ひかり電話ルータのDHCPv6サーバから送られてくるパケットのポート番号が547ではありませんでした。このため送信元のポート番号を無視して宛先のポート番号だけを見るようにしました。

IPv6の転送を許可

IPv4をトンネルするためにIPv4の転送を許可していましたが、加えてIPv6も転送するように設定します。

/etc/ufw/sysctl.conf

# 追加する
net/ipv6/conf/default/forwarding=1
net/ipv6/conf/all/forwarding=1

radvdの設定

radvdを使ってRA送信します。自分のネットワークに接続された端末は、このRAを受信することで自動的にIPv6の設定します。

radvdが配布するRAの設定は/etc/radvd.conf/radvd.confに書きます。

interface eth0 {
  AdvSendAdvert on;
  #MaxRtrAdvInterval 30;
  prefix ::/64 {
    AdvRouterAddr on;
  };
};

ここで指定しているプレフィックス::/64は、マジックワードです。このアドレスを指定すると、指定されたinterfaceの全グローバルアドレスからプレフィックスを決定してRAを送り出してくれます。今回のようにDHCPv6-PDで指定されるアドレスが何になるかわからない場合に便利な指定方法です。

IPv6での通信確認

以上でルータの設定は完了です。ここで再起動して自分のネットワーク内の端末からIPv6で通信できるか試してみます。

確認方法とトラブルシューティングは、IPv6とIPv4のデュアルスタックで接続のIPv6での通信確認を参照して下さい。

設定に間違いがないのに通信できない

今回どこにも間違いはないのに外と通信できないことがありました。自分のルータとひかり電話ルータの間に置いた端末とは通信できるのでルータの設定に問題はないはずですが、なぜかひかり電話ルータを越えて外に出られませんでした。

ひかり電話ルータにWebブラウザで接続してDHCPv6-PDによるプレフィックスの払い出し状況を確認するとなぜかRaspberry PiのLAN側のMACアドレスが登録されていました。そこから推測するとひかり電話ルータは外からの通信を接続されていないRasPiのLAN側宛に送ってしまっているのではないかと推測しました。

RaspPiを何度再起動してDHCPv6-PDをしなおしても登録されているMACアドレスは変わりません。

そこで/etc/dhcpcd.duid/etc/dhcpcd.secretを削除して再起動してみました。するとひかり電話ルータに登録されているMACアドレスは変化ありませんでしたが問題なく外と通信できるようになりました。

DS-Liteによるトンネル作成

IPv6に関する設定は以上ですが、interfacesからeth1に関する設定を全て削除してしまったのでIPv4をトンネルするインターフェイスが作成されません。そこでdhcpcdが設定のフェーズ毎に実行する/etc/dhcpcd.enter-hook2にスクリプトを書いておいてトンネルを作成します。スクリプトが実行される時に設定される変数については、dhcpcd-run-hooksのマニュアルを参照して下さい。

/etc/dhcpcd.enter-hook

#!/bin/sh
# http://techlog.iij.ad.jp/contents/dslite-raspi

REMOTE='2404:8e01::feed:101'

WAN_IF='eth1'
TUN_IF='ip6tnl1'

dig_tunnel()
{
    #  already tunnel exist?
    ip addr show | grep $TUN_IF > /dev/null
    if [ $? -eq 0 ] ; then
	return
    fi

    LOCAL=`ip -6 addr show $WAN_IF scope global |grep inet6 | awk '{print $2}'`
    if [ "$LOCAL" = '' ]; then
	return
    else
	logger dig DS-Lite tunnel $WAN_IF $LOCAL === $REMOTE
    fi

    # IPIP6 tunnel linkup
    ip -6 tunnel add $TUN_IF mode ip4ip6 remote $REMOTE local $LOCAL dev $WAN_IF
    ip link set dev $TUN_IF up

    # IPv4 routing
    route delete default
    route add default dev $TUN_IF
}

delete_tunnel()
{
    ip addr show | grep $TUN_IF > /dev/null
    if [ $? -ne 0 ] ; then
	return
    fi

    logger delete DS-Lite tunnel
    # delete DS-Lite tunnel
    ip -6 tunnel delete $TUN_IF

    # delete default route
    route delete default
}


if [ "$interface" = $WAN_IF ] ; then
    if $if_up ; then
	case "$reason" in
	    BOUND6|REBIND6)
		dig_tunnel
		;;
	esac
    else
	if [ "$reason" = EXPIRE6 ] ; then
	    delete_tunnel
	fi
    fi
fi

参照と脚注

  1. 今回使ったdhcpd以外にもIPv6用のDHCPクライアントはいくつかありますが、dibblerWIDE-DHCPv6では上手くプレフィックスの委譲を受けることができませんでした。委譲はしてもらえていたのかも知れませんが、インターフェイスにアドレスが設定されませんでした。自分で設定する必要があったのかも知れません。

  2. dhcpcdは、/etc/dhcpcd.enter-hookだけでなく/etc/dhcpcd.exit-hookも実行します。しかし今回順番は関係ないので、トンネルの作成と破棄の両方共/etc/dhcpcd.enter-hookに書いています。

IPv6とIPv4のデュアルスタックで接続

ZOOT NATIVE (DS-Lite)でネット接続では、DS-Liteを使ってIPv4通信できることを確認しました。今回は、せっかくZOOT NATIVEがIPv6のIPoEなので、IPv4だけでなくIPv6でも通信できるようにします。

フレッツ光のひかり電話契約なしの場合は/64のプレフィックスしかもらえなので、自分のルータの下に自分のネットワークを置くにはこの方法しかありません。

ひかり電話契約ありの場合は、DHCPv6-PDによりもっと普通に自分のネットワークを置けます。このDHCPv6-PDを使った方法は、DHCPv6-PDでIPv6のサブネットワークを作成を参照して下さい。

Raspbianの設定は、ZOOT NATIVE (DS-Lite)でネット接続での状態になっている前提での説明です。

サイト構成

IPv6は事実上無限の数のIPアドレスを持つので、IPv6に接続したどんな機械でもユニークなIPアドレスを持つことができInternetから接続できます。ということなのですが、ひかり電話契約がない場合は、フレッツ光のひかり電話ルータがRAで配布するプレフィックスは/64となっています。そのためさらに下に別なネットワークを作る事ができません1

そこで今回は、IPv4と同じようにルータでNAPT(マスカレード)してルータ以下のネットワークを隠してIPv6の世界に接続します。このためInternetから自分のネットワーク内の端末へ簡単には接続できません2

自分のネットワーク内では、IPv4のプライベートアドレスに相当するユニークローカルアドレス(ULA)を使用します。今回はfd00::/64を自分のネットワークに使用することにしました。

Raspberry Piのインターフェイスは、次のように使用します。

インターフェイス ネットワーク アドレス
eth0 自分のネットワーク/64 fd00::1/64
eth1 Internet(IPoE) RAで自動設定

自分のネットワーク内の端末は、Raspberry Piが送信するRAで自動的にIPv6アドレスやデフォルトルータが設定されます。

ルータのアドレス指定

自分のネットワークへ入るルートを登録するため、eth0にIPv6のアドレスを割り当てます。

/etc/network/interfaces

# 追加する
iface eth0 inet6 static
 address fd00::1
 netmask 64

radvdをインストール

IPv4のDHCPサーバと同じように、IPv6ではルータ広告(RA)によって端末をネットワークに接続しただけで自動的にアドレスやデフォルトルートが設定されます。このためのサーバソフトがradvdです。

$ sudo apt-get install radvd

radvdが配布するRAの設定は/etc/radvd.conf/radvd.confに書きます。

interface eth0 {
  AdvSendAdvert on;
  #MaxRtrAdvInterval 30;
  #prefix ::/64 { でもOK?
  prefix fd00::/64 {
    AdvRouterAddr on;
  };
};

必要であればDNSの情報をRAで配布することも可能3ですが、今回はIPv4のDHCPに依存することにしました。

どんな内容のRAを送っているか(受信しているか)は、ルータ上で次のコマンドを実行することで確認できます。

$ sudo radvdump

ufwの設定

前回はIPv4のみだったのでDEFAULT_FORWARD_POLICYをACCEPTとして何でも転送を許可していましたが、今回は少し安全にするため通過できるパケットを制限します。制限するポリシーは次のとおりです。

  • 自分のネットワークから外へは無制限に出ていける。
  • 自分のネットワークへは、出て行ったパケットに関連するパケットのみが入れる。

そこで/etc/default/ufwを次のように変更し、許可されたパケット以外は全て破棄するようにします。

DEFAULT_FORWARD_POLICY="DROP"
DEFAULT_INPUT_POLICY="DROP"
DEFAULT_OUTPUT_POLICY="ACCEPT"

許可するパケットのルールは、ufwの設定ファイルに追加します。

/etc/ufw/before.rules

# 以下を追加する。
# accept all from LAN and returned RELATED or ESTABLISHED packets
-A ufw6-before-forward -i eth0 -j ACCEPT
-A ufw6-before-forward -m state --state RELATED,ESTABLISHED -j ACCEPT

/etc/ufw/before6.rules

# 以下を追加する。
# accept from LAN
-A ufw6-before-input -i eth0 -j ACCEPT

# accept all from LAN and returned RELATED or ESTABLISHED packets
-A ufw6-before-forward -i eth0 -j ACCEPT
-A ufw6-before-forward -m state --state RELATED,ESTABLISHED -j ACCEPT

さらにIPv6のパケットをNAPT(マスカレード)するための設定を/etc/ufw/before6.rulesに追加します。追加は、ファイルの最初または最後、要するに*filterとCOMMITに挟まれていない場所にします。

/etc/ufw/before6.rules

*nat
:POSTROUTING ACCEPT [0:0]

# Forward traffic through eth1
-A POSTROUTING -s fd00::/64 -o eth1 -j MASQUERADE

COMMIT

IPv6の転送を許可

IPv4だけでなく、IPv6も転送するように設定します。

/etc/ufw/sysctl.conf

# 追加する
net/ipv6/conf/default/forwarding=1
net/ipv6/conf/all/forwarding=1

net/ipv6/conf/eth1/accept_ra=2
net/ipv6/conf/eth1/accept_ra_pinfo=1
net/ipv6/conf/eth1/autoconf=1

forwardingを有効にすると上流ルータからのRAを無視してしまいます。そこで外につながっているeth1はaccept_raなどを有効にして、RAを受信して自動的にアドレスを設定するようにしています。

IPv6はインターフェイスのMACアドレスからアドレスが決定されます。そのためこのまま外のサイトに接続するとIPv6アドレスからどのメーカのネットワークカードまたはアダプタを使っているがバレてしまいます。これが嫌な時は、プライバシー機能を有効にして隠すことが可能です。

IPv6での通信確認

IPv6で通信するための設定は以上で終わりです。一度再起動して設定を反映させます。

IPv6とIPv4の両方で通信できているかは、次のサイトへWebブラウザでアクセすることで確認できます。

IPv6 test – IPv6/4 connectivity and speed test
IPv4とIPv6の両方で接続できるか調べられる。
あなたの IPv6 をテストしましょう。
IPv6で通信できているかを確認できる。
IIJmio IPv6スピードテスト(β)
IPv6での通信速度を測定できる。
The KAME project
IPv6で接続すると亀が動きます。

トラブルシューティング

接続できない時は、まずIPv6アドレスが割り振られているか確認します。Windowsでは、ipconfigコマンドを使用します。

$ ip -6 addr show
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 state UNKNOWN qlen 1
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: enp0s25: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 state UP qlen 1000
    inet6 2409::xxx:xxxx:xxx:xxx/64 scope global temporary dynamic 
       valid_lft 86165sec preferred_lft 14165sec
    inet6 2409::xxx:xxxx:xxx:xxx/64 scope global mngtmpaddr noprefixroute dynamic 
       valid_lft 86165sec preferred_lft 14165sec
    inet6 fe80::xxx:xxxx:xxx:xxx/64 scope link 
       valid_lft forever preferred_lft forever

IPv6アドレスが割り当てられていることが確認できたら、デフォルトルートが登録されていることを確認します。

$ netstat -rn6
カーネルIPv6 経路テーブル
Destination                    Next Hop                   Flag Met Ref Use If
2409:xxx:xxxx:xxx::/64        ::                         Ue   256 2     7 enp0s25
fe80::/64                      ::                         U    256 0     0 enp0s25
::/0                           fe80::xxx:xxx:xxx:xxx  UG   100 1     1 enp0s25
# 省略

ここで::/0で始まる行がデフォルルートで、送り先がわからない時はパケットをNext Hopのfe80::xxx:xxx:xxx:xxxに送ってどうにかしてもらいます。このアドレスがルータのものか確認します。

参照と脚注

ZOOT NATIVE (DS-LITE)でネット接続

  1. さらに下にネットワークを作らないでも、ひかり電話ルータに直接接続するだけでIPv6で通信することが可能です。ただこれだとパケットの制限をこのルータに依存するのが嫌だな…と。

  2. NAPTでも外から自分のネットワーク内の端末に接続で可能です。その時は、IPv4の時と同じように特定ポートへの通信を特定の端末に転送させるように設定します。これで外部にサーバを公開する事が可能です。

  3. RAでDNSの情報を配布する場合は、RDNSSとDNSSLの設定をradvd.confに追加します。

ZOOT NATIVE (DS-Lite)でネット接続

インターリンク(Interlink)がZOOT NATIVEというIPv6 IPoEサービスを開始しました。この方式にするとIPv4のPPPoEよりも速くなる(遅くならない)という話なので試してみました。

ZOOT NATIVEは基本的にIPv6のサービスですが、今回はトンネルを作成してIPv4でInternetに接続してみます。

IPv6で通信するための設定方法は、IPv6とIPv4のデュアルスタックで接続にあります。この方法は、ひかり電話契約のないユーザにオススメの方法です。ひかり電話契約がある場合は、DHCPv6-PDでIPv6のサブネットワークを作成のように素直にネットワークを接続する方法もあります。

環境

  • フレット光ネクスト ファミリー・ハイスピードタイプ(NTT西日本)
  • ひかり電話オプション契約あり
  • Raspberry Pi B+ Raspbian(Debian jessei)

Raspberry Piの内蔵Ethernet(eth0)にLANを接続し、USB 2.0接続の100BASE-TX Ethernetアダプター(eth1)にフレッツ光ネクストのルータ(PPPoEブリッジ機能を有効)を接続しています。

パソコンのUbuntu 16.04でも、ここで紹介した方法で接続できました。

ZOOT NATIVEの申し込み

申し込みは、インターリンクのWebページから簡単に行えました。ただし事前に次のものを準備しておく必要があります。

  • クレジットカード
  • フレッツ光のお客様IDとアクセスキー1

4月5日の朝に申し込んで、翌4月6日の朝に使用できるようになったというメールが届きました。

設定方法

Raspberry Piを通信の中継だけでなく一般的な市販ルータが持つDNS機能とアドレスの自動割当機能を持たせます。そのためIPv6上でIPv4を使うDS-Liteトンネルの作成以外に、DNSやDHCPサーバ用の設定が入っています。

DNS(unbound)をインストール

まず最初にLANのDNS(キャッシュ)となるunboundをインストールします。ISPのDNSを使用できるならば、このステップは不要です。

$ sudo apt-get install unbound

unboundは、/etc/unbound/unbound.conf.d/にある*.confを起動時に設定ファイルとして読み込みます。そこでunbound-local.confというファイルを作成して設定を書き込みます。

/etc/unbound/unbound.conf.d/unbound-local.conf

server:
    #interface: 0.0.0.0
    interface: 127.0.0.1
    interface: 10.0.0.254
    access-control: 10.0.0.0/24 allow

IPv6のアドレスにはbindしないで、LANと自分自身からの問い合わせにのみ答えるようにしました。

ルータのアドレスを固定

ルータのIPv4アドレスは、LAN内のデフォルトルートとなるので固定されている必要があります。そこでDHCPクライアントを停止して、LANに接続しているeth0のIPv4アドレスを指定します。

まずはDHCPクライアントを停止します2

$ sudo systemctl stop dhcpcd.service
$ sudo systemctl disable dhcpcd.service

固定アドレスは、/etc/network/interfacesに設定ます。アドレスと同時にルータ自身が参照するDNS(自分自身)を指定します。

auto lo
iface lo inet loopback

auto eth0
iface eth0 inet static
 address 10.0.0.254
 netmask 255.255.255.0
 dns-nameservers 127.0.0.1
 dns-search example.jp

これで再起動してもアドレスは変わらず、常に同じIPv4アドレスを使うようになります。

トンネルの出口確認

IPv4で通信できるようにするDS-Liteトンネルの設定には、トンネルの出口に当たるゲートウェイ(AFTR3)のIPv6アドレスが必要です。

AFTRのIPv6アドレスは、NVR510の設定マニュアルに書かれていました。ただしこのアドレスは固定ではなく予告なく変更されることがあるそうなので、接続できなくなった場合は設定を変更する必要があります4

私はNTT西日本を使っているので、AFTRとして2404:8e01::feed:100または2404:8e01::feed:101を使用します。

実際にAFTRと通信できるかping6コマンドで確認しておきます。

$ ping6 -c 2 2404:8e01::feed:100
PING 2404:8e01::feed:100(2404:8e01::feed:100) 56 data bytes
64 bytes from 2404:8e01::feed:100: icmp_seq=1 ttl=58 time=5.26 ms
64 bytes from 2404:8e01::feed:100: icmp_seq=2 ttl=58 time=4.97 ms

--- 2404:8e01::feed:100 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1001ms
rtt min/avg/max/mdev = 4.978/5.120/5.262/0.142 ms

ufwをインストール

ルータなので不要な通信を制限します。そのため通信を制限するufwをインストールします。ufwを使用しない場合は、IPv4をインターフェイス間で転送するように/etc/sysctl.confを編集してIPv4をルーティングするようにします。

$ sudo apt-get install ufw

/etc/ufw/ufw.conf

ENABLED=yes

# allow ssh connection
# これがないとRaspberry PiにLANからsloginできなくなる。
ufw allow 22/tcp

IPv4をルーティングするように設定します。また必要ならば不要な通信を制限する設定を追加します。

/etc/ufw/sysctl.conf

net/ipv4/ip_forward=1

/etc/default/ufw

DEFAULT_FORWARD_POLICY="ACCEPT"
DEFAULT_INPUT_POLICY="DROP"
DEFAULT_OUTPUT_POLICY="ACCEPT"

転送ルーティングのポリシーをACCEPTにすることは通常危険ですが、トンネル出口でアドレス変換が行われていて外から入ってくる通信はないので良いことにしました5

ufwの自分宛ルーティングポリシーはDROPとなっています。そこで/etc/ufw/before.rulesを編集して、LANからDNS(port 53)への通信を許可する次のルールを最後のCOMMITの前に追加します。

# 以下を追加する。
# Accpet for DNS from LAN
-A ufw-before-input -i eth0 -p udp --dport 53 -j ACCEPT
-A ufw-before-input -i eth0 -p tcp --dport 53 -j ACCEPT

ufwの設定がすんだら、DS-LiteでIPv4をトンネルするために必要なモジュールを起動時に読み込むように設定ます。

/etc/modules

ip6_tunnel

ここまできたら、一旦再起動して設定を反映させておきます。

DS-Liteトンネルを作成

DS-Liteトンネルは、DS-Lite(RFC6333)対応ルータをLinux (Raspberry Pi) で作るのシェルスクリプトを使って作成します。

/etc/network/dig-tunnel.sh

#!/bin/bash
# Ref. http://techlog.iij.ad.jp/contents/dslite-raspi

# gw.transix.jp
REMOTE='2404:8e01::feed:100'

#IFACE='eth1'
IFACE=$1

# get my IPv6 address
for i in $(seq 0 9); do
 LOCAL=`ip -6 addr show $IFACE scope global |grep inet6 | awk '{print $2}'`
 if [[ $LOCAL != '' ]]; then
  break
 fi

 sleep 1
done

if [[ $LOCAL == '' ]]; then
 exit
else
 echo $LOCAL
fi

# IPIP6 tunnel linkup
ip -6 tunnel add ip6tnl1 mode ip4ip6 remote $REMOTE local $LOCAL dev $IFACE
ip link set dev ip6tnl1 up

# IPv4 routing
route delete default
route add default dev ip6tnl1

それでは実際にスクリプトを起動してトンネルを掘ってみます。

$ sudo ifconfig up eth1
$ sudo /etc/network/dig-tunnel.sh eth1

トンネルが掘れているか確認します。

$ ip addr show
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether b8:xx:xx:xx:xx:xx brd ff:ff:ff:ff:ff:ff
    inet 10.0.0.254/24 brd 10.0.0.255 scope global eth0
       valid_lft forever preferred_lft forever
    inet6 fe80::xxxx:xxxx:xxxx:xxxx/64 scope link 
       valid_lft forever preferred_lft forever
3: ip6tnl0@NONE: <NOARP> mtu 1452 qdisc noop state DOWN group default qlen 1
    link/tunnel6 :: brd ::
4: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 00:xx:xx:xx:xx:xx brd ff:ff:ff:ff:ff:ff
    inet6 2409:xxx::xxxx/64 scope global mngtmpaddr dynamic 
       valid_lft 14125sec preferred_lft 12325sec
    inet6 fe80::xxxx:xxxx:xxxx:xxxx/64 scope link 
       valid_lft forever preferred_lft forever
5: ip6tnl1@eth1: <POINTOPOINT,NOARP,UP,LOWER_UP> mtu 1452 qdisc noqueue state UNKNOWN group default qlen 1
    link/tunnel6 2409::xxx peer 2404:8e01::feed:100
    inet6 fe80::xxxx:xxxx:xxxx:xxxx/64 scope link 
       valid_lft forever preferred_lft forever

$ netstat -r
Kernel IP routing table
Destination     Gateway         Genmask         Flags   MSS Window  irtt Iface
default         *               0.0.0.0         U         0 0          0 ip6tnl1
10.0.0.0        *               255.255.255.0   U         0 0          0 eth0

$ ping -c 2 www.yahoo.co.jp
PING edge.g.yimg.jp (183.79.248.252) 56(84) bytes of data.
64 bytes from 183.79.248.252: icmp_seq=1 ttl=59 time=4.35 ms
64 bytes from 183.79.248.252: icmp_seq=2 ttl=59 time=4.92 ms

--- edge.g.yimg.jp ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1003ms
rtt min/avg/max/mdev = 4.357/4.640/4.924/0.291 ms

トンネルの自動作成

問題なく接続できることを確認したら、起動した時に自動的にトンネルを掘ってルータとして機能するようにします。

トンネル作成は、/etc/network/interfacesに設定ます。

# これまでの設定に追加
auto eth1
iface eth1 inet manual
 pre-up /sbin/ifconfig eth1 up
 post-up /etc/network/dig-tunnel.sh eth1

ここで再起動して自動的にトンネルが掘れているか確認します。

DHCPサーバをインストール

最後にLAN内の端末を自動設定できるようにDHCPサーバをインストールします。

$ sudo apt-get install isc-dhcp-server

/etc/default/isc-dhcp-server

# eth0(LAN)にのみDHCPサーバとして働く。
#INTERFACES=""
INTERFACES="eth0"

/etc/dhcp/dhcpd.conf

#option domain-name "example.org";
#option domain-name-servers ns1.example.org, ns2.example.org;
option domain-name "example.jp";
option domain-name-servers 10.0.0.254;
option routers 10.0.0.254;

subnet 10.0.0.0 netmask 255.255.255.0 {
  pool {
    range 10.0.0.1 10.0.0.10;
  }
}

通信速度を測定

Raspberry Pi B+をルータとしたDS-Lite接続でどのくらいの速度が出るかBNRスピードテストでテストしてみました。

Ras Pi Ubuntu 16.04 IPv4 PPPoE
22.53Mbps(n=3) 91.02Mbps(n=6) 88.54Mbps(n=2)

テストは一番スピードが出ると予想される早朝に測定しました。Ras PiとUbuntu 16.04はZOOT NATIVEで、IPv4 PPPoEはZOOT NEXTの結果です。

Raspberry Pi B+をルータにした場合は、USB 2.0接続のEthernetアダプターが100BASE-TXのためかCPUの性能が律速なのか、DS-Liteトンネルの性能をフルには発揮できていないようです。

フレッツ光ネクストのハイスピードタイプはPPPoEの通信速度に制限がかけられているという話で、DS-Liteにするとその制限がなくなり本来のIPv6による通信速度に近づくという話でした。しかし今回は、DS-Liteによる通信では、期待されたPPPoEを大きく越えるような高速な通信はできませんでした。

DS-LiteトンネルとPPPoEであまり差がなかった原因は、ルータにしているパソコンの性能が律速になっている可能性はあります。しかしこのパソコンはCore 2 Duoマシンで、速度測定中の負荷を見てもそれほど忙しくしているようには見えません。

ZOOT NATIVEはオススメ?

スピード命で固定のIPv4アドレスが不要ならば、ZOOT NATIVEオススメかな。でも積極的にZOOT NEXTから乗り換えるという程でもないかな。

ゴールデンタイムはZOOT NATIVEの圧勝

残念ながら私の環境ではPPPoEを大きく越える通信速度は見られませんでした。ただしDS-Liteによるトンネルのメリットは、最高速度だけでなくゴールデンタイムでも通信速度が低下しないという点です。

多くの人がネットを使うだろう土曜日の夜にZOOT NEXT(PPPoE)とZOOT NATIVE(IPoE + DS-Lite)で通信速度を測定してみました。なおルータにはRaspberry Piではなく、Ubuntu 16.04マシンを使用しています。

回線 平日の早朝 土曜日の夜
ZOOT NEXT 98.6Mbps(n=3) 3.37Mbps(n=8)
ZOOT NATIVE 83.4Mbps(n=3) 86.8Mbps(n=8)

このようにPPPoEであるZOOT NEXTに見られた夜間の速度低下が全く見られませんでした。信じられなくて、NETXとNATIVEを交互に8回も測定してしまいました。ただし速度低下が見られなかったのは、まだサービス開始から時間が経っていないのユーザが少ないからという可能性があります。

ZOOT NEXTのままで十分

ZOOT NATIVEの欠点は、IPv4の固定アドレスオプションが無いことです。また接続料金が倍になります。

ZOOT NEXT ZOOT NATIVE
1,080円 2,160円

現在の通信速度に問題があるならば、料金が倍になったとしてもこれよりも高い設定のISPは普通にあるので乗り換える価値は非常にあります。しかし夜間に通信速度が低下するとは言っても、Huluなどで動画を見るのに全く支障がありません6。今回測定してみて初めてこんなに速度が低下するのかと気がついたくらいです。

そうすると普通に使える速度なら満足でIPv6の通信が不要なうちは、積極的にZOOT NATIVEに切り替える理由は見当たらない気がします。ZOOT NATIVEは常にフルスピードを求めるユーザ向けということでしょうか。せっかく2ヶ月の無料体験期間を設けてくれているのにごめんなさい。

参照と脚注

  1. フレッツ光のお客様IDとアクセスキーは、フレッツ光を申し込んだ時の書類に記載されていました。

  2. 単純に固定アドレスを使いたいだけの場合は、DHCPクライアントを停止する必要はありません。/etc/dhcpcd.confに固定アドレスを使用するための設定を加えるだけで十分です。今回は、トンネルを掘るシェルスクリプトを起動したかったのでこのようにしました。

  3. AFTRは、Address Family Transition Routerの略。

  4. AFTRのIPv6のアドレスが変わった時、IPv6での通信だけで新しいAFTRを探せるのかな?

  5. 外から入ってくる通信は、全て出て行った通信への返信なのでルータを通過させて問題はない。

  6. ZOOT NEXTとAsahiNetは問題ありませんが、WakWakを使っていた時は非常に通信速度が落ちて動画配信サービスをまともには使えませんでした。

MongoDB 3.2(stable)をUbuntu 16.04にインストール

現在(2016年6月10日)MongoDB 3.xのUbuntu 16.04用のパッケージは、MongoDBから提供されていません。そのためUbuntu 14.04用のパッケージを使うことによる問題で、16.04用のパッケージが公開された時には解決しているはずです。

2016年8月26日:Ubuntu 16.04用のパッケージが提供されています。そのためもうsystemd用の起動設定ファイルを作成する必要はありません。

これまでUbuntu 14.04でMongoDBを運用してきましたが、新しいLTSであるUbuntu 16.04にアップグレードしたらmongodが起動しなくなってしまいました。

ここではUbuntu 16.04にMongoDB 3.2(stable)をインストール(アップグレード)する手順と、使用できるようにするまでのworkaroundを説明します。

MongoDB 3.2のインストール

MongoDBをアップグレードする場合は、データと/etc/mongod.confをバックアップしておきます。

MongoDBのインストール方法は、MongoDBが公開しているInstall MongoDB Community Editionに基づいて行います。

まず改変されていないか確認するための鍵を登録します。この鍵は、以前と変わっているので、アップグレードの場合も必要です。

$ sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv EA312927

次にパッケージのレポジトリを登録します。ここで3.2というバージョン指定をstableに変更すると、MongoDB 3.3が安定版になったらそのままアップグレードされ、常に最新の安定版MongoDBを使用できるようになります。

$ echo "deb http://repo.mongodb.org/apt/ubuntu trusty/mongodb-org/3.2 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-3.2.list
$ sudo apt update

実際にMongoDBをインストールします。アップグレードの場合は、mongodb-orgだけでなくそのメタパッケージが指すパッケージ群を指定しないとアップグレードできません1

# 新規インストールの場合
$ sudo apt install mongodb-org

# アップグレードの場合
$sudo apt install mongodb-org mongodb-org-mongos mongodb-org-server mongodb-org-shell mongodb-org-tools

本来ならばこれでmongodが起動するはずですが、起動ファイル(systemdの設定)が存在しないので自動では起動しません。たぶんUbuntu 16.04用のパッケージが公開されれば修正されるはずです。

mongodを自動起動させるworkaround

Ubuntu16.04用のパッケージが用意されているので、起動設定ファイルの作成ステップは不要です。Ubuntu 16.04用パッケージでは、起動用設定ファイルが/lib/systemd/system/mongod.serviceに作成されます。

mongodが起動しないのは、インストールしたパッケージがUbuntu 14.04用なのでUbuntu 16.04で自動起動させるために必要なsystemd設定が無いからです2

そこでsystemd用の起動設定ファイルmongodb.serviceRunning mongodb on ubuntu 16.04 LTSを参考にして作成します。

$ cat /etc/systemd/system/mongod.service
[Unit]
Description=MongoDB Database Service
Wants=network.target
After=network.target

[Service]
ExecStart=/usr/bin/mongod --config /etc/mongod.conf
ExecReload=/bin/kill -HUP $MAINPID
Restart=always
User=mongodb
Group=mongodb
StandardOutput=syslog
StandardError=syslog

[Install]
WantedBy=multi-user.target

mongod.serviceを作成したら、起動するか確認しておきます。

$ sudo systemctl start mongod
# or
$ sudo service mongod start

$ sudo systemctl status mongod
# or
$ sudo service mongod status
● mongod.service - MongoDB Database Service
   Loaded: loaded (/etc/systemd/system/mongod.service; disabled; vendor preset: 
   Active: active (running) since 金 2016-06-10 09:47:06 JST; 7s ago
 Main PID: 1479 (mongod)
   CGroup: /system.slice/mongod.service
           └─1479 /usr/bin/mongod --config /etc/mongod.conf

 6月 10 09:47:06 rerun systemd[1]: Started MongoDB Database Service.

起動することが確認できたら、自動起動するようにしておきます。

$ sudo systemctl enable mongod
Created symlink from /etc/systemd/system/multi-user.target.wants/mongod.service to /etc/systemd/system/mongod.service.

mongoコマンドの警告表を止める方法

mongoコマンドでサーバに接続すると次のような警告メッセージが表示されることがあります。

$ mongo
MongoDB shell version: 3.2.7
connecting to: test
Server has startup warnings: 
2016-06-10T08:19:18.872+0900 I CONTROL  [initandlisten] 
2016-06-10T08:19:18.872+0900 I CONTROL  [initandlisten] ** WARNING: /sys/kernel/mm/transparent_hugepage/enabled is 'always'.
2016-06-10T08:19:18.872+0900 I CONTROL  [initandlisten] **        We suggest setting it to 'never'
2016-06-10T08:19:18.872+0900 I CONTROL  [initandlisten] 
2016-06-10T08:19:18.872+0900 I CONTROL  [initandlisten] ** WARNING: /sys/kernel/mm/transparent_hugepage/defrag is 'always'.
2016-06-10T08:19:18.872+0900 I CONTROL  [initandlisten] **        We suggest setting it to 'never'
2016-06-10T08:19:18.872+0900 I CONTROL  [initandlisten] 

この場合は、Disable Transparent Huge Pages (THP)を参考にしてkernelのtransparent huge pages機能を無効にします。

機能を無効にするには、/etc/rc.localにkernelの仮想設定ファイルに設定を書き込む命令を加えます。参照したページのように起動ファイルを作成したら、実行される順番によるのか警告を止めることができませんでした。

具体的には、/etc/rc.localexit 0の前に次の文を加えます。

if [ -d /sys/kernel/mm/transparent_hugepage ]; then
    echo never > /sys/kernel/mm/transparent_hugepage/enabled
    echo never > /sys/kernel/mm/transparent_hugepage/defrag
fi

PHPのmongoライブラリ

Ubuntu 16.04では、PHP7が標準になりました。そのためmongodbライブラリをpeclコマンドでインストールすると、次のようなエラーが出てインストールできません。

$ sudo pecl install mongo
WARNING: "pecl/mongo" is deprecated in favor of "channel:///mongodb"
pecl/mongo requires PHP (version >= 5.3.0, version <= 5.99.99), installed version is 7.0.4-7ubuntu2.1
No valid packages found
install failed

そこで素直にパッケージに入っているmongoライブラリをインストールします。

$ sudo apt install php-mongo

脚注

  1. メタパッケージをアップグレードすれば、自動的にメタパッケージでインストールパッケージ群もアップグレードされるのだとずっと考えていました。

  2. Ubuntu 16.04ではsystemdがデーモンを起動させますが、Ubuntu 14.04ではUpstartが起動させていました。そのためUbunt 14.04用のパッケージにはsystemdで必要な設定ファイルが含まれていません。
    systemdに置き換えられたのは15.04からなので、Ubuntu 15.04と15.10でも同じ問題が発生します。

Raspbian(jessi)でのIPアドレスの固定とresolv.conf設定

Debian(Raspbian)のjessieでIPアドレスを固定する方法とresolv.confファイルの設定方法

Debian(Raspbian)では、jessieからネットワーク周りの設定方法が変わりました。そのためDHCPではなくIPアドレスを固定して使用する方法と、関連してresolv.confファイルの設定でこれまでの経験が使えなくなってしまいました。

ここではDebian(Raspbian) jessieでIPアドレスを固定する方法と、resolv.confファイルの設定する方法をメモしておきます。

設定はdhcpcd.confで

Debian(Raspbian) jessieでは、ネットワーク周りの設定は/etc/dhcpcd.confファイルで行います。/etc/network/interfaces/etc/resolv.confファイルを編集してもdhcpcdにより上書きされてしまいます。

IPアドレスを固定する方法

DHCPサーバからIPアドレスをもらって設定するのではなく、指定したIPアドレスを使いたい場合は、dhcpcd.confに次の設定を加えます。

interface eth0
static ip_address=10.0.0.130/24
static routers=10.0.0.254

この設定によりeth0に10.0.0.130(netmask 10.0.0.255)というIPアドレスが設定されます。またstatic routersにより、デフォルトルータに10.0.0.254が指定されます。

$ ip addr show eth0
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether b8:27:XX:XX:XX:XX brd ff:ff:ff:ff:ff:ff
    inet 10.0.0.130/24 brd 10.0.0.255 scope global eth0
       valid_lft forever preferred_lft forever
    inet6 fe80::XXXX:XXX:XXXX:XXXX/64 scope link 
       valid_lft forever preferred_lft forever

$ netstat -rn
Kernel IP routing table
Destination     Gateway         Genmask         Flags   MSS Window  irtt Iface
0.0.0.0         10.0.0.254      0.0.0.0         UG        0 0          0 eth0
10.0.0.0        0.0.0.0         255.255.255.0   U         0 0          0 eth0

resolv.confの設定

上の設定を完了すればIPアドレスを指定して通信することが可能です。しかしホスト名を指定して通信するには、DNSに問い合わせてホスト名をIPアドレスに変換できなければなりません。そのための設定ファイルがresolv.confです。

resolv.confファイルにDNSのアドレスや自分のドメイン名を設定するには、dhcpcd.confに次の設定を加えます。

static domain_name_servers=10.0.0.123 10.0.0.234
static domain_name=nosuz.jp
#static domain_search=sample.jp

この設定により名前解決する時には10.0.0.123と10.0.0.234のDNSに問い合わせるようになります。またホストを指定する時にドメイン名まで指定する必要がなくなり、hostnameを指定するとdomain_nameで指定したドメイン名を付けてDNSに問い合わせるようになります。

domain_searchを設定すると、domain_nameに指定したホスト名が見つからない場合には、domain_searchで指定した別のドメイン名にないか調べるようになります。

ヘッドレスRaspberry PiにRaspbian(jessie)をインストール

ディスプレイ等を接続しないでRaspberry Pi 2にRaspbian(jessie)をインストールしました。固定IPアドレスを使用するには、dhcp.confに設定します。

ディスプレイやキーボードが接続されていないヘッドレスRaspberry PiへRaspbian1をインストールする方法は、設定をネットワークから行うだけで基本的な手順はディスプレイ等が接続されたRaspberry Piへのインストールと同じです。

必要な物

Raspberry Pi本体
今回は、Raspberry Pi2を使用しました。
USB-ACアダプタ
急速充電対応のアダプタをオススメ。特にRaspberry Pi3を使用するときには、取れる電流値に注意する必要があります。
SDメモリカード
Raspberry Pi2以降は、マイクロSDカードを使用します。容量は最低4GBとなっていますが、私の4GBカードはOSイメージが入りきりませんでした。値段は大して変わらないので、8GBを使用することをオススメします。また、できればClass 10の製品を使ったほうがファイルへのアクセス速度が上がります。
ネットワーク
いきなり無線LANで接続するよりは、有線でまずつないでインストールすることをオススメします。
OS
今回Raspbian (jessie)をインストールします。取得方法などは、この後に説明します。
またOSのイメージファイルをSDカードに書き込むためにパソコンが必要です。私はUbuntu 16.04が動いているマシンを使用しましたが、Windowsでもイメージを直接書き込めるソフト2を使用すれば問題ありません。

Raspbianの取得

Raspbianは、公式サイトのダウンロードページまたは国内のミラーサイトからダウンロードします。国内のミラーサイトを使用したほうが、もちろん早くダウンロードが完了します。

ダウンロードが完了したら、ファイルが壊れていないか(改変されていないか)SHA-1フットプリントを見て一応確認しておきます。

$ sha1sum 2016-05-10-raspbian-jessie.zip 
66a50545358e80229d77ebba89ab01f1c0fb4a02  2016-05-10-raspbian-jessie.zip

この値が、公式サイトに書かれているSHA-1の値と同じになっているはずです。もし違っているときには壊れているので捨てます。問題なければ解凍してディスクイメージを取り出します。

$ sudo apt install zip
$ zipinfo -1 2016-05-10-raspbian-jessie.zip
2016-05-10-raspbian-jessie.img
$ unzip 2016-05-10-raspbian-jessie.zip

SDメモリカードへの書き込み

ディスクイメージのファイルを取り出せたら、SDメモリカードに書き込みます。この時普通のコピーではなく、ddまたはddrescueを使用してブート領域の部分から直接上書きします。

# `usb-Multi_Flash_Reader_058F0O1111B1-0\:0`の部分は、SDメモリカードリーダ(アダプタ)に依って変わります。

$ sudo dd bs=4M if=2016-05-10-raspbian-jessie.img of=/dev/disk/by-id/usb-Multi_Flash_Reader_058F0O1111B1-0\:0

# or

$ sudo apt install ddrescue
$ sudo ddrescue 2016-05-10-raspbian-jessie.img /dev/disk/by-id/usb-Multi_Flash_Reader_058F0O1111B1-0\:0

このコマンドを実行する時に/(root)のあるドライブを上書きしてしまう可能性があります。そのミスを防ぐために/dev/sd*ではなく、/dev/disk/by-id/usb-*を使用します。これならば、USB接続のストレージだと一目で分かります。

またddを使用した場合は、途中で進行状況が表示されません。進行状況を確認するには、別の端末から

$ pkill -USER1 dd

を実行して進行状況を表示させるシグナルを送ります。

Raspbianを起動

ディスクイメージをSDメモリカードに書き込んだら、Raspberry Piにセットして通電します。

電源が入ると赤と緑のLEDが両方共点灯します。その後一瞬緑のLEDが消えた後に細かく点滅を繰り返します。緑のLEDはディスク(SDメモリカード)アクセスを示しているので、ブートプロセスが完了すると大体の時間消灯するようになります。

ブートプロセスが完了したらDHCPサーバまたはルータのログを確認して、このRaspberry Piが使用しているIPアドレスを探します。

ログなどを調べられない場合は、IPアドレスの範囲をスキャンして当たりをつけます。この例では、10.0.0.1から10.0.0.126の範囲内で反応するIPアドレスを見つけます。

$ for i in {1..126}; do echo $i; ping -c 1 -W 1 10.0.0.$i >/dev/null && echo 10.0.0.$i; done

Raspberry Piが使用しているIPアドレスが分かったら初期ユーザでログインします。例えば10.0.0.4を使っているとすると、次のようにログイン名を指定して接続します。WindowsのTeraTermでも同じ書き方で接続アドレスとユーザ名を指定できます。

$ slogin pi@10.0.0.4
# 初回は本当に接続するか確認を求められるので、`yes`と入力して続行します。
pi@10.0.0.4's password: # 初期パスワードは`raspberry`となっています。

ログインできれば、後はヘッドレスもディスプレイ等を接続したRaspberry Piもすることは同じです。

固定IPアドレスの設定

Jessieでは、固定IPアドレスを使用する設定を/etc/dhcpcd.confに設定を書き込みます。これまでは/etc/network/interfacesに設定していましたが、変更されています。

固定IPアドレスを使用するには、man dhcpcd.confを参考にして/etc/dhcpcd.confの最後に次の設定を書き加えます。

interface eth0
static ip_address=10.0.0.130/24
static routers=10.0.0.254
static domain_name_servers=10.0.0.127 10.0.0.254

セットアップ

新規ユーザ登録

まずはadduserコマンドで自分のアカウントを作成します。パスワードや名前などを質問されるので、それに答えて入力していきます。

$ adduser nosuz
Adding user `nosuz' ...
Adding new group `nosuz' (1001) ...
Adding new user `nosuz' (1001) with group `nosuz' ...
Creating home directory `/home/nosuz' ...
Copying files from `/etc/skel' ...
Enter new UNIX password: 
Retype new UNIX password: 
passwd: password updated successfully
Changing the user information for nosuz
Enter the new value, or press ENTER for the default
	Full Name []: 
	Room Number []: 
	Work Phone []: 
	Home Phone []: 
	Other []: 
Is the information correct? [Y/n] 

新しく追加したユーザが管理者権限で色々できるようにするため、/etc/sudoersに次のエントリーを追加しておきます。

#nosuz ALL=(ALL) NOPASSWD: ALL
nosuz ALL=(ALL) ALL

NOPASSWD:を指定すると、自分のパスワードを確認されずにコマンド(ここでは全てのコマンド)を管理者権限で実行できます。どちらにするかは、各サイトのセキュリティプリシーによります。

新しいユーザでログインして管理者権限を使えることを確認したら、ユーザ登録作業は完了です。

デフォルトユーザpiの削除

Raspbianにはpiというユーザがいることが公開されておりブルートフォース攻撃の標的になるので、ユーザpiを削除しておきます。

まず/etc/sudoersを編集してユーザpiのエントリーを削除しておきます。削除しなくても良いのですが、後々piというユーザを作成して意図しないで管理者権限で操作できてしまうことを防ぎます。

ユーザを削除するには、deluserコマンドを使用します。piでログインしている場合は、事前にログアウトしておきます。

$ sudo deluser --remove-home pi
Looking for files to backup/remove ...
Removing files ...
Removing user `pi' ...
Warning: group `pi' has no more members.
Done.

ソフトのアップデート

パッケージのダウンロードを速くするために、Raspbianのmirrorサイト3を参考にして近場のサイトからダウンロードするようにapt edit-sourcesコマンドで/etc/apt/sources.listの内容を変更します。直接ファイルを編集しても問題ありませんが、この方法だと書式に問題が有ると教えてくれます。

$ sudo apt edit-sources
# 初回はエディタの選択メニューが表示されます。

$ cat /etc/apt/sources.list
#deb http://mirrordirector.raspbian.org/raspbian/ jessie main contrib non-free rpi
deb http://ftp.yz.yamagata-u.ac.jp/pub/linux/raspbian/raspbian/ jessie main contrib non-free rpi
# Uncomment line below then 'apt-get update' to enable 'apt-get source'
#deb-src http://archive.raspbian.org/raspbian/ jessie main contrib non-free rpi

$ sudo apt update && sudo apt full-upgrade

# Raspberry Piのファームウェアをアップデート。しばらく時間がかかります。
$ sudo rpi-update

ディスク領域の拡張

SDメモリーカードの全領域をRaspbianから使えるようにするには、raspi-configコマンドでパーティションを拡張します。

$ sudo raspi-config
┌─────────┤ Raspberry Pi Software Configuration Tool (raspi-config) ├─────────┐
│                                                                             │
│    1 Expand Filesystem             Ensures that all of the SD card          │
│    2 Change User Password          Change password for the default          │
│    3 Boot Options                  Choose whether to boot into a de         │
│    4 Wait for Network at Boot      Choose whether to wait for netwo         │
│    5 Internationalisation Options  Set up language and regional set         │
│    6 Enable Camera                 Enable this Pi to work with the          │
│    7 Add to Rastrack               Add this Pi to the online Raspbe         │
│    8 Overclock                     Configure overclocking for your          │
│    9 Advanced Options              Configure advanced settings              │
│    0 About raspi-config            Information about this configura         │
│                                                                             │
│                                                                             │
│                    <Select>                    <Finish>                     │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

# メニューの一番を選択します。上下の矢印で移動させて、1のところで`Enter`キーを押すと選択されます。

# `Tab`キーで`Finish`に移動して`Enter`キーを押すとrebootするか聞かれるので、再起動します。
# 再起動したら、`df -h`コマンドでディスク領域が拡張していることを確認します。

終了

終了するときは、次のコマンドで安全に終了させます4

$ sudo shutdown -h now

このコマンドを実行すると緑色LEDがしばらく点滅します。この点滅が収まり緑色LEDが消灯したら、10秒ほど見守ってもう点滅することがないのを確認して電源を切ります。

-hオプションの代わりに-rを指定するとリブートします。

参照と脚注

  1. Rasbianと間違えやすいのですが、Raspbianとbの前にpが入ります。間違えるのは私だけ?

  2. Win32DiskImagerやDD for Windowsなどを使用します。

  3. Raspbian Mirrors 私は山形大学のミラーを使用しています。

  4. もっとも電源をいきなり切っても大抵問題になりません。

PT2で地デジと衛星放送を録画

chardev版のPT2ドライバをUbuntu 16.04にインストールしてテレビ放送(地デジ)を録画できるようにしました。以前は録画できるようになるまで結構苦労した気がするのですが、今回はすんなると簡単に録画サーバになりました。

これまでUSB接続の地デジチューナーを使用していましたが、しばらく前に壊れて録画できなくなっていました。しかしサーバを新しくセットアップしたので、改めて録画サーバ機能をセットアップしました。

いくつかの地デジチューナーを使用できるようですが、今回はあまり手間を掛けたくなかったので、デファクトスタンダードなPT2を使用することにしました。PT2はPCIバス接続という制限がありますが枯れたカードで、思いの外すんなりと必要なソフトをインストールすることができました。

構成

OS Ubuntu 16.04
チューナーカード PT2 Rev. B
ICカードリーダー SCR3310-NTTCom
B-CASカード 地デジ専用または衛星放送対応
チューナーカード
Linuxで使用できるチューナーカードはいくつかありますが、デファクトスタンダードはアースソフトのPT2とPT3です。しかしPT2はとっくに製造が終了しており、PT3も製造終了1となってしまいました。そのため最近はプレミア価格でPT3がヤフオクに出回っています。
今回は、手頃な価格で中古が手に入るPT2を使用しました。ただしこのカードは現在一般的なPCI Expressではない前世代のPCIバスに接続するので、購入前にPCIカードを取り付けられるか確認しておく必要があります。
B-CASカード
地デジ放送や衛星放送を視聴するには、テレビで視聴するときと同じようにそれぞれに対応したB-CASカードが必要です。PT2(PT3)にはこのカードが付属しません。そのためテレビやレコーダから抜いてくるか、B-CASカード付きのチューナーを別に購入する必要があります。
ICカードリーダ
B-CASカードの情報を読み取るために、USB接続の接触型ICカードリーダが必要です。
今回は以前から使用しているSCR3310-NTTComを使用しましたが、現在はこちらも製造終了しているようです。こちらも中古が結構流通しているようですが、別のICカードリーダーも結構な確率で使用できそうです。

ソフトのインストール

ICカードリーダーのパッケージをインストール

まずICカードリータのパッケージをインストールします。

$ sudo apt install pcscd pcsc-tools

# B-CAS を認識できるか確認
$ pcsc_scan

...
Japanese Chijou Digital B-CAS Card (pay TV)

pcsc_scanコマンドを実行しして、Japanese Chijou Digital B-CAS Card (pay TV)が表示に含まれればOKです。このコマンドは実行したままになるので、Ctrl-Cで停止させます。

dvb版PT2ドライバーを削除

地デジチューナのPT2を組み込むとdvb版ドライバがロードされます。このドライバを使用しないのでカーネルから削除します。

$ lsmod | grep earth_pt1
earth_pt1              28672  0
dvb_core              122880  1 earth_pt1

$ sudo rmmod earth_pt1

# ドライバーのロードを禁止する。
$ nano /etc/modprobe.d/blacklist.conf

また次回再起動した時に自動的にロードしないように/etc/modprobe.d/blacklist.confを編集しておきます。次の内容をファイルの最後に加えておくと、earth_pt1をロードしなくなります。

blacklist earth_pt1

chardev版PT2ドライバをインストール

新しくchardev版のPT2用ドライバーを取得してインストールします2

$ wget http://hg.honeyplanet.jp/pt1/archive/tip.tar.bz2
# tarのaオプションは、拡張子から自動的に圧縮アルゴリズムを識別してくれて便利。
$ tar axvf tip.tar.bz2
$ cd pt1-c8688d7d6382/driver

ただしこのままではコンパイルに失敗するので、次のパッチをpt1_pci.cに当てます3

--- pt1_pci.c.orig	2016-05-07 05:49:56.494036485 +0900
+++ pt1_pci.c	2016-05-07 05:50:05.597766146 +0900
@@ -16,6 +16,9 @@
 #include <asm/system.h>
 #endif
 #include <asm/io.h>
+#if LINUX_VERSION_CODE >=KERNEL_VERSION(4,2,0)
+#include <linux/vmalloc.h>
+#endif
 #include <asm/irq.h>
 #include <asm/uaccess.h>

このままインストールすると、カーネルをアップデートするたびに毎回コンパイルと再インストールが必要になります。そこでカーネルがアップデートされるたびに自動的に再コンパイルと再インストールされるようにDKMSに登録しておきます4

まず必要なパッケージをインストールして、ソースをコピーします。

$ sudo apt install dkms

$ sudo cp -r ../driver /usr/src/pt1-c8688d7d6382
# DKMS用の設定ファイルを作成する。
$ sudo nano /usr/src/pt1-c8688d7d6382/dkms.conf

DKMSに登録するためには、設定ファイルdkms.confを作成してソースのディレクトリに保存しておきます。設定ファイルの内容は、次のようになります。

PACKAGE_NAME="pt1"
PACKAGE_VERSION="c8688d7d6382"
CLEAN="make clean"
MAKE="make"
BUILT_MODULE_NAME="pt1_drv"
DEST_MODULE_LOCATION="/kernel/drivers/video/"
AUTOINSTALL="YES"

DKMSを使ってドライバーをインストールします。

$ sudo dkms install -m pt1 -v c8688d7d6382
$ sudo dkms status | grep pt1
pt1, c8688d7d6382, 4.4.0-21-generic, x86_64: installed

# ドライバーをカーネルにロードする。
$ sudo modprobe pt1_drv
$ lsmod|grep pt1
pt1_drv                40960  0

ただ私の環境だけかチューナのデバイスファイルのモードが、rootのみ読み書き可能で、他のユーザはアクセスできないように設定されてしまいます。

$ ls -l /dev/pt1video*
crw------- 1 root root 245, 0  5月  7 07:20 /dev/pt1video0
crw------- 1 root root 245, 1  5月  7 07:20 /dev/pt1video1
crw------- 1 root root 245, 2  5月  7 07:20 /dev/pt1video2
crw------- 1 root root 245, 3  5月  7 07:20 /dev/pt1video3

このままでは録画する時に不便なので、次のエントリーをrootのcrontabに登録して再起動するたびにデバイスファイルのモードを変更しています。

@reboot chmod a+rw /dev/pt1video*

rootのcrontabに登録するには、次のコマンドを使用します。

$ sudo crontab -e

これで誰でもアクセスできるようになりました。

$ ls -l /dev/pt1video*
crw-rw-rw- 1 root root 245, 0  5月  7 12:48 /dev/pt1video0
crw-rw-rw- 1 root root 245, 1  5月  7 12:48 /dev/pt1video1
crw-rw-rw- 1 root root 245, 2  5月  7 12:48 /dev/pt1video2
crw-rw-rw- 1 root root 245, 3  5月  7 12:48 /dev/pt1video3

録画ソフトをインストール

PT2用のchardevドライバーをインストールしたら、録画するプログラムをインストールします。

ただし放送のデコードに必要なライブラリarib25が含まれていないので、昔のソースから取り出して事前にインストールしておく必要があります。

$ sudo apt install zip pkg-config libpcsclite-dev

$ wget http://hg.honeyplanet.jp/pt1/archive/c44e16dbb0e2.zip
$ unzip c44e16dbb0e2.zip && cd pt1-c44e16dbb0e2/arib25
$ make && sudo make install

arib25をインストールしたら、録画プログラムをインストールします。

$ cd ~/pt1-c8688d7d6382/recpt1
$ sudo apt install autoconf automake
$ ./autogen.sh
$ ./configure --enable-b25
$ make && sudo make install

録画テスト

全ての準備が整ったら、まずは受信信号を調べてみます。

$ checksignal 13
device = /dev/pt1video2
C/N = 33.592474dB

オプションの13は、地デジのチャンネルです。これは一般的なNHKなら1chとかのチャンネルとは別で、周波数チャンネルです。この対応は地域(送信塔)毎に異なっているので、対応表で自分の所の周波数チャンネル5を調べておく必要があります。

checksignalを終了するには、Ctrl-Cを入力します。

最後は実際に1分ほど13chを録画して見ます。

$ recpt1 --b25 --strip 13 60 test.mpg
using B25...
enable B25 strip
pid = 6840
C/N = 33.701023dB
Recording...
ecorded 62sec

これで100MiB前後のファイルが作成されるので、VLCなどの再生ソフトでちゃんと録画出来ているか確認します。

実際に使用するには、周波数チャンネルを指定したり時間を秒で指定するのが面倒です。そこで簡単なラップスクリプトを作っておくと便利になります。

参照と脚注

  1. アースソフトの地デジチューナー「PT3」が生産終了に – AKIBA Hotline!

  2. pt2/chardev

  3. パッチの作成には、Linux/テレビ関連/PT2を参考にさせてもらいました。

  4. PT2ドライバをDKMSに登録 – Kung Noi Blog

  5. 放送の周波数チャンネルを調べるには、マスプロの地上デジタル放送 チャンネル一覧表が便利です。

Ubuntu 16.04のZFSで/homeを冗長化

Ubuntu 16.04からZFSがサポートされたので、/homeをミラーリングしたZFS上に作成して冗長化してみました。

これまで使っていたディスクが壊れてしまい、新しくUbuntu 16.04をインストールすることになりました。そこでせっかくなので、このリリースからサポートされたZFSを使ってムフフなファイルたちを無くさないように大切な/homeを冗長化することにしました1

ここでは、ZFSをインストールして使用する方法を簡単にまとめます。ZFSならばバックアップの作成も簡単ですが、ここでは触れません。

システム構成

CPU Pentium G620
RAM 16GiB
Disk 1TB x 2
OS Ubuntu 16.04 Server
メモリ
最低4GB。できれば8GBで、多ければ多いほど良い。もっとも4GB未満でも動かないということもないようです。今回のマシンは、KVMホストもしているので16GBにしています。
ZFSのメモリというとECC付きメモリ or notという話は避けられません。ECC付きのメモリでないとファイルが知らない間に壊れているかもという恐ろしい話があります。一方で、それは他のファイルシステムでも同じで、ZFSだから壊れやすいとはことでもないという話もあります。私は個人的な用途なので気にせずECC無しのメモリを使用しています。
ディスク
ミラーリングの場合は、ディスクが二台必要です。三台でミラーリングして、冗長度を上げることも可能です。またRAIDZの場合は最低3台、RAIDZ2の場合は最低4台のドライブが必要です2
ZFSを構成するドライブ(パーティション)のサイズは、Btrfsと異なり全て同一である必要があります。容量の小さなドライブが混じっていると、全体がその最低サイズに合わせられます3。またディスクを入れ替える場合も、同じかそれ以上のサイズが必要です。
OS
Ubuntu 16.04 Server(64bit)。ZFSを使用できるのは、64bit版のみです。もっとも現在のUbuntuではDesktopとServe共に64bit版が標準なので、それほど気にする必要はありません。しかしアップグレードしてきた場合は32bit版を使っているかも知れないので、その場合は注意が必要です。

システムをインストール

grubブートローダにはちょっとした問題4があるので、ZFSはデータ用のファイルシステムとして使用することをオススメします。/(root)の復旧は/etcとインストール済みのパッケージ一覧があれば/(root)の復旧は簡単ですので、システム全体をZFSにして/(root)自体も冗長化する利点はそれほど大きくありません。

そこで今回は/(root)には冗長性を持たせないで、/homeだけにRAID1の冗長性を持たせることにしました。その代わり復旧に大切な/etcとパッケージ一覧、crontabcronにより適期的にZFS上にコピーしておきます。もちろんZFSのsnapshotを作成して過去に遡れるようにして。

まずsdaに小さなパーティション(8GiBで十分)を作成して、そこに通常通りシステムをインストールします。耐久性はそれほど要求されないので、USBフラッシュメモリにシステムをインストールしても良いかも知れません。

ZFSをインストール

ZFSに必要なカーネルモジュールzfs.koはカーネルに同梱されているので、必要なユーティリティをインストールするだけで完了です。このモジュールがコンパイル済みでカーネルに含まれているので、これまでのDKMSによるzfs.koのコンパイルを待つ面倒臭さがなくなりました。

$ sudo apt install zfsutils-linux

ユーティリティのインストールが完了したら、ZFSに必要なカーネルモジュールがロードされファイルシステムが使えるようになっているか一応確認しておきます。

$ lsmod |grep zfs
zfs                  2813952  3
zunicode              331776  1 zfs
zcommon                57344  1 zfs
znvpair                90112  2 zfs,zcommon
spl                   102400  3 zfs,zcommon,znvpair
zavl                   16384  1 zfs

$ cat /proc/filesystems |grep zfs
nodev	zfs

ミラーリング(RAID1)プールの作成

まずインストールしてあるディスクを確認します。

今後ディスクにアクセするときは、sdaなどの名前ではなく/dev/disk/by-idに表示される名前を使用します5。この名前は、インターフェイス(ata)とディスクのモデル名とシリアル番号の一部から作成されます。そのため今後ディスクを交換する時に、交換が必要なディスクを識別しやすくなります。

$ ls /dev/disk/by-id | grep ^ata
ata-ST31000524AS_9VPCZPQV
ata-ST31000524AS_9VPCZPQV-part1
ata-TOSHIBA_DT01ACA100_36D1KYUNS

ディスクを確認したら、それぞれに同じ容量のパーティションを作成します。

$ sudo cfdisk /dev/disk/by-id/ata-ST31000524AS_9VPCZPQV
$ sudo cfdisk /dev/disk/by-id/ata-TOSHIBA_DT01ACA100_36D1KYUNS

$ ls /dev/disk/by-id | grep ^ata
ata-ST31000524AS_9VPCZPQV
ata-ST31000524AS_9VPCZPQV-part1
ata-TOSHIBA_DT01ACA100_36D1KYUNS
ata-TOSHIBA_DT01ACA100_36D1KYUNS-part1

なぜかブートドライブに作成したパーティションが見えないのでudevadmin triggerコマンドを試してみます。ダメなときは再起動します。

$ ls /dev/disk/by-id/ | grep ^ata
ata-ST31000524AS_9VPCZPQV
ata-ST31000524AS_9VPCZPQV-part1
ata-ST31000524AS_9VPCZPQV-part2
ata-TOSHIBA_DT01ACA100_36D1KYUNS
ata-TOSHIBA_DT01ACA100_36D1KYUNS-part1

パーティションを作成せずにディスク丸ごとZFSにすることも可能で、この方がパフォーマンスが良いとのことです。しかし同じ1TBとして売られているディスクが、メーカーや製品が違ってもセクター数が同じという自信がありません。そこで私はいつも最大サイズより少し小さいパーティションを作成して使っています。

また最近のディスクはセクターサイズが4KiBなので、パーティションの区切りを4KiBのセクターサイズに合わせます。もっとも最近のfdiskなどは、そのことを考慮して配置してくれるので特に気にする必要はありません。

ディスクにパーティションを作成したら、プールを作成します。

$ sudo zpool create -o ashift=12 -o autoexpand=on \
  tank mirror \
  ata-ST31000524AS_9VPCZPQV-part2 \
  ata-TOSHIBA_DT01ACA100_36D1KYUNS-part1

$ sudo zpool status
  pool: tank
 state: ONLINE
  scan: none requested
config:

	NAME                                        STATE     READ WRITE CKSUM
	tank                                        ONLINE       0     0     0
	  mirror-0                                  ONLINE       0     0     0
	    ata-ST31000524AS_9VPCZPQV-part2         ONLINE       0     0     0
	    ata-TOSHIBA_DT01ACA100_36D1KYUNS-part1  ONLINE       0     0     0

errors: No known data errors

-o ashift=12は、セクターサイズの指定です。
この指定によりセクターサイズを2^12B(4KiB)だと指定しています。通常は指定する必要はありませんが、512B/secのディスクを使用していると将来4KiB/secのディスクしか手に入らなくなった時に困ったことになります。

-o autoexpand=onは、将来ディスクを交換した時に可能ならプールのサイズを自動的に拡張する指定です。
このオプションがなくても特に困ることはありません。必要ならば、ディスクの交換後にプールのサイズをマニュアルで拡張することが可能です。ただし拡張できるのは、いずれの場合も冗長構成のディスク全てが現在のプールサイズよりも大きくなった場合に限られます。

tankは、プールの名前です。
/(root)直下のディレクトリ名(binなど)でなければ自由に選べますが、tankpoolが慣習として使われます。

また-O compression=lz4を一緒に指定してファイルシステム全体を圧縮することも可能です。後で見るように、ファイルシステムを作る時に個別に圧縮の有無と方式を指定することも可能です。

ファイルシステムを作成

プールを作成すると自動的に/にプール全体がマウントされますが、目的に応じてファイルシステムを切り出します。今回は、/home用に切り出します。

$ sudo zfs create -o atime=on -o relatime=on \
  -o compression=lz4 tank/home
$ sudo zfs list
NAME        USED  AVAIL  REFER  MOUNTPOINT
tank        372K   868G    96K  /tank
tank/home    96K   868G    96K  /tank/home

-o atime=on -o relatime=onは、ファイルのアクセスタイムの更新方式を指定します。
Linuxはファイルにいつアクセスしたかという情報を記録しており、ファイルにアクセスするたびにファイルの情報を書き換えています。しかしこの情報が使われることはほとんどありません。そこで-o atime=offとしてアクセスタイムの更新を止めてしまうと、ファイルアクセスのパフォーマンスが上がります。しかし一部このアクセス情報を使用するプログラムもあるので、だいたい問題ない程度に更新の頻度を減らすようにします。

-o compression=lz4は、ファイルシステムを圧縮する方法を指定します。
ただ将来さらに優れた圧縮方法が導入されたら自動的にそれを使うように-o compression=onとしておいたほうが良かったかも知れません。zfs setコマンドで後から変更できます。

ファイルシステムを作成したら/homeの内容を移動させて置き換えます。

$ sudo rsync -av /home/ /tank/home
$ cd /
$ sudo rm -rf /home/*
$ sudo zfs set mountpoint=/home tank/home

ZFSはファイルシステムをマウントする時に/etc/fstabを見ないので、/etc/fstabを書き換える必要はありません。

swap on ZFS

スワップをわざわざZFS上に取る必要はないのですが、お試し的にスワップ領域をZFS上に取ってみました。

スワップ領域を作成

スワップ領域をZFS上に作成します6

$ sudo zfs create -V 16G \
  -b $(getconf PAGESIZE) tank/swap
$ sudo zfs set com.sun:auto-snapshot=false tank/swap
$ sudo zfs set sync=always tank/swap

ブロックサイズをページサイズと同じくすることで空きメモリが少ない状況で大きなブロックの書き換えを防ぎます。

sync=alwaysとすることで、キャッシュをすぐに空にしてメモリの使用量を抑えます。

スワップを有効にする

スワップボリュームを作成したら、後は通常のスワップ領域を追加するときと同じです。

まず/etc/fstabを編集して、次のエントリーを追加します。

# swap
/dev/zvol/tank/swap none	swap	default	0	0

次に実際にスワップ領域をフォーマットしてシステムに追加します。

$ sudo mkswap -f /dev/zvol/tank/swap 

$ sudo swapon --all --verbose
swapon /dev/zd32
swapon: /dev/zd32: found swap signature: version 1d, page-size 4, 同じ byte order
swapon: /dev/zd32: pagesize=4096, swapsize=17179869184, devsize=17179869184

fstabを設定してあるので、再起動しても自動的にスワップ領域が有効になります。

参照と脚注

  1. Linuxで使用できるディスクの冗長化には、歴史のあるmdや既に安定期に入りつつ有るBtrfsを使用できます。なのにZFSをなぜ選択したか? 単純にmdやBtrfsよりZFSのコマンドが私にとって分かりやすかったからです。

  2. RAIDZやRAIDZ2に必要なドライブの数は、次の式が成り立つ必要があります。ここで128KiBは、ZFSのデフォルトレコードサイズです。

    128KiB % (ドライブ数 – パリティ数) == 0
    %は、剰余を求める演算記号

    よって、RAIDZはパリティ1なので3,5,9台、RAIDZ2はパリティ2なので4,6,10台となります。

  3. Btrfsは、容量の異なるディスク(パーティション)を組み合わせても、だけ有効に使ってZFSよりも容量を稼げることがあります。またファイルシステムに空きが有る場合は、現在よりも容量の小さいドライブに置き換えることも可能です。

  4. 少し手間はかかりますが、/(root)自体をZFSにすることも可能です。
    ただしgrubブートローダに問題があり、/(root)の入ったプールを作成する時にいくつかのZFS機能を無効にする必要があります。最初の時だけ気にするなら良いのですが、zpool statusコマンドを実行するとzpool upgradeしてくださいというメッセージが親切にも表示されます。そこでzpool upgradeしてしまうと、システムが起動できなくなってしまいます。
    もちろん開発中のgrubではこの制限が取り除かれています。それでもZFSに新しい機能が導入されるたびにブートできなくなる不安がつきまといます。

  5. ZFSのプールを作成する時に/dev/sdaなどの名前を使用した場合は、zpool importコマンドでインポートし直せば/dev/disk/by-idでの名前に変更可能です。ZFSパッケージ登録記念:UBUNTU 15.10にZFS ON LINUX

  6. HOWTO use a zvol as a swap device
    スワップボリューム – archlinux
    Using a zvol for a swap device – FAQ zfsonlinux

Ubuntu 15.10マシンにBluetoothスピーカーを接続

  • Ubuntu 15.10マシンにBluetooth接続のワイヤレス・スピーカーを接続した。
  • Bluetoothスピーカーを接続するのに特別なパッケージのインストールは必要なかった。
  • 音飛びが発生することがある。

パソコンから離れた場所でポッドキャスト(音楽)を聞きたくて、Ubuntu 15.10マシンにBluetoothスピーカーを接続してみました。

当初FMトランスミッターを使ってラジオに飛ばすことを考えていましたが、電気屋さんでBluetooth接続のスピーカーがあることを知り失敗覚悟での挑戦でした。一応その場でググって成功事例があることは確認したのですが、思いの外すんなり行ってしまいちょっと拍子抜けでした。

環境

パソコン ThinkPad T400
OS Ubuntu 15.10
無線スピーカー ELECOM LBT-SPP20

Bluetoothには、従来のVer. 3.0までとBluetooth Low Energy(BLE)と呼ばれるVer. 4.0の二種類が存在します。これらは同じBluetoothですが互換性はありません 。非互換性は、ハードウエアレベルでの非互換性なので、ソフトウエアで対応することはできません。そのため購入前にBluetoothのバージョンが合っているか確認しておく必要が有ります。

今回購入したBluetoothスピーカー(ELECOM LBT-SPP20)は、スマホ対応ということでBluetooth Ver. 4.0(BLE)のみに対応しています。

最近のパソコンは、仕様にBluetoothの対応バージョンが記載されていますが、ThinkPad T400はBluetooth対応というだけでどのバージョンになっているのか記載がありませんでした1。そのためVer. 4.0のみ対応のBluetoothスピーカー(LBT-SPP20)は選ばないほうが賢明です。しかし手元にBluetooth 4.0対応のUSBドングルがあったので、非対応でもなんとかなるだろうという算段でした。

しかしThinkPad T400内蔵のBluetoothはVer. 4.0にも対応していたようで、LBT-SPP20と問題なくペアリングすることが出来ました2

Bluetoothスピーカーとのペアリング

Bluetoothスピーカーを使用するためには、最初にペアリングをおこなう必要が有ります。

Bluetoothスピーカーとのペアリングは次の手順で行います。なおこの手順は、Bluetoothスピーカーに限らずBluetoothデバイスに共通の手順です。

  1. Bluetoothスピーカーをペアリングモードにします。
  2. UbuntuマシンのBluetooth設定を開きます。
  3. デバイス欄下の[+]をクリックして、接続するBluetoothスピーカーを検索します。
  4. Bluetoothスピーカーが表示されたら、それを選択して「進む」をクリックします。
    発見されたBluetoothデバイスを選択して「進む」をクリックします。デバイスの検索には多少時間がかかります。
    発見されたBluetoothデバイスを選択して「進む」をクリックします。デバイスの検索には多少時間がかかります。

    少し待つとペアリングが完了します。
    これでBluetoothデバイスとのペアリングに成功です。
    これでBluetoothデバイスとのペアリングに成功です。

    LBT-SPP20は、ペアリングに失敗することが有りました。この時はもう一度ペアリングさせると上手く行きます。

ペアリングの結果は保存されるので、次回からは電源を入れれば自動的に通信して使用できる状態になります。

サウンド設定

ペアリングに成功したら、Bluetoothスピーカーから音が出るか確認します。

  1. サウンドの設定を開くと出力タブにペアリングしたBluetoothスピーカーが表示されているはずです。表示されない時は、Bluetooth設定の[-]でペアリングを削除して再度ペアリングを行います。
    サウンドの設定。内蔵スピーカーの下にBluetooth接続のスピーカー(LBT-SPP20)が表示されています。
    サウンドの設定。内蔵スピーカーの下にBluetooth接続のスピーカー(LBT-SPP20)が表示されています。
  2. テストボタンをクリックしてBluetoothスピーカーから音が出ることを確認します。
    LBT-SPP20は、ペアリング完了直後は音量が最大に設定されます。そのためテストを行う前に音量を最低に絞っておくことをオススメします。

これで問題がなければ、rhythmbox等で再生した音楽をBluetoothスピーカーで楽しめます。安いスピーカーとはいっても、やはりノートパソコン内蔵のスピーカーとは段違いの音質です。

問題点

UbuntuマシンとBluetoothスピーカーの接続はすんなり行ったのですが、いくつか問題が有ります。

ペアリングで音量設定が最大になる

LBT-SPP20は、ペアリングすると音量設定がリセットされて最大になってしまいます。ペアリング後に音量を下げておくのを忘れると大音量で再生され心臓によくありません。ペアリングが完了したら[-]ボタンを押して音量を最小(「ピポ」と音がする)にしてから、ちょうど良いところまで音量を上げることをオススメします。

音飛びすることがある

時々(結構な頻度かも)音飛びすることが有ります。その時にはsyslogに次のようなログが記録されています。

Jan  5 10:20:13 T400 pulseaudio[1810]: [bluetooth] module-bluez5-device.c: Skipping 103796 us (= 18308 bytes) in audio stream
Jan  5 10:20:13 T400 pulseaudio[1810]: [bluetooth] module-bluez5-device.c: Skipping 71287 us (= 12572 bytes) in audio stream
Jan  5 10:20:13 T400 pulseaudio[1810]: [bluetooth] module-bluez5-device.c: Skipping 106171 us (= 18728 bytes) in audio stream
Jan  5 10:20:13 T400 pulseaudio[1810]: [bluetooth] module-bluez5-device.c: Skipping 72159 us (= 12728 bytes) in audio stream
Jan  5 10:20:13 T400 pulseaudio[1810]: [bluetooth] module-bluez5-device.c: Skipping 8108 us (= 1428 bytes) in audio stream
Jan  5 10:20:14 T400 pulseaudio[1810]: [bluetooth] module-bluez5-device.c: Skipping 150157 us (= 26484 bytes) in audio stream
Jan  5 10:20:14 T400 pulseaudio[1810]: [bluetooth] module-bluez5-device.c: Skipping 36300 us (= 6400 bytes) in audio stream
Jan  5 10:20:14 T400 pulseaudio[1810]: [bluetooth] module-bluez5-device.c: Skipping 165 us (= 28 bytes) in audio stream
Jan  5 10:20:14 T400 pulseaudio[1810]: [bluetooth] module-bluez5-device.c: Skipping 101186 us (= 17848 bytes) in audio stream

この音飛びの原因はWi-Fiとの干渉かと思いThinkPad T400のWi-Fiを無効にしてみましたが改善されませんでした。ただなんとなく夜は昼間に比べて音飛びする頻度が低いような気がするので、どこかの電波(ノイズ)と干渉しているのかもしれません。

Bluetoothスピーカーが消える

UbuntuのBluetooth設定を見るとスピーカーと接続してていても、サウンド設定にBluetoothスピーカーが表示されないことが有ります。この時はペアリングを一度削除して、再度ペアリングをする必要が有ります。

参照と脚注

  1. ThinkPad T400の仕様について書かれたページを見つけたが、Bluetoothは ver. 2.1となっていた。なぜ接続できたんだろう? 見つけたページに誤りがある可能性と、LBT-SP20がver. 4.0の他に従来のBluetoothにも対応していた可能性が考えられます。
    Lenovo ThinkPad T400 Notebook specs

  2. ThnkPad T400内蔵のBluetoothを無線のハードウエアスイッチでOFFにすると、Bluetooth Ver. 4.0 USBドングルを接続してもBluetoothを有効にできませんでした。ドングル自体はUbuntuから認識できているようなのですが、もし内蔵のBluetoothがver. 4.0に対応していなかったら接続できなかったかもしれません。

ZFSパッケージ登録記念:Ubuntu 15.10にZFS on Linux

  • ZFS on LinuxのパッケージがUbuntu 15.10のuniverseに登録された。
  • Ubunut 15.10にZFS on Linuxをインストールしてみた。

この春、DebianでZFS on Linux(ZoL)1が近々サポートされるというニュースが流れました2。しかし結局サポートされるようになったのかどうか、全く話を聞かなくになってしまいました。

そして秋にはUbuntuでZFSが使えるようになるというニュースが流れました3。この時は2016年春にリリース予定のUbuntu 16.04での話でした。そのためUbuntuで使えるようになったとしてもまだ先の話かと思っていました。

ところが先日ZFS on Linuxメーリングリストに「UbuntuのパッケジレポジトリにZoLがある」4があるという話が投稿されました。それを読んでUbuntuのパッケージを検索するとこの秋にリリースされたUbuntu 15.10用のZoLパッケージが見つかりました5。これまでもZoLをPPAからUbuntuにインストール出来ました6が、公式のパッケージとしてZoLが登録されたことは大進歩です。これでOSをアップグレードするときにZFSのカーネルモジュールがインストールされているか心配しなくて良くなります。

これまでPPAのパッケージを使ってZoLをインストールしていましたが、せっかくなので新しく登録されたZFS on LinuxのパッケージをUbuntu 15.10にインストールしてみました。

ZFS on Linuxを使えるマシンの条件

ZFS on Linuxを使用するには、次のような必要条件が有ります。

64-bit Ubuntuシステムであること。
32-bit用のパッケージは提供されていません。
最近Ubuntuをインストールしたマシンは、サーバ用とデスクトップ用共に標準で64-bitになっているのでこの条件は問題ありません。ただしアップグレードを繰り返してきたマシンは32-bitのシステムかもしれません。

64-bitか32-bitかは、uname -iコマンドで確認できます。コマンドの出力がx86_64となっていれば64-bitシステムです。

# 64-bit
$ uname -i
x86_64

# 32-bit
$ uname -i
i686
メモリが8GB以上あること。
もっと少ないメモリ容量でも重複排除を使用しなければ動くことは動くらしいです。逆に重複排除を使用するならば、8GBでは少なすぎます。またメモリは読み出しキャッシュともなるので、実用上はさらにほしい所です。
また普通のメモリでもZFSを使用できますが、データを絶対失いたくない用途ではECC付きのメモリが強く推奨されています7

ZFSでECC付きメモリがどの程度必須かは、ヒートアップ間違い無しの話題です。ECCが付いていない普通のメモリを使っていると、 知らないうちにファイルが壊れる、最悪ファイルシステム全体が壊れることがある という恐ろしい意見を良く見かけます。ただ一方で ECC付きメモリでなくて安全性に違いはない という意見も有ります8

ECC付きのメモリを使っておけば、ファイルが壊れた時に本当は別に原因があったとしてもECC付きのメモリにしておかなかったからかもと後悔をしなくてすみます。ちなみに私は、ホーム・ファイル・サーバにECCの付いていない普通のメモリを使用しています。

ZFS on Linuxをインストール

今回はKVM上で動いているUbuntu 15.10マシンにZFS on Linuxをインストールしてみました。

OS
Ubuntu 15.10 64-bit
メモリ
8GB(8192MB)
ドライブ
5GB + ZFS用に5GBx2
ZFSに使用するドライブには、Virttual DiskのAdvanced optionsでSerial numberを書いておきます。今回は、virtio-drive1virtio-drive2としました。こうすることで、後でドライブが識別しやすくなります。
KVMのVirtual DiskにSerial numberを設定する。
KVMのVirtual DiskにSerial numberを設定する。
$ ls /dev/disk/by-id/
ata-QEMU_DVD-ROM_QM00001  virtio-ubuntu-drive0-part1  virtio-virtio-drive3
virtio-ubuntu-drive0      virtio-virtio-drive2

ドライバ名が頭に付くことを忘れていた。

仮想環境でない本物のドライブでは、次のようにモデル名とシリアル番号から自動的に設定されています。また同じドライブに対して、WWN9からも名前が付けられます。

モデル名とS/N、WWNからデバイス名が作成される。
モデル名とS/N、WWNからデバイス名が作成される。
$ ls /dev/disk/by-id/
usb-ST310005_9VPC_246802468024-0:0
usb-ST310005_9VPC_246802468024-0:0-part1
usb-ST310005_9VPC_246802468024-0:0-part2
# 省略

USB接続だからかWWNでの名前がこの時は作られませんでした。SATAで接続するとwwn-0x5000c50017ffe14fのようなwnnで始まるWWNに由来する名前も作成されます。

ZoLは複数ののパッケージに分割されていますが、zfsutils-linuxをインストールすると必要なパッケージが全てインストールされます。ただし現時点ではパッケージの依存関係にバグがあるのかZFS on Linuxのカーネルモジュールをインストールする時に必要なbuild-essentialパッケージがインストールされません10。そこでこれも同時にインストールします。

$ sudo apt-get update
$ sudo apt-get install build-essential zfsutils-linux

普通のパッケージはファイルをコピーするだけですが、ZoLはカーネルモジュールをコンパイルしてインストールする必要があります。そのためインストールが完了するまで多少時間がかかります。

インストールが完了したら、ZFSが使えるようになっているか確認します。

$ cat /proc/filesystems |grep zfs
nodev	zfs

$ dmesg | grep -E 'SPL:|ZFS:'
[  848.530602] SPL: Loaded module v0.6.4.2-0ubuntu1
[  848.566350] ZFS: Loaded module v0.6.4.2-0ubuntu1.2, ZFS pool version 5000, ZFS filesystem version 5

ZFSを使ってみた

ZFSが使えることが確認できたら、ミラーリング(mirror, RAID1)で冗長化したZFSを作って/homeに使用してみます11

ZFSを使うには、まず複数のドライブをまとめて冗長性を持った一つの記憶システムpoolを作成し、次にpoolを分割してユーザが使用できるファイルシステムを作ります。

poolの作成

まずドライブと対応するデバイス名を確認します。

$ ls -l /dev/disk/by-id
lrwxrwxrwx 1 root root  9 12月 29 08:12 ata-QEMU_DVD-ROM_QM00001 -> ../../sr0
lrwxrwxrwx 1 root root  9 12月 29 08:12 virtio-ubuntu-drive0 -> ../../vda
lrwxrwxrwx 1 root root 10 12月 29 08:12 virtio-ubuntu-drive0-part1 -> ../../vda1
lrwxrwxrwx 1 root root  9 12月 29 08:12 virtio-virtio-drive2 -> ../../vdb
lrwxrwxrwx 1 root root  9 12月 29 08:12 virtio-virtio-drive3 -> ../../vdc

今回ZFSに使用するドライブがvdbとvdcに接続していることがわかりました。このデバイス名は初期化するときにだけ必要で、以後は分かりやすいby-idで示された名前が使用できるようになります。(本当は最初からby-idの名前を使えるはずですが…。)

poolの作成には、zpoolコマンドを使用します。

$ sudo zpool create -o ashift=12 tank mirror vdb vdc
$ sudo zpool status
  pool: tank
 state: ONLINE
  scan: none requested
config:

	NAME        STATE     READ WRITE CKSUM
	tank        ONLINE       0     0     0
	  mirror-0  ONLINE       0     0     0
	    vdb1    ONLINE       0     0     0
	    vdc1    ONLINE       0     0     0

errors: No known data errors

$ sudo zpool list
NAME   SIZE  ALLOC   FREE  EXPANDSZ   FRAG    CAP  DEDUP  HEALTH  ALTROOT
tank  4.97G   360K  4.97G         -     0%     0%  1.00x  ONLINE  -

ドライブがまっさらでパーティションテーブル自体がないときにはエラーになるので、poolを作成するときに-fオプションを追加します。

-o ashift=12オプションは、4KBセクタのドライブに対応するためで、2^12(4096)バイトを単位としてデータを配置させます。

poolの名前をtankとしましたが、この名前は/(root)ディレクトリに無い名前であれば自由に決めることができます。

poolを構成するストレージには、ドライブ丸ごとではなく特定のパーティションを指定することも可能です。ただしドライブ丸ごとのほうが効率が良いということです。

これでpoolの準備は完了です。しかしこれでは障害が発生した時にどのドライブを交換したらよいか分かりにくく、間違ったドライブを交換してしまいそうです。

そこでdisk/by-idで示された分かりやすい名前を使えるようにします。

$ sudo zpool export tank
$ sudo zpool import -d /dev/disk/by-id tank
$ sudo zpool status
  pool: tank
 state: ONLINE
  scan: none requested
config:

	NAME                      STATE     READ WRITE CKSUM
	tank                      ONLINE       0     0     0
	  mirror-0                ONLINE       0     0     0
	    virtio-virtio-drive2  ONLINE       0     0     0
	    virtio-virtio-drive3  ONLINE       0     0     0

errors: No known data errors

これで将来障害が発生したとしても、交換が必要なドライブを間違える心配が減ります。

異なるサイズのドライブの組み合わせ

サイズが異なるドライブ(またはパーティション)を組み合わせた場合は、もっとも容量の小さいドライブに合わせてpoolが作成されます12

また将来ドライブが壊れた時には、壊れたドライブと同じかより大容量のものと交換する必要が有ります。ドライブを交換して最も容量の小さかったドライブが置き換わると、自動的にpoolのサイズが拡張されます。

例えば、500GB + 500GB(500GB)のミラーリングされたpoolのドライブ一台を1TBのドライブと交換したとします。すると500GB + 1TBという構成になりますが、この時のpool容量は500GBのままです。さらに500GBのドライブを1TBのと交換すると1TB + 1TBとなり、poolの容量は自動的に1TBとなります。

ただし容量に空きがあっても小さいサイズのドライブに交換することはできません13

ファイルシステムの作成

poolを作成したらファイルシステムを作成して使用できるようにします。

と言っても実はpoolを作成しただけでファイルシステムが作られて/(root)にマウントされています。そのためpoolの名前に「/(root)ディレクトリに無い名前」という制限があったのです。

$ df -h
Filesystem      Size  Used Avail Use% Mounted on
# 省略
tank            4.9G  128K  4.9G   1% /tank

dfコマンドで使用量がわかるのがZFSの便利なところです。

/homeをZFSにする

このままどんぶり勘定的に使用することも可能ですが、一般的にはこの領域をzfsコマンドで分割して使用します。

ここでは/homeをZFS上に作成して、ドライブが一台壊れてもデータを守れるようにしてみます。

$ sudo zfs create -o atime=on -o relatime=on -o compression=lz4 tank/home
$ sudo zfs list
NAME        USED  AVAIL  REFER  MOUNTPOINT
tank        396K  4.89G    96K  /tank
tank/home    96K  4.89G    96K  /tank/home

これで新しい/homeとなるファイルシステムが出来ました。

zfsコマンドの-o atime=on -o relatime=onオプションは、ファイルアクセス時刻の記録方法をext4のデフォルトと同じにするためです。また-o compression=lz4オプションは、データをlz4で圧縮して記録することを指示しています。

新しいファイルシステムができたので、これまでの/homeを移動させて/homeを切り替えます。

$ sudo rsync -a /home/ /tank/home
# /home/とソースはスラッシュ(/)で終わっている必要がある。
$ ls /tank/home/
# 全てのユーザディレクトリが表示されるはず。

$ cd /
$ /homeを外部メディアにバックアップ
$ sudo rm -r /home/*
$ sudo zfs set mountpoint=/home tank/home
$ sudo zfs list
NAME        USED  AVAIL  REFER  MOUNTPOINT
tank        448K  4.89G    96K  /tank
tank/home   124K  4.89G   124K  /home

$ ls /home/
# 以前と同じく全てのユーザディレクトリが表示されるはず。

$ df -h
Filesystem      Size  Used Avail Use% Mounted on
# 省略
tank            4.9G  128K  4.9G   1% /tank
tank/home       4.9G  128K  4.9G   1% /home

再起動して問題なければ、バックアップを削除します。

$ sudo rm /tank/home.tgz

参照と脚注

  1. ZFS on Linux
    これまでもZFSは、FUSEではサポートされていました。

  2. ZFS & Libdvdcss Should Soon Be In Debian – phoronix
    Debian Is Still Working To Tackle ZFS On Linux Support – phoronix

  3. 2015年10月9日号 ZFSとUbuntu・UWN#436 – Ubuntu Weekly Topics

  4. [zfs-discuss] ZoL available on the Ubuntu repositories

  5. Ubuntuパッケージ検索結果

  6. ZFS Stable Releases for Ubuntu

  7. Do I have to use ECC memory for ZFS? – ZFS ON LINUX FAQ

  8. 第7回 ZFSベストプラクティス-FreeBSD Journal March/April 2015 – BSD界隈四方山話

  9. WWNは、World Wide Nameの略。World Wide Name – ウィキペディア

  10. 本来必要なパッケージは全てインストールされるはずですが、
    zfs-dkms is missing dependency on build-essential – Ubuntu zfs-linux package bugs

  11. ZFSでは、ミラーリングの他にraidz1(RAID5相当)とraidz2(RAID6相当)を冗長化に使用できます。

  12. ドライブ2台のミラーリングでは差が現れませんが、Btrfsは容量が異なるドライブを組み合わせても、できるだけ無駄のないpoolを作成してくれます。btrfs disk usage calculator

  13. Btrfsは、使っている容量が収まれば小さい容量のドライブに置き換えることができるそうです。