Docker

GKEに簡単なPHPアプリを手動デプロイする方法を分かりやすく解説

GKEに簡単なPHPアプリを手動デプロイする方法を分かりやすく解説【ハンズオン】

この記事では、簡単なPHPアプリを手動でGKEにデプロイする方法をハンズオン形式でまとめます。

画像を用いてなるべく分かりやすく解説するので、参考にして頂けると幸いです。

 

環境情報
  • MacOS:10.14.6
  • Docker Desktop:3.2.2
  • Kubernetes:v1.19.7
  • PHP:8.0

 

GKEに簡単なPHPアプリを手動デプロイする方法を分かりやすく解説

ザックリと概要だけお伝えすると、GKEにアプリをデプロイするには、以下の4つの工程が必要です。

  • GCP上にインフラを構築する
  • アプリをパッケージ(イメージ)化する
  • 作成したイメージをGCRに上げる
  • Kubernetesのマニフェストファイルを作成・適用してGKE上にアプリをデプロイする

 

そして、4つの工程をより細かく分割すると、以下の13の手順になります。

  1. GCP上で必要なリソースを作成する(クラスタ、ノード、ロードバランサ、ファイアウォールルール)
  2. ルートディレクトリにappおよびdeployディレクトリを作成する
  3. appの下にindex.phpを作り、任意の文字を出力するPHPコードを記述する(アプリの作成)
  4. deployの下に作成したアプリをパッケージ(イメージ)化するためのDockerfileを作成する
  5. deploy用のDockerイメージを作る
  6. 作成したイメージに別名とタグを付ける(GCRにpushするための準備)
  7. 作成したイメージをプロジェクトのGCRにpushする
  8. デプロイするGKEのクラスタを指定する(クラスタの認証情報を取得する)
  9. Kubernetesのマニフェストファイルを作成する(deployment.yaml)
  10. deployment.yamlを適用させる(Podを作成する)
  11. Kubernetesのマニフェストファイルを作成する(service.yaml)
  12. service.yamlを適用させる(Podに対する外部からのエンドポイントを提供する)
  13. 作成したアプリが表示されるかを画面で確認する

 

今回は、それぞれの工程を画像を交えて分かりやすく解説していきます。

少しでも、GKEにアプリをデプロイする方法が分からない。。」「GKEにアプリをデプロイする方法の情報が少ない。。」「何も分からない。。と思っている方々の参考になれば幸いです。

 

1. GCP上で必要なリソースを作成する(クラスタ、ノード、ロードバランサ、ファイアウォールルール)

まずはGCP上で、デプロイに必要なリソースの作成を行います。

 

作成するのは、以下の4つのリソースです。

それぞれについて、設定方法を分かりやすく解説していきます。

  • クラスタ
  • ノード
  • ロードバランサ
  • ファイアウォールルール

プロジェクトの作成およびgcloudコマンドGoogle Cloud リソースを作成、管理するためのコマンド)とkubectlコマンド(Kubernetesクラスターを制御するためのコマンド)のインストールは完了している状態を前提としています。

まだ設定できていない方は、以下の記事を参考に設定しておいて下さい。

 

クラスタおよびノードの作成

まずはクラスタおよびノードの作成を行います。

 

ノードとは、要はCompute Engine(仮想マシン(VM)インスタンス)です。

ノード内でPodが実行され、Podの中でアプリのコンテナが動作します。

 

そしてクラスタとは、ノードの集合体です。クラスタという「土台」の上に複数のノードが乗っているイメージですね。

 

クラスタおよびノードを作成するには、まずデフォルトのプロジェクトおよびコンピューティングゾーンの設定を行います。

これを行うことで、後ほど紹介するクラスタおよびノードを作成するコマンドを打ったときに、自動的に指定したプロジェクトおよびゾーンにクラスタを生成してくれます。

ちなみに、ここで設定を行わなくても、オプションを付ければ、プロジェクトおよびゾーンは選択できます。

ただ、毎回指定するのは面倒なので、ここで事前に設定しておくようにしましょう。

 

デフォルトのプロジェクトおよびコンピューティングゾーンの設定は以下のコマンドで行います。

gcloud config set project [project-id]
gcloud config set compute/zone [compute-zone]

 

[project-id]には、自身のプロジェクトIDを入力しましょう。

プロジェクトIDは「プロジェクトのホーム画面 > プロジェクト情報」から確認できます。

 

[compute-zone]には、リソースを作成したいリージョン・ゾーンを入力しましょう。

利用できるリージョン・ゾーンは以下のコマンドで確認できます。(NAMEの項目です)

gcloud compute zones list

 

また、以下のページにも使用可能なリージョンおよびゾーンが一覧で掲載されています。

参考:使用可能なリージョンとゾーン

 

どのゾーンを選択すればいいかに関しては、以下の記事が参考になるでしょう。

参考:Compute Engineのリージョン選択に関するベストプラクティス

 

設定した内容は、以下のコマンドで確認できます。

gcloud config list

 

 

デフォルトのプロジェクトおよびリージョン・ゾーンの設定が終わったら、いよいよクラスタおよびノードを作成していきます。

特定の名前・数のクラスタおよびノードを作成するには、以下のコマンドを実行します。

gcloud container clusters create [cluster-name] --num-nodes=1

 

このコマンドにより、自身のプロジェクトに、[cluster-name] で指定した名前のクラスタおよび、そのクラスタ上で稼働する一つのノードが作成されます。

 

ロードバランサの作成

次に、ロードバランサの作成を行います。

 

ここでロードバランサのアクセスを流す先とノードのポートを紐づけることで、ロードバランサのIPにアクセスした際にアプリの画面を表示させることが可能となります。

イメージとしては、以下の記事のLoadBalancerの項目に近いです。

参考:Kubernetes道場 9日目 – Serviceについて

 

それではロードバランサの作成を行いましょう。

自身のプロジェクトから、ネットワークサービス > Cloud Load Balancing に移動して下さい。

 

ロードバランサの作成で、3つのタイプがあると思うので、HTTP(S) 負荷分散を選択しましょう。

ロードバランサの作成で、3つのタイプがあると思うので、HTTP(S) 負荷分散を選択しましょう

 

次に、インターネットから自分の VM へを選択します。

「インターネットから自分の VM へ」を選択します

 

LBの設定を行います。名前の欄には任意の値を指定しましょう。

LBの設定を行います

 

次に、バックエンドの設定をしていきます。バックエンドとは、要はLBがリクエストを流す先です。

「バックエンドサービスを作成」を選択すると設定画面になるので、以下の画像を参考に値を設定しましょう。

バックエンドの設定をしていきます

 

インスタンスグループには、先ほど作成したクラスタ・ノードのグループを選択します。(プルダウンを選択したら、勝手に表示されるはずです)

 

ポート番号には、ノードに指定するポートを指定します。これを指定することにより、LBとノードが紐付けられます。

ポート番号は、30000~32767の範囲で指定できます。Kubernetesのデフォルト値

30000~32767 の範囲で独自の nodePort 値を指定できます。

引用:Service

 

次に、ヘルスチェックの設定を行います。以下の画像を参考に値を入力して下さい。

ポイントは「ポート」です。

ここには、先ほどバックエンドで設定したものと同じ値を指定しましょう。

ヘルスチェックの設定を行います

 

バックエンド設定の作成は以上で完了です。

 

 

次の「ホストとパスのルール」では、「バックエンド」に先ほど作成したバックエンドサービスを指定しましょう。

 

最後に、フロントエンドの構成です。ここでは何も設定する必要はありません。

何も入力せずに、「完了」でOKです。

フロントエンドの構成です。ここでは何も設定する必要はありません

 

以上でロードバランサが作成できました。

 

ファイアウォールルールの作成

最後に、ファイアウォールルールの作成を行います。

これが設定されていないと、アプリが適切に動作していたとしても、永遠にアプリの画面を表示させることができません。(502エラーが返ってきます)

参考:接続に関する一般的な問題のトラブルシューティング

 

そのため、忘れずに設定を行いましょう。

設定の項目については、こちらのページと、以下の画像を参考にして下さい。(若干設定が違う部分もあるので、基本的には以下の画像を参考にして下さい)

ファイアウォールルールの作成

 

一番下のポート指定のところで、このファイアウォールルールが適用されるポートの範囲を指定できます。

今回は、Kubernetesのデフォルトノードポートレンジ(30000~32767)を指定していますが、もちろん特定のノードポートを指定しても大丈夫です。(今回だと、LBで30080を指定したので、30080でもOK)

 

以上でGCP上で必要なリソースの作成は完了です。

 

2. ルートディレクトリにappおよびdeployディレクトリを作成する

次に、ローカル環境でアプリおよび必要なファイルを作成する作業に移りましょう。

まずは、アプリのディレクトリと、デプロイに必要なファイルを配置するディレクトリを作成します。

以下の構成になるようディレクトリを生成して下さい。

ディレクトリを生成

 

ちなみに、最終的には以下のファイル構成を目指します。(ファイルは都度作成していくので、今は作成する必要はありません)

最終的には以下のファイル構成を目指します

 

3. appの下にindex.phpを作り、任意の文字を出力するPHPコードを記述する(アプリの作成)

appディレクトリの下にindex.phpを作成し、中に任意のPHPコードを記述して下さい。

例えばこんな感じ。

<?php

echo "SOOOOO GOOOOD!! SUCCESS!!!";

 

 

表示された際にテンションが上がるよう、なるべくポジティブな言葉を書きましょう。

 

4. deployの下に作成したアプリをパッケージ(イメージ)化するためのDockerfileを作成する

次に、deployディレクトリの下に、作成したアプリをパッケージ(イメージ)化するためのDockerfileを作成します。

Dockerfileに以下のコードを記述して下さい。

FROM php:8.0-apache

RUN set -x \
    && sed -i 's!/var/www/html!/var/www/app!g' /etc/apache2/sites-available/000-default.conf

COPY ./app/index.php /var/www/app/

WORKDIR /var/www/app

 

FROMには、ベースとなるイメージを指定します。

今回は、PHP8.0のモジュールが入っているApacheイメージを採用しました。

 

RUNでは、コンテナ内で実行するコマンドを指定します。

今回は、DocumentRoot(Webサーバーがリクエストを流す先)を/var/www/htmlから/var/www/appに書き換える処理を実装しました。

 

COPYでは、ローカルのファイル(index.php)をコンテナ内のDocumentRoot配下にコピーしています。

 

WORKDIRでは、コンテナに入った際のデフォルトのディレクトリを指定します。

今回はDocumentRootを指定しました。

 

 

このDockerfileを用いてdocker buildすることで、作成したアプリ(PHPコード)をパッケージ(イメージ)化することができます。

 

5. deploy用のDockerイメージを作る

先ほど作成したDockerfileを使って、deploy用のDockerイメージを作成します。

ルートディレクトリ(deploy,appディレクトリを格納しているディレクトリ)から以下のコマンドを実行して下さい。

docker build --file=deploy/Dockerfile -t k8s-abc .

 

このコマンドにより、先ほど作成したDockerfileを使って、k8s-abcという名前のイメージを作成することができます。(イメージ名はk8s-abcである必要はありません。任意の名前を付けて下さい)

 

6. 作成したイメージに別名とタグを付ける(GCRにpushするための準備)

先ほど作成したイメージに対して、別名とタグを付けます。

なぜ別名を付けないといけないかというと、GCRにイメージをpushするには、決められた名前のイメージである必要があるからです。

詳しくは、以下のドキュメントを参考にして下さい。

参考:イメージの push と pull

 

tagを付けるには、以下のコマンドを実行します。

docker tag k8s-abc asia.gcr.io/[project-id]/k8s-abc:v1
docker tag k8s-abc asia.gcr.io/[project-id]/k8s-abc:latest

 

先ほど作成した「k8s-abc」イメージに対して、「ホスト名」「プロジェクトID」「イメージ名」「タグ」を結合した名前を付けています。

 

また、v1を付けたイメージが最新であることを示すために、latestタグも同時に付与しています。

 

7. 作成したイメージをプロジェクトのGCRにpushする

作成したイメージをプロジェクトのGCRにpushします。

以下のコマンドを実行して下さい。

docker push asia.gcr.io/[project-id]/k8s-abc:v1
docker push asia.gcr.io/[project-id]/k8s-abc:latest

※[project-id]には自身のプロジェクトIDを入力して下さい。

GCRにpushできない(unauthorizedエラーがでる)場合は、認証が設定できていない可能性があります。

以下のコマンドを実行して認証を構成しましょう。

gcloud auth login
gcloud auth configure-docker

 

参考:gcloud 認証情報ヘルパー

 

8. デプロイするGKEのクラスタを指定する(クラスタの認証情報を取得する)

アプリのイメージをGCRにpushできたので、あとはGKEにアプリをデプロイするだけです。

アプリをデプロイするためのKubernetesマニフェストファイルを作成していきます。

 

ただ、その前にローカルにクラスタの認証情報を取得しておきましょう。

以下のコマンドを実行することで、指定したクラスタに対してkubectlコマンドが実行できるようになります。

gcloud container clusters get-credentials [cluster-name]

 

※上記のコマンドは、 Kubernetes Engine > クラスタ > 操作 > 接続 から取得できます。

クラスタの認証情報は、Kubernetes Engine > クラスタ > 操作 > 接続 から取得できます

 

9. Kubernetesのマニフェストファイルを作成する(deployment.yaml)

Kubernetesのマニフェストファイルを作成していきます。

まずは、deployment.yamlを作成します。

 

deploymentは、PodやReplicaSetを管理するためのオブジェクトで、これを適用することでPodの生成や世代管理が可能となります。

 

deployの下に、k8sディレクトリを作成し、その下にdeployment.yamlファイルを置いて下さい。

中身は以下のように記述します。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: k8s-abc-deployment
  labels:
    app: k8s-abc-deployment
  creationTimestamp: null
spec:
  replicas: 2
  selector:
    matchLabels:
      app: k8s-abc
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 0
  template:
    metadata:
      labels:
        app: k8s-abc
      creationTimestamp: null
    spec:
      containers:
      - name: k8s-abc
        image: asia.gcr.io/[project-id]/k8s-abc:v1
        imagePullPolicy: Always
        ports:
          - containerPort: 80
        resources:
          limits:
            cpu: 50m
            memory: 100Mi
          requests:
            cpu: 50m
            memory: 100Mi

 

 

簡単な説明付きのコードも載せておきます。

必須フィールド(項目)はapiVersion, kind, metadata, specの4つで、それぞれに必要な項目を設定していく形となります。

apiVersion: apps/v1 # 利用するKubernetesAPI(masterに指示を与えるAPI)のバージョン
kind: Deployment # 作成するオブジェクトの種類。次のどれかから選ぶ -> https://kubernetes.io/docs/reference/kubectl/overview/#resource-types
metadata: # オブジェクトを一意に特定するための情報(オブジェクトの情報)。deployment自身の情報
  name: k8s-abc-deployment # deploymentの名前
  labels:
    app: k8s-abc-deployment # deploymentに指定しているラベル
  creationTimestamp: null # Podの作成日時を記録する
spec: # オブジェクトの望ましい状態(こうあって欲しい状態)を定義
  replicas: 2 # 作成するPod数
  selector: # deploymentが管理するPodのラベルを指定
    matchLabels:
      app: k8s-abc # deploymentが操作するpodを指定する。基本的にspec.template.metadata.labelsと同じものを書く
  strategy: # 古いPodから新しいPodに置き換える際の更新戦略を指定する
    type: RollingUpdate # "Recreate"もしくは"RollingUpdate"を指定できる。デフォルトはRollingUpdate
    rollingUpdate: # RollingUpdateの方法を定義する(replicasが2なので、以下の設定だと最大Pod数は3になる)
      maxSurge: 1 # replicasで指定した数よりも増やしていい最大Pod数
      maxUnavailable: 0 # replicasで指定した数よりも減らしていい最大Pod数
  template: # 要は、podTemplateのこと。Podのあるべき状態を指定する
    metadata:
      labels: # deploymentがデプロイするPodのラベル
        app: k8s-abc # 二つのPodにはそれぞれこのラベルが付いている
      creationTimestamp: null
    spec: # Podの状態を定義
      containers:
      - name: k8s-abc # コンテナ名
        image: asia.gcr.io/[project-id]/k8s-abc:v1 # Pod内部にコンテナを作成するためのイメージを指定
        imagePullPolicy: Always # kubeletが特定のイメージをpullしようとしたときに作用する。Alwaysの場合は、常にコンテナイメージをPullする
        ports:
          - containerPort: 80 # コンテナに外部からアクセスできるポートを指定する(コンテナが開けるポート)
        resources:
          limits: # podが使用するリソース(CPU/メモリ)の制限を指定
            cpu: 50m # cpuの使用制限
            memory: 100Mi # memoryの使用制限
          requests: # podをデプロイする時に必要とするリソース(CPU/メモリ)を指定する
            cpu: 50m
            memory: 100Mi

 

 

また、deployment.yamlを雛形から作りたい場合は、以下のコマンドを実行します。

kubectl create deployment k8s-abc-deployment --image=asia.gcr.io/[project-id]/k8s-abc:v1 --dry-run -o yaml > deployment.yaml

 

deploymentにはdeploymentオブジェクトの名前を、imageには、Pod内に作成するコンテナの素となるイメージを指定して下さい。(先ほどGCRにpushしたイメージです)

 

このコマンドにより、image等がセットされた状態でdeployment.yamlが作成されます。(ただ、足りない部分もあるので、中身の見直しは必要です)

 

10. deployment.yamlを適用させる(Podを作成する)

deployment.yamlを適用(apply)して、クラスタ(ノード)上にアプリのコンテナを含んだPodを生成させましょう。

deployment.yamlを適用するには、以下のコマンドを実行します。

kubectl apply -f deployment.yaml

 

-fはファイル名を表すオプションです。

ちなみに、以下のコマンドでも同様にdeployment.yamlを適用を適用させることができます。

kubectl apply --filename=deployment.yaml

 

 

適用できたら、以下のコマンドを実行してdeploymentオブジェクトおよびPodが作成されていることを確認しましょう。

kubectl get deployments
kubectl get pods

 

11. Kubernetesのマニフェストファイルを作成する(service.yaml)

次に、もう一つのKubernetesマニフェストファイルである、service.yamlを作成していきます。

service とは、「外部からPod(コンテナ)へのエンドポイントを提供する仕組み」です。

これがあることにより、Podの削除や入れ替わり等が行われたとしても、安定的に外部から指定したPod(コンテナ)にアクセスすることが可能となります。

 

serviceについては、以下の記事が分かりやすいので、読んでみて下さい。

関連記事:Kubernetes道場 9日目 – Serviceについて

 

作業としては、k8sディレクトリの下に以下の内容のservice.yamlを置いて下さい。

apiVersion: v1
kind: Service
metadata:
  name: k8s-abc-service
  labels:
    app: k8s-abc-service
  creationTimestamp: null
spec:
  type: NodePort
  selector:
    app: k8s-abc
  ports:
  - port: 80
    targetPort: 80
    protocol: TCP
    nodePort: 30080

 

簡単な説明付きのコードも載せておきます。

apiVersion: v1 # どのバージョンのKubernetesAPIを利用してオブジェクトを作成するか
kind: Service # Serviceとは、コンテナへアクセスするための窓口となるエンドポイントを提供する仕組みのこと
metadata: # オブジェクトを一意に特定するための情報(service自身の情報)
  name: k8s-abc-service # serviceの名前  
  labels:
    app: k8s-abc-service # serviceに指定しているラベル
  creationTimestamp: null
spec: # オブジェクト(service)の望ましい状態
  type: NodePort # NodePortタイプを指定
  selector: # アクセスを流すPod群を指定する
    app: k8s-abc # アクセスの転送先のPod(deployment.yamlのtemplate.metadata.labelsで指定した値)
  ports: # serviceでのポートの転送設定を指定する
  - port: 80 # 80へのアクセスが、以下のtargetPortの80に転送される(serviceでExposeするポートを指定)
    targetPort: 80 # serviceで転送する先のポートを指定する(deploymentのcontainerPortを指定する)
    protocol: TCP # portで使用するプロトコルを指定する
    nodePort: 30080 # 外部(LBとかサーバーとか)からアクセスするためのポートを開ける(外部からPodへのエンドポイントを提供)

 

spec.selectorでアクセスを流す先のPodを指定します。

この設定により、指定したPodに対して外部からのエンドポイントが提供されます。

 

また、nodePortには、ロードバランサのバックエンド設定で指定したポート番号を記述しましょう。

このポート番号が間違っていたら、永遠にアプリの画面を表示できないので要注意です。

 

また、service.yamlを雛形から作りたい場合は、以下のコマンドを実行します。

kubectl expose deployment k8s-abc-deployment --port 80 --target-port=80 --type NodePort --dry-run -o yaml > service.yaml

 

k8s-abc-deploymentには、deployment.yamlのmetadataで設定した名前を指定します。

 

12. service.yamlを適用させる(Podに対する外部からのエンドポイントを提供する)

service.yamlを適用するには、以下のコマンドを実行します。

kubectl apply -f service.yaml

 

適用できたら、以下のコマンドを実行して、serviceオブジェクトが作成できていることを確認しましょう。

kubectl get services

 

13. 作成したアプリが表示されるかを画面で確認する

最後に、作成したアプリが正しく表示されるかを画面で確認しましょう。

 

確認するには、ロードバランサのIPアドレスを使ってアクセスする必要があります。

ネットワークサービス > Cloud Load Balancing から自分の作成したロードバランサを選択しましょう。

すると、以下のフロントエンド情報が表示されるので、このIPを入力します。

フロントエンド情報が表示されるので、このIPを入力します

 

すると、、

作成したアプリの画面を表示することができました。

作成したアプリの画面を表示することができました

 

GKEに簡単なPHPアプリを手動デプロイする方法まとめ

今回は、簡単なPHPアプリをGKEにデプロイする方法について解説しました。

最後にもう一度手順を振り返りましょう。

  1. GCP上で必要なリソースを作成する(クラスタ、ノード、ロードバランサ、ファイアウォールルール)
  2. ルートディレクトリにappおよびdeployディレクトリを作成する
  3. appの下にindex.phpを作り、任意の文字を出力するPHPコードを記述する(アプリの作成)
  4. deployの下に作成したアプリをパッケージ(イメージ)化するためのDockerfileを作成する
  5. deploy用のDockerイメージを作る
  6. 作成したイメージに別名とタグを付ける(GCRにpushするための準備)
  7. 作成したイメージをプロジェクトのGCRにpushする
  8. デプロイするGKEのクラスタを指定する(クラスタの認証情報を取得する)
  9. Kubernetesのマニフェストファイルを作成する(deployment.yaml)
  10. deployment.yamlを適用させる(Podを作成する)
  11. Kubernetesのマニフェストファイルを作成する(service.yaml)
  12. service.yamlを適用させる(Podに対する外部からのエンドポイントを提供する)
  13. 作成したアプリが表示されるかを画面で確認する

 

今回はあくまでPHPでしたが、手順としてはLaravel等のフレームワークや別の言語のアプリをリリースする場合もほとんど同じです。

まずはこの記事を実践して理解を深めた上で、ご自身の環境やアプリに適用して頂けると嬉しいです。

 

最後まで読んで頂きありがとうございました。

COMMENT

メールアドレスが公開されることはありません。

CAPTCHA