ry's Tech blog

Cloud Native技術などについて書いていきます。

Kubenews #30

2021-09-10

Managing Kubernetes seccomp profiles with security profiles operator (click here to source)

seccompプロファイルの作成と管理は煩雑であり、エラーが発生しやすくなるのを緩和する目的で作成された。

セキュリティプロファイルオペレータの機能

  • SeccompプロファイルCRD
  • seccompプロファイルをポッドにバインドするためのCRD
  • 実行中のポッドからseccompプロファイルを作成するためのCRD
  • Seccompプロファイルの同期とノードサポートの検証
  • メトリックス
  • ログエンリッチャー

インストール

cert-managerをインストールする必要があります。

$ kubectl apply -f https://github.com/jetstack/cert-manager/releases/download/v1.4.2/cert-manager.yaml

次にservice profile operatorのインストール

$ kubectl apply -f https://raw.githubusercontent.com/kubernetes-sigs/security-profiles-operator/master/deploy/operator.yaml

seccomp profileの作成

以下のプロファイルは、SCMP_ACT_LOGのデフォルトアクションのみを設定します。

profile1.yaml という名前でファイルを作成します。

apiVersion: security-profiles-operator.x-k8s.io/v1alpha1
kind: SeccompProfile
metadata:
  namespace: default
  name: profile1
spec:
  defaultAction: SCMP_ACT_LOG

では、作成していきます。

$ kubectl apply -f profile1.yaml
seccompprofile.security-profiles-operator.x-k8s.io/profile1 created

$ kubectl get seccompprofile profile1 --output wide
NAME       STATUS      AGE     LOCALHOSTPROFILE
profile1   Installed   7m21s   operator/default/profile1.json

作成されたプロファイルは、

/var/lib/kubelet/seccomp/operator/<namespace>/<profile name>.json

に格納されます。

$ ssh k8s-pool1-18290975-vmss000000 sudo cat /var/lib/kubelet/seccomp/operator/default/profile1.json
{"defaultAction":"SCMP_ACT_LOG"}

seccomp profileの利用

作成したprofileをPodに適用してきます。

apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  securityContext:
    seccompProfile:
      type: Localhost
      localhostProfile: operator/default/profile1.json
  containers:
    - name: nginx
      image: nginx

プロファイルの継承

1つのprofileをベースとして使用して新しいカスタムプロファイルを作成することもできます。

apiVersion: security-profiles-operator.x-k8s.io/v1alpha1
kind: SeccompProfile
metadata:
  namespace: default
  name: inheritance-profile1
spec:
  defaultAction: SCMP_ACT_ERRNO
  baseProfileName: base-profile1
  syscalls:
    - action: SCMP_ACT_ALLOW
      names:
        - mkdir

profile bindings

PodのSpecを直接いじりたくない場合に、ProfileBindingが有用である。 今回は、nginx:1.21.1のimageを使用するPodに対して、最初に作成した profile1を適用させる例を紹介します。

apiVersion: security-profiles-operator.x-k8s.io/v1alpha1
kind: ProfileBinding
metadata:
  name: nginx-binding
spec:
  profileRef:
    kind: SeccompProfile
    name: profile1
  image: nginx:1.21.1

適用します。

$ kubectl apply -f nginx-binding.yaml
profilebinding.security-profiles-operator.x-k8s.io/nginx-binding created

以下のprofileを指定していないPodを作成すると挙動が確認できます。

$ cat <<EOF kubectl create -f -
apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  containers:
    - name: nginx
      image: nginx:1.21.1
EOF
pod/nginx created

$ kubectl get pod nginx -o jsonpath='{.spec.containers[*].securityContext.seccompProfile}'
{"localhostProfile":"operator/default/profile1.json","type":"Localhost"}

profileの記録

以下のmanifestを適用した場合、app: nginx というラベルを持ったPodが作成された際に記録が開始されます。 そして、そのポッドが削除されると、seccompプロファイルリソース(ポッドごと)が作成され、使用できるようになります。

apiVersion: security-profiles-operator.x-k8s.io/v1alpha1
kind: ProfileRecording
metadata:
  name: recording
spec:
  kind: SeccompProfile
  recorder: hook
  podSelector:
    matchLabels:
      app: nginx

Shipwright - Building Container Images In Kubernetes (click here to source)

Shipwrightとという、Kubernetes上でコンテナイメージを作成するツールが紹介されています。

リソースとしては、

  • BuildStrategy or ClusterBuildStrategy
  • Build
  • BuildRun

BuildStrategy or ClusterBuildStrategy

BuildのManifestで指定する、コンテナイメージをビルドする際に使用するツールについてです。

現在は、以下の選択肢があるみたいです。

  • Available ClusterBuildStrategies
Name Supported platforms
buildah linux/amd64 only
BuildKit all
buildpacks-v3-heroku linux/amd64 only
buildpacks-v3 linux/amd64 only
kaniko all
ko all
source-to-image linux/amd64 only
  • Available BuildStrategies
Name Supported platforms
buildpacks-v3-heroku linux/amd64 only
buildpacks-v3 linux/amd64 only

Build

ここで、実際にどうビルドするのかを定義します。

  • spec.source.url : アプリケーションのソースコードのあるレポジトリを指定
  • spec.strategy : ビルドツールを指定
  • spec.output : 作成したimageをプッシュするregistryを指定
    • output.credentials.name : registryにアクセスする際に使用する既存のsecretを指定
apiVersion: shipwright.io/v1alpha1
kind: Build
metadata:
  name: s2i-nodejs-build
spec:
  source:
    url: https://github.com/shipwright-io/sample-nodejs
  strategy:
    name: kaniko
    kind: ClusterBuildStrategy
  output:
    image: us.icr.io/source-to-image-build/nodejs-ex
    credentials:
      name: icr-knbuild

例えば、

  • レポジトリのrootディレクトリにソースコードがない場合は、spec.source.contextDirにて指定
  • 独自のビルドツールを積んでいるimageを使う場合、spec.strategy.namesource-to-imageにし、spec.builder.imageにてそのimageを指定する

など、柔軟性がありそう。

apiVersion: shipwright.io/v1alpha1
kind: Build
metadata:
  name: s2i-nodejs-build
spec:
  source:
    url: https://github.com/shipwright-io/sample-nodejs
    contextDir: source-build/
  strategy:
    name: source-to-image
    kind: ClusterBuildStrategy
  builder:
    image: docker.io/centos/nodejs-10-centos7
  output:
    image: us.icr.io/source-to-image-build/nodejs-ex
    credentials:
      name: icr-knbuild

BuildRun

Kubernetes上でBuildを実行するリソース。

apiVersion: shipwright.io/v1alpha1
kind: BuildRun
metadata:
  name: buildpack-nodejs-buildrun-namespaced
spec:
  buildRef:
    name: s2i-nodejs-build
  serviceAccount:
    name: pipeline

Buildで定義したプッシュ先を上書きしたい場合、このリソースでも定義ができる。

apiVersion: shipwright.io/v1alpha1
kind: BuildRun
metadata:
  name: buildpack-nodejs-buildrun-namespaced
spec:
  buildRef:
    name: s2i-nodejs-build
  serviceAccount:
    name: pipeline
  output:
    image: us.icr.io/source-to-image-build/nodejs-ex
    credentials:
      name: icr-knbuild

Distributed tracing with Knative, OpenTelemetry and Jaeger (click here to source)

Knative、OpenTelemetry、Jaegerを使った分散トレーシングについて書かれています。

Setup

既にKnative Serving and Eventingがデプロイされてていることを前提としています。

まず、クラスターにOpenTelemetryオペレーターを追加します。 こちらは、cert-managerに依存しているため、そちらもデプロイします。

$ kubectl apply -f https://github.com/jetstack/cert-manager/releases/latest/download/cert-manager.yaml 

$ kubectl apply -f https://github.com/open-telemetry/opentelemetry-operator/releases/latest/download/opentelemetry-operator.yaml

次に、イェーガーオペレーターをデプロイします。

$ kubectl create namespace observability
$ kubectl create -n observability \
    -f https://raw.githubusercontent.com/jaegertracing/jaeger-operator/master/deploy/crds/jaegertracing.io_jaegers_crd.yaml \
    -f https://raw.githubusercontent.com/jaegertracing/jaeger-operator/master/deploy/service_account.yaml \
    -f https://raw.githubusercontent.com/jaegertracing/jaeger-operator/master/deploy/role.yaml \
    -f https://raw.githubusercontent.com/jaegertracing/jaeger-operator/master/deploy/role_binding.yaml \
    -f https://raw.githubusercontent.com/jaegertracing/jaeger-operator/master/deploy/operator.yaml

起動したら、次のコマンドを実行してJaegerインスタンスを作成できます。

$ kubectl apply -n observability -f - <<EOF
apiVersion: jaegertracing.io/v1
kind: Jaeger
metadata:
  name: simplest
EOF

次に、OpenTelemetryコレクターを作成します。

$ kubectl apply -f - <<EOF
apiVersion: opentelemetry.io/v1alpha1
kind: OpenTelemetryCollector
metadata:
  name: otel
  namespace: observability
spec:
  config: |
    receivers:
      zipkin:
    exporters:
      logging:
      jaeger:
        endpoint: "simplest-collector.observability:14250"
        insecure: true

    service:
      pipelines:
        traces:
          receivers: [zipkin]
          processors: []
          exporters: [logging, jaeger]
EOF

最後に、すべてのトレースがコレクターを指すようにEventing andServingを構成します。

$ for ns in knative-eventing knative-serving; do
  kubectl patch --namespace "$ns" configmap/config-tracing \
   --type merge \
   --patch '{"data":{"backend":"zipkin","zipkin-endpoint":"http://otel-collector.observability:9411/api/v2/spans", "debug": "true"}}'
done

Hello World

トレースインフラストラクチャがすべてデプロイおよび構成されたので、ハートビートイメージ をContainerSourceとして デプロイして、 すべてが正しく接続されていることをテストおよび確認できます。

$ kubectl apply -f - <<EOF
apiVersion: sources.knative.dev/v1
kind: ContainerSource
metadata:
  name: heartbeats
spec:
  template:
    spec:
      containers:
        - image: gcr.io/knative-nightly/knative.dev/eventing/cmd/heartbeats:latest
          name: heartbeats
          args:
            - --period=1
          env:
            - name: POD_NAME
              value: "heartbeats"
            - name: POD_NAMESPACE
              value: "default"
            - name: K_CONFIG_TRACING
              value: '{"backend":"zipkin","debug":"true","sample-rate":"1","zipkin-endpoint":"http://otel-collector.observability:9411/api/v2/spans"}'
  sink:
    uri: http://dev.null
EOF

今のところ、このコンテナは存在しないドメインhttp://dev.nullにハートビートを送信しているだけなので、このポッドのログを見ると、一連のDNS解決エラーが表示されますが、otel-collectorポッドのログを調べると、サービスからトレースを正常に受信していることがわかります。

ハートビートを受信するためにKnativeサービスを追加し、ハートビートサービスを更新します。

$ kubectl apply -f - <<EOF
apiVersion: serving.knative.dev/v1
kind: Service
metadata:
  name: event-display
spec:
  template:
    spec:
      containers:
        - image: gcr.io/knative-nightly/knative.dev/eventing/cmd/event_display:latest
          env:
            - name: K_CONFIG_TRACING
              value: '{"backend":"zipkin","debug":"true","zipkin-endpoint":"http://otel-collector.observability:9411/api/v2/spans"}'
EOF

$ kubectl apply -f - <<EOF
apiVersion: sources.knative.dev/v1
kind: ContainerSource
metadata:
  name: heartbeats
spec:
  template:
    spec:
      containers:
        - image: gcr.io/knative-nightly/knative.dev/eventing/cmd/heartbeats:latest
          name: heartbeats
          args:
            - --period=1
          env:
            - name: POD_NAME
              value: "heartbeats"
            - name: POD_NAMESPACE
              value: "default"
            - name: K_CONFIG_TRACING
              value: '{"backend":"zipkin","debug":"true","zipkin-endpoint":"http://otel-collector.observability:9411/api/v2/spans"}'
  sink:
    ref:
      apiVersion: serving.knative.dev/v1
      kind: Service
      name: event-display
EOF

これらのサービスがデプロイされたら、Jaegerダッシュボードでもう一度確認することで、おもしろいとレースが表示されます。

Getting fancy

Hello Worldより複雑な構成を紹介してくれているので、記事を読んでみてください。

Kubenews #extra-001

2021-09-**

配信なし

monday.com’s Multi-Regional Architecture: A Deep Dive (click here to source)

マルチリージョンに移行することを決定するときは、パフォーマンス優先、復元力優先、プライバシー優先等の優先事項に対する設計間で作業が大きく異なるため、主な動機を理解する必要があります。

プラットフォームを複数の地域で実行するに至る3つの主な動機

  • パフォーマンス

    • サーバーを顧客の近くで実行すると、待ち時間が短くなり、接続品質が向上し(特にモバイルで)、一般的にエンドユーザーのエクスペリエンスが向上します。
  • レジリエンス

    • 任意のリージョンにおいて任意の時点でユーザーにサービスを提供できる場合、複数のリージョンでシステムを同時に実行することは、システムの全体的なフォールトトレランスの向上、ダウンタイムの短縮につながる。
  • プライバシーとコンプライアンス

    • 顧客が世界のどこにデータを保存するかを選択できるようにすることで、明確な競争上の優位性が生まれ、PIIや機密情報を処理するヘルスケア、銀行、企業などの厳しく規制された業界との連携への扉が開かれます。

2番目のリージョンを追加する際の課題

【課題1】 サブドメインは基本的にスラッグであるが、完全ではない。

ユニークなサブドメインを使えるものもあれば、すべての顧客が使用する共有サブドメインがも存在してしまう。

【課題2】ユーザーが誰であるかさえわからない場合がある。

ログインフローにおいて、匿名の訪問者がプラットフォームに到着し、電子メールとパスワードを入力して、最終的にアカウントにルーティングされる際に、すべてのユーザーが同じサブドメインにアクセスします。

この時、どのリージョンがログインフローを処理するのか。

【課題3】可能な限りベンダーに中立を保つ

アーキテクチャを単一のネットワークサービスプロバイダーにチェーンした場合、いざ大規模な停止が起こった際に、インフラストラクチャ全体を再構築せずに回復することが難しい。

【課題4】再現性

簡単に複製できる方法で新しいリージョンを構築したかった。

monday.comのマルチリージョンデザイン

設計の重要なポイントとして以下を上げている。

  • 各リージョンの独立
  • ユーザーは各リージョンに直接アクセス可能
  • 認証はグローバル
  • ベンダー中立性

そのほか、処理の流れの説明が書かれています。

マルチリージョンをサポートするためのアンバサダーの構成

前で説明したことを基に、マルチリージョンネットワーク、認証サービス、API構造を結び付ける構成について、深く掘り下げて説明がされています。

マルチリージョンでのアプリケーションの展開

次の3つのデプロイトポロジをサポートしているようです。

  • Regional

    • 地域ごとに分けて展開されるアプリケーションは、独立したコンポーネントとしてあらゆるリージョンに展開されます。

    • 各デプロイメントは、地域ごとに独立していて、データを共有せず、互いを認識しないようになっています。

  • Global

    • グローバルなアプリケーションは米国で一度展開され、すべての地域から内部ネットワークを介してアクセスできるようになっている。
  • Replicated

    • レプリケートされたアプリケーションはすべてのリージョンに独立してデプロイされますが、データベースに関しては単一のレプリケートされたものを共有し、それらの状態はすべてのリージョンで同じものになっている。

ロギングとモニタリング

  • Envoy アクセスログ

    • すべてのリージョンからのすべてのアクセスログを一元化されたログシステムにストリーミングします。
  • Prometheus / Grafana

  • AWS CloudWatch

    • インフラストラクチャ全体がAWSクラウド上に構築されているため、トランジットゲートウェイVPC、NLBメトリックを使用して、内部ネットワークアクティビティを追跡します。

Kubernetes Supply Chain Policy Management with Cosign and Kyverno (click here to source)

以前は、connaseiurというツールを紹介しました。

ryo-xjsbx.hatenablog.com

今回はみんな大好きkyverno!

Image Signing with Cosign

  • cosign (github)

  • Generate a keypair

$ cosign generate-key-pair
Enter password for private key:
Enter again:
Private key written to cosign.key
Public key written to cosign.pub
  • Sign a container and store the signature in the registry
$ cosign sign -key cosign.key dlorenc/demo
Enter password for private key:
Pushing signature to: index.docker.io/dlorenc/demo:sha256-87ef60f558bad79beea6425a3b28989f01dd417164150ab3baab98dcbf04def8.sig
  • Verify a container against a public key
$ cosign verify -key cosign.pub dlorenc/demo
The following checks were performed on these signatures:
  - The cosign claims were validated
  - The signatures were verified against the specified public key
{"Critical":{"Identity":{"docker-reference":""},"Image":{"Docker-manifest-digest":"sha256:87ef60f558bad79beea6425a3b28989f01dd417164150ab3baab98dcbf04def8"},"Type":"cosign container image signature"},"Optional":null}

Cosign Image Signature Verification with Kyverno

「ghcr.io/kyverno/」リポジトリの「test-verify-image」という名前で始まるのすべてのイメージを対象として、cosignの共通鍵で複合化できるのかを確認してくれる。

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: check-image
spec:
  validationFailureAction: enforce
  background: false
  rules:
    - name: check-image
      match:
        resources:
          kinds:
            - Pod
      verifyImages:
      - image: "ghcr.io/kyverno/test-verify-image:*"
        key: |-
          – ---BEGIN PUBLIC KEY-----
          MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE8nXRh950IZbRj8Ra/N9sbqOPZrfM
          5/KAQN0/KjHcorm/J5yctVd7iEcnessRQjU917hmKO6JWVGHpDguIyakZA==
          – ---END PUBLIC KEY--- –  

署名されたimageを使ってdeployすると通ります。

kubectl create deployment signed \
--image=ghcr.io/kyverno/test-verify-image:signed

署名されてないimageを使った場合、kyvernoによって弾かれる。

kubectl create deployment unsigned \
--image=ghcr.io/kyverno/test-verify-image:unsigned

error: failed to create deployment: admission webhook "mutate.kyverno.svc" denied the request:

resource Deployment/default/unsigned was blocked due to the following policies

verify-image:
  autogen-verify-image: 'image verification failed for ghcr.io/kyverno/test-verify-image:unsigned:
    signature not found'

別のキーペアにおける鍵で署名されたimageも通りません。

kubectl create deployment signed-other \
--image=ghcr.io/kyverno/test-verify-image:signed-by-someone-else

error: failed to create deployment: admission webhook "mutate.kyverno.svc" denied the request:

resource Deployment/default/signed-other was blocked due to the following policies

verify-image:
  autogen-verify-image: 'image verification failed for ghcr.io/kyverno/test-verify-image:signed-by-someone-else:
    invalid signature'

Audit Logging in Clusters (click here to source)

Falcoを使用した監査ログの検索について書かれています。

監査ポリシー

監査ポリシーは、監査ログの構成を定義します。どのイベントが監査の対象に入るのかを制御します。

パラメータ「omitStages」を使用して、リクエストがログに記録されないようにする対象を定義できます。

監査ポリシーのYAMLファイル

apiVersion: audit.k8s.io/v1 # This is required.
kind: Policy
# Don't generate audit events for all requests in RequestReceived stage.
omitStages:
  - "RequestReceived"
rules:
  # Log pod changes at RequestResponse level
  - level: RequestResponse
    resources:
    - group: ""
      # Resource "pods" doesn't match requests to any subresource of pods,
      # which is consistent with the RBAC policy.
      resources: ["pods"]
  # Log "pods/log", "pods/status" at Metadata level
  - level: Metadata
    resources:
    - group: ""
      resources: ["pods/log", "pods/status"]

  # Don't log requests to a configmap called "controller-leader"
  - level: None
    resources:
    - group: ""
      resources: ["configmaps"]
      resourceNames: ["controller-leader"]

リクエストのステージ

リクエストをログに記録できる4つの段階は、次のように定義されています。

  • RequestReceived

    • サーバーが応答の発行を開始する前の段階。
  • ResponseStarted

    • リクエストのヘッダーの作成は完了したが、レスポンスの本文は送信されていない段階。
  • ResponseComplete

    • リクエストに対するレスポンスボディが完了した段階。
  • Panic

    • パニックが発生した段階。

イベントのレベル

  • None

    • このルールに一致するイベントはログに記録されません。
  • Metadata

    • リクエストのメタデータのみをログに記録し、リクエストまたはレスポンスのbodyはログに記録しません。
  • Request

    • イベントのメタデータとリクエストbodyをログに記録しますが、レスポンスbodyはログに記録しません。
  • RequestResponse

    • イベントメタデータ、リクエストおよびレスポンスのbodyをログに記録します。
    • これは最も有益なレベルですが、クラスターに高い負荷をかける可能性があります

パラメータ「rules」は、監査ポリシーYAMLファイルで必要な唯一のパラメータです。

ここで、どのリクエストをどのレベルでログに記録するかを定義できます。

たとえば、先ほどの例の最初のruleは、Podのすべての変更がRequestResponseレベルでログに記録されることを示しています。

監査のバックエンド

監査ログを外部ストレージに書き込むことに関して、2つの方法があります。

  • ログバックエンド

  • webhookバックエンド

    • イベントを外部HTTPAPIに送信します

kubescape (click here to source)

Kubernetes Hardening Guidance by NSA and CISAに基づいて、Cluster内のリソースをチェックしてくれます。

$ kubescape scan framework nsa --exclude-namespaces kube-system,kube-public
ARMO security scanner starting
[progress] Downloading framework definitions
[success] Downloaded framework
[progress] Accessing Kubernetes objects
W0831 18:12:29.875935     241 warnings.go:70] batch/v1beta1 CronJob is deprecated in v1.21+, unavailable in v1.25+; use batch/v1 CronJob
[success] Accessed successfully to Kubernetes objects, let’s start!!!
[progress] Scanning cluster
◑ [success] Done scanning cluster
[control: Allow privilege escalation] passed 👍
Description: Attackers may gain access to a container and uplift its privilege to enable excessive capabilities.
Summary - Passed:1   Failed:0   Total:1

・・・

[control: Control plane hardening] passed 👍
Description: Kubernetes control plane API is running with non-secure port enabled which allows attackers to gain unprotected access to the cluster.
Summary - Passed:1   Failed:0   Total:1

[control: Dangerous capabilities] passed 👍
Description: Giving dangerous and unnecessary capabilities for a container can increase the impact of a container compromise.
Summary - Passed:1   Failed:0   Total:1

・・・

[control: Privileged container] failed 😥
Description: Potential attackers may gain access to privileged containers and inherit access to the host resources. Therefore, it is not recommended to deploy privileged containers unless it is absolutely necessary.
   Namespace kube-image
      DaemonSet - builder
Summary - Passed:0   Failed:1   Total:1
Remediation: Change the deployment and/or pod definition to unprivileged. The securityContext.privileged should be false.

・・・

+-------------------------------------------------+------------------+---------------+-----------+
|                  CONTROL NAME                   | FAILED RESOURCES | ALL RESOURCES | % SUCCESS |
+-------------------------------------------------+------------------+---------------+-----------+
| Allow privilege escalation                      | 0                | 1             | 100%      |
| Allowed hostPath                                | 1                | 1             | 0%        |
| Anonymous requests                              | 0                | 0             | NaN       |
| Applications credentials in configuration files | 3                | 4             | 25%       |
| Automatic mapping of service account            | 3                | 3             | 0%        |
| Cluster-admin binding                           | 4                | 122           | 96%       |
| Container hostPort                              | 1                | 1             | 0%        |
| Control plane hardening                         | 0                | 1             | 100%      |
| Dangerous capabilities                          | 0                | 1             | 100%      |
| Exec into container                             | 4                | 122           | 96%       |
| Exposed dashboard                               | 0                | 2             | 100%      |
| Host PID/IPC privileges                         | 1                | 1             | 0%        |
| Immutable container filesystem                  | 1                | 1             | 0%        |
| Ingress and Egress blocked                      | 1                | 1             | 0%        |
| Insecure capabilities                           | 0                | 1             | 100%      |
| Linux hardening                                 | 1                | 1             | 0%        |
| Non-root containers                             | 0                | 1             | 100%      |
| Privileged container                            | 1                | 1             | 0%        |
| Resource policies                               | 1                | 1             | 0%        |
| hostNetwork access                              | 1                | 1             | 0%        |
+-------------------------------------------------+------------------+---------------+-----------+
|                       20                        |        23        |      267      |    91%    |
+-------------------------------------------------+------------------+---------------+-----------+

Writing a Kubernetes Validating Webhook using Python (click here to source)

Validating Webhookを実行するコンテナをPythonを用いて作成する方法について書かれています。

How to Secure Containers with Cosign and Distroless Images (click here to source)

Distroless Container Imagesとは何か。

Distroless Container Imagesは、「言語に焦点を合わせたDockerイメージからオペレーティングシステムを除いたもの」です。つまり、アプリケーションとそのランタイム依存関係のみが含まれ、他の通常のOSパッケージマネージャー、Linuxシェル、または標準のLinuxディストリビューションで通常期待されるようなプログラムは含まれません。

ソース

ディストロレスコンテナイメージと一緒にCosignが必要な理由

Cosignの必要性は、ディストロレスイメージを使用しても、タイポスクワッティング攻撃や悪意のあるイメージの受信などのセキュリティ上の脅威に直面する可能性があるためです。

Cosign検証を使用した、ディストロレスコンテナのベースイメージの検証。

こちらでは、実際にディストロレスコンテナイメージとcosignを使用したDemoを紹介してくれています。

Easy, Secure Kubernetes Authentication With Pinniped (click here to source)

Pinnipedについて、Demoを交えて説明してくれています。

Kubenews #29

2021-08-20

youtu.be

Encrypt your Kubernetes Secrets with Mozilla SOPS (click here to source)

Kubernetes Secretsは、base64で暗号化されていて、簡単に複合化できてしまう。 そのソリューションとして、Mozilla SOPSがある。

github : SOPS

・特徴

  • yaml, json, ini, binaryなどに対応

  • 以下のようなSolutionと連携が可能

    • PGP
    • Azure Key Vault
    • AWS KMS
    • GCP KMS
    • HashiCorp Vault

この記事では、Azureに関しての例が書かれており、Azure Service Principal (SP) を使うことを推奨しています。

  • Provision an Azure Service Principal (SP)
# create a service principal
az ad sp create-for-rbac -n sp-sops-keyvault -o json
# {
#   "appId": "00000000-0000-0000-000000000000",
#   "displayName": "http://sp-sops-keyvault",
#   "name": "http://sp-sops-keyvault",
#   "password": "00000000-0000-0000-000000000000",
#   "tenant": "<your_tenant_identifier>
# }

export AZURE_CLIENT_ID=<appId>
export AZURE_CLIENT_SECRET=<password>
export AZURE_TENANT_ID=<tenant>
  • Provisioning an Azure Key Vault instance
# create a new Resource Group
az group create -n rg-sops-sample -l germanywestcentral

# create a Key Vault instance
az keyvault create -n kv-sops-sample \
   -g rg-sops-sample \
   -l germanywestcentral 

# create an access policy for the SP
az keyvault set-policy -n kv-sops-sample \
   -g rg-sops-sample \
   --spn $AZURE_CLIENT_ID \
   --key-permissions encrypt decrypt
  • Create a key in Azure Key Vault for encryption & decryption
# create an key for encryption / decryption 
az keyvault key create -n sops-sample-key \
    --vault-name kv-sops-sample \
    --ops encrypt decrypt \
    --protection software

# read and store key identifier
export KEY_ID=$(az keyvault key show -n sops-sample-key \
    --vault-name kv-sops-sample \
    --query key.kid -o tsv)
# download sops cli for macOS
curl -O -L -C - https://github.com/mozilla/sops/releases/download/v3.7.1/sops-v3.7.1.darwin

# move and rename the cli to /usr/bin
sudo mv sops-v3.7.1.darwin /usr/bin/sops

# make it executable
sudo chmod +x /usr/bin/sops

まず、Sercretを作成します。

# create the Kubernetes secret
kubectl create secret generic demo \
    --from-literal mysecret=secret_value \
    -o yaml \
    --dry-run=client > secret.encoded.yml

# print the contents of secret.encoded.yml
cat secret.encoded.yml

# apiVersion: v1
# data:
#   mysecret: c2VjcmV0X3ZhbHVl
# kind: Secret
# metadata:
#   creationTimestamp: null
#   name: demo

sopsコマンドを用いて、暗号化します。

# encrypt secret.encoded.yml using SOPS
sops --encrypt --encrypted-regex '^(data|stringData)$' \
    --azure-kv $KEY_ID secret.encoded.yml > secret.encrypted.yml

# print the contents of secret.encrypted.yml
cat secret.encrypted.yml

# apiVersion: v1
# data:
#    mysecret: ENC[AES256_GCM,data:gz/WAjWte3bCnNm6e+G4ow==,iv:VB4pAv833tDdD4n76h4CqEZNpGdwA3V1QGWp7PK/Jfc=,tag:CcUy3rti4XcWArmHANVS8Q==,type:str]
# kind: Secret
# metadata:
#     creationTimestamp: null
#     name: demo
# sops:
#     kms: []
#     gcp_kms: []
#     azure_kv:
#         - vault_url: https://kv-sops-sample.vault.azure.net
#           name: sops-sample-key
#           version: ee44c0c0cc9e4620aa4f4c86c4942047
#           created_at: "2021-08-02T20:55:40Z"
#           enc: EjszDACgiDP8rW3wzs-7fAmFzlAhCq0-R9YlA9cuPcq78EXEeNTC8OnlSdXQAGdGrgE9oylu1HKZa4RB9GxzzVDav8uNVPp67NPmC4-teeA5iRE4jqlp1An6sG6CpkZGcAmKWpfj_DEWecqrNGWSLTA2hI_HKwG5xNkFh9Myik6732W-XL65IFqgepcFrNIzeHetznO0j1iISNXqMeJjeCnZ6Qq0jcXUMIfQnXjAllKfjSukiT3A3GlWxP0j50Z328t-JHi5RowYHT-hC8FDOdR_U95sqnFd27RgEXmbDIU6IGvP3vmCiZJz4YQCPXaGhySvFY6qCEoCbCSC4RaoWw
#     hc_vault: []
#     age: []
#     lastmodified: "2021-08-02T20:55:41Z"
#     mac: ENC[AES256_GCM,data:AmKRnzoImfIzPa3JBcuxUKRrse5uZwJGukpLj1wxed3R7lsUN+QAV1+WkfNyeMoW5C3ek7j20Xpbvzi+MgP8zcQOwWSwA79Svgz3hKMn9eTRTfgU+4jYezIIHCwkv61MTN8RGW5AhOInYP8oRPW3zKD+SbBO/Jeu7SC+/oVn07I=,iv:S4Th+0quL84lhJtA/lugEv+iLc+WhWEYPSlXGWKhd/M=,tag:CUGg8+UM7gNSzfjJx1Ua1w==,type:str]
#     pgp: []
#     encrypted_regex: ^(data|stringData)$
#     version: 3.7.1

# delete encoded version of the secret
rm secret.encoded.yml

# add encrypted secret to source control and commit it
git add secret.encrypted.yml
git commit -m 'chore: add encrypted secret'

sopsコマンドを用いて複合化ができます。

# decrypt and deploy the secret
sops --decrypt secret.encrypted.yml | kubectl apply -f -

いつものSecret同様、Pod等から参照が可能です。

apiVersion: v1
kind: Pod
metadata:
  name: echo
  labels:
    app: echo
spec:
    containers:
    - image: thorstenhans/env-via-http:0.0.1
      name: main
      ports:
        - containerPort: 5000
          protocol: TCP
      envFrom:
        - secretRef:
            name: demo
            optional: true
      resources:
        requests:
          cpu: 50m
          memory: 32Mi
        limits:
          cpu: 100m
          memory: 48Mi 

Implementing traffic policies in Kubernetes (click here to source)

Kumaを使用したKubernetesトラフィックポリシーの設計について

2つのバックエンドサービスは外部ネットワークから分離した状態で、ある1つのサービスからの通信を許可したい場合、以下のようなポリシーを適用できる。

cat <<EOF | kumactl apply -f - 
type: TrafficPermission
name: api-to-backends
mesh: default
sources:
  - match:
      service: 'publicAPI'
destinations:
  - match:
      service: 'backend1'
  - match:
      service: 'backend2'
EOF

How to Run HAProxy with Docker (click here to source)

Dockerの実行によるパフォーマンスへの影響

Dockerを使用すると、ホストへのブリッジネットワークを作成することで、コンテナー内で実行されているサービスにアクセスできます。

よって、コンテナのローカルネットワークとホストのブリッジネットワーク間でネットワークアドレス変換(NAT)をするため、遅延が発生します。

前に引用した同じIBMの調査では、DockerのNATによって、クライアントからの100バイトの要求とアプリケーションからの200バイトの応答のレイテンシーが約35 µsから70 µsに倍増されたらしい。

非常に低いレイテンシが必要な場合は、Dockerのホストネットワーク機能の使用に切り替えることで、コンテナはホストと同じネットワークを共有できるため、NATの必要性がなくなります。

Dockerを実行する際のセキュリティに関する考慮事項

HAProxyは、80や443などの制限されたTCPポートにバインドする必要があるため、rootアクセスが必要です。

ただし、起動が完了すると、root権限が削除され、非特権ユーザーとして実行されます。

DockerでHAProxyを実行する

3つのアプリケーションを動かします。

$ sudo docker network create --driver=bridge mynetwork

$ sudo docker run -d \
   --name web1 --net mynetwork jmalloc/echo-server:latest
   
$ sudo docker run -d \
   --name web2 --net mynetwork jmalloc/echo-server:latest
   
$ sudo docker run -d \
   --name web3 --net mynetwork jmalloc/echo-server:latest

$ sudo docker ps

CONTAINER ID   IMAGE                        COMMAND              CREATED              STATUS              PORTS      NAMES
98216bb8c5ff   jmalloc/echo-server:latest   "/bin/echo-server"   About a minute ago   Up About a minute   8080/tcp   web3
ae6accc111d9   jmalloc/echo-server:latest   "/bin/echo-server"   About a minute ago   Up About a minute   8080/tcp   web2
554fafbc2b3b   jmalloc/echo-server:latest   "/bin/echo-server"   About a minute ago   Up About a minute   8080/tcp   web1

HAProxyロードバランサーを介してこれらのコンテナーにトラフィックを中継できるよう、現在のディレクトリにhaproxy.cfgという名前のファイルを作成し、それに以下を追加します。

global
  stats socket /var/run/api.sock user haproxy group haproxy mode 660 level admin expose-fd listeners
  log stdout format raw local0 info

defaults
  mode http
  timeout client 10s
  timeout connect 5s
  timeout server 10s
  timeout http-request 10s
  log global

frontend stats
  bind *:8404
  stats enable
  stats uri /
  stats refresh 10s

frontend myfrontend
  bind :80
  default_backend webservers

backend webservers
  server s1 web1:8080 check
  server s2 web2:8080 check
  server s3 web3:8080 check
  • 最初のフロントエンドはポート8404でリッスンし、HAProxy Statsダッシュボードを有効にします。このダッシュボードには、ロードバランサーに関するライブ統計が表示されます。

  • もう一方のフロントエンドはポート80でリッスンし、Webサーバーのバックエンドにリストされている3つのWebアプリケーションの1つに要求をディスパッチします。

以下のコマンドで、HAProxyを作成します。

$ sudo docker run -d \
   --name haproxy \
   --net mynetwork \
   -v $(pwd):/usr/local/etc/haproxy:ro \
   -p 80:80 \
   -p 8404:8404 \
   haproxytech/haproxy-alpine:2.4

Kubernetes CI/CD with Tekton and ArgoCD (click here to source)

TektonとArgoCDを使用してKubernetesでCI / CDプロセスを構成する方法が書かれています。

AWS App MeshとIstioの比較 (click here to source)

AWSが提供するサービスメッシュのマネージドサービスであるApp MeshとIstioの比較について書かれています。

比較項目としてはいかがあります。

  • ECS環境での利用
  • トラフィックルーティング
  • 障害分離(タイムアウト、リトライ、サーキットブレーカー)
  • Ingress
  • セキュリティ機能
  • オブザーバビリティ関連の機能

OPA GatekeeperによるKubernetesセキュリティの歩き方 (click here to source)

以下のような、運用をしていく中でこういったことに注意したなどの事例を基に説明されている。

ConstraintとConstraintTemplateを何も考えずにクラスタに適用してしまうと、意図していないリソースまでも影響を受ける可能性があります。

enforcementAction: dryrunを使用し、一定期間様子を見ながら適用することをおすすめします

入門 Rancher Desktop

Rancher Desktopとは

Rancher Desktopとは、インストールして起動するだけで、Windows 10やmacOS上に簡単にKubernetes環境を展開することができるオープンソースのアプリケーションです。

rancherdesktop.io

Control Planeにk3s, CRIにcontainerdを用いたClusterを、

上に展開します。

Installation

では、さっそくインストールをしていきたいと思います。

踏むのは何と1stepだけです! 以下のlink先からアプリケーションをダウンロードして起動してください。

github.com

今回、windowsを使って確認をしていきます。

起動

起動をすると、以下のようにアプリケーションが動きます。

rancher-1

Kubernetes Settings」というtabを押していただき、以下のようにゲージが止まり「Reset Kubernetes」が押せる状態になると、Kubernetes Clusterの展開が完了しています。

rancher-2

Mac版では、リソースの指定もできます。

rancher-desktop-mac
rancher-desktop-mac

使い方

Kubernetes Clusterの立ち上げが完了すると、WindowsではUserディレクトリの直下にconfigファイルが生成されています。

では、Nodeの情報を見ていきます。

$ kubectl get nodes -o wide
NAME         STATUS   ROLES            AGE    VERSION         INTERNAL-IP       EXTERNAL-IP   OS-IMAGE   KERNEL-VERSION                   CONTAINER-RUNTIME
w10dyh79c3   Ready    builder,master   17m    v1.19.10+k3s1   <Internal IP>     <none>        Unknown    5.4.72-microsoft-standard-WSL2   containerd://1.4.4-k3s1

初期で動いているNamespace、及びPodは以下のようになっています。

$ kubectl get ns
NAME              STATUS   AGE
default           Active   18m
kube-system       Active   18m
kube-public       Active   18m
kube-node-lease   Active   18m
kube-image        Active   18m

$ kubectl get pods -A
NAMESPACE     NAME                                     READY   STATUS      RESTARTS   AGE
kube-system   coredns-66c464876b-zt485                 1/1     Running     0          18m
kube-system   local-path-provisioner-7ff9579c6-dzvg2   1/1     Running     0          18m
kube-system   metrics-server-7b4f8b595-lmsh2           1/1     Running     0          18m
kube-system   helm-install-traefik-zzbcw               0/1     Completed   0          18m
kube-system   svclb-traefik-wcg8k                      2/2     Running     0          17m
kube-system   traefik-5dd496474-sbb4b                  1/1     Running     0          17m
kube-image    builder-xzrlf                            2/2     Running     0          17m

StorageClassに関しても、以下のように作成されます。

$ kubectl get sc
NAME                   PROVISIONER             RECLAIMPOLICY   VOLUMEBINDINGMODE      ALLOWVOLUMEEXPANSION   AGE
local-path (default)   rancher.io/local-path   Delete          WaitForFirstConsumer   false                  18m

以下のようなmanifestを適用してみます。

$ cat pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: demo-pvc
  namespace: default
spec:
  storageClassName: local-path
  accessModes:
    - ReadWriteOnce
  volumeMode: Filesystem
  resources:
    requests:
      storage: 5Gi

この時点では、StorageClassのvolumeBindingModeが WaitForFirstConsumer であるため、 PodからPVCを指定されるまで、容量の確保がされないようになっています。

$ kubectl apply -f pvc.yaml
persistentvolumeclaim/demo-pvc created

$ kubectl get pvc -n default
NAME       STATUS    VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS   AGE
demo-pvc   Pending                                      local-path     61s

では、このpvcを使うPodを立ち上げてみます。

apiVersion: v1
kind: Pod
metadata:
  name: mypod
spec:
  containers:
    - name: myfrontend
      image: nginx
      volumeMounts:
      - mountPath: "/var/www/html"
        name: mypd
  volumes:
    - name: mypd
      persistentVolumeClaim:
        claimName: 

nginxが問題なく動きました。

$ kubectl apply -f nginx.yaml
pod/demo-pod created

$ kubectl get pods
NAME       READY   STATUS    RESTARTS   AGE
demo-pod   1/1     Running   0          4m22s

$ kubectl get pvc
NAME       STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   AGE
demo-pvc   Bound    pvc-1222f2ff-7afd-4254-b352-640c906b5804   5Gi        RWO            local-path     8m28s

Appendix

k3sのバイナリは以下に配置されています。

# /mnt/c/Users/uwatsr/AppData/Local/xdg.cache/rancher-desktop/k3s
/v1.19.10+k3s1/k3s -h
NAME:
   k3s - Kubernetes, but small and simple

USAGE:
   k3s [global options] command [command options] [arguments...]

VERSION:
   v1.19.10+k3s1 (72e8196c)

COMMANDS:
   server         Run management server
   agent          Run node agent
   kubectl        Run kubectl
   crictl         Run crictl
   ctr            Run ctr
   check-config   Run config check
   etcd-snapshot  Trigger an immediate etcd snapshot
   help, h        Shows a list of commands or help for one command

GLOBAL OPTIONS:
   --debug        (logging) Turn on debug logs [$K3S_DEBUG]
   --help, -h     show help
   --version, -v  print the version

Kubenews #27

2021-08-06

youtu.be

各タイトルを押していただくことで、実際の記事に飛びます。

Prometheus HA with Thanos Sidecar Or Receiver?

  • Thanosは、次の2つの方法でPrometheusとの統合をサポートしています。
  • Thanos Stackは以下のコンポーネントを持ちます。
    • Querier
    • Store
    • Compactor
    • Ruler
  • Thanos Sidecar

    • 複数のプロメテウスサーバーポッドでサイドカーとして実行されます。
    • このコンポーネントは、(Prometheus TSDBからの)オブジェクトストレージへのデータ配信を担当します。
    • Sidecarは、Prometheusのremote read APIの上にThanosのStore APIを実装し、ThanosQuerierという名前の集中コンポーネントからPrometheusサーバーの時系列データをクエリできるようにします。
    • さらに、サイドカーは、TSDBブロックを2時間間隔でオブジェクトストレージにアップロードするように構成することもできます。 この場合、バケットに保存されているデータは、Thanos Storeコンポーネントを使用してクエリできます。これは、同じStore APIを実装しており、ThanosQuerierが検出する必要があります。
  • Thanos Receiver

    • Prometheus Remote Write APIが使用され、PrometheusインスタンスがReceiverにリモートで継続的に書き込むように構成されます。
    • レシーバーは、オブジェクトストレージバケットにデータを入力するように構成されており、独自の保持期間もあります。
    • Querierは、Storeを介してReceiverとストレージバケットのデータをクエリするように構成されています。
  • サイドカーとレシーバーの比較

    • 高可用性
      • サイドカー
        • インスタンスは個別にターゲットをスクレイプし、サイドカーはブロックをオブジェクトストレージにアップロードします。
        • Prometheusは2時間ごとにTSDBブロックを書き込みます。
      • レシーバー
        • 複数のPrometheusインスタンスがデプロイされて同じターゲットをスクレイピングし、Receiver StatefulSetにリモートで書き込むように構成されています。
    • プロメテウスとの統合
      • サイドカー
        • Prometheusインスタンスポッドにサイドカーコンテナを追加するだけで、他のすべてのThanosコンポーネントが一緒に機能します。
        • Querier構成でエンドポイントを追加するだけで、サービスとしてThanosQuerierに公開されます。
      • レシーバー
        • これには、追加のReceiver StatefulSetをデプロイするとともに、TSDBをReceiverにリモート書き込みするために、Prometheusインスタンスの構成を変更する必要があります。
    • ストレージ
      • サイドカー
        • SidecarはPrometheusのローカルストレージから読み取るため、TSDBに追加のローカルストレージ(PV)は必要ありません。
      • レシーバー
        • StatefulSetであるReceiverは、PVでプロビジョニングする必要があります。
        • ここで必要なローカルストレージの量は、--receive.replication-factor、--tsdb.retentionというフラグに依存しています。
        • このセットアップには、Sidecarと比較してより多くのローカルストレージが必要です。
    • データ収集
      • サイドカー
        • TSDBブロックはPrometheusインスタンスのローカルストレージから読み取られ、クエリのためにQuerierに提供されるか、オブジェクトストレージに断続的にエクスポートされます。
      • レシーバー
        • Receiverはプッシュベースのモデルで動作します。
        • TSDBはPrometheusインスタンス自体によってReceiverに継続的にリモートで書き込まれるため、Prometheusをステートレスに近づけることができます。
        • その後、データはレシーバーからオブジェクトストレージにさらにアップロードされます。

What Is Workload Security? On-Premises, Cloud, Kubernetes, and More

Announcing Vitess Arewefastyet

  • Vitess arewefastyet
    • 継続的なベンチマークツール
    • 実行は、CLIからの手動トリガー、cronスケジュール、またはイベント(新しいプル要求、新しいリリースなど)に基づいて、さまざまなソースからトリガーできます。
    • webページから視覚的にベンチマークの結果を見ることが可能

Scheduled-Scaling with Kubernetes HPA External Metrics

  • HPA + Datadogの連携について

Verify Container Image Signatures in Kubernetes using Notary or Cosign or both

  • connaisseur

    • コンテナイメージの署名検証とtrust pinningをKubernetesクラスタに統合するためのアドミッションコントローラ
    • Connaisseurは展開前のイメージ署名の確認することを目指しています。
    • Mutating アドミッションコントローラーとして実装され、Kubernetesクラスターに送信されたリソースの作成または更新リクエストをインターセプトし、すべてのコンテナーイメージを識別たうえで、事前構成された公開鍵に対してそれらの署名を検証します。 その結果に基づいて、それらの要求を受け入れるか拒否します。
  • demo

レポジトリをクローンしてきます。

% git clone https://github.com/sse-secure-systems/connaisseur.git
Cloning into 'connaisseur'...
remote: Enumerating objects: 3682, done.
remote: Counting objects: 100% (764/764), done.
remote: Compressing objects: 100% (285/285), done.
remote: Total 3682 (delta 613), reused 478 (delta 478), pack-reused 2918
Receiving objects: 100% (3682/3682), 10.01 MiB | 3.98 MiB/s, done.
Resolving deltas: 100% (2198/2198), done.

% cd connaisseur

Connaisseurをデプロイします。

% helm install connaisseur helm --atomic --create-namespace --namespace connaisseur
NAME: connaisseur
LAST DEPLOYED: Wed Aug  4 11:45:35 2021
NAMESPACE: connaisseur
STATUS: deployed
REVISION: 1
TEST SUITE: None

% kubectl get pods -n connaisseur
NAME                                      READY   STATUS    RESTARTS   AGE
connaisseur-deployment-7d6bd95d48-bmjxw   1/1     Running   0          93s
connaisseur-deployment-7d6bd95d48-ghbkf   1/1     Running   0          94s
connaisseur-deployment-7d6bd95d48-m9zjh   1/1     Running   0          93s

Official Docker imagesを使ってPodを作成します。

% kubectl run hello-world --image=docker.io/hello-world                                                 
pod/hello-world created

作成されたこと確認できました。

では、署名されていないimageはどうでしょう。

% kubectl run demo --image=docker.io/securesystemsengineering/testimage:unsigned
Error from server: admission webhook "connaisseur-svc.connaisseur.svc" denied the request: Unable to find signed digest for image docker.io/securesystemsengineering/testimage:unsigned.

しっかり弾かれることがわかりました。

Bad Pods

  • こんなものがあったので紹介です。

Kubenews #26

2021-07-09

配信URL

youtu.be

各タイトルを押していただくことで、実際の記事に飛びます。

Kubernetes Essential Tools: 2021

Kubernetesを使っていく上で、様々なケースに対応するためのツールを紹介してくれています。

Run the HAProxy Kubernetes Ingress Controller Outside of Your Kubernetes Cluster

(要約)

Podへ外部から到達する際に、NodePortもしくはLoad BalancerのServiceを公開する必要があり、クラウド環境では、LoadBalancerオプションは各クラウドプロバイダーが用意しているロードバランサーがありそれを利用できるが、オンプレミス環境では、通常 NodePortを使用し、ロードバランサーを手作業で前面に配置する必要があります。

従来のレイアウトでは、外部ロードバランサーがワーカーノードの 1 つにトラフィックを送信し、次に KubernetesIngressコントローラーポッドを実行しているノードにトラフィックを中継します。

HAProxy Kubernetes Ingressコントローラのバージョン 1.5 以降では、Kubernetes クラスターの外部で実行するオプションがあり、前にロードバランサーを追加する必要がなくなります。

注意すべき点として、IngressコントローラがPodとして実行されておらず、Kubernetes クラスタ内に存在しない場合、Pod レベルのネットワークに何らかの方法でアクセスする必要があります。

Project Calicoを Kubernetes のネットワーク プラグインとしてインストールし、次に Calico が BGP ピアリングを介してIngressコントローラ サーバーとネットワーク ルートを共有できるようにすることで、この問題を解決することができます。

Handling Auth in EKS Clusters: Setting Up Kubernetes User Access Using AWS IAM

EKSクラスターでの認証の処理について

kubenews #25

2021-07-02

配信URL

youtu.be

各タイトルを押していただくことで、実際の記事に飛びます。

Monitoring Kyverno with Prometheus

ついに、keyvernoがmonitoringされている例がでました。 keyvernoがに関しては、以下を参照ください。

cAdvisor and Kubernetes Monitoring Guide

Since cAdvisor is already integrated with the kubelet binary, ~~とあり、kubeletに統合されています。

この記事では、cpu, memory, diskなどの項目に関するmetric名やGrafanaから確認する方法についてが書かれているので、とても参考になる資料となっています。

Avoiding Kubernetes Cluster Outages with Synthetic Monitoring

  • Kuberhealthy
    • khcheck / khjob(Kuberhealthy check / Kuberhealthy job)と呼ばれるカスタムリソースによって作成されたテストコンテナーを用いる
    • khjobが1回実行されるのに対し、khcheckは定期的に実行されることを除いて、両方のカスタムリソースの機能はほぼ同じ
    • Kuberhealthy合成チェックのユースケース
      • ネットワークの変更
        • 実行する必要のある主要なネットワーク変更がある場合は、HTTPまたはTCP khchecksを使用して重要なエンドポイントをチェック
      • IAMの変更
        • 適切なKIAM機能を検証するためのKIAMチェックがある。
      • エンドポイント接続
        • データベースやKey-Valueストアなど、クラスター外の重要な要素が稼働しているかどうかを常に確認できる。
      • AMI検証
        • AMIチェックを変更して、NTP同期、ディレクトリ構造、ユーザーアクセスなど、カスタムベイクされたAMIの重要な機能を確認できる。
      • CoreDNSチェック
      • リソースクォータチェック

demo

kuberhealthyをデプロイしていきます。

% kubectl create namespace kuberhealthy

% helm repo add kuberhealthy https://kuberhealthy.github.io/kuberhealthy/helm-repos
"kuberhealthy" has been added to your repositories

% helm install kuberhealthy kuberhealthy/kuberhealthy
NAME: kuberhealthy
LAST DEPLOYED: Fri Jul  2 22:06:02 2021
NAMESPACE: kuberhealthy
STATUS: deployed
REVISION: 1
TEST SUITE: None

デプロイされたか見ていきます。

% kubectl get pods -n kuberhealthy
NAME                            READY   STATUS    RESTARTS   AGE
kuberhealthy-8575448769-r8npz   1/1     Running   0          3d19h
kuberhealthy-8575448769-zslkx   1/1     Running   0          3d19h

なんかAgeがおかしい気もしますが、一旦進みます。

次に、サンプルのアプリを入れます。

% kubectl create deploy nginx --replicas 2 --image nginx:latest
deployment.apps/nginx created

% kubectl expose deployment nginx --type=NodePort --name=example-service --port 80                 
service/example-service exposed

では、アプリが見えるか確認していきます。

% curl 192.168.64.2:30795
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
    }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>

今回、使うServiceは以下です。

% kubectl get svc
NAME              TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)        AGE
example-service   NodePort    10.105.7.80   <none>        80:30795/TCP   42m

では、以下のような2つのチェック用manifestを用意していきます。

今回、違いがわかるように、Service名ではなくIPで書いています。

  • URLが正しいもの
% cat kuberhealthy.yaml       
apiVersion: comcast.github.io/v1
kind: KuberhealthyCheck
metadata:
  name: nginx-reachable
  namespace: kuberhealthy
spec:
  runInterval: 2m
  timeout: 2m
  podSpec:
    containers:
      - name: nginx-reachable-check
        image: kuberhealthy/http-check:v1.5.0
        imagePullPolicy: IfNotPresent
        env:
          - name: CHECK_URL
            value: "http://10.105.7.80:80"
          - name: COUNT #### default: "0"
            value: "5"
          - name: SECONDS #### default: "0"
            value: "1"
          - name: PASSING_PERCENT #### default: "100"
            value: "100"
          - name: REQUEST_TYPE #### default: "GET"
            value: "GET"
          - name: EXPECTED_STATUS_CODE #### default: "200"
            value: "200"
        resources:
          requests:
            cpu: 15m
            memory: 15Mi
          limits:
            cpu: 25m
    restartPolicy: Always
    terminationGracePeriodSeconds: 5
  • URLがおかしいもの
apiVersion: comcast.github.io/v1
kind: KuberhealthyCheck
metadata:
  name: nginx-unreachable
  namespace: kuberhealthy
spec:
  runInterval: 2m
  timeout: 2m
  podSpec:
    containers:
      - name: nginx-unreachable-check
        image: kuberhealthy/http-check:v1.5.0
        imagePullPolicy: IfNotPresent
        env:
          - name: CHECK_URL
            value: "http://10.105.7.180:80"
          - name: COUNT #### default: "0"
            value: "5"
          - name: SECONDS #### default: "0"
            value: "1"
          - name: PASSING_PERCENT #### default: "100"
            value: "100"
          - name: REQUEST_TYPE #### default: "GET"
            value: "GET"
          - name: EXPECTED_STATUS_CODE #### default: "200"
            value: "200"
        resources:
          requests:
            cpu: 15m
            memory: 15Mi
          limits:
            cpu: 25m
    restartPolicy: Always
    terminationGracePeriodSeconds: 5

Applyすると以下のように確認ができます。

% kubectl get khcheck -n kuberhealthy     
NAME                AGE
nginx-reachable     20m
nginx-unreachable   18m

以下のような形でPodは作成されています。

% kubectl get pod -n kuberhealthy
NAME                            READY   STATUS      RESTARTS   AGE
kuberhealthy-8575448769-r8npz   1/1     Running     5          3d23h
kuberhealthy-8575448769-zslkx   1/1     Running     0          3d23h
nginx-reachable-1625242353      0/1     Completed   0          7m56s
nginx-reachable-1625242473      0/1     Completed   0          5m56s
nginx-reachable-1625242593      0/1     Completed   0          3m56s
nginx-reachable-1625242713      0/1     Completed   0          116s
nginx-unreachable-1625242725    1/1     Running     0          104s

では、実行結果を見ていきましょう。 以下のServiceに対してport-forwardしていきます。

% kubectl get svc -n kuberhealthy
NAME           TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)   AGE
kuberhealthy   ClusterIP   10.107.202.150   <none>        80/TCP    3d20h

% kubectl port-forward svc/kuberhealthy 8080:80 -n kuberhealthy

では、アクセスしてみます。

localhost:8080

以下のように、チェック結果を確認することができます。

{
  "OK": false,
  "Errors": [
    "Check execution error: kuberhealthy/nginx-unreachable: timed out waiting for checker pod to report in"
  ],
  "CheckDetails": {
    "kuberhealthy/nginx-reachable": {
      "OK": true,
      "Errors": [],
      "RunDuration": "17.206972822s",
      "Namespace": "kuberhealthy",
      "LastRun": "2021-07-02T14:23:13.09344293Z",
      "AuthoritativePod": "kuberhealthy-8575448769-r8npz",
      "uuid": "7401e1f7-330a-467d-9ad3-d0ea5e8a799f"
    },
    "kuberhealthy/nginx-unreachable": {
      "OK": false,
      "Errors": [
        "Check execution error: kuberhealthy/nginx-unreachable: timed out waiting for checker pod to report in"
      ],
      "RunDuration": "",
      "Namespace": "kuberhealthy",
      "LastRun": "2021-07-02T14:22:46.962592884Z",
      "AuthoritativePod": "kuberhealthy-8575448769-r8npz",
      "uuid": "9adf2caa-0a1d-42bb-9f45-a83ad94aedfa"
    }
  },
  "JobDetails": {},
  "CurrentMaster": "kuberhealthy-8575448769-r8npz"
}

What end-users want out of Prometheus remote storage: A comparison of M3 and Thanos

  • prometheusのリモートストレージソリューションとして、以下が人気
    • Thanos
    • M3
    • Cortex
  • 以下の観点でThanosとM3を比較
    • 信頼性と可用性
      • Thanos
        • クエリアによって取得されたデータに加えてルール(アラートルールやPrometheusレコーディングルールなど)を適用できるネイティブクエリサービスがある。
        • Thanosの分散読み取りまたはクエリパスが原因で失敗率が高くなることがある。
      • M3
        • 集中ストレージを備えた最適化されたクエリエンジンを持つように構築および設計されている。
        • M3のクエリサービスは、クォーラム読み取りロジックを使用して、各データポイントの3つのコピーのうち少なくとも2つがM3DBからフェッチされ、クエリエージェント(Grafanaなど)に返される結果を一貫して計算する。
        • M3のクエリサービスはクエリ要求に優先順位を付けないため、要求(特に大規模な要求)の流入により、ボトルネックが発生し、クエリ処理全体の速度が低下する可能性がある。
    • スケーラビリティとシンプルさ
      • Thanos
        • Thanosは、PrometheusのProxyの役割としてサイドカーで構成される。
        • ???
      • M3
        • 分散時系列データベース(M3DB)、取り込みおよびダウンサンプリング層(M3コーディネーター)、およびクエリエンジン(M3クエリ)の3つのコアコンポーネントで構成されている。
        • アーキテクチャ上、M3は簡単にスケールアップまたはスケールダウンできる。
        • M3DBは1つのユニットとして水平方向にスケールできるが、クラスター内のM3DBノードの数のサイズを変更する際、M3DBはステートフルであり、ノードメンバーシップの変更時にピアにデータをストリーミングするため、大規模な管理が困難になる可能性がある。
          • こちらは、Operatorによって自動的にスケールアップおよびスケールダウンできるようになっている。
    • 効率とスピード
      • Thanos
        • Thanosサイドカーは、2時間のブロックでオブジェクトストレージにデータをアップロードする。
        • Thanosはコンパクターコンポーネントを使用してこれらのブロックを時間の経過とともにマージし、クエリ効率を向上させ、ストレージサイズを削減する。
        • Thanosコンパクターは一度に1つのインスタンスのリクエストのみを処理するように設定されているため、ユーザーはデータが完全に圧縮されるのを待ってから(つまり、2時間ごとに)集計データをクエリできる。
      • M3
        • すべてのダウンサンプリングおよびアグリゲーションはM3・コーディネーターによってローカルに行われる。
        • この設定では、集計はリアルタイムで行われ、各解決間隔の終わりに、集計されたメトリックがすぐにクエリに使用できます(つまり、5分の解像度でデータを集計する場合は5分ごと)。
        • M3コーディネーターサイドカーにダウンタイムがあると、集約されたデータが失われる可能性がある。
    • アフォーダビリティ