littlem-nooblog

エンジニア王に、俺はなるっ!!

Statistics, CloudNative, Backend, etc..

[WIP]「Kubernetesで実践するクラウドネイティブDevOps」 学習ログ

是非、買って読んで欲しい。 学習のログを残す。 https://www.oreilly.co.jp/books/9784873119014/

github https://github.com/cloudnativedevops/demo

流れが早いので多少内容が古くなっていて(2019/3月)監修訳がついている。
特にツールの流行りすたりが激しい。
CNCFのlandscapeがとても勉強になる。

【】は自分の感想とか調べた補足とか、ツールに関しては結構調べてます、後CI/CD周り

  • : は本番環境ではチェックしておいた方がいいもの(自分の主観)

1章 クラウドでの革命

  • 1960年代のメインフレームの時分割利用が一回りして戻ってきたのがクラウド
  • コンピュータを買わずに処理能力を買う
  • 差別化につながらない作業をこなしてくれるマネージドサービス
  • DevOps

    • DevとOpsは分かれていた
    • クラウド(分散システム)は運用含めて全体理解が必要
    • DevOpsは双方のグループの連携の試み
    • DevOpsの考え方には議論が多い
    • 4つの柱「文化、自動化、測定、共有」

      • ビジネス観点

        • 自動化とプラクティス

          • リリースサイクル迅速化 → ソフトウェア品質向上
        • 導入にはビジネス文化の根本的な変革が必要

          • 経営幹部の戦略的なレベルからの取り組み
      • Infrastructure as Code
        クラウドインフラの自動プロビジョニング

        • 運用エンジニア = クラウドを自動化するソフトウェアを書く人
        • 開発者 = 分散システムを考慮した設計をする人
        • ↑共にまなぶことが重要
  • コンテナ
    デプロイには、
    ソフトウェアと依存関係(ライブラリ..)、設定(キーやパスワード)などが必要。
    プロビジョニング、ネットワーク接続、デプロイ、設定、監視など必要。

    • これまで

      • Puppet, Ansibleなど
        デプロイするソフトウェアを実行、設定、更新するコード
      • まるっと仮想マシンイメージにしちゃう
        ビルド・保守に時間がかかる、運用の不安定さ、DLもデプロイも遅い
    • コンテナ登場

      • 標準のパッケージング+配布形式
    • CPU上で直接実行され、仮想化のオーバーヘッドがない
    • VMよりサイズが小さい
    • 密閉状態にパッケージされ、必要な依存関係を持ち運べる
  • オーケストラの指揮 様々なアーキテクチャ、OS、などの資産管理の世界線
    → オーケストレータの実行、ポチッとな

    • Kubernetes

Kubernetesは、自動化、フェイルオーバ、集中ロギング、監視など、非常に優秀なシステム アドミニストレータが行うであろうことを実行します。DevOpsコミュニティで学習蓄積されてき てきた知見を取り入れ、すぐに使用できるデフォルトの機能となっています。 - Kelsey Hightower

  • デプロイを容易にするKubernetes

    • デプロイ時間と労力の削減

      • デフォルト、ローリングアップデート(ゼロダウンタイム)
        他にもいくつかのデプロイ方法がある
    • オートスケールサポート
    • 冗長性とフェイルオーバー
    • 限られたリソースを効率的に活用するのでインフラコストを削減できる
    • プロバイダに非依存

      • 抽象化によりクラウド独自の詳細が隠蔽される
    • Kubernetesを使用する必要性が低い領域

      • ステートフルなデータベースなど
      • クラウド関数で片付くようなスタンドアロン型処理
    • Knative
      コンテナとクラウド関数の両方に対応したソフトウェアデリバリプラットフォーム
  • クラウドネイティブ
    差別化につながらない要素は実行せずビジネスを加速するという実践

    • 自動化可能
    • ユビキタスかつ柔軟
    • 弾力的かつスケーラブル
    • 動的(高可用性)
    • オブザーバブル
    • 分散化
  • 分散型のDevOps
    専用のインフラ組織→
    運用の専門者が各チームに分散される
    ほとんどの組織で運用・開発の片方しかできない人は生き残る余地がなくなる
    【そうなのか?】
  • 開発者生産性工学(DPE)

    • 運用だけではなく、ツール構築、問題の解決、など
      開発者の仕事の効率化をするためのあらゆることを担う強力な中央チーム
    • 組織規模が大きくなると自然に組織される
      各プロジェクトやチームには専門のSREを配属することで開発とインフラの橋渡しをする
      【インフラ基盤の中央チーム+チーム専門のインフラアドバイザ、の構成になっていく?】

2章 Kubernetes最初の一歩

Go+Dockerのお話

  • Goのマルチステージビルド

デモアプリケーションの実行

https://kubernetes.io/ja/docs/tutorials/kubernetes-basics/deploy-app/deploy-interactive/ を参考に書き換えた kubeでdockerを起動して、helloを表示するだけのAPIを叩く

$ kubectl create deployment demo --image=cloudnatived/demo:hello

$ kubectl get deployments
NAME   READY   UP-TO-DATE   AVAILABLE   AGE
demo   1/1     1            1           6m2s

$ kubectl port-forward deploy/demo 9999:8888
Forwarding from 127.0.0.1:9999 -> 8888
Forwarding from [::1]:9999 -> 8888

$ curl http://localhost:9999
Hello, 世界

3章 Kubernetsの環境の選択

o7leok.png

引用: https://x-team.com/blog/introduction-kubernetes-architecture/

  • コントロールプレーン(Master node)
    複数存在し、高可用性を備える

    • kube-apiserver
      APIリクエスト処理
    • etcd
      存在するノード・クラスタのリソースの詳細などを保存するDB
    • kube-scheduler
      新たに作成されるPodが実行される場所を決定する
    • kube-controller-manager Deploymentなどの実行の管理
    • cloud-controller-manager
      クラウドプロバイダとやりとりしてリソースを管理
  • ノード(Worker node)

    • kubelet
      ノードにスケジューリングされているワークロードを起動するコンテナランタイムの運用・ステータス監視
    • kube-proxy Podのグループに対してのトラフィックルーティングする単一不変の仮想IPアドレスを提供する機能の実行管理
    • コンテナランタイム
      コンテナの起動・終了、通信処理

障害について

  • Chaos Monkey、カオステストでランダムにノードやPodを停止させてまともに動くかテストする
  • セルフホスティングは高難易度なのでマネージドサービスを使え

GKE

  • GKEが最善のマネージドサービスなのでこれを使え
  • マルチゾーンクラスタでノードを分散配置できる
  • リージョナルクラスタは、複数のマスターノードも障害ゾーンに跨って分散される
  • セキュリティパッチ自動適用、コントロールプレーンやetcdの高可用性、などはGoogleが面倒を見る
  • クラスタのオートスケール

EKS

AKS

  • 急速な追い上げを見せている
  • 【Kubernetes co-founderのBrendan BurnsがAzureのコンテナ関連サービスのトップをしている】
    【Azureいい!】

その他

  • OpenShift
  • IBM Cloud Kubernetes Service
  • HKS(VMware Essential PKS)
  • Stackpoint.io(NKS)
    マルチクラウドでワーカノードを実行する、マスターノードはマネージドでWebポータルから管理する
  • CKE
  • kops
  • kubespray
  • TK8
  • Kubernetes The Hard Way
    k8sクラスタ構築の指南書的なもの
  • kubeadm
  • Tarmak
  • RKE
  • Puppet Kubernetesモジュール
  • Kubeformation(死んでるプロジェクトぽい)

ベンダロックインの問題

  • Kubernetesを利用すること自体がロックインの回避に繋がるのでマネージドを使っても問題ない
  • どうしても必要ならKubernetesセルフホスティングツールを使用する kops, Kubespray

クラスタレスのコンテナサービス

  • AWS Fargate
  • Azure Container Instances

    • AKSとの統合機能あり
    • サーバレスコンテナ(著者は混乱があるので使いたくない用語と言っている、実際にはサーバはあるから)
    • Event Gridを用いて通信
    • Functionsを利用してACIコンテナ作成・実行
    • Flowでワークフロー構築

4章 Kubernetesオブジェクトの基本操作

Deployment

スーパーバイザ、コンテナに関する全ての情報を格納し監督する

  • コントローラはリソースを監視して望ましい数にレプリカを保つ
  • DeploymentはReplicaSetオブジェクトを作成して、これがレプリカの管理を処理する
# deploymentの詳細
$ kubectl describe deployments/demo

Pod

1つ以上のコンテナのグループを表現する用語

# 調整ループ、望ましい状態への調整トライをループし続ける
$ kubectl get pods --selector app=demo
NAME                   READY   STATUS    RESTARTS   AGE
demo-c84f49bbc-f9ztc   1/1     Running   0          4h27m
$ kubectl delete pods --selector app=demo
pod "demo-c84f49bbc-f9ztc" deleted
$ kubectl get pods --selector app=demo
NAME                   READY   STATUS    RESTARTS   AGE
demo-c84f49bbc-9jq6k   1/1     Running   0          10s

# 実験が終わったらdeploymentをシャットダウン
$ kubectl delete all --selector app=demo
pod "demo-c84f49bbc-9jq6k" deleted
deployment.apps "demo" deleted
replicaset.apps "demo-c84f49bbc" deleted
$ kubectl get pods --selector app=demo
No resources found.

Kubernetesスケジューラ

Deployment
-> 新しいレプリカが必要
-> KubernetesデータベースにPodリソースを作成、Podがキューに追加
-> スケジューリングされていないPodのキューがあれば、Podをキューから取り出して、実行場所となるノードを見つける
-> Podがノードにスケジュールされると、kubeletがコンテナを起動する

リソースマニフェスト

リソースの望ましい状態に関する仕様(マニフェスト)

apiVersion: apps/v1
kind: Deployment
metadata:
  name: demo
  labels:
    app: demo
spec:
  replicas: 1
  selector:
    matchLabels:
      app: demo
  template:
    metadata:
      labels:
        app: demo
    spec:
      containers:
      - name: demo
        image: cloudnatived/demo:hello
        ports:
        - containerPort: 8888
$ kubectl apply -f deployment.yaml

# コンテナは立つ
$ kubectl get pods --selector app=demo
NAME                    READY   STATUS    RESTARTS   AGE
demo-64f9f8d47d-jjmc7   1/1     Running   0          86s

# うまくいかない・・
$ curl http://localhost:9999
curl: (52) Empty reply from server

Serviceリソース

Webプロキシ、ロードバランサのようなもので、 Podに対するリクエストをルーティングするための単一のエントリポイントを提供する。

自分のPort9999をPodのport8888に転送している

apiVersion: v1
kind: Service
metadata:
  name: demo
  labels:
    app: demo
spec:
  ports:
  - port: 9999
    protocol: TCP
    targetPort: 8888
  selector:
    app: demo
  type: ClusterIP
$ kubectl apply -f service.yaml

# demo Serviceをローカルマシンのポートに接続する
$ kubectl port-forward deploy/demo 9999:8888

$ curl http://localhost:9999
Hello, 世界

総合的な情報を出力

$ kubectl describe pod --selector app=demo
Name:           demo-64f9f8d47d-7nzt4
Namespace:      default
Priority:       0
Node:           docker-desktop/192.168.65.3
Start Time:     Mon, 24 Feb 2020 16:34:45 +0900
Labels:         app=demo
                pod-template-hash=64f9f8d47d
Annotations:    <none>
Status:         Running
IP:             10.1.0.12
Controlled By:  ReplicaSet/demo-64f9f8d47d
Containers:
  demo:
    Container ID:   docker://0a7cf35fefc681daa29cf3a064e10ed82d3c459c551313cc4c84e9950622a749
    Image:          cloudnatived/demo:hello
    Image ID:       docker-pullable://cloudnatived/demo@sha256:aeae1e551a6cbd60bcfd56c3b4ffec732c45b8012b7cb758c6c4a34779e0e7fb
    Port:           8888/TCP
    Host Port:      0/TCP
    State:          Running
      Started:      Mon, 24 Feb 2020 16:34:46 +0900
    Ready:          True
    Restart Count:  0
    Environment:    <none>
    Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from default-token-96xfm (ro)
Conditions:
  Type              Status
  Initialized       True
  Ready             True
  ContainersReady   True
  PodScheduled      True
Volumes:
  default-token-96xfm:
    Type:        Secret (a volume populated by a Secret)
    SecretName:  default-token-96xfm
    Optional:    false
QoS Class:       BestEffort
Node-Selectors:  <none>
Tolerations:     node.kubernetes.io/not-ready:NoExecute for 300s
                 node.kubernetes.io/unreachable:NoExecute for 300s
Events:
  Type    Reason     Age   From                     Message
  ----    ------     ----  ----                     -------
  Normal  Scheduled  107s  default-scheduler        Successfully assigned default/demo-64f9f8d47d-7nzt4 to docker-desktop
  Normal  Pulled     107s  kubelet, docker-desktop  Container image "cloudnatived/demo:hello" already present on machine
  Normal  Created    107s  kubelet, docker-desktop  Created container demo
  Normal  Started    106s  kubelet, docker-desktop  Started container demo
# シャットダウン
$ kubectl delete -f ./
deployment.apps "demo" deleted
service "demo" deleted

Helm: Kubernetesパッケージマネージャ

【以下、書籍と異なるバージョンでコメントも個人のものが含まれている】 aptやyum的なものだが、コンテナイメージ自体は含まれない。メタデータの管理。 本はHelmのバージョンが2で古いっぽいので、バージョン3でやってみる。

  • チャート
    アプリケーションをk8sで実行するために必要なリソース定義が全て格納されたHelmパッケージ
  • リポジトリ
    チャートを収集・共有できる場所
    helm hubなるものがありChartが公開されている
  • リリース
    チャートの特定のインスタンス

公式を見つつ試す。

$ brew install helm
$ helm version
version.BuildInfo{Version:"v3.1.1", GitCommit:"afe70585407b420d0097d07b21c47dc511525ac8", GitTreeState:"clean", GoVersion:"go1.13.8"}

# https://github.com/cloudnativedevops/demo/tree/master/hello-helm/k8s/demo
# リポジトリをcloneしてディレクトリに移動
$ helm install demo .
NAME: demo
LAST DEPLOYED: Mon Feb 24 17:18:54 2020
NAMESPACE: default
STATUS: deployed
REVISION: 1
TEST SUITE: None

$ helm list
NAME	NAMESPACE	REVISION	UPDATED                            	STATUS  	CHART     	APP VERSION
demo	default  	1       	2020-02-24 17:18:54.14197 +0900 JST	deployed	demo-1.0.1

# kubectl port-forward deploy/demo 9999:8888は実施が必要
$ curl http://localhost:9999
Hello, 世界

5章 リソースの管理

  • コンテナには常にリソース制限とリソース要求を指定する

    • 各Podに許容される最大・最小のリソース要件を把握して効果的にスケジュールしたい
    • リソース単位

      • 1CPU=1 AWS vCPU, 1Azure vCore, etc..
      • メモリ、メビバイト
    • リソース要求
      リソース要求より少ないリソースしか利用できないノードでは、
      PodはスケジューリングされずにPending状態となる
    • リソース制限
      上限を超える使用は

      • CPU: 処理能力を絞り込むスロットル処理の対象となる
      • Mem: Pod強制終了、可能なら再スケジューリング
    • QoS
      Pod間でリソースの取り合いになる状況ではQoSクラスで優先度が決まり、低いものから強制終了される
  • Liveness probe

    • コンテナが生きているかを監視, /healthz pathにするのが慣例
      起動直後のチェックで失敗する死のループを避ける必要がある
    • gRPC probe
      grpc-health-probeツールを入れる
    • Readiness probe
      一時的にリクエストを処理できない状況であることを、k8sに伝える

      • このprobeが成功するまでk8sはこのPodにリクエストを送信しない
      • 必ずHTTP 200 OKのみを返すこと
      • /tmp/healtyのようなファイルでprobeする場合
        ファイル削除することで一時的にサービスから外せる、障害調査時に役立つ
# READYがPod内の準備できているコンテナ状況
$ kubectl get pods
NAME                    READY   STATUS    RESTARTS   AGE
demo-774d7f849b-kgwfh   1/1     Running   0          27d
  • Pod Disruption Budget 任意のタイミングで失っても構わないPod数を指定

    • minAvairable
    • maxUnavairable
  • Namespace

    • Namespaceの切り方、アプリケーション実行環境ごとなど
    • : 削除保護 Validating Admission Webhook、RBAC(アクセス制御)など
    • : 別のNamespaceのService同士は通信可能 【Network Policyでアクセス制御する必要ありそう】
    • : ResourceQuotaでNamespaceに対してのリソース制限ができる(した方が良い)
    • : LimitRange, デフォルトの制限をNamespaceに適用
$ kubectl get namespaces
NAME              STATUS   AGE
default           Active   28d
docker            Active   28d
kube-node-lease   Active   28d
kube-public       Active   28d
kube-system       Active   28d
$ kubectl get pods --namespace default
NAME                    READY   STATUS    RESTARTS   AGE
demo-774d7f849b-kgwfh   1/1     Running   0          27d

# Quota
$ kubectl create namespace demo
namespace/demo created

$ cat resourcequota.yaml 
apiVersion: v1
kind: List
items:
- apiVersion: v1
  kind: ResourceQuota
  metadata:
    name: pods-high
  spec:
    hard:
      cpu: "1000"
      memory: 200Gi
      pods: "10"

$ kubectl apply --namespace demo -f resourcequota.yaml 
resourcequota/pods-high created

$ kubectl get resourcequotas -n demo
NAME        CREATED AT
pods-high   2020-03-23T08:39:40Z
  • Pod最適化 PrometheusやGrafanaを使用して、リソース状況を可視化し適切なリソース要求を実施すべし
    通常の運用状態で使用する最大量より少し多い値に設定しておく

    • : Vertical Pod Autoscaler
      リソース要求の理想的な値を算出するのに役立つ。
      指定されたDeploymentを監視し、実際の使用量に基づいてPodのリソース要求を自動的に調整する。
  • ノードの最適化
    経験則

    • : ノードは典型的なPodを少なくとも5つは実行できるサイズにする、10個~100個にする
  • ストレージの最適化

    • : IOPS要求についてはKubernetesでサポートされていない。
      コスト削減のためにできる限り容量とIOPSが小さいディスクボリュームをプロビジョンする
  • 使用率が低いリソースの発見
    受信するトラフィックが極めて低いPodを発見する。
    メトリクスを用いて使用率が低いPodを発見できる。

    • 完了したJobのクリーンアップ
      TTL機能がある。TTLAfterFinished Feature Gate
  • プリエンプティブ(スポット)インスタンスの使用
    クラスタにとってコスト削減の良い選択肢だが、
    常に非プリエンプションノードを組み合わせて利用する。
    理論上は全て一気に落ちる可能性もあるので。
    (スポットインスタンスは落ちる前に通知くるけどうまく入れ替えできないのか?)

    • Node Affinity
      障害が許容できないPodをスポットにアサインしないようにできる
  • ワークロードバランスの維持
    ノード障害などでレプリカがあるノードに偏る可能性がある。
    Deschedulerでクラスタを再バランス化するために最善を尽くしてくれる。

6章 クラスタの運用

  • クラスタのサイジングとスケーリング

    • : マネージドサービスならマスターノードの可用性は考えなくてOK
    • : ワーカーノードは最低2つは必要(AZ分散とかは勝手にやってくれるのか?)
    • : 最適なノードサイズはPod数やクラウドベンダなどで変わってくる

      • ノードが大きいほど一般的には割安になる
      • 異種混在ノード、大きなノード、小さなノードを用意して用途に応じて使い分ける方法もある
    • : スケールダウン
      取り除きたいノードをドレイン指示する。Podは徐々に別ノードに移動する。

      • PodDistruptionBudgetリソース

        • minAvailable
          利用可能な状態を維持すべきPodの最小数
        • maxUnavailable
          任意の時点で利用できない状態が許されるPodの最大数
    • : オートスケール、変動が激しいのでなければ使用するな、手作業でスケーリングする方がいい
    • : 適合性テスト
      クラスタが適切に設定されて最新の状態である、ことを確認するツール Sonobuoy
    • : 【ユニットテスト Open Policy Agent】

      • Conftestというものでyamlにルールを定義できる。
        別にk8sだけにしか使えないものではなさそう。
    • : 監査ロギング
      クラスタAPIに対する全操作がログとして残る
    • : 【カオステスト】

      • chaos monkey spinnakerの利用が必須。argo CDでは使えないのか・・
      • pumba
        コンテナレベルのchaos monkey
      • Gremlin
        Failure as a Service, あ、新しい・・
        これ使ってみたいかも

7章 Kubernetesの強力なツール

  • : 【マネージドサービスのマスターノードのログの見方は?】
  • : kubespy, クラスタ内の個別リソースを監視して何が起こるのかを表示できる。【使ってみたい】
  • : stern
    高度なログストリーミングツール, 名前に一致する正規表現, コンテナ再起動でもストリーミング維持など
  • : squash, ライブデバッグ

kubectl

### リソースタイプ
$ kubectl api-resources
NAME                              SHORTNAMES   APIGROUP                       NAMESPACED   KIND
bindings                                                                      true         Binding
componentstatuses                 cs                                          false        ComponentStatus
configmaps                        cm                                          true         ConfigMap
endpoints                         ep                                          true         Endpoints
events                            ev                                          true         Event
limitranges                       limits                                      true         LimitRange
namespaces                        ns                                          false        Namespace
nodes                             no                                          false        Node
persistentvolumeclaims            pvc                                         true         PersistentVolumeClaim
persistentvolumes                 pv                                          false        PersistentVolume
pods                              po                                          true         Pod
...

### 詳細情報表示
$ kubectl get pods -o wide
$ kubectl get pods -o json
{
    "apiVersion": "v1",
    "items": [
        {
            "apiVersion": "v1",
            "kind": "Pod",
            "metadata": {
                "creationTimestamp": "2020-02-24T08:18:54Z",
                ...
$ kubectl get pods -o json | jq '.items[].metadata.name'
"demo-774d7f849b-kgwfh"

### オブジェクトに関する記述
$ kubectl describe pods demo-774d7f849b-kgwfh
Name:           demo-774d7f849b-kgwfh
Namespace:      default
Priority:       0
Node:           docker-desktop/192.168.65.3
Start Time:     Mon, 24 Feb 2020 17:18:54 +0900
Labels:         app=demo
                environment=development
                pod-template-hash=774d7f849b
Annotations:    <none>
Status:         Running
IP:             10.1.0.16
Controlled By:  ReplicaSet/demo-774d7f849b
Containers:
  demo:
    Container ID:   docker://7d7d8b76136913dfb93c46c0ed73a85ab09aef490860b4c288af0bbed8bb9552
    Image:          cloudnatived/demo:hello
    Image ID:       docker-pullable://cloudnatived/demo@sha256:aeae1e551a6cbd60bcfd56c3b4ffec732c45b8012b7cb758c6c4a34779e0e7fb
    Port:           8888/TCP
    Host Port:      0/TCP
    State:          Running
      Started:      Mon, 24 Feb 2020 17:18:55 +0900
    Ready:          True
    Restart Count:  0
    Environment:
      environment:  development
    Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from default-token-96xfm (ro)
Conditions:
  Type              Status
  Initialized       True 
  Ready             True 
  ContainersReady   True 
  PodScheduled      True 
Volumes:
  default-token-96xfm:
    Type:        Secret (a volume populated by a Secret)
    SecretName:  default-token-96xfm
    Optional:    false
QoS Class:       BestEffort
Node-Selectors:  <none>
Tolerations:     node.kubernetes.io/not-ready:NoExecute for 300s
                 node.kubernetes.io/unreachable:NoExecute for 300s
Events:          <none>

マニフェストではなく直接的にリソースを変更するコマンドが存在するが使用禁止。
GitOps!!

### yamlとしてマニフェストを吐き出せる。
$ kubectl get deployments demo -o yaml
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  annotations:
    deployment.kubernetes.io/revision: "1"
  creationTimestamp: "2020-02-24T08:18:54Z"
  generation: 1
  name: demo
  namespace: default
  resourceVersion: "29478"
  selfLink: /apis/extensions/v1beta1/namespaces/default/deployments/demo
  uid: 9725c9b0-5a98-485a-b4a0-a52ffeee87c2
spec:
  progressDeadlineSeconds: 600
  replicas: 1
...

### リソースの差分チェック
$ kubectl diff -f hoge.yaml 
diff -u -N /var/folders/d5/0kw6v0c52sn06yqpr168hgkh0000gn/T/LIVE-517569565/extensions.v1beta1.Deployment.default.demo /var/folders/d5/0kw6v0c52sn06yqpr168hgkh0000gn/T/MERGED-018551000/extensions.v1beta1.Deployment.default.demo
--- /var/folders/d5/0kw6v0c52sn06yqpr168hgkh0000gn/T/LIVE-517569565/extensions.v1beta1.Deployment.default.demo  2020-03-24 18:53:51.000000000 +0900
+++ /var/folders/d5/0kw6v0c52sn06yqpr168hgkh0000gn/T/MERGED-018551000/extensions.v1beta1.Deployment.default.demo        2020-03-24 18:53:51.000000000 +0900
@@ -4,7 +4,10 @@
   annotations:
     deployment.kubernetes.io/revision: "1"
   creationTimestamp: "2020-02-24T08:18:54Z"
-  generation: 1
+  generation: 2
+  labels:
+    app: demo
+    environment: development
   name: demo
   namespace: default
   resourceVersion: "29478"
@@ -12,7 +15,7 @@
   uid: 9725c9b0-5a98-485a-b4a0-a52ffeee87c2
 spec:
   progressDeadlineSeconds: 600
-  replicas: 1
+  replicas: 2
   revisionHistoryLimit: 10
   selector:
     matchLabels:
exit status 1

### コンテナのログをみる
kubectl logs  --tail=20 demo-774d7f849b-kgwfh

## リソースの差分チェック
$ kubectl diff -f hoge.yaml 
diff -u -N /var/folders/d5/0kw6v0c52sn06yqpr168hgkh0000gn/T/LIVE-517569565/extensions.v1beta1.Deployment.default.demo /var/folders/d5/0kw6v0c52sn06yqpr168hgkh0000gn/T/MERGED-018551000/extensions.v1beta1.Deployment.default.demo
--- /var/folders/d5/0kw6v0c52sn06yqpr168hgkh0000gn/T/LIVE-517569565/extensions.v1beta1.Deployment.default.demo  2020-03-24 18:53:51.000000000 +0900
+++ /var/folders/d5/0kw6v0c52sn06yqpr168hgkh0000gn/T/MERGED-018551000/extensions.v1beta1.Deployment.default.demo        2020-03-24 18:53:51.000000000 +0900
@@ -4,7 +4,10 @@
   annotations:
     deployment.kubernetes.io/revision: "1"
   creationTimestamp: "2020-02-24T08:18:54Z"
-  generation: 1
+  generation: 2
+  labels:
+    app: demo
+    environment: development
   name: demo
   namespace: default
   resourceVersion: "29478"
@@ -12,7 +15,7 @@
   uid: 9725c9b0-5a98-485a-b4a0-a52ffeee87c2
 spec:
   progressDeadlineSeconds: 600
-  replicas: 1
+  replicas: 2
   revisionHistoryLimit: 10
   selector:
     matchLabels:
exit status

### コンテナのログをみる
$ kubectl logs  --tail=20 demo-774d7f849b-kgwfh
# --since, --timestampsなどあり

### コンテナへのアタッチ
# 直接ログをコンテナにアタッチして見る。
kubectl attach demo-774d7f849b-kgwfh

### Context
$ kubectl config get-contexts
CURRENT   NAME                 CLUSTER          AUTHINFO         NAMESPACE
*         docker-desktop       docker-desktop   docker-desktop   
          docker-for-desktop   docker-desktop   docker-desktop  

$ kubectl cluster-info
Kubernetes master is running at https://kubernetes.docker.internal:6443
KubeDNS is running at https://kubernetes.docker.internal:6443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy

$ kubectl config use-context docker-for-desktop
Switched to context "docker-for-desktop".
$ kubectl config get-contexts
CURRENT   NAME                 CLUSTER          AUTHINFO         NAMESPACE
          docker-desktop       docker-desktop   docker-desktop   
*         docker-for-desktop   docker-desktop   docker-desktop

$ kubectl config set-context myapp --cluster=gke --namemspace=myapp

busybox

色々な調査でコンテナと同じネットワーク上に配置してhogehogeするときに便利。

$ kubectl run busybox --image=busybox:1.28 --rm -it --restart=Never /bin/sh

8章 コンテナの実行

Pod

  • k8sのスケジューリングの単位
  • Pod内に複数のコンテナが存在し得る

    • 一緒にしないと正常に動作しないのであればPodでまとめる
  • ダイジェストを利用すると必ずイメージを固定して使える
  • securityContext: runAsUser, で非rootユーザとして実行
  • : readOnlyRootFilesystemをtrueにしておく
  • : alllowPrivilegeEscalationをfalseにしておく
  • : ケイパビリティは必要なものだけ付与する
  • : PodSecurityPolicyでクラスタ全てにセキュリティポリシーをアタッチできる
  • : 再起動ポリシ, restartPolicy: OnFailure
    spec:
      containers: # 複数コンテナを指定できる
      - name: demo
        image: cloudnatived/demo:hello
        ports:
        - containerPort: 8888
  • ボリューム

    • emptyDirボリューム

      • Pod内での共有は可能
        ただし、ロック機構がないのでnfsなど使う必要がある
      • Pod削除で消去される一時ボリューム
    • 永続ボリューム

      • ステートフルになるのでだめ
      • KubernetesでDBを実行することは非推奨
      • PersistentVolume, は基本使うな

9章 Podの管理

Label

  • Label自体はユーザ用のタグ付けに過ぎない, リソースを識別する
  • app, environment, version, roleなどをつける

セレクタ

$ kubectl get pods --show-labels
NAME                    READY   STATUS    RESTARTS   AGE   LABELS
demo-774d7f849b-kgwfh   1/1     Running   0          29d   app=demo,environment=development,pod-template-hash=774d7f849b

# セレクタで一致条件を記述して結果を絞る
$ kubectl get pods -l app=demo
NAME                    READY   STATUS    RESTARTS   AGE
demo-774d7f849b-kgwfh   1/1     Running   0          29d

# !=
$ kubectl get pods -l app!=demo2
NAME                    READY   STATUS    RESTARTS   AGE
demo-774d7f849b-kgwfh   1/1     Running   0          29d

# in 集合
$ kubectl get pods -l "environment in (development)"
NAME                    READY   STATUS    RESTARTS   AGE
demo-774d7f849b-kgwfh   1/1     Running   0          29d

$ kubectl get pods -l "environment notin (staging)"
NAME                    READY   STATUS    RESTARTS   AGE
demo-774d7f849b-kgwfh   1/1     Running   0          29d

Node Affinity

【この設定だいぶ大変だな。。割り当てのされ方を考えつつノードに割り当てるのか・・、ノウハウ必要】

  • : Pod Affinityが必須な場合をのぞいて使わない方がいい
  • required, prefferdがある
  • ハードAffinity

    • 特定のAZを指定して、Podがそのゾーンのみにスケジューリングされるようにする
  • ソフトAffinity

    • weightを1から100までの数値で指定してスケジュール先の優先度を決定する
  • Podの同居 podAffinity: WebサーバーPodとRedis Podの同居を指定するなど
    余計なネットワーク経由の通信が発生しないメリットがある
    ソフト・ハードどちらも指定できる
  • Podの分離
    podAntiAffinity: serverのノード間分散を行いたいようなケース

Taint, Toleration

【試してみる】

# テスト用に新しくnamespaceを切る
$ kubectl create namespace fortaint
namespace/fortaint created

# Nodeのtaint状態
$ kubectl describe node docker-desktop |grep Taint
Taints:             <none>

# Taint追加
# Taintを追加すると、 dedicated=trueが容認(Toleration)されているPodしかNodeに割り当てできなくなる
$ kubectl taint nodes docker-desktop dedicated=true:NoSchedule
node/docker-desktop tainted

# Taintが設定されている
$ kubectl describe node docker-desktop |grep Taint
Taints:             dedicated=true:NoSchedule

# fortaint namespaceでdemo Podを作成
$ kubectl apply --namespace fortaint -f deployment.yaml 
deployment.apps/demo created

# Taintのせいでスケジュールできない!
$ kubectl describe pod demo -n fortaint |grep -A 10 Events
Events:
  Type     Reason            Age                  From               Message
  ----     ------            ----                 ----               -------
  Warning  FailedScheduling  70s (x2 over 2m22s)  default-scheduler  0/1 nodes are available: 1 node(s) had taints that the pod didn\'t tolerate.

# Taintの設定をyamlに追加
cat << EOS >> deployment.yaml
      tolerations:
      - key: "dedicated"
        operator: "Equal"
        value: "true"
        effect: "NoSchedule"
EOS

# applyする
$ kubectl apply --namespace fortaint -f deployment.yaml 
deployment.apps/demo configured
$ kubectl describe pod demo -n fortaint |grep -A 10 Events
Events:
  Type    Reason     Age   From                     Message
  ----    ------     ----  ----                     -------
  Normal  Scheduled  7s    default-scheduler        Successfully assigned fortaint/demo-85c9b4589b-dg9vm to docker-desktop
  Normal  Pulled     6s    kubelet, docker-desktop  Container image "cloudnatived/demo:hello" already present on machine
  Normal  Created    6s    kubelet, docker-desktop  Created container demo
  Normal  Started    6s    kubelet, docker-desktop  Started container demo

# ノードにスケジュールされてdemo Podが起動した
$ kubectl get pods -n fortaint
NAME                    READY   STATUS    RESTARTS   AGE
demo-85c9b4589b-dg9vm   1/1     Running   0          26s

# Taint設定を削除しておく
$ kubectl taint nodes docker-desktop dedicated:NoSchedule-
node/docker-desktop untainted
apiVersion: apps/v1
kind: Deployment
metadata:
  name: demo
  labels:
    app: demo
spec:
  replicas: 1
  selector:
    matchLabels:
      app: demo
  template:
    metadata:
      labels:
        app: demo
    spec:
      containers:
      - name: demo
        image: cloudnatived/demo:hello
        ports:
        - containerPort: 8888

Podコントローラ

【実際にやってみないと本番で使えるのかわからないな】

  • ReplicaSet
    既出、Podについてレプリカのグループを管理する
    同じ仕様のPodのレプリカ数を管理 Deploymentによって生成・管理されて、バージョン差分が発生すると新しいReplicaSetの作成が行われる
  • DaemonSet 利用例:ロギングエージェント
    ロギングエージェントとして機能する追加コンテナを全てのPodで実行する(サイドカー)
  • StatefulSet 利用例:Redis, MongoDB, Cassandra
    【ステートフルなものは使いたくはない、データ消えそうで怖い】
  • Job
    利用例:バッチ処理タスク、キューワーカ

    • CronJob
  • Horizontal Pod AutoScaler
    メトリクスを監視して、レプリカ数の増減の判断を自動で行う
    【ECSよりも柔軟にメトリクス定義でオートスケールできそう、メモリ使用率やアプリケーションからのメトリクス利用可能】
  • PodPreset
    【Secret、Volume、VolumeMountや環境変数など、特定の情報を注入するためのオブジェクト】
  • Operator, Custom Resource Definition(CRD)
    【むず・・, https://qiita.com/cvusk/items/773e222e0971a5391a51 わかりやすい!!】

    • Custome Controller
      Custom Resourceを操作するためのコントローラ

      • clint-goで実装
      • code-generatorは、kubernetes styled APIを生成する
    • CRD Custom Resourceを定義する
    • Operator K8s環境を監視し、その現在の状態を使用して数ミリ秒で意思決定を行うソフトウェアベンダーのエンジニアリングチームのようなもの 【わかりやすい、https://qiita.com/MahoTakara/items/af4ad8ab69c24102bd72】

Ingressリソース

Service前段のロードバランサ

  • ファンアウト、ルールに応じた、トラフィックの転送
  • TLS終端
  • Ingressコントローラ、ALBやGLBCでリクエストを待ち受ける

Istio

オライリーから Istio: Up and Runningという本が出たと書いてある。
一冊の本が必要な内容量ということ

  • トラフィック制御
  • 対障害性処理
  • 可視化、分散トレース
  • 認証、セキュリティ機能

Envoy

高性能なプロキシ。
ALBなどのマネージドサービスの自由度では足りないケースで利用する

10章 設定と機密情報

ConfigMap

設定データを保存するための主要なオブジェクト。
ConfigMapからファイルや環境変数経由で設定データをアプリケーションに共有できる。
envFromを用いることで一括で環境変数を設定することができる。

【GitOpsの観点からローカルPCの環境変数を引き渡すようなことはしない方が良さそう】
【Argo CDだとこの設定ファイルの変更も捉えてDeploymentのスペックを更新して、Podの再起動できるのか?】
【Argoについては13章をみてください】

Secret

ConfigMapと同じような設定の仕方だがログやdescribeで値は表示されない。
保存データは暗号化されており、RBACでアクセス制御を適切に行う。

機密情報管理の戦略

マニフェストファイルは平文で書かれているのでGit管理するのはとても危険。
機密データはどのように管理すべきか?
【GitOpsするならSOPSで暗号化したファイルをGit管理+デプロイ時に複合するのが良さそう】

  • バージョン管理を通じた機密情報の暗号化

    • 暗号化してコミットし、デプロイ時に複合化する
    • オペミスによる平文のコミットなどの危険性は残る
    • 様々な案件で同じ機密情報を管理する場合、それぞれでコピペが発生する
  • リモート保存

    • S3などのセキュアなファイルストレージに格納する
    • 【GitOpsの文脈だと、全てがGitでバージョン管理され、ログが取られていないのでだめでは?】
  • 専用ツール CDツールのArgo自体は機密データの専用ツールを提供していない

    • Hashicorp Vault
      いきなり利用することは推奨されないらしい
      管理が必要な機密情報はそう多くないかもしれない
    • SOPS

      • 軽量暗号化ツール
      • Azure Key Vault, KMS, Cloud KMSなどのクラウドの暗号化バックエンドをサポート
    • helm-secrets helmで利用できる暗号・複合化プラグイン
      内部ではSOPSを利用している

11章 セキュリティとバックアップ

アクセス制御

  • stagingとproductionでアクセス権限を分けたい

    • stagingとproductionのクラスタを分ける
    • クラスタごとに権限を分ける
  • RBAC(Role-Based Acess Control) 特定のパーミッションを特定のユーザに与える
# RBAC設定されている
$ kubectl describe pod  -n kube-system |grep RBAC
      --authorization-mode=Node,RBAC

【適切な設定はノウハウが必要そう、実戦で頑張る】

  • ロール

    • namespace, クラスタ全体を対象として指定可能
    • cluster-role
      管理者

      • インターネット公開される可能性のあるDashboardなどに与えてはならない
    • view
    • edit 新しいロールやパーミッションを与えることはできない CDツールに適用するロールはedit
  • ロールバインディング ユーザにロールをバインディングする

    セキュリティスキャン

  • : Clair, 【Trivy】, 【anchore】 コンテナスキャナ、安全でないソフトウェアのスキャンをしてくれる
  • : 【Harbor】 k8s上で運用できるリポジトリ、コンテナイメージの脆弱性チェックつき
  • : 【falco】 侵入検知・異常検知のOSS
  • : 【sysdig】 統合的なセキュリティ・モニタリングプラットフォーム

バックアップ

  • etcdのバックアップ(マネージドなら不要)
  • : Velero https://blog.stormcat.io/post/velero-backup/ クラスタの状態と永続データをバックアップしてS3などに配置する、復元も可能
    障害時に慌てないように定期的な復元テストを実施するべき

【ストレージ】

ステータス監視

kubectl

# コントロールプレーン
$ kubectl get componentstatuses
NAME                 STATUS    MESSAGE             ERROR
controller-manager   Healthy   ok                  
scheduler            Healthy   ok                  
etcd-0               Healthy   {"health":"true"}  
# ノード
# NotReadyだと異常
$ kubectl get nodes
NAME             STATUS   ROLES    AGE   VERSION
docker-desktop   Ready    master   32d   v1.15.5

$ kubectl get pods --all-namespaces
NAMESPACE     NAME                                     READY   STATUS    RESTARTS   AGE
default       demo-774d7f849b-kgwfh                    1/1     Running   0          31d
docker        compose-7b7c5cbbcc-jsgv9                 1/1     Running   0          32d
docker        compose-api-dbbf7c5db-p8swb              1/1     Running   0          32d
fortaint      demo-85c9b4589b-dg9vm                    1/1     Running   0          43h
hoge          demo-64f9f8d47d-7v9qk                    1/1     Running   0          43h
kube-system   coredns-5c98db65d4-cn9kx                 1/1     Running   1          32d
kube-system   coredns-5c98db65d4-tl66p                 1/1     Running   1          32d
kube-system   etcd-docker-desktop                      1/1     Running   0          32d
kube-system   kube-apiserver-docker-desktop            1/1     Running   0          32d
kube-system   kube-controller-manager-docker-desktop   1/1     Running   12         32d
kube-system   kube-proxy-hsq45                         1/1     Running   0          32d
kube-system   kube-scheduler-docker-desktop            1/1     Running   21         32d
  • クラウドプロバイダ のコンソール
  • K8s Dashboard
  • モニタリングツール

    • : Prometheus+Graphana 【圧倒的に利用されている印象、監視はこれ一択では?】
    • : Weave Scope クラスタ・コンテナの視覚化・操作ができるのが有能みたい
      【ArgoでもPodまでは可視化できるしDashboardでも可視化できるがこいつが差別化する機能を持っているのか?】

12章 Kubernetesアプリケーションのデプロイ

生のYAMLファイルだと、変数の取り扱いが厳しい。
Helmはこれを解決するための手段。

  • Helmチャート

    • テンプレート
    • 【Argo CDでのHelmの取り扱いについては別途まとめる】

      • デフォルト値を上書きするためのyamlを準備する?
      • helm upgradeはArgoの方で勝手に面倒みてくれる?
      • secrets+helmの取り扱い, Argo CDではsecretsの機能は個別で持っていない

        • helm-secrets
      • HelmfilemとArgoの使い合わせはできる?

13章 開発ワークフロー

14章 Kubernetesにおける継続的デプロイ

13,14章は内容が似ているのでまとめる。
開発ツールの前に、GitOpsについて考えをまとめる。CI/CDは本ではなくほぼ自分で調べた内容です。
本の内容は少し古そうです。

CDツールはOSSのみまとめる。

GitOps

GitOpsとは?

自分の理解 インフラもアプリと同じように全ての設定・変更がGit管理され、Gitの変更がそのままクラスタに同期されるべき、と言う考え方

この考えに乗っかると、

  • NG: 手動でkubectl applyやhelmの更新などをする
  • NG: secret情報をS3で管理する(Gitでのバージョン管理はされなくなるため)

で、Gitファイル状態 = 本番状態、を実現できるのであればArgo CDを使おうと、Circle CIで全部無理やり自作で作り込もうとどちらでもGitOpsである

GitOpsツールはなんで必要?

Argo CDのようにGitの設定ファイル = 本番状態に特化して、デプロイを担当する機能を持つCDツールを使うとGitOpsが実現しやすい。 Argo CDはあくまでk8sのCDに特化しており、CI(テスト、build)は専門外。
なのでGithub actionsなどと組み合わせて利用する事になる。
一応Argo CIというプロジェクトもあるがまだ開発中。

Argo CDの特徴

  • カナリア/BGデプロイ、ロールバック(好きな時点のGit状態にロールバック) maxSurgeやmaxUnnavailableの設定はどうやるのか?
  • helmや様々なartifactの利用(特定のツール特化でCDを作り込まなくて良い)
  • 複数クラスタ管理
  • RBACポリシーの扱い
  • アプリケーションリソースの健康状態のチェック 【他の監視ツールとの使い分けどうする?】
  • Drift Detection、つまりGit状態と本番で差異があれば検知・可視化
  • UI付き
  • CIツールと組み合わせて使うためのCLI付き
  • Webhook(GitHub, etc..)
  • Access tokens
  • PreSync, Sync, PostSync hooks
  • APIなどの監査ログ
  • Prometheusメトリクス
  • パラメータ overrides

他にも、Argo workflow, UI, CI, Eventsなどプロジェクトが走っている。

Tekton pipelines(CI/CD)

knative用のpipelineツール。k8sで使うときにどのくらい便利なのかよく分からなかった。 knative自体はとても興味があるのでいつかまとめる。

Jenkins X

全然調べてないがGitOps用のツール

spinnaker

歴史があるツール。個人的にはArgoの方が将来性があると感じた。
CIが中心のops、CIops。
マージ → コンテナbuild → レジストリ更新 → レジストリ更新トリガ, spinnakerがコンテナをデプロイ

  • 2年リリースがない、これは大丈夫か
  • k8s専用のCDツールではないので複雑
  • 調べた限りだと不安定な部分があるらしい(試してないので参考程度でお願いします)
  • GitOpsではない

skaffold

ファイルを監視して、build → 本番(ローカルも可能)にapplyするツール
個人的には要らない、GitOpsでもないしファイル変更で本番反映されたら怖い。
ちゃんと調べてないが用途がよくわかってない・・

Jenkins

ない

15章 オブザーバビリティと監視

ツールを入れて収集して満足せず、事実とフィードバックに基づくエンジニアリング文化を醸成し、
組織全体に適用していくことが重要。的なことが書かれていて確かに、と思った。

  • ブラックボックス監視 システムの外側から見える挙動を観察する。内部には踏み込まない。
    pingやcurlで応答を確認する。

    • 予測可能で外部に露出する部分しか監視できない
    • 問題が発生した後でしか通知されない
    • 何が壊れているかわかるが、なぜ壊れているかは不明
  • アップ アップタイム99.99...%、ユーザがハッピーでなければ9の数に意味はありません、痺れる言葉ですね

    • 分散システムは完全な意味でアップとなることはない
      サービスが部分的に劣化していることが当たり前であり、それを前提として稼働する。
      全体で見るとup/downの2値ではないんだと
  • ロギング

    • 中央データベースに集約(ex. elastic search) クエリやグラフを通じて分析や通知がされる
    • S/N比、なんでもかんでも採取するとエラーが埋もれて検知が鈍くなる
    • JSONで構造化しておこう
  • メトリクス

    • 何かの状態を測定・集計した数値
    • なぜか、の理解に役立つ、メモリ不足、CPU不足、I/Oが詰まる
    • 問題の予測に役立つ、障害の未然防止、アラート通知
  • トレーシング 分散システムで特に重要

    • 単一のユーザリクエストがたどるライフサイクル全体を明らかにする
    • 一部ユーザのレイテンシなど
    • : Jaegerなどのツールがある
  • オブザーバビリティパイプライン ログルータのような考え方か?
    アプリ、コンテナ、インフラなどからデータ種類など問わずに一箇所のパイプラインに送信し、
    パイプラインがフィルタして適切な場所に届ける。
    Pub/Sub的な考え方。
  • 外部サービスの監視 uptime robot

16章 Kubernetesにおけるメトリクス

  • カウンタ 増えていくだけの数字、リセットしない限り
  • ゲージ メモリ使用率のように継続的に変化する量
  • 何をメトリクスとすべきか

    • サービス: REDパターン(Requests-Errors-Duration) リクエスト駆動型

      • リクエスト数
      • エラー数
      • 処理時間
    • リソース: USEパターン(Utilization, Saturation, Errors) 関心対象がサービスではなくリソース
    • ビジネスメトリクス
    • Kubernetesのメトリクス

      • クラスタ健全性のメトリクス
      • Deploymentのメトリクス
      • コンテナのメトリクス
      • アプリケーションのメトリクス
      • ランタイムのメトリクス

メトリクスの分析

すごい一般的な話しかないので割愛。

  • メトリクス周りのツール 【Prometheusで統一していくのがいいのかな】

    • Prometheus デファクトスタンダード
      時系列メトリクスデータに基づく監視、アラートツール(Alertmanager)
      事前設定されたポートでユーザのアプリケーションにHTTP接続して取れるものをスクレイプ する 可視化はGrafanaが使われることが多い。
    • stackdriver
    • cloudwatch
    • Azure monitor
    • Datadog 高機能監視ツール
    • New Relic アプリケーション重視
    • NETDATA これもイケてる。でもPrometheusでいいかな

littlem

Written by littlem.