上图是一个客户端访问k8s集群服务的示意图,本文只讲解ingress控制器、NodePort类型的Service对外暴露端口两部分。Ingress和Ingress控制器的官方定义如下。
Ingress 是对集群中服务的外部访问进行管理的 API 对象,典型的访问方式是 HTTP,Ingress 可以提供负载均衡、SSL 终结和基于名称的虚拟托管。
Ingress通常负责通过负载均衡器来实现 Ingress。
官方定义看得人云里雾里。我用大白话解释,打个比方Ingress控制器类似于与nginx,Ingress类似于nginx的配置文件。如果我们只安装nginx,不写nginx的配置文件,例如不写转发规则,则此nginx将毫无意义;反过来,若只有nginx的配置文件,但没装nginx,则配置文件无运行载体。所以Ingress和Ingress控制器是配合着使用的。
从上图可以看出Ingress和Ingress控制器是负责对外部请求的管理、转发,并没有对外暴露端口,需要在Ingress前面加一个NodePort类型的Service,通过这个Service对外暴露端口。
在使用Ingress之前,先要把应用pod(上图中的appX-pod-X)和应用的service(上图中的appX-svc)创建好,读者可阅读 kubernetes零宕机部署探索 创建。但有一点要注意, 需要将kubernetes零宕机部署探索 中的Service改成ClusterIP类型,即上图中app1-svc、app2-svc是ClusterIP类型,红色框的Service才是暴露端口的NodePort类型。具体做法如下
将service-nodeport.yaml改名为service-app3.yaml。(需要改名是因为待会儿要下载一个yaml文件,但那个yaml文件名也是service-nodeport.yaml,为避免冲突,先改下名字)
mv service-nodeport.yaml service-app3.yaml
修改service-app3.yaml,使用ClusterIP类型
apiVersion: v1
kind: Service
metadata:
name: service-app3
spec:
selector:
app: app3
# 使用NodePort方式暴露一个外部端口供调试使用
# type: NodePort
type: ClusterIP
ports:
- name: http
port: 10013
targetPort: 10013
# 外部端口
# nodePort: 30013
1、本文选择的控制器是ingress-nginx,使用裸机方式安装。云厂商不同,安装方式也不同,详情 ingress-nginx github。
wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/nginx-0.24.1/deploy/mandatory.yaml
kubectl apply -f mandatory.yaml
kubectl get pod -n ingress-nginx
下载mandatory.yaml文件可能会被墙,请走代理。
2、安装暴露集群端口的Service。注意本地磁盘不要有service-nodeport.yaml同名文件。
wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/nginx-0.24.1/deploy/provider/baremetal/service-nodeport.yaml
可修改此Service的端口绑定,将Service的80端口绑定给宿主机30080,443端口绑定给宿主机30443。修改如下:
apiVersion: v1
kind: Service
metadata:
name: ingress-nginx
namespace: ingress-nginx
labels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
spec:
type: NodePort
ports:
- name: http
port: 80
targetPort: 80
protocol: TCP
# 绑定裸机端口
nodePort: 30080
- name: https
port: 443
targetPort: 443
protocol: TCP
# 绑定裸机端口
nodePort: 30443
selector:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
kubectl apply -f service-nodeport.yaml
kubectl get svc -n ingress-nginx
从service-nodeport.yaml可以看出来,此Service暴露的两个端口80、443,将外部请求转给ingress-nginx控制器。
对比service-nodeport.yaml的selecor和mandatory.yaml的Deployment labels,ingress-nginx控制器的labels就是:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
我的k8s集群主节点ip是192.168.3.151,浏览器打开 http://192.168.3.151:30080/ 出现404 not found表明ingress-nginx、暴露服务Service 安装成功。
3、ingress-nginx接收请求后,需要将请求转给pod。我们写一个ingress转发规则。
vim ingress-my.yaml
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: ingress-my
annotations:
# 控制器使用nginx
kubernetes.io/ingress.class: "nginx"
spec:
rules:
# host不支持IP,必须是域名
- host: k8s01.com
http:
paths:
# 以app3开头的请求转给service-app3的10013端口
- path: /app3
backend:
serviceName: service-app3
servicePort: 10013
kubectl apply -f ingress-my.yaml
4、修改电脑的C:\Windows\System32\drivers\etc\hosts文件,添加DNS规则,将k8s01.com的请求转发给k8s集群主节点(主节点ip是192.168.xx.xx)。
192.168.xx.xx k8s01.com
5、请求接口: http://k8s01.com:30080/app3/test/get
至此,外部环境访问集群内部服务的功能就实现了。
1、生成私钥
openssl genrsa -out tls.key 2048
2、生成证书
openssl req -new -x509 -key tls.key -out tls.crt -subj /C=CN/ST=Beijing/L=Beijing/O=DevOps/CN=k8s01.com
3、私钥和证书不能直接被ingress控制器使用,需要用到Secret。Secret 是一种包含少量敏感信息例如密码、令牌或密钥的对象, 这样的信息被放在 Pod 规约中或者镜像中。
使用私钥和证书创建secret,名称是secret-k8s01
kubectl create secret tls secret-k8s01 --cert=tls.crt --key=tls.key
4、ingress配置tls,使用secret-k8s01
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: ingress-my
annotations:
# 控制器使用nginx
kubernetes.io/ingress.class: "nginx"
spec:
rules:
# host不支持IP,必须是域名
- host: k8s01.com
http:
paths:
# 以app3开头的请求转给service-app3的10013端口
- path: /app3
backend:
serviceName: service-app3
servicePort: 10013
tls:
- hosts:
- k8s01.com
secretName: secret-k8s01
kubectl apply -f ingress-my.yaml
5、使用https访问集群服务:https://k8s01.com:30443/app3/info
注意:暴露端口Service的443端口在宿主机上的映射是30443端口。
ingress控制器本质上是一个pod,进入ingress-nginx中查看ingress在nginx.conf如何体现。
kubectl get pods -n ingress-nginx
kubectl exec -n ingress-nginx -it nginx-ingress-controller-XXXXXX -- /bin/sh
cat nginx.conf
正如前面所说,ingress规则最终是转化到ingress控制器配置文件中。
最后提一点:Ingress控制器不会将请求转给应用的Service,而是直接将请求转给pod。注意看博客开头的图,Ingress控制器到app1-svc、app2-svc的箭头,用的是灰色箭头,其实ingress会将service的endpoint保存起来,接收到请求后,没有将请求转发给service,而是直接转发给service的endpoint。