Ubuntu16.04でKubernetesを使用してPHPアプリケーションをデプロイする方法
著者は、 Write for DOnations プログラムの一環として、 Open Internet / FreeSpeechを選択して寄付を受け取りました。
序章
Kubernetesは、オープンソースのコンテナオーケストレーションシステムです。 これにより、ダウンタイムを気にすることなく、コンテナーを作成、更新、およびスケーリングできます。
PHPアプリケーションを実行するために、NginxはPHP-FPMのプロキシとして機能します。 この設定を単一のコンテナにコンテナ化するのは面倒なプロセスになる可能性がありますが、Kubernetesは両方のサービスを別々のコンテナで管理するのに役立ちます。 Kubernetesを使用すると、コンテナを再利用および交換可能に保つことができ、新しいバージョンのNginxまたはPHPがリリースされるたびにコンテナイメージを再構築する必要がなくなります。
このチュートリアルでは、PHP 7アプリケーションをKubernetesクラスターにデプロイし、NginxとPHP-FPMを別々のコンテナーで実行します。 また、DigitalOceanのBlockStorage システムを使用して、構成ファイルとアプリケーションコードをコンテナーイメージの外部に保持する方法についても学習します。 このアプローチでは、イメージを再構築するのではなく、構成ボリュームを渡すことで、Web/プロキシサーバーを必要とするすべてのアプリケーションでNginxイメージを再利用できます。
注:このチュートリアルは、 Kubeadm で作成されたKubernetesクラスターでテストされています。これは、DigitalOcean Managed Kubernetes(DOKS)製品とは大きく異なります。 DOKSを使用している場合は、公式の DigitalOceanKubernetes製品ドキュメントで最新情報とチュートリアルを確認してください。
前提条件
- Kubernetesオブジェクトの基本的な理解。 詳細については、Kubernetesの概要の記事をご覧ください。
- Ubuntu16.04で実行されているKubernetesクラスター。 これを設定するには、 Ubuntu16.04チュートリアルでKubeadmを使用してKubernetes1.10クラスターを作成する方法を実行します。
- DigitalOceanアカウントと、ストレージボリュームを作成するための読み取りおよび書き込み権限を持つAPIアクセストークン。 APIアクセストークンがない場合は、ここから作成できます。
- Githubなどの公的にアクセス可能なURLでホストされているアプリケーションコード。
ステップ1—PHP-FPMおよびNginxサービスの作成
このステップでは、PHP-FPMおよびNginxサービスを作成します。 サービスにより、クラスター内から一連のポッドにアクセスできます。 クラスタ内のサービスは、IPアドレスを必要とせずに、名前を介して直接通信できます。 PHP-FPMサービスはPHP-FPMポッドへのアクセスを許可し、NginxサービスはNginxポッドへのアクセスを許可します。
NginxポッドはPHP-FPMポッドをプロキシするため、サービスにそれらを見つける方法を指示する必要があります。 IPアドレスを使用する代わりに、Kubernetesの自動サービス検出を利用して、人間が読み取れる名前を使用してリクエストを適切なサービスにルーティングします。
サービスを作成するには、オブジェクト定義ファイルを作成します。 すべてのKubernetesオブジェクト定義は、少なくとも次のアイテムを含むYAMLファイルです。
apiVersion
:定義が属するKubernetesAPIのバージョン。kind
:このファイルが表すKubernetesオブジェクト。 たとえば、pod
またはservice
です。metadata
:これには、オブジェクトのname
と、それに適用する可能性のあるlabels
が含まれます。spec
:これには、コンテナーイメージやコンテナーへのアクセス元のポートなど、作成するオブジェクトの種類に応じた特定の構成が含まれます。
まず、Kubernetesオブジェクト定義を保持するディレクトリを作成します。
マスターノードにSSHで接続し、Kubernetesオブジェクト定義を保持するdefinitions
ディレクトリを作成します。
- mkdir definitions
新しく作成されたdefinitions
ディレクトリに移動します。
- cd definitions
php_service.yaml
ファイルを作成して、PHP-FPMサービスを作成します。
- nano php_service.yaml
kind
をService
として設定して、このオブジェクトがサービスであることを指定します。
...
apiVersion: v1
kind: Service
PHP-FPMへのアクセスを提供するため、サービスにphp
という名前を付けます。
...
metadata:
name: php
さまざまなオブジェクトをラベルで論理的にグループ化します。 このチュートリアルでは、ラベルを使用して、オブジェクトをフロントエンドやバックエンドなどの「層」にグループ化します。 PHPポッドはこのサービスの背後で実行されるため、tier: backend
というラベルを付けます。
...
labels:
tier: backend
サービスは、selector
ラベルを使用して、アクセスするポッドを決定します。 これらのラベルに一致するポッドは、ポッドがサービスの前に作成されたか後に作成されたかに関係なく、サービスされます。 チュートリアルの後半で、ポッドのラベルを追加します。
tier: backend
ラベルを使用して、ポッドをバックエンド層に割り当てます。 また、app: php
ラベルを追加して、このポッドがPHPを実行することを指定します。 metadata
セクションの後にこれらの2つのラベルを追加します。
...
spec:
selector:
app: php
tier: backend
次に、このサービスへのアクセスに使用するポートを指定します。 このチュートリアルでは、ポート9000
を使用します。 spec
の下のphp_service.yaml
ファイルに追加します。
...
ports:
- protocol: TCP
port: 9000
完成したphp_service.yaml
ファイルは次のようになります。
apiVersion: v1
kind: Service
metadata:
name: php
labels:
tier: backend
spec:
selector:
app: php
tier: backend
ports:
- protocol: TCP
port: 9000
CTRL + o
を押してファイルを保存し、CTRL + x
を押してnano
を終了します。
サービスのオブジェクト定義を作成したので、サービスを実行するには、kubectl apply
コマンドと-f
引数を使用して、php_service.yaml
ファイルを指定します。
サービスを作成します。
- kubectl apply -f php_service.yaml
この出力は、サービスの作成を確認します。
Outputservice/php created
サービスが実行されていることを確認します。
- kubectl get svc
PHP-FPMサービスが実行されていることがわかります。
OutputNAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 10m
php ClusterIP 10.100.59.238 <none> 9000/TCP 5m
Kubernetesがサポートするさまざまなサービスタイプがあります。 php
サービスは、デフォルトのサービスタイプClusterIP
を使用します。 このサービスタイプは内部IPを割り当て、クラスター内からのみサービスに到達できるようにします。
PHP-FPMサービスの準備ができたので、Nginxサービスを作成します。 nginx_service.yaml
という名前の新しいファイルを作成し、エディターで開きます。
- nano nginx_service.yaml
このサービスはNginxポッドを対象としているため、nginx
という名前を付けます。 また、バックエンド層に属するtier: backend
ラベルを追加します。
apiVersion: v1
kind: Service
metadata:
name: nginx
labels:
tier: backend
php
サービスと同様に、セレクターラベルapp: nginx
およびtier: backend
でポッドをターゲットにします。 デフォルトのHTTPポートであるポート80でこのサービスにアクセスできるようにします。
...
spec:
selector:
app: nginx
tier: backend
ports:
- protocol: TCP
port: 80
Nginxサービスは、DropletのパブリックIPアドレスからインターネットにパブリックにアクセスできます。 your_public_ip
は、 DigitalOcean CloudPanelから見つけることができます。 spec.externalIPs
の下に、次を追加します。
...
spec:
externalIPs:
- your_public_ip
nginx_service.yaml
ファイルは次のようになります。
apiVersion: v1
kind: Service
metadata:
name: nginx
labels:
tier: backend
spec:
selector:
app: nginx
tier: backend
ports:
- protocol: TCP
port: 80
externalIPs:
- your_public_ip
ファイルを保存して閉じます。 Nginxサービスを作成します。
- kubectl apply -f nginx_service.yaml
サービスの実行中は、次の出力が表示されます。
Outputservice/nginx created
以下を実行すると、実行中のすべてのサービスを表示できます。
- kubectl get svc
出力にPHP-FPMサービスとNginxサービスの両方が表示されます。
OutputNAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 13m
nginx ClusterIP 10.102.160.47 your_public_ip 80/TCP 50s
php ClusterIP 10.100.59.238 <none> 9000/TCP 8m
実行できるサービスを削除する場合は、次の点に注意してください。
- kubectl delete svc/service_name
PHP-FPMおよびNginxサービスを作成したので、アプリケーションコードと構成ファイルを保存する場所を指定する必要があります。
ステップ2—DigitalOceanストレージプラグインのインストール
Kubernetesは、環境にストレージスペースを作成できるさまざまなストレージプラグインを提供します。 このステップでは、 DigitalOceanストレージプラグインをインストールして、DigitalOceanにブロックストレージを作成します。 インストールが完了すると、ブロックストレージの作成に使用するdo-block-storage
という名前のストレージクラスが追加されます。
まず、DigitalOceanAPIトークンを保存するようにKubernetesシークレットオブジェクトを設定します。 シークレットオブジェクトは、SSHキーやパスワードなどの機密情報を、同じ名前空間内の他のKubernetesオブジェクトと共有するために使用されます。 名前空間は、Kubernetesオブジェクトを論理的に分離する方法を提供します。
secret.yaml
という名前のファイルをエディターで開きます。
- nano secret.yaml
シークレットオブジェクトにdigitalocean
という名前を付け、kube-system
namespace
に追加します。 kube-system
名前空間は、Kubernetesの内部サービスのデフォルトの名前空間であり、さまざまなコンポーネントを起動するためにDigitalOceanストレージプラグインによっても使用されます。
apiVersion: v1
kind: Secret
metadata:
name: digitalocean
namespace: kube-system
シークレットは、spec
キーの代わりに、data
またはstringData
キーを使用して必要な情報を保持します。 data
パラメーターは、取得時に自動的にデコードされるbase64エンコードデータを保持します。 stringData
パラメーターは、作成または更新中に自動的にエンコードされるエンコードされていないデータを保持し、シークレットを取得するときにデータを出力しません。 このチュートリアルでは、便宜上stringData
を使用します。
access-token
をstringData
として追加します。
...
stringData:
access-token: your-api-token
ファイルを保存して終了します。
secret.yaml
ファイルは次のようになります。
apiVersion: v1
kind: Secret
metadata:
name: digitalocean
namespace: kube-system
stringData:
access-token: your-api-token
シークレットを作成します。
- kubectl apply -f secret.yaml
シークレットを作成すると、次の出力が表示されます。
Outputsecret/digitalocean created
次のコマンドで秘密を表示できます。
- kubectl -n kube-system get secret digitalocean
出力は次のようになります。
OutputNAME TYPE DATA AGE
digitalocean Opaque 1 41s
Opaque
タイプは、このシークレットが読み取り専用であることを意味します。これは、stringData
シークレットの標準です。 詳しくはシークレットデザインスペックをご覧ください。 DATA
フィールドには、このシークレットに保存されているアイテムの数が表示されます。 この場合、1つのキーが保存されているため、1
と表示されます。
シークレットが配置されたので、DigitalOceanブロックストレージプラグインをインストールします。
- kubectl apply -f https://raw.githubusercontent.com/digitalocean/csi-digitalocean/master/deploy/kubernetes/releases/csi-digitalocean-v0.3.0.yaml
次のような出力が表示されます。
Outputstorageclass.storage.k8s.io/do-block-storage created
serviceaccount/csi-attacher created
clusterrole.rbac.authorization.k8s.io/external-attacher-runner created
clusterrolebinding.rbac.authorization.k8s.io/csi-attacher-role created
service/csi-attacher-doplug-in created
statefulset.apps/csi-attacher-doplug-in created
serviceaccount/csi-provisioner created
clusterrole.rbac.authorization.k8s.io/external-provisioner-runner created
clusterrolebinding.rbac.authorization.k8s.io/csi-provisioner-role created
service/csi-provisioner-doplug-in created
statefulset.apps/csi-provisioner-doplug-in created
serviceaccount/csi-doplug-in created
clusterrole.rbac.authorization.k8s.io/csi-doplug-in created
clusterrolebinding.rbac.authorization.k8s.io/csi-doplug-in created
daemonset.apps/csi-doplug-in created
DigitalOceanストレージプラグインをインストールしたので、アプリケーションコードと構成ファイルを保持するためのブロックストレージを作成できます。
ステップ3—永続ボリュームの作成
シークレットを配置し、ブロックストレージプラグインをインストールすると、永続ボリュームを作成する準備が整います。 永続ボリューム(PV)は、ポッドのライフサイクルとは無関係に存続する、指定されたサイズのブロックストレージです。 永続ボリュームを使用すると、アプリケーションコードを失うことを心配せずに、ポッドを管理または更新できます。 永続ボリュームには、PersistentVolumeClaim
またはPVCを使用してアクセスします。これにより、PVが必要なパスにマウントされます。
code_volume.yaml
という名前のファイルをエディターで開きます。
- nano code_volume.yaml
次のパラメータと値をファイルに追加して、PVCcode
に名前を付けます。
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: code
PVCのspec
には、次のアイテムが含まれています。
accessModes
これはユースケースによって異なります。- ReadWriteOnce –単一ノードによる読み取り/書き込みとしてボリュームをマウントしますReadOnlyMany –多くのノードによる読み取り専用としてボリュームをマウントしますReadWriteMany –多くのノードによる読み取り/書き込みとしてボリュームをマウントします
resources
–必要なストレージスペース
DigitalOceanブロックストレージは単一ノードにのみマウントされるため、accessModes
をReadWriteOnce
に設定します。 このチュートリアルでは、少量のアプリケーションコードを追加する方法について説明します。したがって、このユースケースでは1GBで十分です。 ボリュームに大量のコードまたはデータを保存する予定の場合は、要件に合わせてstorage
パラメーターを変更できます。 ボリュームの作成後にストレージの量を増やすことはできますが、ディスクの縮小はサポートされていません。
...
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
次に、Kubernetesがボリュームのプロビジョニングに使用するストレージクラスを指定します。 DigitalOceanブロックストレージプラグインによって作成されたdo-block-storage
クラスを使用します。
...
storageClassName: do-block-storage
code_volume.yaml
ファイルは次のようになります。
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: code
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
storageClassName: do-block-storage
ファイルを保存して終了します。
kubectl
を使用して、code
PersistentVolumeClaimを作成します。
- kubectl apply -f code_volume.yaml
次の出力は、オブジェクトが正常に作成され、1GBのPVCをボリュームとしてマウントする準備ができていることを示しています。
Outputpersistentvolumeclaim/code created
使用可能な永続ボリューム(PV)を表示するには:
- kubectl get pv
PVが一覧表示されます。
OutputNAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pvc-ca4df10f-ab8c-11e8-b89d-12331aa95b13 1Gi RWO Delete Bound default/code do-block-storage 2m
上記のフィールドは、Reclaim Policy
とStatus
を除いて、構成ファイルの概要です。 Reclaim Policy
は、PVにアクセスしているPVCが削除された後、PVで何が行われるかを定義します。 Delete
は、KubernetesとDigitalOceanインフラストラクチャからPVを削除します。 Reclaim Policy
とStatus
の詳細については、KubernetesPVドキュメントをご覧ください。
DigitalOceanブロックストレージプラグインを使用して、永続ボリュームを正常に作成しました。 永続ボリュームの準備ができたので、デプロイメントを使用してポッドを作成します。
ステップ4—PHP-FPMデプロイメントの作成
このステップでは、Deploymentを使用してPHP-FPMポッドを作成する方法を学習します。 デプロイメントは、 ReplicaSets を使用してポッドを作成、更新、および管理するための統一された方法を提供します。 更新が期待どおりに機能しない場合、Deploymentはポッドを前のイメージに自動的にロールバックします。
Deployment spec.selector
キーは、管理するポッドのラベルを一覧表示します。 また、template
キーを使用して、必要なポッドを作成します。
このステップでは、Initコンテナの使用法も紹介します。 Init Containers は、ポッドのtemplate
キーで指定された通常のコンテナーの前に、1つ以上のコマンドを実行します。 このチュートリアルでは、InitContainerがwget
を使用してGitHubGistからサンプルindex.php
ファイルをフェッチします。 サンプルファイルの内容は次のとおりです。
<?php
echo phpinfo();
デプロイメントを作成するには、エディターでphp_deployment.yaml
という新しいファイルを開きます。
- nano php_deployment.yaml
このデプロイメントはPHP-FPMポッドを管理するため、デプロイメントオブジェクトにphp
という名前を付けます。 ポッドはバックエンド層に属しているため、tier: backend
ラベルを使用して、デプロイメントをこのグループにグループ化します。
apiVersion: apps/v1
kind: Deployment
metadata:
name: php
labels:
tier: backend
デプロイメントspec
の場合、replicas
パラメーターを使用して、このポッドのコピーをいくつ作成するかを指定します。 replicas
の数は、ニーズと利用可能なリソースによって異なります。 このチュートリアルでは、レプリカを1つ作成します。
...
spec:
replicas: 1
この展開では、app: php
およびtier: backend
ラベルに一致するポッドを管理します。 selector
キーの下に以下を追加します:
...
selector:
matchLabels:
app: php
tier: backend
次に、Deployment spec
には、ポッドのオブジェクト定義にtemplate
が必要です。 このテンプレートは、ポッドを作成するための仕様を定義します。 まず、php
サービスselectors
とデプロイメントのmatchLabels
に指定されたラベルを追加します。 template.metadata.labels
の下にapp: php
とtier: backend
を追加します。
...
template:
metadata:
labels:
app: php
tier: backend
ポッドには複数のコンテナとボリュームを含めることができますが、それぞれに名前が必要です。 ボリュームごとにマウントパスを指定することで、ボリュームをコンテナに選択的にマウントできます。
まず、コンテナがアクセスするボリュームを指定します。 アプリケーションコードを保持するためにcode
という名前のPVCを作成したので、このボリュームにもcode
という名前を付けます。 spec.template.spec.volumes
の下に、以下を追加します。
...
spec:
volumes:
- name: code
persistentVolumeClaim:
claimName: code
次に、このポッドで実行するコンテナーを指定します。 Dockerストアにはさまざまなイメージがありますが、このチュートリアルではphp:7-fpm
イメージを使用します。
spec.template.spec.containers
の下に、以下を追加します。
...
containers:
- name: php
image: php:7-fpm
次に、コンテナがアクセスする必要のあるボリュームをマウントします。 このコンテナはPHPコードを実行するため、code
ボリュームにアクセスする必要があります。 また、mountPath
を使用して、マウントポイントとして/code
を指定します。
spec.template.spec.containers.volumeMounts
の下に、次を追加します。
...
volumeMounts:
- name: code
mountPath: /code
ボリュームをマウントしたので、ボリュームにアプリケーションコードを取得する必要があります。 これを実現するために、以前にFTP / SFTPを使用したか、SSH接続を介してコードを複製したことがあるかもしれませんが、この手順では、Initコンテナを使用してコードをコピーする方法を示します。
セットアッププロセスの複雑さに応じて、単一のinitContainer
を使用してアプリケーションをビルドするスクリプトを実行するか、コマンドごとに1つのinitContainer
を使用できます。 ボリュームがinitContainer
にマウントされていることを確認してください。
このチュートリアルでは、busybox
を含む単一のInitContainerを使用してコードをダウンロードします。 busybox
は、これを実現するために使用するwget
ユーティリティを含む小さな画像です。
spec.template.spec
の下に、initContainer
を追加し、busybox
イメージを指定します。
...
initContainers:
- name: install
image: busybox
Init Containerは、code
ボリュームにアクセスして、その場所にコードをダウンロードできるようにする必要があります。 spec.template.spec.initContainers
の下で、ボリュームcode
を/code
パスにマウントします。
...
volumeMounts:
- name: code
mountPath: /code
各初期化コンテナはcommand
を実行する必要があります。 Init Containerは、wget
を使用して、コードをGithubから/code
作業ディレクトリにダウンロードします。 -O
オプションは、ダウンロードしたファイルに名前を付け、このファイルにindex.php
という名前を付けます。
注:プルするコードを信頼してください。 サーバーにプルする前に、ソースコードを調べて、コードの機能に問題がないことを確認してください。
spec.template.spec.initContainers
のinstall
コンテナの下に、次の行を追加します。
...
command:
- wget
- "-O"
- "/code/index.php"
- https://raw.githubusercontent.com/do-community/php-kubernetes/master/index.php
完成したphp_deployment.yaml
ファイルは次のようになります。
apiVersion: apps/v1
kind: Deployment
metadata:
name: php
labels:
tier: backend
spec:
replicas: 1
selector:
matchLabels:
app: php
tier: backend
template:
metadata:
labels:
app: php
tier: backend
spec:
volumes:
- name: code
persistentVolumeClaim:
claimName: code
containers:
- name: php
image: php:7-fpm
volumeMounts:
- name: code
mountPath: /code
initContainers:
- name: install
image: busybox
volumeMounts:
- name: code
mountPath: /code
command:
- wget
- "-O"
- "/code/index.php"
- https://raw.githubusercontent.com/do-community/php-kubernetes/master/index.php
ファイルを保存して、エディターを終了します。
kubectl
を使用してPHP-FPMデプロイメントを作成します。
- kubectl apply -f php_deployment.yaml
デプロイメントの作成時に、次の出力が表示されます。
Outputdeployment.apps/php created
要約すると、この展開は、指定されたイメージをダウンロードすることから始まります。 次に、PersistentVolumeClaim
からPersistentVolume
を要求し、initContainers
をシリアルに実行します。 完了すると、コンテナが実行され、volumes
が指定されたマウントポイントにマウントされます。 これらの手順がすべて完了すると、ポッドが稼働します。
次のコマンドを実行して、デプロイメントを表示できます。
- kubectl get deployments
次の出力が表示されます。
OutputNAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
php 1 1 1 0 19s
この出力は、デプロイメントの現在の状態を理解するのに役立ちます。 Deployment
は、目的の状態を維持するコントローラーの1つです。 作成したtemplate
は、DESIRED
状態がphp
という名前のポッドの1つのreplicas
を持つことを指定します。 CURRENT
フィールドは、実行中のレプリカの数を示しているため、これはDESIRED
の状態と一致する必要があります。 残りのフィールドについては、KubernetesDeploymentsのドキュメントをご覧ください。
このデプロイメントが開始したポッドは、次のコマンドで表示できます。
- kubectl get pods
このコマンドの出力は、デプロイメントを作成してから経過した時間によって異なります。 作成直後に実行すると、出力は次のようになります。
OutputNAME READY STATUS RESTARTS AGE
php-86d59fd666-bf8zd 0/1 Init:0/1 0 9s
列は次の情報を表します。
Ready
:このポッドを実行しているreplicas
の数。Status
:ポッドのステータス。Init
は、Initコンテナが実行中であることを示します。 この出力では、1つの初期化コンテナのうち0が実行を終了しました。Restarts
:ポッドを開始するためにこのプロセスが再開された回数。 この数は、初期化コンテナのいずれかに障害が発生した場合に増加します。 デプロイメントは、目的の状態に達するまで再起動します。
起動スクリプトの複雑さによっては、ステータスがpodInitializing
に変わるまでに数分かかる場合があります。
OutputNAME READY STATUS RESTARTS AGE
php-86d59fd666-lkwgn 0/1 podInitializing 0 39s
これは、Init Containersが終了し、コンテナーが初期化されていることを意味します。 すべてのコンテナが実行されているときにコマンドを実行すると、ポッドのステータスがRunning
に変わります。
OutputNAME READY STATUS RESTARTS AGE
php-86d59fd666-lkwgn 1/1 Running 0 1m
これで、ポッドが正常に実行されていることがわかります。 ポッドが起動しない場合は、次のコマンドを使用してデバッグできます。
- ポッドの詳細情報を表示します。
- kubectl describe pods pod-name
- ポッドによって生成されたログを表示します。
- kubectl logs pod-name
- ポッド内の特定のコンテナのログを表示します。
- kubectl logs pod-name container-name
アプリケーションコードがマウントされ、PHP-FPMサービスが接続を処理する準備が整いました。 これで、Nginxデプロイメントを作成できます。
ステップ5—Nginxデプロイメントを作成する
このステップでは、ConfigMapを使用してNginxを構成します。 ConfigMapは、他のKubernetesオブジェクト定義で参照できるKey-Value形式で設定を保持します。 このアプローチにより、必要に応じてイメージを再利用したり、別のNginxバージョンと交換したりできる柔軟性が得られます。 ConfigMapを更新すると、それをマウントしているポッドに変更が自動的に複製されます。
エディターを使用して、ConfigMap用のnginx_configMap.yaml
ファイルを作成します。
- nano nginx_configMap.yaml
ConfigMapにnginx-config
という名前を付け、tier: backend
マイクロサービスにグループ化します。
apiVersion: v1
kind: ConfigMap
metadata:
name: nginx-config
labels:
tier: backend
次に、ConfigMapのdata
を追加します。 キーにconfig
という名前を付け、Nginx構成ファイルの内容を値として追加します。 このチュートリアルのサンプルNginx構成を使用できます。
Kubernetesはリクエストをサービスの適切なホストにルーティングできるため、PHP-FPMサービスの名前をIPアドレスの代わりにfastcgi_pass
パラメーターに入力できます。 nginx_configMap.yaml
ファイルに以下を追加します。
...
data:
config : |
server {
index index.php index.html;
error_log /var/log/nginx/error.log;
access_log /var/log/nginx/access.log;
root ^/code^;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass php:9000;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
}
}
nginx_configMap.yaml
ファイルは次のようになります。
apiVersion: v1
kind: ConfigMap
metadata:
name: nginx-config
labels:
tier: backend
data:
config : |
server {
index index.php index.html;
error_log /var/log/nginx/error.log;
access_log /var/log/nginx/access.log;
root /code;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass php:9000;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
}
}
ファイルを保存して、エディターを終了します。
ConfigMapを作成します。
- kubectl apply -f nginx_configMap.yaml
次の出力が表示されます。
Outputconfigmap/nginx-config created
ConfigMapの作成が完了し、Nginxデプロイメントを構築できるようになりました。
エディターで新しいnginx_deployment.yaml
ファイルを開くことから始めます。
- nano nginx_deployment.yaml
展開にnginx
という名前を付け、ラベルtier: backend
を追加します。
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
labels:
tier: backend
展開spec
に1つのreplicas
が必要であることを指定します。 この展開では、ラベルapp: nginx
およびtier: backend
のポッドを管理します。 次のパラメータと値を追加します。
...
spec:
replicas: 1
selector:
matchLabels:
app: nginx
tier: backend
次に、ポッドtemplate
を追加します。 展開selector.matchLabels
に追加したものと同じラベルを使用する必要があります。 以下を追加します。
...
template:
metadata:
labels:
app: nginx
tier: backend
Nginxに、前に作成したcode
PVCへのアクセスを許可します。 spec.template.spec.volumes
の下に、次を追加します。
...
spec:
volumes:
- name: code
persistentVolumeClaim:
claimName: code
ポッドは、ConfigMapをボリュームとしてマウントできます。 ファイル名とキーを指定すると、その値をコンテンツとして持つファイルが作成されます。 ConfigMapを使用するには、path
をkey
の内容を保持するファイルの名前に設定します。 キーconfig
からファイルsite.conf
を作成します。 spec.template.spec.volumes
の下に、以下を追加します。
...
- name: config
configMap:
name: nginx-config
items:
- key: config
path: site.conf
警告:ファイルが指定されていない場合、key
の内容がボリュームのmountPath
に置き換わります。 これは、パスが明示的に指定されていない場合、宛先フォルダー内のすべてのコンテンツが失われることを意味します。
次に、ポッドを作成する画像を指定します。 このチュートリアルでは、安定性のためにnginx:1.7.9
イメージを使用しますが、他のNginxイメージはDockerストアで見つけることができます。 また、ポート80でNginxを利用できるようにします。 spec.template.spec
の下に以下を追加します:
...
containers:
- name: nginx
image: nginx:1.7.9
ports:
- containerPort: 80
NginxとPHP-FPMは同じパスでファイルにアクセスする必要があるため、code
ボリュームを/code
にマウントします。
...
volumeMounts:
- name: code
mountPath: /code
nginx:1.7.9
イメージは、/etc/nginx/conf.d
ディレクトリの下にあるすべての構成ファイルを自動的にロードします。 このディレクトリにconfig
ボリュームをマウントすると、ファイル/etc/nginx/conf.d/site.conf
が作成されます。 volumeMounts
の下に以下を追加します。
...
- name: config
mountPath: /etc/nginx/conf.d
nginx_deployment.yaml
ファイルは次のようになります。
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
labels:
tier: backend
spec:
replicas: 1
selector:
matchLabels:
app: nginx
tier: backend
template:
metadata:
labels:
app: nginx
tier: backend
spec:
volumes:
- name: code
persistentVolumeClaim:
claimName: code
- name: config
configMap:
name: nginx-config
items:
- key: config
path: site.conf
containers:
- name: nginx
image: nginx:1.7.9
ports:
- containerPort: 80
volumeMounts:
- name: code
mountPath: /code
- name: config
mountPath: /etc/nginx/conf.d
ファイルを保存して、エディターを終了します。
Nginxデプロイメントを作成します。
- kubectl apply -f nginx_deployment.yaml
次の出力は、デプロイメントが作成されたことを示しています。
Outputdeployment.apps/nginx created
次のコマンドを使用してデプロイメントを一覧表示します。
- kubectl get deployments
NginxとPHP-FPMの展開が表示されます。
OutputNAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
nginx 1 1 1 0 16s
php 1 1 1 1 7m
両方のデプロイメントによって管理されているポッドを一覧表示します。
- kubectl get pods
実行中のポッドが表示されます。
OutputNAME READY STATUS RESTARTS AGE
nginx-7bf5476b6f-zppml 1/1 Running 0 32s
php-86d59fd666-lkwgn 1/1 Running 0 7m
すべてのKubernetesオブジェクトがアクティブになったので、ブラウザでNginxサービスにアクセスできます。
実行中のサービスを一覧表示します。
- kubectl get services -o wide
Nginxサービスの外部IPを取得します。
OutputNAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 39m <none>
nginx ClusterIP 10.102.160.47 your_public_ip 80/TCP 27m app=nginx,tier=backend
php ClusterIP 10.100.59.238 <none> 9000/TCP 34m app=php,tier=backend
ブラウザで、http://your_public_ip
と入力してサーバーにアクセスします。 php_info()
の出力が表示され、Kubernetesサービスが稼働中であることが確認されます。
結論
このガイドでは、PHP-FPMサービスとNginxサービスをコンテナ化して、それらを個別に管理できるようにしました。 このアプローチにより、プロジェクトの成長に伴うスケーラビリティが向上するだけでなく、リソースを効率的に使用できるようになります。 また、将来サービスを簡単に更新できるように、アプリケーションコードをボリュームに保存しました。