溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶(hù)服務(wù)條款》

如何從零開(kāi)始建立EMQ X MQTT服務(wù)器的K8S集群

發(fā)布時(shí)間:2021-12-07 09:09:34 來(lái)源:億速云 閱讀:183 作者:iii 欄目:云計(jì)算

本篇內(nèi)容介紹了“如何從零開(kāi)始建立EMQ X MQTT服務(wù)器的K8S集群”的有關(guān)知識(shí),在實(shí)際案例的操作過(guò)程中,不少人都會(huì)遇到這樣的困境,接下來(lái)就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!

EMQ X Team 提供了 Helm chart 方便用戶(hù)在 kubernetes 集群上一鍵部署 EMQ X MQTT 服務(wù)器, 這是 EMQ X Team 最推薦的在 kubernetes 或 k3s 集群上部署 EMQ X MQTT 服務(wù)器的方法。 

在 K8S 上部署單個(gè) EMQ X MQTT服務(wù)器節(jié)點(diǎn)

使用 Pod 直接部署 EMQ X Broker

在Kubernetes中,最小的管理元素不是一個(gè)個(gè)獨(dú)立的容器,而是 Pod,Pod 是 Kubernetes 應(yīng)用程序的基本執(zhí)行單元,即它是 Kubernetes 對(duì)象模型中創(chuàng)建或部署的最小和最簡(jiǎn)單的單元。Pod 表示在 集群 上運(yùn)行的進(jìn)程。

EMQ X Broker 在 docker hub 上提供了鏡像, 因此可以很方便的在單個(gè)的 pod 上部署 EMQ X Broker,使用 kubectl run 命令創(chuàng)建一個(gè)運(yùn)行著 EMQ X Broker 的 Pod:

$ kubectl run emqx --image=emqx/emqx:v4.1-rc.1  --generator=run-pod/v1
pod/emqx created

查看 EMQ X Broker 的狀態(tài):

$ kubectl get pods -o wide
NAME   READY   STATUS    RESTARTS   AGE
emqx   1/1     Running   0          3m13s
$ kubectl exec emqx -- emqx_ctl status
Node 'emqx@192.168.77.108' is started
emqx 4.1-rc.1 is running

刪除 Pod:

$ kubectl delete pods emqx
pod "emqx" deleted

Pod 并不是被設(shè)計(jì)成一個(gè)持久化的資源,它不會(huì)在調(diào)度失敗,節(jié)點(diǎn)崩潰,或者其他回收中(比如因?yàn)橘Y源的缺乏,或者其他的維護(hù)中)幸存下來(lái),因此,還需要一個(gè)控制器來(lái)管理 Pod。

使用 Deoloyment 部署 Pod

Deployment 為 Pod 和 ReplicaSet 提供了一個(gè)聲明式定義(declarative)方法,用來(lái)替代以前的 ReplicationController 來(lái)方便的管理應(yīng)用。典型的應(yīng)用場(chǎng)景包括:

  • 定義Deployment來(lái)創(chuàng)建Pod和ReplicaSet

  • 滾動(dòng)升級(jí)和回滾應(yīng)用

  • 擴(kuò)容和縮容

  • 暫停和繼續(xù)Deployment

使用 Deployment 部署一個(gè) EMQ X Broker Pod:

  • 定義 Deployment:

    $ cat deployment.yaml
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: emqx-deployment
      labels:
        app: emqx
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: emqx
      template:
        metadata:
          labels:
            app: emqx
        spec:
          containers:
          - name: emqx
            image: emqx/emqx:v4.1-rc.1
            ports:
            - name: mqtt
                containerPort: 1883
            - name: mqttssl
                containerPort: 8883
            - name: mgmt
                containerPort: 8081
            - name: ws
                containerPort: 8083
            - name: wss
                containerPort: 8084
            - name: dashboard
                containerPort: 18083
  • 部署 Deployment:

    $  kubectl apply -f deployment.yaml
    deployment.apps/emqx-deployment created
  • 查看部署情況:

    $ kubectl get deployment
    NAME                              READY   UP-TO-DATE   AVAILABLE   AGE
    deployment.apps/emqx-deployment   3/3     3            3           74s
    $ kubectl get pods
    NAME                                  READY   STATUS    RESTARTS   AGE
    pod/emqx-deployment-7c44dbd68-8j77l   1/1     Running   0          74s
    $ kubectl exec pod/emqx-deployment-7c44dbd68-8j77l -- emqx_ctl status
    Node 'emqx-deployment-7c44dbd68-
    8j77l@192.168.77.117' is started
    emqx 4.1-rc.1 is running
  • 嘗試手動(dòng)刪除 Pod

    $ kubectl delete pods emqx-deployment-7c44dbd68-8j77l
    pod "emqx-deployment-7c44dbd68-8j77l" deleted
    $ kubectl get pods
    NAME                              READY   STATUS    RESTARTS   AGE
    emqx-deployment-68fcb4bfd6-2nhh7   1/1     Running   0          59s

輸出結(jié)果表明成功用 Deployment 部署了 EMQ X Broker Pod,即使是此 Pod 被意外終止,Deployment 也會(huì)重新創(chuàng)建一個(gè)新的 Pod。

使用 Services 公開(kāi) EMQ X Broker Pod 服務(wù)

Kubernetes Pods 是有生命周期的。他們可以被創(chuàng)建,而且銷(xiāo)毀不會(huì)再啟動(dòng)。 如果使用 Deployment 來(lái)運(yùn)行應(yīng)用程序,則它可以動(dòng)態(tài)創(chuàng)建和銷(xiāo)毀 Pod。

每個(gè) Pod 都有自己的 IP 地址,但是在 Deployment 中,在同一時(shí)刻運(yùn)行的 Pod 集合可能與稍后運(yùn)行該應(yīng)用程序的 Pod 集合不同。

這導(dǎo)致了一個(gè)問(wèn)題:如果使用 EMQ X Broker Pod 為 MQTT 客戶(hù)端提供服務(wù),那么客戶(hù)端應(yīng)該如何如何找出并跟蹤要連接的 IP 地址,以便客戶(hù)端使用 EMQ X Broker 服務(wù)呢?

答案是:Service

Service 是將運(yùn)行在一組 Pods 上的應(yīng)用程序公開(kāi)為網(wǎng)絡(luò)服務(wù)的抽象方法。

使用 Service 將 EMQ X Broker Pod 公開(kāi)為網(wǎng)絡(luò)服務(wù):

  • 定義 Service:

    $cat service.yaml
    apiVersion: v1
    kind: Service
    metadata:
      name: emqx-service
    spec:
      selector:
        app: emqx
      ports:
        - name: mqtt
          port: 1883
          protocol: TCP
          targetPort: mqtt
        - name: mqttssl
          port: 8883
          protocol: TCP
          targetPort: mqttssl
        - name: mgmt
          port: 8081
          protocol: TCP
          targetPort: mgmt
        - name: ws
          port: 8083
          protocol: TCP
          targetPort: ws
        - name: wss
          port: 8084
          protocol: TCP
          targetPort: wss
        - name: dashboard
          port: 18083
          protocol: TCP
          targetPort: dashboard
  • 部署 Service:

    $ kubectl apply -f service.yaml
    service/emqx-service created
  • 查看部署情況

    $ kubectl get svc
    NAME           TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)                                        AGE
    emqx-service   ClusterIP   10.96.54.205   <none>        1883/TCP,8883/TCP,8081/TCP,8083/TCP,8084/TCP,18083/TCP   58s
  • 使用 Service 提供的 IP 查看 EMQ X Broker 的 API

    $ curl 10.96.54.205:8081/status
    Node emqx-deployment-68fcb4bfd6-
    2nhh7@192.168.77.120 is started
    emqx is running

至此,單個(gè) EMQ X Broker 節(jié)點(diǎn)在 kubernetes 上部署完畢,通過(guò) Deployment 管理 EMQ X Broker Pod,通過(guò) Service 將 EMQ X Broker 服務(wù)暴露出去。

通過(guò) kubernetes 自動(dòng)集群 EMQ X MQTT 服務(wù)器

上文中通過(guò) Deployment 部署了單個(gè)的 EMQ X Broker Pod,通過(guò) Deployment 擴(kuò)展 Pod 的數(shù)量是極為方便的,執(zhí)行 kubectl scale deployment ${deployment_name} --replicas ${numer} 命令即可擴(kuò)展 Pod 的數(shù)量,下面將 EMQ X Broker Pod 擴(kuò)展為 3 個(gè):

$ kubectl scale deployment emqx-deployment --replicas 3
deployment.apps/emqx-deployment scaled
$ kubectl get pods
NAME                               READY   STATUS    RESTARTS   AGE
emqx-deployment-68fcb4bfd6-2nhh7   1/1     Running   0          18m
emqx-deployment-68fcb4bfd6-mpvch   1/1     Running   0          6s
emqx-deployment-68fcb4bfd6-mx55q   1/1     Running   0          6s
$ kubectl exec emqx-deployment-68fcb4bfd6-2nhh7 -- emqx_ctl status
Node 'emqx-deployment-68fcb4bfd6-2nhh7@192.168.77.120' is started
emqx 4.1-rc.1 is running
$ kubectl exec emqx-deployment-68fcb4bfd6-2nhh7 -- emqx_ctl cluster status
Cluster status: #{running_nodes =>
                      ['emqx-deployment-68fcb4bfd6-2nhh7@192.168.77.120'],
                  stopped_nodes => []}

可以看到 EMQ X Broker Pod 的數(shù)量被擴(kuò)展為 3 個(gè),但是每個(gè) Pod 都是獨(dú)立的,并沒(méi)有集群,接下來(lái)嘗試通過(guò) kubernetes 自動(dòng)集群 EMQ X Broker Pod。

修改 EMQ X Broker 的配置

查看 EMQ X Broker 文檔中關(guān)于 自動(dòng)集群的內(nèi)容,可以看到需要修改 EMQ X Broker 的配置:

cluster.discovery = kubernetes
cluster.kubernetes.apiserver = http://10.110.111.204:8080
cluster.kubernetes.service_name = ekka
cluster.kubernetes.address_type = ip
cluster.kubernetes.app_name = ekka

其中 cluster.kubernetes.apiserver 為 kubernetes apiserver 的地址,可以通過(guò) kubectl cluster-info 命令獲取,cluster.kubernetes.service_name 為上文中 Service 的 name, cluster.kubernetes.app_name 為 EMQ X Broker 的 node.name@ 符號(hào)之前的部分,所以還需要將集群中 EMQ X Broker 設(shè)置為統(tǒng)一的 node.name 的前綴。

EMQ X Broker 的 docker 鏡像提供了通過(guò)環(huán)境變量修改配置的功能,具體可以查看 docker hub 或 Github。

  • 修改 Deployment 的 yaml 文件,增加環(huán)境變量:

    $ cat deployment.yaml
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: emqx-deployment
      labels:
        app: emqx
    spec:
      replicas: 3
      selector:
        matchLabels:
          app: emqx
      template:
        metadata:
          labels:
            app: emqx
        spec:
          containers:
          - name: emqx
            image: emqx/emqx:v4.1-rc.1
            ports:
            - name: mqtt
              containerPort: 1883
            - name: mqttssl
              containerPort: 8883
            - name: mgmt
              containerPort: 8081
            - name: ws
              containerPort: 8083
            - name: wss
              containerPort: 8084
            - name: dashboard
              containerPort: 18083
            env:
            - name: EMQX_NAME
                value: emqx
            - name: EMQX_CLUSTER__DISCOVERY
              value: k8s
            - name: EMQX_CLUSTER__K8S__APP_NAME
              value: emqx
            - name: EMQX_CLUSTER__K8S__SERVICE_NAME
              value: emqx-service
            - name: EMQX_CLUSTER__K8S__APISERVER
              value: "https://kubernetes.default.svc:443"
            - name: EMQX_CLUSTER__K8S__NAMESPACE
              value: default

因?yàn)? `kubectl scale deployment ${deployment_name} --replicas ${numer} 命令不會(huì)修改 yaml 文件,所以修改 yaml 時(shí)需要設(shè)置 spec.replicas: 3 。

Pod 中內(nèi)建 kubernetes 的 DNS 規(guī)則,所以 https://kubernetes.default.svc:443 會(huì)被解析為 kubernetes apiserver  的地址。

  • 刪除之前的 Deployment,重新部署:

    $ kubectl delete deployment emqx-deployment
    deployment.apps "emqx-deployment" deleted
    $ kubectl apply -f deployment.yaml
    deployment.apps/emqx-deployment created

賦予 Pod 訪問(wèn) kubernetes apiserver 的權(quán)限

上文部署 Deployment 之后,查看 EMQ X Broker 的狀態(tài),可以看到 EMQ X Broker 雖然成功啟動(dòng)了,但是依然沒(méi)有集群成功,查看 EMQ X Broker Pod 的 log:

$ kubectl get pods
NAME                               READY   STATUS    RESTARTS   AGE
emqx-deployment-5c8cfc4d75-67lmt   1/1     Running   0          5s
emqx-deployment-5c8cfc4d75-r6jgb   1/1     Running   0          5s
emqx-deployment-5c8cfc4d75-wv2hj   1/1     Running   0          5s
$ kubectl exec emqx-deployment-5c8cfc4d75-67lmt -- emqx_ctl status
Node 'emqx@192.168.87.150' is started
emqx 4.1-rc.1 is running
$ kubectl exec emqx-deployment-5c8cfc4d75-67lmt -- emqx_ctl cluster status
Cluster status: #{running_nodes => ['emqx@192.168.87.150'],
                  stopped_nodes => []}                  
$ kubectl logs emqx-deployment-76f6895c46-4684f
···
(emqx@192.168.87.150)1> 2020-05-20 01:48:39.726 [error] Ekka(AutoCluster): Discovery error: {403,
                                     "{\"kind\":\"Status\",\"apiVersion\":\"v1\",\"metadata\":{},\"status\":\"Failure\",\"message\":\"endpoints \\\"emqx-service\\\" is forbidden: User \\\"system:serviceaccount:default:default\\\" cannot get resource \\\"endpoints\\\" in API group \\\"\\\" in the namespace \\\"default\\\"\",\"reason\":\"Forbidden\",\"details\":{\"name\":\"emqx-service\",\"kind\":\"endpoints\"},\"code\":403}\n"}
···

Pod 因?yàn)闄?quán)限問(wèn)題在訪問(wèn) kubernetes apiserver 的時(shí)候被拒絕,返回 HTTP 403,所以集群失敗。

普通 Pod 是無(wú)法訪問(wèn) kubernetes apiserver 的,解決這個(gè)問(wèn)題有兩種方法,一種是開(kāi)放 kubernetes apiserver 的 http 接口,但是這種方法存在一定的安全隱患,另外一種是通過(guò) ServiceAccount、Role 和 RoleBinding 配置 RBAC 鑒權(quán)。

  • 定義  ServiceAccount、Role 和 RoleBinding:

    $ cat rbac.yaml
    apiVersion: v1
    kind: ServiceAccount
    metadata:
      namespace: default
      name: emqx
    ---
    kind: Role
    apiVersion: rbac.authorization.kubernetes.io/v1beta1
    metadata:
      namespace: default
      name: emqx
    rules:
    - apiGroups:
      - ""
      resources:
      - endpoints 
      verbs: 
      - get
      - watch
      - list
    ---
    kind: RoleBinding
    apiVersion: rbac.authorization.kubernetes.io/v1beta1
    metadata:
      namespace: default
      name: emqx
    subjects:
      - kind: ServiceAccount
        name: emqx
        namespace: default
    roleRef:
      kind: Role
      name: emqx
      apiGroup: rbac.authorization.kubernetes.io
  • 部署相應(yīng)的資源:

    $ kubectl apply -f rbac.yaml
    serviceaccount/emqx created
    role.rbac.authorization.kubernetes.io/emqx created
    rolebinding.rbac.authorization.kubernetes.io/emqx created
  • 修改 Deployment 的 yaml 文件,增加 spec.template.spec.serviceAccountName,并重新部署:

    $cat deployment.yaml
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: emqx-deployment
      labels:
        app: emqx
    spec:
      replicas: 3
      selector:
        matchLabels:
          app: emqx
      template:
        metadata:
          labels:
            app: emqx
        spec:
          serviceAccountName: emqx
          containers:
          - name: emqx
            image: emqx/emqx:v4.1-rc.1
            ports:
            - name: mqtt
              containerPort: 1883
            - name: mqttssl
              containerPort: 8883
            - name: mgmt
              containerPort: 8081
            - name: ws
              containerPort: 8083
            - name: wss
              containerPort: 8084
            - name: dashboard
              containerPort: 18083
            env:
            - name: EMQX_NAME
                value: emqx
            - name: EMQX_CLUSTER__DISCOVERY
              value: kubernetes
            - name: EMQX_CLUSTER__K8S__APP_NAME
              value: emqx
            - name: EMQX_CLUSTER__K8S__SERVICE_NAME
              value: emqx-service
            - name: EMQX_CLUSTER__K8S__APISERVER
              value: "https://kubernetes.default.svc:443"
            - name: EMQX_CLUSTER__K8S__NAMESPACE
              value: default          
    $ kubectl delete deployment emqx-deployment
    deployment.apps "emqx-deployment" deleted
    $ kubectl apply -f deployment.yaml
    deployment.apps/emqx-deployment created
  • 查看狀態(tài):

    $ kubectl get pods
    NAME                              READY   STATUS    RESTARTS   AGE
    emqx-deployment-6b854486c-dhd7p   1/1     Running   0          10s
    emqx-deployment-6b854486c-psv2r   1/1     Running   0          10s
    emqx-deployment-6b854486c-tdzld   1/1     Running   0          10s
    $ kubectl exec emqx-deployment-6b854486c-dhd7p  -- emqx_ctl status
    Node '
    emqx@192.168.77.92' is started
    emqx 4.1-rc.1 is running
    $ kubectl exec emqx-deployment-6b854486c-dhd7p  -- emqx_ctl cluster status
    Cluster status: #{running_nodes =>
                          ['
    emqx@192.168.77.115','
    emqx@192.168.77.92',
                           '
    emqx@192.168.87.157'],
                      stopped_nodes => []}
  • 中止一個(gè) Pod:

    $ kubectl delete pods emqx-deployment-6b854486c-dhd7p
    pod "emqx-deployment-6b854486c-dhd7p" deleted
    $ kubectl get pods
    NAME                              READY   STATUS    RESTARTS   AGE
    emqx-deployment-6b854486c-846v7   1/1     Running   0          56s
    emqx-deployment-6b854486c-psv2r   1/1     Running   0          3m50s
    emqx-deployment-6b854486c-tdzld   1/1     Running   0          3m50s
    $ kubectl exec emqx-deployment-6b854486c-846v7 -- emqx_ctl cluster status
    Cluster status: #{running_nodes =>
                          ['
    emqx@192.168.77.115','
    emqx@192.168.77.84',
                           '
    emqx@192.168.87.157'],
                      stopped_nodes => ['
    emqx@192.168.77.92']}

    輸出結(jié)果表明 EMQ X Broker 會(huì)正確的顯示已經(jīng)停掉的 Pod,并將 Deployment 新建的 Pod 加入集群。

至此,EMQ X Broker 在 kubernetes 上成功建立集群。

持久化 EMQ X Broker 集群

上文中使用的 Deployment 來(lái)管理 Pod,但是 Pod 的網(wǎng)絡(luò)是不停變動(dòng)的,而且當(dāng) Pod 被銷(xiāo)毀重建時(shí),儲(chǔ)存在 EMQ X Broker 的數(shù)據(jù)和配置也就隨之消失了,這在生產(chǎn)中是不能接受的,接下來(lái)嘗試把 EMQ X Broker 的集群持久化,即使 Pod 被銷(xiāo)毀重建,EMQ X Broker 的數(shù)據(jù)依然可以保存下來(lái)。

ConfigMap

ConfigMap 是 configMap 是一種 API 對(duì)象,用來(lái)將非機(jī)密性的數(shù)據(jù)保存到健值對(duì)中。使用時(shí)可以用作環(huán)境變量、命令行參數(shù)或者存儲(chǔ)卷中的配置文件。

ConfigMap 將您的環(huán)境配置信息和 容器鏡像 解耦,便于應(yīng)用配置的修改。

ConfigMap 并不提供保密或者加密功能。如果你想存儲(chǔ)的數(shù)據(jù)是機(jī)密的,請(qǐng)使用 Secret ,或者使用其他第三方工具來(lái)保證你的數(shù)據(jù)的私密性,而不是用 ConfigMap。

接下來(lái)使用 ConfigMap 記錄 EMQ X Broker 的配置,并將它們以環(huán)境變量的方式導(dǎo)入到 Deployment 中。

  • 定義 Configmap,并部署:

    $cat configmap.yaml
    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: emqx-config
    data:
      EMQX_CLUSTER__K8S__ADDRESS_TYPE: "hostname"
      EMQX_CLUSTER__K8S__APISERVER: "https://kubernetes.default.svc:443"
      EMQX_CLUSTER__K8S__SUFFIX: "svc.cluster.local"  
    $ kubectl apply -f configmap.yaml
    configmap/emqx-config created
  • 配置 Deployment 來(lái)使用 Configmap

    $cat deployment.yaml
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: emqx-deployment
      labels:
        app: emqx
    spec:
      replicas: 3
      selector:
        matchLabels:
          app: emqx
      template:
        metadata:
          labels:
            app: emqx
        spec:
          serviceAccountName: emqx
          containers:
          - name: emqx
            image: emqx/emqx:v4.1-rc.1
            ports:
            - name: mqtt
              containerPort: 1883
            - name: mqttssl
              containerPort: 8883
            - name: mgmt
              containerPort: 8081
            - name: ws
              containerPort: 8083
            - name: wss
              containerPort: 8084
            - name: dashboard
              containerPort: 18083
            envFrom:
              - configMapRef:
                  name: emqx-config
  • 重新部署 Deployment,查看狀態(tài)

    $ kubectl delete -f deployment.yaml
    deployment.apps "emqx-deployment" deleted
    $ kubectl apply -f deployment.yaml
    deployment.apps/emqx-deployment created
    $ kubectl get pods
    NAME                               READY   STATUS    RESTARTS   AGE
    emqx-deployment-5c7696b5d7-k9lzj   1/1     Running   0          3s
    emqx-deployment-5c7696b5d7-mdwkt   1/1     Running   0          3s
    emqx-deployment-5c7696b5d7-z57z7   1/1     Running   0          3s
    $ kubectl exec emqx-deployment-5c7696b5d7-k9lzj -- emqx_ctl status
    Node '
    emqx@192.168.87.149' is started
    emqx 4.1-rc.1 is running
    $ kubectl exec emqx-deployment-5c7696b5d7-k9lzj -- emqx_ctl cluster status
    Cluster status: #{running_nodes =>
                          ['
    emqx@192.168.77.106','
    emqx@192.168.77.107',
                           '
    emqx@192.168.87.149'],
                      stopped_nodes => []}

EMQ X Broker 的配置文件已經(jīng)解耦到 Configmap 中了,如果有需要,可以自由的配置一個(gè)或多個(gè) Configmap,并把它們作為環(huán)境變量或是文件引入到 Pod 內(nèi)。

StatefulSet

StatefulSet 是為了解決有狀態(tài)服務(wù)的問(wèn)題(對(duì)應(yīng) Deployments 和 ReplicaSets 是為無(wú)狀態(tài)服務(wù)而設(shè)計(jì)),其應(yīng)用場(chǎng)景包括

  • 穩(wěn)定的持久化存儲(chǔ),即 Pod 重新調(diào)度后還是能訪問(wèn)到相同的持久化數(shù)據(jù),基于 PVC 來(lái)實(shí)現(xiàn)

  • 穩(wěn)定的網(wǎng)絡(luò)標(biāo)志,即 Pod 重新調(diào)度后其 PodName 和 HostName 不變,基于 Headless Service(即沒(méi)有Cluster IP的Service)來(lái)實(shí)現(xiàn)

  • 有序部署,有序擴(kuò)展,即 Pod 是有順序的,在部署或者擴(kuò)展的時(shí)候要依據(jù)定義的順序依次依次進(jìn)行(即從0到N-1,在下一個(gè)Pod運(yùn)行之前所有之前的 Pod 必須都是 Running 和 Ready 狀態(tài)),基于 init containers 來(lái)實(shí)現(xiàn)

  • 有序收縮,有序刪除(即從N-1到0)

從上面的應(yīng)用場(chǎng)景可以發(fā)現(xiàn),StatefulSet由以下幾個(gè)部分組成:

  • 用于定義網(wǎng)絡(luò)標(biāo)志(DNS domain)的 Headless Service

  • 用于創(chuàng)建 PersistentVolumes 的 volumeClaimTemplates

  • 定義具體應(yīng)用的 StatefulSet

StatefulSet 中每個(gè) Pod 的 DNS 格式為 statefulSetName-{0..N-1}.serviceName.namespace.svc.cluster.local ,其中

  • serviceName 為 Headless Service 的名字

  • 0..N-1 為 Pod 所在的序號(hào),從 0 開(kāi)始到 N-1

  • statefulSetName 為StatefulSet的名字

  • namespace 為服務(wù)所在的 namespace,Headless Servic 和 StatefulSet 必須在相同的 namespace

  • .cluster.local 為 Cluster Domain

接下來(lái)使用 StatefulSet 代替 Deployment 來(lái)管理 Pod。

  • 刪除 Deployment:

    $ kubectl delete deployment emqx-deployment
    deployment.apps "emqx-deployment" deleted
  • 定義 StatefulSet:

    $cat statefulset.yaml
    apiVersion: apps/v1
    kind: StatefulSet
    metadata:
      name: emqx-statefulset
      labels:
        app: emqx
    spec:
        serviceName: emqx-headless
      updateStrategy:
        type: RollingUpdate
      replicas: 3
      selector:
        matchLabels:
          app: emqx
      template:
        metadata:
          labels:
            app: emqx
        spec:
          serviceAccountName: emqx
          containers:
          - name: emqx
            image: emqx/emqx:v4.1-rc.1
            ports:
            - name: mqtt
              containerPort: 1883
            - name: mqttssl
              containerPort: 8883
            - name: mgmt
              containerPort: 8081
            - name: ws
              containerPort: 8083
            - name: wss
              containerPort: 8084
            - name: dashboard
              containerPort: 18083
            envFrom:
              - configMapRef:
                  name: emqx-config

注意,StatefulSet 需要 Headless Service 來(lái)實(shí)現(xiàn)穩(wěn)定的網(wǎng)絡(luò)標(biāo)志,因此需要再定義一個(gè) Service

  $cat headless.yaml
  apiVersion: v1
  kind: Service
  metadata:
    name: emqx-headless
  spec:
    type: ClusterIP
    clusterIP: None
    selector:
      app: emqx
    ports:
    - name: mqtt
      port: 1883
      protocol: TCP
      targetPort: 1883
    - name: mqttssl
      port: 8883
      protocol: TCP
      targetPort: 8883
    - name: mgmt
      port: 8081
      protocol: TCP
      targetPort: 8081
    - name: websocket
      port: 8083
      protocol: TCP
      targetPort: 8083
    - name: wss
      port: 8084
      protocol: TCP
      targetPort: 8084
    - name: dashboard
      port: 18083
      protocol: TCP
      targetPort: 18083

因?yàn)?Headless Service 并不需要 IP,所以配置了 clusterIP: None 。

  • 部署相應(yīng)的資源:

    $ kubectl apply -f headless-service.yaml
    service/emqx-headless created
    $ kubectl apply -f statefulset.yaml
    statefulset.apps/emqx-deployment created
    $ kubectl get pods
    NAME                               READY   STATUS    RESTARTS   AGE
    emqx-statefulset-0                 1/1     Running   0          2m59s
    emqx-statefulset-1                 1/1     Running   0          2m57s
    emqx-statefulset-2                 1/1     Running   0          2m54s
    $ kubectl exec emqx-statefulset-0 -- emqx_ctl cluster status
    Cluster status: #{running_nodes =>
                          ['
    emqx@192.168.77.105','
    emqx@192.168.87.153',
                           '
    emqx@192.168.87.155'],
                      stopped_nodes => []}
  • 更新 Configmap:

    StatefulSet 提供了穩(wěn)定的網(wǎng)絡(luò)標(biāo)志,EMQ X Broker 支持使用 hostname 和 dns 規(guī)則來(lái)代提 IP 實(shí)現(xiàn)集群,以 hostname 為例,需要修改 emqx.conf

    cluster.kubernetes.address_type = hostname
    cluster.kubernetes.suffix = "svc.cluster.local"

    kubernetes 集群中 Pod 的 DNS 規(guī)則可以由用戶(hù)自定義,EMQ X Broker 提供了  cluster.kubernetes.suffix 方便用戶(hù)匹配自定的 DNS 規(guī)則,本文使用默認(rèn)的 DNS 規(guī)則:statefulSetName-{0..N-1}.serviceName.namespace.svc.cluster.local ,DNS 規(guī)則中的 serviceName 為 StatefulSet 使用的 Headless Service,所以還需要將 cluster.kubernetes.service_name  修改為 Headless Service Name。

    將配置項(xiàng)轉(zhuǎn)為環(huán)境變量,需要在 Configmap 中配置:

    EMQX_CLUSTER__K8S__ADDRESS_TYPE: "hostname"
    EMQX_CLUSTER__K8S__SUFFIX: "svc.cluster.local"
    EMQX_CLUSTER__K8S__SERVICE_NAME: emqx-headless

    Configmap 提供了熱更新功能,執(zhí)行 $ kubectl edit configmap emqx-config 來(lái)熱更新 Configmap。

  • 重新部署 StatefulSet:

    Configmap 更新之后 Pod 并不會(huì)重啟,需要我們手動(dòng)更新 StatefulSet

    $ kubectl delete statefulset emqx-statefulset
    statefulset.apps "emqx-statefulset" deleted
    $ kubectl apply -f statefulset.yaml
    statefulset.apps/emqx-statefulset created
    $ kubectl get pods
    NAME                 READY   STATUS    RESTARTS   AGE
    emqx-statefulset-0   1/1     Running   0          115s
    emqx-statefulset-1   1/1     Running   0          112s
    emqx-statefulset-2   1/1     Running   0          110s
    $ kubectl exec emqx-statefulset-2 -- emqx_ctl cluster status
    Cluster status: #{running_nodes =>
                          ['emqx
    @emqx-statefulset-0.emqx-headless.default.svc.cluster.local',
                           'emqx
    @emqx-statefulset-1.emqx-headless.default.svc.cluster.local',
                           'emqx
    @emqx-statefulset-2.emqx-headless.default.svc.cluster.local'],
                      stopped_nodes => []}

    可以看到新的 EMQ X Broker 集群已經(jīng)成功的建立起來(lái)了。

  • 中止一個(gè) Pod:

    StatefulSet 中的 Pod 重新調(diào)度后其 PodName 和 HostName 不變,下面來(lái)嘗試一下:

    $ kubectl get pods
    kuNAME                 READY   STATUS    RESTARTS   AGE
    emqx-statefulset-0   1/1     Running   0          6m20s
    emqx-statefulset-1   1/1     Running   0          6m17s
    emqx-statefulset-2   1/1     Running   0          6m15s
    $ kubectl delete pod emqx-statefulset-0
    pod "emqx-statefulset-0" deleted
    $ kubectl get pods
    NAME                 READY   STATUS    RESTARTS   AGE
    emqx-statefulset-0   1/1     Running   0          27s
    emqx-statefulset-1   1/1     Running   0          9m45s
    emqx-statefulset-2   1/1     Running   0          9m43s
    $ kubectl exec emqx-statefulset-2 -- emqx_ctl cluster status
    Cluster status: #{running_nodes =>
                          ['emqx
    @emqx-statefulset-0.emqx-headless.default.svc.cluster.local',
                           'emqx
    @emqx-statefulset-1.emqx-headless.default.svc.cluster.local',
                           'emqx
    @emqx-statefulset-2.emqx-headless.default.svc.cluster.local'],
                      stopped_nodes => []}

    跟預(yù)期的一樣,StatefulSet 重新調(diào)度了一個(gè)具有相同網(wǎng)絡(luò)標(biāo)志的 Pod,Pod 中的 EMQ X Broker 也成功的加入了集群。

StorageClasses、PersistentVolume 和 PersistentVolumeClaim

PersistentVolume(PV)是由管理員設(shè)置的存儲(chǔ),它是群集的一部分。就像節(jié)點(diǎn)是集群中的資源一樣,PV 也是集群中的資源。 PV 是 Volume 之類(lèi)的卷插件,但具有獨(dú)立于使用 PV 的 Pod 的生命周期。此 API  對(duì)象包含存儲(chǔ)實(shí)現(xiàn)的細(xì)節(jié),即 NFS、iSCSI 或特定于云供應(yīng)商的存儲(chǔ)系統(tǒng)。

PersistentVolumeClaim(PVC)是用戶(hù)存儲(chǔ)的請(qǐng)求。它與 Pod 相似。Pod 消耗節(jié)點(diǎn)資源,PVC 消耗 PV 資源。Pod 可以請(qǐng)求特定級(jí)別的資源(CPU 和內(nèi)存)。聲明可以請(qǐng)求特定的大小和訪問(wèn)模式(例如,可以以讀/寫(xiě)一次或 只讀多次模式掛載)。

StorageClass 為管理員提供了描述存儲(chǔ) “class(類(lèi))” 的方法。 不同的 class  可能會(huì)映射到不同的服務(wù)質(zhì)量等級(jí)或備份策略,或由群集管理員確定的任意策略。 Kubernetes 本身不清楚各種 class  代表的什么。這個(gè)概念在其他存儲(chǔ)系統(tǒng)中有時(shí)被稱(chēng)為“配置文件”。

在部署 EMQ X Broker 的時(shí)候,可以預(yù)先創(chuàng)建好 PV 或 StorageClass,然后利用 PVC 將 EMQ X Broker 的 /opt/emqx/data/mnesia 目錄掛載出來(lái),當(dāng)Pods被重新調(diào)度之后,EMQ X 會(huì)從 /opt/emqx/data/mnesia 目錄中獲取數(shù)據(jù)并恢復(fù),從而實(shí)現(xiàn) EMQ X Broker 的持久化。

  • 定義 StatefulSet

    $cat statefulset.yaml
    apiVersion: apps/v1
    kind: StatefulSet
    metadata:
      name: emqx-statefulset
      labels:
        app: emqx
    spec:
      replicas: 3
      serviceName: emqx-headless
      updateStrategy:
        type: RollingUpdate
      selector:
        matchLabels:
          app: emqx
      template:
        metadata:
          labels:
            app: emqx
        spec:
          volumes:
          - name: emqx-data
            persistentVolumeClaim:
              claimName: emqx-pvc
          serviceAccountName: emqx
          containers:
          - name: emqx
            image: emqx/emqx:v4.1-rc.1
            ports:
            - name: mqtt
              containerPort: 1883
            - name: mqttssl
              containerPort: 8883
            - name: mgmt
              containerPort: 8081
            - name: ws
              containerPort: 8083
            - name: wss
              containerPort: 8084
            - name: dashboard
              containerPort: 18083
            envFrom:
              - configMapRef:
                  name: emqx-config
            volumeMounts:
            - name: emqx-data
              mountPath: "/opt/emqx/data/mnesia"
      volumeClaimTemplates:
      - metadata:
          name: emqx-pvc
          annotations:
            volume.alpha.kubernetes.io/storage-class: manual
        spec:
          accessModes: [ "ReadWriteOnce" ]
          resources:
            requests:
              storage: 1Gi

該文件首先通過(guò) volumeClaimTemplates 指定了使用 StorageClass 的 name 為 manual 的存儲(chǔ)類(lèi)創(chuàng)建名稱(chēng)為 emqx-pvc 的 PVC 資源,PVC 資源的讀寫(xiě)模式為 ReadWriteOnce,需要 1Gi 的空間,然后將此 PVC 定義為 name 為 emqx-data 的 volumes,并將此 volumes 掛載在 Pod 中的 /opt/emqx/data/mnesia  目錄下。

  • 部署資源:

    部署 StatefulSet 之前,需要用戶(hù)或 kubernetes 集群管理員自行創(chuàng)建存儲(chǔ)類(lèi)。

    $ kubectl apply -f statefulset.yaml
    statefulset.apps/emqx-statefulset created
    $ kubectl get pods
    NAME                 READY   STATUS    RESTARTS   AGE
    emqx-statefulset-0   1/1     Running   0          27s
    emqx-statefulset-1   1/1     Running   0          9m45s
    emqx-statefulset-2   1/1     Running   0          9m43s
    $ kubectl get pvc
    NAME                                 STATUS    VOLUME                                 CAPACITY   ACCESS MODES   STORAGECLASS   AGE
    emqx-data-emqx-statefulset-0   Bound     pvc-8094cd75-adb5-11e9-80cc-0697b59e8064   1Gi        RWO            gp2            2m11s
    emqx-data-emqx-statefulset-0   Bound     pvc-9325441d-adb5-11e9-80cc-0697b59e8064   1Gi        RWO            gp2            99s
    emqx-data-emqx-statefulset-0   Bound     pvc-ad425e9d-adb5-11e9-80cc-0697b59e8064   1Gi        RWO            gp2            56s

    輸出結(jié)果表明該 PVC 的狀態(tài)為 Bound,PVC 存儲(chǔ)已經(jīng)成功的建立了,當(dāng) Pod 被重新調(diào)度時(shí),EMQ X Broker 會(huì)讀取掛載到 PVC 中的數(shù)據(jù),從而實(shí)現(xiàn)持久化。

MQTT 快速體驗(yàn)

MQTT 在線服務(wù)器

EMQ X MQTT 物聯(lián)網(wǎng)云服務(wù) 提供了一個(gè)在線的公共 MQTT 5.0 服務(wù)器,不需要任何安裝您就可以快速開(kāi)始 MQTT 協(xié)議的學(xué)習(xí)、測(cè)試或原型制作。

該 MQTT 服務(wù)器的詳細(xì)接入信息請(qǐng)見(jiàn) EMQ 官網(wǎng)頁(yè)面: 免費(fèi)的在線 MQTT 服務(wù)器。

MQTT 在線客戶(hù)端

EMQ 也提供了支持瀏覽器訪問(wèn)的 MQTT 在線客戶(hù)端工具,該工具支持通過(guò)普通或者加密的 WebSocket 端口連接至 MQTT 服務(wù)器,同時(shí)也支持緩存連接方便下次訪問(wèn)使用。

“如何從零開(kāi)始建立EMQ X MQTT服務(wù)器的K8S集群”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識(shí)可以關(guān)注億速云網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實(shí)用文章!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI