传统上,Kubernetes使用Ingress
控制器来处理从外部进入集群的流量。使用Istio时,情况不再如此。 Istio已用新的Gateway
和VirtualServices
资源替换了熟悉的Ingress
资源。它们协同工作,将流量路由到网格中。在网格内部,不需要Gateway
,因为服务可以通过集群本地服务名称相互访问。
正如我之前文章介绍过的,kubernetes提供的Ingress过于简单,暴露出来的属性表达性太弱。当然社区也意识到了这个问题,从kubernetes1.19 版本,在逐步补全功能。Istio解决方案中,自己实现了Istio gateway。在非istio场景外,gloo,ambasaador ,contour等网关 可以满足我们生产环境的需求。
部署
我们看下社区默认的部署。
通过Deployment管理的一组istio-ingressgateway
Pod。
IngressGateway,这是Envoy代理的封装。它的配置方式与服务网格中使用的Sidecar相同。当我们创建或更改Gateway或VirtualService时,Istio Pilot控制器会检测到更改,该控制器会将这些信息转换为Envoy配置并将其发送到相关代理,包括IngressGateway内部的Envoy。
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: istio-ingressgateway
istio: ingressgateway
release: istio
name: istio-ingressgateway
namespace: istio-system
spec:
selector:
matchLabels:
app: istio-ingressgateway
istio: ingressgateway
strategy:
rollingUpdate:
maxSurge: 100%
maxUnavailable: 25%
template:
metadata:
annotations:
prometheus.io/path: /stats/prometheus
prometheus.io/port: "15090"
prometheus.io/scrape: "true"
sidecar.istio.io/inject: "false"
labels:
app: istio-ingressgateway
chart: gateways
heritage: Tiller
istio: ingressgateway
release: istio
service.istio.io/canonical-name: istio-ingressgateway
service.istio.io/canonical-revision: latest
spec:
affinity:
nodeAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- preference:
matchExpressions:
- key: kubernetes.io/arch
operator: In
values:
- amd64
weight: 2
- preference:
matchExpressions:
- key: kubernetes.io/arch
operator: In
values:
- ppc64le
weight: 2
- preference:
matchExpressions:
- key: kubernetes.io/arch
operator: In
values:
- s390x
weight: 2
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/arch
operator: In
values:
- amd64
- ppc64le
- s390x
containers:
- args:
- proxy
- router
- --domain
- $(POD_NAMESPACE).svc.cluster.local
- --proxyLogLevel=warning
- --proxyComponentLogLevel=misc:error
- --log_output_level=default:info
- --serviceCluster
- istio-ingressgateway
- --trust-domain=cluster.local
env:
- name: JWT_POLICY
value: third-party-jwt
- name: PILOT_CERT_PROVIDER
value: istiod
- name: CA_ADDR
value: istiod.istio-system.svc:15012
- name: NODE_NAME
valueFrom:
fieldRef:
apiVersion: v1
fieldPath: spec.nodeName
- name: POD_NAME
valueFrom:
fieldRef:
apiVersion: v1
fieldPath: metadata.name
- name: POD_NAMESPACE
valueFrom:
fieldRef:
apiVersion: v1
fieldPath: metadata.namespace
- name: INSTANCE_IP
valueFrom:
fieldRef:
apiVersion: v1
fieldPath: status.podIP
- name: HOST_IP
valueFrom:
fieldRef:
apiVersion: v1
fieldPath: status.hostIP
- name: SERVICE_ACCOUNT
valueFrom:
fieldRef:
fieldPath: spec.serviceAccountName
- name: CANONICAL_SERVICE
valueFrom:
fieldRef:
fieldPath: metadata.labels['service.istio.io/canonical-name']
- name: CANONICAL_REVISION
valueFrom:
fieldRef:
fieldPath: metadata.labels['service.istio.io/canonical-revision']
- name: ISTIO_META_WORKLOAD_NAME
value: istio-ingressgateway
- name: ISTIO_META_OWNER
value: kubernetes://apis/apps/v1/namespaces/istio-system/deployments/istio-ingressgateway
- name: ISTIO_META_MESH_ID
value: cluster.local
- name: ISTIO_META_ROUTER_MODE
value: sni-dnat
- name: ISTIO_META_CLUSTER_ID
value: Kubernetes
image: docker.io/istio/proxyv2:1.7.3
name: istio-proxy
ports:
- containerPort: 15021
- containerPort: 8080
- containerPort: 8443
- containerPort: 15443
- containerPort: 15090
name: http-envoy-prom
protocol: TCP
readinessProbe:
failureThreshold: 30
httpGet:
path: /healthz/ready
port: 15021
scheme: HTTP
initialDelaySeconds: 1
periodSeconds: 2
successThreshold: 1
timeoutSeconds: 1
resources:
limits:
cpu: 2000m
memory: 1024Mi
requests:
cpu: 100m
memory: 128Mi
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
privileged: false
readOnlyRootFilesystem: true
volumeMounts:
- mountPath: /etc/istio/proxy
name: istio-envoy
- mountPath: /etc/istio/config
name: config-volume
- mountPath: /var/run/secrets/istio
name: istiod-ca-cert
- mountPath: /var/run/secrets/tokens
name: istio-token
readOnly: true
- mountPath: /var/run/ingress_gateway
name: gatewaysdsudspath
- mountPath: /etc/istio/pod
name: podinfo
- mountPath: /etc/istio/ingressgateway-certs
name: ingressgateway-certs
readOnly: true
- mountPath: /etc/istio/ingressgateway-ca-certs
name: ingressgateway-ca-certs
readOnly: true
securityContext:
fsGroup: 1337
runAsGroup: 1337
runAsNonRoot: true
runAsUser: 1337
serviceAccountName: istio-ingressgateway-service-account
volumes:
- configMap:
name: istio-ca-root-cert
name: istiod-ca-cert
- downwardAPI:
items:
- fieldRef:
fieldPath: metadata.labels
path: labels
- fieldRef:
fieldPath: metadata.annotations
path: annotations
name: podinfo
- emptyDir: {}
name: istio-envoy
- emptyDir: {}
name: gatewaysdsudspath
- name: istio-token
projected:
sources:
- serviceAccountToken:
audience: istio-ca
expirationSeconds: 43200
path: istio-token
- configMap:
name: istio
optional: true
name: config-volume
- name: ingressgateway-certs
secret:
optional: true
secretName: istio-ingressgateway-certs
- name: ingressgateway-ca-certs
secret:
optional: true
secretName: istio-ingressgateway-ca-certs
我们在IngressGateway部署中必须关心的是SSL证书。为了能够访问gateway资源中的证书,请确保已正确安装了证书。
volumeMounts:
- mountPath: /etc/istio/ingressgateway-certs
name: ingressgateway-certs
readOnly: true
- mountPath: /etc/istio/ingressgateway-ca-certs
name: ingressgateway-ca-certs
readOnly: true
volumes:
- name: ingressgateway-certs
secret:
optional: true
secretName: istio-ingressgateway-certs
- name: ingressgateway-ca-certs
secret:
optional: true
secretName: istio-ingressgateway-ca-certs
由于istio-ingressgateway
主要处理边界流量,所以必须创建LoadBalancer类型的service,所有外部流量都通过此云负载均衡器进入集群,该负载均衡器将流量路由到istio-ingressgateway
的envoy容器。
apiVersion: v1
kind: Service
metadata:
labels:
app: istio-ingressgateway
istio: ingressgateway
release: istio
name: istio-ingressgateway
namespace: istio-system
spec:
ports:
- name: status-port
port: 15021
targetPort: 15021
- name: http2
port: 80
targetPort: 8080
- name: https
port: 443
targetPort: 8443
- name: tls
port: 15443
targetPort: 15443
selector:
app: istio-ingressgateway
istio: ingressgateway
type: LoadBalancer
出于性能考虑,我们应该讲.spec.externalTrafficPolicy设置为local模式,避免二跳。
其他包括HPA,PDB以及RBAC等资源。
单集群多Gateway
有时创建多个ingress gateway也很有用。例如,在一个非常大的集群中,有成千上万的服务,您可能不想通过一个云负载均衡器和一个部署来驱动所有外部流量,但希望水平分担负载。
部署多个Gateway,比较简单,参照上一步部署,注意更改一下命名,复制多个部署即可。
那我们如何选择ingress gateway那?通过selector选择。如下:
metadata:
name: gateway
spec:
selector:
istio: second-istio-ingressgateway
配置
Ingress Gateway 不包含任何流量路由配置。Ingress 流量的路由使用 Istio 路由规则来配置,和内部服务请求完全一样。
让我们一起来看如何为 HTTP 流量在 80 端口上配置 Gateway
。
- 创建 Istio
Gateway
:
$ kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: httpbin-gateway
spec:
selector:
istio: ingressgateway # use Istio default gateway implementation
servers:
- port:
number: 80
name: http
protocol: HTTP
hosts:
- "httpbin.example.com"
EOF
- 为通过
Gateway
的入口流量配置路由:
$ kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: httpbin
spec:
hosts:
- "httpbin.example.com"
gateways:
- httpbin-gateway
http:
- match:
- uri:
prefix: /status
- uri:
prefix: /delay
route:
- destination:
port:
number: 8000
host: httpbin
EOF
已为 httpbin
服务创建了虚拟服务配置,包含两个路由规则,允许流量流向路径 /status
和 /delay
。
gateways 列表规约了哪些请求允许通过 httpbin-gateway
网关。 所有其他外部请求均被拒绝并返回 404 响应。
安全性
使用 SDS 为 Gateway 提供 HTTPS 加密支持
可以配置 TLS Ingress Gateway ,让它从 Ingress Gateway 代理通过 SDS 获取凭据。Ingress Gateway 代理和 Ingress Gateway 在同一个 Pod 中运行,监视 Ingress Gateway 所在命名空间中新建的 Secret
。在 Ingress Gateway 中启用 SDS 具有如下好处:
- Ingress Gateway 无需重启,就可以动态的新增、删除或者更新密钥/证书对以及根证书。
- 无需加载
Secret
卷。创建了kubernetes
`Secret之后,这个
Secret` 就会被 Gateway 代理捕获,并以密钥/证书对和根证书的形式发送给 Ingress Gateway 。 - Gateway 代理能够监视多个密钥/证书对。只需要为每个主机名创建
Secret
并更新 Gateway 定义就可以了。
无 TLS 终止的 Ingress Gateway
配置 Ingress Gateway 以执行 SNI 透传,而不是对传入请求进行 TLS 终止。例如:
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: mygateway
spec:
selector:
istio: ingressgateway # use istio default ingress gateway
servers:
- port:
number: 443
name: https
protocol: HTTPS
tls:
mode: PASSTHROUGH
hosts:
- nginx.example.com