Docker と IOS XE ルータを連携させてみる

今回は、前回紹介した Ansible のIOSモジュールを使った具体的なユースケースとして、Docker と IOS XE ルータを連携させてみたいと思います。

Docker の外部ネットワーク接続(Bridge ドライバの場合)

そもそも Docker が外部ネットワークとどのように接続していたかというと、デフォルトの Bridge ドライバを用いた場合、コンテナから外部への通信のため、ホストの Linux ブリッジ(docker0)で iptables により IP マスカレード(シスコ用語では“Dynamic PAT”)されていました。さらに、外部からコンテナの特定のサービスにアクセスさせたい場合は、加えて、ポートフォワーディング(シスコ用語では“Static PAT”)も実施しています。外部からアクセスできるポート番号(Global ポート番号)は明示的に設定することもできますが、同一ホスト上で複数の同一サービスが立ち上がる可能性を考慮すると、このポート番号は動的に割り振られることになります。この場合、外部から特定のサービスがどの Global ポート番号で起動しているのかを知る仕組みが必要になりますが、Docker コンテナ起動時に Consuletcd などの分散キー バリュー ストアに動的に登録することでサービスディスカバリを実現するというのが常套手段です。これを実現する有名なツールとして、Registrator があります。

外部ネットワークとの連携する際の考慮点(1)

Docker を外部ネットワークと連携させるにあたって、第一の考慮点は、ホストで実行される NAT 処理(以後、PAT も含めてた広い意味で「NAT」と呼びます)がそれなりに負荷になるということです。ネットワーク的な処理にリソースを空費し、肝心なサービスの処理が十分に実行できないということでは本末転倒です。

外部ネットワークとの連携する際の考慮点(2)

第二の考慮点は、前述のように Global ポート番号が動的に決まる特性のある Dockerized なサービスに対して、外部ネットワーク側で何か気の利いたことをしようとすると、従来のネットワーク設定は基本的に静的なため、かなり厄介なことになります。外部ネットワーク側でサービスに合わせてセキュリティや QoS のポリシーを適用しようとした場合、サービス ディスカバリに問い合わせをして動的に設定を変更する必要がでてきますが、こういった仕組みをネットワーク側で作りこむのは、現実的にかなり難しいのではないでしょうか。

やりたいこと

そこで、考慮点(1) に対処すべく、Docker 側では NAT 処理なしで特定の VLAN に落とし込み、NAT 処理は外部の IOS ルータで実施するようにします。その際に、考慮点(2) に対処するため、ポート フォワーディングの代わりに、フローティング IP(シスコ用語で言えば Static PAT の代わりである“Static NAT”)を用います。ひとつのコンテナにひとつの IP アドレスを割り振るというのは、かなり思い切った対応ですが、IP アドレス ベースでポリシーを実施できるので、NAT ルータより向こう側のネットワークの設定は、従来どおり静的できます。

Macvlan ドライバ

ちなみに、特定のコンテナを NAT 処理なしに特定の VLAN に落とし込む方法としては、Docker リリース1.12 から正式サポートとなった、Macvlan ドライバの Bridge モードを使います。Macvlan 自体の詳細は、本家サイトの以下のページを参照ください。

https://docs.docker.com/engine/userguide/networking/get-started-macvlan/

Translator

上述の方針にしたがって、今回、試作してみたのが拙作の Translator です。

https://github.com/tetsusat/translator

セットアップを簡単にするため、Translator 自体 Docker コンテナとして動作します。おかげで、わざわざ Ansible が動作する環境を用意する必要がありません。

$ docker run -d \
    --name=translator \
    --net=host \
    --volume=/var/run/docker.sock:/tmp/docker.sock \
    --env IOS_MGMT_IP="<ios_mgmt_ip>" \
    --env IOS_USER="<ios_user>" \
    --env IOS_PASS="<ios_pass>" \
    --env IOS_ENABLE_PASS="<ios_enable_pass>" \
    --env OUTSIDE_INTERFACE="GigabitEthernetX" \
    --env INSIDE_INTERFACE="GigabitEthernetY" \
    tetsusat/translator:latest \
      ios-ansible

あとは、以下のように Macvlan の Docker ネットワークを作成したタイミングで、Docker Remote API 経由でイベントを検知し、テナント用の VRF、ダウンサイドのサブ インターフェイス、IP マスカレード相当の Dynamic PAT が設定されます。

$ docker network create -d macvlan --subnet=192.168.1.0/24 --gateway=192.168.1.254 -o parent=eth1.10 mytenant

また、以下のように Docker コンテナを起動したタイミングで、同様に、フローティング IP 相当の Static NAT が設定されます。

$ docker run --net=mytenant --ip=192.168.1.1 -it -l global_ip=10.0.1.1 alpine /bin/sh

ネーミングからピンときた方もいるかもしれませんが、Translator は前述の Registrator の仕組みをかなり参考にさせてもらってます。手前味噌ですが、Translator は Registrator と同様に Plaggableなアーキテクチャになっていて、Ansible の他にも、RESTCONF でも IOS XEル ータを制御できるようになってます。潜在的には、他のプラットフォームや API にも対応できる余地を残しています。

結びに代えて

Docker はその API ファーストなアーキテクチャのおかげで、Docker 社およびその前身である dotCloud 社が作ったプロダクトを超えて、周囲に豊かなエコシステムが出来上がった好例だと思います。個人的には、ネットワークの世界でも、API ファーストの考え方が当たり前になって、今までになかったような画期的な利用例やサービスが雨後の竹の子のようにニョキニョキと現れるような日が遠からず到来することを切望します o(^-^)o

Share
佐藤 哲大

2001年、シスコシステムズ株式会社(当時)に新卒として入社。官公庁、製造担当のハイタッチ SE を経て、ルータ系の技術支援、ソリューション開発に従事。SDN 応用技術室の開設に伴い、2013年4月から現職。

(趣味と実益を兼ねて)日夜、プログラミングや OSS と戯れ中。