最近Kubernetesを触る機会があったので、学習用にminikubeでEC-CUBEを動作させるサンプルを作ってみました。備忘も兼ねて手順を残しておこうと思います。
全体の構成
全体の構成は以下のようなイメージです。
| minikube ---------------------------------------------------
| |
| node ----------------------------------------------------| |
| | | |
| | [ web(eccube) ] [ db(pgsql) ] [ mail(mailcatcher) ] | |
| | | | |
| | [ pvc ] | |
| | | | |
| | [ pv ] | |
| | | |
| -------------------------------------------------------- |
| |
-------------------------------------------------------------
web、db(postgresql)、メール(mailcatcher)の構成で、EC-CUBEの永続化が必要なファイル群を保持する用途としてPersistentVolumeを用意しています。
前準備
minikubeのインストール
$ brew install minikube
起動しておきます
$ minikube start
MailCatcherのpodを作る
メールサーバのpodから作っていきます。
apiVersion: apps/v1
kind: Deployment
metadata:
name: eccube-mail
spec:
replicas: 1
selector:
matchLabels:
app: eccube-mail
template:
metadata:
labels:
app: eccube-mail
spec:
containers:
- name: eccube-mail
image: schickling/mailcatcher
ports:
- containerPort: 1025
- containerPort: 1080
---
apiVersion: v1
kind: Service
metadata:
name: eccube-mail
spec:
type: NodePort
selector:
app: eccube-mail
ports:
- port: 1080
targetPort: 1080
name: mailer
- port: 1025
targetPort: 1025
name: smtp
作成したマニフェストをapplyし、podを立ち上げます。
$ kubectl apply -f mail-deploy.yml
deployment.apps/eccube-mail created
service/eccube-mail created
podの状況を確認して、StatusがRunningになっていたらOK。
$ kubectl get po
NAME READY STATUS RESTARTS AGE
eccube-mail-5b8cf64bb9-85c5s 1/1 Running 0 83s
MailCatcherのWEBメーラを確認するには、 minikube serviceを実行します。
$ minikube service eccube-mail
|-----------|-------------|-------------|---------------------------|
| NAMESPACE | NAME | TARGET PORT | URL |
|-----------|-------------|-------------|---------------------------|
| default | eccube-mail | mailer/1080 | http://192.168.49.2:31044 |
| | | smtp/1025 | http://192.168.49.2:30208 |
|-----------|-------------|-------------|---------------------------|
🏃 Starting tunnel for service eccube-mail.
|-----------|-------------|-------------|------------------------|
| NAMESPACE | NAME | TARGET PORT | URL |
|-----------|-------------|-------------|------------------------|
| default | eccube-mail | | http://127.0.0.1:58752 |
| | | | http://127.0.0.1:58753 |
|-----------|-------------|-------------|------------------------|
上記の出力結果だと、http://127.0.0.1:58752 にアクセスし、画面が表示されることを確認します。
確認できたらminikube serviceコマンドは終了しても大丈夫です。
PostgreSQLのpodを作る
次にPostgreSQLのpodを作ります。
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: eccube-pgsql
labels:
app: eccube-pgsql
spec:
replicas: 1
selector:
matchLabels:
app: eccube-pgsql
serviceName: eccube-pgsql
template:
metadata:
labels:
app: eccube-pgsql
spec:
containers:
- image: postgres:10-alpine
name: eccube-pgsql
env:
- name: POSTGRES_USER
value: postgres
- name: POSTGRES_PASSWORD
value: password
volumeMounts:
- name: data
mountPath: /var/lib/postgresql
volumeClaimTemplates:
- metadata:
name: data
spec:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 500Mi
上記のマニフェストをapplyし、pgsqlのpodが立ち上がるのを確認します。
$ kubectl apply -f pgsql-deploy.yml
statefulset.apps/eccube-pgsql created
service/eccube-pgsql created
$ kubectl get po
NAME READY STATUS RESTARTS AGE
eccube-mail-5b8cf64bb9-85c5s 1/1 Running 0 9m54s
eccube-pgsql-0 1/1 Running 0 44s
webサーバのpodを作る
まず、EC-CUBEを配置するための永続ボリュームを作成します。
永続ボリュームの作成
apiVersion: v1
kind: PersistentVolume
metadata:
name: eccube-pv
spec:
storageClassName: standard
capacity:
storage: 3Gi
accessModes:
- ReadWriteOnce
hostPath:
path: /data/eccube
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: eccube-pvc
spec:
storageClassName: standard
accessModes:
- ReadWriteOnce
volumeMode: Filesystem
resources:
requests:
storage: 500Mi
上記のマニフェストをapplyし、作成を確認します。
$ kubectl apply -f eccube-pv.yml -f eccube-pvc.yml
persistentvolume/eccube-pv created
persistentvolumeclaim/eccube-pvc created
$ kubectl get pv,pvc
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
persistentvolume/eccube-pv 3Gi RWO Retain Bound default/eccube-pvc standard 2m14s
persistentvolume/pvc-fd0555f5-0bd1-4d78-b969-ba05167ac274 500Mi RWO Delete Bound default/data-eccube-pgsql-0 standard 16h
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
persistentvolumeclaim/data-eccube-pgsql-0 Bound pvc-fd0555f5-0bd1-4d78-b969-ba05167ac274 500Mi RWO standard 16h
persistentvolumeclaim/eccube-pvc Bound eccube-pv 3Gi RWO standard 113s
apacheのpodの作成
次に、apacheのpodを作成していきます。
コンテナは、eccube/php-ext-apacheを使っています。
apiVersion: apps/v1
kind: Deployment
metadata:
name: eccube
spec:
selector:
matchLabels:
app: eccube
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
template:
metadata:
labels:
app: eccube
spec:
containers:
- name: eccube
image: eccube/php-ext-apache:7.3
volumeMounts:
- name: htdocs-volume
mountPath: /var/www/html
- name: persistent-volume
mountPath: /opt/ec-cube
volumes:
- name: htdocs-volume
emptyDir: {}
- name: persistent-volume
persistentVolumeClaim:
claimName: eccube-pvc
---
apiVersion: v1
kind: Service
metadata:
name: eccube
spec:
type: NodePort
selector:
app: eccube
ports:
- port: 80
targetPort: 80
上記のマニフェストをapplyし、作成を確認します。
$ kubectl apply -f eccube-deploy.yml
deployment.apps/eccube created
service/eccube created
$ kubectl get po
NAME READY STATUS RESTARTS AGE
eccube-bc7745978-rg64c 1/1 Running 0 98m
eccube-mail-5b8cf64bb9-85c5s 1/1 Running 0 161m
eccube-pgsql-0 1/1 Running 0 152m
これで各pod群の準備ができました。
EC-CUBEの配置
ここからEC-CUBEの配置をしていきます。
アプリケーションによって生成・変更されるファイルがあり、そういったファイルはpodの再起動で初期化されるため、永続化することが必要になります。
今回永続化の対象にするのは以下のファイル群です。
|||永続化|
|--- | --- | --- ||
|app | Customize ||
|app | DoctrineMigrations |
|app | Plugin | ○|
|app | PluginData | ○
|app | config |
|app | proxy | ○
|app | template | ○
|bin | |
|html | | ○
|src | |
|var | | ○
|vendor | |
|composer.json | | ○
|composer.lock | | ○
|symfony.lock | | ○
|index.php | |
|maintenance.php | |
|robots.txt | |
|.env | | ○
これを元に、初期化スクリプトを作ります。
#!/usr/bin/env bash
set -x
TMP_DIR=/tmp
ECCUBE_VER=4.0.5
ECCUBE_FILE=${TMP_DIR}/eccube-${ECCUBE_VER}.tar.gz
DOCROOT_DIR=/var/www/html
PV_DIR=/opt/ec-cube
cd ${TMP_DIR}
curl -O https://downloads.ec-cube.net/src/eccube-${ECCUBE_VER}.tar.gz
if [ -d ${DOCROOT_DIR} ]; then
rm -rf ${DOCROOT_DIR}
mkdir -p ${DOCROOT_DIR}
fi
# document root配下に展開
cd ${DOCROOT_DIR}
tar xvzf ${ECCUBE_FILE} --strip-components 1
rm -rf ${DOCROOT_DIR}/composer.json
rm -rf ${DOCROOT_DIR}/composer.lock
rm -rf ${DOCROOT_DIR}/symfony.lock
rm -rf ${DOCROOT_DIR}/app/Plugin
rm -rf ${DOCROOT_DIR}/app/PluginData
rm -rf ${DOCROOT_DIR}/app/template
rm -rf ${DOCROOT_DIR}/html
rm -rf ${DOCROOT_DIR}/var
# link作成
ln -s ${PV_DIR}/.env ${DOCROOT_DIR}/.env
ln -s ${PV_DIR}/composer.json ${DOCROOT_DIR}/composer.json
ln -s ${PV_DIR}/composer.lock ${DOCROOT_DIR}/composer.lock
ln -s ${PV_DIR}/symfony.lock ${DOCROOT_DIR}/symfony.lock
ln -s ${PV_DIR}/app/Plugin ${DOCROOT_DIR}/app/Plugin
ln -s ${PV_DIR}/app/PluginData ${DOCROOT_DIR}/app/PluginData
ln -s ${PV_DIR}/app/template ${DOCROOT_DIR}/app/template
ln -s ${PV_DIR}/html ${DOCROOT_DIR}/html
ln -s ${PV_DIR}/var ${DOCROOT_DIR}/var
# 永続ボリュームへ展開
cd ${PV_DIR}
ARCHIVE_ROOT=$(tar tf ${ECCUBE_FILE} | sort | head -n 1)
if [ ! -f ${PV_DIR}/.env ]; then
cat << EOF > .env
APP_ENV=${APP_ENV}
APP_DEBUG=${APP_DEBUG}
DATABASE_URL=${DATABASE_URL}
DATABASE_SERVER_VERSION=${DATABASE_SERVER_VERSION}
MAILER_URL=${MAILER_URL}
ECCUBE_AUTH_MAGIC=${ECCUBE_AUTH_MAGIC}
ECCUBE_ADMIN_ROUTE=${ECCUBE_ADMIN_ROUTE}
EOF
tar xfz ${ECCUBE_FILE} ${ARCHIVE_ROOT}composer.json --strip-components 1
tar xfz ${ECCUBE_FILE} ${ARCHIVE_ROOT}composer.lock --strip-components 1
tar xfz ${ECCUBE_FILE} ${ARCHIVE_ROOT}symfony.lock --strip-components 1
tar xfz ${ECCUBE_FILE} ${ARCHIVE_ROOT}app/Plugin --strip-components 1
tar xfz ${ECCUBE_FILE} ${ARCHIVE_ROOT}app/PluginData --strip-components 1
tar xfz ${ECCUBE_FILE} ${ARCHIVE_ROOT}app/template --strip-components 1
tar xfz ${ECCUBE_FILE} ${ARCHIVE_ROOT}html --strip-components 1
tar xfz ${ECCUBE_FILE} ${ARCHIVE_ROOT}var --strip-components 1
cd ${DOCROOT_DIR}
bin/console e:i --no-interaction
else
tar xfz ${ECCUBE_FILE} ${ARCHIVE_ROOT}composer.json --strip-components 1
tar xfz ${ECCUBE_FILE} ${ARCHIVE_ROOT}composer.lock --strip-components 1
tar xfz ${ECCUBE_FILE} ${ARCHIVE_ROOT}symfony.lock --strip-components 1
tar xfz ${ECCUBE_FILE} ${ARCHIVE_ROOT}vendor --strip-components 1
tar xfz ${ECCUBE_FILE} ${ARCHIVE_ROOT}html --strip-components 1
cd ${DOCROOT_DIR}
bin/console cache:clear --no-warmup --env=prod
bin/console eccube:composer:require-already-installed
bin/console doctrine:schema:update --force --dump-sql
bin/console doctrine:migrations:migrate --no-interaction
fi
bin/console cache:clear --no-warmup --env=prod
bin/console cache:warmup --no-optional-warmers --env=prod
composer dump-autoload -o
chown -R www-data:www-data ${PV_DIR}
chown -R www-data:www-data ${DOCROOT_DIR}
DocumentRoot直下は毎回クリア・ソースコードが展開され、永続化されている/opt/ec-cubeへシンボリックリンクを貼る構成にしています。
また、初回起動時はEC-CUBEのインストールを実行し、2回目以降はスキーマ更新やマイグレーションを行います。
このスクリプトをpod初期化時に実行できるよう、コンテナ化します。
FROM eccube/php-ext-apache:7.3
ADD eccube_install.sh /
ローカルのDockerイメージにminikubeからアクセスできるよう、ビルド前に以下を実行します。
$ eval $(minikube -p minikube docker-env)
ビルドします。
$ docker build . -t local/eccube-maintenance
初期化スクリプトの用意はできたので、apacheのpod初期化時に実行されるよう、eccube-deploy.yml
を以下のように修正します。
apiVersion: apps/v1
...
spec:
+ initContainers:
+ - name: eccube-init
+ image: local/eccube-maintenance:latest
+ imagePullPolicy: IfNotPresent
+ envFrom:
+ - configMapRef:
+ name: eccube-config
+ volumeMounts:
+ - name: htdocs-volume
+ mountPath: /var/www/html
+ - name: persistent-volume
+ mountPath: /opt/ec-cube
+ command: ["/eccube_install.sh"]
containers:
- name: eccube
image: eccube/php-ext-apache:7.3
volumeMounts:
- name: htdocs-volume
mountPath: /var/www/html
- name: persistent-volume
mountPath: /opt/ec-cube
...
また、EC-CUBEの初期化時に渡す環境変数を定義しておきます
apiVersion: v1
kind: ConfigMap
metadata:
name: eccube-config
data:
APP_ENV: 'prod'
APP_DEBUG: '0'
DATABASE_URL: 'postgresql://postgres:password@eccube-pgsql:5432/eccube.db'
DATABASE_SERVER_VERSION: '10'
MAILER_URL: 'smtp://eccube-mail:1025'
ECCUBE_ADMIN_USER: 'admin'
ECCUBE_ADMIN_PASS: 'password'
ECCUBE_AUTH_MAGIC: 'Myvpx7CecbURw9cF'
ECCUBE_ADMIN_ROUTE: 'admin'
上記のマニフェストをapplyします。
$ kubectl apply -f eccube-config.yml -f eccube-deploy.yml
configmap/eccube-config created
deployment.apps/eccube configured
service/eccube unchanged
動作確認
minikube service eccube
でEC-CUBEの動作確認をします。
ブラウザでEC-CUBEの画面が立ち上がれば成功です。
$ minikube service eccube
|-----------|--------|-------------|---------------------------|
| NAMESPACE | NAME | TARGET PORT | URL |
|-----------|--------|-------------|---------------------------|
| default | eccube | 80 | http://192.168.49.2:30541 |
|-----------|--------|-------------|---------------------------|
🏃 Starting tunnel for service eccube.
|-----------|--------|-------------|------------------------|
| NAMESPACE | NAME | TARGET PORT | URL |
|-----------|--------|-------------|------------------------|
| default | eccube | | http://127.0.0.1:62911 |
|-----------|--------|-------------|------------------------|
🎉 Opening service default/eccube in default browser...
❗ Dockerドライバーをdarwin上で動かしているため、実行するにはターミナルを開く必要があります。
以上になります。
マニフェストやDockerfileはこちらにも上げていますので、参考にしていただければ幸いです。