Skip to main content

Consule Connect Mesh

  • 优势
    • mesh gateway 打通集群
    • ingress gateway 允许外部访问内部服务
    • terminating gateway 允许内部 mtls 访问外部服务
    • 支持代码层集成 - 提供 Go SDK
    • 连通性好
    • 支持 7 层路由
    • 没有集成 prometheus 和 grafana - 更适合利用现有实例
  • 劣势
    • 需要两个 sidecard
      • consul-connect-inject-init
      • consul-connect-envoy-sidecar
      • consul-connect-lifecycle-sidecar
    • connect 主要 支持连通性,跟踪和指标都没有支持
    • 界面功能较弱
    • 流量切分实例分组需要配置,没有界面
    • observability 和 指标都依赖 envoy - 没有默认配置
  • 特性
    • mtls
    • intention - Service-to-Service 权限
      • consul intention create -deny web '*'
    • 自动注入
      • consul.hashicorp.com/connect-inject: 'true'
  • Control Plane
    • Consul UI
  • Data Plane
    • 内建 - 主要用于开发
    • envoy
  • 注意
    • 必须配合 consule 使用
  • Mesh Gateway
    • 网关互通 - 跨集群/区域
    • 服务到服务
  • Ingress Gateway
    • 接受外部流量
    • 外部访问内部服务
  • Terminating Gateway
    • 内部访问外部
  • Intention - ACL 控制
  • 代理
    • 内建 - 不适用于生产
    • Envoy
  • 证书管理
    • 内建 CA
    • Vault
  • 参考
kubectl port-forward service/consul-server 8500:8500
# tls
# kubectl port-forward service/consul-server 8501:8501

# token
export CONSUL_HTTP_TOKEN=$(kubectl get secrets/consul-bootstrap-acl-token --template={{.data.token}} | base64 -d)
consul info

# in pod
export CONSUL_HTTP_ADDR="${HOST_IP}:8500"

# 命令行启动
# -- -l trace - envoy 的 trace 日志
consul connect envoy \
-sidecar-for echo -http-addr http://127.0.0.1:8500 \
-grpc-addr http://127.0.0.1:8502 \
-admin-bind 127.0.0.1:0

annotations

  • consul.hashicorp.com/connect-inject
    • bool
    • 是否注入 sidecard
  • consul.hashicorp.com/connect-service
    • 服务的名字
    • 默认为第一个 container 的名字
    • 如果启用了 acl,名字必须与 ServiceAccount 相同
  • consul.hashicorp.com/connect-service-port
    • 接受请求的端口
    • 默认为第一个暴露端口
    • 可以是名字也可以是端口号
    • proxy 监听动态端口
  • consul.hashicorp.com/connect-service-upstreams
    • 连接到的上游服务
    • 逗号分割指定多个
    • [service-name]:[port]:[optional datacenter]
    • prepared_query:[query name]:[port]
  • consul.hashicorp.com/connect-service-protocol
    • 注册协议
    • helm 安装时使用 defaultProtocol 指定默认协议
      • 建议指定为 http
  • consul.hashicorp.com/service-tags
    • 逗号分割指定多个
  • consul.hashicorp.com/service-meta-<KEY>
  • consul.hashicorp.com/sidecar-proxy- - proxy 配置
    • cpu/memory-limit/request
    • helm 默认配置 connectInject.sidecarProxy.resources

k8s

apiVersion: v1
kind: ServiceAccount
metadata:
name: alpine-connect
---
apiVersion: v1
kind: Pod
metadata:
name: alpine-connect
annotations:
consul.hashicorp.com/connect-inject: 'true'
consul.hashicorp.com/connect-service-upstreams: consul:8500,static-server:1234,web-test:2019,whoami-v1:1992
spec:
serviceAccountName: alpine-connect
containers:
- name: alpine-connect
image: wener/base
command:
- tail
args:
- -f
- /dev/null
kubectl exec alpine-connect -it -c alpine-connect -- sh
apiVersion: v1
kind: ServiceAccount
metadata:
name: static-server
---
apiVersion: v1
kind: Pod
metadata:
name: static-server
annotations:
consul.hashicorp.com/connect-inject: 'true'
spec:
containers:
# consule 中的服务名
- name: static-server
image: hashicorp/http-echo:latest
args:
- -text="hello world"
- -listen=:8080
ports:
- containerPort: 8080
name: http
# 如果启用了 ACL, serviceAccountName 必须要匹配 Consil 中的服务名
serviceAccountName: static-server
apiVersion: v1
kind: ServiceAccount
metadata:
name: static-client
---
apiVersion: v1
kind: Pod
metadata:
name: static-client
annotations:
'consul.hashicorp.com/connect-inject': 'true'
'consul.hashicorp.com/connect-service-upstreams': 'static-server:1234'
spec:
containers:
# 服务名
- name: static-client
image: tutum/curl:latest
# 保持运行
command: ['/bin/sh', '-c', '--']
args: ['while true; do sleep 30; done;']
# ACL 要求
serviceAccountName: static-client
apiVersion: v1
kind: ServiceAccount
metadata:
name: web-test
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-test
labels:
app: web-test
spec:
replicas: 3
selector:
matchLabels:
app: web-test
template:
metadata:
name: web-test
labels:
app: web-test
annotations:
consul.hashicorp.com/connect-service-upstreams: 'static-server:1234'
consul.hashicorp.com/connect-inject: 'true'
spec:
containers:
- name: web-test
image: nginx:alpine
ports:
- containerPort: 80
serviceAccountName: web-test
apiVersion: v1
kind: ServiceAccount
metadata:
name: static-server-next
---
apiVersion: v1
kind: Pod
metadata:
name: static-server-next
annotations:
consul.hashicorp.com/connect-inject: 'true'
spec:
containers:
- name: static-server-next
image: hashicorp/http-echo:latest
args:
- -text="hello world"
- -listen=:8080
ports:
- containerPort: 8080
name: http
serviceAccountName: static-server-next
cat << HCL | consul config write -
Kind = "service-defaults"
Name = "static-server"
Protocol = "http"
HCL
cat << HCL | consul config write -
Kind = "service-defaults"
Name = "static-server-next"
Protocol = "http"
HCL
cat << HCL | consul config write -
Kind = "service-router"
Name = "static-server"
Routes = [
{
Match {
HTTP {
PathPrefix = "/next"
}
}

Destination {
Service = "static-server-next"
}
},
]
HCL

whomai

apiVersion: v1
kind: ServiceAccount
metadata:
name: whoami
---
kind: Deployment
apiVersion: apps/v1
metadata:
name: whoami-v1
labels:
app: whoami-v1
spec:
replicas: 2
selector:
matchLabels:
app: whoami-v1
template:
metadata:
labels:
app: whoami-v1
annotations:
consul.hashicorp.com/connect-inject: 'true'
consul.hashicorp.com/connect-service-protocol: http
consul.hashicorp.com/service-tags: app=whoami
consul.hashicorp.com/service-meta-version: v1
spec:
serviceAccountName: whoami
containers:
- name: whoami
image: containous/whoami
# diff
env:
- name: WHOAMI_NAME
value: V1
ports:
- containerPort: 80
livenessProbe:
httpGet:
path: /health
port: 80
initialDelaySeconds: 3
periodSeconds: 3
---
kind: Deployment
apiVersion: apps/v1
metadata:
name: whoami-v2
labels:
app: whoami-v2
spec:
replicas: 2
selector:
matchLabels:
app: whoami-v2
template:
metadata:
labels:
app: whoami-v2
annotations:
consul.hashicorp.com/connect-inject: 'true'
consul.hashicorp.com/connect-service-protocol: http
consul.hashicorp.com/service-tags: app=whoami
consul.hashicorp.com/service-meta-version: v2
spec:
# same service
serviceAccountName: whoami
containers:
- name: whoami
image: containous/whoami
# diff
env:
- name: WHOAMI_NAME
value: V2
ports:
- containerPort: 80
livenessProbe:
httpGet:
path: /health
port: 80
initialDelaySeconds: 3
periodSeconds: 3
cat << HCL | consul config write -
Kind = "service-defaults"
Name = "whoami"
Protocol = "http"
Expose = {
Checks = true
Paths = [{
Path = "/health"
}]
}
HCL
cat << HCL | consul config write -
Kind = "service-resolver"
Name = "whoami"
DefaultSubset = "v2"
Subsets = {
"v1" = {
Filter = "Service.Meta.version == v1"
}
"v2" = {
Filter = "Service.Meta.version == v2"
}
}
HCL

cat << HCL | consul config write -
Kind = "service-router"
Name = "whoami"
Routes = [
{
Match {
HTTP {
Header = [
{
Name = "x-version"
Exact = "2"
},
]
}
}
Destination {
Service = "whoami"
ServiceSubset = "v2"
}
},
{
Match {
HTTP {
PathPrefix = "/v2"
}
}
Destination {
Service = "whoami"
ServiceSubset = "v2"
}
},

{
Match {
HTTP {
Header = [
{
Name = "x-version"
Exact = "1"
},
]
}
}
Destination {
Service = "whoami"
ServiceSubset = "v1"
}
},
{
Match {
HTTP {
PathPrefix = "/v1"
}
}
Destination {
Service = "whoami"
ServiceSubset = "v1"
}
},
]
HCL

分组

Kind          = "service-resolver"
Name = "whoami"
DefaultSubset = "v1"
Subsets = {
"v1" = {
Filter = "Service.Meta.version == v1"
}
"v2" = {
Filter = "Service.Meta.version == v2"
}
}

流量切分

Kind = "service-splitter"
Name = "web"
Splits = [
{
Weight = 90
ServiceSubset = "v1"
},
{
Weight = 10
ServiceSubset = "v2"
},
]