在宅環境可視化システムをGKEにリプレイスする

kosa3
10 min readApr 25, 2020

--

# はじめに

前記事の「在宅環境をKibanaで可視化する」をローカルで動かしていて徐々に肌感で湿度と温度がわかってくるようになってきました。

ただやはりローカルで動かしているためPCを常時起動させることはやはり気に掛かるためクラウドに移行をしました。

今回はGKEを利用して以下のような構成で構築しました。

GKEを選択したのはKubernetesを学んでみたかったことと初学者でも比較的簡単に構築できそうだと感じGKEにしました。(無料クレジットが残っていたのも大きい)

# クラスター作成

クラスターのノードは2つ作りました。(ESからCPUメモリが足りないと言われたので。。)

$ gcloud container clusters create iot-home --num-nodes=2

# ワーカーノードの作成

次にクラスタに配置するワーカーノードを作成します。

前記事のシステム構成から各パーツのマニフェストファイルを作ります。

まずはPublisher用のワーカーノードを作成していきます。
Publisherは10分間に一度ジョブとして動けば良いのでCronJobのAPIを利用してマニフェストを書きます。

環境変数のエンドポイントは後ほど作成するService名を指定します。
NatureAPIのアクセストークンはSecretKeyとして指定します。

コンテナイメージはpublisherのDockerfileをGCRに保管しています。
DockerHubでも良いですが今回はプライベートなGCRに保管します。

apiVersion: batch/v1beta1
kind: CronJob
metadata:
name: pub
spec:
concurrencyPolicy: Replace
schedule: "*/10 * * * *"
jobTemplate:
spec:
template:
spec:
containers:
- env:
- name: RABBITMQ_ENDPOINT
value: broker-service
- name: NATURE_ACCESS_TOKEN
valueFrom:
secretKeyRef:
name: nature-key
key: nature-token
name: pub
image: gcr.io/iot-home-274911/pub:v1
restartPolicy: OnFailure

次にBrokerのRabbitMQのワーカーノードを作成します。
マニフェストの種類はPodでも良いですがreplica数も調整できてローリングアップデートができるDeploymentを利用してPodを作成していきます。

また、PublisherやSubscriberとのPod同士の通信を可能にするためにBrokerにServiceを追加します。Serviceで通信することでPodの変更時(デプロイ)にもよしなにIPを振り分けてくれるためServiceを利用します。

また、RabbitMQの管理画面などブラウザ側でアクセスする環境を用意する場合はServiceあるいはIngressを利用します。

今回は特にL7層まで利用しないのでServiceのLBでアクセスを繋いでいます。

apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: broker
name: broker
spec:
replicas: 1
selector:
matchLabels:
app: broker
template:
metadata:
labels:
app: broker
spec:
containers:
- image: rabbitmq:3.8-management
name: broker

---
apiVersion: v1
kind: Service
metadata:
name: broker-service
spec:
selector:
app: broker
ports:
- protocol: TCP
port: 5672
targetPort: 5672
---
apiVersion: v1
kind: Service
metadata:
name: broker-management-service
spec:
selector:
app: broker
ports:
- protocol: TCP
port: 15672
targetPort: 15672
type: LoadBalancer

次にSubscriberを作成します。
これによってBrokerにたまったデータをElasticsearchに転送します。

apiVersion: apps/v1
kind: Deployment
metadata:
name: sub
labels:
app: sub
spec:
replicas: 1
selector:
matchLabels:
app: sub
template:
metadata:
labels:
app: sub
spec:
containers:
- env:
- name: ES_ENDPOINT
value: http://es-service:9200
- name: RABBITMQ_ENDPOINT
value: broker-service
image: gcr.io/iot-home-274911/sub:v1
name: sub

次にElasticsearchとKibanaを作成します。
Elasticsearchのデータストアは永続的に保管したいのでStatefulを使ってPodを作成していきます。
Statefulを利用してクラウドストレージにデータを保管しています。

KibanaにElasticsearchのホスト名を指定する時にService名だけだと`no elasticsearch node available` でうまく接続ができませんでしたがhttp or httpsを追記してあげることで接続の確認ができました。

apiVersion: apps/v1
kind: StatefulSet
metadata:
name: es
spec:
selector:
matchLabels:
app: es
serviceName: "es"
replicas: 1
template:
metadata:
labels:
app: es
spec:
containers:
- name: es
image: elasticsearch:7.6.2
env:
- name: discovery.type
value: single-node
- name: ES_JAVA_OPTS
value: -Xms512m -Xmx512m
- name: bootstrap.memory_lock
value: "true"
ports:
- containerPort: 9200
volumeMounts:
- name: es-data
mountPath: /es-data
volumeClaimTemplates:
- metadata:
name: es-data
spec:
accessModes: [ "ReadWriteOnce" ]
resources:
requests:
storage: 1Gi
---
apiVersion: v1
kind: Service
metadata:
name: es-service
spec:
selector:
app: es
ports:
- protocol: TCP
port: 9200
targetPort: 9200
type: LoadBalancer

---
apiVersion: apps/v1
kind: Deployment
metadata:
name: kibana
labels:
app: kibana
spec:
replicas: 1
selector:
matchLabels:
app: kibana
template:
metadata:
labels:
app: kibana
spec:
containers:
- name: kibana
image: kibana:7.6.2
resources:
limits:
cpu: 1000m
requests:
cpu: 100m
env:
- name: ELASTICSEARCH_HOSTS
value: http://es-service:9200

---
apiVersion: v1
kind: Service
metadata:
name: kibana-service
labels:
app: kibana
spec:
selector:
app: kibana
ports:
- port: 5601
protocol: TCP
targetPort: 5601
type: LoadBalancer

最後にこれらを記載したファイルをGKEに適用していきます。
ファイルは分けても良いですが今回は一緒にしています。

$ kubectl apply -f iot-home.yaml

実行できたら以下のようにPodとサービスのステータスがグリーンになっていれば成功です。

node
service

何かしらPodにエラーが発生した場合はkubectl describe pod名 や kubectl logs イメージ名 でログを確認したりGCPのLoggingを利用して問題を見つけていきます。

以下のように起動したElasticsearchにデータが投入されていることが確認できたらOKです。

また、外部からのアクセス制限などはLB側でのIP制限やアプリ単位での認証、Private VPCなど準備する必要があります。

まとめ

今回は勉強がてらマニフェストファイルを自作していきました、最低限のマニフェストでリプレイスしましたがKubernetesの良さを発揮しておらずクラスター内のノード管理やオートスケールなどまだまだ奥が深い技術なので引き続き学んでいきます。

またdocker-compose.ymlが用意されているプロジェクトではKubernetesのマニフェストを吐き出すkomposeなどのツールがあるためそれを使ってみても良いかもしれません。

--

--