はじめに
こんにちは!
本記事は「本気で学ぶKubernetes」シリーズの第20回です。このシリーズでは、Kubernetesの基礎から実践まで、段階的に学んでいきます。
このシリーズは、第1回から順に読むことで体系的に学べる構成にしています。
まだご覧になっていない方は、ぜひ最初からご覧ください!
今回はもう少し複雑な構成を想定して、レガシーなLAMPスタックのシステムをKubernetesにリフトしてみたいと思います。
この記事は人間がKubernetesの公式ドキュメントを読み漁りながら書いていますのでご安心ください!
TL;DR
忙しい方のために要点だけ図示しておきます!
GKEへのリフト計画について
多くの企業でまだオンプレミスのレガシーなLAMP構成やVMで稼動するシステム、Kubernetesクラスタを運用しているシステムなどがあります。
運用負荷軽減やシステム拡張性を求めてクラウド環境に移行する場合、GKE Standardも1つの選択肢ですね。
GKE Standardは既存のk8sのマニフェストを活用することでほぼそのまま動作させることができますし、ノードの種類も細かく指定できオンプレKubernetesと同じ感覚で扱えるうえ、クラウドネイティブな構成にシフトさせていくことも可能です。
概要
全体としては以下の順番で進めていきたいと思います。
- minikubeでLAMP構成を構築
- GKE Standardクラスタを作成
- kubectxでクラスタを切り替え
- minikubeで使ったマニフェストをGKEにそのまま適用
- 同じように動作することを確認
kubectx/kubensのインストール
まずクラスタとnamespace切り替えを便利にするkubectxとkubensをインストールします。
実際の運用では、複数のKubernetesクラスタを使い分けたり、defaultnamespaceではなくアプリケーションごとにnamespaceを分けるのが一般的です。
今回もminikubeとGKEの2つのクラスタを扱いますが、これらの効率よく使い分けられるツールがありますので活用していきたいと思います。
# kubectx/kubensをインストール
brew install kubectx
インストールが完了すると、kubectxとkubensコマンドが使えるようになります。
minikubeクラスタのセットアップ
ローカル環境でminikubeクラスタを起動します。
# minikubeクラスタを起動
minikube start
# クラスタ情報を確認
kubectl cluster-info
# Kubernetes control plane is running at https://127.0.0.1:xxxxx
# CoreDNS is running at https://127.0.0.1:xxxxx/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy
minikubeクラスタが無事に起動しましたので、先ほどインストールしたkubectxでクラスタを確認してみます。
kubectx
# minikube
現在はminikubeクラスタだけが表示されていることがわかりました。
namespaceの作成と切り替え
lamp-appというnamespaceを作成して、kubensで切り替えます。
# namespaceを作成
kubectl create namespace lamp-app
# namespace/lamp-app created
# namespaceを切り替え
kubens lamp-app
# Context "minikube" modified.
# Active namespace is "lamp-app".
# 現在のnamespaceを確認
kubens
# default
# kube-node-lease
# kube-public
# kube-system
# lamp-app(太字で表示される)
これ以降のkubectlコマンドは全てlamp-appnamespace内で実行されるようになります
MySQLのデプロイ
Secretの作成
MySQLのrootパスワードをSecretに格納します。
SecretはAPIキーやDBの接続情報など機密情報を保存するためのサービスでしたね。
以前の記事でも触れているので、忘れた方はぜひご確認ください!
【本気で学ぶKubernetes】SecretとVolumeで機密情報とデータを扱う
# MySQLのrootパスワードを格納
kubectl create secret generic mysql-secret \
--from-literal=password=mypassword123
# secret/mysql-secret created
StatefulSetマニフェストの作成
StatefulSetはデータベースやキューなどの状態を保持する必要があるサービスを動作させる際にKubernetesで利用される機能です。
こちらも以前の記事で触れていますので併せてご確認ください!
【本気で学ぶKubernetes】StatefulSet入門 - Deploymentとの違いを理解する
apiVersion: v1
kind: Service
metadata:
name: mysql
spec:
ports:
- port: 3306
clusterIP: None # Headless Service
selector:
app: mysql
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: mysql
spec:
serviceName: mysql
replicas: 1
selector:
matchLabels:
app: mysql
template:
metadata:
labels:
app: mysql
spec:
containers:
- name: mysql
image: mysql:8.0
env:
- name: MYSQL_ROOT_PASSWORD
valueFrom:
secretKeyRef:
name: mysql-secret
key: password
- name: MYSQL_DATABASE
value: testdb
ports:
- containerPort: 3306
name: mysql
volumeMounts:
- name: mysql-storage
mountPath: /var/lib/mysql
volumeClaimTemplates:
- metadata:
name: mysql-storage
spec:
accessModes: [ "ReadWriteOnce" ]
resources:
requests:
storage: 10Gi
過去の記事でも触れたようにvolumeClaimTemplatesを作成することによりPodごとにPersistentVolumeClaimを自動作成することができます。
マニフェストを適用してみます。
kubectl apply -f mysql-statefulset.yaml
# service/mysql created
# statefulset.apps/mysql created
StatefulSetとPodが作成されていることを確認しておきます。
kubectl get statefulset
# NAME READY AGE
# mysql 1/1 30s
kubectl get pods -l app=mysql
# NAME READY STATUS RESTARTS AGE
# mysql-0 1/1 Running 0 40s
WordPressのデプロイ
次にアプリケーション部分のWordPressをデプロイします。
WordPressは言わずもがなMySQLに接続して動作する代表的なPHPアプリケーションです。
以下のマニフェストを作成して適用します。
apiVersion: apps/v1
kind: Deployment
metadata:
name: wordpress
spec:
replicas: 2
selector:
matchLabels:
app: wordpress
template:
metadata:
labels:
app: wordpress
spec:
containers:
- name: wordpress
image: wordpress:latest
ports:
- containerPort: 80
env:
- name: WORDPRESS_DB_HOST
value: mysql
- name: WORDPRESS_DB_NAME
value: testdb
- name: WORDPRESS_DB_USER
value: root
- name: WORDPRESS_DB_PASSWORD
valueFrom:
secretKeyRef:
name: mysql-secret
key: password
---
apiVersion: v1
kind: Service
metadata:
name: wordpress
spec:
type: LoadBalancer
selector:
app: wordpress
ports:
- protocol: TCP
port: 80
targetPort: 80
上記では環境変数でMySQLの接続情報を渡すようになっています。
マニフェストを適用します。
kubectl apply -f wordpress-deployment.yaml
# deployment.apps/wordpress created
# service/wordpress created
DeploymentとServiceの状態を確認してみます。
kubectl get deployment
# NAME READY UP-TO-DATE AVAILABLE AGE
# wordpress 2/2 2 2 1m
kubectl get pods -l app=wordpress
# NAME READY STATUS RESTARTS AGE
# wordpress-xxxxxxxxxx-aaaaa 1/1 Running 0 1m
# wordpress-xxxxxxxxxx-bbbbb 1/1 Running 0 1m
kubectl get service wordpress
# NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
# wordpress LoadBalancer 10.xxx.xx.xx <pending> 80:xxxxx/TCP 1m
minikubeでの動作確認
minikubeでLoadBalancer Serviceにアクセスする方法としてminikube tunnelもありますが、今回はminikube serviceコマンドを使って確認していきます。
# minikube serviceでアクセス用のURLを取得
minikube service wordpress -n lamp-app --url
# http://127.0.0.1:xxxxx
このコマンドは、LoadBalancer Serviceに対してポートフォワーディングを自動的に設定し、アクセス可能なURLを表示してくれます。
表示されたURLにブラウザでアクセスしてみます。
Worpressの初期画面が表示されました!
GKE Standardクラスタの作成
ここからはminikubeで動作確認できたマニフェストを、そのままGKE Standardにも適用してみます。
まず、GKE APIを有効化します。
# GKE APIを有効化
gcloud services enable container.googleapis.com
次に、GKE Standardクラスタを作成します。
# Standardクラスタを作成(東京ゾーン)
gcloud container clusters create lamp-cluster \
--zone=asia-northeast1-a \
--machine-type=e2-medium \
--num-nodes=2 \
--disk-size=20
GKE Standardではcreateコマンドを使い、--machine-typeや--num-nodesを明示的に指定する必要があります。
今回はe2-mediumインスタンスを2台用意しました。
クラスタが作成されたら、kubectlでGKEに接続できるようにkubeconfigを取得します。(クラスタの作成には5〜10分ほどかかります)
# kubeconfigを取得
gcloud container clusters get-credentials lamp-cluster \
--zone=asia-northeast1-a
# Fetching cluster endpoint and auth data.
# kubeconfig entry generated for lamp-cluster.
kubectxでクラスタを切り替え
kubectxを使ってクラスタを確認してみます。
# クラスタ一覧を確認
kubectx
# gke_PROJECT-ID_asia-northeast1-a_lamp-cluster
# minikube
minikubeとGKE両方のクラスタが表示されました!
現在のクラスタはGKEになっているはずですが、念の為確認してみます。
# 現在のクラスタを確認
kubectl config current-context
# gke_PROJECT-ID_asia-northeast1-a_lamp-cluster
# ノードを確認
kubectl get nodes
# NAME STATUS ROLES AGE VERSION
# gke-lamp-cluster-default-pool-xxxxx-xxxx Ready <none> 2m v1.28.x-gke.xxx
# gke-lamp-cluster-default-pool-xxxxx-yyyy Ready <none> 2m v1.28.x-gke.xxx
GKEクラスタに接続できていることが確認できました。
GKEコンソールでもクラスタの詳細を確認できます。Standardモードで作成されており、ノード数や構成が確認できます。
GKEにnamespaceを作成
GKEにも同じようにnamespaceを作成します。
# namespaceを作成
kubectl create namespace lamp-app
# namespace/lamp-app created
# namespaceを切り替え
kubens lamp-app
# Context "gke_PROJECT-ID_asia-northeast1-a_lamp-cluster" modified.
# Active namespace is "lamp-app".
GKEに同じマニフェストを適用
minikubeで使ったマニフェストをGKEにそのまま適用していきます。
Secretの作成
kubectl create secret generic mysql-secret \
--from-literal=password=mypassword123
# secret/mysql-secret created
マニフェストの適用
# MySQL StatefulSetを適用
kubectl apply -f mysql-statefulset.yaml
# service/mysql created
# statefulset.apps/mysql created
# WordPress Deploymentを適用
kubectl apply -f wordpress-deployment.yaml
# deployment.apps/wordpress created
# service/wordpress created
minikubeで使ったマニフェストを何も変更せずそのまま適用しただけです!
リソースの確認
GKEコンソールで確認してみます。Workloadsの画面では、WordPressのDeploymentとMySQLのStatefulSetが正常に稼働していることが確認できます。
ConfigMapsとSecretsの画面では、作成したmysql-secretが確認できます。
LoadBalancer Serviceの確認
外部公開用のロードバランサーが作成されているので、コマンドで確認します。
kubectl get service wordpress
# NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
# wordpress LoadBalancer 34.118.xxx.xx <pending> 80:xxxxx/TCP 1m
kubectl get service wordpress -w
# NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
# wordpress LoadBalancer 34.118.xxx.xx 34.xxx.xxx.xxx 80:xxxxx/TCP 2m
外部IPが割り当てられていることが確認できました。
GKEコンソールのServicesの画面でも、wordpress ServiceがExternal Load Balancerとして作成され、外部IPが割り当てられていることが確認できます。
GKEでの動作確認
それでは、GKEでも同じように動作するか確認してみます。
# EXTERNAL-IPを環境変数に格納
EXTERNAL_IP=$(kubectl get service wordpress -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
echo "http://$EXTERNAL_IP"
# http://34.xxx.xxx.xxx
ブラウザでhttp://34.xxx.xxx.xxxにアクセスすると、WordPressのセットアップ画面が表示されます!
GKEでも同じように動作することが確認できました!
今回はデータを用意していないので構成をそのまま移行しただけですが、実際はデータ移行やオンプレ特有の設定情報などがあるかと思いますので各自設定調整してください。
クリーンアップ
GKEのクリーンアップ
# GKEに切り替え
kubectx gke_PROJECT-ID_asia-northeast1-a_lamp-cluster
namespaceを使っている場合はnamespace自体を削除すれば中のリソースも全て削除されます。
LoadBalancer Serviceは外部のGoogle Cloud Load Balancerを作成するため、念の為先に個別削除しておきます。
# LoadBalancer Serviceを先に削除(外部リソース解放のため)
kubectl delete service wordpress
# service "wordpress" deleted from lamp-app namespace
# namespaceごと削除
kubectl delete namespace lamp-app
# namespace "lamp-app" deleted
クラスタ自体を削除します。
gcloud container clusters delete lamp-cluster \
--zone=asia-northeast1-a
# The following clusters will be deleted.
# - [lamp-cluster] in [asia-northeast1-a]
# Do you want to continue (Y/n)? Y
# Deleting cluster lamp-cluster...done.
# Deleted [https://container.googleapis.com/v1/projects/<project>/zones/asia-northeast1-a/clusters/lamp-cluster].
削除忘れのためコンソールでも確認しておいてください!
minikubeのクリーンアップ
minikubeクラスタをクリーンアップしておきます
# minikubeに切り替え
kubectx minikube
# namespaceごと削除
kubectl delete namespace lamp-app
# namespace "lamp-app" deleted
まとめと次回予告
minikubeとGKE StandardでLAMP構成(MySQL + Apache + PHP)を構築してみました。
minikube上で作成した際と全く同じマニフェストをそのまま適用して、両方の環境で同じように動作することを確認できました。
今回はクラスタやnamespaceの切り替えが行えるkubectxとkubensをツールを使いましたが、これは実際のKubernetesの運用でもほぼほぼ必須のツールになってくると思いますのでぜひ押さえておきたいですね!
次回は、Kubernetesのトラブルシューティングについて学んでいきます。kubectl logs、kubectl describe、kubectl eventsを使ったデバッグ方法や、よくあるエラーパターンと対処法を実践していければと思います!
それでは、また次回!






