Edited at

kubernetesにingressを導入する方法

More than 1 year has passed since last update.


なぜingress?

kubernetesはpods, deployments, servicesの基本要素で構成されており、標準的には、serviceにロードバランサーを設定してIPを晒し、外部インターネットからアクセスできるようにします。

しかし、HTTPSにリダイレクトするには内部でnginx-proxyを持つ必要がありますし、service毎にIPアドレスが生成されてしまうという問題があります。

ingressはHTTPSレイヤーのロードバランサーであり、


  • IP管理などを個別のserviceではなくingressで管理できる

  • Googleが推奨している

などのメリットがあります。

参考:

他にもリージョン間にまたがるロードバランスが可能であるなどのメリットもありますが、流石にそこまでサービスを大規模に展開していないのでその恩恵は今のところありません。


環境

kubernetes エンジン 1.8.6-gke.0


ingress導入

インターネット → service ではなく、インターネット → ingress → service であることに留意すると分かりやすくなります。以降は、既に動いているserviceがあるのを前提に進めます。


1. service, deploymentの設定

現在動いているserviceのデプロイメントを、type: LoadBalancer ではなく、type: NodePortにし、portをtargetPortと同じにします。以下はserviceとdeploymentを一緒に記述したyamlです。

apiVersion: v1

kind: Service
metadata:
name: fuga-api
namespace: fuga-namespace
labels:
app: fuga-api
spec:
type: (LoadBalancer->) NodePort
ports:
- port: (80->)8080
targetPort: 8080
protocol: TCP
selector:
app: fuga-api
---
apiVersion: apps/v1beta1
kind: Deployment
metadata:
name: fuga-api
namespace: fuga-namespace
spec:
replicas: 1
revisionHistoryLimit: 3
template:
metadata:
namespace: fuga-namespace
labels:
app: fuga-api
version: latest
spec:
containers:
- name: fuga-api
image: asia.gcr.io/hogehoge/fuga-image:a1
ports:
- containerPort: 8080

ポートの設定がミソです。もう80からアクセスは受け付けません。

これを記述したファイルを保存し、kubectl apply -f deploy-service.yamlとして更新します。

serviceのIPアドレスは"<none>"になっているはずです。


2. ingressの設定

serviceで設定した'fuga-api'をserviceNameに指定します。また、8080をservicePortに指定します。8080という数字は、imageで指定したウェブアプリケーションがそのポートを受け付けているからそう設定しているだけなので、例えばRailsのpumaが3000を受け付けていれば全て3000に置き換えます。

apiVersion: extensions/v1beta1

kind: Ingress
metadata:
name: fuga-ingress
namespace: fuga-namespace
annotations:
kubernetes.io/ingress.global-static-ip-name: fuga-ipaddress # optional
spec:
rules:
- host: fuga.example.com
http:
paths:
- backend:
serviceName: fuga-api
servicePort: 8080

(オプション)また、1つのingressで1つのIPアドレスが割り当てられますが、ingressを削除→上げ直すたびに変わってしまうので、固定のIPを設定するようにします。やり方は以下を参考にしてください。

Ingressにstatic-ipを指定してやった on GKE and GCE

先程と同様、同じくkubectl apply -f ingress.yamlとします。

以上です。簡単でしたね。ingressはIPアドレスが割り当てられるまで1~2分かかります。もし5分以上たっても割り当てられない場合、GCPの「IAMと管理」→「割り当て」から、静的IPアドレスの上限を確認してみてください。


3. 確認

HTTPでアクセスできるかブラウザで確認して見てください。見られない場合、いくつかチェックポイントがあります。まず、DNSの設定、pod, service, deploymentにエラーがない、綴ミスなどの確認は必須です。


どのページにアクセスしても502が返る

→ ingressの適用に時間がかかっている

IPアドレスが割り当てられても、サービスとingressを結びつけるのに時間がかかるみたいです。最大5分位待ちましょう。


fuga.example.com/healthzはokと表示される場合

→ ingress自体の設定は問題なし、アプリケーションの問題です。

ingressの適用は、ウェブアプリケーションのrootがstatus 200を返す必要があります。(つまり、rootに来たときにリダイレクトはアウト)作り直してもう一度確認してください。rootでリダイレクトしてもOKな設定にできるかどうかは調査中です


追記(2018/2/3)

DeploymentにreadinessProbeの設定をすればうまくいきました。ヘルスチェック時には、ここで指定したパスを見に行って、無ければrootという動きをするようです。以下はreadinessProbeの設定例です。

      containers:

- name: fuga-api
image: asia.gcr.io/hogehoge/fuga-image:a1
ports:
- containerPort: 8080
readinessProbe:
httpGet:
path: /alive-path
port: 8080


SSL化

ingress - TLSにしたがい、secretsを作成します。キーと証明書はlets encryptなどで入手しましょう。

apiVersion: v1

kind: Secret
metadata:
name: fuga-ssl
namespace: fuga-namespace
type: Opaque
data:
tls.crt: base64 encode crt
tls.key: base64 encode key

ingressのyamlに以下のようにsecret名を記述します。service単位ではなくて全部ingressで管理できるのが嬉しいところですよね。一つのingressで複数ホストに対する複数証明書を記述することも出来ます。

spec:

tls:
- secretName: fuga-ssl
rules:
- host: fuga.example.com
http:
paths:
- backend:
serviceName: fuga-api
servicePort: 8080

ingressはじめはとっつきにくくて苦労しましたが、慣れてくれば便利です。効率的にサービスを管理したい場合、導入しておくのをおすすめします。