本文档介绍了如何在 Google Distributed Cloud 的用户集群中创建 Kubernetes Ingress 对象。一个 Ingress 与一个或多个 Service 相关联,每个 Service 与一组 Pod 相关联。
准备工作
与管理员工作站建立 SSH 连接:
创建 Deployment
以下是 Deployment 的清单。
apiVersion: apps/v1
kind: Deployment
metadata:
name: hello-deployment
spec:
selector:
matchLabels:
greeting: hello
replicas: 3
template:
metadata:
labels:
greeting: hello
spec:
containers:
- name: hello-world
image: "gcr.io/google-samples/hello-app:2.0"
env:
- name: "PORT"
value: "50000"
- name: hello-kubernetes
image: "gcr.io/google-samples/node-hello:1.0"
env:
- name: "PORT"
value: "8080"
在本练习中,您需要了解 Deployment 清单的以下要点:
属于 Deployment 的每个 Pod 都具有
greeting: hello标签。每个 Pod 都有两个容器。
env字段指定hello-app容器侦听 TCP 端口 50000,node-hello容器侦听 TCP 端口 8080。对于hello-app,您可以通过查看 hello-app 源代码来了解PORT环境变量的效果。
将此清单复制到名为 hello-deployment.yaml 的文件,然后创建该 Deployment:
kubectl apply --kubeconfig USER_CLUSTER_KUBECONFIG -f hello-deployment.yaml
其中,USER_CLUSTER_KUBECONFIG 是用户集群的 kubeconfig 文件的路径。
使用 Service 公开 Deployment
要为客户端提供稳定的方法来向 Deployment 的 Pod 发送请求,请创建一个 Service。
以下是将 Deployment 公开给集群内的客户端的 Service 的清单:
apiVersion: v1
kind: Service
metadata:
name: hello-service
spec:
type: ClusterIP
selector:
greeting: hello
ports:
- name: world-port
protocol: TCP
port: 60000
targetPort: 50000
- name: kubernetes-port
protocol: TCP
port: 60001
targetPort: 8080
将此清单复制到名为 hello-service.yaml 的文件,然后创建该 Service:
kubectl apply --kubeconfig USER_CLUSTER_KUBECONFIG -f hello-service.yaml
查看 Service:
kubectl --kubeconfig USER_CLUSTER_KUBECONFIG get service hello-service --output yaml
输出显示已提供给 Service 的 clusterIP 值。例如:
apiVersion: v1
kind: Service
metadata:
annotations:
...
spec:
clusterIP: 10.96.14.249
clusterIPs:
- 10.96.14.249
ipFamilies:
- IPv4
ipFamilyPolicy: SingleStack
ports:
- name: world-port
port: 60000
protocol: TCP
targetPort: 50000
- name: kubernetes-port
port: 60001
protocol: TCP
targetPort: 8080
selector:
greeting: hello
sessionAffinity: None
type: ClusterIP
status:
loadBalancer: {}
在上面的输出中,ports 字段是 Kubernetes ServicePort 对象数组:一个对象名为 world-port,一个对象名为 kubernetes-port。
以下是客户端调用 Service 的方式:
使用
world-port:在其中一个集群节点上运行的客户端会向port上的clusterIP发送请求。在此示例中为 10.96.14.249:60000。该请求将被转发到targetPort上的成员 Pod。在此示例中为 POD_IP_ADDRESS:50000。使用
kubernetes-port:在其中一个集群节点上运行的客户端会向port上的clusterIP发送请求。在此示例中为 10.96.14.249:60001。该请求将被转发到targetPort上的成员 Pod。在此示例中为 POD_IP_ADDRESS:8080。
Ingress 组件
以下是与 Ingress 相关的一些集群组件:
istio-ingressDeployment。这是 Ingress 代理。Ingress 代理会根据 Ingress 对象中指定的规则将流量转发到内部 Service。istio-ingressService。此 Service 会公开istio-ingressDeployment。istiodDeployment。这是 Ingress 控制器。Ingress 控制器会监视 Ingress 对象的创建,并相应地配置 Ingress 代理。
创建 Ingress
以下是 Ingress 的清单:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: my-ingress
spec:
rules:
- http:
paths:
- path: /greet-the-world
pathType: Exact
backend:
service:
name: hello-service
port:
number: 60000
- path: /greet-kubernetes
pathType: Exact
backend:
service:
name: hello-service
port:
number: 60001
将此清单复制到名为 my-ingress.yaml 的文件,然后创建该 Ingress:
kubectl apply --kubeconfig USER_CLUSTER_KUBECONFIG -f my-ingress.yaml
创建用户集群时,您需要在集群配置文件中指定 loadbalancer.ingressVip 值。此 IP 地址是在集群负载均衡器上配置的。创建 Ingress 时,Ingress 会获得与其外部 IP 地址相同的 VIP 地址。
当客户端向您的用户集群 Ingress VIP 地址发送请求时,请求将路由到您的负载均衡器。负载均衡器使用 istio-ingress Service 将请求转发到在用户集群中运行的 Ingress 代理。该 Ingress 代理配置为根据请求网址中的路径将请求转发到不同的后端。
/greet-the-world 路径
Ingress 清单中有一条规则指出,/greet-the-world 路径与 serviceName: hello-service 和 servicePort: 60000 相关联。您应该还记得,60000 是 hello-service Service 的 world-port 部分中的 port 值。
- name: world-port
port: 60000
protocol: TCP
targetPort: 50000
Ingress Service 将请求转发到 clusterIP:50000。然后,请求会转到 hello-service Service 的一个成员 Pod。该 Pod 中侦听端口 50000 的容器会显示 Hello World! 消息。
/greet-kubernetes 路径
Ingress 清单中有一条规则指出,/greet-kubernetes 路径与 serviceName: hello-service 和 servicePort: 60001 相关联。您应该还记得,60001 是 hello-service Service 的 kubernetes-port 部分中的 port 值。
- name: kubernetes-port
port: 60001
protocol: TCP
targetPort: 8080
Ingress Service 将请求转发到 clusterIP:8080。然后,请求会转到 hello-service Service 的一个成员 Pod。该 Pod 中侦听端口 8080 的容器会显示 Hello Kubernetes! 消息。
测试 Ingress
使用 /greet-the-world 路径测试 Ingress:
curl USER_CLUSTER_INGRESS_VIP/greet-the-world
将 USER_CLUSTER_INGRESS_VIP 替换为 Ingress 的外部 IP 地址。
输出结果会显示 Hello, world! 消息:
Hello, world! Version: 2.0.0 Hostname: ...
使用 /greet-kubernetes 路径测试 Ingress:
curl USER_CLUSTER_INGRESS_VIP/greet-kubernetes
输出结果会显示 Hello, Kubernetes! 消息:
Hello Kubernetes!
为 Ingress 设置 HTTPS
如果您想要接受来自客户端的 HTTPS 请求,则 Ingress 代理必须具有证书,这样才能向客户端证明其身份。此代理还必须具有私钥才能完成 HTTPS 握手。
以下示例使用这些实体:
Ingress 代理:参与 HTTPS 握手,然后将数据包转发到
hello-serviceService 的成员 Pod。hello-serviceService 的网域:Example Org 中的 altostrat.com
请按照以下步骤操作:
创建根证书和私钥。此示例使用 Root CA Example Org 中的根证书授权机构
root.ca.example.com。openssl req -x509 -sha256 -nodes -days 365 -newkey rsa:2048 -subj '/O=Root CA Example Inc./CN=root.ca.example.com' -keyout root-ca.key -out root-ca.crt
创建证书签名请求:
openssl req -out server.csr -newkey rsa:2048 -nodes -keyout server.key -subj "/CN=altostrat.com/O=Example Org"
为 Ingress 代理创建服务证书。
openssl x509 -req -days 365 -CA root-ca.crt -CAkey root-ca.key -set_serial 0 -in server.csr -out server.crt
现在,您已经创建了以下证书和密钥:
root-ca.crt:根 CA 的证书root-ca.key:根 CA 的私钥server.crt:Ingress 代理的服务证书server.key:Ingress 代理的私钥
创建包含服务证书和密钥的 Kubernetes Secret。
kubectl create secret tls example-server-creds --key=server.key --cert=server.crt --namespace gke-system
生成的 Secret 名为
example-server-creds。
创建 Deployment 和 Service
如果您已在本指南的 HTTP 部分中创建了 Deployment 和 Service,请保留它们。如果您尚未创建,请立即按照针对 HTTP 所述的步骤进行创建。
创建 Ingress
为 HTTPS 创建 Ingress 与为 HTTP 创建 Ingress 类似,但 HTTPS 的 Ingress 规范包含一个用于指定主机和 Secret 的 tls 部分。tls 部分中的 hosts 需要明确匹配 rules 部分中的 host。
如果您的后端 Service 位于单独的命名空间中,则您需要在与 Ingress 相同的命名空间中创建 ExternalName 类型的 Service,以将流量路由到后端 Service。
如果您之前在 HTTP 部分中创建了 Ingress,请先删除该 Ingress,然后再继续操作。
删除 Ingress:
kubectl --kubeconfig USER_CLUSTER_KUBECONFIG delete ingress my-ingress
如需处理您之前创建的 Service 的流量,请创建一个具有 tls 部分的新 Ingress。这将在客户端和入站流量代理之间启用 HTTPS。
以下是 Ingress 的清单:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: my-ingress-2
spec:
tls:
- hosts:
- altostrat.com
secretName: example-server-creds
rules:
- host: altostrat.com
http:
paths:
- path: /greet-the-world
pathType: Exact
backend:
service:
name: hello-service
port:
number: 60000
- path: /greet-kubernetes
pathType: Exact
backend:
service:
name: hello-service
port:
number: 60001
将该清单保存到名为 my-ingress-2.yaml 的文件中,然后创建 Ingress:
kubectl apply --kubeconfig USER_CLUSTER_KUBECONFIG -f my-ingress-2.yaml
通过测试确认。
测试 /greet-the-world 路径:
curl -v --resolve altostrat.com:443:USER_CLUSTER_INGRESS_VIP https://altostrat.com/greet-the-world --cacert root-ca.crt
输出:
Hello, world! Version: 2.0.0 Hostname: hello-deployment-5ff7f68854-wqzp7
测试
/greet-kubernetes路径:curl -v --resolve altostrat.com:443:USER_CLUSTER_INGRESS_VIP https://altostrat.com/greet-kubernetes --cacert root-ca.crt
输出:
Hello Kubernetes!
清理
删除 Ingress:
kubectl --kubeconfig USER_CLUSTER_KUBECONFIG delete ingress INGRESS_NAME
将 INGRESS_NAME 替换为 Ingress 的名称,例如 my-ingress 或 my-ingress-2。
删除 Service:
kubectl --kubeconfig USER_CLUSTER_KUBECONFIG delete service hello-service
删除 Deployment:
kubectl --kubeconfig USER_CLUSTER_KUBECONFIG delete deployment hello-deployment