kubernetes連携時の動作2
前回に引き続き、contrailとkubernetesを組み合わせた場合の動作の確認となる。
https://github.com/Juniper/contrail-controller/wiki/Kubernetes
ingress
ingress はservice と違い、L7でのロードバランスを行う仕組みとなる。
contrail 使用時は、各スレーブノード内にhaproxyが起動し、振り分けを行う動作となる。
サンプルのyamlは以下を参照。
https://github.com/tnaganawa/contrail-k8s-tutorial/tree/master/yml/3_contrail-cni-features/3_ingress
順に定義していくと、以下のように、ingress がsvc に対してアタッチされる動作となる。
root@ip-172-31-3-97:~# kubectl get pod -o wide NAME READY STATUS RESTARTS AGE IP NODE cirros-pod 1/1 Running 1 1d 10.47.255.252 ip-172-31-6-143 nginx-deployment-1286893921-hjkth 1/1 Running 0 6m 10.47.255.252 ip-172-31-6-143 nginx-deployment-1286893921-tbkhk 1/1 Running 0 6m 10.47.255.251 ip-172-31-15-186 root@ip-172-31-3-97:~# kubectl get deployment -o wide NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE CONTAINER(S) IMAGE(S) SELECTOR nginx-deployment 2 2 2 2 6m nginx nginx:1.7.9 app=nginx-deployment root@ip-172-31-3-97:~# kubectl get svc -o wide NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR kubernetes 10.96.0.1443/TCP 21d nginx-svc 10.97.170.21 80/TCP 6m app=nginx-deployment root@ip-172-31-3-97:~# kubectl get ing -o wide NAME HOSTS ADDRESS PORTS AGE nginx-ingress * 10.47.255.250 80 6m
pod内にログインして、curl実行することで、urlが提供されていることが分かる。
root@ip-172-31-3-97:~# kubectl exec -it cirros-pod sh / # / # curl 10.47.255.250 <!DOCTYPE html> <html> <head> <title>Welcome to nginx!</title> <style> (snip)
なお、ルーティングテーブルを確認してみると、該当のIPは各スレーブノードへの経路が配布されており、行き先は、特定のlinux namespaceとなっている。
スレーブノードにログインして確認 (agentのdocker内でnetnsが作成されている) してみると、以下のようにhaproxyが起動されていることが分かる。
root@ip-172-31-15-186(agent):/# ip netns RTNETLINK answers: Invalid argument RTNETLINK answers: Invalid argument vrouter-8e2c207e-8799-4422-8f3c-631635e67e03:aab44187-c1f9-11e7-8cc3-06b5b8f5fd22 root@ip-172-31-15-186(agent):/# root@ip-172-31-15-186(agent):/# ps -ef | cat UID PID PPID C STIME TTY TIME CMD root 1 0 0 07:12 ? 00:00:00 /lib/systemd/systemd systemd.unit=multi-user.target root 19 1 0 07:12 ? 00:00:00 /lib/systemd/systemd-journald root 814 1 2 07:12 ? 00:00:37 /usr/bin/contrail-vrouter-agent contrail 821 1 0 07:12 ? 00:00:05 /usr/bin/python /usr/bin/contrail-nodemgr --nodetype=contrail-vrouter message+ 920 1 0 07:12 ? 00:00:00 /usr/bin/dbus-daemon --system --address=systemd: --nofork --nopidfile --systemd-activation haproxy 2898 1 0 07:19 ? 00:00:00 haproxy -f /var/lib/contrail/loadbalancer/haproxy/aab44187-c1f9-11e7-8cc3-06b5b8f5fd22/haproxy.conf -p /var/lib/contrail/loadbalancer/haproxy/aab44187-c1f9-11e7-8cc3-06b5b8f5fd22/haproxy.pid -sf 2887 root 3451 0 0 07:34 ? 00:00:00 bash root 3802 3451 0 07:43 ? 00:00:00 ps -ef root 3803 3451 0 07:43 ? 00:00:00 cat root@ip-172-31-15-186(agent):/#
haproxy自体は各スレーブノードで起動されているようなので、スレーブノードが全て停止しない限り、ingressは継続出来るようである。
namespace
通常、kubernetes でnamespace を設定した場合、
等の違いはあるが、ネットワーク的には分離されない状況となる。
contrail 使用時も、この動作に変化はないが、追加の機能として、namespace 作成時に以下のannotation を設定することで、互いに疎通が取れないnamespace を作成することが出来るようになる。
※ 内部的には namespace の名前を持つ仮想ネットワークが作成される
annotations: { "opencontrail.org/isolation" : "true" }
yamlのサンプルは以下を参照。
https://github.com/tnaganawa/contrail-k8s-tutorial/tree/master/yml/3_contrail-cni-features/4_namespace
作成を行うと、以下のようにnamespaceが作成される。
root@ip-172-31-3-97:~# kubectl get ns -o wide NAME STATUS AGE default Active 21d kube-public Active 21d kube-system Active 21d myns1 Active 8m myns2 Active 6m root@ip-172-31-3-97:~# kubectl get pod -n myns1 -o wide NAME READY STATUS RESTARTS AGE IP NODE cirros-myns1 1/1 Running 0 2m 10.47.255.252 ip-172-31-15-186 root@ip-172-31-3-97:~# kubectl get pod -n myns2 -o wide NAME READY STATUS RESTARTS AGE IP NODE cirros-myns2 1/1 Running 0 11s 10.47.255.250 ip-172-31-6-143 root@ip-172-31-3-97:~#
※ namespace内にpodを作る場合、以下のように、作成時にnamespaceを指定する必要があるので注意
# kubectl create -n myns1 -f cirros-myns1.yaml pod "cirros-myns1" created
この状態で、myns1内のpodに入り、myns2内のpodにpingを打つと、pingが飛ばず、ネットワークが分離されていることが確認できる。
複数のシステムを扱い、システム間で互いに疎通できないようにしたい場合に、活用できるのではなかろうか。
root@ip-172-31-3-97:~# kubectl exec -it -n myns1 cirros-myns1 sh / # ping 10.47.255.250 PING 10.47.255.250 (10.47.255.250): 56 data bytes ^C --- 10.47.255.250 ping statistics --- 2 packets transmitted, 0 packets received, 100% packet loss
kubernetes連携時の動作1
contrail と kubernetes を組み合わせた場合の動作について、ざっくりとまとめておく。
詳細はこちらを参照。
https://github.com/Juniper/contrail-controller/wiki/Kubernetes
使用したyamlについては、こちらにまとめておく。
https://github.com/tnaganawa/contrail-k8s-tutorial/tree/master/yml/3_contrail-cni-features
pod, deployment
podは、kubernetes 内で実際にアプリの処理を行う部分で、複数のコンテナで構成される。
deploymentは、同じpodを複数まとめて立ち上げる仕組みで、スケールアウト等に用いられる。
※ 特に通常のkubernetes の動作と変わりがないので、詳しくはこちら等を参照。
https://kubernetes.io/docs/concepts/workloads/pods/pod/
https://kubernetes.io/docs/concepts/workloads/controllers/deployment/
service
service はpod にアクセスを行うための、ロードバランサーのようなものになる。
contrail では、type: ClusterIP (pod間の通信向け) と type: LoadBalancer (外部からの通信向け) が使用できる。
contrailを使用した場合、複数のpodを持つdeployment に対してserviceを定義すると、各vrouter (外部ルーターがある場合、そちらにも) にnext-hopが2つ設定され、ECMPでの負荷分散が行われる動作になる。
実際 clusterip で定義を行ってみて、内部のpodから確認してみたときの出力は以下となる。
2台のノード上にあるdeploymentに対して、ssh 用のsvc (ip: 10.96.205.1) を定義しているのだが、この場合、contrail内のルーティングテーブルには、svc用に、2つのnext-hop(172.31.6.143, 24と172.31.15.186, 60)が定義されている。
kubernetes 側から確認した場合、以下のように、deploymentに対応したpod2つと、svc 1つが定義されている状況となる。
root@ip-172-31-3-97:~# kubectl get pod -o wide NAME READY STATUS RESTARTS AGE IP NODE cirros-deployment-899733556-cj3jp 1/1 Running 0 1h 10.47.255.246 ip-172-31-15-186 cirros-deployment-899733556-tlr0m 1/1 Running 0 1h 10.47.255.247 ip-172-31-6-143 cirros-pod 1/1 Running 0 18s 10.47.255.252 ip-172-31-6-143 root@ip-172-31-3-97:~# root@ip-172-31-3-97:~# kubectl get deployment -o wide NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE CONTAINER(S) IMAGE(S) SELECTOR cirros-deployment 2 2 2 2 1h cirros cirros app=cirros-deployment root@ip-172-31-3-97:~# root@ip-172-31-3-97:~# kubectl get svc -o wide NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR cirros-clusterip 10.96.205.122/TCP 6s app=cirros-deployment kubernetes 10.96.0.1 443/TCP 19d root@ip-172-31-3-97:~#
podにログインした後、何度かsshを発行すると、以下のように別の鍵が返ってきて、負荷分散が行われていることが分かる。
root@ip-172-31-3-97:~# kubectl exec -it cirros-pod sh / # ssh 10.96.205.1 Host '10.96.205.1' is not in the trusted hosts file. (fingerprint md5 8b:31:ad:50:47:de:8d:b3:9a:3a:e6:da:b9:e5:f8:7a) Do you want to continue connecting? (y/n) ssh: Connection to root@10.96.205.1:22 exited: Didn't validate host key / # ssh 10.96.205.1 Host '10.96.205.1' is not in the trusted hosts file. (fingerprint md5 bb:ac:0e:ea:1e:a9:41:57:dc:e0:04:59:f7:49:b5:23) Do you want to continue connecting? (y/n) ssh: Connection to root@10.96.205.1:22 exited: Didn't validate host key
ノード上でvrouterのflow をダンプしてみた結果は以下となり、 vrouter上で 10.96.205.1 向けの通信について、DNAT が発行されていることが分かる。
root@ip-172-31-15-186(agent):/# flow -l Flow table(size 80609280, entries 629760) Entries: Created 639 Added 639 Deleted 1020 Changed 1020 Processed 639 Used Overflow entries 0 (Created Flows/CPU: 639)(oflows 0) Action:F=Forward, D=Drop N=NAT(S=SNAT, D=DNAT, Ps=SPAT, Pd=DPAT, L=Link Local Port) Other:K(nh)=Key_Nexthop, S(nh)=RPF_Nexthop Flags:E=Evicted, Ec=Evict Candidate, N=New Flow, M=Modified Dm=Delete Marked TCP(r=reverse):S=SYN, F=FIN, R=RST, C=HalfClose, E=Established, D=Dead Index Source:Port/Destination:Port Proto(V) ----------------------------------------------------------------------------------- 138600<=>147932 10.47.255.246:22 6 (2->2) 10.47.255.252:57490 (Gen: 1, K(nh):60, Action:N(S), Flags:, TCP:SSrEEr, QOS:-1, S(nh):60, Stats:8/1458, SPort 55502, TTL 0, Sinfo 11.0.0.0) 147932<=>138600 10.47.255.252:57490 6 (2->2) 10.96.205.1:22 (Gen: 1, K(nh):60, Action:N(D), Flags:, TCP:SSrEEr, QOS:-1, S(nh):65, Stats:8/1022, SPort 60991, TTL 0, Sinfo 172.31.6.143) (snip)
※ flow -l の詳しい読み方は以下を参照。
https://www.juniper.net/documentation/en_US/contrail3.2/topics/task/configuration/vrouter-cli-utilities-vnc.html#jd0e369
type: LoadBalancer では、上記の動作に加えて、外部から疎通するためのIPが払い出される動作になるが、こちらを定義する場合、事前にexternalのネットワークから、floating-ipを取得できるようにしておく必要がある。
作業としては以下の順番で実施する。
1. configure>networking>networks から適当な仮想ネットワークを作成 (public-network1, 10.0.101.0/24 で作成) し、advanced options の external にチェックをつける。
2. configure>networking>floating ips でfloating-ipの作成を行い、取得元のvnとして、1で作成したネットワークを指定する。
3. 2で取得したfloating-ip を、contrail-kube-manager に設定する
※ 3 の設定方法は以下となる。
(マスター上で実施) # kubectl exec -it -n kube-system contrail-kube-manager-xxxxx bash # vi /etc/contrail/kube-manager.conf (以下を追記) -public_fip_pool = {} +public_fip_pool = {'domain': 'default-domain', 'project': 'default', 'network': 'public-network1', 'name': 'default' } # systemctl restart contrail-kube-manager.service
上記実施後、deployment に対して、service を定義すると、external ip としてipが払い出され、該当ipがvMXに配布されることが確認出来る。
※ 今回は 10.0.101.5 として払い出されている
root@ip-172-31-3-97:~# kubectl get svc -o wide NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR cirros-clusterip 10.96.205.122/TCP 14m app=cirros-deployment cirros-loadbalancer 10.101.93.103 ,10.0.101.5 22:30344/TCP 21s app=cirros-deployment kubernetes 10.96.0.1 443/TCP 19d root@ip-172-31-3-97:~#
実際にvMXに連携用の設定を入れた際の、show route は以下となった。
_contrail_public-network1-l3-1.inet.0: 5 destinations, 7 routes (5 active, 0 holddown, 0 hidden) @ = Routing Use Only, # = Forwarding Use Only0.0.0.0/0 *[Static/5] 02:20:39 to table inet.0 10.0.101.0/24 *[Static/5] 02:20:39 Discard 10.0.101.3/32 *[BGP/170] 00:00:06, MED 100, localpref 200, from 172.31.3.97 AS path: ? validation-state: unverified, > via gr-0/0/0.32772, Push 23 10.0.101.5/32 @[BGP/170] 00:00:14, MED 100, localpref 200, from 172.31.3.97 AS path: ? validation-state: unverified, > via gr-0/0/0.32769, Push 24 [BGP/170] 00:00:39, MED 100, localpref 200, from 172.31.3.97 AS path: ? validation-state: unverified, > via gr-0/0/0.32772, Push 60 #[Multipath/255] 00:00:14, metric 100, metric2 0 via gr-0/0/0.32769, Push 24 > via gr-0/0/0.32772, Push 60
- = Active Route, - = Last Active, * = Both
配布された経路のnext-hop は、2つのmplsラベル となっており、それぞれdeployment で作成されたpodのラベルに対応している。
このため、external-router を通過した通信が、直接別のスレーブノードに分散されて、負荷分散が行われることになる。
使用したvMXコンフィグは以下を参照(一部、multipathの設定を追加する必要があった)。
https://github.com/tnaganawa/contrail-k8s-tutorial/blob/master/vmx-config/vmx-config-k8s-ecmp-loadbalance
稼働確認用のインスタンスから確認してみたところ、こちらも、以下のように異なった鍵が返っており、外部からアクセスする場合も、負荷分散が行われていることが確認出来た。
[root@ip-172-31-9-34 ~]# ssh 10.0.101.5 The authenticity of host '10.0.101.5 (10.0.101.5)' can't be established. RSA key fingerprint is SHA256:rbD/ry5jzyMDiqR/EYljBE0PZCG/jmBrhtSTEUvkqUs. RSA key fingerprint is MD5:bb:ac:0e:ea:1e:a9:41:57:dc:e0:04:59:f7:49:b5:23. Are you sure you want to continue connecting (yes/no)? Host key verification failed. [root@ip-172-31-9-34 ~]# ssh 10.0.101.5 The authenticity of host '10.0.101.5 (10.0.101.5)' can't be established. RSA key fingerprint is SHA256:pVn6/oc05FNLEpZ5djBX4+gqh2D/fiBClMQ1DbXUsK0. RSA key fingerprint is MD5:8b:31:ad:50:47:de:8d:b3:9a:3a:e6:da:b9:e5:f8:7a. Are you sure you want to continue connecting (yes/no)? Host key verification failed. [root@ip-172-31-9-34 ~]#
通常、service を提供する場合、haproxy等が使われる場合が多いかとは思うが、contrail を使う場合、上記のようにルーターから直接割り振りが行われるため、状況によっては、構成が簡単になるのではなかろうか。
opencontrailでのexternal-router経由のサービスチェイン
前回の続きで、今回はexternal-router(以下、vMX)を通過するトラフィックに対して、サービスチェインを構成する場合の設定となる。
http://aaabbb-200904.hatenablog.jp/entry/2017/10/29/223844
前回、前々回はnest kvmを使用するため、gcp環境を使ったのだが、今回はvMXも使いたかった関係で、ハイパーバイザとしてqemuを使用して、aws環境での構築を行った。
※ ubuntu16.04.2(ami-ea4eae8c), t2.large 3台を使用
手順は前回と同じだが、追加で、以下の作業を実施している。
1. computeにログイン 2. 以下を実施 # docker exec -it -u root nova_compute bash # apt-get update # apt-get install vim-common # vi /etc/nova/nova.conf [libvirt] の節に、 virt_type=qemu を追記 # reboot
※ なお、前回発生した、169.254関係の事象は、今回は発生しなかった、、
このあと本題の、vMXを通過するトラフィックについてサービスチェインを行う場合の設定なのだが、以下の順序で設定を行う必要がある。
1. contrail 上に、ルートターゲットを持ったvn2つ (以下、vn1, vn2、ルートターゲットはそれぞれ 64512:1, 64512:2 で設定) を作成する
2. vMXに上記のルートターゲットを設定した2つのVRF, および、該当VRFに入るためのfirewall filter を定義する
3. 2で作成したvnの間でサービスチェインを設定する
なお、vMX上で該当のVRFに入る条件、および出る条件については、今回はvpcの構成上、ge-0/0/0 のみが一つのサブネットに存在するような構成にしていたため、稼働確認用のインスタンス2台 (以下、pc1, pc2) を用意し、それぞれのソースアドレスで、vn1, vn2に出入りするように設定しておいた。
※ それぞれfirewall filterと VRF内のrouting-options で設定
最終的なvmxコンフィグは以下となる。
https://github.com/tnaganawa/contrail-k8s-tutorial/blob/master/vmx-config/vmx-config-for-service-chaining
contrail-controllerのIP: 172.31.4.76
computeノードのIP: 172.31.10.155
vMX ge-0/0/0のIP: 172.31.10.57
pc1のIP: 172.31.9.34
pc2のIP: 172.31.8.198
また、サービスチェイン設定前後の変化の確認用に、上記 2, 3 のタイミングでの、vmx 内 vn1, vn2 の、ルーティングテーブルを載せておく。
2, 3を比べると、サービスチェインの効果で、vn1のルーティングテーブルがvn2にコピー、vn2のルーティングテーブルがvn1にコピーされ、コピー後のnext-hopがサービスインスタンスのmplsラベルになっていることがわかる (前回同様、該当のmplsラベル (30, 34) が、サービスインスタンスのものとなっている)
(サービスチェイン前) vn1.inet.0: 4 destinations, 4 routes (4 active, 0 holddown, 0 hidden)10.0.1.3/32 *[BGP/170] 00:09:34, MED 100, localpref 200, from 172.31.4.76 AS path: ?, validation-state: unverified > via gr-0/0/0.32771, Push 26 10.0.1.4/32 *[BGP/170] 00:09:34, MED 100, localpref 200, from 172.31.4.76 AS path: ?, validation-state: unverified > via gr-0/0/0.32771, Push 30 10.0.1.5/32 *[BGP/170] 00:09:34, MED 100, localpref 200, from 172.31.4.76 AS path: ?, validation-state: unverified > via gr-0/0/0.32771, Push 30 172.31.9.34/32 *[Static/5] 00:08:24 to table inet.0 vn2.inet.0: 4 destinations, 4 routes (4 active, 0 holddown, 0 hidden)
- = Active Route, - = Last Active, * = Both
10.0.2.3/32 *[BGP/170] 00:05:54, MED 100, localpref 200, from 172.31.4.76 AS path: ?, validation-state: unverified > via gr-0/0/0.32771, Push 22 10.0.2.4/32 *[BGP/170] 00:05:54, MED 200, localpref 100, from 172.31.4.76 AS path: ?, validation-state: unverified > via gr-0/0/0.32771, Push 34 10.0.2.5/32 *[BGP/170] 00:05:54, MED 100, localpref 200, from 172.31.4.76 AS path: ?, validation-state: unverified > via gr-0/0/0.32771, Push 34 172.31.8.198/32 *[Static/5] 00:05:55 to table inet.0 (サービスチェイン後) vn1.inet.0: 8 destinations, 8 routes (8 active, 0 holddown, 0 hidden)
- = Active Route, - = Last Active, * = Both
10.0.1.3/32 *[BGP/170] 00:07:49, MED 100, localpref 200, from 172.31.4.76 AS path: ?, validation-state: unverified > via gr-0/0/0.32771, Push 26 10.0.1.4/32 *[BGP/170] 00:07:49, MED 100, localpref 200, from 172.31.4.76 AS path: ?, validation-state: unverified > via gr-0/0/0.32771, Push 30 10.0.1.5/32 *[BGP/170] 00:07:49, MED 100, localpref 200, from 172.31.4.76 AS path: ?, validation-state: unverified > via gr-0/0/0.32771, Push 30 10.0.2.3/32 *[BGP/170] 00:07:49, MED 100, localpref 200, from 172.31.4.76 AS path: ?, validation-state: unverified > via gr-0/0/0.32771, Push 30 10.0.2.4/32 *[BGP/170] 00:07:49, MED 100, localpref 200, from 172.31.4.76 AS path: ?, validation-state: unverified > via gr-0/0/0.32771, Push 30 10.0.2.5/32 *[BGP/170] 00:07:49, MED 100, localpref 200, from 172.31.4.76 AS path: ?, validation-state: unverified > via gr-0/0/0.32771, Push 30 172.31.8.198/32 *[BGP/170] 00:04:09, MED 100, localpref 200, from 172.31.4.76 AS path: ?, validation-state: unverified > via gr-0/0/0.32771, Push 30 172.31.9.34/32 *[Static/5] 00:06:39 to table inet.0 vn2.inet.0: 8 destinations, 8 routes (8 active, 0 holddown, 0 hidden)
- = Active Route, - = Last Active, * = Both
10.0.1.3/32 *[BGP/170] 00:04:09, MED 100, localpref 200, from 172.31.4.76 AS path: ?, validation-state: unverified > via gr-0/0/0.32771, Push 34 10.0.1.4/32 *[BGP/170] 00:04:09, MED 100, localpref 200, from 172.31.4.76 AS path: ?, validation-state: unverified > via gr-0/0/0.32771, Push 34 10.0.1.5/32 *[BGP/170] 00:04:09, MED 100, localpref 200, from 172.31.4.76 AS path: ?, validation-state: unverified > via gr-0/0/0.32771, Push 34 10.0.2.3/32 *[BGP/170] 00:04:09, MED 100, localpref 200, from 172.31.4.76 AS path: ?, validation-state: unverified > via gr-0/0/0.32771, Push 22 10.0.2.4/32 *[BGP/170] 00:04:09, MED 200, localpref 100, from 172.31.4.76 AS path: ?, validation-state: unverified > via gr-0/0/0.32771, Push 34 10.0.2.5/32 *[BGP/170] 00:04:09, MED 100, localpref 200, from 172.31.4.76 AS path: ?, validation-state: unverified > via gr-0/0/0.32771, Push 34 172.31.8.198/32 *[Static/5] 00:04:10 to table inet.0 172.31.9.34/32 *[BGP/170] 00:04:09, MED 100, localpref 200, from 172.31.4.76 AS path: ?, validation-state: unverified > via gr-0/0/0.32771, Push 34
- = Active Route, - = Last Active, * = Both
更に、pc1, pc2, 1-to-2 (サービスインスタンス) に対して、以下のルートを設定することで、pc1, pc2間で、1-to-2 を通過してpingが飛ぶことを確認出来た。(1-to-2 上で sysctl -w net.ipv4.ip_forward=0 で、pingが飛ばなくなることを確認)
(pc1) ip route add 172.31.8.198/32 via 172.31.10.57 (pc2) ip route add 172.31.9.34/32 via 172.31.10.57 (1-to-2) ip route add 172.31.9.34/32 via 10.0.1.1 ip route add 172.31.8.198/32 via 10.0.2.1
上記の例では、1つのサービスインスタンスだけを挟んでいるが、前回同様、複数のサービスインスタンスを挟むことも出来る。
また、firewall filterを工夫することで、適当なソースアドレス、行き先アドレスについてのみ、サービスを適用する、等も可能となる。
ルーターを通過するトラフィックごとに、適用するサービスを制御したい場合には、役にたつのではなかろうか。
opencontrailでのサービスチェイン
前回 (http://aaabbb-200904.hatenablog.jp/entry/2017/10/29/191914) に続いて、openstack上のopencontrailで、サービスチェインを試してみたので、まとめておく。
※ k8s版だと該当uiが無効化されており、使用不可
サービスチェインの設定方法は以下を参照。
https://www.juniper.net/documentation/en_US/contrail3.2/topics/task/configuration/service-chaining-vnc.html
https://www.juniper.net/documentation/en_US/contrail3.2/topics/task/configuration/service-chaining-example-ui.html
今回試した構成では、以下のように、1-to-2 というcirrosイメージを作成して、そちらを2つの仮想ネットワークの間に挟んでいる。
vm1(10.0.1.3) - vn1 - (10.0.1.4)1-to-2(10.0.2.4) - vn2 - vm2(10.0.2.3)
通常、この構成であれば、vm1 のデフォルトゲートウェイを 10.0.1.4, vm2のデフォルトゲートウェイを10.0.2.4 にむければ、そのままルーティング可能 (1-to-2で net.ipv4.ip_forward=1 の定義は必要) だが、今回はvm1のデフォルトゲートウェイは10.0.1.1, vm2 のデフォルトゲートウェイは10.0.2.1 となっており、どちらもvrouterが提供するipを向いている。
このため、サービスチェインが構成される前だと、vn1/vn2のVRFは、どちらも、10.0.(2/1).3 への経路を持っていないので、vm1, vm2の間で、pingは飛ばない状況になる。
一方、サービスチェインが構成されると、vn1/vn2はお互いが持っている経路を相互にインポートし、かつ、インポートした経路のnext-hop を1-to-2のip(実際には対応するmplsラベル) に変更する、という形で経路が配布される。
このため、サービスチェイン設定時には、以下のようにルーティングが行われる形になる
vm1(10.0.1.3) - (10.0.1.1: 10.0.2.xは10.0.1.4に送付)vn1 - (10.0.1.4)1-to-2(10.0.2.4) - vn2(10.0.2.1: 10.0.1.xは10.0.2.1に送付) - vm2(10.0.2.3)
※ 確認用に、サービスチェイン設定後のvn1 のルーティングテーブルと、ip/mplsラベルの対応を載せておく (label 22が10.0.1.4に対応)
実際の作業では、以下のような順で設定を行っている。
- service templateの作成
- service instanceの作成(v2テンプレートの場合、事前にhorizonで1-to-2を立ち上げておく必要あり)
- policyの作成
- network へのpolicy付与
結果の画面は以下のようになる。
- service templateの作成
- service instanceの作成
- policyの作成
- network へのpolicy付与
また、cirros自身の設定は、以下のように実施しておく。
# ifconfig eth1 10.0.2.4 netmask 255.255.255.0
# echo 1 > /proc/sys/net/ipv4/ip_forward
この状態で、vm1 から vm2に向けてping を実施すると、pingが通ることが確認できる。
ちなみに、contrailのサービスチェインでは、vn1からvn2への疎通で、複数のservice instance を通すこともできる。
※ 以下の例では 1-to-2-2 としてcirrosを作成
この場合、1-to-2 の 10.0.2.4側から出た後、そのパケットがそのまま 1-to-2-2 のvn1 側(下記の例では、10.0.1.6) に届く動作になる (ルーティング的には、1-to-2から出た側のVRFで10.0.2.3 のnext-hopが10.0.1.6のmplsラベル (38) にセットされている)
少々非直観的な感はあるが、慣れるとvlanを駆使する場合と比べてかなり表現力が増すので、覚えておくとよいのではなかろうか。
kolla-openstack+opencontrail の組み合わせを試してみた
こまどりブログ (https://komadori-blog.blogspot.jp/2017/10/kolla-openstack-ocata-open-contrail40.html) の記載にしたがって、kolla-openstackとopenstackの組み合わせを試してみたので、まとめておく。
※ 先日からnested kvmが使用可能になった、gcp環境で実施
https://cloudplatform.googleblog.com/2017/09/introducing-nested-virtualization-for.html
事前準備として、GCPでnest環境を使う場合、以下のように、事前にカスタムイメージを作成しておく必要がある。
https://cloud.google.com/compute/docs/instances/enable-nested-virtualization-vm-instances#enablenestedvirt
※ また、最新のubuntu16.04.3 だと、vrouterの起動が上手くいかなかったため、2017/2 時点のイメージ(16.04.2に対応)を使用するようにしている
$ gcloud auth login $ gcloud compute images create nested-vm-image \ --project "プロジェクト名" \ --source-image projects/ubuntu-os-cloud/global/images/ubuntu-1604-xenial-v20170220 \ --licenses "https://www.googleapis.com/compute/v1/projects/vm-options/global/licenses/enable-vmx"
この後、
2vcpu, memory 7.5GB, disk 20GB (※ リージョンは us-central1-c を使用した)
で3台のinstance を作成し、ansible を順に実行することで、以下のように openstack/opencontrail が起動されることを確認できた。
なお、gcp の環境では以下の追加設定が必要だったため、念のため記載しておく。
- ansible の設定記載時にnicが2本必要だったため、 以下のコマンドで ens4:0 を作成し、neutron_external_interface に指定した
ifconfig ens4:0 10.128.1.11 netmask 255.255.255.0
- kolla-host.yml 実行時に "api_interface が未定義"、とのエラーが出たため、 ../etc/kolla/globals.yml で api_interface をコメントインした
ここまででhorizon, opencontrail は起動できたのだが、この後、cirros 起動、もしくはcompute上での169.254.0.3 (インスタンスに接続できるip) へのping、を実施したところ、computeへの疎通が取れなくなる、という事象が発生した。
原因不明なのだが、回避策として、以下を実施している。
- configure > network > link-local services で metadata を削除(cirros起動時の疎通不可が改善した)
- ping については手動で発行した場合のみ発生していたので、ログインはvncから行い、link-local アドレスは使わないようにする
最終的に、上記仮想ネットワーク2つにvm1/2 を作成、ルーターで接続し、pingが通ることを確認することが出来た。
追記: ui確認のためのsshコマンドは以下を使用
$ ssh -L 8080:10.128.0.2:80 -L 6080:10.128.0.2:6080 ubuntu@(instance-1の外部ip)
$ ssh -L 8143:127.0.0.1:8143 ubuntu@(instance-2の外部ip)
補足: 元文書はこちら
http://www.opencontrail.org/opencontrail-containers-now-on-dockerhub/
https://gitlab.com/gokulpch/OpenContrail-Kolla/blob/master/README.md
opencontrail内のネットワークに外から疎通するには
前回の続きとなる。
http://aaabbb-200904.hatenablog.jp/entry/2017/10/24/232741
前回作成したk8s+contrail の環境を使用して、contrail 内部のネットワークから外に出る方法をまとめておく。
contrail のネットワークでは、他のノードと、MPLS over GRE で疎通する関係上、そのままだとcontrail内のvmは、お互いの間でしか疎通できない。
外に出るためには、MPLS over GREの通信を、通常のIP通信に変換する仕組みが必要となる。
今回は、aws上のvMXを使用して、変換を行うようにした。
vMXの起動方法については以下を参照。
https://www.juniper.net/documentation/en_US/vmx15.1f6/topics/concept/vmx-aws-overview.html
この後、MPLS over GREの通信を、vMXで終端するための設定を行うのだが、こちらはおおまかに、以下の4ステップで実施できる。
- BGPの設定
- GREの設定
- VRFの設定
- firewall filter の設定
コンフィグそのものは、多くの部分を、contrail の device-manager という機能を使って、自動生成できる。
device-manager の設定方法は、以下を参照。
https://www.juniper.net/documentation/en_US/contrail4.0/topics/concept/using-device-manager-netconf-contrail.html
※ ただし、今回は、'router' に対してroute-target設定を行っている関係で、VRF/firewall filterの設定は自動生成できなかったため、この部分は手動で記述している。
また、実際に試してみたところ、docker hub に上がっている 4.0.1.0 のイメージでは、そのままだとvMXに対してコンフィグ投入を行うことが出来なかった。
事前に以下の変更を行っておくことで、コンフィグ投入を行えることが確認できた。
マスター上で実施: # kubectl exec -it contrail-controller-xxxxx -n kube-system bash (controller)# vi /usr/lib/python2.7/dist-packages/device_manager/mx_conf.py 17行目 - _products = ['mx'] + _products = ['mx', 'vmx'] (controller)# systemctl restart contrail-device-manager.service
最終的なvMXコンフィグは以下となる。
https://github.com/tnaganawa/contrail-k8s-tutorial/blob/master/vmx-config/vmx-config
※ コンフィグ内のIPは、それぞれ以下の意味となる。
マスターノードのIP: 172.31.3.97
スレーブノードのIP: 172.31.6.143
vMX ge-0/0/0のIP: 172.31.10.57
稼働確認用ノードのIP: 172.31.9.34
設定実施後、以下のように各ノードのipが配布されてきていることと、稼働確認用ノードからのping, ssh疎通 (セキュリティグループで許可しているvm(office, mgmt)について) ができることが確認できた。
> show route contrail-dc-router.inet.0: 4 destinations, 4 routes (4 active, 0 holddown, 0 hidden) + = Active Route, - = Last Active, * = Both 10.0.11.4/32 *[BGP/170] 00:07:49, MED 100, localpref 200, from 172.31.3.97 AS path: ?, validation-state: unverified > via gr-0/0/0.32769, Push 34 10.0.12.4/32 *[BGP/170] 00:07:48, MED 100, localpref 200, from 172.31.3.97 AS path: ?, validation-state: unverified > via gr-0/0/0.32769, Push 40 10.0.13.4/32 *[BGP/170] 00:07:49, MED 100, localpref 200, from 172.31.3.97 AS path: ?, validation-state: unverified > via gr-0/0/0.32769, Push 51 10.0.14.4/32 *[BGP/170] 00:07:49, MED 100, localpref 200, from 172.31.3.97 AS path: ?, validation-state: unverified > via gr-0/0/0.32769, Push 45
なお、vMXで終端しないといけないのは少々面倒に見えるが、例えば、openstackのml2プラグイン等では、bgp無しのvxlanを使用する関係上、networkノードという特別なノードを設置しないと終端が出来ない。
https://docs.openstack.org/liberty/ja/networking-guide/scenario-classic-ovs.html
contrailではbgp/mplsという標準的な仕組みを使っている関係で、ルーターで直接オーバーレイを終端出来る、というのは、メリットといえるのではなかろうか。
opencontrailで仮想ネットワーク間のルーティング、セキュリティポリシーを構成するには
概要
前回の続きとなる。
http://aaabbb-200904.hatenablog.jp/entry/2017/10/15/034243
前回作成した k8s+contrail の環境を使用して、web/db/mgmt等のセグメントを作成し、疎通確認を行ってみる。
作成するセグメントとセキュリティポリシーは以下とする。
(セグメント) dc-web-network 10.0.11.0/24 dc-db-network 10.0.12.0/24 office-network 10.0.13.0/24 mgmt-network 10.0.14.0/24 (セキュリティポリシー) dc-web-sg: mgmt: tcp/22 dc-db-sg: web: tcp/22 (tcp/5432の代わり) mgmt: tcp/22 office-sg: all: all mgmt-sg: 172.31.9.34/32: all (稼働確認用ノードのIP, 後述)
セグメントの使い分けとしては、以下を想定している。
- web/dbのセグメントには、mgmtセグメントからだけssh可能
- dbのpostgresqlには、webからのみアクセス可能
- mgmt には稼働確認用ノードからだけssh可能
また、セグメント間は、互いにルーティングが出来るようにし、かつmgmtについては、稼働確認用のノード(contrail外)からも疎通が出来るようにしたい。
上記を実現するために、contrail 内では、'router'と、'security group'が使用できるので、以下にまとめていく。
router
contrail内のrouterは、定義した仮想ネットワーク(以下、vn)間に疎通を許可するための設定となる。
※ 内部的にはroute-targetの払い出しと、接続されたvnへの該当route-targetのインポート/エクスポート定義の追加、を実施している
上記の4つのvn間でルーティングを設定するためには、configure>networks>routersからルーターを作成(dc-routerとして作成)し、上記4つのネットワークを'connected networks'に追加すればよい。
また、次回、vMXにも該当経路を配布するため、routerのroute-target を明示的に指定している(64512:201として指定)
仮想ネットワーク内へのコンテナ作成
なお、contrail内にvnを作る場合、configure>networks>network から作成可能となる。
また、該当vn内にk8sのコンテナを作る場合、以下のようにannotationを設定することで、該当vn内にコンテナを作ることができる。
※ contrail動作の説明用の使い方で、k8s の使い方としてはあまり一般的ではないので注意
https://github.com/tnaganawa/contrail-k8s-tutorial/blob/master/yml/2_dc/cirros-dc-web.yaml#L7
今回は、各vn内に1つずつ、containerを作っておく。
security group
security groupは、openstack等で使用できるものとほぼ同じで、各vmに疎通できる通信を設定するものとなる。
contrailでは、vmに接続されている'port'を提供しているため、こちらに対してsecurity groupを設定することになる。
security group(以下、sg)では、通信の許可、しか設定できないため、基本的には、デフォルトではsgには何も設定せず、許可する通信のみsg内に追加していくことになる。
今回は、各vnごとに1つずつsgを作成し、sg名単位で許可していくことにした。
設定例は以下となる。(例では、dc-web用のsgに mgmtからの疎通を許可している)
※ ポートごとの定義は以下のように、該当ネットワーク内の各ポートに、セキュリティグループを設定していくことになる
疎通確認
作成したそれぞれのコンテナにログインするには、以下のようなコマンドが使用できる
# kubectl exec -it cirros-mgmt sh
ログイン後、ping, ssh 等で、ルーティング、セキュリティポリシーが正しく設定されていることを確認していく。
# ping 10.0.11.4 # ssh cirros@10.0.11.4
ルーティングテーブルの確認
contrailの各vnのルーティングテーブルは、以下から確認できる。
monitor>control nodes>(コントロールノード名)>routes
また、next-hop は、以下から確認できる。
monitor>virtual routers>(スレーブノード名)>interfaces
※ 上記の例では、dc-web-networkのルーティングテーブルで 10.0.12.4の行き先が40のMPLSラベルであり、該当のラベルが cirros-dc-dbに対応することがわかる。
上記のように、contrail内ではルーティング、およびL4までのファイアウォールが設定できる。
上記の定義は、スレーブノードを追加すれば、そちらのvrouterにもそのまま適用される。
各スイッチやファイアウォール、ハイパーバイザ等で、順に作業していく必要がないので、だいぶ構築が楽になるのではなかろうか。