Closed oomichi closed 3 years ago
service が load balancer を持つところでタイムアウト タイムアウト待ちの状態
$ kubectl -n e2e-tests-services-zz4sg get service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service LoadBalancer 10.102.11.85 <pending> 80:31660/TCP 32s
$
$ kubectl -n e2e-tests-services-zz4sg describe service service
Name: service
Namespace: e2e-tests-services-zz4sg
Labels: <none>
Annotations: <none>
Selector: name=service
Type: LoadBalancer
IP: 10.102.11.85
Port: <unset> 80/TCP
TargetPort: 9376/TCP
NodePort: <unset> 31660/TCP
Endpoints: 10.244.1.82:9376,10.244.1.83:9376,10.244.2.104:9376
Session Affinity: ClientIP
External Traffic Policy: Local
HealthCheck NodePort: 30895
Events: <none>
LBが使えるように環境設定が必要
師匠が記事を書いていた: https://qiita.com/yuanying/items/704a173033410d882eea
と思ったら、自動化されておらず罠だった。 たぶん、OpenStack external LBが必要? もしくは ingress controller?
なお、OpenStack externel cloud provider では
lxkong: if you config use-octavia=no, then neutron lbaas will be used.
らしい。
意訳
Kubernetes において NodePort、LoadBalancer、Ingress の違いの説明を求められることが最近多い。
それらは全て外部から k8s クラスタへトラフィックを運ぶための異なる方法だ。
それぞれの詳細を見ていき、あなたにあったものを選ぼう。
ClusterIP
ClusterIP: ClusterIP service はデフォルトの k8s service だ。これはクラスタ内部で異なる APPs 間の
通信を行うのに使える。外部アクセスには対応しない。Internet からのアクセスが出来ないにも
関わらず、なぜ私がここで ClusterIP を挙げたのか。それは k8s proxy を使うことで Internet からの
アクセスが可能になるからだ。下記のコマンドで proxy を起動することにより、
http://localhost:8080/api/v1/proxy/namespaces/<NAMESPACE>/services/<SERVICE-NAME>:<PORT-NAME>/
でアクセス可能になる。たとえば
http://localhost:8080/api/v1/proxy/namespaces/default/services/my-internal-service:http/
などだ。
$ kubectl proxy --port=8080
どのようなときに ClusterIP + proxy を使うか。主に下記のようにデバッグ用途(商用では使うなとのこと)
1. Services のデバッグ
2. 内部 dashboard の表示、内部トラフィックの許可など
NodePort
NodePort: NodePort service は外部トラフィックを直接サービスに送り込む最も原始気的な方法だ。
NodePort はその名が示すとおり、全てのノード上で特定のポートをオープンし、そのポート宛の
トラフィックを特定サービスにフォワーディングする。そのサービスは Pod に LB する。
NodePort にはいくつかのデメリットがある。
1. 1つのポートあたり1つのサービスしかもてない。
2. 30000-32767 番の範囲のポートしか使えない。
3. もしもノードの IP アドレスが変わったら、それを(あなた自身で)処理しなければならない
これらの理由により、NodePort を商用で使うことはお薦めしない。
デモやその他の一時的な用途には使える。
LoadBalancer
LoadBalancer: LoadBalancer service は最も標準的な方法だ。GKE では、全てのトラフィックを
あなたのサービスにフォワーディングするために単一の IP アドレスをあなたに提供する
Network Load Balancer を作成する。
もしも service を外部に直接公開したい場合、この方法が default だ。
全てのトラフィックはサービスにフォワーディングされる。フィルタリングやルーティングは不要だ。
つまり、HTTP/HTTPSに関わらず、TCP、UDP、Websocket、gRPCなど何でも使える。
LoadBalancerの大きなデメリットは、それぞれの service が独自のIP アドレスを持つことがあり、
その公開したサービス毎の LoadBalancer に対してそれぞれ支払いする必要があることだ。
しかもそれは多くの場合、高額になる。
Ingress
前述のものとはことなり、Ingress は実際には service の一種ではない。
その代わりに、それは複数サービスの前に置かれ、クラスタへつながる smart router もしくは
entrypoint として動作する。
Ingress を使うことによって多くの異なることができ、そして多くの Ingress Controller の種類が
存在する。それらの Controller はそれぞれ異なる Capabilities を持っている。
GKE におけるデフォルトの Ingress Controller は HTTP(S) Load Balancer を作成する。
これは path もしくは subpath ベースのルーティングの両方を可能にする。
たとえば、foo.yourdomain.com で foo サービスをルーティングしつつ、
yourdomain.com/bar/ というパスで bar サービスをルーティングすることも可能だ。
Ingress はサービスを公開する上でもっともパワフルな方法だ。
しかし、同時に Ingress は最も複雑な方法と言えるだろう。
Ingress Controller は多くの種類がある。たとえば、Google Cloud Load Balancer、
Nginx、Contour、Istio さらに多くがある。
また、cert-manager のような Ingress Controllers向けのプラグインも存在する。
Ingress は同一IPアドレスに対して複数のサービスを公開したい場合にもっともパワフルな
方法になるだろう。同じ L7 プロトコル(HTTP/HTTPSなどの)で異なる複数のサービスを
公開することが可能だ。あなたは1つのロードバランサにのみ料金を支払えばよい。
ClusterIP + Proxyのためし
$ kubectl run nginx --image=nginx
$ kubectl expose deployment nginx --port 80
$ kubectl proxy --port=8080
Starting to serve on 127.0.0.1:8080
別コンソールで → NotFound になり、うまくいかない
$ kubectl get services
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 19d
nginx ClusterIP 10.108.91.8 <none> 80/TCP 18m
$ curl http://localhost:8080/api/v1/proxy/namespaces/default/services/nginx:http
{
"kind": "Status",
"apiVersion": "v1",
"metadata": {
},
"status": "Failure",
"message": "the server could not find the requested resource",
"reason": "NotFound",
"details": {
},
"code": 404
}
NodePort service ためし。
$ kubectl expose --port=80 --type=NodePort deployment nginx
$ kubectl get services
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 19d
nginx NodePort 10.101.0.37 <none> 80:32460/TCP 10s
$ sudo netstat -anp | grep 32460
tcp6 0 0 :::32460 :::* LISTEN 2294/kube-proxy
$
node01:
$ sudo netstat -anp | grep 32460
tcp6 0 0 :::32460 :::* LISTEN 1925/kube-proxy
$
$ curl http://localhost:32460
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
body {
width: 35em;
margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif;
}
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
$
この Issue では LoadBalancer 型の Service が有効になっていないこと。 これは Ingress とは異なる。 OpenStack external cloud provider で対応する必要がある。 今回は Neutron LBaaS v2 を使ってみる。(新たに Octavia を入れるのが面倒なだけ)
HAproxy バックエンドが一般的のようなのでそれを使う。
iaas-ctrl で neutron-lbaas 関連パッケージのインストール、インストールの確認
$ sudo apt-get install neutron-lbaas-common neutron-lbaasv2-agent
$ ls /etc/neutron/neutron_lbaas.conf
/etc/neutron/neutron_lbaas.conf
$ ls /usr/lib/python2.7/dist-packages/neutron_lbaas
agent agent_scheduler.pyc common drivers _i18n.py __init__.py locale opts.pyc tests version.pyc
agent_scheduler.py cmd db extensions _i18n.pyc __init__.pyc opts.py services version.py
$
/etc/neutron/neutron.confでservice_pluginsとしてLBを指定
diff -u /etc/neutron/neutron.conf.orig /etc/neutron/neutron.conf
--- /etc/neutron/neutron.conf.orig 2018-10-17 11:28:55.273820025 -0700
+++ /etc/neutron/neutron.conf 2018-10-17 11:29:27.638097797 -0700
@@ -1,7 +1,7 @@
[DEFAULT]
core_plugin = ml2
transport_url = rabbit://openstack:RABBIT_PASS@iaas-ctrl
-service_plugins = neutron.services.l3_router.l3_router_plugin.L3RouterPlugin
+service_plugins = neutron.services.l3_router.l3_router_plugin.L3RouterPlugin,neutron_lbaas.services.loadbalancer.plugin.LoadBalancerPluginv2
[database]
connection = mysql+pymysql://neutron:NEUTRON_DBPASS@iaas-ctrl/neutron
/etc/neutron/neutron_lbaas.confでHAProxyバックエンドを指定
--- /etc/neutron/neutron_lbaas.conf.orig 2018-10-17 11:48:02.627671395 -0700
+++ /etc/neutron/neutron_lbaas.conf 2018-10-17 11:48:45.536040065 -0700
@@ -211,4 +211,4 @@
# Defines providers for advanced services using the format:
# <service_type>:<name>:<driver>[:default] (multi valued)
-#service_provider =
+service_provider = LOADBALANCERV2:Haproxy:neutron_lbaas.drivers.haproxy.plugin_driver.HaproxyOnHostPluginDriver:default
/etc/neutron/lbaas_agent.ini のinterface_driver で linuxbridge を指定 (/etc/neutron/plugins/ml2/ml2_conf.ini の mechanism_driversで linuxbridge を指定しているため)
--- /etc/neutron/lbaas_agent.ini.orig 2018-10-17 11:51:48.169609261 -0700
+++ /etc/neutron/lbaas_agent.ini 2018-10-17 12:04:37.196217584 -0700
@@ -20,7 +20,7 @@
#ovs_use_veth = false
# The driver used to manage the virtual interface. (string value)
-#interface_driver = <None>
+interface_driver = linuxbridge
#
# From oslo.log
LBaaS v2 向けの DB テーブル作成
$ sudo neutron-db-manage --subproject neutron-lbaas upgrade head
マシン再起動
$ sudo reboot
/var/log/neutron/neutron-lbaasv2-agent.log
2018-10-17 12:38:16.639 2110 WARNING stevedore.named [req-73d21ea4-5513-4165-b9e7-4cdba920b3a5 - - - - -] Could not load neutron_lbaas.drivers.haproxy.namespace_driver.HaproxyNSDriver
ひとまず動いている
$ neutron lbaas-loadbalancer-create --name test-lb provider
neutron CLI is deprecated and will be removed in the future. Use openstack CLI instead.
Created a new loadbalancer:
+---------------------+--------------------------------------+
| Field | Value |
+---------------------+--------------------------------------+
| admin_state_up | True |
| description | |
| id | c910fd08-dc7e-4824-a1b2-d6c3a6769e0d |
| listeners | |
| name | test-lb |
| operating_status | OFFLINE |
| pools | |
| provider | haproxy |
| provisioning_status | PENDING_CREATE |
| tenant_id | 682e74f275fe427abd9eb6759f3b68c5 |
| vip_address | 192.168.1.102 |
| vip_port_id | e5c2ca95-82c7-4168-99e9-282280e2311b |
| vip_subnet_id | 43ed897b-3c10-4d5c-8f6d-263edcd817c7 |
+---------------------+--------------------------------------+
$ neutron lbaas-loadbalancer-show test-lb
neutron CLI is deprecated and will be removed in the future. Use openstack CLI instead.
+---------------------+--------------------------------------+
| Field | Value |
+---------------------+--------------------------------------+
| admin_state_up | True |
| description | |
| id | c910fd08-dc7e-4824-a1b2-d6c3a6769e0d |
| listeners | |
| name | test-lb |
| operating_status | ONLINE |
| pools | |
| provider | haproxy |
| provisioning_status | ACTIVE |
| tenant_id | 682e74f275fe427abd9eb6759f3b68c5 |
| vip_address | 192.168.1.102 |
| vip_port_id | e5c2ca95-82c7-4168-99e9-282280e2311b |
| vip_subnet_id | 43ed897b-3c10-4d5c-8f6d-263edcd817c7 |
+---------------------+--------------------------------------+
Pingが通らない。
$ neutron lbaas-loadbalancer-create --name test-lb provider
$ neutron security-group-create lbaas
$ neutron security-group-rule-create --direction ingress --protocol icmp lbaas
$ neutron security-group-rule-create --direction ingress --protocol tcp --port-range-min 80 --port-range-max 80 --remote-ip-prefix 0.0.0.0/0 lbaas
$ neutron security-group-rule-create --direction ingress --protocol tcp --port-range-min 443 --port-range-max 443 --remote-ip-prefix 0.0.0.0/0 lbaas
$ neutron lbaas-loadbalancer-show test-lb
$ neutron port-update --security-group lbaas 40491d41-1f0a-4d66-b214-cc9b6d11da53
$ neutron lbaas-listener-create --name test-lb-http --loadbalancer test-lb --protocol HTTP --protocol-port 80
$ ping 192.168.1.116
ログ
2018-10-17 14:24:46.927 2110 ERROR neutron.agent.linux.utils [req-a3a28736-3115-4303-b9ec-19d3f354c712 e5e99065fd524f328c2f81e28a6fbc42 682e74f275fe427abd9eb6759f3b68c5 - - -] Exit code: 99; Stdin: ; Stdout: ; Stderr: /usr/bin/neutron-rootwrap: Unauthorized command: ip netns exec qlbaas-c910fd08-dc7e-4824-a1b2-d6c3a6769e0d arping -U -I ns-e5c2ca95-82 -c 3 192.168.1.102 (no filter matched)
arpingパッケージを入れてみた
$ sudo apt-get install arping
/var/log/neutron/neutron-lbaasv2-agent.log ログの内容が変わった。arping は実行できるようになったがタイムアウトが発生。
2018-10-17 17:27:19.672 2110 ERROR neutron.agent.linux.utils [req-64a47b03-930f-4fee-8f54-0d819e63b814 e5e99065fd524f328c2f81e28a6fbc42 682e74f275fe427abd9eb6759f3b68c5 - - -] Exit code: 1; Stdin: ; Stdout: ARPING 192.168.1.116
Timeout
Timeout
Timeout
--- 192.168.1.116 statistics ---
3 packets transmitted, 0 packets received, 100% unanswered (0 extra)
lbaas-loadbalancer-create で LB 作成後、HTTP/HTTPSとICMP を許可する security-group を LB のポートに適用した後、対象 LB への Ping が通ることを想定している。
よって、lbaas-loadbalancer-create 実施時に LB ポートのアドレス(192.168.1.116)の 仮想インターフェースが作られているはず。 network namespaces で LB 専用 namespace が作られている。 また、その中に LB インターフェースがあることを確認できる。
$ sudo ip netns list
qlbaas-2a7a1c68-fd33-4155-a2b1-be5ef59d2942 (id: 1)
qdhcp-bfd9fd43-c9b4-43ad-bb67-930c674f2605 (id: 0)
$ sudo ip netns exec qlbaas-2a7a1c68-fd33-4155-a2b1-be5ef59d2942 ifconfig
..
ns-40491d41-1f Link encap:Ethernet HWaddr fa:16:3e:44:02:65
inet addr:192.168.1.116 Bcast:192.168.1.255 Mask:255.255.255.0
inet6 addr: fe80::f816:3eff:fe44:265/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:560876 errors:0 dropped:0 overruns:0 frame:0
TX packets:85 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:33654758 (33.6 MB) TX bytes:7466 (7.4 KB)
また、その ns 内で ping が通ることを確認できる。
$ sudo ip netns exec qlbaas-2a7a1c68-fd33-4155-a2b1-be5ef59d2942 ping 192.168.1.116
PING 192.168.1.116 (192.168.1.116) 56(84) bytes of data.
64 bytes from 192.168.1.116: icmp_seq=1 ttl=64 time=0.047 ms
64 bytes from 192.168.1.116: icmp_seq=2 ttl=64 time=0.063 ms
しかし、ns 外からでは ping が通らない。
$ ping 192.168.1.116
PING 192.168.1.116 (192.168.1.116) 56(84) bytes of data.
^C
--- 192.168.1.116 ping statistics ---
2 packets transmitted, 0 received, 100% packet loss, time 1000ms
そもそも k8s ノードなどにも ssh ログインできなくなっている。
$ ssh 192.168.1.104
(戻ってこない)
lbaas-listener を削除したら ssh ログインできるようになった。
$ neutron lbaas-listener-delete 4daf2bdc-8041-45c0-ad53-5ca42645172e
やはり
$ neutron lbaas-listener-create --name test-lb-http --loadbalancer test-lb --protocol HTTP --protocol-port 80
のタイミングで lbaas 用の network ns が作られ、k8s ノードを含む 192.168.1.0/24 のホストに ssh ログインできなくなる模様 たぶん、lbaas-listener が存在する状況で ping が通るようになれば多くの問題が解ける気がする。
そもそも、LBaaSに割り当てるアドレス帯が間違っていた。
192.168.1.0/24 は OpenStack 内部ネットワークで、本来は外部のアドレス帯にすべき。
よって、
neutron lbaas-loadbalancer-create --name test-lb <サブネット名>
で指定するサブネットを外部にする。
2箇所、設定変更
$ sudo vi /etc/neutron/plugins/ml2/linuxbridge_agent.ini
--- /etc/neutron/plugins/ml2/linuxbridge_agent.ini.orig 2018-11-02 19:22:37.216606432 -0700
+++ /etc/neutron/plugins/ml2/linuxbridge_agent.ini 2018-11-02 19:23:09.688938039 -0700
@@ -1,5 +1,5 @@
[linux_bridge]
-physical_interface_mappings = provider:enp2s0
+physical_interface_mappings = provider:enp2s0,company:enp0s31f6
[vxlan]
enable_vxlan = false
$ sudo vi /etc/neutron/plugins/ml2/ml2_conf.ini
--- /etc/neutron/plugins/ml2/ml2_conf.ini.orig 2018-11-02 19:35:31.419231892 -0700
+++ /etc/neutron/plugins/ml2/ml2_conf.ini 2018-11-02 19:36:26.559857509 -0700
@@ -5,5 +5,5 @@
extension_drivers = port_security
[ml2_type_flat]
-flat_networks = provider
+flat_networks = provider,company
変更を反映
$ sudo reboot
社内NWを追加
$ neutron net-create company \
--router:external True \
--provider:network_type flat \
--provider:physical_network company
社内Subnetを追加(サブネット帯は ifconfig の結果から)
$ neutron subnet-create company 172.27.138.0/24 --disable-dhcp --name company-subnet
この状態でやってみる
$ neutron lbaas-loadbalancer-create --name test-lb company-subnet
$ neutron security-group-create lbaas
$ neutron security-group-rule-create --direction ingress --protocol icmp lbaas
$ neutron security-group-rule-create --direction ingress --protocol tcp --port-range-min 80 --port-range-max 80 --remote-ip-prefix 0.0.0.0/0 lbaas
$ neutron security-group-rule-create --direction ingress --protocol tcp --port-range-min 443 --port-range-max 443 --remote-ip-prefix 0.0.0.0/0 lbaas
$ neutron lbaas-loadbalancer-show test-lb
$ neutron port-update --security-group lbaas bfe21506-0e38-4b0e-b4ba-690820241470
$ neutron lbaas-listener-create --name test-lb-http --loadbalancer test-lb --protocol HTTP --protocol-port 80
だめだ、ping が通らない
Slackで教えてもらった情報から整理
Kubernetes において外部(インターネット)からのトラフィックを受ける方法として、ClusterIP、NodePort、LoadBalancer、Ingress がある。
ClusterIP、NodePortはデバッグ、もしくは k8s クラスタ内部の Pod 間通信用であり、商用で使えるのは LoadBalancer、Ingress となる。
LoadBalancer の実装はクラウドプロバイダに依存し、OpenStack の場合は openstack external cloud provider がその実装であり、Neutron を制御することになる。
Neutron は既にDHCPが動作しているネットワーク環境(社内ネットワークや自宅ネットワーク)上で新たな NIC を作成する場合、DHCP無効を指定して
Network を作成することになる。これにより、既存の外部 DHCP からのIPアドレス付与を受けることとなる。
しかし、Neutron としては外部 DHCP から付与されたIP アドレスではなく、内部DB 上で勝手に付与した IPアドレスで管理されることになる。
つまり、実際に NIC に付与された IP アドレスと Neutron が表示する IP アドレスが異なる状況に陥る。さらに Neutron の情報をもとに
openstack external cloud provider がLoadBalancer の情報を更新するため、結局 k8s 上で見える LoadBalancer の IP アドレスも実際と異なってしまい、
LoadBalancer として外部に見せるべきアドレスがわからなくなってしまう。
OpenStack IaaS上に e2e テスト実行VMを構成していたため、テスト対象とテスターが内部 ネットワークに閉じた環境となっており、Neutron LBaaS が有効になる環境ではなかった。 テストとしては一先ずスキップし、テスト環境の再構築時に OpenStack External Cloud Provider を試みることにする。