LoginSignup
34
19

More than 3 years have passed since last update.

KubernetesでのIngress経由のSession Sticky

Last updated at Posted at 2018-05-24

マイクロサービスではアプリケーションはステートレスであるのが望ましいですが、既存アプリケーションをなるべくリファクタリングせずKubernetesで動かしたい場合など、Kubernetes環境でもSession Stickyを使いたい場合はあると思います。

MinikubeやIBM Cloud Privateなど、Ingress ControllerとしてNGINX Ingress Controllerを使用している環境では、NGINX Ingress ControllerのSession Sticky機能を使って、Session Sticky(Session Affinity)が行えます。セッションを使うWebアプリケーションをMinikubeにデプロイし、Session Stickyができることを確認してみます。

MinikubeでのIngressの利用

MinikubeでIngressのaddonが有効になっているかを確認し、有効でない場合は有効にします。

minikube addons list
minikube addons enable ingress

セッションを使うアプリケーションの準備

セッションを使うWebアプリケーションと、そのアプリケーションをデプロイ済みのLibertyコンテナを準備します。今回はアプリがデプロイ済みのsotoiwa540/sample:1.0というLibertyイメージを使用します。

アプリケーションの作成方法は以下の記事が参考になります。

アプリケーションのデプロイ

sotoiwa540/sample:1.0のLibertyコンテナのPodをデプロイするマニフェストを作成します。

liberty-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: liberty
spec:
  selector:
    matchLabels:
      app: liberty
  replicas: 3
  template:
    metadata:
      labels:
        app: liberty
    spec:
      containers:
      - name: liberty
        image: sotoiwa540/sample:1.0
        imagePullPolicy: Always
        ports:
        - containerPort: 9080

マニフェストを適用します。

kubectl apply -f liberty-deployment.yaml

確認します。

$ kubectl get po
NAME                      READY   STATUS    RESTARTS   AGE
liberty-f68456cbc-dzrzq   1/1     Running   0          64s
liberty-f68456cbc-gbgjm   1/1     Running   0          64s
liberty-f68456cbc-m5fbr   1/1     Running   0          64s
$

Serviceの作成

Serviceのマニフェストを作成します。

liberty-service.yaml
apiVersion: v1
kind: Service
metadata:
  name: liberty
spec:
  type: ClusterIP
  selector:
    app: liberty
  ports:
  - protocol: TCP
    port: 9080

マニフェストを適用します。

kubectl apply -f liberty-service.yaml

確認します。

$ kubectl get svc
NAME         TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)    AGE
kubernetes   ClusterIP   10.96.0.1      <none>        443/TCP    4m10s
liberty      ClusterIP   10.102.34.78   <none>        9080/TCP   68s
$

Ingressの作成

Ingressのマニフェストを作成します。

MinikubeではなくIBM Cloud Privateの場合は、 Nginx Ingress Controllerの設定として--annotations-prefix=ingress.kubernetes.io設定されているため、アノテーションのキー名はnginx.ingress.kubernetes.io/hogehogeではなくingress.kubernetes.io/hogehogeであることに注意。

(参考)
Enable Ingress Controller to use a new annotation prefix

liberty-ingress.yaml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: liberty
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  rules:
  - host: sample.example.com
    http:
      paths:
      - path: /app1
        backend:
          serviceName: liberty
          servicePort: 9080

マニフェストを適用します。

kubectl apply -f liberty-ingress.yaml
$ kubectl get ing
NAME      HOSTS                ADDRESS     PORTS   AGE
liberty   sample.example.com   10.0.2.15   80      7s
$

Minikubeの場合はMinikubeのIPを確認します。

$ minikube ip
192.168.99.113
$

/etc/hosts192.168.99.113 sample.example.comを追記します。

sudo vi /etc/hosts

動作確認(Stickyなし)

ブラウザを開き、以下のURLでIngress経由でアプリケーションにアクセスします。

incrementボタンを押すことでセッションのカウンターを増やすことができます。ボタンを連打し、セッションが維持されていないので、カウントが増えていかないことを確認します。

image.png

curlでアクセスしてレスポンスヘッダを確認します。JSESSIONIDのみがSet-Cookieされています。

$ curl -v -c cookie.dat http://sample.example.com/app1/sample/session?increment=increment 2>&1 | grep -i "set-cookie:"
< Set-Cookie: JSESSIONID=0000w76PPbo4dXi5lAo03nzhSLM:e5aed9a9-19cb-41df-b170-6d6aa0791700; Path=/; HttpOnly
$

cookie.datJSESSIIONIDが保存されていることが確認できます。

$ cat cookie.dat
# Netscape HTTP Cookie File
# https://curl.haxx.se/docs/http-cookies.html
# This file was generated by libcurl! Edit at your own risk.

#HttpOnly_sample.example.com    FALSE   /   FALSE   0   JSESSIONID  0000w76PPbo4dXi5lAo03nzhSLM:e5aed9a9-19cb-41df-b170-6d6aa0791700
$

Session Stickyの有効化

Ingressを一度削除します。

kubectl delete -f liberty-ingress.yaml

以下のドキュメントを参考に、IngressでのActive Cookie Session Affinityを有効にするためのアノテーションを追加します。Active Cookieなので、IngressがCookieを付加するようになるはずです。

liberty-ingress-sticky.yamlを作成します。

Kubernetes環境がMinikubeではなくIBM Cloud Privateの場合はnginx.ingress.kubernetes.io/hogehogeではなくingress.kubernetes.io/hogehogeであることに注意。

liberty-ingress-sticky.yaml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: liberty
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
    nginx.ingress.kubernetes.io/affinity: "cookie"
    nginx.ingress.kubernetes.io/session-cookie-name: "route"
    nginx.ingress.kubernetes.io/session-cookie-hash: "sha1"
spec:
  rules:
  - host: sample.example.com
    http:
      paths:
      - path: /app1
        backend:
          serviceName: liberty
          servicePort: 9080

マニフェストを適用します。

kubectl apply -f liberty-ingress-sticky.yaml

動作確認(Stickyあり)

アプリケーションにアクセスします。

incrementボタンを連打します。今度はセッションが維持されているのでカウンターが増えていくことが確認できます。

image.png

curlでアクセスしてレスポンスヘッダを確認します。JSESSIONIDに加えてrouteがSet-Cookieされています。

$ curl -v -c cookie.dat http://sample.example.com/app1/sample/session?increment=increment 2>&1 | grep -i "set-cookie:"
< Set-Cookie: route=62d26518514d05ee42de6a48017d492202d11606; Domain=sample.example.com; Path=/app1; HttpOnly
< Set-Cookie: JSESSIONID=00003DHvBFe2s00bLutVDflq3It:e5aed9a9-19cb-41df-b170-6d6aa0791700; Path=/; HttpOnly
$

cookie.datを確認すると、JSESSIONIDに加えて、IngressがセットしたrouteというCookieが確認できます。

$ cat cookie.dat
# Netscape HTTP Cookie File
# https://curl.haxx.se/docs/http-cookies.html
# This file was generated by libcurl! Edit at your own risk.

#HttpOnly_.sample.example.com   TRUE    /app1   FALSE   0   route   872ea48729dcfeef62390b62963ddcc20e5bbf9b
#HttpOnly_sample.example.com    FALSE   /   FALSE   0   JSESSIONID  00008gyAfvIxqgTLiaTHXqMXRDQ:e5aed9a9-19cb-41df-b170-6d6aa0791700

Ingress ControllerのHA構成

Ingress ControllerがHA構成の場合、最初にCookieを発行したIngress Controllerとは違うIngress Controllerにリクエストが割り振られたとしたら、ちゃんとStickyが効くのかを確認します。

MinikubeではIngress ControllerはHA構成になっていないので、ここでは、簡易的に検証するため、単にIngress ControllerのPodを再起動することによりIngress Controllerが保持している情報をクリアしてみて、そのあともStickyが有効になるのかを確認します。

Podを削除して再作成させます。

$ kubectl get po -n kube-system | grep ingress
nginx-ingress-controller-6958898f8f-2tc59   1/1     Running   0          2m29s
$ kubectl delete po -n kube-system nginx-ingress-controller-6958898f8f-2tc59
pod "nginx-ingress-controller-6958898f8f-2tc59" deleted
$ kubectl get po -n kube-system | grep ingress
nginx-ingress-controller-6958898f8f-4bbvv   0/1     Running   0          13s
$

先ほどのブラウザでアクセスし、セッションが維持されることを確認します。

image.png

何度か再作成を繰り返してみても、セッションは維持されます。ですので、Ingress ControllerがHA構成の場合、その前段にいる負荷分散装置からIngress Controllerに対しては、アフィニティーを効かせなくても大丈夫と思われます。

(補足)
IBM Cloud Private v3.1.0に付属のバージョンのNGINX Ingress ControllerではCookieの値は単に<PodのIP>:<ポート>を指定のアルゴリズム(sha1)でハッシュしただけのものなので、echo -n '172.17.0.7:9080' | shasum -a 1のようにしたものと一致したのですが、この変更で変わったっぽいです。他にもアフィニティー関連の修正は多そうなので、バージョンによる挙動の違いには注意した方がよさそうです。

環境 イメージ
minikube v0.32.0 quay.io/kubernetes-ingress-controller/nginx-ingress-controller:0.21.0
IBM Cloud Private v3.1.0 mycluster.icp:8500/ibmcom/nginx-ingress-controller-amd64:0.16.2

参考リンク

34
19
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
34
19