LoginSignup
4
3

More than 5 years have passed since last update.

kubernetesのServiceとIngressをカンチガイしていた話

Posted at

やりたかったこと

アプリ開発中、バックエンドで使用する2種類のAPIサーバをkubernetesにデプロイし、Ingress経由で公開しようとしました。
そのときのエンドポイントを下のように設定しようとしました。

  • /server1 → APIサーバ1にアクセス
  • /server2 → APIサーバ2にアクセス

使用しているkubernetes環境は以下の通りです。

  • ホスティングサービス: IBM Cloud Kubernetes Service
  • バージョン: 1.9.10_1523 (ちょい古め)

起きたこと

どちらのエンドポイントにアクセスしても、両方のサーバに均等に到達してしまう…:fearful:

例: /server1 に3回アクセス → APIサーバ1に1回、APIサーバ2に2回到達

やらかした原因

例えば次のようなアプリをデプロイしていたとします。

name port binding
server1 8000:8000
server2 8080:8080

このとき、ServiceとIngressを下のように書いていました。

service.yml
apiVersion: v1
kind: Service
metadata:
  name: all-in-one-service
  labels:
    project: current-project
spec:
  type: LoadBalancer
  loadBalancerIP: <available IP>
  selector:
    project: current-project
  ports:
  - port: 8000
    targetPort: 8000
    name: server1
  - port: 8080
    targetPort: 8080
    name: server2
ingress.yml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: my-ingress
  labels:
    project: current-project
spec:
  rules:
  - host: <available hostname>
    http:
      paths:
      - path: /service1
        backend:
          serviceName: all-in-one-service
          servicePort: 8000
      - path: /service2
        backend:
          serviceName: all-in-one-service
          servicePort: 8080

これでうまく行くはず!:sunglasses:…と思ってたのですが。うまく行かない。
IBM Cloud Kubernetes Serviceのドキュメントを見ながらデバッグしました。

以下、実際にデバッグしたときの手順です。

  1. kubectl get po -n kube-system | grep albで、nginx-ingressが動いているpodの名前を探す
  2. kubectl logs <podname> -n kube-system nginx-ingressで、nginx-ingressのログを取得する
  3. kubectl exec -it <podname> bash -c nginx-ingress -n kube-systemで、nginx-ingressのコンテナにログインする
  4. nginxの設定ファイルを探し出す。今回は/etc/nginx/conf.d/以下にありました。

nginxの設定ファイルを見ると、下のような部分がありました。

my-ingress.conf(抜粋)
  location /service1 {
    ...
    proxy_pass http://my-cluster-url.eu-central.containers.mybluemix.net-all-in-one-service;
    ...
  }

  location /service2 {
    ...
    proxy_pass http://my-cluster-url.eu-central.containers.mybluemix.net-all-in-one-service;
    ...
  }

ん?同じURL…?

IngressにはserviceNameとservicePortを両方書くけれど、servicePortは関係なく、両方のパスに対して同じServiceを紐づけているだけということが分かりました。
だからうまく行かなかったんですね。

どう直したか

シンプルに、ServiceをDeploymentごとに分けました。
Ingressに指定するパスごとに別々のServiceが割りあたるようにしました。

svc-server1.yml
apiVersion: v1
kind: Service
metadata:
  name: service-for-server1
  labels:
    project: current-project
spec:
  selector:
    app: server1
    project: current-project
  ports:
  - port: 8000
    targetPort: 8000
svc-server2.yml
apiVersion: v1
kind: Service
metadata:
  name: service-for-server2
  labels:
    project: current-project
spec:
  selector:
    app: server2
    project: current-project
  ports:
  - port: 8080
    targetPort: 8080
ingress.yml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: my-ingress
  labels:
    project: current-project
spec:
  rules:
  - host: <available hostname>
    http:
      paths:
      - path: /service1
        backend:
          serviceName: service-for-server1
          servicePort: 8000
      - path: /service2
        backend:
          serviceName: service-for-server2
          servicePort: 8080

これで今度こそ解決:sunglasses:

おわりに

実はIngressのルーティング問題の他にも、気づいて直したやらかしがいくつかあります。

  • ServiceでLoadBalancerIPを指定しているので、名前空間変えてデプロイしたりできなかった。
  • そもそもIngressに紐付けるだけならLoadBalancerでなくても良かった。
    • Serviceのtypeを指定せずにClusterIPになっててもIngressに登録できるみたいです。

他にもこんなとこやらかしてるよ、というツッコミお待ちしております。k8sむずかしい。

4
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
3