[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もデプロイも遅い
- Puppet, Ansibleなど
-
コンテナ登場
- 標準のパッケージング+配布形式
- 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の環境の選択
引用: 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
クラウドプロバイダとやりとりしてリソースを管理
- kube-apiserver
-
ノード(Worker node)
- kubelet
ノードにスケジューリングされているワークロードを起動するコンテナランタイムの運用・ステータス監視 - kube-proxy Podのグループに対してのトラフィックルーティングする単一不変の仮想IPアドレスを提供する機能の実行管理
- コンテナランタイム
コンテナの起動・終了、通信処理
- kubelet
障害について
- Chaos Monkey、カオステストでランダムにノードやPodを停止させてまともに動くかテストする
- セルフホスティングは高難易度なのでマネージドサービスを使え
GKE
- GKEが最善のマネージドサービスなのでこれを使え
- マルチゾーンクラスタでノードを分散配置できる
- リージョナルクラスタは、複数のマスターノードも障害ゾーンに跨って分散される
- セキュリティパッチ自動適用、コントロールプレーンやetcdの高可用性、などはGoogleが面倒を見る
- クラスタのオートスケール
EKS
- ECSは悪くないがKubernetesにこそ未来があるためEKSを提供した
- 自分で行う必要のあるセットアップが多くなる覚悟が必要
- クラスタインフラだけでなくマスターノードにも課金が発生するためGKEより割高
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つ以上のコンテナのグループを表現する用語
-
Deploymentを作成することで、DeploymentがPodを起動
- ReplicaSetがバージョンを表現する
- Deployment, ReplicaSet, Podの関係
# 調整ループ、望ましい状態への調整トライをループし続ける
$ 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する場合
ファイル削除することで一時的にサービスから外せる、障害調査時に役立つ
- コンテナが生きているかを監視, /healthz pathにするのが慣例
# 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のリソース要求を自動的に調整する。
- : Vertical Pod Autoscaler
-
ノードの最適化
経験則- : ノードは典型的なPodを少なくとも5つは実行できるサイズにする、10個~100個にする
-
ストレージの最適化
- : IOPS要求についてはKubernetesでサポートされていない。
コスト削減のためにできる限り容量とIOPSが小さいディスクボリュームをプロビジョンする
- : IOPS要求についてはKubernetesでサポートされていない。
-
使用率が低いリソースの発見
受信するトラフィックが極めて低いPodを発見する。
メトリクスを用いて使用率が低いPodを発見できる。- 完了したJobのクリーンアップ
TTL機能がある。TTLAfterFinished Feature Gate
- 完了したJobのクリーンアップ
-
プリエンプティブ(スポット)インスタンスの使用
クラスタにとってコスト削減の良い選択肢だが、
常に非プリエンプションノードを組み合わせて利用する。
理論上は全て一気に落ちる可能性もあるので。
(スポットインスタンスは落ちる前に通知くるけどうまく入れ替えできないのか?)- Node Affinity
障害が許容できないPodをスポットにアサインしないようにできる
- Node Affinity
- ワークロードバランスの維持
ノード障害などでレプリカがあるノードに偏る可能性がある。
Deschedulerでクラスタを再バランス化するために最善を尽くしてくれる。
6章 クラスタの運用
-
クラスタのサイジングとスケーリング
- : マネージドサービスならマスターノードの可用性は考えなくてOK
- : ワーカーノードは最低2つは必要(AZ分散とかは勝手にやってくれるのか?)
-
: 最適なノードサイズはPod数やクラウドベンダなどで変わってくる
- ノードが大きいほど一般的には割安になる
- 異種混在ノード、大きなノード、小さなノードを用意して用途に応じて使い分ける方法もある
-
: スケールダウン
取り除きたいノードをドレイン指示する。Podは徐々に別ノードに移動する。-
PodDistruptionBudgetリソース
- minAvailable
利用可能な状態を維持すべきPodの最小数 - maxUnavailable
任意の時点で利用できない状態が許されるPodの最大数
- minAvailable
-
- : オートスケール、変動が激しいのでなければ使用するな、手作業でスケーリングする方がいい
- : 適合性テスト
クラスタが適切に設定されて最新の状態である、ことを確認するツール Sonobuoy -
: 【ユニットテスト Open Policy Agent】
- Conftestというものでyamlにルールを定義できる。
別にk8sだけにしか使えないものではなさそう。
- Conftestというものでyamlにルールを定義できる。
- : 監査ロギング
クラスタ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削除で消去される一時ボリューム
- 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を利用している
- Hashicorp Vault
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などに配置する、復元も可能
障害時に慌てないように定期的な復元テストを実施するべき
【ストレージ】
- Rook ストレージを提供する https://qiita.com/ysakashita/items/f27c0948b4e339c5d1e0
ステータス監視
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でいいかな
- Prometheus
デファクトスタンダード
Written by littlem.