vExperts Advent Calendar 2018の12月21日分の投稿です。
Network Policy
Network PolicyはKubernetesクラスター内のPod間通信や、他のネットワークとの通信を制御するために利用します。ラベルを使用してPodを選択し、選択したPodに許可されるトラフィックを指定するルールを定義します。Network PolicyはCNIプラグインによって実装され、Network Policyを利用するにはNetwork PolicyをサポートするCNIプラグインを使用する必要があります。
Network Policyに対応するネットワークプラグイン
FlannelはNetwork Policyに対応していませんが、多くのネットワークプラグインはNetwork Policyに対応しており、VMware NSX-TもNetwork Policyに対応しています。各CNIプラグインは比較は以下の資料が参考になります。
VMware NSX-TのNetwork Policy実装
NSX-Tの分散ファイアウォールは、ハイパーバイザー上の仮想マシンに対して透過的なファイアウォール機能を提供することができます。ハイパーバイザー上のKubernetes環境でNSX-T Container Plug-inを利用することにより、Kubernetes環境のコンテナネットワークとしてNSX-Tを利用することが可能になります。Kubernetes環境ではハイパーバイザー上の仮想マシンがNodeとして機能し、仮想マシン内でPod(コンテナ)が起動します。コンテナ間の通信はNode内で行われる可能性があるため、コンテナ間の通信を制御するためにNode VM内のOpen vSwitchがハイパーバイザーと連携し、ハイパーバイザーの分散ファイアウォール機能により同一Node内のPod間の通信を制御することを実現しています。
NSX-TのCNIプラグインは、NCP(NSX-T Container Plug-in)とNSX Node Agent、Open vSwitchによって構成されます。NCPはKubernetes Masterと通信してPodの作成や削除に対してNSX Managerに対して論理ネットワークの変更を行います。NSX Node AgentはDaemonSetとしてKubernetes Node上機能し、Open vSwitchと共にNode上のコンテナネットワークの管理を行います。
# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE
nsx-ncp-kvjdp 1/1 Running 0 3d19h 192.168.9.21 node01 <none>
nsx-node-agent-b2nzp 2/2 Running 0 3d19h 192.168.9.22 node02 <none>
nsx-node-agent-fpprh 2/2 Running 0 3d19h 192.168.9.21 node01 <none>
確認してみた
Enforcing Network Policies in Kubernetesを参考にNetwork Policyを構成して、NSX-Tの実装を確認してみます。
確認は以下の環境で行いました。
- Ubuntu 16.04.5
- Kubernetes 1.12.3
- vSphere 6.7.0
- NSX-T 2.3
- NSX Container Plugin 2.3.1
Nginx Podの作成
テスト用のnginx podを作成します。
# cat nginx.yaml
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
selector:
matchLabels:
app: nginx
replicas: 2
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.15.7-alpine
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: nginx
spec:
ports:
- port: 80
protocol: TCP
selector:
app: nginx
# kubectl apply -f nginx.yaml
deployment.apps/nginx-deployment created
service/nginx created
作成されたpodを確認します。作成されたnginx podにはapp=nginx
ラベルが付与され、172.15.0.4
と172.15.0.5
のIPアドレスが割り当てられ、内部向けのClusterIPとして10.110.125.44
が割り当てられています。
# kubectl get pod -l app=nginx -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE
nginx-deployment-797d64cb5f-6m4xl 1/1 Running 0 9s 172.15.0.5 node01 <none>
nginx-deployment-797d64cb5f-lrhc6 1/1 Running 0 9s 172.15.0.4 node02 <none>
# kubectl get svc -o wide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 19h <none>
nginx ClusterIP 10.110.125.44 <none> 80/TCP 17s app=nginx
作成されたPodはNSX Manager上でも論理ポートとして認識されます。
論理ポートの詳細画面では、PodのIPアドレスが認識されていることがわかります。以下の画面は、Pod nginx-deployment-797d64cb5f-6m4xl
の詳細画面です。
クライアント用Podの作成
busyboxコンテナイメージでクライアント用のPodを起動します。
# kubectl run busybox --rm -ti --image=busybox /bin/sh
kubectl run --generator=deployment/apps.v1beta1 is DEPRECATED and will be removed in a future version. Use kubectl create instead.
If you don't see a command prompt, try pressing enter.
/ #
Network Policyを利用していないため、wgetコマンドでnginxにアクセスしてみるとClusterIP経由でアクセスが可能です。
/ # wget --spider --timeout 1 nginx
Connecting to nginx (10.110.125.44:80)
/ #
Network Policyの適用
以下のNetwork Policyはを適用します。'''app=foo'''ラベルが付いているPodはnginxに対するアクセスを許可します。
# cat access-nginx.yaml
kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
name: access-nginx
spec:
podSelector:
matchLabels:
app: nginx
ingress:
- from:
- podSelector:
matchLabels:
app: foo
# kubectl apply -f access-nginx.yaml
networkpolicy.networking.k8s.io/access-nginx created
# kubectl get networkpolicy
NAME POD-SELECTOR AGE
access-nginx app=nginx 6s
クライアント用Podからのアクセス確認
クライアント用Podにはapp=foo
ラベルを付与していないため、Network Policyが有効化されたことでnginxに対してアクセスができなくなります。
/ # wget --spider --timeout 1 nginx
Connecting to nginx (10.110.125.44:80)
wget: download timed out
/ #
分散ファイアウォールルールの確認
Network Policyを適用したことにより、NSX Managerの分散ファイアウォールルールにセクションとルールが追加されています。
追加されているルールは次のような状態です。適用先はすべてproj-k8scluster-default
となっています。
名前 | 送信元 | 宛先 | アクション |
---|---|---|---|
ir-k8scluster-default-access-nginx-all | src-k8scluster-default-access-nginx-all | tgt-k8scluster-default-access-nginx | 許可 |
ir-k8scluster-default-access-nginx | 任意 | tgt-k8scluster-default-access-nginx | ドロップ |
er-k8scluster-default-access-nginx | tgt-k8scluster-default-access-nginx | 任意 | 許可 |
送信元/宛先として利用されているsrc-k8scluster-default-access-nginx-all
とtgt-k8scluster-default-access-nginx
はNSX ManagerのIPセットとして定義されており、tgt-k8scluster-default-access-nginx
にはnginx PodのIPアドレスが登録されています。(この時点ではsrc-k8scluster-default-access-nginx-all
には何も登録されていません)
適用先のproj-k8scluster-default
は、NSX ManagerのNS Groupとして定義されており、以下のようなメンバーシップ基準によりdefaultネームスペースに存在するすべてのPodがこのNS Groupにマッチします。(今回はdefaultネームスペースで確認を行っているため)
クライアント用PodのLabelの更新 (app=foo)
起動済みのクライアント用Podのラベルを更新して、app=foo
に変更します。
# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE
busybox-68f48b9c57-bt5fg 1/1 Running 0 3m13s 172.15.0.2 node02 <none>
nginx-deployment-797d64cb5f-6m4xl 1/1 Running 0 5m28s 172.15.0.5 node01 <none>
nginx-deployment-797d64cb5f-lrhc6 1/1 Running 0 5m28s 172.15.0.4 node02 <none>
nsx-ncp-kvjdp 1/1 Running 0 5h33m 192.168.9.21 node01 <none>
nsx-node-agent-b2nzp 2/2 Running 0 5h31m 192.168.9.22 node02 <none>
nsx-node-agent-fpprh 2/2 Running 0 5h31m 192.168.9.21 node01 <none>
# kubectl label pod busybox-68f48b9c57-bt5fg --overwrite app=foo
pod/busybox-68f48b9c57-bt5fg labeled
再度アクセスを確認すると、クライアント用Podからnginxへのアクセスが可能になりました。
/ # wget --spider --timeout 1 nginx
Connecting to nginx (10.110.125.44:80)
/ #
ラベルを更新したことにより、src-k8scluster-default-access-nginx-all
IPセットにクライアント用PodのIPアドレス(172.16.0.2)が追加されています。
クライアント用PodのLabelの更新 (app=bar)
クライアント用PodのLabelをapp=bar
に変更すると、src-k8scluster-default-access-nginx-all
IPセットからクライアント用Podのアドレスが削除され、再びnginxにアクセスできなくなります。
# kubectl label pod busybox-68f48b9c57-bt5fg --overwrite app=bar
pod/busybox-68f48b9c57-bt5fg labeled
/ # wget --spider --timeout 1 nginx
Connecting to nginx (10.110.125.44:80)
wget: download timed out
/ #
Traceflow機能
NSX ManagerにはTraceflowと呼ばれる論理ネットワークの可視化ツールがあり、この機能を使うことによりPod間通信の通信パスを確認することも可能です。
Node VMとハイパーバイザー内の状態
Node VM上でOpen vSwitchの状態を確認すると、Pod用の論理ポートが生成され、VLAN IDが付与されています。
root@node02:~# ovs-vsctl show
3e4093e6-ef13-47d9-a6fa-c8ef144dd7b4
Bridge br-int
Port "ens192"
Interface "ens192"
Port br-int
Interface br-int
type: internal
Port "busybox-68f48b9c57-bt5fg_7c45839e0879a86"
tag: 14
Interface "7c45839e0879a86"
Port nsx_agent_outer
tag: 4094
Interface nsx_agent_outer
Port "coredns-576cbf47c7-c5wfw_b9d8ffb2df016a5"
tag: 1
Interface "b9d8ffb2df016a5"
Port "nginx-deployment-797d64cb5f-lrhc6_2c0ea440acf1152"
tag: 13
Interface "2c0ea440acf1152"
ovs_version: "2.9.1.9968033"
ハイパーバイザー内でNode VMのスイッチポートに対する接続状態を確認すると、Node VM上で管理されているOpen vSwitchの論理ポートがNode VMのサブインターフェースとしてハイパーバイザー上で認識されており、各ポートには分散ファイアウォール用のフィルターが適用されています。Node VM内で起動するコンテナ間の通信制御がハイパーバイザーの分散ファイアウォールにオフロードされています。
[root@nsxt-esx02:~] summarize-dvfilter
...
world 5739119 vmm0:node02 vcUuid:'50 36 53 ba cb 95 d2 06-e8 8c 33 b4 7b ba d1 0e'
port 67108884 node02.eth1
vNic slot 2
name: nic-5739119-eth1-vmware-sfw.2
agentName: vmware-sfw
state: IOChain Attached
vmState: Detached
failurePolicy: failClosed
serviceVMID: none
filter source: Dynamic Filter Creation
...
port 67108904 node02.eth1.13
vNic slot 1
name: nic-5739119-eth33-vmware-sfw.1
agentName: vmware-sfw
state: IOChain Attached
vmState: Detached
failurePolicy: failClosed
serviceVMID: none
filter source: Alternate Opaque Channel
port 67108906 node02.eth1.14
vNic slot 1
name: nic-5739119-eth35-vmware-sfw.1
agentName: vmware-sfw
state: IOChain Attached
vmState: Detached
failurePolicy: failClosed
serviceVMID: none
filter source: Alternate Opaque Channel
...
Pod向けのインターフェースに適用されているフィルターを確認すると分散ファイアウォールルールが実際に適用されている事がわかります。
[root@nsxt-esx02:~] vsipioctl getrules -f nic-5739119-eth33-vmware-sfw.1
ruleset mainrs {
# generation number: 0
# realization time : 2018-12-17T09:22:20
rule 6266 at 1 in protocol any from addrset 105ee703-a9f2-4a5c-bf48-e56338b44a97 to addrset 9a0c2b94-3a78-42af-9d38-a2432cc89a00 accept;
rule 6269 at 2 in protocol any from any to addrset 9a0c2b94-3a78-42af-9d38-a2432cc89a00 drop;
rule 6270 at 3 out protocol any from addrset 9a0c2b94-3a78-42af-9d38-a2432cc89a00 to any accept;
rule 2 at 4 inout protocol any from any to any accept;
}
ruleset mainrs_L2 {
# generation number: 0
# realization time : 2018-12-17T09:22:20
rule 1 at 1 inout ethertype any stateless from any to any accept;
}
ファイアウォールルールの送信元、宛先として利用されているアドレスセットの内容を確認することが可能です。
[root@nsxt-esx02:~] vsipioctl getaddrsets -f nic-5739119-eth33-vmware-sfw.1
addrset 105ee703-a9f2-4a5c-bf48-e56338b44a97 {
# generation number: 0
# realization time : 2018-12-17T09:30:34
ip 172.15.0.2,
}
addrset 9a0c2b94-3a78-42af-9d38-a2432cc89a00 {
# generation number: 0
# realization time : 2018-12-17T09:22:19
ip 172.15.0.4,
ip 172.15.0.5,
}
まとめ
NSX-Tをk8sのコンテナネットワークとして利用すことにより、NSX-Tの分散ファイアウォール機能によりNetwork Policyを利用することが可能です。また、NSX-TはKubernetesのネームスペース作成じに動的にセグメントを生成したり、オンプレミスの環境であってもtype: LoadBalancer
の利用が可能になります。仮想マシン環境との親和性も高いため、NSX-Tの管理画面を通じて、Kubernetes環境とVM環境が混在する場合も一貫したネットワーク管理が可能になります。