consul 发展到今日,早已不是只用于服务发现和配置共享的工具了。官方对其的定义是自动化网络配置,发现服务并启用跨任何云或运行时的安全连接。
特性
- 与Kubernetes集成和扩展。利用Helm在Kubernetes上快速部署Consul。自动为Kubernetes资源注入sidecar。将多个集群联合到一个服务网格中。
- 跨任何运行时的服务网格。在任何运行时或基础架构中跨任何云在裸机,虚拟机和Kubernetes集群中部署服务网格。
- 动态的负载均衡。通过集成的DNS解决发现的服务。自动化第三方负载均衡器(F5,NGINX,HAProxy)。无需手动配置网络设备。
- 安全的多云服务网络。利用访问策略和服务网格资源之间的自动mTLS加密,在任何环境中运行的安全服务。
- 通过运行状况检查发现服务。Consul支持检测新服务的部署,对现有服务的更改,并提供实时代理运行状况以减少停机时间。
- 强大的生态系统。Consul为许多流行的DevOps和网络工具提供支持并与之集成。
默认端口
consul 默认使用下列端口
- 8300(tcp): Server RPC,server 用于接受其他 agent 的请求
- 8301(tcp,udp): Serf LAN,数据中心内 gossip 交换数据用
- 8302(tcp,udp): Serf WAN,跨数据中心 gossip 交换数据用
- 8400(tcp): CLI RPC,接受命令行的 RPC 调用
- 8500(tcp): HTTP API 及 Web UI
- 8600(tcp udp): DNS 服务,可以把它配置到 53 端口来响应 dns 请求
部署
官方推荐的helm部署方案,包括了诸多解决方案。当我们只是用来做服务发现或是配置中心的时候,我们可以选择yaml部署。
本文将完成在Kubernetes上部署三(3)节点Consul集群。
- 使用StatefulSet的三(3)个节点Consul群集
- 使用TLS和加密密钥的Consul成员之间的安全通信
生成 TLS Certificates
新建ca目录,包含以下三个文件:
ca-config.json
{ "signing": { "default": { "expiry": "43800h" }, "profiles": { "default": { "usages": ["signing", "key encipherment", "server auth", "client auth"], "expiry": "43800h" } } }}
ca-csr.json
{ "hosts": [ "cluster.consul" ], "key": { "algo": "rsa", "size": 2048 }, "names": [ { "C": "US", "L": "Portland", "O": "Kubernetes", "OU": "CA", "ST": "Oregon" } ]}
consul-csr.json
{ "CN": "server.dc1.cluster.consul", "hosts": [ "server.dc1.cluster.consul", "127.0.0.1" ], "key": { "algo": "rsa", "size": 2048 }, "names": [ { "C": "US", "L": "Portland", "O": "Hightower Labs", "OU": "Consul", "ST": "Oregon" } ]}
Consul成员之间的RPC通信将使用TLS进行加密。初始化证书颁发机构(CA):
cfssl gencert -initca ca/ca-csr.json | cfssljson -bare ca
创建Consul TLS证书和私钥:
cfssl gencert \ -ca=ca.pem \ -ca-key=ca-key.pem \ -config=ca/ca-config.json \ -profile=default \ ca/consul-csr.json | cfssljson -bare consul
此时,您应该在当前工作目录中具有以下文件:
ca-key.pemca.pemconsul-key.pemconsul.pem
生成 Consul Gossip Encryption Key
Consul成员之间的Gossip通信将使用共享的加密密钥进行加密。生成并存储加密密钥:
GOSSIP_ENCRYPTION_KEY=$(consul keygen)
创建 Consul Secret 和 Configmap
Consul集群将使用CLI标志,TLS证书和配置文件的组合进行配置,这些文件引用Kubernetes configmap和secret。
将Gossip加密密钥和TLS证书存储在密钥中:
kubectl create secret generic consul -n discovery \ --from-literal="gossip-encryption-key=${GOSSIP_ENCRYPTION_KEY}" \ --from-file=ca.pem \ --from-file=consul.pem \ --from-file=consul-key.pem
将Consul服务器配置文件存储在ConfigMap中:
kubectl create configmap consul -n discovery --from-file=server.json
而server.json文件如下:
{ "bind_addr": "0.0.0.0", "ca_file": "/etc/tls/ca.pem", "cert_file": "/etc/tls/consul.pem", "client_addr": "0.0.0.0", "disable_host_node_id": true, "data_dir": "/consul/data", "datacenter": "dc1", "domain": "cluster.consul", "key_file": "/etc/tls/consul-key.pem", "ports": { "https": 8443 }, "retry_join": [ "provider=k8s namespace=discovery label_selector=\"app=consul,component=server\"" ], "server": true, "telemetry": { "prometheus_retention_time": "5m" }, "verify_incoming": true, "verify_outgoing": true, "verify_server_hostname": true, "ui": true}
创建 Consul Service
apiVersion: v1kind: Servicemetadata: name: consul namespace: discovery labels: name: consulspec: clusterIP: None ports: - name: http port: 8500 targetPort: 8500 - name: cli-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: agent-rpc port: 8300 targetPort: 8300 - name: dns port: 8600 targetPort: 8600 selector: app: consul
创建 Consul Service Account
由于我们retry_join 使用的是k8s provider,所有必须要配置rbac。给与获取pod的权限。
apiVersion: v1kind: ServiceAccountmetadata: name: consul namespace: discovery labels: app: consul---apiVersion: rbac.authorization.k8s.io/v1kind: ClusterRolemetadata: name: consul labels: app: consulrules: - apiGroups: [""] resources: - pods verbs: - get - list---apiVersion: rbac.authorization.k8s.io/v1kind: ClusterRoleBindingmetadata: name: consulroleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: consulsubjects: - kind: ServiceAccount name: consul namespace: discovery
创建 Consul StatefulSet
apiVersion: apps/v1kind: StatefulSetmetadata: name: consul namespace: discoveryspec: selector: matchLabels: app: consul component: server serviceName: consul podManagementPolicy: "Parallel" replicas: 3 template: metadata: labels: app: consul component: server annotations: consul.hashicorp.com/connect-inject: "false" spec: serviceAccountName: consul affinity: podAntiAffinity: requiredDuringSchedulingIgnoredDuringExecution: - labelSelector: matchExpressions: - key: app operator: In values: - consul topologyKey: kubernetes.io/hostname terminationGracePeriodSeconds: 10 securityContext: fsGroup: 1000 containers: - name: consul image: "consul:1.7.3" env: - name: POD_IP valueFrom: fieldRef: fieldPath: status.podIP - name: GOSSIP_ENCRYPTION_KEY valueFrom: secretKeyRef: name: consul key: gossip-encryption-key args: - "agent" - "-advertise=$(POD_IP)" - "-bootstrap-expect=3" - "-config-file=/etc/consul/config/server.json" - "-encrypt=$(GOSSIP_ENCRYPTION_KEY)" volumeMounts: - name: data mountPath: /consul/data - name: config mountPath: /etc/consul/config - name: tls mountPath: /etc/tls lifecycle: preStop: exec: command: - /bin/sh - -c - consul leave ports: - containerPort: 8500 name: ui-port - containerPort: 8400 name: cli-port - containerPort: 8301 name: serflan - containerPort: 8302 name: serfwan - containerPort: 8600 name: dns - containerPort: 8300 name: server volumes: - name: config configMap: name: consul - name: tls secret: secretName: consul volumeClaimTemplates: - metadata: name: data namespace: discovery annotations: everest.io/disk-volume-type: SAS spec: accessModes: - ReadWriteOnce resources: requests: storage: 10Gi storageClassName: csi-disk-topology
由于我的安装是在华为云上,所以如果是其他公有云或是其他存储,注意替换volumeClaimTemplates。
查看安装情况:
kubectl get pods -n discovery -l app=consulNAME READY STATUS RESTARTS AGEconsul-0 1/1 Running 0 13hconsul-1 1/1 Running 0 13hconsul-2 1/1 Running 0 13h
验证
通过访问UI,可以看到我们的三个实例均已成功加入集群,并且选举成功。