gcp
kubernetes

GKE でアプリケーションを動かすまでのメモ

Kubernetes2 Advent Calendar 2017 16日目です(10日遅れました..)
https://qiita.com/advent-calendar/2017/kubernetes2

GKE を触る機会があったので GKE を使って kubenetes クラスタを使ってサンプルアプリが動くまでのコマンドなどを(ほぼ自分用に)忘備録としてまとめてみました
初めて GCP+Kubenetes を使ってどっちもよくわからんて状態だったのでとりあえず最終的にココらへんのコマンドを使ったら動く所まで行ったというメモ程度な感じです

結構やることが多かったので結構コマンドをそのまま列挙する感じになってしまっています

やりたいこと

  • Kubenetes(GKE)
  • MySQL(Cloud SQL)

を使ったWEBアプリケーション環境の構築

プロジェクト作成 ~ gcloud コマンドに設定

GCP にはプロジェクト単位で課金をするアカウントを設定する必要があるようなので、あらかじめ以下のコマンドで課金を行うアカウントのIDの取得しておきます

gcloud beta billing accounts list

取得したらプロジェクトの作成と gcloud コマンドの設定を行う

gcloud projects create sample-app # プロジェクト作成
gcloud beta billing projects link sample-app --billing-account=XXXXXX-XXXXXX-XXXXXX # 決済アカウントと紐付け(XXXXXX-XXXXXX-XXXXXX の部分は先ほど取得したアカウントIDに置き換える)
gcloud config set project sample-app # gcloud コマンドで操作するデフォルトのプロジェクトを設定
gcloud config set compute/zone asia-northeast1-b # gcloud コマンドで利用するデフォルトのリージョンを設定

Cloud SQL

サンプルで作成するアプリケーションでは Cloud SQL の MySQL を利用してみようと思うので gcloud コマンドから Cloud SQL API の有効化します
GCP ではプロジェクト単位で各 API を利用する際に予め有効化しておく必要があるようです

https://cloud.google.com/service-management/enable-disable

gcloud service-management enable sqladmin.googleapis.com

有効化したので Cloud SQL インスタンスを起動

gcloud beta sql instances create sample-app \
  --tier db-f1-micro \
  --backup \
  --backup-start-time '19:00' \
  --database-version MYSQL_5_7 \
  --activation-policy ALWAYS \
  --enable-bin-log \
  --region asia-northeast1 \
  --gce-zone asia-northeast1-b \
  --maintenance-release-channel production \
  --maintenance-window-day MON \
  --maintenance-window-hour 18 \
  --storage-auto-increase \
  --storage-type SSD \
  --database-flags character_set_server=utf8

起動後に MySQL の root アカウントのパスワード設定やアプリケーション用ユーザーの作成を行います

root_password=$(pwgen -sy 16 1)
app_user_password=$(pwgen -sy 16 1)
gcloud sql instances set-root-password sample-app --password $root_password
gcloud beta sql users create app_user cloudsqlproxy~% --instance=sample-app --password=$app_user_password

サービスアカウント

Cloud SQL への接続にはいくつかの方法があるようだが GKE を利用する場合に Cloud SQL Proxy を使った方法が紹介されていたのでこの方法を使って接続できるようにしてみます
https://cloud.google.com/sql/docs/mysql/connect-container-engine

GKE のコンテナ上で Cloud SQL Proxy を利用するにはサービスアカウントが必要なようなので作成を行います
https://cloud.google.com/iam/docs/service-accounts

個人的な雑な理解としてはサービスアカウント=AWSでいう所のIAMロールぽく使えるものみたいな認識です

gcloud iam service-accounts create cloud-sql

作成したサービスアカウントの email を取得

gcloud iam service-accounts list

更にこのサービスアカウントを利用して Cloud SQL Proxy で接続できるようにするために Cloud SQL クライアント権限を付与

gcloud projects add-iam-policy-binding sample-app \
  --member='serviceAccount:cloud-sql@sample-app.iam.gserviceaccount.com' \
  --role='roles/cloudsql.client'

cloud-sql@sample-app.iam.gserviceaccount.com の部分を取得した email に差し替えて実行する

権限を付与したらこのサービスアカウントを利用するための秘密鍵を生成

gcloud iam service-accounts keys create ~/cloud-sql-key.json --iam-account cloud-sql@sample-app.iam.gserviceaccount.com

https://cloud.google.com/sql/docs/mysql/connect-admin-proxy#install
を参考に環境にあわせた Cloud SQL Proxy をインストールして Cloud SQL Proxy を起動する

cloud_sql_proxy \
  -instances=sample-app:asia-northeast1:sample-app=tcp:3306 \
  -credential_file="~/cloud-sql-key.json"

-credential_file="~/cloud-sql-key.json" で渡した json ファイルのサービスアカウントで Cloud SQL Proxy が立ち上がるようです

実際に接続できるかを確認してみる

mysql -h 127.0.0.1 -u sample-app -p$app_user_password

GKE

Cloud SQL 周りの設定ができたので次は GKE 関連の設定などをおこなっていきます
GKE を利用するために compute API を有効化します

gcloud service-management enable compute.googleapis.com

Kubenetes のクラスタを作成

gcloud container clusters create sample-app \
  --cluster-version=1.7.8 \
  --image-type=COS \
  --machine-type=g1-small \
  --num-nodes=3 \
  --node-labels=role=sample-app-node \
  --enable-cloud-logging \
  --enable-cloud-monitoring

更に kubectl コマンド用に以下で credentials を取得しておく

gcloud container clusters get-credentials sample-app --zone asia-northeast1-b --project sample-app
kubectl config use-context gke_sample-app_asia-northeast1-b_sample-app

Cloud SQL Proxy 向けの credentials を設定

kubectl create secret generic コマンドを使ってパスワードなど暗号化したいデータをコンテナに渡すことができるようなので設定しておく

kubectl create secret generic cloudsql-oauth-credentials --from-file=credentials.json='~/cloud-sql-key.json'

kubenates 関連情報の設定

ドメインを当てる場合に IP が切り替わると困るので static ip を取得して利用するようにする

gcloud compute addresses create sample-app-static-ip --global

deployment 生成

kubenetes では自作した docker イメージを利用するようにしてみたいので Container Registory API を有効化する

gcloud service-management enable containerregistry.googleapis.com

有効にしたらデプロイしたいコンテナアプリケーションを

gcloud docker -- push asia.gcr.io/sample-app

のようにして Container Registory に push する

push したイメージを利用して以下のような deployment の mainifest ファイルを作成

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: app
spec:
  minReadySeconds: 15
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 100%
      maxUnavailable: 0
  replicas: 2 # 作成する pod の数
  template:
    metadata:
      labels:
        app: app
    spec:
      containers:
        - image: asia.gcr.io/sample-app:latest # リリースするコンテナを設定
          name: app
          ports:
            - containerPort: 3000 # 起動するアプリケーションポートの番号
              name: app
          readinessProbe: # リクエスト送信可能かをチェックするヘルスチェックのパス情報を記載
            httpGet:
              path: /healthz
              port: 3000
            initialDelaySeconds: 60
            periodSeconds: 60
            timeoutSeconds: 5
            successThreshold: 1
            failureThreshold: 10
          livenessProbe: # コンテナが行きているかをチェックするヘルスチェックのパス情報を記載
            httpGet:
              path: /healthz
              port: 3000
            initialDelaySeconds: 60
            periodSeconds: 60
            timeoutSeconds: 5
            successThreshold: 1
            failureThreshold: 10
        - image: b.gcr.io/cloudsql-docker/gce-proxy:1.09 # Cloud SQL Proxy コンテナ
          name: cloudsql-proxy
          command: ["/cloud_sql_proxy",
                    "--dir=/cloudsql",
                    "-instances=sample-app:asia-northeast1:sample-app=tcp:3306", # 接続先情報 gcloud sql instances describe sample-app | grep connectionName のようにして取得できる
                    "-credential_file=/secrets/cloudsql-proxy/credentials.json"] # サービスアカウントの認証 json ファイル
          volumeMounts:
            - name: cloudsql-oauth-credentials
              mountPath: /secrets/cloudsql
              readOnly: true
            - name: ssl-certs
              mountPath: /etc/ssl/certs
            - name: cloudsql
              mountPath: /cloudsql
      volumes:
        - name: cloudsql-oauth-credentials
          secret:
            secretName: cloudsql-oauth-credentials # kubectl create secret generic で設定した秘密情報データを設定
        - name: ssl-certs
          hostPath:
            path: /etc/ssl/certs
        - name: cloudsql
          emptyDir:

作成したら

kubectl apply -f deployment.yml

のようにして kubenetes に設定を適用する
適用したら

kubectl get pods

のようにして manifest ファイルから起動した pod の情報を取得できる

NodePort Service を作成

次に NodePort の作成を行う

kubectl expose deployment app --target-port=3000 --type=NodePort

Ingress 作成

次に Ingress の作成を行う
deployment の時のように manifest ファイルを作成して適用する

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: app-ingress
  annotations:
    kubernetes.io/ingress.global-static-ip-name: sample-app-static-ip # gcloud compute addresses create の時の名前を指定する
spec:
  backend:
    serviceName: app
    servicePort: 3000
kubectl apply -f ingress.yaml

実行したら

watch kubectl get ingress

を実行して最終的に

NAME          HOSTS     ADDRESS          PORTS     AGE
app-ingress   *         11.111.111.111   80        1m

のように ADDRESS のIPアドレスが表示されるまで1~2分待つ
(何分も待っても表示されない場合何らかでうまく行ってない可能性が高い)

この時点で↑で表示されるIPアドレスにアクセスするとアプリケーションが表示されるはずです
うまく行っていれば対象IPにドメインを割り当てたりすれば良いかと思います
(ややこしかったのでSSL対応についてはスキップしてます)

感想

いきなり GCP も Kubenetes も慣れていない状態で GKE 触ろうとすると両方を覚えながらやらなきゃいけないので覚えることが多くてはじめに動かすところまで行くのが結構大変でした