この記事に続いて、OpenShiftのルータと同様、ホスト名でポッドにアクセスできるようにします。
OpenShiftはHA Proxyを使ってましたが、KubernetesではNGINX Ingress Controllerを使う記事が多いので、それにしました。
今回は、以下を参照しています。
- NGINX Ingress Controller
- MetalLB
- オンプレK8sで使えるGoogle製External Load Balancer: MetalLB
- ingress-nginxを使用してオンプレでもIngressを使用する
MetalLBの構築
実際にはNGINX Ingress Controllerを先に構築して、上手く動かなくて調べてる中で、目的のためにMetalLBが必要とうことが判りました。他にも選択肢があるのかもしれませんが、NGINX Ingress ControllerのドキュメントでベアメタルではMetalLBを使うと解決するって書いてあるので、それに従いました。
ます、以下のコマンドでインストール。
# kubectl apply -f https://raw.githubusercontent.com/google/metallb/v0.8.1/manifests/metallb.yaml
namespace/metallb-system created
podsecuritypolicy.policy/speaker created
serviceaccount/controller created
serviceaccount/speaker created
clusterrole.rbac.authorization.k8s.io/metallb-system:controller created
clusterrole.rbac.authorization.k8s.io/metallb-system:speaker created
role.rbac.authorization.k8s.io/config-watcher created
clusterrolebinding.rbac.authorization.k8s.io/metallb-system:controller created
clusterrolebinding.rbac.authorization.k8s.io/metallb-system:speaker created
rolebinding.rbac.authorization.k8s.io/config-watcher created
daemonset.apps/speaker created
deployment.apps/controller created
次にMetalLBの設定を行います。
# cat <<EOF > metallb-l2.yaml
apiVersion: v1
kind: ConfigMap
metadata:
namespace: metallb-system
name: config
data:
config: |
address-pools:
- name: default
protocol: layer2
addresses:
- 192.168.122.64-192.168.122.253
EOF
# kubectl apply -f metallb-l2.yaml
- MetalLBではBGPとL2の2つのモードがありますが、今回の環境で使用しているCNIのcalicoとBGPモードには特定の使い方で問題があるとのことです。
今回は無難にL2モードにしました。 - addressesの値は、いろいろとハマりました。
- Bare-metal considerationsの説明には、ワーカーノードのIPアドレスを指定する例がありますが、それでは上手く行きませんでした。
- 外部に公開するIPアドレスの範囲を指定するとあるので、仮想サーバのネットワークである192.168.121.0/24を指定したら、サービスのEXTERNAL-IPとして192.168.121.0が割り当たってしまいました。そのせいだと思うのですが通信ができませんでした。
-
そこで物理ホスト側で仮想サーバに割り当てるアドレスを192.168.121.200〜254となるようにvirsh net-editで変更し、192.168.121.1はゲートウェイで使われているので、残りを指定しました。(2019/8/26追記)そこで仮想サーバには静的なアドレスを割り当てるようにしました。
NGINX Ingress Controllerの構築
以下のコマンドでインストール。
# kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/static/mandatory.yaml
namespace/ingress-nginx created
configmap/nginx-configuration created
configmap/tcp-services created
configmap/udp-services created
serviceaccount/nginx-ingress-serviceaccount created
clusterrole.rbac.authorization.k8s.io/nginx-ingress-clusterrole created
role.rbac.authorization.k8s.io/nginx-ingress-role created
rolebinding.rbac.authorization.k8s.io/nginx-ingress-role-nisa-binding created
clusterrolebinding.rbac.authorization.k8s.io/nginx-ingress-clusterrole-nisa-binding created
deployment.apps/nginx-ingress-controller created
# curl -L -O https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/static/provider/cloud-generic.yaml
# vi cloud-generic.yaml
* spec:配下にloadBalancerIP: 192.168.122.64を追記
# kubectl apply -f cloud-generic.yaml
service/ingress-nginx created
# kubectl -n ingress-nginx get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
ingress-nginx LoadBalancer 10.101.221.156 192.168.122.64 80:31288/TCP,443:32439/TCP 172m
- この2つめのサービスの作成もハマりました。Installation GuideでベアメタルならこのURLでサービスを作成すると記述があり、Bare-metal considerationsにサービスの作成について言及がありません。これで作成されるサービスはNodePortでNGINX Ingress Controllerが外部に公開されません。
で、こちらの記事を参考にcloud-generic.yamlを指定したら、上手く行きました。 - (2019/8/26追記)ingress-nginxサービスの外部アドレスが動的なのがムズムズするので、loadBalancerIPを指定するようにしました。指定するアドレスは、MetalLBで指定したプール内でなければならないです。
物理ホストからNGINX Ingress Controllerへ転送
(2019/8/22追記)
物理ホストには既にkube-apiserver用ロードバランサーとして建てたnginxがあるので、これを使ってNGINX Ingress Controllerへ転送させます。
nginx.conf
user nginx;
worker_processes 1;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
stream {
upstream backend {
least_conn;
server k8s-master1:6443;
server k8s-master2:6443;
}
server {
listen 6443;
proxy_pass backend;
}
server {
listen 80;
proxy_pass 192.168.122.64:80;
}
server {
listen 443;
proxy_pass 192.168.122.64:443;
}
}
- httpディレクティブは消して、http/httpsポートをそのままNGINX Ingress Controllerへ転送するようにしました。
- 今回はNGINX Ingress Controllerのサービスに払いだされたアドレスを設定していますが、ちょっとムズムズするので、別途、サービスのアドレスを固定化する方法を検討したいと思います。
hello worldアプリケーションで確認
前回と同じhello worldアプリケーションをデプロイして、疎通を確認しました。
# cat <<EOF > hello-world.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app.kubernetes.io/name: hello
name: hello-world
spec:
replicas: 1
selector:
matchLabels:
app: hello-world
template:
metadata:
labels:
app: hello-world
spec:
containers:
- image: gcr.io/hello-minikube-zero-install/hello-node
name: hello-world
ports:
- containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
name: hello-world
spec:
ports:
- name: http
port: 8080
protocol: TCP
targetPort: 8080
selector:
app: hello-world
type: NodePort
---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: hello-router
spec:
rules:
- http:
paths:
- path: /
backend:
serviceName: hello-world
servicePort: 8080
host: hello-world.kubernetes.local
EOF
# kubectl apply -f hello-world.yaml
# curl hello-world.kubernetes.local
Hello World!