Kubernetes--案例:使用Ingress发布tomcat
假设有这样一套环境: Kubernetes集群上的tomcat-deploy控制器生成了两个运行于Pod资源中的tomcat实例,tomcat-svc是将它们统一暴露于集群中的访问入口。现在需要通过Ingress资源将tomcat-svc发布给集群外部的客户端访问。
【为了方便理解,下面的测试操作过程将把每一步分解开来放在单独的一节中进行。】
1. 准备名称空间
假设本示例中创建的所有资源都位于新建的testing名称空间中,与其他的资源再逻辑上进行隔离,以方便管理。下面的配置信息保存于 testing-namespace.yaml 资源清单文件中:
kind: Namespace apiVersion: v1 metadata: name: testing labels: env: testing
而后运行创建命令完成资源的创建,并确认资源的存在:
]$ kubectl apply -f testing-namespace.yaml namespace/testing created ]$ kubectl get namespaces testing NAME STATUS AGE testing Active 10s
2. 部署tomcat实例
在此示例中,tomcat应用本身代表着运行于tomcat容器中的一个实际应用。具体实践中,它通常应该是包含了某应用程序的war文件的镜像文件。下面的配置清单使用了Deployment控制器于testing中部署tomcat相关的Pod对象,它保存于tomcat-deploy.yaml文件中:
apiVersion: apps/v1 kind: Deployment metadata: name: tomcat-deploy namespace: testing spec: replicas: 2 selector: matchLabels: app: tomcat template: metadata: labels: app: tomcat spec: containers: - name: tomcat image: tomcat:8.0.50-jre8-alpine ports: - containerPort: 8080 name: httpport - containerPort: 8009 name: ajpport
运行资源创建命令完成Deployment控制器和Pod资源的创建,命令如下:
]$ kubectl apply -f tomcat-deploy.yaml deployment.apps/tomcat-deploy created
接着运行命令以确认其成功完成,且各Pod已经处于正常运行状态中:
]$ kubectl get pods -n testing NAME READY STATUS RESTARTS AGE tomcat-deploy-789fbddff4-blq8x 1/1 Running 0 33s tomcat-deploy-789fbddff4-mntzq 1/1 Running 0 33s
实践中,如果需要更多的Pod资源承载用户访问,那么使用Deployment控制器的规模伸缩机制即可完成,或者直接修改上面的配置文件并执行 “ kubectl apply ” 命令重新进行应用。
3. 创建Service资源
Ingress资源仅通过Service资源识别相应的Pod资源,获取其IP和端口,而后Ingress控制器即可直接使用各Pod对象的IP地址与它直接进行通信,而不经由Service资源的代理和调度,因此Service资源的ClusterIP对Ingress控制器来说一无所用。不过,若集群内的其他Pod客户端需要与其通信,那么保留ClusterIP似乎也是很有必要的。
下面的配置文件中定义了Service资源tomcat-svc,它通过标签选择器将相关的Pod对象归于一组,并通过80/TCP端口暴露Pod对象的8080/TCP端口。如果需要暴露容器的8009/TCP端口,那么只需要将其以类似的格式配置于列表中即可:
apiVersion: v1 kind: Service metadata: name: tomcat-svc namespace: testing labels: app: tomcat-svc spec: selector: app: tomcat ports: - name: http port: 80 targetPort: 8080 protocol: TCP
运行资源创建命令完成Service资源的创建:
]$ kubectl apply -f tomcat-svc.yaml service/tomcat-svc created
接着运行命令以确认其成功完成:
]$ kubectl get svc tomcat-svc -n testing NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE tomcat-svc ClusterIP 10.110.186.173 <none> 80/TCP 33s
4. 创建Ingress资源
通过Ingress资源的FQDN主机名或URL路径等类型发布的服务,只有用户的访问请求能够匹配到其 .spec.rules.host 字段定义的主机时才能被相应的规则处理。如果要明确匹配用户的处理请求,比如希望将那些发往 tomcat.ilinux.io 主机的所有请求代理至 tomcat-svc 资源的后端Pod,则可以使用如下命令配置文件中的内容:
]$ kubectl describe ingresses -n testing Name: tomcat-svc Namespace: testing Address: 10.105.36.24 Default backend: default-http-backend:80 Rules: Host Path Backends ---- ---- -------- tomcat.ilinux.io tomcat-svc:80 Annotations: Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal CREATE 43m nginx-ingress-controller Ingress testing/tomcat
接下来即可通过Ingress控制器的前端Service资源的NodePort来访问此服务,在上一篇 “Kubernetes--部署Ingress控制器(Nginx)” 中,此Service资源的ClusterIP被明确定义为10.99.99.99,并以节点端口30080映射Ingress控制器的80端口。因此,这里使用Ingress中定义的主机名tomcat.ilinux.io:30080即可访问tomcat应用。当然,实践中,其前端应该有一个外部的负载均衡设备接收并调度此类请求。
不过,用户对tomcat.ilinux.io主机之外的地址发起的被此Ingress规则匹配到的请求将发往Ingress控制器的默认的后端,及default-http-backend,它通常只能返回一个404提示信息。用户也可以按照需求自定义默认后端,例如,如下面的配置文件片段所示,它通过.spec.backend定义了所有无法由此Ingress匹配的访问请求都由相应的后端default-svc这个Service资源来处理:
spec: backend: serviceName: default-svc servicePort: 80
5. 配置TLS Ingress资源
一般来说,如果有基于HTTPS通信的需求,那么它应该由外部的负载均衡器(external-LB)予以实现,并在SSL会话卸载后将访问请求转发到Ingress控制器。不过,如果外部负载均衡器工作于传输层而不是工作与应用层的反向代理服务器,或者存在直接通过Ingress控制器接收客户端请求的需求,又期望它们能够提供HTTPS服务时,就应该配置TLS类型的Ingress资源。
将此类服务公开发布到互联网时,HTTPS服务用到的证书应由公信CA签署并颁发,用户遵循其相应流程准备好相关的数字证书即可。如果出于测试或内部使用之目的,那么也可以选择自制私有证书。openssl工具程序是用于生成自签证书的常用工具~这里使用它生成用于测试的私钥和自签证书:
]$ openssl genrsa -out tls.key 2048 ]$ openssl req -new -x509 -key tls.key -out tls.crt \ -subj /C=CN/ST=Beijing/L=Beijing/O=DevOps/CN=tomcat.ilinux.io -days 3650
注意:TLS Secret中包含的证书必须以tls.crt作为其键名,私钥文件必须以tls.key为键名,因此上面生成的私钥文件和证书文件名将直接保存为键名形式,以便于后面创建Secret对象时直接作为键名引用。
在Ingress控制器上配置HTTPS主机时,不能直接使用私钥和证书文件,而是要使用Secret资源对象来传递相关的数据。所以,接下来要根据私钥和证书生成用于配置TLS Ingress的Secret资源,在创建Ingress规则时由其将用到的Secret资源中的信息注入Ingress控制器的Pod对象中,用于为配置的HTTPS虚拟主机提供相应的私钥和证书。下面的命令会创建一个TLS类型名为tomcat-ingress-secret的Secret资源:
]$ kubectl create secret tls tomcat-ingress-secret --cert=tls.crt --key=tls.key -n testing secret/tomcat-ingress-secret created
确认Secret资源tomcat-ingress-secret创建成功完成:
]$ kubectl get secrets tomcat-ingress-secret -n testing NAME TYPE DATA AGE tomcat-ingress-secret kubernetes.io/tls 2 33s
apiVersion: extensions/v1beta1 kind: Ingress metadata: name: tomcat-ingress-tls annotations: kubernetes.io/ingress.class: "nginx" spec: tls: - hosts: - tomcat.ilinux.io secretName: tomcat-ingress-secret rules: - host: tomcat.ilinux.io http: paths: - path: / backend: serviceName: tomcat-svc servicePort: 80
运行资源创建命令完成Service资源的创建:
]$ kkubectl apply -f tomcat-ingress-tls.yaml
而后通过详细信息确认其创建成功完成,且已经正确关联到相应的tomcat-svc资源:
]$ kubectl describe ingress tomcat-ingress-tls -n testing Name: tomcat-ingress-tls Namespace: testing Address: Default backend: default-http-backend:80 TLS: tomcat-ingress-secret terminates tomcat.linux.io Rules: Host Path Backends ---- ---- -------- tomcat.ilinux.io / tomcat-svc:80 Annotations: Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal CREATE 31m nginx-ingress-controller Ingress testing/tomcat-ingress-tls
接下来即可通过Ingress控制器前端Service资源的NodePort来访问此服务,在 “Kubernetes--部署Ingress控制器(Nginx)” 中,此Service资源以节点端口30443映射控制器的443端口。因此,这里使用Ingress中定义的主机名tomcat.ilinux.io:30443即可访问tomcat应用。另外,也可以使用curl进行访问测试,只要对应用的主机能够正确解析tomcat.ilinux.io主机名即可,例如,可使用“ curl -k -v tomcat.ilinux.io:30443/ ”命令及其输出表明,TLS类型的Ingress已然配置成功,大家可自行进行测试~
到此为止,实践配置目标已经全部达成。需要再次提醒的是,在实际使用中,在集群之外应该存在一个用于调度用户请求至各个节点上Ingress控制器相关的NodePort的负载均衡器。如果不具有LBaaS的使用条件,用户也可以基于Nginx、Haproxy、LVS等手动构建,并通过Keepalived等解决方案实现其服务的高可用配置。