はじめに
前略、ローカルで動かしている学習用のFlowアプリケーションをKubernetesで動かしてみようと思います。
docker-composeからk8sに移行する
以前の記事で、ローカルで動かしているFlowアプリケーションをocker-copmposeで動かせるようにしました。
- 【PHPフレームワークFlow】Flowをコンテナ上で動かす
- 【PHPフレームワークFlow】Flowをコンテナ上で動かす②
- 【PHPフレームワークFlow】Flowをコンテナ上で動かす③
- 【PHPフレームワークFlow】Flowをコンテナ上で動かす④
そろそろKubernetesも試したくなってきたので、移行してみようと思います。
元のdocker-compose.yaml
こちらが元のDockerFileです。
以下以外にもgrafanaありますが、動作確認するだけなら不要なので割愛しています。
services:
app:
container_name: app
build:
context: .
dockerfile: ./Docker/local/Dockerfile
ports:
- "8082:8081"
volumes:
- flow-logs:/app/Data/Logs
db:
container_name: mysql
image: mysql:8.0.36
volumes:
- db_data4:/var/lib/mysql
environment:
MYSQL_ROOT_PASSWORD: hogehoge
MYSQL_DATABASE: mydatabase
ports:
- "3306:3306"
valkey:
image: valkey/valkey:9.1.1
container_name: valkey-container
volumes:
- valkey_data:/data
ports:
- "6379:6379"
volumes:
db_data4: {}
app_data4: {}
valkey_data: {}
実装
というわけで実装していきましょう。
今回はMacのDocker Desktopに内蔵されているKubernetesを利用します。
- macOS
- Docker Desktop
- Kubernetes: Docker Desktop内蔵(Kubeadm方式)
事前にDocker DesktopにてKubernetesを有効化しておきましょう。
ディレクトリ構成
ディレクトリ構成は以下です。
$ tree -L 3 --dirsfirst
.
├── Docker
│ └── local
│ ├── Dockerfile
│ └── entrypoint.sh
├── k8s
│ ├── app
│ │ ├── deployment.yaml
│ │ └── service.yaml
│ ├── mysql
│ │ ├── deployment.yaml
│ │ ├── pvc.yaml
│ │ └── service.yaml
│ ├── valkey
│ │ ├── deployment.yaml
│ │ └── service.yaml
│ └── namespace.yaml
└── docker-compose.yaml
namespace.yaml
まずはnamespaceです。
k8sでは管理したいリソースを配置する空間としてnamespaceという概念が存在ます。
今回はアプリケーション、DB、キャッシュサーバをすべて同一のnamespace上で管理します。
シンプルに名前だけ定義しました。のちのリソースごとのマニフェストファイルでこのnamespaceに配置することを宣言します。
# k8s/namespace.yaml
apiVersion: v1
kind: Namespace
metadata:
name: flow-play-ground
app
まずはアプリケーションのマニフェストファイルです。
deployment.yaml
細かい書き方の説明は割愛しますが、ポイントは以下の通り
- metadataに所属するnamespaceを記載
- specには管理するPodの定義を追加
- selectorはこのdeploymentで管理する対象のPodを記述
- templateには管理するPodの定義を記述
- metadataには付与する情報を記述(selectorの対象になるように)
- specには作成するPodの情報を記載(コンテナイメージ、環境変数など)
apiVersion: apps/v1
kind: Deployment
metadata:
name: flow-app
namespace: flow-play-ground
spec:
replicas: 1
selector:
matchLabels:
app: flow-app
template:
metadata:
labels:
app: flow-app
spec:
containers:
- name: php
image: flow-play-ground-app:latest
imagePullPolicy: Never
workingDir: /app
env:
- name: FLOW_CONTEXT
value: Development
コンテナイメージはdocker-composeで動かしていた時と同じものを利用しています。
事前にbuildしておく必要があるのでやっておきましょう。
DockerFileはこちら
# =============================
# 1. Composer install stage
# =============================
FROM php:8.5-cli AS composer
# zip / unzip が必要(Composer が zip アーカイブを解凍する)
# RUN apt-get update && apt-get install -y \
# unzip git \
# && rm -rf /var/lib/apt/lists/*
WORKDIR /app
# Composer を入れる(公式推奨のコピー)
COPY --from=composer:2 /usr/bin/composer /usr/bin/composer
# 非rootユーザーを作成
RUN adduser --disabled-password --gecos '' appuser
# アプリケーションコードをコピー
COPY ./ /app
# composer update
# RUN composer install --no-interaction --prefer-dist
# =============================
# 2. Application stage
# =============================
# ベースイメージ
FROM php:8.5-cli
# 必要なPHP拡張モジュールをインストール
RUN docker-php-ext-install pdo_mysql
# phpredisのinstall
RUN pecl install redis && docker-php-ext-enable redis
# 作業ディレクトリを設定
WORKDIR /app
# 非rootユーザーを作成
RUN adduser --disabled-password --gecos '' appuser
# アプリケーションコードをコピー
COPY --from=composer /app /app
# エントリポイントスクリプトをコピー
COPY ./Docker/local/entrypoint.sh /usr/local/bin/entrypoint.sh
# スクリプトに実行権限を付与
RUN chmod +x /usr/local/bin/entrypoint.sh
ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]
#!/bin/bash
# Data配下のファイルを削除
rm -rf /app/Data
# Docker用の設定ファイルに置き換え
rm /app/Configuration/Settings.yaml
cp /app/Configuration/Settings.yaml_forDocker /app/Configuration/Settings.yaml
# Application配下のファイルをDistributionPackagesの内容で置き換え
# NOTE: 新しくcloneする場合は不要
# rm -f /app/Packages/Application/*
# cp -r /app/DistributionPackages/* /app/Packages/Application/
# Neos.Welcomeの設定ファイルをDocker用に置き換え
rm /app/Packages/Application/Neos.Welcome/Configuration/Settings.yaml
cp /app/Packages/Application/Neos.Welcome/Configuration/Container/Settings.yaml /app/Packages/Application/Neos.Welcome/Configuration/Settings.yaml
# 実行できるように権限を変更
chown -R appuser /app
chmod -R 775 /app
# データベースマイグレーション
su - appuser -c "cd /app ; ./flow doctrine:update"
echo "Server running. Please go to http://localhost:8081 to browse the application."
# サーバーを起動
su - appuser -c "cd /app ; ./flow server:run --host=0.0.0.0"
service.yaml
Serviceには通信に関する内容を記載します。
このPodは外部からアクセス可能とするため、type: LoadBalancerというtypeを指定しています。
8081で通信を受け付けます。
apiVersion: v1
kind: Service
metadata:
name: flow-app
namespace: flow-play-ground
spec:
type: LoadBalancer
selector:
app: flow-app
ports:
- port: 8081
targetPort: 8081
mysql
続いてDBです。
deployment.yaml
ほぼアプリと同様です。
違いとしては、データを永続化できるようVolumeをマウントしていることくらいです。
後述するpvc.yamlで定義するボリュームを利用しています。
DB名やパスワードはsecretsやconfigmapを使うべきですが、いったん動かしたいのでこのままにしています。
apiVersion: apps/v1
kind: Deployment
metadata:
name: mysql
namespace: flow-play-ground
spec:
replicas: 1
strategy:
type: Recreate
selector:
matchLabels:
app: mysql
template:
metadata:
labels:
app: mysql
spec:
containers:
- name: mysql
image: mysql:8.0.36
ports:
- containerPort: 3306
env:
- name: MYSQL_ROOT_PASSWORD
value: hogehoge
- name: MYSQL_DATABASE
value: mydatabase
volumeMounts:
- name: data
mountPath: /var/lib/mysql
volumes:
- name: data
persistentVolumeClaim:
claimName: mysql-data
service.yaml
続いてserviceです。
appと違い外から通信する必要はありません。
typeはデフォルトのClusterIPになり、これはクラスタ内からのみアクセスできるIPが払い出される形です。
appからはServiceで定義したmysqlというホスト名で接続できます。
apiVersion: v1
kind: Service
metadata:
name: mysql
namespace: flow-play-ground
spec:
selector:
app: mysql
ports:
- port: 3306
targetPort: 3306
pvc.yaml
pvc.yamlはDBを永続化するためのボリュームを定義しました。
PersistentVolumeClaimとは容量など必要なスペックを指定してボリュームを要求するときに使う定義です。ここでは、5Giのボリュームを要求しています。
accessModesのReadWriteOnceは「1台のノードからのみ読み書き可能」という定義です。
DBのノードから読み書きできれば十分です。
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: mysql-data
namespace: flow-play-ground
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 5Gi
valkey
最後にキャッシュサーバのvalkeyです。
deployment.yaml
deploymentです。特に変わったところなし。
apiVersion: apps/v1
kind: Deployment
metadata:
name: valkey
namespace: flow-play-ground
spec:
replicas: 1
selector:
matchLabels:
app: valkey
template:
metadata:
labels:
app: valkey
spec:
containers:
- name: valkey
image: valkey/valkey:9.1.1
ports:
- containerPort: 6379
service.yaml
serviceです。
こちらもDB同様typeはデフォルトのClusterIPで十分です。
apiVersion: v1
kind: Service
metadata:
name: valkey
namespace: flow-play-ground
spec:
selector:
app: valkey
ports:
- port: 6379
targetPort: 6379
起動
まずはnamespaceの作成を行います。
kubectl apply -f k8s/namespace.yaml
続いて起動です。
$ kubectl apply -R -f k8s
deployment.apps/flow-app configured
service/flow-app unchanged
deployment.apps/mysql configured
persistentvolumeclaim/mysql-data unchanged
service/mysql unchanged
namespace/flow-play-ground unchanged
deployment.apps/valkey configured
service/valkey unchanged
起動後、kubectl get podsで起動しているかを確認します。
RunningになってればOKです。
$ kubectl get pods -n flow-play-ground
NAME READY STATUS RESTARTS AGE
flow-app-5fdbcdb776-7w729 1/1 Running 0 22s
mysql-76cd56cb9b-72k5x 1/1 Running 0 22s
valkey-f79d7b6cb-p9t48 1/1 Running 0 22s
最後に停止です。
Podの数を0にすることでnamespaceを残したまま停止できます。
$ kubectl scale deployment --all -n flow-play-ground --replicas=0
deployment.apps/flow-app scaled
deployment.apps/mysql scaled
deployment.apps/valkey scaled
以下のようになっていれば停止できています。
$ kubectl get pods -n flow-play-ground
No resources found in flow-play-ground namespace.
動作確認
最後に動作確認です。起動させた状態で以下のようにリクエストを投げたところ、無事にレスポンスが返ってきました!
(データは事前に投入していました)
おわりに
今回はFlowプロジェクトをローカルのk8sで起動してみました。
思いの外サクッと動いてくれてよかったです。
今後は、今回は割愛したgurafanaなどの移行やArgoCDを用いたgitopsなども試してみようと思います。
ここまでご覧いただきありがとうございました!

