Open

GKEでRailsを動かしてみる

18

GKEについて軽く学んでみるの続き。

  • 気になっている要素ごとにスレッドを作る
    • 読んだ記事や経過をつなげる
    • スレッド最上部に現段階での結論を書いて更新していく

とやってみる (かもしれない)。

デプロイ

  • 基本Cloud Buildを使って、ビルドとデプロイは分離する
    • ロールバックも簡単にできるように

ビルド

  • docker build
  • assetsをCloud Storageにアップロード
  • k8sのマニフェスト生成
  • マニフェストをCloud Storageにアップロード
  • デプロイをトリガーする

デプロイ

  • Cloud Storageからマニフェストをダウンロード
  • db:migrate を実行するJobのマニフェストをapply
  • db:migrate の完了/失敗を待つ
  • マニフェストのapply

未読記事メモ

マイグレーションについて

  • なるべくデプロイ前後どちらのschemaでも動くように書く
    • 無理な場合は場合はあきらめてダウンタイム
  • KubernetesのJobでdb:migrate したあとにデプロイする
    • Jobではサイドカーに cloud_sql_proxy を使うけど、 db:migrate が終了したら cloud_sql_proxy も終了するように、ちょっとしたハックが必要
    • Cloud Buildではmigration用Jobの完了/失敗を kubectl wait で待つ
      • https://stackoverflow.com/a/60286538/2468823
      • 時間がかかるmigrationの場合Cloud Buildのビルド時間が無駄に長くなってしまうので、migrationの完了は待たずにmigration用のJob完了時にデプロイを開始するように分割する改善が必要そう
  • ロールバックするには db:rollback ではなく、より宣言的な db:migrate VERSION=XXX を使う。
    • 新しいバージョンのコードがないとできないので、ここで使うコンテナのimageは Deployment と違いlatestを使う。db/migrate 下にファイルが追加されるような場合には問題ないけど、既存のファイルを更新するような変更が入ると問題になりうる。ただ、これはmigration自体の性質なので…

static assetsの扱い

IngressのバックエンドをCloud Storageにするのは今のところできなさそう?

Cloud Storageの前にHTTP(S) Load Balancingを置くなら、今はIngressとは別にTerraformで管理した方が良さそうか。

Cloud CDN + Cloud Storageと圧縮

GKEというかGCPの話。

Cloud CDN自体に圧縮の機能はないので、Cloud Storageで設定する必要がある。

Cloud CDN does not compress or decompress responses itself, but it can serve responses generated by your origin server that are compressed by using encodings such as gzip and DEFLATE.
Troubleshooting  |  Cloud CDN  |  Google Cloud

Cloud Storageは、metadataとしてContent-Encoding: gzipがついているときは以下のように配信する。

  • リクエストにAccept-Encoding: gzipがついている場合はそのまま配信
  • ついていない場合はdecompressしてContent-Encodingを除いて配信

Vary: Accept-Encodingはちゃんと勝手につく。
Transcoding of gzip-compressed files  |  Cloud Storage  |  Google Cloud

Cloud Storageにアップロードする際には以上のことを考慮して工夫しないといけない。

  1. 生成されたassetsのうち、gzipされているものを.gzを取り除いてgsutil -h "Content-Encoding: gzip" -h "Cache-Control: public, immutable, max-age=31536000" cp
  2. 関連するassetsを削除
  3. 残りのassetsをgsutil -h "Cache-Control: public, immutable, max-age=31536000" cp

ちょっと不便なところ

他のCDNを使うか、自分で管理するものを増やしたくはないけど間にnginxみたいなものを挟んだ方が便利そうだな…
もしくはpumaが入っているpodにnginxも入れて、Cloud Storageを使わない方がだいぶシンプルになるかも。

Secretsの管理

  • Podが立ち上がりまくるのでなければ、とりあえずKubenetestのSecretsは使わずに他でも使っているberglas + Secret Managerでもいいような気がするんだが、berglasのexamplesでのMutatingWebhookConfiguration がなんなのか、こいつ使わないといけない理由がわかっていない

未読記事メモ

logging

  • デフォルトでSTDOUTSTDERRがCloud Loggingに送られる
    • FluentDがDaemonSetで入っている
      • ConfigMapで設定をいじれる
    • 30日間保存される
  • Cloud LoggingからはCloud StorageやBigQueryにエクスポートできる

構造化ログ周りは記事にまとめた

https://zenn.dev/en30/articles/b48f48ff4710d9

RailsでCloud Loggingに適した構造化ログを出力する

requestSize, responseSize

The size of the HTTP request message in bytes, including the request headers and the request body.

で、rackのレベルだと簡単に取れなさそうでどうしたものか。

スケーリングについて

概要

  • Podに関する理想的な状態はyamlで指定する
    • kind: VerticalPodAutoscaler: スケールアップ。あるPodに対する理想的なCPU、Memoryの量。
    • kind: HorizontalPodAutoscaler: スケールアウト。理想的なPod数。
  • Podの理想的な状態を実現するために必要なNodeのスケールは
    • GKE Standardだと、node poolを作りCluster Autoscalerを有効にするとnode pool内のnode数調整を自動でやってくれる
    • GKE Autopilotだとnode poolの管理もなしで自動でやってくれる

Horizontal Pod autoscaling

  • スケールの基準
    • Actual resource usage: Podが使っているCPU、メモリ使用量
    • Custom metrics: Kubernetes objectによるmetrics
    • External metrics: cluster外のサービスによるmetrics
  • 複数のmetricsを使う場合は最大値でscaleされる

Custom / External Metricsでのオートスケール

参考

独自ドメインとHTTPS

Kubernetes外でやる必要があること

  • global static IP addressの予約
    • terraformのgoogle_compute_global_addressリソースで
  • 予約したIPアドレスを指すAレコードを登録

マニフェスト

以下でやっていること

  • Ingressを作って予約したstatic ipを指定
  • httpsのマネージド証明書を使う
  • httpの場合にhttpsにリダイレクト
apiVersion: networking.gke.io/v1
kind: ManagedCertificate
metadata:
  name: ingress-certificate
spec:
  domains:
    - $DOMAIN

---

apiVersion: networking.gke.io/v1beta1
kind: FrontendConfig
metadata:
  name: ingress-config
spec:
  redirectToHttps:
    enabled: true

---

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: web-ingress
  annotations:
    kubernetes.io/ingress.class: "gce"
    kubernetes.io/ingress.global-static-ip-name: $INGRESS_GLOBAL_STATIC_IP_NAME
    networking.gke.io/managed-certificates: ingress-certificate
    networking.gke.io/v1beta1.FrontendConfig: ingress-config

spec:
  backend:
    # ...

https://cloud.google.com/blog/products/networking/introducing-cloud-domains
Cloud Domainsというサービスができていたの知らなかった。

Since Cloud Domains uses Google Domains — Google’s internet domain name registration service — as the registrar, customers can access a wide range of registrar features through Google Domains management console.

Google Domainsに対する、GCP的なインターフェースができたという感じっぽい。

驚いたところ

ログインするとコメントできます