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

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

Avatar for Tomofumi Hayashi Tomofumi Hayashi
August 27, 2017
38

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

July Tech Festa, August 2017

Avatar for Tomofumi Hayashi

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... 😉