執筆中。【連載】Kubernates入門・GKEデプロイと発展的利用 第7回 ~ GKE上にTODOアプリケーションを構築する ~
はじめに
この連載ではコンテナオーケストレーションツールである、 Kubernatesの使い方を学びます。
今回はGoogle Kubernetes Engine上で実際にTODOアプリケーションを動作させてみましょう。
サンプルコード
こちらに順次アップしていきますー。
連載記事一覧
構成
こんな感じ。MySQL、API、Webアプケーションの順でデプロイしていき、最終的にIngressで公開します。

MySQLをMaster Slave構成でGKE上に構築する
Dockerで永続化データを扱うコンテナを実行するためには、データボリュームが利用されます。
Kubernetesでは、以下のKubernetesリソースで、外部ストレージをボリュームとして利用できます。
- PersistentVolume
- PersistentVolumeClaim
- StorageClass
- StatefulSet
ここではGKEでのMySQL構築を通して、永続化データを扱うPodの実行について解説します。
PersistentVolumeとPersistentVolumeClaim
PersistentVolumeはストレージの実体です。GCPではGCEPersistentDiskが該当します。
対してPersistentVolumeClaimはストレージを論理的に抽象化したリソースで、PersistentVolumeに対して必要な容量を動的に確保できます。
PersistentVolumeClaimのマニフェストファイルのイメージは次のようなものです。
PodからはPersistentVolumeClaimを直接マウントできます。
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pvc-example
spec:
accessModes:
- ReadWriteOnce
storageClassName: ssd
resources:
requests:
storage: 4Gi
accessModesはPodからストレージへのマウントポリシーのことです。ReadWriteOnceであればどこか1つのノードからのR/Wマウントのみが許可されます。
storageClassNameは後述するStorageClassリソースの名前のことで、利用するストレージの種類を定義します。
ボリュームが必要な容量を.resources.requests.storageで指定できます。
StorageClass
StorageClassはPersistentVolumeが確保するストレージの種類を定義できるリソースです。
直前のPersistentVolumeClaimのstorageClassNameで指定していた値の実体です。
GCPのストレージには「標準」と「SSD」が存在します。ここではSSDを利用してストレージを作成できるようにしましょう。
次のようなstorage-class-ssd.yamlというマニフェストファイルを作成します。
# storage-class-ssd.yaml
kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
name: ssd
annotations:
storageclass.kubernetes.io/is-default-class: "false"
labels:
kubernetes.io/cluster-service: "true"
provisioner: kubernetes.io/gce-pd
parameters:
type: pd-ssd
ssdという名前のSSDに対応したStorageClassを定義しています。
provisionerはGCPの永続ストレージであるGCEPersistentDiskに対応したVolumePluginであるgce-pdを指定します。
このプラグインのパラメータのtype属性にSSDに対応したpd-ssdを指定します。
$ kubectl apply -f storage-class-ssd.yaml storageclass.stroage.k8s.io "ssd" created
StatefulSet
Deployment : 定義されたPod仕様に基づきPodを作成するリソース。
- 一意性を持つPodや永続化データを持つ必要のないステートレスなアプリケーションをデプロイするのに向いている。
StatefulSet : データストアのように継続的にデータを永続化するステートフルなアプリケーションの管理に向いたリソース。
- StatefulSetではpod-0、pod-1、pod-2のような連番で一意な識別子でPodを作成。StatefulSetが作るPodの識別子は、Podが再作成されても保たれる。また、スケーリングも識別子の連番が維持されるように行われる。
ここではStatefulSetを使用してMySQLのMasterとSlaveのPodを作成していきます。
Podが安定した識別子を持つことで、Podが再作成されてもストレージを継続して同じPodに紐づけることができます。 そのため、Podが持つデータを再作成前と同じ状態で復元できます。
まず、MasterのStatefulSetを次のmysql-master.yamlというマニフェストファイルに定義して作成します
Masterの設定
# mysql-master.yaml
apiVersion: v1
kind: Service
metadata:
name: mysql-master
labels:
app: mysql-master
spec:
ports:
- port: 3306
name: mysql
clusterIP: None
selector:
app: mysql-master
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: mysql-master
labels:
app: mysql-master
spec:
serviceName: "mysql-master"
selector:
matchLabels:
app: mysql-master
replicas: 1
template:
metadata:
labels:
app: mysql-master
spec:
terminationGracePeriodSeconds: 60
containers:
- name: mysql
image: gihyodocker/tododb:latest
imagePullPolicy: Always
args:
- "--ignore-db-dir=lost+found"
ports:
- containerPort: 3306
env:
- name: MYSQL_ROOT_PASSWORD
value: "gihyo"
- name: MYSQL_DATABASE
value: "tododb"
- name: MYSQL_USER
value: "gihyo"
- name: MYSQL_PASSWORD
value: "gihyo"
- name: MYSQL_MASTER
value: "true"
volumeMounts:
- name: mysql-data
mountPath: /var/lib/mysql
volumeClaimTemplates:
- metadata:
name: mysql-data
spec:
accessModes: [ "ReadWriteOnce" ]
storageClassName: ssd
resources:
requests:
storage: 4Gi
反映します。
$ kubectl apply -f mysql-master.yaml service "mysql-master" created statefulset.apps "mysql-master" created
Slaveの設定
続いてSlaveのStatefulSetを次のmysql-slave.yamlというマニフェストファイルに定義して作成します。
# mysql-slave.yaml
apiVersion: v1
kind: Service
metadata:
name: mysql-slave
labels:
app: mysql-slave
spec:
ports:
- port: 3306
name: mysql
clusterIP: None
selector:
app: mysql-slave
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: mysql-slave
labels:
app: mysql-slave
spec:
serviceName: "mysql-slave"
selector:
matchLabels:
app: mysql-slave
replicas: 2
updateStrategy:
type: OnDelete
template:
metadata:
labels:
app: mysql-slave
spec:
terminationGracePeriodSeconds: 60
containers:
- name: mysql
image: gihyodocker/tododb:latest
imagePullPolicy: Always
args:
- "--ignore-db-dir=lost+found"
ports:
- containerPort: 3306
env:
- name: MYSQL_MASTER_HOST
value: "mysql-master"
- name: MYSQL_ROOT_PASSWORD
value: "gihyo"
- name: MYSQL_DATABASE
value: "tododb"
- name: MYSQL_USER
value: "gihyo"
- name: MYSQL_PASSWORD
value: "gihyo"
- name: MYSQL_REPL_USER
value: "repl"
- name: MYSQL_REPL_PASSWORD
value: "gihyo"
volumeMounts:
- name: mysql-data
mountPath: /var/lib/mysql
volumeClaimTemplates:
- metadata:
name: mysql-data
spec:
accessModes: [ "ReadWriteOnce" ]
storageClassName: ssd
resources:
requests:
storage: 4Gi
$ kubectl apply -f mysql-slave.yaml service "mysql-slave" created statefulset.apps "mysql-slave" created
SlaveもMasterと要領は同じです。レプリカ数と名前、環境変数だけが異なります。SlaveはMasterの場所を知る必要があるため、環境変数MYSQL_MASTER_HOSTでMasterのService名であるmysql-masterを指定しています。
実行内容の確認
StatefulSetで作成されたMasterのPodにinit-data.shで初期データ登録を実行し、SlaveのPodに反映されているかを確認します。
$ kubectl get pod NAME READY STATUS RESTARTS AGE mysql-master-0 1/1 Running 0 48m mysql-slave-0 1/1 Running 0 5m mysql-slave-1 1/1 Running 0 5m $ kubectl exec -it mysql-master-0 init-data.sh $ kubectl exec -it mysql-slave-0 bash root@mysql-slave-0:/# mysql -u root -pgihyo tododb -e "SHOW TABLES;" mysql: [Warning] Using a password on the command line interface can be insecure. +------------------+ | Tables_in_tododb | +------------------+ | todo | +------------------+