これまでにServiceによるロードバランシングは見てきましたが、Serviceは現時点ではL4 LoadBalancer相当であり、
HTTPヘッダーなどは考慮されません。TLS TerminationもServiceレベルでは行えないため、Podまたは外部LoadBalancer単位で行う必要があります。
また外部に公開するアプリケーションに対して、type=LoadBalancerなServiceを一つ一つ用意すると、Serviceの分だけLoadBalancerのコストがかかります。

このような課題に対して、IngressはService前のL7レベル LoadBalancer相当の機能を提供します。
IngressはServiceに対するHost名ベースまたはパスベースのルーティングを提供します。外部LoadBalancerはIngress (Controller)に対してルーティングすれば複数のLoadBalancerを用意する必要はありません。
またTLS Terminationを行うこともできます。

IngressはKubernetesのリソースであり、このリソースを以ってServiceへのルーティングを定義できます。Ingreeリソースを使用するにはIngress Controllerを用意することが必要です。Ingress ControllerはPodとしてデプロイ可能です。
Ingress Controller自体はAPI仕様であり、Ingress Controllerの実装としては
などが有名です。
本ドキュメントではIaaSに依らずに使用できるContourを使用します。
目次
Contourのインストール
次のコマンドを実行してください。
kubectl apply -f https://raw.githubusercontent.com/projectcontour/contour/release-0.15/examples/render/deployment-rbac.yaml
デフォルトでtype: LoadBalancerなServiceが作成されます。type: NodePortを使用したい場合は次のコマンドを実行してください。
curl https://raw.githubusercontent.com/projectcontour/contour/release-0.15/examples/render/deployment-rbac.yaml | sed 's/LoadBalancer/NodePort/' | kubectl apply -f -
kubectl get -n heptio-contour all
出力結果
NAME READY STATUS RESTARTS AGE
pod/contour-596f4bf6c4-48fs7 2/2 Running 0 13m
pod/contour-596f4bf6c4-ztmrc 2/2 Running 0 13m
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/contour NodePort 10.100.200.168 <none> 80:31005/TCP,443:31353/TCP 13m
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/contour 2/2 2 2 13m
NAME DESIRED CURRENT READY AGE
replicaset.apps/contour-596f4bf6c4 2 2 2 13m
Ingressリソースの作成
hello-pksアプリのデプロイとそのアプリにhello-pks.example.comでアクセスするためのIngressリソースを作成します。
kind: Service
apiVersion: v1
metadata:
name: hello-pks
spec:
type: ClusterIP
selector:
app: hello-pks
ports:
- protocol: TCP
port: 8080
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: hello-pks
spec:
replicas: 2
selector:
matchLabels:
app: hello-pks
template:
metadata:
labels:
app: hello-pks
spec:
containers:
- image: making/hello-pks:0.0.2
name: hello-pks
ports:
- containerPort: 8080
env:
- name: NODE_NAME
valueFrom:
fieldRef:
fieldPath: spec.nodeName
- name: NODE_IP
valueFrom:
fieldRef:
fieldPath: status.hostIP
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: POD_IP
valueFrom:
fieldRef:
fieldPath: status.podIP
---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: hello-pks
annotations:
kubernetes.io/ingress.class: contour
spec:
rules:
- host: hello-pks.example.com
http:
paths:
- path: /
backend:
serviceName: hello-pks
servicePort: 8080
ここではtype: ClusterIPでServiceリソースを作成するので、このままではクラスタ外から直接アクセスできません。Ingressリソースを作成し、Hostヘッダがhello-pks.example.comの場合にhello-pksサービスにルーティングされるようにします。
kubernetes.io/ingress.classアノテーションはIngress Controllerが複数インストールされている場合は必須です。一つしかインストールされていない場合は不要です。
次のコマンドで作成されたリソースを確認してください。
kubectl get pod,service,ingress
出力結果
NAME READY STATUS RESTARTS AGE
pod/hello-pks-7f897d97b9-g8tlp 1/1 Running 0 24m
pod/hello-pks-7f897d97b9-tbr7t 1/1 Running 0 24m
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/hello-pks ClusterIP 10.100.200.179 <none> 8080/TCP 24m
service/kubernetes ClusterIP 10.100.200.1 <none> 443/TCP 45d
NAME HOSTS ADDRESS PORTS AGE
ingress.extensions/hello-pks hello-pks.example.com 80 24m
次のコマンドでアプリケーションにアクセスしてください。
curl http://<contour ServiceのExternal-IP>:80 -v -H "Host: hello-pks.example.com"
type: NodePortを使用している場合は、次のコマンドを実行してください。
curl http://<Worker NodeのIP>:<contour Serviceの80ポートに対するnodePort> -v -H "Host: hello-pks.example.com"
出力結果
> GET / HTTP/1.1
> Host: hello-pks.example.com
> User-Agent: curl/7.54.0
> Accept: */*
>
< HTTP/1.1 200 OK
< content-type: application/json;charset=UTF-8
< x-envoy-upstream-service-time: 7
< date: Sun, 29 Sep 2019 16:50:48 GMT
< server: envoy
< transfer-encoding: chunked
<
{
"node" : {
"NODE_IP" : "192.168.3.21",
"NODE_NAME" : "093a9c8b-0827-41b2-bc12-e129f2c33833"
},
"pod" : {
"POD_IP" : "10.200.33.56",
"POD_NAME" : "hello-pks-7f897d97b9-g8tlp",
"POD_NAMESPACE" : "default"
},
"container" : { }
}
Contourの場合は
Ingressリソースの代わりにIngressRouteカスタムリソースを使用することもできます。IngressRouteリソースはContour独自ですが、Ingressよりも高度な設定ができます。
TLS終端の有効化
次にTLSを有効にします。
5. ConfigMap/Secretで設定情報の管理で作成したようにgen_ssl_certs.shでTLS証明書を作成します。
gen_ssl_certs.shをダウンロードしていない場合は次のコマンドで取得してください。
wget https://raw.githubusercontent.com/aws-quickstart/quickstart-pivotal-cloudfoundry/master/scripts/gen_ssl_certs.sh
chmod +x gen_ssl_certs.sh
*.example.comに対する証明書を作成します。
./gen_ssl_certs.sh example.com
次のコマンドでこの証明書に対するSecretリソースを作成するYAMLを生成します。
kubectl create secret tls hello-pks-tls \
--cert=example.com.crt \
--key=example.com.key \
--dry-run -o yaml > hello-pks-tls.yml
hello-pks.ymlを次のように変更してください。
kind: Service
apiVersion: v1
metadata:
name: hello-pks
spec:
type: ClusterIP
selector:
app: hello-pks
ports:
- protocol: TCP
port: 8080
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: hello-pks
spec:
replicas: 2
selector:
matchLabels:
app: hello-pks
template:
metadata:
labels:
app: hello-pks
spec:
containers:
- image: making/hello-pks:0.0.2
name: hello-pks
ports:
- containerPort: 8080
env:
- name: NODE_NAME
valueFrom:
fieldRef:
fieldPath: spec.nodeName
- name: NODE_IP
valueFrom:
fieldRef:
fieldPath: status.hostIP
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: POD_IP
valueFrom:
fieldRef:
fieldPath: status.podIP
---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: hello-pks
annotations:
kubernetes.io/ingress.class: contour
spec:
rules:
- host: hello-pks.example.com
http:
paths:
- path: /
backend:
serviceName: hello-pks
servicePort: 8080
tls: # ここを追加
- hosts:
- hello-pks.example.com
secretName: hello-pks-tls
次のコマンドで変更を反映します。
kubectl apply -f hello-pks.yml -f hello-pks-tls.yml
次のコマンドでIngressリソースを確認します。
kubectl get ingress
PORTS列に443が追加されたことを確認してください。
NAME HOSTS ADDRESS PORTS AGE
hello-pks hello-pks.example.com 80, 443 33m
/etc/hostsに次の行を追加してください。
<Worker NodeのIPまたはExternal IP> hello-pks.example.com
次のコマンドでアプリケーションにアクセスしてください。
curl https://hello-pks.example.com:443 -k -v
type: NodePortを使用している場合は、次のコマンドを実行してください。
curl https://hello-pks.example.com:<contour Serviceの443ポートに対するnodePort> -k -v
実行結果
> GET / HTTP/2
> Host: hello-pks.example.com:31353
> User-Agent: curl/7.54.0
> Accept: */*
>
< HTTP/2 200
< content-type: application/json;charset=UTF-8
< x-envoy-upstream-service-time: 10
< date: Sun, 29 Sep 2019 17:12:06 GMT
< server: envoy
<
{
"node" : {
"NODE_IP" : "192.168.3.21",
"NODE_NAME" : "093a9c8b-0827-41b2-bc12-e129f2c33833"
},
"pod" : {
"POD_IP" : "10.200.33.56",
"POD_NAME" : "hello-pks-7f897d97b9-g8tlp",
"POD_NAMESPACE" : "default"
},
"container" : { }
}
TLS終端をIngress Controllerで行うことで、アプリケーション側では特にTLSの設定をすることなく、HTTPSでアクセスできるようになりました。