SRE兼スクラムマスターのブログ

チーム開発が好きなエンジニアブログです。検証した技術やチームの取り組みを書いていきます。

KEDA v2 よる イベント駆動オートスケール 環境を構築する

Kubernetes を基盤としたプロジェクトで実際に利用している、KEDA というコンポーネントのメジャーバージョンが上がったので追加機能についてまとめる.

KEDAとは

KEDA (Kubernetes Event-driven Autoscaling)は, kubernetes clusterに追加できる単一目的の軽量コンポーネントで,CNCFのSandboxプロジェクトにホストされているkubernetes ベースのイベント駆動オートスケーラーである. 宣言的に定義されたイベントに応じて, Kubernetes の任意のコンテナーのスケーリングを促進できる. Horizo​​ntal Pod Autoscaler などの kubernetesコンポーネントと連携して動作し,上書きや重複なしに機能拡張できる.

keda.sh

KEDA を使うと嬉しいこと

Kubernetes Horizo​​ntal Pod Autoscaler では CPU , Memory , Metrics API をトリガーに自動スケーリングが可能である. しかし, 多くの点で, それは症状の治療に似ており, 実際の原因ではないことがある. 例えばメッセージングの仕組みを利用していた場合に, 大量のメッセージによって最終的にCPU使用率が上昇するが, この場合本当にスケーリングしたい条件は, キューに滞留しているメッセージの数であったりする. これらの場合, KEDA を用いればシンプルに スケーリング環境を構築できる.

v2の追加機能

追加されたスケール対象

  • StatefulSet
  • Custom Resource
  • ScaledJobs

DeploymentやJobが主な対象だったが、サブリソースとしての Custom Resource や Jobスケール専用の ScaledJobs が追加されたり 対象毎の特性に応じたプロパティ設定が可能となった.

追加されたスケーラー

  • CPU
  • Memory
  • External Push
  • Metrics API
  • Azure Log Analytics
  • IBM MQ

Kubernetes Horizo​​ntal Pod Autoscaler でも取得が可能だった CPU , Memory も追加されているのが印象的である. Kubernetesの複雑さの一部を取り除くために, Kubernetes API を使用しなくても対処できるようにするためだと推測している.

事前準備

localに kubernetes 環境を構築する。 今回は minikube を使って cluster の構築を行う. kubernetes.io

インストール

$ kubectl apply -f https://github.com/kedacore/keda/releases/download/v2.0.0/keda-2.0.0.yaml

namespace/keda created
customresourcedefinition.apiextensions.k8s.io/scaledjobs.keda.sh created
customresourcedefinition.apiextensions.k8s.io/scaledobjects.keda.sh created
customresourcedefinition.apiextensions.k8s.io/triggerauthentications.keda.sh created
serviceaccount/keda-operator created
clusterrole.rbac.authorization.k8s.io/keda-external-metrics-reader created
clusterrole.rbac.authorization.k8s.io/keda-operator created
rolebinding.rbac.authorization.k8s.io/keda-auth-reader created
clusterrolebinding.rbac.authorization.k8s.io/keda-hpa-controller-external-metrics created
clusterrolebinding.rbac.authorization.k8s.io/keda-operator created
clusterrolebinding.rbac.authorization.k8s.io/keda:system:auth-delegator created
service/keda-metrics-apiserver created
deployment.apps/keda-metrics-apiserver created
deployment.apps/keda-operator created
apiservice.apiregistration.k8s.io/v1beta1.external.metrics.k8s.io created
  • NamespaceDeployment など KEDA のリソースが作成されている.
$ kubectl get all -n keda
NAME                                          READY   STATUS    RESTARTS   AGE
pod/keda-metrics-apiserver-5bffbfbd68-ftg6q   1/1     Running   0          3m12s
pod/keda-operator-7b98595dc7-b4rnb            1/1     Running   0          3m12s

NAME                             TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)          AGE  
service/keda-metrics-apiserver   ClusterIP   10.97.130.94   <none>        443/TCP,80/TCP   3m12s

NAME                                     READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/keda-metrics-apiserver   1/1     1            1           3m12s
deployment.apps/keda-operator            1/1     1            1           3m12s

NAME                                                DESIRED   CURRENT   READY   AGE
replicaset.apps/keda-metrics-apiserver-5bffbfbd68   1         1         1       3m12s
replicaset.apps/keda-operator-7b98595dc7            1         1         1       3m12s

イベント駆動スケールを試す

せっかくなので KEDA v2から追加された Metrics API を試してみる 今回は自分で定義したAPIから Metrics を取得する.

サンプルはこちら

github.com

  • KEDA の トリガー対象とmetrics用のアプリケーションをデプロイする.
$ make deploy-app
or 
$ kubectl apply -f ./deploy/demo/app/

namespace/demo created
service/components-mock created
deployment.apps/components-mock created
deployment.apps/nginx created

demo Namespace にmetrics用のアプリケーションcomponents-mockとスケール対象のnginxがデプロイされる.

$ kubectl get all -n demo
NAME                                   READY   STATUS    RESTARTS   AGE
pod/components-mock-6b58c499dd-x6bf7   1/1     Running   0          95s
pod/nginx-6799fc88d8-p9jp5             1/1     Running   0          95s

NAME                      TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)    AGE
service/components-mock   ClusterIP   10.99.64.141   <none>        3003/TCP   95s

NAME                              READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/components-mock   1/1     1            1           95s
deployment.apps/nginx             1/1     1            1           95s

NAME                                         DESIRED   CURRENT   READY   AGE
replicaset.apps/components-mock-6b58c499dd   1         1         1       95s
replicaset.apps/nginx-6799fc88d8             1         1         1       95s
  • KEDA の ScaledObject をデプロイする

今回デプロイする ScaledObject閾値2 に設定している.

apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
  name: http-scaledobject
  namespace: demo
  labels:
    deploymentName: nginx
spec:
  maxReplicaCount: 5
  scaleTargetRef:
    name: nginx
  triggers:
    - type: metrics-api
      metadata:
        targetValue: '2'  # 閾値
        url: "http://components-mock.demo.svc.cluster.local:3003/components"  # 対象のREST API
        valueLocation: "components.worker.tasks"  # responseのjson構造

なお, サンプルではレスポンスのデフォルトが 0のため ScaledObject がトリガーされnginx0に Scale Inする.

$ make deploy-scaledobject
or 
$ kubectl apply -f ./deploy/demo/scaledobject/metrics-api.yaml
scaledobject.keda.sh/http-scaledobject created

demo Namespace を確認すると 0に Scale In したことが分かる.

$ kubectl get po -n demo
NAME                               READY   STATUS    RESTARTS   AGE
components-mock-6b58c499dd-x6bf7   1/1     Running   0          7m16s
  • 値を変更して, Scale Outさせる /deploy/demo/app/component.yaml を変更する
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: components-mock
  name: components-mock
  namespace: demo
spec:
  replicas: 1
  selector:
    matchLabels:
      app: components-mock
  strategy:
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 1
    type: RollingUpdate
  template:
    metadata:
      labels:
        app: components-mock
    spec:
      containers:
      - name: components-mock
        image: cabi99/components-mock:0.0.1
        env:
        - name: WORKER_TASKS
          value: "0"   # ここの値を「2」に変更する
        imagePullPolicy: Always
        ports:
        - containerPort: 3003

変更後に再デプロイする.

$ make deploy-app
or 
$ kubectl apply -f ./deploy/demo/app/

namespace/demo unchanged
service/components-mock unchanged
deployment.apps/components-mock configured
deployment.apps/nginx unchanged

nginx が Scale Outしていることが確認できる.

$ kubectl get po -n demo -w

NAME                               READY   STATUS              RESTARTS   AGE
components-mock-6c494cd68b-4tkmv   1/1     Running             0          32s
nginx-6799fc88d8-22q9l             0/1     ContainerCreating   0          4s 
nginx-6799fc88d8-22q9l             1/1     Running             0          5s

なお、今回は閾値を2にしているので、WORKER_TASKS を 10 に変更してデプロイすれば, maxReplicaCount で定義した値までScale Outする.

$ kubectl get po -n demo -w

NAME                               READY   STATUS    RESTARTS   AGE  
components-mock-6d66575d55-r8vxh   1/1     Running   0          2m17s
nginx-6799fc88d8-22q9l             1/1     Running   0          4m11s
nginx-6799fc88d8-95r6v             1/1     Running   0          2m4s 
nginx-6799fc88d8-jkdqw             1/1     Running   0          2m4s 
nginx-6799fc88d8-wkmq4             1/1     Running   0          2m4s
nginx-6799fc88d8-xvctr             1/1     Running   0          109s

まとめ

KEDA v2を触ってみたが, v1との使い勝手に大きな差はなかった. しかし, 今回のバージョンアップで CPU と メモリ が追加により, Kubernetes Horizo​​ntal Pod Autoscaler と共存する形でなく, 自動スケーリング のリソースは全て KEDA に統一することで シンプル性を担保できる. また, Metrics API を利用すれば, APIが提供されているサービスをトリガーにすることが容易であったり, SQLクエリに基づいてワークフローを自動スケーリングも可能になるので拡張性の高い環境構築に活かせると感じた.

VSCode の Remote Development を使って開発者体験を上げる

はじめに

Remote Developmentとは

Remote Developmentは, VSCode からServerやWindows Subsystem for Linux (WSL), Containerなどの VSCode を実行しているホスト以とは別の環境に接続し, Server上のワークスペースを開発環境のように扱うことができる. これにより環境構築済みのServerへVSCodeから直接アクセスすることができ,開発者間での環境を簡単に統一できたり, ローカル環境に影響を与えず, 開発環境を構築/削除が容易にできる.

code.visualstudio.com

試してみる

今回はMacを使い, SSHで他のサーバに接続する手順を説明する.

拡張機能インストール

はじめに, Remote Development拡張機能をインストールする. VSCodeRemote Developmentを検索し,インストールする. Remote Development をインストールすると,Remote WSL, Remote SSH, Remote Containers のようにそれぞれに接続するための 拡張機能が自動的にインストールされる. とくにRemote WSL はWSLを利用しているWindowsユーザーにとっては便利機能だと思う.

f:id:JunichiMitsunaga:20201130232217p:plain
Remote Development Extension

SSH接続

サーバへの接続はSSHを用いて行われるため,鍵認証方式でサーバとSSH接続できるようにセットアップしておく必要がある. 今回は, Microsoft Azure 上に仮想マシンを作成してそこに接続する.

docs.microsoft.com

VSCode の左側のRemote Development タブを開くと接続先一覧が表示される.すでにsshで接続するために,~/.ssh/configなどがある場合は読み込まれて設定している接続先一覧が表示される.

configファイルを持っていない場合は,No SSH hosts...のような表示が出ているので,ギアクリックしてSSHのconfigファイルを作成する.

f:id:JunichiMitsunaga:20201201001208p:plain
Remote SSH Extension 1

config ファイルを以下のformatで作成する.

# Read more about SSH config files: https://linux.die.net/man/5/ssh_config
Host host1
    HostName xxx.xxx.xxx.xxx (IPアドレス, DNSなど接続先)
    Port 22
    User hoge (ログインするユーザ名)
    IdentityFile ~/.ssh/sample_rsa (鍵認証に使う鍵ファイルを記述)

configファイルを設定するとconfig のhostが表示されるので選択して接続する.

f:id:JunichiMitsunaga:20201201001501p:plain
Remote SSH Extension 2

f:id:JunichiMitsunaga:20201201110835p:plain
Remote SSH Extension 3

「Continue」を選択する.

f:id:JunichiMitsunaga:20201201111058p:plain
Remote SSH Extension 4

接続が成功したら,「Open Folder」から接続先のフォルダを選択して操作できるようになる.

f:id:JunichiMitsunaga:20201201111250p:plain
Remote SSH Extension 5

Container 接続

接続するために, nginx のimageをpullして起動しておく.

$docker run --name remote-sample -d -p 8080:80 nginx
$ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                  NAMES
c164ead158ca        nginx               "/docker-entrypoint.…"   15 seconds ago      Up 13 seconds       0.0.0.0:8080->80/tcp   remote-sample

nginx が起動したのを確認して, Remote Development タブを開くと, Containers に nginxが表示される. リアルタイムで表示されなかったが,VSCodeを再起動したら表示された.

f:id:JunichiMitsunaga:20201130235455p:plain
Remote Containers Extension 1

nginx を選択して, 「Attach Container」を選ぶと nginx containerに接続して, container内部の情報をVSCodeで閲覧して修正できる. 添付画像は container 接続後に /etc/nginx 配下のfileを確認している.

f:id:JunichiMitsunaga:20201130235915p:plain
Remote Containers Extension 2

他にもチュートリアル用のContainerが用意されているので,そちらで各開発言語が含まれているContainerに接続できる.

code.visualstudio.com

終わりに

別環境をローカル環境のように扱うことができ,かつ使い慣れたエディタで開発できることは非常に便利になった. 環境構築されたContainerやServerを使うことで初期設定のコストが削減される. またローカル特有の問題に影響を受けることも少ない.

Flux v2 を使った GitOps チュートリアル Flux v1 との比較

Weaveworks社が提唱する kubernetes のベストプラクティスで , Single Source of Truth として Git を採用し,Kubernetes リソースなどを継続的にデリバリーしていく GitOps がある。 今回はそんな GitOpsを実現するツールである Flux のv2が出てきたのでチュートリアルを試し、 v1との比較を行っていく。

なお、 GitOps の説明や過去にv1を検証した内容は以下の記事等に紹介がある。

Get started

今回は Flux v2の動作を確認するために「Get started」の内容に沿って実施していく。 toolkit.fluxcd.io

事前準備

localに kubernetes 環境を構築する。 今回は minikube を使って cluster の構築を行う。 kubernetes.io

$ kubectl version --short
Client Version: v1.19.3
Server Version: v1.19.2

次に Flux を操作するためのクライアントをインストールする。 v1の時は fluxctl だったが、v2からは flux に変更されている。

$curl -s https://toolkit.fluxcd.io/install.sh | sudo bash
$flux --version
flux version 0.2.3

最後にチュートリアルで使う GitHub リポジトリをフォークしておく。 github.com

セットアップ

flux を使って, Flux に対応した環境か確認する。

$ flux check --pre
► checking prerequisites
✔ kubectl 1.19.4 >=1.18.0
✔ Kubernetes 1.19.2 >=1.16.0
✔ prerequisites checks passed

環境の問題はなさそうなので,環境変数GITHUB_TOKEN GITHUB_USER GITHUB_REPOを設定して flux bootstrapコマンドを実行する。

$ export GITHUB_TOKEN=<your-token>
$ export GITHUB_USER=<your-username>
$ export GITHUB_REPO=<repository-name>

$ flux bootstrap github \
    --owner=${GITHUB_USER} \
    --repository=${GITHUB_REPO} \
    --branch=main \
    --personal \
    --path=clusters/staging
► connecting to github.com
✔ repository cloned
✚ generating manifests
✔ components are up to date
► installing components in flux-system namespace

namespace/flux-system created
networkpolicy.networking.k8s.io/allow-scraping created
networkpolicy.networking.k8s.io/allow-webhooks created
networkpolicy.networking.k8s.io/deny-ingress created
role.rbac.authorization.k8s.io/crd-controller-flux-system created
rolebinding.rbac.authorization.k8s.io/crd-controller-flux-system created
clusterrolebinding.rbac.authorization.k8s.io/cluster-reconciler-flux-system created
customresourcedefinition.apiextensions.k8s.io/buckets.source.toolkit.fluxcd.io created
customresourcedefinition.apiextensions.k8s.io/gitrepositories.source.toolkit.fluxcd.io created
customresourcedefinition.apiextensions.k8s.io/helmcharts.source.toolkit.fluxcd.io created
customresourcedefinition.apiextensions.k8s.io/helmrepositories.source.toolkit.fluxcd.io created
service/source-controller created
deployment.apps/source-controller created
customresourcedefinition.apiextensions.k8s.io/kustomizations.kustomize.toolkit.fluxcd.io created
deployment.apps/kustomize-controller created
customresourcedefinition.apiextensions.k8s.io/helmreleases.helm.toolkit.fluxcd.io created
deployment.apps/helm-controller created
customresourcedefinition.apiextensions.k8s.io/alerts.notification.toolkit.fluxcd.io created
customresourcedefinition.apiextensions.k8s.io/providers.notification.toolkit.fluxcd.io created
customresourcedefinition.apiextensions.k8s.io/receivers.notification.toolkit.fluxcd.io created
service/notification-controller created
service/webhook-receiver created
deployment.apps/notification-controller created
Waiting for deployment "source-controller" rollout to finish: 0 of 1 updated replicas are available...
deployment "source-controller" successfully rolled out
Waiting for deployment "kustomize-controller" rollout to finish: 0 of 1 updated replicas are available...
deployment "kustomize-controller" successfully rolled out
deployment "helm-controller" successfully rolled out
Waiting for deployment "notification-controller" rollout to finish: 0 of 1 updated replicas are available...
deployment "notification-controller" successfully rolled out
✔ install completed
► configuring deploy key
✔ deploy key configured
► generating sync manifests
✔ sync manifests pushed
► applying sync manifests
◎ waiting for cluster sync
✔ bootstrap finished

$ kubectl get all -n flux-system

NAME                                           READY   STATUS    RESTARTS   AGE
pod/helm-controller-7fc55767cc-bfzck           1/1     Running   0          4m51s
pod/kustomize-controller-6b85bf79f9-t6qs4      1/1     Running   0          4m51s
pod/notification-controller-7bb8667967-6xqdb   1/1     Running   0          4m48s
pod/source-controller-6cdb6c8889-hpsxx         1/1     Running   0          4m53s

NAME                              TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)   AGE
service/notification-controller   ClusterIP   10.108.140.72    <none>        80/TCP    4m50s
service/source-controller         ClusterIP   10.104.224.8     <none>        80/TCP    4m53s
service/webhook-receiver          ClusterIP   10.103.160.216   <none>        80/TCP    4m48s

NAME                                      READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/helm-controller           1/1     1            1           4m51s
deployment.apps/kustomize-controller      1/1     1            1           4m53s
deployment.apps/notification-controller   1/1     1            1           4m48s
deployment.apps/source-controller         1/1     1            1           4m53s

NAME                                                 DESIRED   CURRENT   READY   AGE
replicaset.apps/helm-controller-7fc55767cc           1         1         1       4m51s
replicaset.apps/kustomize-controller-6b85bf79f9      1         1         1       4m52s
replicaset.apps/notification-controller-7bb8667967   1         1         1       4m48s
replicaset.apps/source-controller-6cdb6c8889         1         1         1       4m53s

bootstrap コマンドで flux-system のnamespaceが作成されて, GitOpsを実施するための kustomize , helm のcontrollerが作成されている。 この他にもv2では監視機能が強化されたこともあって notificationのcontrollerが作成されている。 Flux v1flux-agentmemcacheのみだったのに対して役割に応じてcontrollerが増えているようだ。 Flux v2 の全体構成は公式に掲載されている図が非常に分かりやすい。

           Flux v2 構成図 https://toolkit.fluxcd.io/diagrams/gitops-toolkit.png

           Flux v2より引用

なお、bootstrapで対象にしたrepository で管理されているmanifestがclusterに展開されていることが分かる。

$ flux get kustomizations --all-namespaces
NAMESPACE       NAME            REVISION                                        SUSPENDED       READY   MESSAGE
flux-system     apps            main/32112c9d1a3f89fdd35f91fe3ae5d0b8096923b1   False           True    Applied revision: main/32112c9d1a3f89fdd35f91fe3ae5d0b8096923b1
flux-system     flux-system     main/32112c9d1a3f89fdd35f91fe3ae5d0b8096923b1   False           True    Applied revision: main/32112c9d1a3f89fdd35f91fe3ae5d0b8096923b1
flux-system     infrastructure  main/32112c9d1a3f89fdd35f91fe3ae5d0b8096923b1   False           True    Applied revision: main/32112c9d1a3f89fdd35f91fe3ae5d0b8096923b1


$ flux get helmreleases --all-namespaces
NAMESPACE       NAME    REVISION        SUSPENDED       READY   MESSAGE
nginx           nginx   5.6.14          False           True    release reconciliation succeeded
podinfo         podinfo 5.0.3           False           True    release reconciliation succeeded
redis           redis   11.3.4          False           True    release reconciliation succeeded

GitOps実践

初期状態の確認

まず, bootstrapでデプロイされた初期のappにアクセスするためにport-forwardする。

$ kubectl -n podinfo port-forward svc/podinfo 9898:9898

Forwarding from 127.0.0.1:9898 -> 9898
Forwarding from [::1]:9898 -> 9898
Handling connection for 9898
Handling connection for 9898

ブラウザからlocalhost:9898にアクセスすると、下記のようなサンプルアプリケーション画面が表示される。なお、初期状態ではv5.0.3と表示される。

サンプルアプリケーション画面初期状態
flux v2 gitops before

マニフェストの修正

GitOps対象のリポジトリ flux2-kustomize-helm-example の中にあるマニフェスト flux2-kustomize-helm-example/workloads/apps/staging/podinfo-values.yamlを修正する。chart.spec.version: ">=1.0.0-alpha"chart.spec.version: "5.0.0"に変更し、repositoryにpushしておく。

podinfoを確認すると変更されたことが確認できる

$ flux get helmreleases --all-namespaces
NAMESPACE       NAME    REVISION        SUSPENDED       READY   MESSAGE
nginx           nginx   5.6.14          False           True    release reconciliation succeeded  
podinfo         podinfo 5.0.0           False           True    release reconciliation succeeded  
redis           redis   11.3.4          False           True    release reconciliation succeeded

再度、ブラウザから確認する

$ kubectl -n podinfo port-forward svc/podinfo 9898:9898
Forwarding from 127.0.0.1:9898 -> 9898
Forwarding from [::1]:9898 -> 9898

versionが 5.0.0に変更していることが分かる これによりgitの結果を正とした GitOpsが実現できている

f:id:JunichiMitsunaga:20201118094212p:plain
flux v2 gitops after

モニタリングを設定

Flux v1では flux agentの監視が困難であり、同期の失敗を検知/修正するまでに時間がかかっていたが、 Flux v2 になってからは Prometheusによる監視と Grafanaダッシュボードが提供された。チュートリアルでは扱っていないが、有用な仕組みなので試してみる。

flux2リポジトリにあるmanifestから作成する

$ flux create source git monitoring \
>   --interval=30m \
>   --url=https://github.com/fluxcd/flux2 \
>   --branch=main
✚ generating GitRepository source
► applying GitRepository source
✔ GitRepository source created
◎ waiting for GitRepository source reconciliation
✔ GitRepository source reconciliation completed
✔ fetched revision: main/37fb0f632b7acd192a314388c8f6bab5a6376764

$ flux create kustomization monitoring \
  --interval=1h \
  --prune=true \
  --source=monitoring \
  --path="./manifests/monitoring" \
  --health-check="Deployment/prometheus.flux-system" \
  --health-check="Deployment/grafana.flux-system"

✚ generating Kustomization
► applying Kustomization
✔ Kustomization created
◎ waiting for Kustomization reconciliation
✔ Kustomization monitoring is ready
✔ applied revision main/37fb0f632b7acd192a314388c8f6bab5a6376764

kubectl -n flux-system port-forward svc/grafana 3000:3000

ブラウザでダッシュボードにアクセスすると GitOps 状態が確認できる。

Control planeのダッシュボード

http://localhost:3000/d/gitops-toolkit-control-plane/gitops-toolkit-control-plane

f:id:JunichiMitsunaga:20201118100432p:plain
control

Cluster reconciliationのダッシュボード

http://localhost:3000/d/flux-cluster/flux-cluster-stats

f:id:JunichiMitsunaga:20201118100354p:plain
cluster

v1との比較

導入のしやすさ

v2になってbootstrap コマンドが追加されたことによって、コマンド1つで設定できるため、v1と比較してnamespaceの準備等がなくなり、簡単に設定できるようになった。

監視

Flux v1 のlogを監視して、errorが発生した場合にトラブルシューティングするなど、泥臭いことをやっていた(少なくとも自分の環境では)。 Flux v2PrometheusGrafanaが提供されたので、metricsの取得やダッシュボードによる可視化が可能になり、保守性が高まった。 また、slackへの通知などの機能も提供されたので、障害発生から検知までの時間短縮に繋がる。

構成

Flux v1はflux agentが1つだったことに対して、Flux v2では役割毎にcontrol planeが分かれた。個人的には役割が明確になったため、トラブルシューティングが簡単になり、かつ自分たちの環境にマッチした最小構成を構築するのが容易になったと感じた。

まとめ

Flux v2チュートリアルを実施してみたが、Flux v1の時よりも導入は容易になったと感じる。 CLIに関しての変更はv1ユーザーにとっては破壊的変更なため、v2へ移行するには時間がかかりそうだ。しかし、移行した場合は、監視や通知といったこれまで苦戦していた部分が提供されているので、時間をかけてしっかり移行していきたいと思う。

移行の手順は用意されているのでcluserの移行だけなら簡単そう。 pipelineやその他の仕組みでFlux CLIを使っている場合は、考慮が必要そう。

toolkit.fluxcd.io

GitOps Days 2020 参加レポート 2日目

はじめに

2020/5/21(木)開催のGitOps Days 2020のDay2に参加してきましたので、 まとめていきたいと思います!

※1日目と同様に発表者ではなく、ただ聞くだけです。。。

1日目の参加レポートはこちらです。 cabi99.hatenablog.com

印象深かったセッションなど

ここでは印象深かったセッション(など)についてまとめていきます。 Day 1ではGitOpsを実際に導入するための具体的な技術をチームに定着させる方法やGitOpsの今後について説明するなど、 1つ1つのセッションが濃ゆい内容になります。

11:00 – 11:57 am PT: Flux and Helm: Intro and How to teach your teams – Stefan Prodan and Leigh Capili

@stefanprodanさん@capileighさんが従来のCI/CDパイプラインの課題を明確にし、GitOpsに変更する利点と具体的なデプロイの流れを説明しデモを見せてくれました。

従来のCI/CDの課題

従来のCI/CDではビルドとデリバリーを自動化できていましたが ここでの問題提起は監視や復旧といったオペレーション観点となっています。 CI/CDを導入しているチームに共通して抱えている課題のように感じます。

トレーサビリティ

  • クラスターで実行されているアプリのバージョンを確認するか?
  • 複数ビルドを並行して実行するとどうなるのか?

セキュリティ

  • クラスター認証の管理方法をどうするのか?
  • 複数クラスターをターゲットにする方法は?

ディザスターリカバリ

  • インフラ依存関係に対処する方法は?

GitOpsに変更する利点

全体的にGitで宣言的に管理できるようになります。 これにより従来のようにrebuildする機会も減り、Gitのマニフェストを 前バージョンに戻すだけで切り戻しができるようになります。 OPAのようなポリシー適応はまだ実現していないので興味深いです。

  • インフラストラクチャの変更についてPRsとレビューで協力できる
  • 静的分析(OPA)でポリシーを適用できる
  • rollbackとrevertが簡単
  • 平均回復時間を短縮できる

GitOps準備

GitOps実現にあたって必要なものを説明しています。

必須

オペレーション

  • リポジトリ変更を監視し、通知する
  • 設定ドリフトを検出して修正する
  • 設定とドリフトに関するアラート
  • コミッターのバリデーションを行う

flux, helmを利用したGitOpsデモ

デモについては省略します。

fluxの使い方はこちらを参考にしてください。 cabi99.hatenablog.com

所感

2日目は1日目に説明した概念について具体的にデモをする場面が多いです。 これから導入する人や動作のイメージがわかない人向けのような気もしました。 2日間を通してGitOpsは概念であり、実現の方法が1つでないこと、そしてセキュリティに対して利点が多いこと。 これらが参加する前の自分になかった視点なのでとても参考になりました。 また、これらの新しい知識をプロダクトチームにoutputできるのでよりチームのDevOpsが促進することを楽しみにしています。 とても有益なイベントでしたので次回開催もぜひ参加したいと思います。

GitOps Days 2020 参加レポート 1日目

はじめに

2020/5/20(水)開催のGitOps Days 2020に参加してきましたので、 まとめていきたいと思います!

※発表者ではなく、ただ聞くだけです。。。

www.gitopsdays.com

GitOps Daysは、私が知っている限りではGitOpsに関するはじめての大きめイベントです。 はじめてGitOpsについて学びたい人や、GitOpsの利点を理解するようにチームを説得する人向けのようです。 現在のプロダクトでGitOpsを導入しているので世界的にGitOpsがどのように浸透しているのか?今後の展望はどうなっていくのか?などに興味を持ち参加しました。

GitOpsとは?

まずGitOpsとは何ぞや?という疑問もあると思うので説明します。 GitOpsはWeaveworks社が提唱した、Kubernetesの運用ベストプラクティスであり、 宣言的インフラストラクチャとアプリケーションの「Single source of Truth」としてGitを利用し、システム実行環境やアプリケーションの変更を行う方法です。

簡単に述べるとgitのcodeと環境面が同期して常にcodeの状態が正になる方法です。 メリットとして、codeですべて管理できる、環境構築が容易になる、セキュリティが向上するなどが挙げられます。

過去にGitOpsを実現するfluxを検証したことがあるので興味がある方はご覧ください。 cabi99.hatenablog.com

印象深かったセッションなど

ここでは印象深かったセッション(など)についてまとめていきます。 Day 1ではGitOpsがどのようなものなのか?概念やメリットを説明しています。 他にも具体的なプラクティスを紹介し、導入企業のエンジニアが事例を紹介しています。

10:00 – 10:27 am PT: GitOps Practitioner Highlight – Palo Alto Networks – Javeria Khan

Javeria KhanさんがGitOpsプラクティスを紹介してくれました。

利用する技術以外にもメリットやオンボーディング時の注意点が興味深かいです。

GitOpsの利点

  1. 可逆性
  2. 監査証跡
  3. 透明性
  4. 反復的なタスクを自動化する
  5. 開発および運用チーム間のコラボレーション

5番以外の利点は認識としてありました。 GitOpsにより環境が同期するため、コード管理時にDevelopとOperationを意識する。 これによりDevとOpsのようにチームが完全分業体制から共通の概念を持つ one teamとして機能しやすいのだと解釈しました。

Layer別の役割と技術

GitOps導入で技術の統一は必須でなく、それぞれの用途に合う仕組みを採用します。 また、環境なのかアプリケーションなのかでオーナシップを持つメンバーが変化します。

インフラ層(IaC)

ステークホルダー

  • SRE
  • Infra Engineers
  • Management

プロビジョニング(例)

  • Terraform → Atlantis
  • Salt → Scheduled states

設定情報(例)

Puppet → code manage Flux, Argo → cluster controllers + config repos

アプリ層

ステークホルダー

  • Developers
  • DevOps, Test Engineers

アプリケーションTemplating, Deployments

  • Helm, Kustomize
  • Flux, Argo: cluster controllers + app manifest
  • Flagger: Blue/Green

オンボーディングで心掛けること

自分たちのチームもGitOpsを導入しているのですが、 オンボーディング時の心掛けはかなり同意です!

  • Dev

    • 時間を先行投資して、仕組みと文化を定着させること
  • Management

    • 個人への依存をなくすこと

12:40 – 1:10 pm PT: GitOps for Cost Efficiency, Compliance, Velocity, Security, Resilience, and more! – Cornelia Davis

@cdavisafcさんによるコスト効率、コンプライアンス、速度などなど良い点をてんこ盛りに説明して頂いてます。

GoogleDevOps Elite performance reportでは、セキュリティについてあまり言及されていないので、ここでGitOpsだよ!と述べています。 システムの可用性、セキュリティを支えるために、必要な要素がGitOpsによりどのようにカイゼンするか?明確になるセッションでした。

GitOpsを支える5つの要素

  • アプリケーションチームの生産性
  • アプリケーションチームの自主性
  • 安全なネットワークの確立
  • 再現性
  • 冗長性

ここは動画が公開されてもう一度視聴してからまとめようと思います。。。

1:10 – 1:17 pm PT: Security and GitOps – Maya Kaczorowski

パズルがアイスクリームと同じくらい大好きな @MayaKaczorowski さんによる GitOpsがもたらすセキュリティの利点の説明です。

個人的には従来のCIOpsのようなpush型デプロイからpull型デプロイへ変更されるため kubernetes clusterのip制御が無くなるので、セキュリティホールのリスクが減る認識でした。 このセッションでは、それ以外にもセキュリティの利点があることを学べました。

セキュリティ利点

管理

さまざまな仕組みが「〇〇 as Code」で実現するため、 バージョニングや不変なものをSingleSourceに集約でき、全体を管理しやすくなる。

監視

デプロイ方法が決まるため、監視しやすい

セキュリティアップデート

デプロイが単純化されるため、セキュリティアップデートに集中する時間が取れる。

軽くまとめてみる?

gitログ、PRコメント、およびレビューポリシーにより、責任を共有しセキュリティの脆弱性の解決に対して協力体制が作れるようです。 同じ指標が持てるようになれば、同じ方向に向かって協力できるようになるのが良いです。 なんだかエンジニアリングでプロジェクトをデザインしている感じが好きです。

GitOps = IaC + Config as Code + Policy as code + Policy as code + thing as code

所感

Day 1は主にGitOpsの抽象的な部分を説明が多かったです。 GitOps自体は哲学であり、それを実現する仕組みは1つでなく、目的に併せて変化するものだと感じました。 実際に導入事例の紹介でも企業によって「GitOps = 〇〇 + △△」の定義が異なることも 多く、各企業が自分たちのモデルにあったものを探して適応している印象です。 もしかすると組織のDevOps習熟度で、この辺は変化していきそうな気がします。

※英語を学習中なので、所々説明している内容と異なるかもしれませんがご了承ください。 むしろ、これはこういうことだよとかフィードバックがあると嬉しいです。

KEDA による イベント駆動オートスケール と 使い方を考えてみる

背景

MicrosoftAKS を利用して kubernetes を運用しており、podのauto scaleはHorizontal Pod Autoscalerの機能を利用しています。 Horizontal Pod Autoscalerは、簡単に説明すると指定したmetricをpodから取得して、閾値に達した場合、podをauto scaleする仕組みです。 これはkubernetesでcontainerを安定し運用するための便利な仕組みです。しかし、kubernetesのリソースに対して監視するため 外部リソースの状態に応じてpodをscaleする場合は、別の仕組みを検討する必要があります。

KEDAとは

KEDA (Kubernetes Event-driven Autoscaling)は、 kubernetes clusterに追加できる単一目的の軽量コンポーネントで、CNCFのSandboxプロジェクトにホストされているkubernetesベースのイベント駆動オートスケーラーです。宣言的に定義されたイベントに応じて、kubernetesの任意のコンテナーのスケーリングを促進できる。Horizo​​ntal Pod Autoscalerなどのkubernetesコンポーネントと連携して動作し、上書きや重複なしに機能拡張できます。

keda.sh

KEDAの役割

KEDAはkubernetes内で2つの重要な役割を果たします。

  • Agent kubernetes deploymentをアクティブ/非アクティブ化を管理します。

  • Metrics kubernetes metricsサーバーとして機能します。キューの長さやストリームラグなどのイベントデータをHorizo​​ntal Pod Autoscalerに公開してscale outを促進します。ソースから直接イベントを消費するのはDeploymentの役割であり、これにより、豊富なイベントの統合が維持され、キューメッセージの完了や破棄などのジェスチャーをそのまま使用できます。

Architecture

公式の説明からKEDAはetcdや外部リソースを監視して標準のHPAや対象podに命令します。

https://keda.sh/img/keda-arch.png

対象ソース

AWSやAzureなど幅広く対応しています。また、「External」リソースを利用することで柔軟なevent操作ができます。 詳細はこちら https://keda.sh/docs/concepts/#event-sources-and-scalers

デプロイ

今回はYAML Manifestを使ってdeployします。 ※HelmやOperatorも可

  • KEDAのrepositoryをcloneし、CRDを作成する
kubectl apply -f ./deploy/crds
  • scaleとtriggerを行うCRDがあることを確認する
$ kubectl get crds
NAME                                 CREATED AT
scaledobjects.keda.k8s.io            2020-04-21T01:43:13Z
triggerauthentications.keda.k8s.io   2020-04-21T01:43:13Z
  • CRDを作成したらKEDA operatorとmetrics serverを作成する
kubectl apply -f ./deploy
  • デフォルトでは「keda」namespaceに作成される
$ kubectl get all -n keda
NAME                                         READY   STATUS    RESTARTS   AGE
pod/keda-metrics-apiserver-f465ccb68-wdk5l   1/1     Running   0          23h
pod/keda-operator-8fdf64d5-pkwf9             1/1     Running   0          23h

NAME                             TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)             AGE
service/keda-metrics-apiserver   ClusterIP   10.105.111.250   <none>        443/TCP,80/TCP      23h
service/keda-operator-metrics    ClusterIP   10.110.125.60    <none>        8383/TCP,8686/TCP   23h

NAME                                     READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/keda-metrics-apiserver   1/1     1            1           23h
deployment.apps/keda-operator            1/1     1            1           23h

NAME                                               DESIRED   CURRENT   READY   AGE
replicaset.apps/keda-metrics-apiserver-f465ccb68   1         1         1       23h
replicaset.apps/keda-operator-8fdf64d5             1         1         1       23h

これでKEDAのdeployは完了です。

動作確認

KEDAのdeployが完了したので実際外部リソースをtriggerしてpodのauto scaleを確認します。 今回はnginxのpodをAzure storage accountのblob container file uploadイベントをhookしてpodをscaleさせます。

簡単なサンプルですがこちらに載せておきます。 https://github.com/JunichiMitsunaga/keda-example

  • Azureにresource groupとstorage accountを作成する
az group create --location japaneast --name keda-example
az storage account create --name kedaexample --resource-group keda-example
  • connection stringを取得する
az storage account show-connection-string --name kedaexample
  • 取得したconnection stringでk8sのsecretを作成する

01-secret.yaml

apiVersion: v1
kind: Secret
metadata:
  name: account-secret
  namespace: keda-scale
data:
  connectionString: ***
  • auto scale用のpodをdeployする
kubectl apply -f .deploy/
  • 「keda-scale」namespaceにpodがdeployされていることを確認する
$ kubectl get all -n keda-scale                         
NAME                              READY   STATUS    RESTARTS   AGE
pod/scale-nginx-898f5b6d4-x8897   1/1     Running   0          46s

NAME                          READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/scale-nginx   1/1     1            1           47s

NAME                                    DESIRED   CURRENT   READY   AGE
replicaset.apps/scale-nginx-898f5b6d4   1         1         1       46s
  • KEDAによるscaleを実施するために「ScaledObject」をデプロイする
kubectl apply -f keda-hpa/
  • 「ScaledObject」がdeployされていることを確認する
$ kubectl get ScaledObject -n keda-scale
NAME                      DEPLOYMENT    TRIGGERS     AGE
azure-blob-scaledobject   scale-nginx   azure-blob   28s

ScaledObjectをdeployするとscale条件にマッチしてないため該当のpodは0スケールされます。 ※この仕組みは地味にうれしいですね

$ kubectl get po -n keda-scale
No resources found in keda-scale namespace.
  • triggerを満たしてauto scaleを確認する 今回のtriggerはblob containerにfileを2つ以上uploadすること

1つ目のfileをuploadする 条件を満たしていないのでscaleされない

$ kubectl get po -w -n keda-scale

2つ目のfileをuploadする 条件を満たすのでpodがscale outされる

$ kubectl get po -w -n keda-scale
NAME                          READY   STATUS    RESTARTS   AGE
scale-nginx-898f5b6d4-zhgdm   0/1     Pending   0          0s
scale-nginx-898f5b6d4-zhgdm   0/1     Pending   0          0s
scale-nginx-898f5b6d4-zhgdm   0/1     ContainerCreating   0          0s
scale-nginx-898f5b6d4-zhgdm   1/1     Running             0          4s

fileを削除して条件を満たさないように変更する

$ kubectl get po -n keda-scale -w
NAME                          READY   STATUS    RESTARTS   AGE
scale-nginx-898f5b6d4-ftffd   1/1     Running   0          16s
scale-nginx-898f5b6d4-ftffd   1/1     Terminating   0          70s
scale-nginx-898f5b6d4-ftffd   0/1     Terminating   0          72s
scale-nginx-898f5b6d4-ftffd   0/1     Terminating   0          72s
scale-nginx-898f5b6d4-ftffd   0/1     Terminating   0          75s
scale-nginx-898f5b6d4-ftffd   0/1     Terminating   0          75s

以上よりAzure Blob Storageのeventからpodをscaleできた。

運用を考えてみる

リソース監視からのauto scale

背景で述べているようにkubernetesの標準機能はmemoryやcpuをtriggerにするため、Databaseのような外部リソースやpod内のthread、connection数といった他のmetricをtriggerにするのが困難でした。KEDAを利用することでAzure Monitorなどといった監視サービスと併用することでpodのconnection数が上限をtriggerにscale outするなどの運用方法が考えられます。 ただし、scale outする場合の他のリソースへの影響を考慮するため キャパシティプランニングする必要はあります。

Serverlessの実行

Serverlessアプリケーションは、AWS LambdaやAzure FunctionsなどのFaaSやAzure Container Instance(ACI) によるpodの起動など、さまざまな方法が挙げられます。もちろん、これらの仕組みでも十分に実現できますが、KEDAを利用することでkubernetes cluster内に一元管理できるためコストが楽になると感じました。 とくに長時間のbatch処理は「Azure Queue Storage → KEDAによるAuto Scale」といったシンプルな実装で管理でき、タイムアウト意識する必要も減るため有用な仕組みになりそうです。

所感

触ってみた印象としてKEDAは、kubernetes cluster内で実現するFaaSのイメージです。とくにkubernetesを普段運用している方は、扱いやすいものだと思います。 プロダクトを安定させる使い方や、新機能を効率よく動かす使い方など、プロダクトの課題に沿った形で柔軟に使えそうなので、auto scale や batch処理なの運用設計に困っている人がいれば是非触ってみてほしいです。

初心者の 負荷試験入門 2

はじめに

本記事は初心者の負荷試験入門シリーズの第2弾です!

前回の 初心者の負荷試験入門 その1 では、負荷試験のざっくりとした目的や指標、性能改善をまとめました。負荷試験を実施するにあたってどのような指標が必要なのかは何となくわかりましたが、実際にどのようなToolを利用してシステムに負荷をかけていくのかはまだ見ていないので今回はそれをまとめてみようと思います。

負荷試験ツール

ひとえにツールといっても負荷試験のツールにはいくつか種類があるようで、主に「攻撃ツール」、「モニタリングツール」、「プロファイリングツール」の3種類のツールを利用する。 ツールの役割はこんな感じ 攻撃ツール:システムに負荷を与えるツール(大量リクエストの送信など) モニタリングツール:システムのリソース状況を観測して可視化するツール プロファイリングツール:ミドルやアプリケーション内部を解析して可視化するツール

攻撃ツールの選択

攻撃ツールとは

システムを利用する側の動きをシミュレーションすることにより、対象のシステムを高負荷状態にできるツールのことを指します。 攻撃ツールを利用することでシステムに大量のリクエストが発生し、Dos攻撃を受けたかのような状態となります。

攻撃ツールに求められる要件

負荷試験を行うために攻撃ツールに必要とされる主な要件は下記の4つになります。 1.リクエストを正しくシミュレーションできること 2.攻撃の強さを制御できること 3.対象のシステムに対して十分な負荷を発生させられること 4.攻撃ツールの設置場所、起動場所を選択できること

1.リクエストを正しくシミュレーションできること 攻撃ツールによってはシナリオを組んだ攻撃が出来ないツールも存在するため、負荷試験の要件にそぐわない場合はこれらのツールを選定から外した方がよさそうです。

2.攻撃の強さを制御できること クライアントの同時起動数、リクエスト間隔、最大スループット数を調整することで攻撃の強さを設定できます。

3.対象のシステムに対して十分な負荷を発生させられること 攻撃ツールにより、どこまでの高負荷状態を効率よく発生させられるかが異なる為、自分たちのシステムの特性に合ったツールを選択する必要があります。

4.攻撃ツールの設置場所、起動場所を選択できること 攻撃ツールによって起動できる攻撃サーバに制約がある為、攻撃サーバを設置する場所が制限されるものがあります。

攻撃ツール用語

ツールによって多少用語が異なることがありますが、たいていの攻撃ツールは下記表のような概念が存在しています。用語を理解していればツールが変更になったとしても同じように負荷試験が行えるようです。

用語 説明
クライアント HTTPリクエストを同時に1つだけ発行できるリクエスト生成機
クライアントの同時起動数 攻撃ツール上で利用される攻撃用クライアントの数
Ramp-Up 期間 攻撃開始後にすべてのクライアントが起動するまでのウォームアップ期間
シナリオ クライアント毎に設定されたHTTPリクエストの発生パターン
シナリオ実行回数 クライアントがシナリオに沿ったリクエストを実施する回数
スループット システムが単位時間あたりに処理できるリクエストの数
レイテンシ 攻撃ツールがリクエストを出してからレスポンスを受け取るまでの期間

攻撃ツールの例

具体的な攻撃ツールを一部紹介しています。(各ツールの詳細については割愛します…調べたら記述予定)

  • Apache JMeter 特徴
    • リクエスト毎に動的にパラメータを変更可能
    • 複数のURLを組み合わせたシナリオを実施できる
    • GET,POST,PUT,DELETEメソッドの試験が可能 etc
  • Locust 特徴
    • シナリオをPythonスクリプトで記述できるため、柔軟なシナリオが作成できる
    • 結果表示がシンプル
    • 必要なサーバリソースが少ないた為、攻撃サーバで負荷をかけやすい etc
  • Gatling 特徴
    • developerフレンドリーなシナリオファイル
    • 見やすいレポートHTML etc

攻撃ツールにはそれぞれ特徴があり、負荷試験の対象となるシステムによって使い分けることが必要です。 とくに同じシステムに対する負荷試験でも利用するツールによって大きく結果がことなることがあるため、場合によっては複数のツールで攻撃を行い結果を比較してみることも必要かもしれません。

モニタリングツール/プロファイリングツール

攻撃ツールの中にはスループットの監視ツールや可視化ツールが含まれているものも多いですが、攻撃ツールから観測できるレイテンシはシステム全体のレイテンシのみであり、個別のサブシステム等のレイテンシは観測できません。

サブシステムにおける詳細なモニタリングやプロファイリングを補助するためのツールとして以下があります。 - topコマンドとnetstatコマンド - AWS管理コンソール(AWSを利用している場合) etc

そしてこれらのツールを利用してモニタリングしておきたい項目が以下の表になります。

サブシステム 監視すべきもの
ネットワーク 転送量
ハードウェアやOS CPU,メモリ,プロセス数,SWAP
TCP 外部へのコネクション状況
ディスク R/W 転送データ量
サーバミドルウェア コネクション数
アプリケーション プロファイラーにて監視

今後について

負荷試験に利用するツールについて調べたが主に攻撃ツールの特性による試験の向き不向き等が見えてきました。モニタリングについては文章ベースなので今後、実際にサンプルアプリケーションを作成して負荷試験を試してみる中でモニタリングのやり方を学習していこうと思います。

そのほか、こんなツールがあるよなど情報があればぜひご連絡頂ければと思います。