8
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

KUSANAGI on GKE

Last updated at Posted at 2018-09-24

はじめに

GKE で WordPress を実装するために情報を探していたところ、KUSANAGI Runs on Docker というのが公開(まだベータ版みたいですが)されていましたので、この Docker イメージ(kusanagi-nginx、kusanagi-php7)をそのまま使って KUSANAGI を GKE 上に実装し、更には KUSANAGI へのアクセスに Let's Encrypt を利用して HTTPS 化したいと思います。

尚、本投稿でのコマンドの実行は、全て Google Cloud Shell 内で行っています。

実装イメージ図

KUSANAGI-image.png

クラスタ作成

GKE に リージョンクラスタ を作成します。
リージョンクラスタ はリージョン内の全ゾーン(--node-locations オプションでゾーンを指定した場合は、指定された全ゾーン)にノードが作成されるので、可用性を高めることができます。
また KUSANAGI のパフォーマンスを出来る限り落とさないよう、永続ディスクには GCE のリージョン永続ディスクRegional Persistent Disk)を利用します。

今回は東京リージョン(ap-northeast1)の内、2ゾーン(asia-northeast1-a、asia-northeast1-b)にまたがるクラスタを作成します。

クラスタ作成スクリプトの準備

クラスタ作成コマンドは、指定するパラメータの数が結構多いので、Shell スクリプト化します。

create-cluster.sh
#!/bin/bash

CLUSTER_ID=test-cluster                     #クラスタ名
MACHINE_TYPE=n1-standard-1                  #ノードのマシンタイプ(デフォルト:n1-standard-1)
REGION=asia-northeast1                      #クラスタを作成するリージョン
NUM_NODES=1                                 #ゾーン毎に配置するノード数
NODE_LOCATIONS=${REGION}-a,${REGION}-b      #ノードを配置するゾーン ※リージョン永続ディスクを使う場合は2ノードまで
NETWORK=default                             #ノードに接続されるVPC
SUBNETWORK=default                          #ノードに接続されるサブネット
CLUSTER_VERSION=$(gcloud beta container get-server-config --region ${REGION} --format='value(validMasterVersions[0])')

gcloud beta container clusters create ${CLUSTER_ID} \
    --cluster-version=${CLUSTER_VERSION} \
    --machine-type=${MACHINE_TYPE} \
    --region=${REGION} \
    --num-nodes=${NUM_NODES} \
    --node-locations=${NODE_LOCATIONS} \
    --network=${NETWORK} \
    --subnetwork=${SUBNETWORK} \
    --enable-autorepair

スクリプトの実行

クラスタ作成スクリプトを実行します。作成完了まで多少時間がかかります。

$ sh create-cluster.sh
Creating cluster test-cluster...done.
Created [https://container.googleapis.com/v1beta1/projects/gooday-development/zones/asia-northeast1/clusters/test-cluster].
To inspect the contents of your cluster, go to: https://console.cloud.google.com/kubernetes/workload_/gcloud/asia-northeast1/test-cluster?project=gooday-development
kubeconfig entry generated for test-cluster.
NAME          LOCATION         MASTER_VERSION  MASTER_IP      MACHINE_TYPE   NODE_VERSION  NUM_NODES  STATUS
test-cluster  asia-northeast1  1.10.7-gke.1    35.200.88.154  n1-standard-1  1.10.7-gke.1  2          RUNNING

Helm

GKE(K8s)で Let's Encrypt の証明書を管理(取得、自動更新)するには、K8s パッケージ(以降、Chart)の cert-manager を クラスタに用意します。
cert-manager をクラスタにデプロイするには、K8s Helm(以降、Helm)と呼ばれるパッケージマネージャを利用します。(Linux でいう yumapt-get、Python でいう pip と似た感じですかね)

Helm クライアントのインストール

Cloud Shell では Helm クライアントが用意されていないのでインストールする必要があります。

$ curl https://raw.githubusercontent.com/kubernetes/helm/master/scripts/get | bash

Tiller のインストール

Helm のサーバ部分は Tiller と呼ばれ、Helm クライアントからのリクエストの受付、公式 Chart リポジトリ(以降、Helm Repo)から Chart をクラスタにインストール(デプロイ)、インストール済 Chart のリリース監視等の役割を担います。
Tiller は自身のクラスタ内にデプロイする必要があり、Helm クライアントと Tiller 間は、クラスタ管理権限を持つ専用のサービスアカウント tiller を介して接続されます。

0001.jpg

サービスアカウント 'tiller' の作成

サービスアカウント tiller を、名前空間 kube-system に作成します。

$ kubectl create serviceaccount -n kube-system tiller

# サービスアカウント確認
$ kubectl describe sa tiller -n kube-system
Name:                tiller
Namespace:           kube-system
Labels:              <none>
Annotations:         <none>
Image pull secrets:  <none>
Mountable secrets:   tiller-token-XXXXX
Tokens:              tiller-token-XXXXX
Events:              <none>

cluster-admin ロールにバインド

サービスアカウント tiller に クラスタ管理者ロール cluster-admin を割り当てます。

$ kubectl create clusterrolebinding tiller-binding \
    --clusterrole=cluster-admin \
    --serviceaccount kube-system:tiller

# ロールバインド確認
$ kubectl describe clusterrolebinding tiller-binding
Name:         tiller-binding
Labels:       <none>
Annotations:  <none>
Role:
  Kind:  ClusterRole
  Name:  cluster-admin
Subjects:
  Kind            Name    Namespace
  ----            ----    ---------
  ServiceAccount  tiller  kube-system

Tiller のデプロイ

K8s クラスタに Tiller をデプロイします。
Tiller のデプロイには、kubectl コマンドではなく、 helm クライアントを用います。

$ helm init --service-account tiller

# デプロイの確認
$ kubectl get pod,deploy,svc  -n kube-system -l name=tiller
NAME                                READY     STATUS    RESTARTS   AGE
pod/tiller-deploy-895d57dd9-gmtjs   1/1       Running   0          1d

NAME                                  DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
deployment.extensions/tiller-deploy   1         1         1            1           1d

NAME                    TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)     AGE
service/tiller-deploy   ClusterIP   10.1.163.92   <none>        44134/TCP   1d

helm リポジトリのアップデート

利用可能な Chart の情報を、Helm Repo から Helm クライアントにキャッシュします。

$ helm repo update

証明書取得(DNS 認証方式)

Let's Encrypt では証明書を取得するにあたり、「自分がドメインの所有者かどうか」を認証してもらう方式として、次の3つがサポートされています。

  • HTTP-01
    Let’s Encryptの認証局からワンタイムトークンを発行してもらい、Webサーバに認証用ファイルを設置する。
    認証局からHTTP(80番ポート)でアクセスしてもらい、ワンタイムトークンと認証用ファイルとの妥当性を検証する。

  • TLS-SNI-01
    HTTP-01と同じ方法だが、HTTPS(443ポート)を使用する。

  • DNS-01
    Let’s Encryptの認証局から発行してもらったワンタイムトークンを対象ドメインのTXTレコードに登録することで検証する。

DNS による認証方式(DNS-01)だと、事前にWebサイトを準備する必要が無いので、今回は DNS プロバイダに Amazon Route53 を使い証明書を取得したいと思います。
※ Route53 の代わりに Cloud DNS を利用することもできます。

cert-manager インストール

Helm を用いて cert-manager を K8s クラスタにインストールします。

$ helm install \
    --name cert-manager \
    --namespace kube-system \
    stable/cert-manager

# Chart 確認
$ helm list
NAME            REVISION        UPDATED                         STATUS          CHART                   APP VERSION     NAMESPACE
cert-manager    1               Tue Sep 11 11:57:24 2018        DEPLOYED        cert-manager-v0.4.1     v0.4.1          kube-system

# デプロイ確認
$ kubectl get deploy -n kube-system
NAME                    DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
cert-manager            1         1         1            1           2m

AWS IAM ユーザー登録

cert-manager が Route63 を操作できるよう、AWS 側にて次のポリシーをアタッチした IAM ユーザーを作成します。
作成後は、Access Key と Secret Access Key を控えておきます。
※ IAM ユーザーの作成手順は割愛します。

ポリシー
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": "route53:GetChange",
            "Resource": "arn:aws:route53:::change/*"
        },
        {
            "Effect": "Allow",
            "Action": "route53:ChangeResourceRecordSets",
            "Resource": "arn:aws:route53:::hostedzone/*"
        },
        {
            "Effect": "Allow",
            "Action": "route53:ListHostedZonesByName",
            "Resource": "*"
        }
    ]
}

AWS Secret Access Key 登録

控えておいた Secret Access Key を Base64 エンコード (echo -n '<Secret Access Key>' | base64)し、その値を K8s クラスタの Secret リソースに登録します。
尚、Secret Access Key の値を持った Secret リソースは、cert-manager と同一 namespace(kube-system)に作成する必要がある点に注意してください。

Manifest ファイル作成

secret.yaml
apiVersion: v1
kind: Secret
metadata:
  name: prod-route53-credentials-secret
  namespace: kube-system
type: Opaque
data:
  secret-access-key: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

Secret 作成

$ kubectl apply -f secret.yaml

# Secret 確認
$ kubectl describe secret prod-route53-credentials-secret -n kube-system
Name:         prod-route53-credentials-secret
Namespace:    kube-system
Labels:       <none>
Annotations:
Type:         Opaque

Data
====
secret-access-key:  40 bytes

Issuer/ClusterIssuer 作成

認証局(Let's Encrypt)と DNS プロバイダー(Amazon Route53)の情報を Issuer/ClusterIssuer リソースとして作成します。
尚、namespace 毎に利用可能なリソースは Issuer、K8s クラスタ全体で利用可能なリソースは ClusterIssuer で作成します。
今回は ClusterIssuer リソースとして作成します。

Manifest ファイル作成

cluster-issuer.yaml
apiVersion: certmanager.k8s.io/v1alpha1
kind: ClusterIssuer
metadata:
  name: letsencrypt-prod

spec:
  acme:
    server: https://acme-v02.api.letsencrypt.org/directory
    email: myname@example.com #TODO: Your email address
    privateKeySecretRef:
      name: letsencrypt-prod
    http01: {}
    dns01:
      providers:
      - name: prod-dns
        #couddns: #for Google Cloud DNS
        #  ・・・
        route53:
          accessKeyId: AKXXXXXXXXXXXXXXXXXX #TODO: Your aws access key
          region: ap-northeast-1 #TODO: Your region of amazon route53
          secretAccessKeySecretRef:
            name: prod-route53-credentials-secret
            key: secret-access-key

ClusterIssuer リソース作成

$ kubectl apply -f cluster-issuer.yaml

# ClusterIssuer リソース確認
$ kubectl describe clusterissuer letsencrypt-prod
Name:         letsencrypt-prod
Namespace:
Labels:       <none>
Annotations:  kubectl.kubernetes.io/last-applied-configuration={"apiVersion":"certmanager.k8s.io/v1alpha1","kind":"ClusterIssuer","metadata":{"annotations":{},"name":"letsencrypt-prod","namespace":""},"spec":{"acme...
API Version:  certmanager.k8s.io/v1alpha1
Kind:         ClusterIssuer
Metadata:
  Cluster Name:
  Creation Timestamp:  2018-09-12T02:08:04Z
  Generation:          1
  Resource Version:    7907617
  Self Link:           /apis/certmanager.k8s.io/v1alpha1/clusterissuers/letsencrypt-prod
  UID:                 af2856dd-b630-11e8-9a5d-42010a92004d
Spec:
  Acme:
    Dns 01:
      Providers:
        Name:  prod-dns
        Route 53:
          Access Key ID:   AKXXXXXXXXXXXXXXXXXX
          Hosted Zone ID:
          Region:          ap-northeast-1
          Secret Access Key Secret Ref:
            Key:   secret-access-key
            Name:  prod-route53-credentials-secret
    Email:         myname@example.com
    Http 01:
    Private Key Secret Ref:
      Key:
      Name:  letsencrypt-prod
    Server:  https://acme-v02.api.letsencrypt.org/directory
Status:
  Acme:
    Uri:  https://acme-v02.api.letsencrypt.org/acme/acct/99999999
  Conditions:
    Last Transition Time:  2018-09-12T02:08:05Z
    Message:               The ACME account was registered with the ACME server
    Reason:                ACMEAccountRegistered
    Status:                True
    Type:                  Ready
Events:                    <none>

TLS 証明書の取得

Certificate リソースにより TSL 証明書を取得します。

Manifest ファイル作成

Let's Encrypt はSAN(Subject Alternative Name、サブジェクト代替名)対応の証明書を発行することができます。例えば www.example.comexample.com と2つのホスト名に対応した証明書を作成することができます。
またワイルドカード(*)証明書にも対応しています。

certificate.yaml
apiVersion: certmanager.k8s.io/v1alpha1
kind: Certificate
metadata:
  name: cert-kusanagi
spec:
  secretName: cert-kusanagi-tls
  issuerRef:
    name: letsencrypt-prod
    kind: ClusterIssuer
  commonName: 'kusanagi.example.com'
  dnsNames:
    - 'www.kusanagi.example.com'
    - 'kusanagi.example.com'
  acme:
    config:
      - dns01:
          provider: prod-dns
        domains:
          - 'kusanagi.example.com'

Certificate リソース作成(証明書取得)

証明書を Manifest ファイルを元に取得します。kubectl describe コマンドで出力された Eventcert-manager Certificate issued successfully が出力されたら作成完了です。
証明書に追加取得が必要な場合は、Certificate リソース を作成することで簡単に追加取得することができます。

$ kubectl apply -f certificate.yaml

# Certificate 確認
$ kubectl describe certificate cert-kusanagi

・・・

Events:
  Type    Reason          Age   From          Message
  ----    ------          ----  ----          -------
  Normal  CreateOrder     3m    cert-manager  Created new ACME order, attempting validation...
  Normal  DomainVerified  1m    cert-manager  Domain "kusanagi.example.com" verified with "dns-01" validation
  Normal  IssueCert       47s   cert-manager  Issuing certificate...
  Normal  CertObtained    45s   cert-manager  Obtained certificate from ACME server
  Normal  CertIssued      45s   cert-manager  Certificate issued successfully

尚、取得処理の最中に cert-manager が Route53 のゾーン情報に _acme-challenge.kusanagi.example.com というホスト名の TXT レコードを追加し、その値(Value)に Let's Encrypt 認証トークンがセットしていることが確認できます。

TLS 証明書、秘密鍵の確認

取得した TLS 証明書(tls.crt)と秘密鍵(tls.key)が Secret リソースに保存されていることを確認します。

$ kubectl describe secret cert-kusanagi-tls
Name:         cert-kusanagi-tls
Namespace:    default
Labels:       certmanager.k8s.io/certificate-name=cert-kusanagi
Annotations:  certmanager.k8s.io/alt-names=kusanagi.example.com
              certmanager.k8s.io/common-name=kusanagi.example.com
              certmanager.k8s.io/issuer-kind=ClusterIssuer
              certmanager.k8s.io/issuer-name=letsencrypt-prod

Type:  kubernetes.io/tls

Data
====
tls.crt:  3846 bytes  #TLS証明書
tls.key:  1679 bytes  #秘密鍵

これで証明書の取得は完了です。
更に、TLS 証明書の有効期限の30日前になると、cert-manager が 認証局(Let's Encrypt)に対し自動更新してくれます。

StorageClassリソースの作成

リージョン永続ディスクの StorageClass を作成します。
StorageClass を作成することで、後述の PersistentVolumeClaim からリージョン永続ディスクをアサインすることが出来るようになります。

Manifest ファイルの準備

storage-class.yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: regpd
provisioner: kubernetes.io/gce-pd
parameters:
  type: pd-standard  #pd-standard(HDD)|pd-ssd(SSD)
  replication-type: regional-pd
  zones: asia-northeast1-a, asia-northeast1-b

StorageClass 作成、確認

$ kubectl apply -p storage-class.yaml
storageclass.storage.k8s.io/regpd created

#StorageClass 確認
$ kubectl describe sc regpd
Name:            regpd
IsDefaultClass:  No
Annotations:     kubectl.kubernetes.io/last-applied-configuration={"apiVersion":"storage.k8s.io/v1","kind":"StorageClass","metadata":{"annotations":{},"name":"regpd","namespace":""},"parameters":{"replication-type":"regional-pd","type":"pd-standard","zones":"asia-northeast1-a, asia-northeast1-b"},"provisioner":"kubernetes.io/gce-pd"}

Provisioner:           kubernetes.io/gce-pd
Parameters:            replication-type=regional-pd,type=pd-standard,zones=asia-northeast1-a, asia-northeast1-b
AllowVolumeExpansion:  <unset>
MountOptions:          <none>
ReclaimPolicy:         Delete
VolumeBindingMode:     Immediate
Events:                <none>

Cloud SQL アクセス用サービスアカウントキーの取得

Pod から Cloud SQL を利用するため、アクセス用のサービスアカウントキー を取得します。

サービスアカウント 'cloudsql' の作成

$ gcloud iam service-accounts create cloudsql --display-name="cloudsql"

サービスアカウントへ役割(Cloud SQL クライアント)付与

$ gcloud projects add-iam-policy-binding <Project ID> \
    --member="serviceAccount:cloudsql@<Project ID>.iam.gserviceaccount.com" \
    --role="roles/cloudsql.client"

サービスアカウントキーの取得

カレントディレクトリ内に credentials.json というキーファイル名でサービスアカウントキーを保存します。

$ gcloud iam service-accounts keys create ./credentials.json --iam-account cloudsql@<Project ID>.iam.gserviceaccount.com

Secret に登録

サービスアカウントキーを Secret に登録します。
ここで登録した Secret service-account-token を Pod 内の Cloud SQL Proxy コンテナが読み取り、Cloud SQL へ接続することができます。

$ kubectl create secret generic service-account-token --from-file=credentials.json=./credentials.json

$ kubectl describe secret service-account-token
Name:         service-account-token
Namespace:    default
Labels:       <none>
Annotations:  <none>

Type:  Opaque

Data
====
credentials.json:  2337 bytes

Cloud SQL

KUSANAGI のバックエンド DB を Cloud SQL に作成します。

もし既に MySQL インスタンスが存在するなら、そのインスタンスを利用することもできます。
(その場合、インスタンスの作成部分は飛ばし、データベースの作成から行ってください)

インスタンス作成スクリプト

Cloud SQL インスタンスを作成する Shell スクリプトを用意します。

create-cloudsql.sh
#!/bin/bash

INSTANCE_ID=kusanagi            #インスタンスID
REGION=asia-northeast1          #インスタンスを作成するリージョン
DATABASE_VERSION=MYSQL_5_7      #データベースバージョン
NUMBER_CPUS=1                   #割当てvCPU数
MEMORY_SIZE=3840MiB             #割当てメモリ容量
STORAGE_TYPE=HDD                #ストレージの種類(HDD|SSD)
STORAGE_SIZE=10GB               #ストレージの容量(GB単位)

gcloud beta sql instances create ${INSTANCE_ID} \
    --region=${REGION} \
    --database-version=${DATABASE_VERSION} \
    --cpu=${NUMBER_CPUS} \
    --memory=${MEMORY_SIZE} \
    --storage-type=${STORAGE_TYPE} \
    --storage-size=${STORAGE_SIZE} \
    --storage-auto-increase

インスタンス作成

インスタンス作成スクリプトを実行します。しばらく待つとインスタンスが作成されます。

$ sh create-cloudsql.sh
Creating Cloud SQL instance...done.
Created [https://www.googleapis.com/sql/v1beta4/projects/gooday-development/instances/kusanagi].
NAME      DATABASE_VERSION  LOCATION           TIER              ADDRESS        STATUS
kusanagi  MYSQL_5_7         asia-northeast1-c  db-custom-1-3840  35.XXX.XXX.XXX RUNNABLE

データベース作成

インスタンス内にデータベース(kusanagi)を作成します。

$ gcloud sql databases create kusanagi --instance=kusanagi

ユーザー作成

データベース接続ユーザー(kusanagi)を作成します。

$ gcloud sql users create kusanagi --host=% --instance=kusanagi --password=<PASSWORD>

外部IPアドレスの予約

KUSANAGI 公開用に、外部 IP アドレス(グローバル IP アドレス)を予約します。
今回は kusanagi-ip という名前で予約しました。

$ gcloud compute addresses create kusanagi-ip --global

$ gcloud compute addresses list --filter="name=('kusanagi-ip')"
NAME         REGION  ADDRESS        STATUS
kusanagi-ip          35.201.XXX.XXX RESERVED

Route53 に A レコードを追加

Amazon Route53 に A レコード kusanagi.example.comexample.com の部分は実際のドメイン名に置換してください)を追加し、名前解決ができるようにします。
その際 A レコードの値(Value)には、前述で予約した 外部 IP アドレス(35.201.XXX.XXX)を入力してください。
※ Route53 への A レコード追加方法は割愛します。

KUSANAGI デプロイ

ここまでの手順で前準備が整いましたので、いよいよ KUSANAGI を GKE にデプロイします。

KUSANAGI イメージを GCR へアップロード

KUSANAGI の Docker イメージのうち、kusanagi-nginxkusanagi-php7 を Container Registry(GCR)にアップロードします。

# kusanagi-nginx イメージのダウンロード、タグ付け、GCR へアップロード
$ docker pull primestrategy/kusanagi-nginx:1.10.0-1
$ docker tag primestrategy/kusanagi-nginx:1.10.0-1 asia.gcr.io/gooday_internal_system/kusanagi-nginx:1.10.0-1
$ gcloud docker -- push asia.gcr.io/gooday_internal_system/kusanagi-nginx:1.10.0-1

# kusanagi-php7 イメージのダウンロード、タグ付け、GCR へアップロード
$ docker pull primestrategy/kusanagi-php7:7.0.6-1
$ docker tag primestrategy/kusanagi-php7:7.0.6-1 asia.gcr.io/gooday_internal_system/kusanagi-php7:7.0.6-1
$ gcloud docker -- push asia.gcr.io/gooday_internal_system/kusanagi-php7:7.0.6-1

KUSANAGI デプロイ

KUSANAGI 環境をデプロイします。
今回は1つの Manifest ファイルで次の環境を実装しています。

  • PersistentVolumeClaim(/home/kusanagi/etc/kusanagi.d/etc/nginx/conf.d
  • Deployment(kusanagi-nginxkusanagi-php7cloudsql-proxy
  • Service(NortPort)
  • Ingress

Manifest ファイルの準備

deploy-kusanagi.yaml
# /home/kusanagi, /etc/kusanagi.d, /etc/nginx/conf.d データ永続用PVC
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: pvc-kusanagi-data
  namespace: default
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 10Gi
  storageClassName: regpd
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  annotations:
    deployment.kubernetes.io/revision: "1"
  generation: 1
  labels:
    run: kusanagi
  name: kusanagi
  namespace: default
spec:
  replicas: 1
  selector:
    matchLabels:
      run: kusanagi
  template:
    metadata:
      labels:
        run: kusanagi
    spec:
      containers:
      - image: asia.gcr.io/gooday_internal_system/kusanagi-nginx:1.10.0-1
        imagePullPolicy: Always
        name: kusanagi-nginx
        env:
        - name: PROFILE
          value: "kusanagi_html"           #KUSANAGI プロファイル名
        - name: FQDN
          value: "kusanagi.example.co.jp"  #KUSANAGI ホスト名(FQDN)
        - name: WPLANG
          value: "ja"                      #WordPress の言語
        - name: BCACHE
          value: "off"                     #生成ページのキャッシュ(on|off)
        - name: FCACHE
          value: "off"                     #FastCGIレスポンスのキャッシュ(on|off)
        ports:
        - containerPort: 80
          protocol: TCP
        - containerPort: 443
          protocol: TCP
        readinessProbe:  #ヘルスチェック設定(Ingressが行うヘルスチェックの設定に反映)
          httpGet:
            path: /readme.html
            port: 80
          initialDelaySeconds: 5
          periodSeconds: 10
        volumeMounts:
        - mountPath: "/home/kusanagi"
          name: kusanagi-data
          subPath: home
        - mountPath: "/etc/nginx/conf.d"
          name: kusanagi-data
          subPath: nginx-confd
        - mountPath: "/etc/kusanagi.d"
          name: kusanagi-data
          subPath: kusanagid
        resources:
          requests:
            cpu: 20m
      - image: asia.gcr.io/gooday_internal_system/kusanagi-php7:7.0.6-1
        imagePullPolicy: Always
        name: kusanagi-php7
        ports:
        - containerPort: 9000
          protocol: TCP
        volumeMounts:
        - mountPath: "/home/kusanagi"
          name: kusanagi-data
          subPath: home
        - mountPath: "/etc/nginx/conf.d"
          name: kusanagi-data
          subPath: nginx-confd
        - mountPath: "/etc/kusanagi.d"
          name: kusanagi-data
          subPath: kusanagid
        resources:
          requests:
            cpu: 20m
      - image: b.gcr.io/cloudsql-docker/gce-proxy:latest
        imagePullPolicy: Always
        name: cloudsql-proxy
        command:
        - /cloud_sql_proxy
        - -dir=/cloudsql
        - -instances=<Project ID>:asia-northeast1:kusanagi=tcp:3306  #Cloud SQL インスタンス接続名
        - -credential_file=/credentials/credentials.json
        volumeMounts:
        - mountPath: /cloudsql
          name: cloudsql
        - mountPath: /etc/ssl/certs
          name: ssl-certs
        - mountPath: /credentials    #サービスアカウントキーのマウント
          name: service-account-token
      hostAliases:        #ホストエイリアスの設定
      - hostnames:        #  Nginx がバックエンドのコンテナ kusanagi-php7 (FastCGI) に対し
        - php             #  'php' というホスト名で Proxy している為
        ip: 127.0.0.1     #  各コンテナの /etc/hosts に追加される
      volumes:
      - name: kusanagi-data
        persistentVolumeClaim:
          claimName: "pvc-kusanagi-data"
      - name: cloudsql
        emptyDir:
      - name: ssl-certs
        hostPath:
          path: /etc/ssl/certs
      - name: service-account-token  #サービスアカウントキーの Secret
        secret:
          secretName: service-account-token
---
apiVersion: v1
kind: Service
metadata:
  name: kusanagi-nodeport
  namespace: default
  labels:
    run: kusanagi-nodeport
spec:
  type: NodePort
  ports:
  - port: 80
    protocol: TCP
    targetPort: 80
  selector:
    run: kusanagi
---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: kusanagi-ingress
  annotations:
    #kubernetes.io/ingress.allow-http: "false"  #HTTPSのみ許可する場合はコメントアウトを外す
    kubernetes.io/ingress.global-static-ip-name: "kusanagi-ip"  #外部 IP アドレス名
    kubernetes.io/ingress.class: "gce"
    kubernetes.io/tls-acme: "true"
spec:
  tls:
  - secretName: cert-kusanagi-tls #TLS 証明書、秘密鍵が保存されている Secret 名
  backend:
    serviceName: kusanagi-nodeport  #NodePort サービス名
    servicePort: 80  #NodePortの待受ポート

デプロイ

$ kubectl apply -f deploy-kusanagi.yaml

Ingress 確認

Ingress の準備が完了(ヘルスチェックの完了)するまで暫く待ちます。(結構長い時間がかかる場合があります)

Annotations: にある ingress.kubernetes.io/backends: のステータスが Unknown から HEALTHY に変われば準備完了です。

$ kubectl describe ingress kusanagi-ingress
Name:             kusanagi-ingress
Namespace:        default
Address:          130.211.XXX.XXX
Default backend:  kusanagi-nodeport:80 (10.36.0.14:80)
TLS:
  cert-kusanagi-tls terminates
Rules:
  Host  Path  Backends
  ----  ----  --------
  *     *     kusanagi-nodeport:80 (10.36.0.14:80)
Annotations:
  kubernetes.io/tls-acme:                            true
  ingress.kubernetes.io/backends:                    {"k8s-be-30098--49f84941322af08b":"HEALTHY"}  #'Unknown' から 'HEALTHY' になるまで待つ 
  ingress.kubernetes.io/https-forwarding-rule:       k8s-fws-default-kusanagi-ingress--49f84941322af08b
  ingress.kubernetes.io/https-target-proxy:          k8s-tps-default-kusanagi-ingress--49f84941322af08b
  ingress.kubernetes.io/ssl-cert:                    k8s-ssl-d11f06e1315aac38-e5a1656857d9445c--49f84941322af08b
  ingress.kubernetes.io/url-map:                     k8s-um-default-kusanagi-ingress--49f84941322af08b
  ingress.kubernetes.io/forwarding-rule:             k8s-fw-default-kusanagi-ingress--49f84941322af08b
  ingress.kubernetes.io/target-proxy:                k8s-tp-default-kusanagi-ingress--49f84941322af08b
  kubectl.kubernetes.io/last-applied-configuration:  {"apiVersion":"extensions/v1beta1","kind":"Ingress","metadata":{"annotations":{"kubernetes.io/ingress.class":"gce","kubernetes.io/ingress.global-static-ip-name":"kusanagi-ip","kubernetes.io/tls-acme":"true"},"name":"kusanagi-ingress","namespace":"default"},"spec":{"backend":{"serviceName":"kusanagi-nodeport","servicePort":80},"tls":[{"secretName":"cert-kusanagi-tls"}]}}

  kubernetes.io/ingress.class:                  gce
  kubernetes.io/ingress.global-static-ip-name:  kusanagi-ip
Events:                                         <none>

KUSANAGI 初期設定

ブラウザから http://kusanagi.example.com にアクセスし、次の手順で初期設定を行います。

※初期設定の際、HTTPSでアクセスすると CSS が読み込まれない為、初期設定の間は HTTP でアクセスします。

さあ、始めましょう! をクリックします。
screencapture-kusanagi-kaho-enterprise-co-jp-wp-admin-setup-config-php-2018-09-21-13_34_54.png

データベース名ユーザー名パスワードデータベースのホスト名に Cloud SQL の接続情報を入力して**送信**をクリックします。
※注
データベースのホスト名には localhost がデフォルトで表示されていますが、127.0.0.1 を入力してください。
kusanagi-php7 のコンテナ内からは、名前解決ができないようです。(調査中)
screencapture-kusanagi-kaho-enterprise-co-jp-wp-admin-setup-config-php-2018-09-21-13_36_09.png

**インストール実行**をクリックします。
screencapture-kusanagi-kaho-enterprise-co-jp-wp-admin-setup-config-php-2018-09-21-13_37_10.png

各項目に任意の情報を入力して**WordPress をインストール**をクリックします。
**※ パスワードは必ず控えておきましょう。
screencapture-kusanagi-kaho-enterprise-co-jp-wp-admin-install-php-2018-09-21-13_38_28.png

**ログイン**をクリックします。
screencapture-kusanagi-kaho-enterprise-co-jp-wp-admin-install-php-2018-09-21-13_38_51.png

ログインページが表示されたら、一旦ブラウザを閉じます。

WordPress 設定ファイルの変更

このまま HTTPS でアクセスすると、CSS や JS が読み込まれない為、WordPress 設定ファイル(wp-config.php)に細工をします。

コンテナにログイン

#Pod 名確認
$ kubectl get pod
NAME                        READY     STATUS    RESTARTS   AGE
kusanagi-XXXXXXXXXX-XXXXX   3/3       Running   0          29m

# Pod 内のコンテナ kusanagi-nginx へログイン
$ kubectl exec -it kusanagi-XXXXXXXXXX-XXXXX -c kusanagi-nginx /bin/bash

WordPress 設定ファイル編集

wp-config.php をエディタで開きます。

# vi /home/kusanagi/kusanagi_html/DocumentRoot/wp-config.php

次の追加(ここから)追加(ここまで)間の5行を、該当箇所に追加して保存します。
※実際にはマルチバイト(日本語)部分が文字化けしていますが、構わず追加しましょう。

wp-config.php
・・・
#define('FORCE_SSL_ADMIN', true);
#define('WP_CACHE', true);

/* 追加(ここから) */
if($_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https') {
  $_SERVER['HTTPS'] = 'on';
  $_ENV['HTTPS'] = 'on';
}
define('FS_METHOD', 'direct');
/* 追加(ここまで) */

/* 編集が必要なのはここまでです ! WordPress でブログをお楽しみください。 */
・・・

HTTPS 確認

ブラウザを開き、https://kusanagi.wxample.com/wp-admin へアクセスします。

ユーザー名パスワードを入力して**ログイン**をクリックします。
screencapture-kusanagi-kaho-enterprise-co-jp-wp-login-php-2018-09-21-13_39_09.png

ダッシュボードが表示され、KUSANAGI を利用できる状態になります。
FireShot Capture 16 - ダッシュボード ‹ MySite — WordPress - http___kusanagi.kaho-enterprise.co.jp_wp-admin_.png

Tips

HSTS ※2018.09.27 追記

Cloud CloadBalancer は HTTP接続を HTTPS へリダイレクトする機能を持たないため、次のような方法でリダイレクトを実装する必要があります。

  • Cloud LoadBalancer の代わりに Nginx Controller (Helm Chart) を利用する。(ssl-redirect パラメータ)
  • KUSANAGI Nginx 側でリダイレクトする。

今回は比較的手軽な後者の方法を利用することにします。

ヘルスチェック設定

Cloud LoadBalancer からのヘルスチェックに対し、HTTP ステータスコード 200 を返すよう設定します。
Pod 内の kusanagi-nginx コンテナへログインし、次のような /etc/nginx/confd/default.conf を作成します。

/etc/nginx/conf.d/default.conf
server {
    listen 80 default_server;
    access_log off;
    error_log /var/log/nginx/error.log warn;

    location / {
        add_header Content-Type "text/plain";
        return 200 "ok";
    }
}

リダイレクト設定

HTTP アクセスされた場合、HTTPS の URL へリダイレクトさせるよう、/etc/nginx/conf.d/<KUSANAGI の PROFILE名>_http.conf を編集します。

/etc/nginx/conf.d/kusanagi_html_http.conf
...
        access_log ...;
        error_log ...;

        # TLS Redirect
        if ($http_x_forwarded_proto != https) {    #追加
            return 301 https://$host$request_uri;  #追加
        }                                          #追加
...

Nginx リロード

kill コマンドで設定をリロードします。

# kill -HUP `cat /run/nginx.pid`
8
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?