一、Ingress 为弥补 NodePort 不足而生
NodePort 存在的不足:
- 一个端口只能一个服务使用,端口需提前规划
- 只支持 4 层负载均衡(iptables 和 ipvs)
扩展:
- 四层:基于 IP 和端口转发
- 七层:HTTP 协议,例如 url、cookie
二、Pod 与 Ingress 的关系
- 通过 Service 相关联
- 通过
Ingress Controller
(类似iptables
的机制)实现 Pod 的负载均衡
a.支持 TCP/UDP 4 层和 HTTP 7 层
Ingress 与 Nodeport 同级。
三、Ingress Controller
实现:
- 部署 Ingress Controller
- 创建 Ingress 规则
注意:由于 kube-proxy 借助了操作系统现有的机制实现了负载均衡,但是 Ingress Controller 技术在 Linux 内核中没有集成,所以需要单独部署;创建 Ingress 规则就好比创建一个 Service 规则
Ingress Controller 有很多实现,我们这里采用官方维护的 Nginx
控制器。
Github:https://github.com/kubernetes/ingress-nginx
部署:
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/nginx-0.30.0/deploy/static/mandatory.yaml
注意事项:
- 镜像地址修改成国内的:
lizhenliang/nginx-ingress-controller:0.30.0
- 建议直接宿主机网络暴露:
hostNetwork: true
注意:也可以下载本站资源 ingress.zip
kubectl apply -f ingress-controller.yaml
参数解释:
--configmap
:配置文件路径--tcp-services-configmap
:tcp 转发服务的配置文件路径--udp-services-configmap
:upd 转发服务的配置文件路径--publish-service
:Ingress-service 配置文件路径--annotations-prefix
:Ingress 自身注解
其他主流控制器:
Traefik
:HTTP 反向代理、负载均衡工具(类似 nginx)Istio
:服务治理,控制入口流量
[root@k8s-master ingress]# kubectl get deploy -n ingress-nginx NAME READY UP-TO-DATE AVAILABLE AGE nginx-ingress-controller 1/1 1 1 5m18s [root@k8s-master ingress]# kubectl get pod -n ingress-nginx NAME READY STATUS RESTARTS AGE nginx-ingress-controller-766fb9f77-cjmvm 1/1 Running 0 71s
接下来就是暴露 Ingress-Controller 的端口号到宿主机中,这时有人会想到用 Service 的 NodePort 去暴露,但是这样的话会多走一层,性能会有所下降,数据包会多一层转发,流程如下:
user
-> nodeport
-> iptables/ipvs
-> ingress controller(pod)
-> [service]
-> pod
更好的办法就是通过 hostnetwork
,去声明 Pod 使用宿主机的网络,而 Pod 默认是使用容器自己的网络的,这样的话除了容器的网络,其他都处于隔离状态,让容器网络与宿主机网络处于同一命名空间中
user
-> lb
-> ingress controller(pod)
-> [service]
-> pod
Ingress-Controller
的端口号已经固定,即80
和443
,可以在分配的节点机器上查看
四、Ingress 暴露应用
4.1 http
yaml 示例 ingress.yaml
:
# http apiVersion: networking.k8s.io/v1beta1 kind: Ingress metadata: name: example-ingress spec: rules: - host: blog.ctnrs.com http: paths: - path: / backend: serviceName: web servicePort: 80
参数解释:
host
:域名,类似 nginx 中的server_name
path
:类似 nginx 中的location
serviceName
:deployment 中对应的 Service 名称,暴露的项目名称servicePort
:监听端口,类似 nginx 中的listen
,Service 的端口(内部端口)
server { listen 80 ; server_name blog.ctnrs.com; location / { } }
kubectl apply -f ingress.yaml
[root@k8s-master ingress]# kubectl get ing NAME CLASS HOSTS ADDRESS PORTS AGE example-ingress <none> blog.ctnrs.com 80 45s
因为 Ingress 是基于域名进行分流的,所以需要绑定 host 去访问(Ingress-Controller 在哪个节点上,host 就绑定哪个节点和域名)
原理解释:因为部署的 Ingress-Controller 就好比单独部署的 Nginx,Nginx 使用的宿主机的网络,所以 Pod 在哪个节点上,才会监听哪个节点的端口。
对应关系:
4.2 https
提前准备自签域名证书,先安装 cfssl
工具 cfssl.sh
:
wget https://pkg.cfssl.org/R1.2/cfssl_linux-amd64 wget https://pkg.cfssl.org/R1.2/cfssljson_linux-amd64 wget https://pkg.cfssl.org/R1.2/cfssl-certinfo_linux-amd64 chmod +x cfssl* mv cfssl_linux-amd64 /usr/bin/cfssl mv cfssljson_linux-amd64 /usr/bin/cfssljson mv cfssl-certinfo_linux-amd64 /usr/bin/cfssl-certinfo
使用 cfssl
工具签发 certs.sh
:
cat > ca-config.json <<EOF { "signing": { "default": { "expiry": "87600h" }, "profiles": { "kubernetes": { "expiry": "87600h", "usages": [ "signing", "key encipherment", "server auth", "client auth" ] } } } } EOF cat > ca-csr.json <<EOF { "CN": "kubernetes", "key": { "algo": "rsa", "size": 2048 }, "names": [ { "C": "CN", "L": "Beijing", "ST": "Beijing" } ] } EOF cfssl gencert -initca ca-csr.json | cfssljson -bare ca - cat > blog.ctnrs.com-csr.json <<EOF { "CN": "blog.ctnrs.com", "hosts": [], "key": { "algo": "rsa", "size": 2048 }, "names": [ { "C": "CN", "L": "BeiJing", "ST": "BeiJing" } ] } EOF # 生成证书 cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=kubernetes blog.ctnrs.com-csr.json | cfssljson -bare blog.ctnrs.com # 将证书保存到k8s secret中 kubectl create secret tls blog-ctnrs-com --cert=blog.ctnrs.com.pem --key=blog.ctnrs.com-key.pem
查看证书:
[root@k8s-master ingress]# kubectl get secret NAME TYPE DATA AGE blog-ctnrs-com kubernetes.io/tls 2 2m8s
yaml 示例:
# https apiVersion: networking.k8s.io/v1beta1 kind: Ingress metadata: name: tls-example-ingress spec: tls: - hosts: - blog.ctnrs.com secretName: blog-ctnrs-com rules: - host: blog.ctnrs.com http: paths: - path: / backend: serviceName: web servicePort: 80
参数解释:
tls
:tls 证书信息host(s)
:域名,类似 nginx 中的server_name
secretName:
:保存在 k8s 中的证书名称rules
:http 配置,使用 https 配置也会默认创建一个 http,访问 http 会跳转到 httpspath
:类似 nginx 中的location
serviceName
:deployment 中对应的 Service 名称,暴露的项目名称servicePort
:监听端口,类似 nginx 中的listen
,Service 的端口(内部端口)
server { listen 443 ssl; crt xxx; key xxx; server_name blog.ctnrs.com; root /usr/share/nginx/html; location / { } }
五、解决 Ingress 高可用
NodePort 暴露端口之后,每个节点都可以访问,唯独 Ingress 只能是 controller 所在的节点上可以访问
方案:
1、扩容 Ingress-Controller Pod 副本数
(1)提高并发能力
(2)尽量让多个节点提供服务
2、把控制器固定到几台节点
(1)daemonset(与 nodeport 一样)
(2)nodeselector+ 污点
污点,即使加污点容忍也不会完全分配到专门几个节点
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于