共计 5449 个字符,预计需要花费 14 分钟才能阅读完成。
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.pem | |
ca.pem | |
consul-key.pem | |
consul.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: v1 | |
kind: Service | |
metadata: | |
name: consul | |
namespace: discovery | |
labels: | |
name: consul | |
spec: | |
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: v1 | |
kind: ServiceAccount | |
metadata: | |
name: consul | |
namespace: discovery | |
labels: | |
app: consul | |
--- | |
apiVersion: rbac.authorization.k8s.io/v1 | |
kind: ClusterRole | |
metadata: | |
name: consul | |
labels: | |
app: consul | |
rules: | |
- apiGroups: [""] | |
resources: | |
- pods | |
verbs: | |
- get | |
- list | |
--- | |
apiVersion: rbac.authorization.k8s.io/v1 | |
kind: ClusterRoleBinding | |
metadata: | |
name: consul | |
roleRef: | |
apiGroup: rbac.authorization.k8s.io | |
kind: ClusterRole | |
name: consul | |
subjects: | |
- kind: ServiceAccount | |
name: consul | |
namespace: discovery |
创建 Consul StatefulSet
apiVersion: apps/v1 | |
kind: StatefulSet | |
metadata: | |
name: consul | |
namespace: discovery | |
spec: | |
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=consul | |
NAME READY STATUS RESTARTS AGE | |
consul-0 1/1 Running 0 13h | |
consul-1 1/1 Running 0 13h | |
consul-2 1/1 Running 0 13h |
验证
通过访问 UI,可以看到我们的三个实例均已成功加入集群,并且选举成功。
正文完