minikube + helmでローカル環境を構築する


plasmaの動作確認のためにローカル環境を構築する機会がありminikube + helmで構築してみようと始めたのがエントリのモチベーション。

plasmaはServer Push型のミドルウェアでFRESH!で使われている。ポーリング撲滅を掲げgRPC/SSEを用いて省コネクションでイベントのSubscribeを実現している。
plasmaの動作確認にはplasmaredisのミドルウェアとイベントをSubscribeするアプリケーションが必要(kotlin + SpringBootで書いた)。これらをコンテナ化してローカル環境で確認していきたい。

これまでのローカルのコンテナ実行環境は docker-composeでやっていたけど、Kubernetesの初学も兼ねてminikubeでやってみる。helmを使いコンテナ全体をパッケージングしていく。

minikubeでkubernetes環境を起動する

1
2
$  minikube start
$  eval $(minikube docker-env)

必要なDockerイメージをビルドまたはプルした状態がこちら。

1
2
3
4
5
6
$ docker images | grep -v "gcr.io"
REPOSITORY                                             TAG                 IMAGE ID            CREATED             SIZE
soushin/plasmacli                                      latest              49ca95df3dad        2 days ago          942MB
redis                                                  latest              861cc310cd91        4 days ago          107MB
openfresh/plasma                                       latest              7ff567596426        6 weeks ago         16.6MB
java                                                   openjdk-8           d23bdf5b1b1b        12 months ago       643MB

gcr.io/*のイメージはリストから排除しています

helmを使いコンテナ全体をパッケージングをする

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
$ helm create plasmacli
$ tree ./plasmacli
./plasmacli
├── Chart.yaml
├── charts
├── templates
│   ├── NOTES.txt
│   ├── _helpers.tpl
│   ├── deployment.yaml
│   ├── ingress.yaml
│   └── service.yaml
└── values.yaml

helm create {packageName}で雛形を生成する。


このエントリで修正したyamlは values.yamltemplates/deployment.yamlの2つ。
templates/deployment.yamlにコンテナとコンテナ内の環境変数、Internal/Externalのポートを定義する。値は values.yamlから参照する。

templates/deployment.yamlとvalues.yaml
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
# `plasmacli`コンテナ定義を抜粋

      containers:
        - name: plasmacli
          image: "{{ .Values.plasmaCli.image.repository }}:{{ .Values.plasmaCli.image.tag }}"
          imagePullPolicy: {{ .Values.plasmaCli.image.pullPolicy }}
          ports:
            - name: plasmacli
              containerPort: {{ .Values.service.internalPort }}
          env:
          - name: PLASMA_CLI_PORT
            value: {{ .Values.service.internalPort | quote }}
          - name: PLASMA_HOST
            value: {{ .Values.plasmaCli.env.plasmaHost | quote }}
          - name: PLASMA_PORT
            value: {{ .Values.plasmaCli.env.plasmaPort | quote }}

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
# 関連する値を `values.yaml`から抜粋

plasmaCli:
  image:
    repository: soushin/plasmacli
    tag: latest
    pullPolicy: IfNotPresent
  env:
    plasmaHost: localhost
    plasmaPort: 50051

service:
  type: NodePort
  port: 80
  internalPort: 8080

パッケージングしたchartをインストールする

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
$ helm package plasmacli
$ helm install --name plasmacli local/plasmacli
NAME:   plasmacli
LAST DEPLOYED: Sat Jan 27 11:30:23 2018
NAMESPACE: default
STATUS: DEPLOYED

RESOURCES:
==> v1/Service
NAME       TYPE      CLUSTER-IP    EXTERNAL-IP  PORT(S)       AGE
plasmacli  NodePort  10.98.66.149  <none>       80:31118/TCP  0s

==> v1beta2/Deployment
NAME       DESIRED  CURRENT  UP-TO-DATE  AVAILABLE  AGE
plasmacli  1        0        0           0          0s

podを確認してみると無事起動している。

1
2
3
$ kubectl get pods -n default
NAME                        READY     STATUS    RESTARTS   AGE
plasmacli-957c79484-d4dkh   3/3       Running   0          2d

クラスタの外からアクセスする

クラスタの外からのアクセスにはserviceをNodePort化したのでポート番号が払い出されている。
アクセスURLは次のように確認できる。

1
2
$ minikube service plasmacli --url
http://192.168.64.12:31118

このURLのバックエンドにはイベントをSubscribeするアプリケーションが設定されているので次のように /health_check が叩けるようになっている。

1
2
$ curl http://192.168.64.12:31118/health_check
true

plasmaの動作確認をしてみよう

イベントをSubscribeするアプリケーションではイベント名:my-eventをSubscribeするようにしている。

redisからchannelへPublishする。

1
2
PUBLISH plasma '{"meta": { "type": "my-event"}, "data": "HELLO"}'
PUBLISH plasma '{"meta": { "type": "my-event"}, "data": "My Plasma"}'

イベントをSubscribeするアプリケーションのログの最後にPayloadデータ(HELLO, My Plasmaの文字列)が出力できた。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
$ kubectl logs -f  plasmacli-957c79484-d4dkh -c plasmacli

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::             (v2.0.0.M7)

[INFO ][2018-01-27 11:30:26.380] Starting Application.Companion on plasmacli-957c79484-d4dkh with PID 5 (/usr/local/plasma-cli/lib/plasma-cli.jar started by root in /)
[INFO ][2018-01-27 11:30:26.420] No active profile set, falling back to default profiles: default
[INFO ][2018-01-27 11:30:26.582] Refreshing org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext@445b84c0: startup date [Sat Jan 27 11:30:26 GMT+09:00 2018]; root of context hierarchy
[INFO ][2018-01-27 11:30:29.531] Mapped (Accept: [application/json] && /health_check) => {
 (GET && /) -> org.springframework.web.reactive.function.server.RouterFunctionDsl$GET$1@709ba3fb
}
[INFO ][2018-01-27 11:30:29.564] Mapped URL path [/webjars/**] onto handler of type [class org.springframework.web.reactive.resource.ResourceWebHandler]
[INFO ][2018-01-27 11:30:29.565] Mapped URL path [/**] onto handler of type [class org.springframework.web.reactive.resource.ResourceWebHandler]
[INFO ][2018-01-27 11:30:29.661] Looking for @ControllerAdvice: org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext@445b84c0: startup date [Sat Jan 27 11:30:26 GMT+09:00 2018]; root of context hierarchy
[INFO ][2018-01-27 11:30:31.598] Registering beans for JMX exposure on startup
[INFO ][2018-01-27 11:30:31.745] Started HttpServer on /0.0.0.0:8080
[INFO ][2018-01-27 11:30:31.761] Netty started on port(s): 8080
[INFO ][2018-01-27 11:30:31.773] Started Application.Companion in 6.292 seconds (JVM running for 7.875)

[INFO ][2018-01-27 11:46:06.378] stream observe: onNext={"HELLO"}
[INFO ][2018-01-27 11:48:48.386] stream observe: onNext={"My Plasma"}

コードはgithubにあります

コードはgithubに置いてますので合わせて参照ください。

まとめ