WordPressをKubernetes に構築する手順(GCP GKE)
Kubernetes へ WordPress を設置したので作業経緯を記録する記事です。
この記事が指す Kubernetes は、GKE (Google Kubernetes Engine) です。とはいえ GKE 特有の機能に依存したものではないため、その他 Kubernetes クラスタでも概ね大丈夫だと思います。MySQL の部分だけ Cloud SQL を使うため、一部例外あり。
また、手順だけではなくどうしてそういう設定(構成にしているのか)という点も補足していきます。
今回の記事で作る構成
WordPredd コンテナを1つ構築する方法です。複数台構成ではないので可用性は低下するものの、土台となる Kubernetes は複数台の仮想マシン(ノード)で稼働しているケースが大半でしょうから、一定の可用性を有していることになります。また、SSLの終端にあたり Ingress と Let’s Encrypt を利用しています。
複数コンテナ構成にする場合の課題
想定アクセス数などの非機能要件による設計次第です。コンテナなので replica: 2
にすればいいんじゃないの?となりますが、コンテンツ用のボリュームの考慮が必要なのでそう簡単にはいきません。WordPress コンテンツの変化って何あるの?ということですが、例えば以下の行為によります。
- 記事の投稿のために画像をアップロードした場合
- 管理画面から任意のプラグインをインストールシた場合
- 管理画面上のエディタでテーマを一部書き換えた場合
- 管理画面上から WordPress そのものをアップグレードした場合
- …などなど
プラグインやテーマ、アップグレード行為については一切やらない(やる場合は Docker Image でしっかり管理する)という運用もありますが、記事のための画像アップロードについては頻度を考えると現実的ではないでしょう。一切画像を使わないテキストコンテンツならば、まあ大丈夫だけど・・・という感じです。
複数ノード上のコンテナ(Pod)から単一のボリュームを読み書きしようとすると選択肢が非常に限られます。例えばNFSボリュームを使えば解決できますが、手間やコストとの相談ですね。
Persistent Volumes | Kubernetes ― https://kubernetes.io/docs/concepts/storage/persistent-volumes/#access-modes
他の案としては、 wp-content
は Docker Image として固めてしまって、アップロード画像のみ外部ストレージで運用する手段も有用です。
この場合、プラグインの追加といったちょっとしたシーンでもビルドしなければならないので面倒ではありますが、コンテナ設計としてはより理想的です。オブジェクトストレージに画像をアップロードするプラグインも別の記事で紹介していますので参考まで。
長くなりましたが、この記事ではシンプルな構成で構築していきます。
Kubernetes デプロイ設計の方針
Kubernetes 上では、とある「目的」を達成する「手段(設定方法)」が複数あるケースも多く、開発者や運用者の関係など様々な要素により最適解が変わってくる部分です。開発者と運用者が異なる場合は、一般的には運用者が理解できるように優しく(難易度を下げて)提供します。
今回は、開発者と運用者が同一の前提で、ほどほどに使いやすければいいくらいのスタンスです。
前提条件
Kubernetes では Docker の知識がそのまま流用可能ですので、まずは WordPress オフィシャル提供の Docker イメージをローカル環境で構築してみることをおすすめします。WordPress のオフィシャルイメージに関しては、開発環境づくりの記事で記載しました。
今回の構成は以下の前提とします。
- WordPress オフィシャルイメージを利用
- コンテナ(Pod)構成はシングル
- データベースはMySQLだが、GCPのマネージドサービス(Cloud SQL)を利用する
- ロードバランサはマネージドを使う
- Ingress Controller は Nginx を使う(別用途のサイトも収容しており複数サイトを終端するため)
事前準備
- CloudSQL にユーザーを作っておく
- CloudSQL 接続用の鍵(JSONフォーマット)を用意しておく
- WordPress 接続用 ユーザ・パスワードは環境変数に用意しておく。変数名は何でも構いませんがこの記事では以下の通りとします
GCP_CLOUDSQL_INSTANCE_NAME
- Cloud SQL インスタンス作成時に用意される
project-name:region-name:cloudsql-instance-name:3306
のような書式の文字列
- Cloud SQL インスタンス作成時に用意される
WORDPRESS_DB_NAME
WORDPRESS_DB_USER
WORDPRESS_DB_PASSWORD
- 上記3点は、いわゆる通常の MySQL 接続情報
# 変数リスト
WORDPRESS_DB_NAME=
WORDPRESS_DB_USER=
WORDPRESS_DB_PASSWORD=
GCP_CLOUDSQL_INSTANCE_NAME=
設定値の管理方針
大きくわけると(1)平文で設定値を管理する、(2)暗号化して設定値を管理する、という2種類があります。使い分けが面倒であれば全て暗号化しておくのも手ですが、「今の設定値どうなってるんだっけ」というのをちょっとコマンドやコンフィグファイルで確認したい場合に手間が増えますので、個人で気には情報の質を踏まえて使い分けするのがいいと思います。
- 秘匿情報ではない設定値は ConfigMap として準備しておく
- 秘匿情報は、 Secret を作る
上記の通り、平文か暗号化とは別に、設置値をどのようにアプリケーションに適用するかも考える必要があります。環境変数で設定できる場合は原則は環境設定で統一してしまうのがよいでしょう。ただし Docker Image の設計に依りますので、環境変数では対応出来ない場合には設定ファイルを何らかの手段で配置することとします。
デプロイ作業(準備作業)
以降の説明では、 yourns
という名前のネームスペースに構築しているものとします。
CloudSQL用のシークレットファイル
/path/to/鍵ファイルの場所
: 任意の場所に CloudSQL 接続用の鍵ファイル(JSON)を配置しておきます。そしてそのファイルを secret に格納します。
kubectl -n yourns create secret generic database-key --from-file=cloudsql.json=/path/to/鍵ファイルの場所
kubectl -n yourns describe secret database-key
環境変数
/path/to/secrets.env
: 事前準備の内容に沿って、任意の場所に環境変数のリストを準備しておきます。そして以下のコマンドで secret に流し込みます。
やっていることは単純に、 --from-literal=
の書式で Secret を設定しているだけです。こんな面倒くさそうなことをしなくてもいいのですが、ローカルの開発環境のファイルを手っ取り早く格納するのに都合がいいのでこのようにしました。
_secrets=$(cat ~/path/to/secrets.env | sed -e 's/^/--from-literal=/' | tr "\n" ' ')
# 必要に応じて中身を確認
echo $_secrets
# 内容が意図したものであれば、それらを Secret に登録する。
eval "kubectl -n yourns create secret generic env-production $_secrets"
登録に成功したら、以下のように設定されたことを確認できます。
kubectl -n yourns describe secret env-production
Name: env-production
Namespace: yourns
Labels: <none>
Annotations: <none>
Type: Opaque
Data
====
GCP_CLOUDSQL_INSTANCE_NAME: XX bytes
WORDPRESS_DB_NAME: XX bytes
WORDPRESS_DB_PASSWORD: XX bytes
WORDPRESS_DB_USER: XX bytes
configMap 作成
configmap.yml
---
apiVersion: v1
kind: ConfigMap
metadata:
name: wordpress-config
namespace: yourns
data:
WORDPRESS_DB_HOST: "127.0.0.1"
#WORDPRESS_CONFIG_EXTRA: |
# define('WP_追加設定したいものがあればここに書ける', true);
書いたら配置。 apply
としていますが、初回なら create
でも構いません。
kubectl -n yourns apply -f configmap.yml
PHP.ini ファイルセット
PHPの設定をするため、 php.ini
を ConfigMap にセットします。ここでは2つのファイルを配置しています。
origin.ini
: もともと WordPress の Docker Image に用意されている.ini
ファイル群をまとめたファイルです。何故改て用意するのかは、この記事の末尾にエラーの経緯を記載しています。upload_max_filesize.ini
: WordPress 管理画面での画像アップロードサイズが標準では 2Mbyte しかありません。これでは少々少ないと思いますので拡張します。
upload_max_filesize.ini
upload_max_filesize = 8M
origin.ini
error_reporting = E_ERROR | E_WARNING | E_PARSE | E_CORE_ERROR | E_CORE_WARNING | E_COMPILE_ERROR | E_COMPILE_WARNING | E_RECO
VERABLE_ERROR
display_errors = Off
display_startup_errors = Off
log_errors = On
error_log = /dev/stderr
log_errors_max_len = 1024
ignore_repeated_errors = On
ignore_repeated_source = Off
html_errors = Off
opcache.memory_consumption=128
opcache.interned_strings_buffer=8
opcache.max_accelerated_files=4000
opcache.revalidate_freq=2
opcache.fast_shutdown=1
zend_extension=opcache
extension=bcmath.so
extension=gd.so
extension=mysqli.so
extension=zip.so
extension=imagick
extension=exif.so
extension=sodium
そしてコマンドを実行します。この例では、 .ini ファイルは conf/
ディレクトリに配置していますが、パス指定が正しければどこでも構いません。
kubectl -n yourns create configmap php-ini-files --from-file=conf/origin.ini --from-file=conf/upload_max_filesize.ini
PVC (Persistent Volume Claim) 作成
コンテナが必要とするディスクを要求するためのリソースです。この例では「1GByteのディスクが欲しい」というシンプルな要求を書いています。
このディスクは、追々 wp-content/
といった失いたくない情報(変化のある情報)を格納するディレクトリ用に使います。
pvc.yml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: wordpress-content-disk
namespace: yourns
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
kubectl -n yourns apply -f pvc.yml
詳細な設定、例えばSSDがいいとか別のプロトコルがいいとか、、といったケースには、どのクラウドプロバイダーを利用しているかによって事情が異なります。例えば、AWSやGCPや、Azureでは・・・といった具合です。
Persitent Volume の詳細はオフィシャルドキュメントを参照してください。
永続ボリューム | Kubernetes ― https://kubernetes.io/ja/docs/concepts/storage/persistent-volumes/
中間チェックリスト
ここまでの設定で、以下の内容が正しく表示されることを確認します。
# cloudsql.json があること
kubectl -n yourns describe secret database-key
# 事前準備をしたDB接続用の情報4つがあること
kubectl -n yourns describe secret env-production
# WordPress 向けの設定情報があること(暗号化していないので中身が表示される)
kubectl -n yourns describe configmap wordpress-config
# PHP設定情報があること(暗号化していないので中身が表示される)
kubectl -n yourns describe configmap php-ini-files
# wordpress-content-disk があること
kubectl -n yourns get pvc
デプロイ作業(本番)
ここからは、いよいよ公開するための作業をしていきます。Kubernetes の基本として、以下のリソースについて予め概念を把握しておくことを推奨します。
- Pod
- Service
- Deployment
- Ingress
Service
service.yml
apiVersion: v1
kind: Service
metadata:
name: wordpress
namespace: yourns
labels:
name: wordpress
spec:
type: NodePort
ports:
- name: http
port: 80
targetPort: 80
selector:
app: wordpress
kubectl -n yourns apply -f service.yml
Deployment
いきなりゴチャっとしますが、まずは完成形を貼り付けます。
- この記事執筆時点で最新の WordPress 5.8 イメージを利用しています。
- MySQL (Cloud SQL) への接続のために Proxy を利用しています。Google提供のものです。
- 外部アプリケーションから Cloud SQL に接続する | Cloud SQL for MySQL | Google Cloud ― https://cloud.google.com/sql/docs/mysql/connect-external-app?hl=ja
- 応答確認の
livenessProbe
を設定してはいますがとりあえず感満載です。
Deployment の中身でいくつか、古臭い点や暫定的な内容もあるため文末で説明します。必要に応じて参照してください。
deployment.yml
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: wordpress
namespace: yourns
spec:
replicas: 1
selector:
matchLabels:
app: wordpress
template:
metadata:
labels:
app: wordpress
spec:
containers:
# CONTAINER: 1
- name: wordpress
image: wordpress:5.8
ports:
- name: http-port
containerPort: 80
livenessProbe:
httpGet:
path: /readme.html
port: http-port
initialDelaySeconds: 30
timeoutSeconds: 1
envFrom:
- secretRef:
name: env-production
env:
- name: WORDPRESS_DB_HOST
valueFrom:
configMapKeyRef:
name: wordpress-config
key: WORDPRESS_DB_HOST
- name: WORDPRESS_CONFIG_EXTRA
valueFrom:
configMapKeyRef:
name: wordpress-config
key: WORDPRESS_CONFIG_EXTRA
volumeMounts:
- mountPath: /usr/local/etc/php/conf.d
name: php-ini-files
readOnly: true
- name: wordpress-disk
mountPath: "/var/www/html"
# CONTAINER: 2
- name: cloudsql
image: gcr.io/cloudsql-docker/gce-proxy:1.17
imagePullPolicy: IfNotPresent
command:
- "/cloud_sql_proxy"
- "-instances=$(GCP_CLOUDSQL_INSTANCE_NAME)"
- "-credential_file=/credentials/cloudsql.json"
securityContext:
runAsUser: 2 # non-root user
allowPrivilegeEscalation: false
envFrom:
- secretRef:
name: env-production
volumeMounts:
- mountPath: /cloudsql
name: cloudsql
- mountPath: /credentials
name: database-key
volumes:
- name: php-ini-files
configMap:
name: php-ini-files
- name: wordpress-disk
persistentVolumeClaim:
claimName: wordpress-content-disk
- name: cloudsql
emptyDir: {}
- name: database-key
secret:
secretName: database-key
Deployment の最初の行にある apiVersion: apps/v1
について、古い記事では extensions/v1beta1
と書かれていますが、 Kubernetes のバージョン 1.16 あたりで廃止されています。利用している Kubernetes のバージョンに注意してください。
そしてリソースを適用します。
kubectl -n yourns apply -f deployment.yml
動作確認(公開前)
この時点ではまだインターネット上に公開していませんが、ポート転送によりローカル環境からのみ接続して確認することが可能な状態になりました。
初期構築ならば一通り完了してから動作確認でもよいと思いますが、マメに確認した方が後々動かなかった時の切り分けがしやすいので、確認しておきましょう。
まずはテストに用いる Pod の名前を確認します。以下の例では wordpress-1abcd2345e-x2k2g
です。
注:この時点で STATUS が Running になっていない場合は、そもそもコンテナの起動に失敗していますので何か間違っている状態です。先に進む前に正常化しましょう。
kubectl -n yourns get pod
NAME READY STATUS RESTARTS AGE
wordpress-1abcd2345e-x2k2g 2/2 Running 0 XXd
そして、Pod名と動作確認用のポートを指定して以下のコマンド port-forward
を実行します。この例では、 localhost:9999
で確認できるようになります。
# Podの名前を入れること
kubectl -n yourns port-forward wordpress-1abcd2345e-x2k2g 9999:80
ここでもしエラーが出た場合、Pod の内部に接続したり、ログを見て調査する必要があります。
exec -it
を使うとコンテナ(Pod)内に接続できます。-c app
では、接続先のコンテナを指定しています。今回の例では Pod 内に WordPress コンテナと Cloud SQL Proxy コンテナの2つがありますので明示する必要があります。- 最後に
bash
と書くことでコンテナ内の bash でターミナル接続ができます。
kubectl -n yourns exec -it wordpress-1abcd2345e-x2k2g -c wordpress -- bash
Pod と Command の間に --
をつけないと警告が出ます。
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl kubectl exec [POD] – [COMMAND] instead.
デプロイ作業(公開:証明書と LB)
ここまでの手順で接続確認ができたらもう完成したようなもので、あとはインターネットに公開するのみです。Ingress などを使って公開しましょう。
最後の仕上げではありますが、ここからの記事は少々前提情報を割愛しています。
Ingress Controller (Nginx) や Let’s Encrypt 自動更新のための Cert Manager が使える前提での手順なのですが、 WordPress のデプロイというメインの目的に対して説明対象がズレてしまいますのでこの記事では省略しています。また、この記事で利用している Cert Manager はバージョンが古いため、最新情報は別途確認が必要です。
こういうやり方もあるのか、という一例として参考にしてください。
証明書作成
certificate.yml
以下のリソースをデプロイすると、自動で Let’s Encrypt を用いた SSL 証明書を作成してくれます。
apiVersion: cert-manager.io/v1alpha2
kind: Certificate
metadata:
name: wordpress-cert
namespace: yourns
spec:
commonName: wordpress.example.com
secretName: wordpress-tls
issuerRef:
name: letsencrypt-prod
kind: ClusterIssuer
dnsNames:
- wordpress.example.com
kubectl -n yourns apply -f certificate.yml
作成されたことを確認する。
kubectl -n yourns describe certificate wordpress-cert
確認結果はこんな感じか:
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal GeneratedKey 2m31s cert-manager Generated a new private key
Normal Requested 2m31s cert-manager Created new CertificateRequest resource "wordpress-cert-2840638159"
Normal Issued 2m6s cert-manager Certificate issued successfully
あるいはこんな感じ:
Status:
Conditions:
Last Transition Time: 2022-01-18T05:19:14Z
Message: Certificate is up to date and has not expired
Reason: Ready
Status: True
Type: Ready
Not After: 2022-04-18T04:19:12Z
Let’s Encrypt の証明書期限3ヶ月を意識することなく自動で更新してくれるので大変便利です。
ローロバランサー(Ingress)作成
ingress.yml
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: wordpress-ingress
namespace: yourns
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/ssl-redirect: "true"
nginx.ingress.kubernetes.io/proxy-body-size: 8m
spec:
tls:
- secretName: wordpress-tls
hosts:
- wordpress.example.com
rules:
- host: wordpress.example.com
http:
paths:
- backend:
serviceName: wordpress
servicePort: 80
これでインターネットへの公開が完了しました。
この例ではhttps://wordpress.example.com
でアクセスできることを確認します。
まとめ
WordPress オフィシャルイメージを使って、Kubernetes に配置するための大きな流れを記載しました。Kubernetes へデプロイ方法はいくつかあるなかでの一例になればと思います。
(参考)Deployment に関する補足説明
本文中に記載した Deployment からいくつか抜粋して部分説明します。
spec:
#... 省略
template:
#... 省略
spec:
containers:
- name: wordpress
image: wordpress:5.8
ports:
- name: http-port
containerPort: 80
livenessProbe:
httpGet:
path: /readme.html
port: http-port
initialDelaySeconds: 30
timeoutSeconds: 1
livenessProbe は、いわゆる死活監視の設定です。死活監視先を謝ると、「死活監視では応答OKなのに実際にはアプリケーションが応答せずにダウンしている」ということもあるので、監視先は重要です。
WordPress の場合は index.php
がいいような気はしますが、この例では readme.html
とすることで、少なくとも HTTP 応答はできる(但しPHPが応答するかはわからない)くらいのレベル感にしています。
Liveness Probe、Readiness ProbeおよびStartup Probeを使用する | Kubernetes ― https://kubernetes.io/ja/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/
spec:
#... 省略
template:
#... 省略
spec:
containers:
- name: wordpress
envFrom:
- secretRef:
name: env-production
env:
- name: WORDPRESS_DB_HOST
valueFrom:
configMapKeyRef:
name: wordpress-config
key: WORDPRESS_DB_HOST
- name: WORDPRESS_CONFIG_EXTRA
valueFrom:
configMapKeyRef:
name: wordpress-config
key: WORDPRESS_CONFIG_EXTRA
環境変数の設定方法がいくつか混在しています。
envFrom
を利用して全てのConfigMapのデータをコンテナ環境変数として定義します。ConfigMapからのキーがPodの環境変数名になります。valueFrom
を使うと、1個1個正確に明示して環境変数を設定します。
一括投入という意味では envFrom
でまとめて適用した方が楽ですし、 volueFrom
を使うと Deployment コンフィグが長文になりますので見づらくなります。一方、何の設定をしているのかを明確に指示している点では、 envFrom
よりも valueFrom
での個別指定の方が意思が現れますので作業ミスなどのリスクが低減できます。
よって、チームなどの複数メンバーで運営する場合には vlueFrom
を使うべきでしょう。
Podを構成してConfigMapを使用する | Kubernetes ― https://kubernetes.io/ja/docs/tasks/configure-pod-container/configure-pod-configmap/
spec:
#... 省略
template:
#... 省略
spec:
containers:
- name: wordpress
#... 省略
volumeMounts:
- mountPath: /usr/local/etc/php/conf.d
name: php-ini-files
readOnly: true
- name: wordpress-disk
mountPath: "/var/www/html"
Persistent Volume (永続ディスク)に対して、 /var/www/html
を割り当てています。これは WordPress オフィシャルイメージにおける、HTTPサーバーの公開用ディレクトリです。 /var/www/html/wp-content
部分を割り当てるでもいいような気はしますが、管理画面上から WordPress のバージョンアップをGUIで行う場合は WordPrses を構成する PHP ファイル全体への変更が入るはずですので、素直にHTTPのルートディレクトリを割り当てています。
spec:
#... 省略
template:
#... 省略
spec:
containers:
# CONTAINER: 2
- name: cloudsql
image: gcr.io/cloudsql-docker/gce-proxy:1.17
imagePullPolicy: IfNotPresent
command:
- "/cloud_sql_proxy"
- "-instances=$(GCP_CLOUDSQL_INSTANCE_NAME)"
- "-credential_file=/credentials/cloudsql.json"
securityContext:
runAsUser: 2 # non-root user
allowPrivilegeEscalation: false
この記事ではバージョン 1.17 を指定していますが、本記事執筆時点(2022/02/06)における最新バージョンは 1.28 です。
GoogleCloudPlatform/cloudsql-proxy: Cloud SQL proxy client and Go library ― https://github.com/GoogleCloudPlatform/cloudsql-proxy
自身の検証構成の都合で 1.17 から 1.18 にアップグレードした際に意図せぬエラーが出たことから、暫定処置として 1.17 を指定したのでこのようになっていますが、新しいバージョンを利用するようにしてください。
"-instances=$(GCP_CLOUDSQL_INSTANCE_NAME)"
としている点はちょっとしたポイントです。
Deployment は Git 共有などの都合も踏まえて秘匿情報は記載したくありません。コマンド内の文字列も変数化できますので活用しましょう。 $()
にて囲んだ部分が変数化できます。 ${}
だとNGなので気をつけてください。
(参考)発生した問題と解決策
作業途中で以下のエラーが発生しました。このエラー文中の /var/www/html...
などのパスは、WordPress オフィシャルの Docker コンテナ内のパス情報です。
Fatal error: Uncaught Error: Call to undefined function mysql_connect() in /var/www/html/wp-includes/wp-db.php:1688 Stack trace: #0 /var/www/html/wp-includes/wp-db.php(632): wpdb->db_connect() #1 /var/www/html/wp-includes/load.php(558): wpdb->__construct(‘wordpressf0’, ‘pence.kaput.dat…’, ‘wordpress_headl…’, ‘127.0.0.1’) #2 /var/www/html/wp-settings.php(124): require_wp_db() #3 /var/www/html/wp-config.php(133): require_once('/var/www/html/w…') #4 /var/www/html/wp-load.php(50): require_once('/var/www/html/w…') #5 /var/www/html/wp-blog-header.php(13): require_once('/var/www/html/w…') #6 /var/www/html/index.php(17): require('/var/www/html/w…') #7 {main} thrown in /var/www/html/wp-includes/wp-db.php on line 1688
このエラーそのものは、PHPの設定ファイル (php.ini
)に以下の記載をすれば解決します。
extension=mysqli
ですが、この基本的なコンフィグが無効になっているわけはありません。原因は、アップロードサイズの上限を拡張するために追加設定をした部分にありました。
PHPのconfディレクトリを上書きしないように注意
まず、WordPress オフィシャルイメージの PHP ファイルは以下の通り。 $PHP_INI_DIR
という変数が予め用意されています。そして、細かい設定単位で .ini
ファイルが配置されています。mysqli もありますね。
$ find $PHP_INI_DIR/conf.d/
/usr/local/etc/php/conf.d/
/usr/local/etc/php/conf.d/error-logging.ini
/usr/local/etc/php/conf.d/opcache-recommended.ini
/usr/local/etc/php/conf.d/docker-php-ext-opcache.ini
/usr/local/etc/php/conf.d/docker-php-ext-bcmath.ini
/usr/local/etc/php/conf.d/docker-php-ext-gd.ini
/usr/local/etc/php/conf.d/docker-php-ext-mysqli.ini
/usr/local/etc/php/conf.d/docker-php-ext-zip.ini
/usr/local/etc/php/conf.d/docker-php-ext-imagick.ini
/usr/local/etc/php/conf.d/docker-php-ext-exif.ini
/usr/local/etc/php/conf.d/docker-php-ext-sodium.ini
これに対して、 upload_max_filesize
を設定するために Kubernetes の ConfigMap を利用しましたが、どのようにマウントされるかというと以下の通りになります。 $PHP_INI_DIR/conf
が上書きされてしまっていますね。
# コンテナ内部 with configmap volumes
/usr/local/etc/php
/usr/local/etc/php/conf.d
/usr/local/etc/php/conf.d/..data
/usr/local/etc/php/conf.d/..2022_01_18_08_55_07.759485203
/usr/local/etc/php/conf.d/..2022_01_18_08_55_07.759485203/upload_max_filesize.ini
/usr/local/etc/php/conf.d/upload_max_filesize.ini
注意: **
/etc/config/
**ディレクトリに何かファイルがある場合、それらは削除されます。
公式ドキュメントの説明でも明確に上書きと書かれています。
Podを構成してConfigMapを使用する | Kubernetes ― https://kubernetes.io/ja/docs/tasks/configure-pod-container/configure-pod-configmap/#configmapに保存されているデータをボリュームに入力する
既存ファイルを上書きせずに追加したいコンフィグのみを都合よく配置する方法が思いつかなかったので(Dockerfile を弄ることも今回はしたくなかったので)、力技ですが既存ファイルの設定を吐き出してマウントすることにします。
# 設定書き出し用のワンライナー
cd $PHP_INI_DIR
find conf.d/ -type f | xargs more | sed 's/:/;/g' | sed 's/conf.d/; conf.d/' > origin.txt
実際に吐き出したコンフィグは以下の通り。変更の頻度は高くないと思うので、あまり問題にならないはずです。
;;;;;;;;;;;;;;
; conf.d/error-logging.ini
;;;;;;;;;;;;;;
error_reporting = E_ERROR | E_WARNING | E_PARSE | E_CORE_ERROR | E_CORE_WARNING | E_COMPILE_ERROR | E_COMPILE_WARNING | E_RECO
VERABLE_ERROR
display_errors = Off
display_startup_errors = Off
log_errors = On
error_log = /dev/stderr
log_errors_max_len = 1024
ignore_repeated_errors = On
ignore_repeated_source = Off
html_errors = Off
;;;;;;;;;;;;;;
; conf.d/opcache-recommended.ini
;;;;;;;;;;;;;;
opcache.memory_consumption=128
opcache.interned_strings_buffer=8
opcache.max_accelerated_files=4000
opcache.revalidate_freq=2
opcache.fast_shutdown=1
;;;;;;;;;;;;;;
; conf.d/docker-php-ext-opcache.ini
;;;;;;;;;;;;;;
zend_extension=opcache
;;;;;;;;;;;;;;
; conf.d/docker-php-ext-bcmath.ini
;;;;;;;;;;;;;;
extension=bcmath.so
;;;;;;;;;;;;;;
; conf.d/docker-php-ext-gd.ini
;;;;;;;;;;;;;;
extension=gd.so
;;;;;;;;;;;;;;
; conf.d/docker-php-ext-mysqli.ini
;;;;;;;;;;;;;;
extension=mysqli.so
;;;;;;;;;;;;;;
; conf.d/docker-php-ext-zip.ini
;;;;;;;;;;;;;;
extension=zip.so
;;;;;;;;;;;;;;
; conf.d/docker-php-ext-imagick.ini
;;;;;;;;;;;;;;
extension=imagick
;;;;;;;;;;;;;;
; conf.d/docker-php-ext-exif.ini
;;;;;;;;;;;;;;
extension=exif.so
;;;;;;;;;;;;;;
; conf.d/docker-php-ext-sodium.ini
;;;;;;;;;;;;;;
extension=sodium