Coursera の "App Deployment, Debugging, and Performance" を受講したメモ (Cloud Build, App Engine, Cloud Monitoring, etc)

Coursera の [App Deployment, Debugging, and Performance
](https://www.coursera.org/learn/app-deployment-debugging-performance) を受講した。知らなかった知識を箇条書きにしているので、ちゃんと階層化できてないかもしれない。


## 関連記事

- [Getting Started With Application Development(Datastore, Bigtable, Cloud Spanner, etc)](https://qiita.com/kudojp/items/9891c8491f8bea264cd0) 
- [Securing and Integrating Components of your Application(IAM, IAP, Pub/Sub, Cloud Endpoint, Cloud Function, etc)](https://qiita.com/kudojp/items/08103d1e8fdb565cb27b)
- 🌟[App Deployment, Debugging, and Performance(Cloud Build, App Engine, Cloud Monitoring, etc)](https://qiita.com/kudojp/items/9e0795219c81e848febe)


## Cloud Build


### cloud buildで単一のdockerイメージのビルドとプッシュ

- ディレクトリにDockerfileを用意する
- `gcloud builds submit --tag gcr.io/${GOOGLE_CLOUD_PROJECT}/my_image .`とか

### cloud buildでビルドパイプライン構築し、複数のdockerイメージのビルドとプッシュ

(様々なリポジトリやクラウド ストレージ スペースからソースコードをインポートし、仕様に合わせてビルドを実行し、Docker コンテナや Java アーカイブなどのアーティファクトを生成できます)

1. yamlファイル(`cloudbuild.yaml`とか)でbuild pipelineを指定する
   - この中でbuildのstepを定義する。(docker imageをビルドする、というステップもある)
   - １ステップ１コンテナ
      - step name = そのステップを実行するコンテナ名を指定。(これをpullしてくる)
      - step image = そのステップで作成されるコンテナイメージ名を指定。(この名でpushされる?)
      - ~~この時に使われるコンテナイメージは、Cloud buildersと呼ばれるイメージの中から選択する。~~
        - ~~例えば、gke-deploy builderを使用すれば、gke-deployコマンド(kubectlコマンドのwrapper)を使用した、gke clusterへのデプロイができる。~~
   - 生成物(artifact)は /workspace レポジトリに保存され、次のstepで使用される。
2. `gcloud builds submit --config cloudbuild.yaml .`を実行。

以下、cloudbuilld.yamlの例。

```yaml
steps:
- name: 'gcr.io/cloud-builders/docker'　　　# このコンテナ(今回はcloud builder)をpullして、この中で実行。
  args: ['build', '-t', 'gcr.io/my-project/my-image', '.']  # コンテナで指定されたエントリポイントの引数となる。つまり　docker build -t ....が実行される。
  timeout: 500s 
- name: 'gcr.io/cloud-builders/docker'
  args: ['push', 'gcr.io/my-project/my-image']  # docker push ....が実行される。(artifactが前のstepから引き継がれている??)
- name: 'gcr.io/cloud-builders/kubectl'
  args: ['set', 'image', 'deployment/my-deployment', 'my-container=gcr.io/my-project/my-image']  # kubectl set ...が実行される。
  env:
  - 'CLOUDSDK_COMPUTE_ZONE=us-east4-b'
  - 'CLOUDSDK_CONTAINER_CLUSTER=my-cluster'
options:
    machineType: 'N1_HIGHCPU_8'
timeout: 660s
tags: ['mytag1', 'mytag2']
images: ['gcr.io/my-project/myimage']     # 今回のビルドパイプラインで完成したイメージはこの名前でGCRにpushされる
```

また、ビルドの過程で聖生物が作成される場合は、`artifact: xxx`を指定することで Cloud Storage に保存ができる。

## Deployment Manager

See: [Cloud Deployment Managerを少し触ってみて感じた事](
https://qiita.com/shotaTsuge/items/bb995f4e2f3f6ae9d12d)

- コンテナが走るVM, GCPのリソースの上限ををファイルで**declarativeに**指定できる。
    - 指定できるリソースは、Instance, Autoscaling Group, Firewall, Network, Load Balancingなど。
    - Chef, Puppet, Ansible and Terraform でも似たようなことができる。
- configurationのsubsetをchunkとして作成してそれを再利したり、configurationのtemplateに(pythonのjinjaを使って)値を流し込むことができる。
- startup scriptsによって、依存する処理を先に実行できる。
- deploymentをdeleteすると、そのdeploymentによって作られたインスタンスはstopされる。

実行コマンドは、`$ gcloud deployment-manager deployments update ......`みたいなの。

See: https://dev.classmethod.jp/articles/gcp-cloud-deployment-manager


---

# Application Execution Environments


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/534442/cac21f17-ce77-0eee-6790-6be650b40a0d.png)

## Google Cloud Dataflow

- Apache Beam SDKs の Java API か Python API を用いて定義したパイプラインをGCP上で走らせることができる。
    - 要は、平行にデータ処理パイプラインを走らせることができる。
    - 内部では、GCPの他のサービスを使える。例えば、
        - events ingestion using Cloud Pub/Sub
        - Data Warehousing using BigQuery
        - Machine Learning APIs
- workloadに合わせてリソースをautoscalingしてくれる。


See: [GCP の Cloud Dataproc と Cloud Dataflow](https://qiita.com/kudojp/items/88048305df362bc74e57)

## Cloud Functions

- サーバーレスでコードを実行できる。
- 発動のtriggerは以下の２種類
    - event driven。例えば、
        - `an object being added to a cloud storage bucket`
        - `a message being published to a Pub/Sub topic`
    - web hooks。
- 対応言語は、Go, Java, Python, Node.js
- 100 milliseconds単位で課金される。


## App Engine

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/534442/587542e9-60f8-ca34-757e-2a5cbf02b205.png)
より詳細な比較は、See: https://cloud.google.com/appengine/docs/flexible/go/flexible-for-standard-users?hl=ja

- App Engine stdでは、組み込みの google.appengine API を介して Datastore などのサービスにアクセスする
    - Clint libraryも使える。
- App Engine flexでは Docker コンテナが走っている。
- App Engine flexでは、`gcloud app deploy`コマンドを実行することで、以下ができる。
    - アプリケーションのdeploy
    - source code を Cloud Storage へアップロード
    - **builds a Docker image for your application with the runtime environment**
        - これゆえに将来的に、GKEやGCEに用意に移行できる。
    - pushes the image to Container Registry
    - sets up a load balancer and runs your application in three zones
    - launches and auto scales Compute Engine instances

- Blue/green, Traffic-splitting, Rolling and Canary release ができる。

- 以下の場合はGKEやGCEを考えるべし。
    - HTTP or HTTPS以外のネットワークプロトコルを使いたい場合
    - データをpersistent disksに書き込みたい場合
        -  volumeをtmpfsに置かれる(が、もちろんこれはメモリ上にのっているので永続化はされない)
    - traffic が、spikyあるいはvery lowである場合
- ロケーションは、multi-regional


- AppEngine flexibleは、リクエストがきていない時でも、scale to 0 するわけではないので、cloud functionの方がcostは安くて済む
    - 多分起動に分単位の時間がかかるから
    - standardだと、scale to 0 する。
- AppEngineのflexibleは、stanndardと比較して、インスタンスの初期化により時間がかかる
- サポートされる言語は以下
    - standadは、
        - ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/534442/e61f32de-1de2-4e2e-a6a6-7f51f72c8bdb.png)
    - flexibleは、コンテナベースなので、基本どの言語でも大丈夫という認識。



## Google Kubernetes Engine

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/534442/c7d8cabf-0b5d-3912-f576-004499184c2f.png)

- Cloud Build や Container Registry とともに用いることで、デプロイを自動化できる。
- (デフォルトで)Google Cloud persistent disks が自動でprovisionされるので、これを使用してstateful appを作成できる。
- Kubernetes ingress resources を設定し、Kubernetes network load balancer services と Google Cloud, HTTP and HTTPS load balancersをdeployしたら、Google Cloud network load balancersが自動でprovisionされる
- HTTP or HTTPS以外のネットワークプロトコルを使える
- GCEを単体で用いるよりも、start and stop much faster (usually in seconds)


### kubernetesの基礎知識


- `Deployment` objectsは、deploying stateless applications like web servers
- `Service` は、Podの集合で実行されているアプリケーションをネットワークサービスとして公開する抽象的な方法です。



### cluster autoscaler について

https://tech.quickguard.jp/posts/gke-autoscale-overview/ がめちゃわかりやすいので、参照。
以下の五種類のスケーリング方法がある。


- `水平Podオートスケーラー` Pod の数を増減する。 `HPA (Horizontal Pod Autoscaler)`
- `垂直Podオートスケーラー`	Pod の Resource request を適正値に補正する。	`VPA (Vertical Pod Autoscaler)`
    - Pod は、適切な量のリソースが利用可能なノードにスケジュールされる。よって、コンテナの CPU のリクエストと上限、およびメモリのリクエストと上限に対してどの値を指定するか、自分で考える必要がなくなる。
    - verticalというが、既存のnodeの使用可能なリソースを動的に増やす、ということではないという認識。
- `多次元Podオートスケーラー` HPA と VPA を同時に実現する。	`MPA (Multidimensional Pod Autoscaler)`
- `クラスタ・オートスケーラー` ノードプール内のノードの数を増減する。	`CA (Cluster Autoscaler)`
- `ノード自動プロビジョニング` ノードプールを作成＆削除する。	`NAP (Node Auto-provisioning)`


## Google Compute Engine

- block storageとして以下を使用できる。
    - persistent disk
        - SSD, HDDから選べる
        - PD上のデータはすべて冗長化されているので、一般的な単体ディスクよりも高い可用性を提供する(ちゃんと理解してない)
        - マルチリーダー機能を搭載することで、複数の仮想マシンが 1 つの Persistent Disk からデータを読み取ることができます
        - スナップショットの保存ができる。
    - local SSD
        - persistent disksとは違って、ローカル SSD は VM インスタンスをホストするサーバーに物理的にアタッチされます。
        - Persistent Disk に比べて、優れたパフォーマンス、非常に高い 1 秒間の入力 / 出力オペレーション数（IOPS）、非常に低いレイテンシが実現されます。
        - ローカル SSD がアタッチされている VM を停止して再起動することはできません。
            - GCE がtermianatedになると、local SSDのデータは失われる
- HTTP or HTTPS以外のネットワークプロトコルを使える
- per second billing

- preemptible VM も要チェック🔥
    - 価格は通常の二割
    - 途中で勝手に止まるかも
    - 最大一ヶ月で止まる
    - Jobの実行に適している

<details><summary>block storageとは？</summary><div>

- block storage
    - 物理マシンの記録領域をボリュームという単位で分割、さらにその内部を固定長のブロックに切り出して、そのブロックにデータを保存、管理するというストレージ形式です。
- object storage
    - フラット構造
    - 全てのメタデータはオブジェクト と一緒に格納され、一意の識別子を持つフラットなアドレス空間に保存されます。
- file storage
    - 階層構造
    - ファイルストレージにおいて、データは「フォルダ」や「ディレクトリ」といった形式で、階層的に管理、保存されます。

</div></details>


## Cloud Run

Cloud Run はマネージド コンピューティング プラットフォームで、リクエストまたはイベント経由で呼び出し可能なコンテナを実行できます。 Cloud Run はサーバーレスです。 インフラストラクチャ管理が一切不要なため、最も重要な作業であるアプリケーションの構築に集中できます。

- 数秒で立ち上がる(コンテナベースなのに!)
- 100 milliseconds単位で課金される。

-----

# Google Cloud's operations suite (旧`Stackdriver`)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/534442/fc4a4c4b-33a4-6f1f-9e3e-6f636b1c4c0a.png)


- APM tools = Application Performance Management (=パフォーマンス管理)であり、`Cloud Trace`、`Cloud Profiler`、`Cloud Debugger`からなる。
   - 目的は、`reduce latency`, `reduce cost`, `more reliable にする`
   - 収集されたデータ量に合わせて課金される
   - マルチクラウド対応なので、GCP上にないインスタンスもモニタリングできる。

- Golden signals for monitoring = `latency`, `traffic`, `errors`, `satuation`
    - 例えばlatencyなら、`99 percent of requests over 30 days have latency less than 100 milliseconds`とか。

## Cloud Trace

- 分散tracing systemであり、GCP上でそれを可視化できる。
- 以下を容易に知れる。知れるのは**「latencyのみ」**という認識
    - How long does it take my application to handle a given request?
    - Why is it taking my applications so long to handle requests?
    - Why do some of my requests take longer than others?
    - What is the overall latency of requests to my application?
    - Has latency for my application increased or decreased over time?
    - What can I do to reduce application latency?
    - What are my applications dependencies? (マイクロサービスで効果発揮???)
- Cloud trace agent(library)をコードベース内でインポートする。
    - node.jsだと、` @google-cloud/trace-agent`
- App Engineで起動したアプリにはデフォルトで導入されている。
- 一リクエスト一単位で、時間を計測し、その統計値を出す(??)


## Cloud Profiler

- CPU, heapの使用量を監視する。
- ボトルネックや、リソース消費量を監視できる。
- pathの中で(行ごとに???)実行時間がかかった箇所の表示もできるはず
- New Relicみたいなもん。
- (導入方法)Java, Go, Node.js, and Pythonで、profiling agent(大抵はlibrary)をVMにインストールする。インスタンス一つにつき一つのprofileが作成される。
- stack traceの中のコードをクリックすることで、Cloud Debuggerが開く。

## Cloud Debugger

コード上のあるポイントでローカル変数を確認したり、debug snapshotを取得したい場所を選択したりできる。アプリを再起動する必要はない。

App Engine アプリケーションでは、デバッガは自動的に有効になります。Google Kubernetes Engine または Compute Engine では、簡単な手順で有効にできます。

Cloud Source Repositoryにソースコードをアップロードして連携できたらGUI上でファイルを見ながらログポイントを指定できる様になる。(連携できていない場合には、ファイル名と行番号で指定)

Stack Debugger API から利用することも可能。Cloud debug agent(library)をコードベース内でインポートする。(node.jsだと、`@google-cloud/debug-agent`)





## Cloud Error Reporting

- 実行中に発生したエラーをGCPに送信する
- Cloud debug agent(library)をコードベース内でインポートする。
    - node.jsだと、`@google-cloud/error-reporting`

## Cloud Logging

- Cloud logging agentをマシンにインストールすることで、ログをCloud Loggingへ**ストリーム**することができる。
    - 例えば、マシンのsyslogに書き出されたログを送信する
    - これなら、third-party applicationのログも見ることができる！
- logging agent は fluentd をベースにしたアプリケーションである。　
- DataFlow, App Engine flexi, Cloud Functionsでは、built-inサポートされている。GKEではワンチェックでenableできる。
- GCP上で、「HTTPステータス200以外のログメッセージが秒400未満になったらアラートを発する」みたいな設定ができる。


## Cloud Monitoring

- metrics色々を、Dashboardsでデータを可視化できる。 Alertsを設定できる。
- SLO モニタリング 
    - アプリケーションのサービスレベル目標（ServiceLevelObjective）を自動推定またはカスタム定義し、SLO 違反の発生時に通知を受け取れるようにします。
- カスタム指標の設定
    - - アプリケーションをインストルメントして、アプリケーション レベルやビジネスレベルの指標を Cloud Monitoring でモニタリングできます。


### cloud monitoring agent


[Cloud Monitoring エージェントは、collectd ベースのデーモンで、仮想マシン インスタンスからシステム指標とアプリケーション指標を収集して Monitoring に送信します。デフォルトでは、Monitoring エージェントはディスク、CPU、ネットワーク、プロセスの指標を収集します。サードパーティ アプリケーションをモニタリングしてすべてのエージェント指標を取得するように Monitoring エージェントを構成できます。](https://cloud.google.com/monitoring/agent/monitoring)


### GKEの場合取得されるのは、

デフォルトで以下を取ってきくれると言う認識。

- コンテナの指標
- CPU使用率
- ディスク使用率
- ページフォールト（メジャー）
- ページフォールト（マイナー）
- メモリー消費量
- ノード（GCEのVM）のメトリクス
- NodeのCPU使用率
- ディスク読み込みI/O
- ディスク書き込みI/O
- ネットワーク インバウンド トラフィック
- ネットワーク アウトバウンド トラフィック