Minikubeで開発環境を作成する
前提条件
私の環境はWindows10です。
ツールのダウンロード
minikubeを以下からインストールしてください:
https://minikube.sigs.k8s.io/docs/start/
minikubeにはvirtualboxドライバーを使います。
以下からvirtualboxをインストールしてください:
http://virtualbox.org/wiki/Downloads
Gitも使用します。以下からGitをインストールしてください:
https://git-scm.com/downloads
skaffoldも以下からインストールしてください:
https://skaffold.dev/docs/install/
そしてkubectlも以下からインストールします:
https://kubernetes.io/docs/tasks/tools/install-kubectl-windows/
(chocoやscoopを使うと簡単にインストールできます)
インストール確認
それぞれのツールをインストール後、PowerShellでminikubeにアクセスできるか確認しましょう。
PowerShellを開いて次のコマンドを実行:
minikube version
出力例:
minikube version: v1.35.0
commit: dd5d320e41b5451cdf3c01891bc4e13d189586ed-dirty
次にGitのバージョン確認:
git -v
出力例:
git version 2.47.1.windows.2
テストプロジェクトの作成
次のようにディレクトリを作成:
cd Documents
mkdir projects
cd projects
mkdir test-project
cd test-project
このプロジェクトはminikubeのクラスターで動かします。
Minikubeクラスターの起動
用語解説
-
コンテナとは?
アプリケーションとその依存関係をまとめた軽量な分離環境です。様々な環境間で一貫性を保てます。 -
ポッドとは?
Kubernetesにおける最小のデプロイ単位で、1つ以上のコンテナを内包します。 -
クラスターとは?
複数のワーカーノードがポッドを実行する、Kubernetesの最上位構成です。
クラスター起動
以下のコマンドで起動:
minikube start --driver=virtualbox
※Dockerドライバーを使う場合は次のようにマウントするフォルダを指定しつつ起動できます:
minikube start --mount --mount-string="$HOME:/src" --driver=docker
ただし、virtualboxではこれは使用できません(でもDocker Desktopと違って無料です)
UbuntuなどのLinux系はDockerを無料で使えるので試してみてください。仕組み上仕方ないのですが、Dockerは爆速なのに対してvirtualboxは遅いのでイライラします。
Windows/MacはDockerを使うならDocker desktopになっちゃうので、とりあえずvirtualboxでいきます。
Kubernetesのインストール確認
minikube経由でkubernetes(kubectl)を確認します。
kubectlを直接使えることも確かめておきます。
minikube kubectl -- version
kubectl -- version
出力例:
Client Version: v1.32.0
Kustomize Version: v5.5.0
Server Version: v1.32.0
ポッドの作成(PHP, Nginx, MariaDB)
まずIngressを有効にします:
minikube addons enable ingress
次に以下の内容を php-mariadb.yaml
に保存します。
このファイルにはポッド内のコンテナ定義が含まれています。
このファイルの改行コードは「CRLF」ではなく「LF」にしてください。
以下が php-mariadb.yaml
の内容です:
# MariaDBのDeployment
apiVersion: apps/v1
kind: Deployment
metadata:
# Deploymentの名前
name: mariadb
# Deploymentを区別するためのラベル
labels:
app: mariadb
spec:
# MariaDBインスタンスの数
replicas: 1
selector:
# Podのためのmatch label
matchLabels:
app: mariadb
template:
metadata:
labels:
app: mariadb
spec:
containers:
- name: mariadb
# MariaDBのためのDocker image
image: mariadb:11.3
# MariaDBの動くport
ports:
- containerPort: 3306
# MariaDBの環境変数
env:
- name: MYSQL_ROOT_PASSWORD
value: "rootpassword"
- name: MYSQL_DATABASE
value: "mydatabase"
- name: MYSQL_USER
value: "myuser"
- name: MYSQL_PASSWORD
value: "mypassword"
# MariaDB data storageのボリュームマウンティング
volumeMounts:
- name: mariadb-storage
mountPath: /var/lib/mysql
# volumeの定義
volumes:
- name: mariadb-storage
emptyDir: {}
---
# MariaDB Service
apiVersion: v1
kind: Service
metadata:
# MariaDBサービス名
name: mariadb
spec:
ports:
- port: 3306
selector:
# MariaDB podに接続するためのセレクター
app: mariadb
---
# PHPのWebアプリ用のDeployment
apiVersion: apps/v1
kind: Deployment
metadata:
# Deployment名
name: php-app
# PHPのdeploymentを区別するためのラベル
labels:
app: php-app
spec:
# PHPポッドのインスタンス数
replicas: 1
selector:
matchLabels:
app: php-app
template:
metadata:
labels:
app: php-app
spec:
containers:
- name: php-app
# PHPのウェブアプリのインスタンス数
image: php:8.3-apache
# PHP/Apacheの動くポート番号
ports:
- containerPort: 80
# Virtualbox内のminikubeがホストマシンとなりますが、そのホストマシンへのマウント設定
volumeMounts:
- name: php-app-code
mountPath: /var/www/html
- name: apache-config
mountPath: /etc/apache2/sites-enabled/000-default.conf
subPath: default
# ボリューム定義
volumes:
- name: php-app-code
hostPath:
path: "/mnt/project"
type: Directory
- name: apache-config
configMap:
name: apache-config
---
# Apacheの設定のコンフィグマップ
apiVersion: v1
kind: ConfigMap
metadata:
name: apache-config
data:
default: |
<VirtualHost *:80>
ServerAdmin webmaster@localhost
DocumentRoot /var/www/html
<Directory "/var/www/html">
Options Indexes FollowSymLinks
AllowOverride All
Require all granted
DirectoryIndex index.html index.php
</Directory>
ErrorLog /var/log/apache2/error.log
CustomLog /var/log/apache2/access.log combined
</VirtualHost>
---
# PHPのウェブアプリ用のService
apiVersion: v1
kind: Service
metadata:
# Service名
name: php-app-service
spec:
type: ClusterIP
ports:
- port: 80
targetPort: 80
selector:
# PHPのPODに接続するためのセレクター
app: php-app
---
# Ingressのリソース(PHPのウェブアプリに接続するためのNginxのこと。めんどくさい部分を色々初期設定済みにしてくれているのがIngress。別に自分でNginxを位置から定義してクラスターへの入口を作りたい人はそれでもいい)
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: php-app-ingress
spec:
ingressClassName: nginx
rules:
- host: localhost
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: php-app-service
port:
number: 80
skaffold.yamlの作成
次の内容を skaffold.yaml
として保存します:
apiVersion: skaffold/v4beta12
kind: Config
metadata:
name: php-mariadb-app
deploy:
kubectl: {}
manifests:
rawYaml:
- php-mariadb.yaml
そうするとtest-project
のなかがこうなるはずです。
マウント用ディレクトリ作成
まず、マウント用のディレクトリを作成します:
mkdir mounttest
以下のコマンドでホストとminikubeをマウント接続します:
minikube mount "$Home\\Documents\\projects\\test-project\\mounttest:/mnt/project"
このコマンドはマウント状態を維持するため、このターミナルは開いたままにしておいてください。
以降の作業は別ターミナルを開いて実行します。
skaffoldを使ったデプロイ
以下のコマンドを実行して、開発環境を開始します(test-project
ディレクトリで実行):
cd {test-projectのディレクトリ}
skaffold delete
skaffold run --force
これも実行中にログを出力し続けるため、別の作業をする場合はさらに別のターミナルを使いましょう。
環境の動作確認
数分待つと、Kubernetes環境がminikubeクラスター上に構築されます。
次のコマンドでポッドの状態を確認します:
kubectl get pods
出力例:
NAME READY STATUS RESTARTS AGE
mariadb-998f96ddb-84kqs 1/1 Running 0 64s
php-app-bf6f77579-454jl 1/1 Running 0 64s
READY
がすべて 1/1
であれば、環境は正常に動作しています。
これらは「ポッド(Pod)」と呼ばれます。
例:
- mariadb-998f96ddb-84kqs(ポッド)
- php-app-bf6f77579-454jl(ポッド)
それぞれのポッドの中に、.yaml
で定義したコンテナが動作しています。
1つのポッドに複数コンテナを含めることも可能です。たとえば、ログ用の「サイドカーコンテナ」を一緒に動かすこともできます。
ポッドのトラブルシューティング
もし READY
が 1/1
にならない場合は、以下でポッドの詳細を確認します:
kubectl describe pod php-app-bf6f77579-454jl
標準出力のログを確認するには:
kubectl logs php-app-bf6f77579-454jl
クラスタ全体のイベントを確認するには:
kubectl get events --sort-by='.metadata.creationTimestamp'
ホストPCからminikubeへアクセス
Ingressでファイルを確認
まずはminikube tunnelをつかっておきます。
minikube tunnel
minikubeはVirtual machine内でk8s環境をつくります。通常はHost PCに直接k8s環境を作りますが、今回は開発用にVirtual machine内にk8sを作りました。このk8s環境にHostからアクセスしようとするとPort forwardなどの対応が必要になっちゃいます。
minikube tunnelをするとアクセスできるようになります。(環境によってはアクセスできないかもなので、その場合はあきらめてkubectlでport forwardingしましょう…)
minikube tunnelは一度実行すると動き続けるので、次の作業は別ターミナルを開いて行います。
IngressのIPを確認します。
kubectl get ingress
NAME CLASS HOSTS ADDRESS PORTS AGE
php-app-ingress nginx localhost 192.168.59.100 80 93
IPは192.168.59.100とわかりました。
ブラウザで http://192.168.59.100
にアクセスすると、 404
エラーが表示されます。
これが表示されれば、Ingress経由で接続できている証拠です。
今度はこのIPを使って次のように .yaml
を修正します:
# Ingress resource for PHP Application
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: php-app-ingress
spec:
ingressClassName: nginx
rules:
- host: 192.168.59.100.nip.io #!!! ここをかえる !!!!
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: php-app-service
port:
number: 80
PHPファイルを作成して動作確認
mounttest
に index.php
を作成します:
<?php
echo "Hello World!";
ブラウザで次にアクセスします:
http://192.168.59.100.nip.io/
「Hello World!」が表示されれば成功!
なんで最初は404だったのにIPをlocalhost
から192.168.59.100.nip.io
に書き換えるとアクセスできるようになったのでしょうか?
.yaml の中のIngress定義では、最初こうなっていました:
rules:
- host: localhost
つまりこのIngressルールは「ホスト名が localhost のリクエストだけを処理する」という設定です。
でも、minikube が作った仮想ネットワーク(例:192.168.59.100)は、ホストOSの localhost とは別世界のIPアドレスです。なのでブラウザから 192.168.59.100 にアクセスすると、
Ingressコントローラーが
ホスト名が一致しない (localhostじゃない) から
適用するルールがなくて 404 を返すという状態になります。
なぜ 192.168.59.100.nip.io に変えるとアクセスできるのかというと
rules:
- host: 192.168.59.100.nip.io
に変更することで、Ingressがこのホスト名を認識して、
「あ、これは自分が担当するホスト名だ!」
と判断して、ルーティング処理してくれるようになるためです。
ここでのキモ
nip.io は無料のDNSサービスで、xxx.xxx.xxx.xxx.nip.io にアクセスすると自動でそのIPに名前解決される。
192.168.59.100.nip.io → DNSが 192.168.59.100 に解決してくれる。
つまり「DNSで名前をつけつつ、Ingressの host 条件にも合う」ということになる。
PHPコードの変更が即時反映されない場合
php.ini
に次の設定を追加・変更して、opcache
を無効にしてください:
opcache.enable=0
opcache.validate_timestamps=1
opcache.revalidate_freq=0
これで、mounttest
フォルダのPHPを変更すれば、kubernetes内のpodに即時反映されるようになります。
MariaDBをホストPCから使う(NodePort)
MariaDBのService定義をNodePortに変更する必要があります。以下は修正済みの php-mariadb.yaml
の該当部分です:
# MariaDB Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: mariadb
labels:
app: mariadb
spec:
replicas: 1
selector:
matchLabels:
app: mariadb
template:
metadata:
labels:
app: mariadb
spec:
containers:
- name: mariadb
image: mariadb:11.3
ports:
- containerPort: 3306
env:
- name: MYSQL_ROOT_PASSWORD
value: "rootpassword"
- name: MYSQL_DATABASE
value: "mydatabase"
- name: MYSQL_USER
value: "myuser"
- name: MYSQL_PASSWORD
value: "mypassword"
volumeMounts:
- name: mariadb-storage
mountPath: /var/lib/mysql
volumes:
- name: mariadb-storage
emptyDir: {}
---
# NodePort Service
kind: Service
apiVersion: v1
metadata:
name: mariadb
spec:
type: NodePort
selector:
app: mariadb
ports:
- port: 3306
targetPort: 3306
protocol: TCP
nodePort: 30036 # 任意のポート番号(例:30000〜32767)
再デプロイ
skaffold run
を止めて(Ctrl+C)、以下のコマンドで再デプロイします:
skaffold delete
skaffold run --force
minikube tunnelもやり直したほうがいいかもしれません。
MinikubeのIP確認
minikube ip
出力例:
192.168.59.100
このIPとNodePort(例:30036)を組み合わせてMariaDBにアクセスできます。
例:
192.168.59.100:30036
MariaDBへの接続情報(環境変数)
MariaDBの接続には以下の設定が使われています:
ユーザー名: myuser
パスワード: mypassword
データベース: mydatabase
ルートパスワード: rootpassword
この情報を使って、ホスト側のMySQLクライアントやDBツール(A5SQLmk2やDBeaverなど)から接続できます。
まとめ
これで、
- PHPファイルを編集するとリアルタイム反映されるKubernetes環境
- Ingress経由でアクセス可能なWebサーバ
- NodePort経由でMariaDBに外部から接続可能
な本格的なローカルKubernetes開発環境が完成しました!
おまけリンク集
-
Skaffold公式サンプル:
https://github.com/GoogleContainerTools/skaffold/tree/main/examples -
Skaffoldのパラメータ一覧:
https://skaffold.dev/docs/references/yaml/