使用 Kubernetes 聯邦(Kubefed)進行多集群管理

熱烈歡迎你,相識是一種緣分,Echa 哥為了你的到來特意準備了一份驚喜,k8s學習資料《 》


前一篇文章 《 》對 Federation v2 的基本概念和工作原理簡單介紹,本文著重介紹 Kubefed 的使用。

本文的實驗環境採用 v0.1.0-rc6 進行。

<code>$ kubefedctl version
kubefedctl version: version.Info{Version:"v0.1.0-rc6", GitCommit:"7586b42f4f477f1912caf28287fa2e0a7f68f407", GitTreeState:"clean", BuildDate:"2019-08-17T03:55:05Z", GoVersion:"go1.12.5", Compiler:"gc", Platform:"linux/amd64"}
複製代碼/<code>

安裝

Federation v2 的安裝分兩個部分,一是 Controller Plan 和 kubefedctl。

Controller Plan

Controller Plan 可以使用 Helm 部署(目前 Helm 還是使用 v2 版本),參考官方安裝文檔:github.com/kubernetes-…

添加 helm repo:

<code>$ helm repo add kubefed-charts https://raw.githubusercontent.com/kubernetes-sigs/kubefed/master/charts

$ helm repo list
NAME URL
kubefed-charts https://raw.githubusercontent.com/kubernetes-sigs/kubefed/master/charts
複製代碼/<code>

找到目前的版本:

<code>$ helm search kubefed
NAME \tCHART VERSION\tAPP VERSION\tDESCRIPTION
kubefed-charts/kubefed \t0.1.0-rc6 \t \tKubeFed helm chart
kubefed-charts/federation-v2\t0.0.10 \t \tKubernetes Federation V2 helm chart
複製代碼/<code>

然後使用 helm 直接安裝最新版本即可:

<code>$ helm install kubefed-charts/kubefed --name kubefed --version=0.1.0-rc6 --namespace kube-federation-system
複製代碼/<code>

kubefedctl

kubefedctl 是一個二進制程序,可以在 Github 的 Release 頁面找到最新版本的下載地址:github.com/kubernetes-…

<code>$ wget https://github.com/kubernetes-sigs/kubefed/releases/download/v0.1.0-rc6/kubefedctl-0.1.0-rc6-linux-amd64.tgz

$ tar -zxvf kubefedctl-0.1.0-rc6-linux-amd64.tgz

$ mv kubefedctl /usr/local/bin/
複製代碼/<code>

kubefedctl 提供了很多便捷操作,比如集群註冊、資源註冊等。

多集群管理

可以使用 kubefedctl join 命令接入新集群,在接入之前,需要先將多個集群信息配置在本地的 kubeconfig 中。

基本使用方式為:

<code>kubefedctl join  --cluster-context  --host-cluster-context <host>
複製代碼/<host>/<code>

比如:

<code>kubefedctl join cluster1 --cluster-context cluster1 \\
--host-cluster-context cluster1 --v=2
kubefedctl join cluster2 --cluster-context cluster2 \\
--host-cluster-context cluster1 --v=2
複製代碼/<code>

Kubefed 是利用 CR 來存儲自己所需要的數據,因此當使用 kubefedctl join 後,可以在 host cluster 查看到集群信息:

<code>$ kubectl -n kube-federation-system get kubefedclusters
NAME READY AGE
cluster1 True 3d22h
cluster2 True 3d22h
cluster3 True 3d22h
複製代碼/<code>

kubefedctl join 命令只是將 Kubeconfig 裡的配置轉化為 KubeFedCluster 自定義資源存儲到 kube-federation-system 命名空間中:

<code>$ kubectl -n kube-federation-system get kubefedclusters cluster1 -o yaml
apiVersion: core.kubefed.io/v1beta1
kind: KubeFedCluster
metadata:
creationTimestamp: "2019-10-24T08:05:38Z"
generation: 1
name: cluster1
namespace: kube-federation-system
resourceVersion: "647452"
selfLink: /apis/core.kubefed.io/v1beta1/namespaces/kube-federation-system/kubefedclusters/cluster1
uid: 4c5eb57f-5ed4-4cec-89f3-cfc062492ae0
spec:
apiEndpoint: https://172.16.200.1:6443
caBundle: LS....Qo=
secretRef:
name: cluster1-shb2x
status:
conditions:
- lastProbeTime: "2019-10-28T06:25:58Z"
lastTransitionTime: "2019-10-28T05:13:47Z"
message: /healthz responded with ok
reason: ClusterReady
status: "True"
type: Ready
region: ""
複製代碼/<code>

資源

Federation v1 的淘汰的原因之一便是對資源拓展比較死板(需要拓展 API Server)而且沒有預料的 CRD 的大規模應用,因此 Federation v2 在資源管理上面做的非常靈活。

對於 KubeFed 來說,資源管理分兩類,一是資源的類型管理,另一個是被聯邦(federated)的資源管理。

對於資源類型,kubefedctl 提供了 enable 來使新的資源可以被聯邦管理:

<code>kubefedctl enable <target>
複製代碼/<target>/<code>

其中 可以使用以下的描述:

  • 類型,即 Kind (比如 Deployment)
  • 複數名詞 (比如 deployments)
  • 帶 api group 的複數資源名詞 (比如 deployment.apps)
  • 縮寫 (比如 deploy)

比如我們需要把 istio 中的 VirtualService 資源交給聯邦管理,可以使用:

<code>kubefedctl enable VirtualService
複製代碼/<code>

因為 Kubefed 是通過 CRD 管理資源,因此,當 enable 執行之後可以看到 Host Cluster 中新增了一種名為 federatedvirtualservices 的 CRD:

<code>$ kubectl get crd | grep virtualservice
federatedvirtualservices.types.kubefed.io 2019-10-24T13:12:46Z
virtualservices.networking.istio.io 2019-10-24T08:06:01Z
複製代碼/<code>

該 CRD 裡面描述了 federatedvirtualservices 類型的必需字段,比如:placement、overrides 等。

kubefedctl enable 完成了資源類型的管理,對於需要被聯邦的資源管理編輯基於新創建的 CRD 展開的。不過要部署資源之前,需要先創建 federatednamespaces ,多集群的資源只會部署到被 kubefed 管理的 namespace 中:

<code>$ kubectl get federatednamespaces
NAME AGE
default 3d21h
複製代碼/<code>

這裡嘗試創建一個 federatedvirtualservices 類型的資源:

<code>$ kubectl get federatedvirtualservices
NAME AGE
service-route 3d4h
複製代碼/<code>

完整 yaml:

<code>apiVersion: types.kubefed.io/v1beta1
kind: FederatedVirtualService
metadata:
name: service-route
namespace: default
spec:
placement:
clusters:
- name: cluster1
- name: cluster2
- name: cluster3
template:
metadata:
name: service-route
spec:
gateways:
- service-gateway
hosts:
- '*'
http:
- match:
- uri:
prefix: /
route:

- destination:
host: service-a-1
port:
number: 3000
複製代碼/<code>

這時,Kubefed 會根據 template 裡的描述為目標集群創建對應的 virtualservice 資源。

<code>$ kubectl get virtualservices
NAME GATEWAYS HOSTS AGE
service-route [service-gateway] [*] 3d4h
複製代碼/<code>

調度

Kubefed 目前只能做到一些簡單的集群間調度,即手工指定。

對於手工指定的調度方式主要分為兩部分,一是直接在資源中制定目的地,二是通過 ReplicaSchedulingPreference 進行比例分配。

對於每個被聯邦的資源來說,都有一個 placement 字段用來描述將要部署在哪個集群,可以從 CRD 的描述中瞭解其定義思路:

<code>placement:
properties:
clusterSelector:
properties:
matchExpressions:
items:
properties:
key:
type: string
operator:
type: string
values:
items:
type: string
type: array

required:
- key
- operator
type: object
type: array
matchLabels:
additionalProperties:
type: string
type: object
type: object
clusters:
items:
properties:
name:
type: string
required:
- name
type: object
type: array
type: object
複製代碼/<code>

使用示例如下,可以通過 clusters 指定一個 cluster 列表,或者通過 clusterSelector 來根據集群標籤選擇集群:

<code>spec:
placement:
clusters:
- name: cluster2
- name: cluster1
clusterSelector:
matchLabels:
foo: bar
複製代碼/<code>

不過有兩點要注意:

  1. 如果 clusters 字段被指定,clusterSelector 將會被忽略
  2. 被選擇的集群是平等的,該資源會在每個被選中的集群中部署一個無差別副本

如果需要在多個集群間進行區別調度的話就需要引入 ReplicaSchedulingPreference 進行按比例的調度了。

ReplicaSchedulingPreference 定義了包括多個和調度相關的字段來描述調度策略:

<code>apiVersion: scheduling.kubefed.io/v1alpha1
kind: ReplicaSchedulingPreference
metadata:
name: test-deployment
namespace: test-ns
spec:
targetKind: FederatedDeployment
totalReplicas: 9
clusters:
A:
minReplicas: 4
maxReplicas: 6
weight: 1
B:
minReplicas: 4
maxReplicas: 8
weight: 2
複製代碼/<code>
  • totalReplicas 定義了總副本數
  • clusters 描述不同集群的 最大\\最小 副本以及權重

Kubefed 會根據調度策略的定義來進行維護不同集群的副本數,具體細節可以參考文檔:( github.com/kubernetes-… )。

網絡

Kubefed 還有一個亮點功能是跨集群間的網絡訪問。Kubefed 通過引入外部 DNS,將 Ingress Controller 和 metallb 等外部 LB 結合起來,使跨集群的流量可配置。

以 Ingress 舉例,用戶可以創建 IngressDNSRecord 類型的資源,並指定域名,Kubefed 將會根據 IngressDNSRecord 自定配置相關的 DNS 策略,並應用到外部服務器中。


使用 Kubernetes 聯邦(Kubefed)進行多集群管理

創建 IngressDNSRecord 類型的資源:

<code>apiVersion: multiclusterdns.kubefed.io/v1alpha1
kind: IngressDNSRecord
metadata:
name: test-ingress
namespace: test-namespace
spec:
hosts:
- ingress.example.com
recordTTL: 300
複製代碼/<code>

DNS Endpoint controller 會生成相關的 DNSEndpoint:

<code>$ kubectl -n test-namespace get dnsendpoints -o yaml
apiVersion: v1
items:
- apiVersion: multiclusterdns.kubefed.io/v1alpha1
kind: DNSEndpoint
metadata:
creationTimestamp: 2018-10-10T20:37:38Z
generation: 1
name: ingress-test-ingress
namespace: test-namespace
resourceVersion: "251874"
selfLink: /apis/multiclusterdns.kubefed.io/v1alpha1/namespaces/test-namespace/dnsendpoints/ingress-test-ingress
uid: 538d1063-cccc-11e8-bebb-42010a8a00b8
spec:
endpoints:
- dnsName: ingress.example.com
recordTTL: 300
recordType: A
targets:
- $CLUSTER1_INGRESS_IP
- $CLUSTER2_INGRESS_IP
status: {}
kind: List
metadata:
resourceVersion: ""
selfLink: ""
複製代碼/<code>

ExternalDNS controller 會監聽 DNSEndpoint 資源,收到事件後會將該記錄應用到 DNS 服務器上,如果成員集群的內部 DNS 服務器使用該外部 DNS 服務器作為上游服務器,那麼成員集群可以直接訪問對於域名就可以實現跨集群訪問。

部署

官方倉庫中有完整的實例以供實驗,可以參考:github.com/kubernetes-…

除了調度之外,Kubefed 通過 overrides 字段實現不同集群間的差異化部署:

<code>apiVersion: types.kubefed.io/v1beta1
kind: FederatedDeployment
metadata:
name: test-deployment
namespace: test-namespace
spec:
template:
metadata:
labels:
app: nginx
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- image: nginx
name: nginx
placement:
clusters:
- name: cluster2
- name: cluster1
overrides:
- clusterName: cluster2
clusterOverrides:
- path: "/spec/replicas"
value: 5
- path: "/spec/template/spec/containers/0/image"
value: "nginx:1.17.0-alpine"
- path: "/metadata/annotations"
op: "add"
value:
foo: bar
- path: "/metadata/annotations/foo"

op: "remove"
複製代碼/<code>

對該 Deployment 部署之後,可以通過 kubectl describe 查看部署狀態:

<code>$ kubectl describe federateddeployment.types.kubefed.io/test-deployment
Name: test-deployment
Namespace: default
Labels: <none>
Annotations: kubectl.kubernetes.io/last-applied-configuration:
{"apiVersion":"types.kubefed.io/v1beta1","kind":"FederatedDeployment","metadata":{"annotations":{},"name":"test-deployment","namespace":"d...
API Version: types.kubefed.io/v1beta1
Kind: FederatedDeployment
Metadata:
Creation Timestamp: 2019-10-28T07:55:34Z
Finalizers:
kubefed.io/sync-controller
Generation: 1
Resource Version: 657714
Self Link: /apis/types.kubefed.io/v1beta1/namespaces/default/federateddeployments/test-deployment
UID: 6016a3eb-7e7f-4756-ba40-b655581f06ad
Spec:
Overrides:
Cluster Name: cluster2
Cluster Overrides:
Path: /spec/replicas
Value: 5
Path: /spec/template/spec/containers/0/image
Value: nginx:1.17.0-alpine
Op: add
Path: /metadata/annotations
Value:
Foo: bar
Op: remove
Path: /metadata/annotations/foo
Placement:
Clusters:
Name: cluster2
Name: cluster1
Template:
Metadata:
Labels:
App: nginx
Spec:
Replicas: 3
Selector:
Match Labels:
App: nginx

Template:
Metadata:
Labels:
App: nginx
Spec:
Containers:
Image: nginx
Name: nginx
Status:
Clusters:
Name: cluster1
Name: cluster2
Conditions:
Last Transition Time: 2019-10-28T07:55:35Z
Last Update Time: 2019-10-28T07:55:49Z
Status: True
Type: Propagation
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal CreateInCluster 14s federateddeployment-controller Creating Deployment "default/test-deployment" in cluster "cluster2"
Normal CreateInCluster 14s federateddeployment-controller Creating Deployment "default/test-deployment" in cluster "cluster1"
Normal UpdateInCluster 0s (x10 over 12s) federateddeployment-controller Updating Deployment "default/test-deployment" in cluster "cluster2"
複製代碼/<none>/<code>

以及可以看到,在不同集群間的差異:

<code>$ kubectl --context=cluster1 get deploy | grep test
test-deployment 3/3 3 3 98s

$ kubectl --context=cluster2 get deploy | grep test
test-deployment 5/5 5 5 105s/<code>


分享到:


相關文章: