Upgrade to Pro — share decks privately, control downloads, hide ads and more …

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

Tomofumi Hayashi
August 27, 2017
17

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

July Tech Festa, August 2017

Tomofumi Hayashi

August 27, 2017
Tweet

Transcript

  1. コンテナで使ってるネットワークインターフェイスって? 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 /]#
  2. コンテナで使ってるネットワークインターフェイスって? [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’ オプションを追加
  3. コンテナで使ってるネットワークインターフェイスって? 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インターフェース
  4. 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”
  5. コンテナのネットワークの分離 namespace (名前空間)というものでネットワークを 含む各種リソースを分離 × PID_NS: pid空間を分離 × NET_NS: ネットワークを分離

    (← これ!) × USER_NS: ユーザ権限を分離 × IPC_NS: メッセージキュー・shmemの分離 × UTS_NS: ホストネームの分離
  6. コンテナのネットワークの分離 NET_NS: ×<kernel>/include/net/net_namespace.h に定義 × IPv4 (arp/ルーティング 含む) × IPv6

    (neighbor/ルーティング 含む) × Unixドメインソケット × netfilter (例: iptables) × conntrack (NATテーブル) × その他(MPLS, sctp等) これらをNET_NS毎 に分離 コンテナ毎に分離
  7. ホスト NET_NS1 (ホストのNET_NS) em1 192.168.1.1 bash ‘docker run --net host

    … bash’ の場合 dockerで作成 '--net host': NET_NSを作成せずにホストのものをそのまま流用 (pidは分離)
  8. ‘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
  9. ‘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()
  10. 例 $ 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,
  11. 例 $ 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
  12. 例 $ 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
  13. k8sの場合 k8sの場合は? × コンテナランタイム: docker × ネットワーク: CNI (Calico) 結果

    × docker側はネットワークが無いという × k8sから見るとネットワークはあるという → 実際コンテナにはネットワークが見える
  14. k8sのコンテナとネットワークの関係 1. kubectlでコンテナの起動命令 2. kubeletがdockerでコンテナを"--net none"で起動 実際にはdocker API経由なので NetworkMode =

    "none" 1. コンテナはネットワーク無しで起動 →なのでdockerから見るとネットワークはなしで起動している 1. kubeletがCNIを起動してコンテナにネットワークを追加 →なのでk8sはネットワークを認識している& ネットワークが実際に存在する
  15. 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)とコンテナの情報
  16. 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アドレスを設定
  17. 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:
  18. 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... 😉