Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

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

3,762 views

Published on

July Tech Festa, August 2017

Published in: Engineering
  • Hello! Get Your Professional Job-Winning Resume Here - Check our website! https://vk.cc/818RFv
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here

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

  1. 1. コンテナのネットワークインターフェース その実装手法とその応用について @JTF 2017, 2017/8/27 林 智史 s1061123@gmail.com id:s1061123, @s1061123
  2. 2. Agenda ×コンテナのネットワークについて ×実際の手法 ×コードの解説 ×応用
  3. 3. Agenda ×コンテナのネットワークについて × どんなインターフェイスで通信しているのか? × どうやって他のコンテナと分離しているのか? × 実際の手法 ×コードの解説 ×応用
  4. 4. コンテナで使ってるネットワークインターフェイスって? 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 /]#
  5. 5. コンテナで使ってるネットワークインターフェイスって? [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’ オプションを追加
  6. 6. コンテナで使ってるネットワークインターフェイスって? 32: eth0@if33: <BROADCAST, link/ether 02:42:ac:11 veth inet 172.17.0.2/16 sco valid_lft forever p
  7. 7. コンテナで使ってるネットワークインターフェイスって? 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インターフェース
  8. 8. 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”
  9. 9. Agenda ×コンテナのネットワークについて × どんなインターフェイスで通信しているのか? × どうやって他のコンテナと分離しているのか? × 実際の手法 ×コードの解説 ×応用
  10. 10. コンテナのネットワークの分離 namespace (名前空間)というものでネットワークを 含む各種リソースを分離 × PID_NS: pid空間を分離 × NET_NS: ネットワークを分離 (← これ!) × USER_NS: ユーザ権限を分離 × IPC_NS: メッセージキュー・shmemの分離 × UTS_NS: ホストネームの分離
  11. 11. コンテナのネットワークの分離 NET_NS: ×<kernel>/include/net/net_namespace.h に定義 × IPv4 (arp/ルーティング 含む) × IPv6 (neighbor/ルーティング 含む) × Unixドメインソケット × netfilter (例: iptables) × conntrack (NATテーブル) × その他(MPLS, sctp等) これらをNET_NS毎 に分離 コンテナ毎に分離
  12. 12. コンテナのネットワークの分離 ホスト NET_NS1 (ホストのNET_NS) NET_NS2 (dockerで作成) em1 192.168.1.1 bash bash eth0 192.168.1.1 同じアドレスで も競合しない!
  13. 13. コンテナのネットワークの分離 'docker run --net host ...’ ‘docker run --net bridge …’ ‘docker run --net none ...’
  14. 14. ホスト NET_NS1 (ホストのNET_NS) em1 192.168.1.1 bash ‘docker run --net host … bash’ の場合 dockerで作成 '--net host': NET_NSを作成せずにホストのものをそのまま流用 (pidは分離)
  15. 15. ‘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
  16. 16. ‘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()
  17. 17. Agenda ×コンテナのネットワークについて ×実際の手法 ×dockerがどのように提供しているのか? ×k8sがどのように提供しているのか? ×コードの解説 ×応用
  18. 18. Agenda ×コンテナのネットワークについて ×実際の手法 ×dockerがどのように提供しているのか? ×k8sがどのように提供しているのか? ×コードの解説 ×応用
  19. 19. dockerの場合 × Docker自身はネットワークを作成しない × libnetworkを使用して作成 × libnetworkはドライバでどのようなネットワークを指 定可能 × ドライバでは以下のAPIを実装している × Config × {Create,Delete}Network × {Create,Delete}Endpoint × Join, Leave
  20. 20. 例 $ 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,
  21. 21. Agenda ×コンテナのネットワークについて ×実際の手法 ×dockerがどのように提供しているのか? ×K8sがどのように提供しているのか? × コンテナランタイム: docker × ネットワーク: CNI (Calico) ×コードの解説 ×応用
  22. 22. 例 $ 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
  23. 23. 例 $ 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
  24. 24. k8sの場合 k8sの場合は? × コンテナランタイム: docker × ネットワーク: CNI (Calico) 結果 × docker側はネットワークが無いという × k8sから見るとネットワークはあるという → 実際コンテナにはネットワークが見える
  25. 25. k8sのコンテナとネットワークの関係 1. kubectlでコンテナの起動命令 2. kubeletがdockerでコンテナを"--net none"で起動 実際にはdocker API経由なので NetworkMode = "none" 1. コンテナはネットワーク無しで起動 →なのでdockerから見るとネットワークはなしで起動している 1. kubeletがCNIを起動してコンテナにネットワークを追加 →なのでk8sはネットワークを認識している& ネットワークが実際に存在する
  26. 26. Agenda ×コンテナのネットワークについて ×実際の手法 ×コードの解説 (超簡略版) × CNIがどのようにインターフェースをコンテナに関連付けしているのか? × CNIプロジェクト本家のbridgeプラグイン × github.com/containernetworking/plugins/main/bridge/bridge.g o × 500行程度 ×応用
  27. 27. 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)とコンテナの情報
  28. 28. 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アドレスを設定
  29. 29. bridge.go コードから分かること: × vethはnetlink (kernelの機能)で作成可能 × netlinkのIFLA_NET_NS_FDでインターフェースを他のNET_NSに移動 × setns()システムコールを使うことでプログラム内で希望したNET_NSに移動 × Go言語ではnetlink, netns等のライブラリがgithubに存在すること → これらを使えばコンテナのネットワークを自由に変更可能?
  30. 30. Agenda ×コンテナのネットワークについて ×実際の手法 ×コードの解説 (超簡略版) ×応用 × ここまでの知見からツールを作ってみました × ツールの解説 × デモ
  31. 31. 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
  32. 32. demo1 × dockerとnetns間をvethで接続してping koko -d test1,eth0,192.168.1.1/24 -d test2,eth0,192.168.1.2/24
  33. 33. demo2 × dockerのコンテナにveth3を作成 × veth2が受信するパケットをミラーして、vxlanにして他のホストに送信 koko -d node1,mirror1,mirror:ingress:eth0 -x eth1,10.10.10.2,100
  34. 34. Agenda ×コンテナのネットワークについて ×実際の手法 ×コードの解説 ×応用
  35. 35. Thanks! Any questions? You can find me at @s1061123 & s1061123@gmail.com
  36. 36. 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:
  37. 37. 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... 😉

×