コンテナのネットワークインターフェース
その実装手法とその応用について
@JTF 2017, 2017/8/27
林 智史
s1061123@gmail.com
id:s1061123, @s1061123
Agenda
×コンテナのネットワークについて
×実際の手法
×コードの解説
×応用
Agenda
×コンテナのネットワークについて
× どんなインターフェイスで通信しているのか?
× どうやって他のコンテナと分離しているのか?
× 実際の手法
×コードの解説
×応用
コンテナで使ってるネットワークインターフェイスって?
tom@kagaribi $ docker run -it --rm centos_test bash
[root@5c747e947ec9 /]# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN 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
2: ip6tnl0@NONE: <NOARP> mtu 1452 qdisc noop state DOWN qlen 1
link/tunnel6 :: brd ::
3: sit0@NONE: <NOARP> mtu 1480 qdisc noop state DOWN qlen 1
link/sit 0.0.0.0 brd 0.0.0.0
32: eth0@if33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP
link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 172.17.0.2/16 scope global eth0
valid_lft forever preferred_lft forever
[root@5c747e947ec9 /]#
コンテナで使ってるネットワークインターフェイスって?
[root@5c747e947ec9 /]# ip -d a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN qlen 1
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 promiscuity 0
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
2: ip6tnl0@NONE: <NOARP> mtu 1452 qdisc noop state DOWN qlen 1
link/tunnel6 :: brd :: promiscuity 0
ip6tnl ip6ip6 remote :: local :: encaplimit 0 hoplimit 0 tclass 0x00 flowlabel 0x00000
(flowinfo 0x00000000)
3: sit0@NONE: <NOARP> mtu 1480 qdisc noop state DOWN qlen 1
link/sit 0.0.0.0 brd 0.0.0.0 promiscuity 0
sit remote any local any ttl 64 nopmtudisc 6rd-prefix 2002::/16
32: eth0@if33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP
link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0 promiscuity 0
veth
inet 172.17.0.2/16 scope global eth0
valid_lft forever preferred_lft forever
‘-d’ / ‘-details’
オプションを追加
コンテナで使ってるネットワークインターフェイスって?
32: eth0@if33: <BROADCAST,
link/ether 02:42:ac:11
veth
inet 172.17.0.2/16 sco
valid_lft forever p
コンテナで使ってるネットワークインターフェイスって?
32: eth0@if33: <BROADCAST,
link/ether 02:42:ac:11
veth
inet 172.17.0.2/16 sco
valid_lft forever p
ifi_index
= IFインデックス
IFLA_IFNAME
= 名前
対面のインターフェースの
ifi_index or 対面の名前
veth
= カーネルが提供する仮想
L2インターフェース
vethとは?
× カーネルが提供するL2仮想インターフェース
× OpenVZから由来
× Linuxカーネル内では <kernel>/drivers/net/veth.c で実装
× P2P (Point-to-point)での接続形態
× つまり相手(接続先)は一つ
× 接続先はIFLA_LINK_NETNSIDで確認
× ‘ip link add’コマンドで作成可能
× 例: “ ip link add veth1 type veth peer name veth2”
Agenda
×コンテナのネットワークについて
× どんなインターフェイスで通信しているのか?
× どうやって他のコンテナと分離しているのか?
× 実際の手法
×コードの解説
×応用
コンテナのネットワークの分離
namespace (名前空間)というものでネットワークを
含む各種リソースを分離
× PID_NS: pid空間を分離
× NET_NS: ネットワークを分離 (← これ!)
× USER_NS: ユーザ権限を分離
× IPC_NS: メッセージキュー・shmemの分離
× UTS_NS: ホストネームの分離
コンテナのネットワークの分離
NET_NS:
×<kernel>/include/net/net_namespace.h に定義
× IPv4 (arp/ルーティング 含む)
× IPv6 (neighbor/ルーティング 含む)
× Unixドメインソケット
× netfilter (例: iptables)
× conntrack (NATテーブル)
× その他(MPLS, sctp等)
これらをNET_NS毎
に分離
コンテナ毎に分離
コンテナのネットワークの分離
ホスト
NET_NS1 (ホストのNET_NS) NET_NS2 (dockerで作成)
em1
192.168.1.1
bash bash
eth0
192.168.1.1
同じアドレスで
も競合しない!
コンテナのネットワークの分離
'docker run --net host ...’
‘docker run --net bridge …’
‘docker run --net none ...’
ホスト
NET_NS1 (ホストのNET_NS)
em1
192.168.1.1
bash
‘docker run --net host … bash’ の場合
dockerで作成
'--net host': NET_NSを作成せずにホストのものをそのまま流用 (pidは分離)
‘docker run --net bridge … bash’ の場合
ホスト
NET_NS1 (ホストのNET_NS)
em1
192.168.1.1
Bridge
(docker0)
NET_NS2 (dockerで作成)
bash
dockerで作成
veth
veth
'--net bridge':
NET_NSを作成して、ホストのNET_NSにあるブリッジ(docker0)とvethで接続
lo
‘docker run --net none … bash’ の場合
ホスト
NET_NS1 (ホストのNET_NS) NET_NS2 (dockerで作成)
em1
192.168.1.1
bash bash
'--net none: NET_NSを作成して、他に何も行なわない
lo
しかしlo等のデバイスはNET_NS
作成時にカーネルが自動的に作
成
<kernel>/net/core/net_namespace.c:
setup_net()
Agenda
×コンテナのネットワークについて
×実際の手法
×dockerがどのように提供しているのか?
×k8sがどのように提供しているのか?
×コードの解説
×応用
Agenda
×コンテナのネットワークについて
×実際の手法
×dockerがどのように提供しているのか?
×k8sがどのように提供しているのか?
×コードの解説
×応用
dockerの場合
× Docker自身はネットワークを作成しない
× libnetworkを使用して作成
× libnetworkはドライバでどのようなネットワークを指
定可能
× ドライバでは以下のAPIを実装している
× Config
× {Create,Delete}Network
× {Create,Delete}Endpoint
× Join, Leave
例
$ docker inspect test | jq .[]."NetworkSettings"
{
"Bridge": "",
"SandboxID": "be01b37c006ad9139c1f3b648dbf02d29761f630c33e9620d60fcd401aae0b5b",
"HairpinMode": false,
"LinkLocalIPv6Address": "",
"LinkLocalIPv6PrefixLen": 0,
"Ports": {},
"SandboxKey": "/var/run/docker/netns/be01b37c006a",
"SecondaryIPAddresses": null,
"SecondaryIPv6Addresses": null,
"EndpointID": "118e24eb9ef5727d3d43814866597b07c4429bc9b055b941285b6d7b6e300388",
"Gateway": "172.17.0.1",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"IPAddress": "172.17.0.2",
"IPPrefixLen": 16,
"IPv6Gateway": "",
"MacAddress": "02:42:ac:11:00:02",
"Networks": {
"bridge": {
"IPAMConfig": null,
Agenda
×コンテナのネットワークについて
×実際の手法
×dockerがどのように提供しているのか?
×K8sがどのように提供しているのか?
× コンテナランタイム: docker
× ネットワーク: CNI (Calico)
×コードの解説
×応用
例
$ docker inspect k8s_test1-node1_centos1-2797499804-fdqd1_default_018173b3-8247-11e7-b2d6-
525400075920_0 | jq .[]."NetworkSettings"
{
"Bridge": "",
"SandboxID": "",
"HairpinMode": false,
"LinkLocalIPv6Address": "",
"LinkLocalIPv6PrefixLen": 0,
"Ports": null,
"SandboxKey": "",
"SecondaryIPAddresses": null,
"SecondaryIPv6Addresses": null,
"EndpointID": "",
"Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"IPAddress": "",
"IPPrefixLen": 0,
"IPv6Gateway": "",
"MacAddress": "",
"Networks": null
例
$ kubectl get -o wide pod
NAME READY STATUS RESTARTS AGE IP NODE
centos1-2797499804-fdqd1 1/1 Running 0 9m 192.168.58.193 k8s-node02
$ docker exec -it k8s_test1-node1_centos1-2797499804-fdqd1_default_018173b3-8247-11e7-b2d6-525400075920_0 bash
[root@centos1-2797499804-fdqd1 /]# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN 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: tunl0@NONE: <NOARP> mtu 1480 qdisc noop state DOWN qlen 1
link/ipip 0.0.0.0 brd 0.0.0.0
4: eth0@if6: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP
link/ether 22:e6:c3:21:5f:a7 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 192.168.58.193/32 scope global eth0
valid_lft forever preferred_lft forever
inet6 fe80::20e6:c3ff:fe21:5fa7/64 scope link
valid_lft forever preferred_lft forever
k8sの場合
k8sの場合は?
× コンテナランタイム: docker
× ネットワーク: CNI (Calico)
結果
× docker側はネットワークが無いという
× k8sから見るとネットワークはあるという
→ 実際コンテナにはネットワークが見える
k8sのコンテナとネットワークの関係
1. kubectlでコンテナの起動命令
2. kubeletがdockerでコンテナを"--net none"で起動
実際にはdocker API経由なので NetworkMode = "none"
1. コンテナはネットワーク無しで起動
→なのでdockerから見るとネットワークはなしで起動している
1. kubeletがCNIを起動してコンテナにネットワークを追加
→なのでk8sはネットワークを認識している&
ネットワークが実際に存在する
Agenda
×コンテナのネットワークについて
×実際の手法
×コードの解説 (超簡略版)
× CNIがどのようにインターフェースをコンテナに関連付けしているのか?
× CNIプロジェクト本家のbridgeプラグイン
× github.com/containernetworking/plugins/main/bridge/bridge.g
o
× 500行程度
×応用
bridge.go
489 func main() {
490 skel.PluginMain(cmdAdd, cmdDel, version.All)
491 }
× https://github.com/containernetworking/cni に仕様書
× CNIは単体で実行できるものならなんでもOK (shell scriptも可)
× 実装するものはADDとDELとVERSIONの3命令
× 必要な情報はSTDINと環境変数で提供
× STDIN: ネットワークの情報 (/etc/cni/net.d)
× 環境変数: コマンド(ADD/DEL/VERSION)とコンテナの情報
bridge.go
310 func cmdAdd(args *skel.CmdArgs) error {
//略
324 br, brInterface, err := setupBridge(n)
//略
329 netns, err := ns.GetNS(args.Netns)
//略
335 hostInterface, containerInterface, err := setupVeth(netns, br, args.IfName,
n.MTU, n.HairpinMode)
//略
365 if err := netns.Do(func(_ ns.NetNS) error {
//略
375 if err := ipam.ConfigureIface(args.IfName, result); err != nil {
ブリッジを見つけて
コンテナのNET_NSを
取得
Vethの作成とブリッ
ジへの接続
コンテナのNET_NSに
移動して
IPアドレスを設定
bridge.go
コードから分かること:
× vethはnetlink (kernelの機能)で作成可能
× netlinkのIFLA_NET_NS_FDでインターフェースを他のNET_NSに移動
× setns()システムコールを使うことでプログラム内で希望したNET_NSに移動
× Go言語ではnetlink, netns等のライブラリがgithubに存在すること
→ これらを使えばコンテナのネットワークを自由に変更可能?
Agenda
×コンテナのネットワークについて
×実際の手法
×コードの解説 (超簡略版)
×応用
× ここまでの知見からツールを作ってみました
× ツールの解説
× デモ
koko (Container Connector)
https://github.com/redhat-nfvpe/koko
netns, netlinkを使ってコンテナをp2pで接続するコマンド
コンテナ:
docker, netns, PID
インターフェース:
veth, vxlan, vlan, macvlan
Port-mirroring (network tapping)
ingress, egress, both
demo1
× dockerとnetns間をvethで接続してping
koko -d test1,eth0,192.168.1.1/24 -d test2,eth0,192.168.1.2/24
demo2
× dockerのコンテナにveth3を作成
× veth2が受信するパケットをミラーして、vxlanにして他のホストに送信
koko -d node1,mirror1,mirror:ingress:eth0 -x eth1,10.10.10.2,100
Agenda
×コンテナのネットワークについて
×実際の手法
×コードの解説
×応用
Thanks!
Any questions?
You can find me at
@s1061123
&
s1061123@gmail.com
SlidesCarnival icons are editable shapes.
This means that you can:
● Resize them without losing quality.
● Change fill color and opacity.
● Change line color, width and style.
Isn’t that nice? :)
Examples:
Now you can use any emoji as an icon!
And of course it resizes without losing quality and you can change the color.
How? Follow Google instructions
https://twitter.com/googledocs/status/730087240156643328
✋👆👉👍👤👦👧👨👩👪💃🏃💑❤😂
😉😋😒😭👶😸🐟🍒🍔💣📌📖🔨🎃🎈
🎨🏈🏰🌏🔌🔑 and many more...
😉

コンテナのネットワークインターフェース その実装手法とその応用について

Editor's Notes

  • #2 http://www.slidescarnival.com/ja/%E3%82%A2%E3%82%A4%E3%82%A2%E3%83%A9%E3%82%B9%E3%81%AE%E3%83%97%E3%83%AC%E3%82%BC%E3%83%B3%E3%83%86%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E3%83%86%E3%83%B3%E3%83%97%E3%83%AC%E3%83%BC%E3%83%88/1681