第521回ではLXD 3.0の基本的な使い方を紹介しました。今回はLXD 2.0から3.0にかけて大幅に改善されたネットワーク周りの設定について紹介しましょう。特に次のような設定方法について解説します。
- ネットワークインターフェースの追加
- 固定IPアドレスの指定
- 標準のインターフェースeth0のカスタマイズ
- 特定のアドレス・ポートにホストの外からアクセスする方法
LXDにおけるネットワークの設定
現在のLXD 3.0にはネットワークに関する2種類の設定インターフェースが存在します[1]。
ブリッジインターフェースはホスト上でlxd init
を実行したときにも設定されます。特に設定を変更していないなら「lxdbr0」という名前のブリッジインターフェースが作られていることでしょう。
上記lxdbr0では、IPv4/IPv6のアドレスレンジが設定されており、それが作成されたコンテナに割り当てられます。
Ubuntu 16.04 LTSのLXD 2.0では、LXDが作る唯一のブリッジインターフェースを使うか、別途自分で作ったインターフェースを使うかの二択でした。LXD 3.0(に至るまでの2.xの間)で、lxc network
コマンドを使うことで、LXDが管理する複数のブリッジインターフェースを持てるようになり、コンテナごとにインターフェースの割り当てを変えられるようになったのです。これにより同じホスト上で異なるネットワークセグメントに属する複数のコンテナを構築できます。
個々のコンテナインスタンスにおけるネットワークインターフェースはlxc config device
コマンドによって追加・削除します。ただし何も設定せずにコンテナを起動した場合は、lxc config
は未設定の状態となり、lxc profile
の値が継承されます。
たとえば何も設定せずに「container」コンテナを作成・起動してみましょう。
デバイス設定は空にも関わらずeth0インターフェースが作られています。これは作成したコンテナには自動的にdefaultプロファイルが適用され、そのプロファイルの中にeth0についての設定が書かれているからです。defaultプロファイルの内容を確認してみましょう。
上記のプロファイルの設定は、そのプロファイルが適用されているコンテナにも継承されます。ちなみに、「lxc config device show
」ではなく「lxc config show
」に「--expanded
」オプションを付加して実行すれば、継承されたプロファイルの内容も展開されて表示されます。
LXDにおけるプロファイルの設定はまた別の機会に譲るとして、今回はネットワークの基本設定をいくつか紹介しましょう[2]。
ネットワークインターフェースを追加する
コンテナに複数のネットワークインターフェースを持たせたいことがあるでしょう。LXD 3.0では次の種類(nictype)のネットワークデバイスを追加可能です。
- physical:ホスト上の物理デバイスをそのままコンテナの中に見せる方式です。指定したデバイスはホスト上からは見えなくなります。性能的な要件から物理NICを特定のコンテナのみで使用したい場合に便利です。
- bridged:ホスト上の仮想ブリッジに紐付いた仮想ネットワークデバイスを作成する方式です。コンテナに最初から存在するeth0はこの方式を使っています。
- macvlan:既存のデバイスに対して異なるMACアドレスを割り当てた仮想ネットワークデバイスを作成する方式です。第533回のようにコンテナをホストの外からも見えるようにしたい場合に便利ですが、ホストとコンテナでの通信はできなくなります。
- p2p:vethペアを作成し片方をコンテナに割り当てる方式です。bridgedと異なり、特定のインターフェースへの紐付けは必須ではありません。より柔軟に複雑なネットワーク環境を構築したい場合に使うようです。
- sriov:ホスト上の物理デバイスの仮想機能(Virtual Function)をコンテナに専有させる方式です。物理デバイスがSR-IOVに対応している必要があります。
LXDではネットワークインターフェースを次のように追加します。
設定名は追加するデバイス設定を一意に決める値です。nicを含む他のデバイス設定と被らない値を指定する必要があります。設定名がそのままコンテナ内部のネットワークインタフェースデバイスの名前になるため、用途にあわせたわかりやすい名前を付けるといいでしょう。もし設定名とデバイス名を一致させたくない場合はオプションに「name=デバイス名
」を指定してください。
オプションは「key=value
」の形で指定します。nictypeによって、指定できるオプションが異なるので注意してください。設定可能なkeyと初期値などはLXDのドキュメントに一覧があります。
「とりあえずインターフェースを追加したい」ならbridgedかmacvlanを使うことになるでしょう。このうちlxdbr0に対するbridgedはlxc network
コマンドを使います。その手順は後述の「ブリッジインターフェースで固定IPアドレスを設定する」で紹介することにして、ここではmacvlanインターフェースを追加してみましょう。
たとえば「container」コンテナにmacvlanタイプのeth1を追加したい場合は、次のように設定します。
ここで「parent=
」に指定しているのは、実際にフレームを送受信するホスト上のネットワークインターフェースです。macvlanではこのインターフェースのサブインターフェースとしてデバイスを作成します[3]。「nictype=bridged
」として作成するならブリッジインターフェースを指定します。
実際にコンテナの中で「ip addr
」を実行するとeth1が作成されていることがわかります。
enp0s31f6が親デバイスではあるものの、MACアドレスは異なります。このため、たとえばdhclient
コマンドを使えば、親デバイスとは異なるIPアドレスが割り振られます。
ためしにeth1あてに外部からアクセスしつつ、enp0s31f6に対してパケットキャプチャしてみれば、eth1宛のフレームがMACアドレスが異なるはずのenp0s31f6を経由していることがわかるでしょう。うまくアドレスが割り当たっているようであれば、第533回のように起動時にeth1に対してDHCPでアドレスを取得するよう、netplanの設定ファイルを変更しておきましょう。
ちなみにLXDで設定したmacvlanのモードは「bridge」になります。よって特に設定しなくても同じホスト上の同じ物理インターフェースを親に持つコンテナ同士なら通信できるのです。
MACアドレスには「00:16:3e」で始まるランダムなアドレスが割り当てられます[4]。「hwaddr=FOO
」と設定することで、任意のMACアドレスを設定することも可能です。
もし追加したインターフェースを削除したい場合は、次のように実行します。
ブリッジインターフェースで固定IPアドレスを設定する
コンテナがUbuntu 18.04 LTSの場合、何も設定しなければCloud-Init経由でeth0がDHCPv4を利用してIPv4アドレスを、RAを利用してIPv6を取得する設定になっています[5]。具体的にはLXD自身がdnsmasqを起動し、lxdbr0に紐付けます。このdnsmasqがDHCPv4およびステートレスDHCPv6/SLAACを利用してIPアドレスを設定するわけです。
たとえばIPv4のlease情報は次のように確認できます。
単にホストからコンテナのIPアドレスを知りたければlxc list
コマンドを使うと良いでしょう。
コンテナの用途によっては静的にIPアドレスを割り当てたい場合もあるでしょう。次のようにbridgedなネットワークインターフェースデバイスを作成し、「ipv4.address」キーをセットすれば、LXDがコンテナ起動時に静的なIPv4アドレスを割り当ててくれます。
まずbridgedなネットワークインターフェースデバイスを作成します。LXDには標準でlxdbr0ネットワークが作成されていますので、これを親に持つインターフェース「eth1」を作成しましょう。
次にこのインターフェースに対してIPv4アドレス「10.154.195.100」を割り当てます。
「ipv4.address」による設定では、実際にこのIPv4アドレスをコンテナに割り当てるのはLXDが実行しているdnsmasqの役割です。つまりコンテナから見るとDHCP経由で固定アドレスを取得することになります。
うまくアドレスが割り当たっているようであれば、第533回のように起動時にeth1に対してDHCPでアドレスを取得するよう、netplanの設定ファイルを変更しておきましょう。繰り返しになりますが、コンテナからはDHCP経由でアドレスを取得します。よってnetplanの設定も「dhcp4: true」としてください。LXDがleaseしているアドレスのリストはlxc network list-leases
で確認できます。
ちなみに「ipv6.address」を使えば、静的なIPv6アドレスを指定可能です。ただしこの設定を使うためには、LXDのステートフルDHCPv6を有効化する必要があります[6]。
なお、dnsmasqによるIPアドレスレンジは、lxd init
時に設定しています。特に指定せずにすべて初期値どおりに設定していたとしたら、CIDR(Classless Inter-Domain Routing)形式でランダムなアドレスレンジが指定されているはずです。任意の値に変更したい場合は、次のように実行してください。
連続する範囲をハイフンで、不連続な範囲をカンマで区切って指定できます。
標準のインターフェースeth0をカスタマイズする
eth0はdefaultプロファイルから継承されたデバイスです。このためlxc config device
による設定の変更が動作しない場合もあります。おおよそ「defaultプロファイルを継承しているすべてのコンテナで適用可能とは言えない設定」は、lxc config device
が使えないと考えればいいでしょう。たとえばIPv4アドレスを指定する「ipv4.address
」はプロファイルで設定できませんので、プロファイルから継承したデバイスに対する「lxc config device
」は使えません。
もし、eth0をより柔軟に設定変更したいのであれば、次のいずれかの方法でeth0を明示的に設定する必要があります。
- defaultプロファイルをカスタマイズする
- default以外のプロファイルを作成し、それを適用する
- コンテナに対してeth0設定を上書きする
1.のdefaultプロファイルをカスタマイズする方法は、そのホスト上のすべてのコンテナに対して同じ設定を適用したい場合に便利です。ただしIPアドレスのようなコンテナ固有の設定は共有できません。2.の別のプロファイルを作る方法は、特定のコンテナ群のみdefault以外のプロファイルを適用する場合、もしくはdefaultプロファイルにいくつかの設定を上書きする場合に便利です。しかしながらIPアドレス云々の制約は1.と同じです。このため、コンテナ固有の設定を行いたいなら、3.の方法が現実的でしょう。
3.の方法において、eth0をlxdbr0に属するbridgedなインターフェースとして作るのであれば、固定IPアドレスを割り当てた時と手順は同じです。ただしattachする際にあらかじめコンテナを停止しておいたほうが良いでしょう。
macvlanなインターフェースをeth0として作るのであれば、単純に「lxc config device add」をするだけです。明示的に「name=eth0」を指定しないと、eth1が作られてしまうので注意してください。
特定のアドレス・ポートを公開する
コンテナでbridgedインターフェースを使っている場合、コンテナからインターネット(ホストの外)へのアクセスは可能ではあるものの、インターネット(ホストの外)からアクセスはできません。これはコンテナで動かしているサービスを外部に公開したい場合に不便です。
LXD 2.0の頃はリバースプロキシーを用意したり、iptablesを使ってポートフォワーディングなどを手動で設定する必要がありましたが、LXD 3.0までに「proxy」デバイスが追加され、これを設定することでlxcコマンドから各種転送設定を行えるようになりました。
たとえばホストの80番ポート宛のアクセスを、すべてcontainerコンテナの8080番ポートに転送するには次のように設定します。
「port80」は任意の設定名です。LXD自身はlistenで指定したアドレスとポート番号でbind()
やlisten()
を行い、ネットワークプロキシーとして振る舞い、connectで指定したアドレス・ポート番号に転送します。
proxyデバイスは次のコマンドで削除できます。
なお、より新しいLXD 3.x系ではTCPだけでなく、UDPやUNIXソケットなどもサポートしているようです。