Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Kubernetesクラスタ内のリソースに 柔軟なフィルタリングをかける方法 3-shake SRE Tech Talk #4 LT / SRETT4-LT-amsy810

Kubernetesクラスタ内のリソースに 柔軟なフィルタリングをかける方法 3-shake SRE Tech Talk #4 LT / SRETT4-LT-amsy810

Masaya Aoyama (@amsy810)

August 04, 2022
Tweet

More Decks by Masaya Aoyama (@amsy810)

Other Decks in Programming

Transcript

  1. Masaya Aoyama
    3-shake
    Kubernetesクラスタ内のリソースに
    柔軟なフィルタリングをかける方法
    3-shake SRE Tech Talk #4 LT
    amsy810 @amsy810

    View Slide

  2. - Co-chair
    ⻘⼭真也
    + CREATIONLINE - 技術アドバイザ
    + SAKURA Internet Research Center – 客員研究員
    + 3-shake 技術顧問
    + PLAID
    - Organizer
    - KaaS Product Owner - Publications
    Twitter: @amsy810

    View Slide

  3. kubectl get pods
    --filter Service ʹඥ෇͍͍ͯͳ͍Pod

    View Slide

  4. kubectl get ServiceMonitors
    --filter Serviceʹඥ෇͍͍ͯͳ͍ServiceMonitor

    View Slide

  5. Ͳ͏΍ͬͯ΍Γ·͔͢ʁ

    View Slide

  6. • ServiceMonitor は Prometheus Operator で実装されている API
    • 指定された条件の Service (Endpoint)に対して Scrape を⾏う
    ServiceMonitor と Service リソース
    Kind: ServiceMonitor
    spec:
    endpoints:
    - path: /metrics
    port: service
    namespaceSelector:
    matchNames:
    - default
    selector:
    matchLabels:
    app: my-app
    Kind: Service
    metadata:
    namespace: default
    labels:
    app: my-app
    spec: {}
    Service
    Endpoint
    10.0.0.1
    Endpoint
    10.0.0.2
    app: my-app
    app: my-app
    app: my-app
    Scrape

    View Slide

  7. • ラベルの整理を⾏ったところ ServiceMonitor にマッチしない状態に
    • Argo CD が app.kubernetes.io/instance ラベルを付与する兼ね合いで Git リポジトリ上では判別できないケースもあり
    ServiceMonitor と Service リソース
    Kind: ServiceMonitor
    spec:
    endpoints:
    - path: /metrics
    port: service
    namespaceSelector:
    matchNames:
    - default
    selector:
    matchLabels:
    app: my-app
    Kind: Service
    metadata:
    namespace: default
    labels:
    app: dummy
    spec: {}
    Service
    Endpoint
    10.0.0.1
    Endpoint
    10.0.0.2
    app: dummy
    app: dummy
    app: dummy
    Scrape

    View Slide

  8. 無意味な ServiceMonitor の⼀覧を表⽰したい
    = ServiceMonitor で指定されている Service が存在するか否か
    • e.g. Deployment に PDB / HPA / etc が存在しているか
    • e.g. 使われていない ConfigMap / ServiceAccount / etc が存在するか
    実現したいこと
    Service
    Endpoint
    10.0.0.1
    Endpoint
    10.0.0.2
    app: dummy
    app: dummy
    app: dummy
    Scrape

    View Slide

  9. • kubectl get servicemonitors -o jsonpath=ʻ.items[?(@...)]ʼ
    • 複数のリソースにまたがる条件⼀致は指定できない
    • jq や go-template でも同様
    • 軽量なプログラムを Go などで実装する
    • client-goで実装し、ポリシーロジックを実装するのは少々⼿間がかかる
    • Gatekeeper で ServiceMonitor / Service の 作成/更新時 にチェックを⾏う
    • audit 機能があるものの新たな要件発⽣時には対応しづらい
    考えられる⽅法

    View Slide

  10. ղܾࡦͷ࣮૷ํ๏ࣗମ͸Α͋͘Δ࿩Ͱ͢

    View Slide

  11. • kubectl get した結果を元に Conftest を実⾏する
    Conftest を⽤いて柔軟なフィルターを実装する
    deny[msg] {
    sm = input.items[_]
    sm.kind == "ServiceMonitor"
    not has_valid_svc(sm, input.items)
    msg = sprintf("ServiceMonitor=%s", [sm.metadata.name])
    }
    $ kubectl get service,servicemonitor –A –o yaml
    apiVersion: v1
    items:
    - kind: Service
    metadata: {name: svc-1}
    - kind: Service
    metadata: {name: svc-2}
    - kind: ServiceMonitor
    metadata: {name: sm-1}
    ...
    • 取得した複数の Object は items[] 配列に格納
    • YAML ストリームではなく単⼀のドキュメントと
    して返されるため、”conftest test” 実⾏時の
    --combine オプションは不要

    View Slide

  12. kubectl get と conftest test --combine を両⽴する
    • kubectl get で取得した list を元にテストする場合
    deny[msg] {
    sm = input[_]
    sm.kind == "ServiceMonitor"
    not has_valid_svc(sm, input)
    msg = sprintf("ServiceMonitor=%s", [sm.metadata.name])
    }
    deny[msg] {
    sm = input.items[_]
    sm.kind == "ServiceMonitor"
    not has_valid_svc(sm, input.items)
    msg = sprintf("ServiceMonitor=%s", [sm.metadata.name])
    }
    • conftest test --combine でマニフェストを元にテストする場合(CI での利⽤を想定)
    後々 CI にも Conftest を組み込んで再利⽤できる形で関数を実装する
    特定のリソース or リソースの配列に対する関数を意識して実装する

    View Slide

  13. あとは Rego でポリシーを実装するだけ
    • ServiceMonitor の Selector に⼀致する Service の存在確認(実際には Namespace を考慮すること)
    # ServiceMonitor にマッチする Service が1つ以上存在することの確認
    has_valid_svc(sm, items){
    svc = items[i]
    svc.kind == "Service"
    match_svc(sm, svc)
    }
    # 「1つのServiceMonitorのSelector」と「1つのServiceのラベル」がマッチするか否かの確認
    match_svc(sm, svc) {
    s := {sprintf("%s=%s", [i, sm.spec.selector.matchLabels[i]]) | sm.spec.selector.matchLabels[i]}
    l := {sprintf("%s=%s", [i, svc.metadata.labels[i]]) | svc.metadata.labels[i]}
    sub := s - l
    count(sub) = 0
    }
    ポリシーは下記の通り数⾏で表現可能

    View Slide

  14. まとめ
    クラスタから取得した情報をもとに、柔軟にフィルタリングを掛ける場合にも Conftest は有⽤
    • yq などでの表現⼒ < Rego の表現⼒
    • 複数のリソースにまたがるポリシー
    実装したフィルタリングポリシーは、場合によっては CI に組み込むことも有⽤
    • ServiceMonitor に適切な Service が存在するか(不適切な Selector の防⽌)
    Kind: ServiceMonitor
    spec:
    endpoints:
    - path: /metrics
    port: service
    selector:
    matchLabels:
    app: my-app
    Kind: Service
    metadata:
    namespace: default
    labels:
    app: dummy
    spec: {}

    View Slide

  15. View Slide

  16. Thank you for your attention
    Twitter: @amsy810

    View Slide