Dockerに統合されたkubernetesでローカル開発用のMySQLを運用する

DockerCon EU 2017でDockerにKubernetesが統合されるとアナウンスされていましたが、早くもDocker CE for MacのEdgeリリースでk8sがローカル環境で使えるようになってました。これまでローカルのk8s環境はminikubeをインストールしていたのですが、この機会にDockerで完結させるように移行してみました。

Docker上のkubernetesセットアップ

まず、既にMac上にHomebrewでkubectlを入れている場合は削除しておきます(Dockerであらためてkubectlがインストールされるので)。

$ brew uninstall kubectl

Kubernetesが統合されたDocker CE for Macをダウンロードし(執筆時点ではEdgeリリースのみが対象)、インストールすると設定画面に「Kubernetes」メニューが出来ているので、「Enable Kubernetes」にチェックを入れるとk8sがインストールされます。

DockerのKubernetesセットアップ画面

これでkubectlコマンドが使えるようになります。私の場合はminikubeも入れたままにしているので、以下のようにcontextをDocker側に切り替えます。

$ kubectl config use-context docker-for-desktop

nodesを確認してみると、docker-for-desktopという名前でノードが起動していました。

$ kubectl get nodes
NAME STATUS ROLES AGE VERSION
docker-for-desktop Ready master 11m v1.8.2

dashboadは現時点では手動でインストールする必要があるので、以下のようにdashboad用のPodを作成します。

$ kubectl create -f https://raw.githubusercontent.com/kubernetes/dashboard/master/src/deploy/recommended/kubernetes-dashboard.yaml

ブラウザからアクセスできるようにServiceのtypeをClusterIPからNodePortに変更します。あわせて外部アクセス用ポート番号も確認しておきます。

$ kubectl -n kube-system edit service kubernetes-dashboard
apiVersion: v1
kind: Service
.
.
.
spec:
clusterIP: 10.108.208.167
externalTrafficPolicy: Cluster
ports:
- nodePort: 32744 # 外部からのアクセス用Port
port: 443
protocol: TCP
targetPort: 8443
selector:
k8s-app: kubernetes-dashboard
sessionAffinity: None
type: NodePort # typeをNodePortに変更
status:
loadBalancer: {}

この設定例の場合は、ブラウザからhttps://localhost:32744でアクセスできます。

kubenetesのダッシュボード

MySQLのコンテナーを導入

これまでローカル開発用のMySQLはMAMPを使って運用していました。ローカルのMySQLでは複数のデータベースを構築することが多いので、Dockerで運用するにしても1つのDBインスタンスで複数のアプリから参照されるような構成にしたいと思っていました。そのため、以下のような構築方針としました。

  • MySQLのコンテナーは単独で起動する
  • データベースは別アプリ向けに複数作成する
  • データは永続化し、ローカルのファイルシステムから参照できるようにする
  • MySQLWorkbench等からアクセスできるようにホストOSへポートを公開する

kubenetesでMySQLを運用するには、ボリュームを永続化するためPersistentVolumes(以下PV)を作成します。ホストとなるMacのファイルシステムで参照できるように以下のような構成でPVを作成します。

local-volumes.yml

apiVersion: v1
kind: PersistentVolume
metadata:
name: local-pv-1
labels:
type: local
spec:
storageClassName: sc-db
capacity:
storage: 10Gi
accessModes:
- ReadWriteOnce
hostPath:
path: "/Users/miyake/k8s-pv/pv-1" # ローカルPCの適当なパスを指定

以下のコマンドでPVを作成します。

$ kubectl create -f local-volumes.yml

MySQLのDeploymentに設定するボリュームには直接PVを紐付けず、PersistentVolumeClaims(以下PVC)を作成してPVCを経由するようにさせた方が良いようです。なお、PVCとPVはstorageClassNameの名前でバインドさせます。

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: mysql-pv-claim
labels:
app: dev
spec:
storageClassName: sc-db # この設定でPVとバインドされる
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
$ kubectl create -f mysql-pv-claim.yml

MySQLのコンテナーを作成する前に、MySQLパスワードSecretをkubernetes上にセットしておきます。そうすることで、MySQL自体のマニフェストファイルにはパスワードを記述しなくて良くなり、環境毎にもパスワードを変更できるようになります。

$ kubectl create secret generic mysql-pass --from-literal=password={YOUR_PASSWORD}

MySQLのDeploymentServiceを作成するマニフェストは以下のように作成しました。Deploymentでは、mysqlの公式イメージをバージョン指定タグを使って取得しています。Serviceの設定では、NodePortを利用してポートをホストマシンに公開するようにしています。

apiVersion: apps/v1beta2
kind: Deployment
metadata:
name: mysql
labels:
app: dev
spec:
selector:
matchLabels:
app: dev
tier: db
strategy:
type: Recreate
template:
metadata:
labels:
app: dev
tier: db
spec:
containers:
- image: mysql:5.7
name: mysql
env:
- name: MYSQL_ROOT_PASSWORD
valueFrom:
secretKeyRef:
name: mysql-pass
key: password
ports:
- containerPort: 3306
name: mysql
volumeMounts:
- name: mysql-persistent-storage
mountPath: /var/lib/mysql
volumes:
- name: mysql-persistent-storage
persistentVolumeClaim:
claimName: mysql-pv-claim
---
apiVersion: v1
kind: Service
metadata:
name: mysql
labels:
app: dev
spec:
ports:
- port: 3306
selector:
app: dev
tier: db
type: NodePort

以下を実行して、数分待つとMuySQLのPodが起動しているはずです。

$ kubectl create -f mysql.yml

ダッシュボードのPod一覧

Serviceの内容を確認してホストマシンからMySQLにアクセスするためのPortを確認します。

$ kubectl get svc mysql
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
mysql NodePort 10.107.115.159 <none> 3306:30319/TCP 3m

上記例では外部向けのPortが30319であることがわかるので、MySQLWorkbenchでは以下のように設定すると接続できるはずです。

MySQL Workbench

これで、今後はDocker for Macを起動すれば、自動的にkubernetes上のMySQLがいつでも使える状態の環境になりました。ちなみに個人的にはクラウド上ではPaaSのMySQLしか使わない方針なので、ここで紹介した方法はあくまでもローカル開発用に特化した構築方法です。運用環境用のMySQLをkubernetesで構築するには他にも考慮事項が出てくると思いますのでご注意下さい。