入門 Rancher Desktop
Rancher Desktopとは
Rancher Desktopとは、インストールして起動するだけで、Windows 10やmacOS上に簡単にKubernetes環境を展開することができるオープンソースのアプリケーションです。
Control Planeにk3s, CRIにcontainerdを用いたClusterを、
上に展開します。
Installation
では、さっそくインストールをしていきたいと思います。
踏むのは何と1stepだけです! 以下のlink先からアプリケーションをダウンロードして起動してください。
今回、windowsを使って確認をしていきます。
起動
起動をすると、以下のようにアプリケーションが動きます。
「Kubernetes Settings」というtabを押していただき、以下のようにゲージが止まり「Reset Kubernetes」が押せる状態になると、Kubernetes Clusterの展開が完了しています。
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
各タイトルを押していただくことで、実際の記事に飛びます。
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
サイドカーとレシーバーの比較
- 高可用性
- プロメテウスとの統合
- ストレージ
- サイドカー
- SidecarはPrometheusのローカルストレージから読み取るため、TSDBに追加のローカルストレージ(PV)は必要ありません。
- レシーバー
- StatefulSetであるReceiverは、PVでプロビジョニングする必要があります。
- ここで必要なローカルストレージの量は、--receive.replication-factor、--tsdb.retentionというフラグに依存しています。
- このセットアップには、Sidecarと比較してより多くのローカルストレージが必要です。
- サイドカー
- データ収集
What Is Workload Security? On-Premises, Cloud, Kubernetes, and More
Announcing Vitess Arewefastyet
- Vitess arewefastyet
Scheduled-Scaling with Kubernetes HPA External Metrics
- HPA + Datadogの連携について
Verify Container Image Signatures in Kubernetes using Notary or Cosign or both
-
- コンテナイメージの署名検証と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
各タイトルを押していただくことで、実際の記事に飛びます。
Kubernetes Essential Tools: 2021
Kubernetesを使っていく上で、様々なケースに対応するためのツールを紹介してくれています。
Run the HAProxy Kubernetes Ingress Controller Outside of Your Kubernetes Cluster
(要約)
Podへ外部から到達する際に、NodePortもしくはLoad BalancerのServiceを公開する必要があり、クラウド環境では、LoadBalancerオプションは各クラウドプロバイダーが用意しているロードバランサーがありそれを利用できるが、オンプレミス環境では、通常 NodePortを使用し、ロードバランサーを手作業で前面に配置する必要があります。
従来のレイアウトでは、外部ロードバランサーがワーカーノードの 1 つにトラフィックを送信し、次に Kubernetes がIngressコントローラーポッドを実行しているノードにトラフィックを中継します。
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
各タイトルを押していただくことで、実際の記事に飛びます。
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合成チェックのユースケース
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
- Thanos
- スケーラビリティとシンプルさ
- Thanos
- Thanosは、PrometheusのProxyの役割としてサイドカーで構成される。
- ???
- M3
- 分散時系列データベース(M3DB)、取り込みおよびダウンサンプリング層(M3コーディネーター)、およびクエリエンジン(M3クエリ)の3つのコアコンポーネントで構成されている。
- アーキテクチャ上、M3は簡単にスケールアップまたはスケールダウンできる。
- M3DBは1つのユニットとして水平方向にスケールできるが、クラスター内のM3DBノードの数のサイズを変更する際、M3DBはステートフルであり、ノードメンバーシップの変更時にピアにデータをストリーミングするため、大規模な管理が困難になる可能性がある。
- こちらは、Operatorによって自動的にスケールアップおよびスケールダウンできるようになっている。
- Thanos
- 効率とスピード
- Thanos
- M3
- すべてのダウンサンプリングおよびアグリゲーションはM3・コーディネーターによってローカルに行われる。
- この設定では、集計はリアルタイムで行われ、各解決間隔の終わりに、集計されたメトリックがすぐにクエリに使用できます(つまり、5分の解像度でデータを集計する場合は5分ごと)。
- M3コーディネーターサイドカーにダウンタイムがあると、集約されたデータが失われる可能性がある。
- アフォーダビリティ
- 信頼性と可用性
Kubenews #19
2021-05-21
配信URL
各タイトルを押していただくことで、実際の記事に飛びます。
PromCon Online 2021 highlights
Introducing an Operator for Cortex
vcluster
- vcluster homepage
- Kubernetes Cluster上で仮想的にclusterを作成するもの
- 第17回でも少し話した。
- 配信にてデモあり
kubenews #18
2021-05-14
配信URL
Kubernetes 変更内容共有会(v1.21)
- Youtube URL
- 自分的気になったポイント
- Allow DaemonSets to surge during update like Deployments
- DaemonSet に MaxSurge が導入
- CrossNamespacePodAffinity quota scope API
- namespaceSelectorやnamespaceフィールドを通して指定する、cross-namespaceなPodAffinityTermのNamespaceを制限します。(#98582)
- デフォルトのPodAffinityでは同じNamespaceに属するPodを考慮してスケジュール先を計算しますが、この機能を利用すると対象となるNamespaceを拡張できます。
- ProbeレベルのterminationGracePeriodSecondsフィールドを追加
- Generic Ephemeral Volumes
- Allow DaemonSets to surge during update like Deployments
volumes: - name: varlog hostPath: path: /var/log - name: scratch ephemeral: metadata: labels: type: fluentd-elasticsearch-volume
Annotating Kubernetes Services for Humans
- ヒューマンサービスディスカバリー
- サービス検出の人間的な側面
- 特定のサービスを所有しているのは誰ですか?チームはどのSlackチャネルに取り組んでいますか?サービスのソースはどこにありますか?現在知られ、追跡されている問題は何ですか?
- ここに対してはあまり注意が払われない。
- サービス検出の人間的な側面
- Kubernetesアノテーションは、この問題を正確に解決するように設計されている。
- 見積もりサービスと呼ばれる見積もり用のKubernetesサービスがあるとします。
- kubectl annotate service quote a8r.io/owner=”@sally”` をしてあげると、そのサービスのオーナーがすぐわかる。
- 見積もりサービスと呼ばれる見積もり用のKubernetesサービスがあるとします。
Name: quote Namespace: default Labels: <none> Annotations: a8r.io/owner: @sally Selector: app=quote Type: ClusterIP IP: 10.109.142.131 Port: http 80/TCP TargetPort: 8080/TCP Endpoints: <none> Session Affinity: None Events: <none>
- 注釈に共通の規則
- 注釈に共通の規則を採用することで、一貫性と理解性が保証される。
- サービスカタログ
- describeする上での問題
- マイクロサービスとアノテーションの数が急増するにつれて、実行kubectl describeは面倒になる可能性がある。
- さらに、を使用kubectl describeするには、すべての開発者がKubernetesクラスターに直接アクセスできる必要があある。
- 以下の様なツールを使って可視化しよう。
- describeする上での問題
Using Finalizers to Control Deletion
- kubectl delete
- kubectl delete でリソースの状態は、
live
からcollected
になる。
- kubectl delete でリソースの状態は、
- finalizer
- ファイナライザは、削除前の操作を通知するリソースのキー。
- リソースのガベージ コレクションを制御し、リソースを削除する前に実行するクリーンアップ操作をコントローラに警告するように設計されている。
- finalizerを含ませたリソースを作成して削除しようとすると、消えない。
- Kubernetes がオブジェクトにファイナライザーが含まれていることを確認し、読み取り専用の状態にしたから。
cat <<EOF | kubectl create -f - apiVersion: v1 kind: ConfigMap metadata: name: mymap finalizers: - kubernetes EOF
- finalizerを含むリソースに関しては、kubectl delete でリソースの状態は、
live
からfinalizaiton
になり、finalizer keyを取り除くことで、deletion
というステータスになる。
- finalizerを含むリソースに関しては、kubectl delete でリソースの状態は、
kubectl patch configmap/mymap \ --type json \ --patch='[ { "op": "remove", "path": "/metadata/finalizers" } ]'
- したがって、ファイナライザーを持つオブジェクトを削除しようとすると、コントローラがファイナライザーキーを削除するか、または Kubectl を使用してファイナライザーが削除されるまで、ファイナライズのままになります。ファイナライザーリストが空になると、オブジェクトは Kubernetes によって実際に再利用され、キューに入れ、レジストリから削除されます。
- 所有者
- 親オブジェクトを最初に作成し、次に子オブジェクトを作成すると、子を消しても親は消えないが、親を消すと子も消える。
cat <<EOF | kubectl create -f - apiVersion: v1 kind: ConfigMap metadata: name: mymap-parent EOF CM_UID=$(kubectl get configmap mymap-parent -o jsonpath="{.metadata.uid}") cat <<EOF | kubectl create -f - apiVersion: v1 kind: ConfigMap metadata: name: mymap-child ownerReferences: - apiVersion: v1 kind: ConfigMap name: mymap-parent uid: $CM_UID EOF
--cascade=false
を渡してあげると、親を消しても子は消えない。
kubectl delete --cascade=false configmap/mymap-parent configmap "mymap-parent" deleted kubectl get configmap NAME DATA AGE mymap-child 0 13m21s
- namespaceの強制終了
- namespaceを削除し、その下にあるすべてのオブジェクトを削除しても、その名前空間がまだ存在することがある。(Terminationの状態で残り続ける)
# kubectl get ns test-ns -o json > delete.json # vi delete.json { "apiVersion": "v1", "kind": "Namespace", "metadata": { "annotations": { ... "name": "test-ns", ... }, "spec": { "finalizers": [ "kubernetes" ] }, "status": { "phase": "Terminating" } }
- spec.finalizersを消して、APIに渡すと強制的に消せる。
# kubectl proxy & # curl -H "Content-Type: application/json" -X PUT --data-binary @delete.json http://127.0.0.1:8001/api/v1/namespaces/<ns>/finalize