この記事は、Udemyの講座 https://www.udemy.com/course/certified-kubernetes-administrator-with-practice-tests および https://kodekloud.com/ の内容を学習しながらまとめたものです。
- 201 Switching Routing
- 202 DNS
- 204 Network Namespaces
- 206 Docker Networking
- 207 CNI
- 212 Pod Networking
- 213 CNI in Kubernetes
- 223 Service Networking
- 226 DNS in kubernetes
- 227 Core DNS in kubernetes
- 230 Ingress
201 Switching Routing
Switchは同一ネットワーク内のデバイスを接続します。

Routerは2つ以上の分離されたネットワークを接続します。あるネットワークから別のネットワークへパケットが移動する際にはGatewayを経由しますが、これはRouterに接続されたアドレスを意味します。

カーネルのルーティングテーブルは以下のコマンドで確認できます。
root@latte01:~# route -n
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
0.0.0.0 192.168.219.1 0.0.0.0 UG 100 0 0 enp2s0
169.254.0.0 0.0.0.0 255.255.0.0 U 1000 0 0 enp2s0
172.17.0.0 0.0.0.0 255.255.0.0 U 0 0 0 docker0
192.168.219.0 0.0.0.0 255.255.255.0 U 100 0 0 enp2s0
アクセスしたいすべてのIPアドレスを明示する代わりに、0.0.0.0 を入力してすべてのネットワークを表すことができます。

外部へ出るルーターと内部ネットワークへ出るルーターが分離されている場合、ルーティングテーブルに別途指定できます。

LinuxマシンをRouterとしてセットアップするにはどうすればよいでしょうか?以下のようにBに2つのネットワークインターフェースを付与した上で、AからBへpingを送っても、正常にpingは返ってきません。その理由は、Linuxではセキュリティ上の問題から、デフォルトでパケットの転送(forward)がブロックされているためです。

Bのマシンで echo 1 > /proc/sys/net/ipv4/ip_forward を実行してforwardを有効にすると、正常にRouterとして動作するようになります。再起動後も同じ設定を維持するには、/etc/sysctl.conf に net.ipv4.ip_forward =1 を設定します。
202 DNS
/etc/hosts にHost Bを「db」として登録すると、IPの代わりに文字列の名前を使用できるようになります。/etc/hosts はローカルのネームサーバー(DNS)と呼ばれます。ただし、実際に「db」と呼ばれるサーバーのホスト名が「db」ではない場合があります。また、サーバー数が増えたり、IPアドレスが変更される状況では管理がさらに困難になります。

IPアドレスとホスト名のマッピングを管理するサーバーをDNSサーバーと呼びます。
すべてのサーバーは /etc/resolv.conf というファイルにネームサーバーを登録して使用します。

ネームサーバーを利用するからといって、ローカルの /etc/hosts ファイルが使えなくなるわけではなく、同様に使用可能です。IP→ホスト名のマッピング情報を検索する際、DNSサーバーよりも /etc/hosts ファイルの内容が優先的に検索されます。この順序は /etc/nsswitch.conf のhostsに登録されています。デフォルトは files dns となっており、これは /etc/hosts を先に検索するという意味です。
8.8.8.8はGoogleが運営する有名なネームサーバーです。複数のネームサーバーをここに定義できます。
DNSサーバーでapps.google.comを検索する場合、以下のようにDNSツリーをたどってIPアドレスを取得します。一度取得したらローカルにキャッシュして再利用します。

IPをホスト名に変換するのをAタイプレコードと呼びます。エイリアス(別名)を持たせるのをCNAMEと呼びます。

nslookup <domain_name> でネームサーバーとIPを調べることができますが、注意すべき点はnslookupは /etc/hosts を検索しないということです。このため、実際のローカルでのネットワーク動作と異なる場合があることを認識しておく必要があります。
digもネームサーバーを調べるのに優れたツールです。
nslookup www.google.com
dig www.google.com
204 Network Namespaces
コンテナには独自のRouting TableとARP Tableが存在します。独立したネットワーク名前空間が存在するのです。

新規ネットワーク名前空間を作成するには ip netns add <namespace_name> を入力します。ip ns コマンドで作成された名前空間を確認できます。
名前空間内部でipコマンドを使用するには以下のようにします。link コマンド入力時、ホストとは異なりloopback link以外は確認できません。arp や route コマンドも同様です。

新しい名前空間は外部への接続が設定されていないため、他の名前空間との通信のためにはネットワーク接続を設定する必要があります。この接続プロセスは物理的なケーブルを接続すること(virtual cable)に似ています。

設定が完了すると、ARPテーブルを照会した際に相手の情報が含まれています。ただし、ホストのARPテーブルにはこれに関連する情報は全くありません。

2つではなくそれ以上の名前空間が存在する場合はどうすればよいでしょうか?この場合、仮想スイッチを作成する必要があります。Linux BridgeとOpen vSwitchが最も有名で、今回はLinux Bridgeについて説明します。

Linux Bridgeを作成する前に、以前作成したredとblueのvirtual cableを削除します。ip -n red link del veth-red で削除できます。
以下の方法でLinux Bridgeに名前空間を接続すると、名前空間同士で通信ができるようになります。


BridgeとHost間の接続を設定するにはどうすればよいでしょうか?BridgeにIPを付与すれば完了です。

このように作成した4つの名前空間はプライベートネットワークであるため、外部との通信はできません。

以下のようにblueのルーティングテーブルにgatewayとしてBridge Networkを設定します。

そして以下のコマンドで 192.168.15.0/24 から入ってくるパケットをホストのパケットとして設定すると、pingが可能になります。

最後にデフォルトゲートウェイまで設定すれば完了です。

外部からプライベートネットワークにアクセスするには2つの方法があります。NATを利用するか、ポートフォワーディングを利用する方法です。

206 Docker Networking
Dockerは内部的に docker0 というBridgeを作成し、名前空間間およびホストマシンとの通信に使用します。これは docker network ls コマンドで確認できます。


Dockerでコンテナを起動すると、名前空間が1つ作成されると考えてください。そしてその名前空間とdocker0 Bridgeは、先ほど見たvirtual cableで接続されます。


ポートフォワーディングも先ほど見たのと同様に、iptablesにNATルールを追加して行います。

ポートフォワーディングが設定された後、iptables -nvL -t nat コマンドでiptablesを確認すると、DNATが追加されていることが確認できます。

207 CNI
以前、Network Namespaceを作成してネットワークを接続するプロセスと、Dockerでネットワークを接続するプロセスを一緒に見てきました。この2つは非常に似ています。rkt、Mesos、Kubernetesも同じ問題を解決する必要があります。CNI(Container Network Interface)は、Kubernetesでコンテナ間のネットワーク通信のために実装すべき事項を定義しています。そのため、CNIに準拠して実装されたプラグインは、どのランタイムでも正常に動作します。

DockerはCNI標準に準拠しておらず、独自のCNM(Container Network Model)を持っているため、CNI(Flannel、Weaveworks)を使用できません。

etcdプロセスが使用中のポートの確認方法:
$ netstat -anp | grep etcd
tcp 0 0 192.5.203.6:2379 0.0.0.0:* LISTEN 3644/etcd
tcp 0 0 127.0.0.1:2379 0.0.0.0:* LISTEN 3644/etcd
tcp 0 0 192.5.203.6:2380 0.0.0.0:* LISTEN 3644/etcd
...
2379ポートはetcdがすべてのKubernetes Control Planeコンポーネントと通信する際に使用するポートで、2380はピア接続に使用するポートです。
212 Pod Networking
Kubernetesはすべてのpodに固有のIPアドレスを付与し、すべてのpod間でNATなしに通信可能なモデルを構築しました。このネットワークモデルを構築するために、Kubernetesはどのような問題を解決する必要があったのでしょうか?CNI標準に準拠して作られたさまざまなネットワークプラグインがこれらを解決しました(Flannel、Weave net、Cilium)。

まず、すべてのノードにBridge Networkを作成し、Podが作成されるたびにネットワーク名前空間とBridgeに接続されるvethを生成します。これにより、1つのノード内にあるPod同士は通信可能な状態になります。しかし、別のノードにあるPodとの通信はまだできません。

各ノードのルーティングテーブルに以下のようにgatewayを設定すれば、他のノードとのネットワーク通信も問題なく行えるようになります。

概念的にはそれほど複雑ではありませんが、数百〜数千台のノードがある環境のKubernetesクラスターに適用するのは容易ではありません。しかし、CNIがこれを解決してくれるため、大きな心配は不要です。CNIは複雑なスクリプトを ADD、DELETE にグループ化して管理・実行できるように提供しています。
これらのスクリプトは /etc/cni/net.d/net-script.conflist と /opt/cni/bin/net-script.sh にあり、ユーザーが直接これらのスクリプトを使用することもできます。

213 CNI in Kubernetes
network-pluginはkubelet.serviceで設定可能です。CNIの実行バイナリは /opt/cni/bin に位置し、設定ファイルは /etc/cni/net.d 配下にあります。

実際にBridge Networkの構成に使用される設定ファイルは以下のようになっています。

Bridge Networkの範囲を知りたい場合は、ip link でBridge Network名を見つけ、ip addr show で調査します。
$ ip addr show weave
4: weave: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1376 qdisc noqueue state UP group default qlen 1000
link/ether be:b5:e6:4f:f0:c1 brd ff:ff:ff:ff:ff:ff
inet 10.244.0.1/16 brd 10.244.255.255 scope global weave
valid_lft forever preferred_lft forever
$ ip addr show weave
4: weave: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1376 qdisc noqueue state UP group default qlen 1000
link/ether aa:be:68:65:bf:37 brd ff:ff:ff:ff:ff:ff
inet 10.244.192.0/16 brd 10.244.255.255 scope global weave
valid_lft forever preferred_lft forever
223 Service Networking
Serviceがデプロイされると、どのノードにデプロイされていても他のサービスから利用できる必要があります。このために、KubernetesではServiceにCluster IPを作成します。これにより、実際のPodのIPが変わっても、Serviceを使用する側はCluster IPを使用するため、シームレスに運用できます。クラスター外部からIPにアクセスする必要がある場合、Cluster IPは使用できません。この場合、NodePortというServiceで外部にエンドポイントを提供できます。これを可能にするのはkube-proxyです。cluster-ipの範囲はkube-api-serverの起動時に引数として入力する値です。


実際にiptablesでサービス名を検索すると、Cluster IPと実際のPodのIPがDNATとして設定されていることが確認できます。

ip addr でBridgeのネットワーク範囲を確認できます。
226 DNS in kubernetes
Kubernetes内部でもDNSを利用できます。Serviceを作成するとCluster IPが生成され、このCluster IPはKube DNSにサービス名で登録されます。他のPodからCluster IPではなくホスト名(web-service)でアクセスしても問題なくアクセスできます。もちろん、同じnamespaceにある場合の話で、別のnamespaceにあるPodからアクセスするには web-service.apps でアクセスする必要があります。


ServiceではないPodはDNSに自動的に登録されません。設定を通じて登録できますが、この場合ホスト名はIPアドレスの . を - に置換したものが設定されます。

227 Core DNS in kubernetes
CoreDNSはkube-system namespaceで実行されるReplicaSet(Deployment)です。
/etc/coredns/Corefile でCoreDNSに関する設定ができます。CoreDNSの設定値はConfigMapに保存され、この値も変更可能です。

CoreDNSは kube-dns という名前でクラスター内部からアクセス可能なエンドポイントを作成し、すべてのPodの /etc/resolv.conf のnameserverにこのDNSサーバーのIPアドレスが自動的に記入されます。

ホスト名だけを入力してもFQDN(Fully Qualified Domain Name)を取得できますが、その理由は先ほど見た /etc/resolv.conf 内部の search に設定された上位ドメインのためです。

Pod内部でnslookupした結果をローカルにコピーする方法:
kubectl exec -it hr -- nslookup mysql.payroll > /root/CKA/nslookup.out
230 Ingress
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: test-ingress
namespace: critical-space
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
nginx.ingress.kubernetes.io/ssl-redirect: "false"
spec:
rules:
- http:
paths:
- path: /pay
pathType: Prefix
backend:
service:
name: pay-service
port:
number: 8282
クイズ
Q1: 「CKA_9_Network」の主なトピックは何ですか?
CKA_9_Network
Q2: この記事の重要なポイントは何ですか?
CKA_9_Network
Q3: この記事の概念を実践にどう適用できますか?
記事全体で議論されている実践的な例やパターンを参考にしてください。