EclipseでJavaアプリを書いて、Libertyコンテナで、Kubernetesで公開するまでの話し (その1)


Kuberntesのサービスはkube-proxyによって、複数のポッド（コンテナ）へリクエストを分散する機能を持っています。しかし、実態はiptablesを使って、リクエストをポッドへ均等に振り分けるものであり、サーブレットのセッション・オブジェクトを利用している場合、常に同じアプリケーション・サーバーへ割当たるとは限らない事を考慮する必要があります。

Kubernetesの負荷分散の動きを見るために、Javaプログラムを書いて動きを追ってみます。


次の箇条書きは、この記事で想定するストーリです。 IBM WebSphereの新しいアーキテクチャを採用し軽量化され
、コンテナ上での利用に適した Libetyを利用します。 Libertyのサーブレット実行環境を整えるために、長くなりますが、Eclipse のインストールから始めます。


1. 統合IDE環境 Eclipise をインストールする
2. Liberty プラグインを設定する
3. セッション・オブジェクトを利用するJava Webアプリケーションを書く
4. Eclipse上でテストして動作を確認する
5. ローカル環境で、コンテナをビルドして動作を確認する
6. コンテナをDockerHubへ登録してKuberntesで動作を確認する
7. 複数のポッドへ分散させた時の問題を確認する



## Eclipse のインストール

ECLIPSEのダウンロードページ https://www.eclipse.org/downloads/ から Eclipse OXYGEN 64bitのインストーラーをダウンロードします。

インストーラーを起動して、インストールするパッケージのリストが表示されますから、「Eclipse IDE for Java EE Developers」を選択します。 インストールが完了すると、Eclipseを起動します。ワークスペースなどは、デフォルトでも構いません。

起動後にEclipseの初回起動画面として、選択メニューが表示されます。 既存のワークスペースを選んだ場合、この初回起動画面が表示されないので、新規のワークスペースで起動します。

## IBM Liberty Developer Tools for Oxygen

初回起動のメニュー画面の中で、「Launch the Eclipse Marketplace」を選択します。 Eclipse Marketplace のウィンドで、「IBM Liberty Developer Tools for Oxygen」を検索して、インストールします。 インストールするフィチャーの選択を要求するので、次のスクリーン・ショットに様に選択します。

![スクリーンショット 2018-05-17 21.12.08.png](https://qiita-image-store.s3.amazonaws.com/0/42829/991c67c7-57d6-f536-1329-62f6bb7a3024.png "スクリーンショット 2018-05-17 21.12.08.png")

次に、ライセンスの確認画面が現れるので、Acceptをしてインストールを完了すると、Eclipseの再起動の許可の対話ウィンドが表示されるので、「Restart Now」をクリックしてEclipseの準備を完了させます。

## Javaアプリケーションサーバー Libertyのセットアップ

再起動後に、ウィンド右端の「コーヒー豆とフォルダー」の上のアイコンをクリックすると、次の画面に変わります。 
![スクリーンショット 2018-05-20 19.02.52.png](https://qiita-image-store.s3.amazonaws.com/0/42829/a5df3823-1026-e09d-9ff1-9e10993ac88e.png "スクリーンショット 2018-05-20 19.02.52.png")

このウィンド中央下に、アプリケーションサーバーの状態を表示する枠があります。 Server のタブを選択すると、メッセージ表示されています。

![スクリーンショット 2018-05-17 21.26.50.png](https://qiita-image-store.s3.amazonaws.com/0/42829/a630b51d-f857-d1e8-2e55-a6de07abcebc.png "スクリーンショット 2018-05-17 21.26.50.png")


「Install from an archive or a repository」と JRE 「Use default JRE」を選択して、「Next」をクリックします。

![スクリーンショット 2018-05-17 21.27.36.png](https://qiita-image-store.s3.amazonaws.com/0/42829/ddcd628f-a498-b6f6-93f3-c52e19d7d5f2.png "スクリーンショット 2018-05-17 21.27.36.png")

「No servers are available. Click this link to create a new server...」のメッセージをクリックして、New Server ウインドを開き、Liberty Server を選択します。

![スクリーンショット 2018-05-20 20.49.10.png](https://qiita-image-store.s3.amazonaws.com/0/42829/01d8cb7a-5247-6eb7-b451-6a66886ff54f.png "スクリーンショット 2018-05-20 20.49.10.png")

Libertyの公式コンテナと合わせるために設定するため、「Download and install a new runtime environment from ibm.com」を選択して、リストの中から、「WAS Liberty with Java EE 7 Web Profile」を選択します。 

![スクリーンショット 2018-05-20 20.51.48.png](https://qiita-image-store.s3.amazonaws.com/0/42829/8338a8ec-f08f-26d6-6cea-b87764cc8e35.png "スクリーンショット 2018-05-20 20.51.48.png")

「Install Additional Content」で、次の２つをインストールします。「Base Bundle」、「Java EE 7 Web Profile Bundle」を選択します。

![スクリーンショット 2018-05-20 20.52.16.png](https://qiita-image-store.s3.amazonaws.com/0/42829/d8e70a95-fbf1-7a0d-ee49-140c48688b3a.png "スクリーンショット 2018-05-20 20.52.16.png")

ライセンス情報を表示されるので、アクセプトして、次へ進みます。サーバー名は、デフォルトで表示される「defaultServer」を利用して、「Finish」をクリックします。


![スクリーンショット 2018-05-20 20.52.45.png](https://qiita-image-store.s3.amazonaws.com/0/42829/9651de9d-d91c-7b3a-b292-5e2a8ab12d09.png "スクリーンショット 2018-05-20 20.52.45.png")


## Java アプリケーションの開発


### プロジェクトの作成

プロジェクト Sample1を作成します。 Eclipse 左上のアイコンをクリックして、「Dynamic Web Project」を選びます。

![スクリーンショット 2018-05-20 21.21.34.png](https://qiita-image-store.s3.amazonaws.com/0/42829/d8cdae5a-ae13-a4e0-3b48-14050d0dc47d.png "スクリーンショット 2018-05-20 21.21.34.png")

「Project name」に、Sample1を入れ、「Add EAR membership」の 「Add project to an EAR」のチェックを外します。 今回は、WARファイルだけを作成します。 「Finish」をクリックしてプロジェクト Sample1を作成を完了します。

![スクリーンショット 2018-05-20 21.21.57.png](https://qiita-image-store.s3.amazonaws.com/0/42829/92d03289-203c-3880-c556-6015fdf7edc1.png "スクリーンショット 2018-05-20 21.21.57.png")


Sample1に、全部で5つのファイルを作成します。残りの一個は任意です。 内訳は4つのjavaファイルと 1つのjspファイルを作ります。 画像のjpgファイルは、無くても構いません。 インターネットから好みの画像をダウンロードして、差し替えると良いでしょう。

![スクリーンショット 2018-05-21 7.48.08.png](https://qiita-image-store.s3.amazonaws.com/0/42829/efbdc8e8-fb3e-fe51-843f-0df399550a64.png "スクリーンショット 2018-05-21 7.48.08.png")




### パッケージの作成

「Java Resources」にマウスをポイントして、右クリックして「New」でメニューを開いて「Package」を選んで、「org.sample」を作成します。

これから、パッケージの中に、4つのファイルを作成していきます。

* Sample1.java            ウェブ画面を送出するサーブレット、応答画面は ReplySample1.jspを利用。
* ViewSessionObject.java  セッション・オブジェクトをテキストで応答するサーブレット
* SetSessionObject.java   セッション・オブジェクトをセットして、テキストで応答するサーブレット
* SessionObject.java      セッション・オブジェクトのエンティティを格納するためのクラス


WebContentsの中に2つのファイルを作成します。

* ReplySample1.jsp        サーブレットSample1から呼び出される応答画面を作成
* WebSphereLibery.jpg     画像ファイル、好みの画像ファイルをおきます。



### サーブレットの作成

「Sample1」を展開して、「Servlet」で右クリックして、メニューを展開し、「New」,「Servlet」を選びます。

![スクリーンショット 2018-05-20 21.32.31.png](https://qiita-image-store.s3.amazonaws.com/0/42829/1933a410-7dee-ec38-3343-1e7e196ce8ae.png "スクリーンショット 2018-05-20 21.32.31.png")

「Java package」に「org.sample」をセットして、「Class name」に「Sample1」をセットして「Finish」をクリックすると、雛形が作成されます。 下記を参考にして、protected void doGet()にコードを追加します。そして、赤色のエラーが表示されるので、エラーが解消する様に、import文を追加します。



~~~Sample1.java
package org.sample;

import java.io.IOException;
import java.net.InetAddress;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

/**
 * Servlet implementation class Sample1
 */
@WebServlet("/Sample1")
public class Sample1 extends HttpServlet {
	private static final long serialVersionUID = 1L;
       
    /**
     * @see HttpServlet#HttpServlet()
     */
    public Sample1() {
        super();
        // TODO Auto-generated constructor stub
    }

	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

		// get environment
        InetAddress ia = InetAddress.getLocalHost();
        String IpAddr = ia.getHostAddress();                                            
        String HostName = ia.getHostName();                                               
        request.setAttribute("IPaddr", IpAddr);
        request.setAttribute("Hostname", HostName);

        // get http parameter 
		String param1 = request.getParameter("param1");

		// get session object
		HttpSession session = request.getSession();
		SessionObject so = (SessionObject)session.getAttribute("param1");
		if (so == null) {
			so = new SessionObject();
			session.setAttribute("param1", so);
		}

		// set entity bean
		if ( param1 != null ) {
			so.setParam1(param1);
		}
		
		RequestDispatcher requestDispatcher = request.getRequestDispatcher("ReplySample1.jsp");	
		requestDispatcher.forward(request, response);
	}

	/**
	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
		doGet(request, response);
	}

}
~~~


次も同様の手順で、サーブレット ViewSessionObject.javaを追加して、雛形のコードのdoGetメソッドの中を以下で置き換えます。 同様にエラーが解消するまで、import文を追加します。

~~~ViewSessionObject.java
...
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.setContentType("text/plain; charset=UTF-8"); 
        PrintWriter out = response.getWriter(); 
        InetAddress ia = InetAddress.getLocalHost();
        out.println("Host Name = " + ia.getHostName());
        out.println("IPaddr    = " + ia.getHostAddress());
		HttpSession session = request.getSession();
		SessionObject so = (SessionObject)session.getAttribute("param1");
        out.println("param1    = " + so.getParam1());
		//response.getWriter().append("Served at: ").append(request.getContextPath());
	}
...
~~~


Eclipseのサーブレットメニューから SetSessionObject.javaを追加して、雛形のコードのdoGetメソッドの中を以下で置き換えます。 同様にエラーが解消するまで、import文を追加します。

~~~SetSessionObject.java
...
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// get environment
        InetAddress ia = InetAddress.getLocalHost();
        String IpAddr = ia.getHostAddress();                                            
        String HostName = ia.getHostName();                                               
        request.setAttribute("IPaddr", IpAddr);
        request.setAttribute("Hostname", HostName);

        // get http parameter 
		String param1 = request.getParameter("param1");

		// get session object
		HttpSession session = request.getSession();
		SessionObject so = (SessionObject)session.getAttribute("param1");
		if (so == null) {
			so = new SessionObject();
			session.setAttribute("param1", so);
		}

		// set entity bean
		if ( param1 != null ) {
			so.setParam1(param1);
		}

        response.setContentType("text/plain; charset=UTF-8"); 
        PrintWriter out = response.getWriter(); 
        out.println("set param1 = " + param1 );
		
	}
...
~~~




### JSPファイルの追加

サーブレット「Sample1」の応答として利用するJSPファイル「ReplySample1.jsp」を作成します。
「WebContent」で左クリック、「New」を展開して、「JSP File」を選択します。
![スクリーンショット 2018-05-20 21.48.21.png](https://qiita-image-store.s3.amazonaws.com/0/42829/3691fba4-8680-5a86-26be-6a07ef240461.png "スクリーンショット 2018-05-20 21.48.21.png")

雛形のJSPファイルが作成されるので、以下の内容に置き換えます。 

~~~ReplySample1.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<jsp:useBean id="param1" class="org.sample.SessionObject" scope="session" />

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>

<img src="WebSphereLiberty.jpg" width="300">

<h1>Reply web page by Sample1 Servlet</h1>

HostName: <%= request.getAttribute("Hostname") %><br>
IP address: <%= request.getAttribute("IPaddr") %><br>
<br>
Session Object (param1) = <jsp:getProperty name="param1" property="param1" /><br>
<p>パラメータ付きリンク</p>
Set param1 : <a href="?param1=LIBERTY">set param1=LIBERTY</a><br>
Set param1 : <a href="?param1=WebSphere">set param1=WebSphere</a><br>
Get param1 : <a href="Sample1">パラメータなしは、保存した値の表示</a><br>

<p>パラメータでGETのためアルファベットのみ対応</p>
<FORM ACTION='Sample1' METHOD='GET'>
<INPUT TYPE='text' NAME='param1' VALUE=''>
<INPUT TYPE='submit' VALUE=ENTER'>
</FORM>

<p>サーブレットで結果を返す</p>
<a href="ViewSessionObject">ViewSessionObject</a>


</body>
</html>
~~~


### セッション・オブジェクトに保存するためのJavaBeanの追加

セッション・オブジェクトとして保存するデータ構造として、以下のファイルを作成します。

~~~SessionObject.java
package org.sample;

public class SessionObject {

	private String param1 = "Default Value";
	public String getParam1() {
		return param1;
	}
	public void setParam1( String inputdata) {
		this.param1 = inputdata;	
	}

}
~~~

## アプリケーションのEclipse上でのテスト

Eclipse ウィンドの中央下、アプリケーションサーバーのペインで、「Server」タブを開いて、「Libety Server」をクリックして、開始ボタンでサーバーをスタートさせます。

![スクリーンショット 2018-05-20 21.57.44.png](https://qiita-image-store.s3.amazonaws.com/0/42829/e6c1b587-0158-b230-895b-a7060941382b.png "スクリーンショット 2018-05-20 21.57.44.png")

Eclipse内のブラウザ、または、Chromeなどのブラウザで、http://localhost:9080/Sample1/Sample1 を開くと、Javaアプリケーションの画面が開きます。 ウェブ画面を利用して、セッション・オブジェクトの追加と更新ができます。

この画面の中で、Session Object (param1)が、セッション・オブジェクトに保存されたデータです。



### Curlでのテスト

ウェブ画面だけでは、テスト結果を記録として残し難くので、テキスト画面として、curlコマンドで、セッション・オブジェクトのセットと表示ができる様にしたのが、SetSessionObjectとViewSessionObject の二つのサーブレットです。


次はセッション・オブジェクトのセットの例です。 セッションを識別するためのJSESSIONIDを保存して再利用するために、オプションを追加します。 "-c" はクッキーを保存し、"-b" はファイルに保存されたクッキーを再利用します。

~~~
$ curl -c cookie.dat http://localhost:9080/Sample1/SetSessionObject?param1=KUBERNETES
set param1 = KUBERNETES
~~~


そして、セッション・オブジェクトの取り出しの例です。

~~~
$ curl -b cookie.dat http://localhost:9080/Sample1/ViewSessionObject
Host Name = imac.local
IPaddr    = 192.168.1.25
param1    = KUBERNETES
~~~

これでセッション・オブジェクトを利用するJavaアプリケーションの準備ができました。



## ローカル環境で、コンテナをビルドして動作を確認

ローカルにDockerCEが、インストールされていない場合は、https://www.docker.com/community-edition#/download からダウンロードしてインストールします。

### WARファイルのエクスポート

「Sample1」を右クリックして、メニューを展開、「Export」、「WAR file」を選択して、プロジェクトの成果物をエクスポートします。

![スクリーンショット 2018-05-20 22.31.09.png](https://qiita-image-store.s3.amazonaws.com/0/42829/94783ab5-239a-34a3-01ac-04af427f9ffa.png "スクリーンショット 2018-05-20 22.31.09.png")


### Dockerのビルド

WebSphere Liberty の公式コンテナに、アプリケーションを追加して、カスタムコンテナをビルドする Dockerfileです。

~~~Dockerfile
FROM websphere-liberty:webProfile7
ADD ./Sample1.war /config/dropins/
~~~

このDockerfileとエクスポートしたwarファイルを利用して、次のコマンドでコンテナをビルドします。

~~~
$ docker build -t sample1:0.1 -f Dockerfile .
Sending build context to Docker daemon  7.899MB
Step 1/2 : FROM websphere-liberty:webProfile7
 ---> d2be0385dd52
Step 2/2 : ADD ./Sample1.war /config/dropins/
 ---> 3a8178c76f5c
Successfully built 3a8178c76f5c
Successfully tagged sample1:0.1
~~~



### DockerCE環境でのテスト

ローカルのコンテナ環境で、ビルドしたコンテナを作成してテストします。

~~~
$ docker run -d --rm -p 9080:9080 --name sample1 sample1:0.1
542055eddd87e74b0720a7eb17771c33882add697ecc44bf5021126473ecb494

$ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                              NAMES
542055eddd87        sample1:0.1         "/opt/ibm/docker/doc…"   11 seconds ago      Up 9 seconds        0.0.0.0:9080->9080/tcp, 9443/tcp   sample1
~~~


コンテナのサービスは、次のアドレスでアクセスできます。 `http://localhost:9080/Sample1/Sample1` 
次の様なウェブ画面が表示されます。

![スクリーンショット 2018-05-20 23.19.45.png](https://qiita-image-store.s3.amazonaws.com/0/42829/ccdc7454-0431-55c4-7186-190ac5ab2611.png "スクリーンショット 2018-05-20 23.19.45.png")



## Kuberntesでの動作テスト

カスタムビルドしたコンテナをDocker Hubに登録して、Kubernetesにでデプロイをすすめていきます。Docker HubのユーザーIDは、https://hub.docker.com/ から無料で作成できます。

次の手順で Docker Hub にログインして、タグを付与して、登録します。

~~~
$ docker login
Username (maho): 
Password: 
Login Succeeded

$ docker tag sample1:0.1 maho/sample1:0.1
$ docker push maho/sample1:0.1
The push refers to repository [docker.io/maho/sample1]
1f9b2348b7fe: Pushed 
65241fd38f95: Mounted from maho/java-apl-1st 
03e874ba4469: Mounted from maho/java-apl-1st 
66eecd8428af: Mounted from maho/java-apl-1st 
40b22d33afe4: Mounted from maho/java-apl-1st 
6ff1f4760575: Mounted from maho/java-apl-1st 
b79a9e3b7c43: Mounted from maho/java-apl-1st 
1bb66452c5c3: Mounted from maho/java-apl-1st 
81eca69295c0: Mounted from maho/java-apl-1st 
e27a778e6a14: Mounted from maho/java-apl-1st 
9b9775ad094a: Mounted from maho/java-apl-1st 
bf3d982208f5: Mounted from maho/java-apl-1st 
cd7b4cc1c2dd: Mounted from maho/java-apl-1st 
3a0404adc8bd: Mounted from maho/java-apl-1st 
82718dbf791d: Mounted from maho/java-apl-1st 
c8aa3ff3c3d3: Mounted from maho/java-apl-1st 
0.1: digest: sha256:cf5ebf09376a4714d11f23f648881a1bc97ac1801e01fda45f2263cd1d4157cb size: 3665
~~~


minikubeをスタートさせます。 minikubeをインストールするには、https://kubernetes.io/docs/tasks/tools/install-minikube/ を参照してください。

スタートとして、kubectlが利用できるまでの手順を以下に提示します。 minikube を開始することで、kubectlの環境設定は自動的に実施されるので、下記の通り、すぐにkubectlが利用できる様になります。

~~~
$ minikube start
Starting local Kubernetes v1.10.0 cluster...
Starting VM...
Getting VM IP address...
Moving files into cluster...
Setting up certs...
Connecting to cluster...
Setting up kubeconfig...
Starting cluster components...
Kubectl is now configured to use the cluster.
Loading cached images from config file.

$ minikube status
minikube: Running
cluster: Running
kubectl: Correctly Configured: pointing to minikube-vm at 192.168.99.100

$ kubectl get node
NAME       STATUS    ROLES     AGE       VERSION
minikube   Ready     master    20h       v1.10.0
~~~


次はカスタムコンテナをKubernetesにデプロイするためのYAMLです。 次のYAMLで、Deployment と Service の二つを定義します。

~~~sample1.yml 
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: liberty
spec:
  replicas: 1
  template:
    metadata:
      labels:
        app: liberty
    spec:
      containers:
      - name: was
        image: maho/sample1:0.1
        ports:
        - containerPort: 9080
---
apiVersion: v1
kind: Service
metadata:
  name: liberty
spec:
  type: NodePort
  selector:
    app: liberty
  ports:
  - protocol: TCP
    port: 9080
    nodePort: 32180
~~~

次のコマンドで適用します。

~~~
$ kubectl apply -f sample1.yml 
deployment "liberty" created
service "liberty" created
~~~


これで、minikubeのIPアドレス 192.168.99.100 で NodePort番号 32180でアクセスできる様になります。

ブラウザから、`http://192.168.99.100:32180/Sample1/Sample1` としてアクセスできます。



# Kubernetes上でのテスト


## ポッド１個の場合

最初に、ポッドのレプリカ数を１個としてアクセスして、セッション・オブジェクトをセットして、表示を12回実施した結果です。
最初にセットしたパラメータが、全ての応答で表示され、期待通りの結果です。

~~~
$ kubectl get po -o wide
NAME                       READY     STATUS    RESTARTS   AGE       IP           NODE
liberty-577c9f77cf-942bd   1/1       Running   0          33s       172.17.0.3   minikube
$ curl -c cookie.dat http://192.168.99.100:32180/Sample1/SetSessionObject?param1=ABC123
set param1 = ABC123
$ curl -b cookie.dat http://192.168.99.100:32180/Sample1/ViewSessionObject
Host Name = liberty-577c9f77cf-942bd
IPaddr    = 172.17.0.3
session object = ABC123
$ curl -b cookie.dat http://192.168.99.100:32180/Sample1/ViewSessionObject
Host Name = liberty-577c9f77cf-942bd
IPaddr    = 172.17.0.3
session object = ABC123
$ curl -b cookie.dat http://192.168.99.100:32180/Sample1/ViewSessionObject
Host Name = liberty-577c9f77cf-942bd
IPaddr    = 172.17.0.3
session object = ABC123
$ curl -b cookie.dat http://192.168.99.100:32180/Sample1/ViewSessionObject
Host Name = liberty-577c9f77cf-942bd
IPaddr    = 172.17.0.3
session object = ABC123
$ curl -b cookie.dat http://192.168.99.100:32180/Sample1/ViewSessionObject
Host Name = liberty-577c9f77cf-942bd
IPaddr    = 172.17.0.3
session object = ABC123
$ curl -b cookie.dat http://192.168.99.100:32180/Sample1/ViewSessionObject
Host Name = liberty-577c9f77cf-942bd
IPaddr    = 172.17.0.3
session object = ABC123
$ curl -b cookie.dat http://192.168.99.100:32180/Sample1/ViewSessionObject
Host Name = liberty-577c9f77cf-942bd
IPaddr    = 172.17.0.3
session object = ABC123
$ curl -b cookie.dat http://192.168.99.100:32180/Sample1/ViewSessionObject
Host Name = liberty-577c9f77cf-942bd
IPaddr    = 172.17.0.3
session object = ABC123
$ curl -b cookie.dat http://192.168.99.100:32180/Sample1/ViewSessionObject
Host Name = liberty-577c9f77cf-942bd
IPaddr    = 172.17.0.3
session object = ABC123
$ curl -b cookie.dat http://192.168.99.100:32180/Sample1/ViewSessionObject
Host Name = liberty-577c9f77cf-942bd
IPaddr    = 172.17.0.3
session object = ABC123
$ curl -b cookie.dat http://192.168.99.100:32180/Sample1/ViewSessionObject
Host Name = liberty-577c9f77cf-942bd
IPaddr    = 172.17.0.3
session object = ABC123
$ curl -b cookie.dat http://192.168.99.100:32180/Sample1/ViewSessionObject
Host Name = liberty-577c9f77cf-942bd
IPaddr    = 172.17.0.3
session object = ABC123
~~~



## ポッド数５のケース

ポッドのレプリカ数を増やして、増やして、セッション・オブジェクトの応答が、どの様に変化するか検証していきます。

~~~sample1.yml
...
spec:
  replicas: 5
...
~~~  

下記の結果の様に、最初に、セッション・オブジェクトをセットしたポッド以外からは、セッション・オブジェクトが応答できない。つまり、ポッド間でセッション・オブジェクトが共有されておらず、クッキーも参照していない事が判ると思います。

~~~
$ kubectl get po -o wide
NAME                       READY     STATUS    RESTARTS   AGE       IP            NODE
liberty-577c9f77cf-465zq   1/1       Running   0          1m        172.17.0.5    minikube
liberty-577c9f77cf-5fnmj   1/1       Running   0          1m        172.17.0.10   minikube
liberty-577c9f77cf-942bd   1/1       Running   0          3m        172.17.0.3    minikube
liberty-577c9f77cf-c457x   1/1       Running   0          1m        172.17.0.9    minikube
liberty-577c9f77cf-n4sb9   1/1       Running   0          1m        172.17.0.7    minikube
$ curl -b cookie.dat http://192.168.99.100:32180/Sample1/ViewSessionObject
Host Name = liberty-577c9f77cf-n4sb9
IPaddr    = 172.17.0.7
session object = (null)
$ curl -b cookie.dat http://192.168.99.100:32180/Sample1/ViewSessionObject
Host Name = liberty-577c9f77cf-942bd
IPaddr    = 172.17.0.3
session object = ABC123
$ curl -b cookie.dat http://192.168.99.100:32180/Sample1/ViewSessionObject
Host Name = liberty-577c9f77cf-465zq
IPaddr    = 172.17.0.5
session object = (null)
$ curl -b cookie.dat http://192.168.99.100:32180/Sample1/ViewSessionObject
Host Name = liberty-577c9f77cf-c457x
IPaddr    = 172.17.0.9
session object = (null)
$ curl -b cookie.dat http://192.168.99.100:32180/Sample1/ViewSessionObject
Host Name = liberty-577c9f77cf-c457x
IPaddr    = 172.17.0.9
session object = (null)
$ curl -b cookie.dat http://192.168.99.100:32180/Sample1/ViewSessionObject
Host Name = liberty-577c9f77cf-465zq
IPaddr    = 172.17.0.5
session object = (null)
$ curl -b cookie.dat http://192.168.99.100:32180/Sample1/ViewSessionObject
Host Name = liberty-577c9f77cf-n4sb9
IPaddr    = 172.17.0.7
session object = (null)
$ curl -b cookie.dat http://192.168.99.100:32180/Sample1/ViewSessionObject
Host Name = liberty-577c9f77cf-465zq
IPaddr    = 172.17.0.5
session object = (null)
$ curl -b cookie.dat http://192.168.99.100:32180/Sample1/ViewSessionObject
Host Name = liberty-577c9f77cf-n4sb9
IPaddr    = 172.17.0.7
session object = (null)
$ curl -b cookie.dat http://192.168.99.100:32180/Sample1/ViewSessionObject
Host Name = liberty-577c9f77cf-5fnmj
IPaddr    = 172.17.0.10
session object = (null)
$ curl -b cookie.dat http://192.168.99.100:32180/Sample1/ViewSessionObject
Host Name = liberty-577c9f77cf-942bd
IPaddr    = 172.17.0.3
session object = ABC123
$ curl -b cookie.dat http://192.168.99.100:32180/Sample1/ViewSessionObject
Host Name = liberty-577c9f77cf-n4sb9
IPaddr    = 172.17.0.7
session object = (null)
~~~


# まとめ

kube-proxyの実装は、iptablesであり、クッキーを参照してセッションを追跡して、同じアプリケーションサーバーへ振り分けるという機能が無い事が判ったと思います。 この事から、Kubernetesを利用するには、セッション・パーシステンスの共有または、Session Affinityを活かすためのkube-proxyのバイパスが必要ということになります。

続きは、その２で記載したいと思います。