• 需要一个kubernetes集群,集群各节点中提前准备好consul镜像【版本:1.6.0】
  • 创建k8s-consul-service.yaml服务,注意我们使用的是StatefulSet类型,所以Service中clusterIP选择为None【Headless Service】,这样StatefulSet中所有pod都可以通过DNS映射相互找到

StatefulSet

StatefulSet是为了解决有状态服务的问题(对应Deployments和ReplicaSets是为无状态服务而设计),其应用场景包括

  • 稳定的持久化存储,即Pod重新调度后还是能访问到相同的持久化数据,基于PVC来实现
  • 稳定的网络标志,即Pod重新调度后其PodName和HostName不变,基于Headless Service(即没有Cluster IP的Service)来实现
  • 有序部署,有序扩展,即Pod是有顺序的,在部署或者扩展的时候要依据定义的顺序依次依次进行(即从0到N-1,在下一个Pod运行之前所有之前的Pod必须都是Running和Ready状态),基于init containers来实现
  • 有序收缩,有序删除(即从N-1到0)

从上面的应用场景可以发现,StatefulSet由以下几个部分组成:

  • 用于定义网络标志(DNS domain)的Headless Service
  • 用于创建PersistentVolumes的volumeClaimTemplates
  • 定义具体应用的StatefulSet

StatefulSet中每个Pod的DNS格式为statefulSetName-{0..N-1}.serviceName.namespace.svc.cluster.local,其中

  • serviceName为Headless Service的名字
  • 0..N-1为Pod所在的序号,从0开始到N-1
  • statefulSetName为StatefulSet的名字
  • namespace为服务所在的namespace,Headless Servic和StatefulSet必须在相同的namespace
  • .cluster.local为Cluster Domain
apiVersion: v1
kind: Service
metadata:
  name: consul
  labels:
    name: consul
spec:
  type: ClusterIP
  clusterIP: None
  ports:
    - name: http
      port: 8500
      targetPort: 8500
    - name: https
      port: 8443
      targetPort: 8443
    - name: rpc
      port: 8400
      targetPort: 8400
    - name: serflan-tcp
      protocol: "TCP"
      port: 8301
      targetPort: 8301
    - name: serflan-udp
      protocol: "UDP"
      port: 8301
      targetPort: 8301
    - name: serfwan-tcp
      protocol: "TCP"
      port: 8302
      targetPort: 8302
    - name: serfwan-udp
      protocol: "UDP"
      port: 8302
      targetPort: 8302
    - name: server
      port: 8300
      targetPort: 8300
    - name: consuldns
      port: 8600
      targetPort: 8600
  selector:
    app: consul
  • 创建k8s-consul-statefulset.yaml

注意其中-retry-join=consul-0.consul.$(NAMESPACE).svc.cluster.local就是基于StatefulSet特性

apiVersion: apps/v1beta1
kind: StatefulSet
metadata:
  name: consul
spec:
  serviceName: consul
  replicas: 3
  template:
    metadata:
      labels:
        app: consul
        component: server
    spec:
      serviceAccountName: consul
      terminationGracePeriodSeconds: 10
      containers:
      - name: consul
        image: consul:1.6.0
        args:
          - "agent"
          - "-server"
          - "-bootstrap-expect=3"
          - "-ui"
          - "-data-dir=/consul/data"
          - "-bind=0.0.0.0"
          - "-client=0.0.0.0"
          - "-advertise=$(PODIP)"
          - "-retry-join=consul-0.consul.$(NAMESPACE).svc.cluster.local"
          - "-retry-join=consul-1.consul.$(NAMESPACE).svc.cluster.local"
          - "-retry-join=consul-2.consul.$(NAMESPACE).svc.cluster.local"
          - "-domain=cluster.local"
          - "-disable-host-node-id"
        volumeMounts:
          - name: data
            mountPath: /consul/data
        env:
          - name: PODIP
            valueFrom:
              fieldRef:
                fieldPath: status.podIP
          - name: NAMESPACE
            valueFrom:
              fieldRef:
                fieldPath: metadata.namespace
        ports:
          - containerPort: 8500
            name: ui-port
          - containerPort: 8400
            name: alt-port
          - containerPort: 53
            name: udp-port
          - containerPort: 8443
            name: https-port
          - containerPort: 8080
            name: http-port
          - containerPort: 8301
            name: serflan
          - containerPort: 8302
            name: serfwan
          - containerPort: 8600
            name: consuldns
          - containerPort: 8300
            name: server
      volumes:
        - name: data
          hostPath:
            path: /root/consul/data

*************测试一下******************:

第一步:使用命令代创建主机端口映射

[root@k8s-master ~]# kubectl port-forward consul-0 8500:8500
Forwarding from 127.0.0.1:8500 -> 8500
Forwarding from [::1]:8500 -> 8500

第二步:注意这个8500地址只能本机访问,使用curl命令继续测试

[root@k8s-master ~]# curl 127.0.0.1:8500
<a href="/ui/">Moved Permanently</a>.

不用担心,以上结果是正确的,因为通过浏览器访问的话,127.0.0.1:8500会自动跳转到http://127.0.0.1:8500/ui/dc1/services默认ui展示界面,由于curl无法模拟浏览器交互跳转行为,因此显示以上内容永久重定向.

  • 创建nginx-ingress代理,供外部访问,创建k8s-consul-nginx-ingress.yaml

注意其中的域名consul.deri.com,访问的机器hosts中需要加入IP 域名 之后才能访问!

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: ingress-consul
  namespace: default
  annotations:
    kubernets.io/ingress.class: "nginx"
spec:
  rules:
  - host: consul.deri.com
    http:
      paths:
      - path:
        backend:
          serviceName: consul
          servicePort: 8500

  • 遇到的问题

问题一:

[WARN] memberlist: Failed to resolve consul-2.consul.default.svc.cluster.local: lookup consul-2.consul.default.svc.cluster.local on 10.96.0.10:53: no such host

这是DNS解析出现问题,排除CoreDNS状态,通过nslookup命令测试,发现并无问题。

解决办法:

使用命令kubectl delete pod consul-0 consul-1 consul-2删除创建StatefulSet时自动创建的pod,让k8s自动再创建新的consul-0 consul-1 consul-2 pod,发现问题不见了,猜测原因可能是部署k8s的宿主机性能太差,DNS服务处理太慢导致。

Logo

开源、云原生的融合云平台

更多推荐