0%

K8S中安装使用Ingress

Ingress简介

ingress是k8s中的一个七层的负载均衡,可以把流量路由到service。
如果没有ingress,我们可以通过外部的nginx、haproxy等也可以实现七层负载均衡,但是配置nginx比较麻烦,因为想要配置nginx的upstream必须先查询service的ip,那如果使用service的name,还要维护一个dns;如果想要换成haproxy,成本也比较高。而有了ingress,实际上就是把nginx等七层负载均衡集成到了k8s中,配置就更加简单也更加通用。

它的工作原理是ingress服务作为流量的入口,收到请求后,根据host、path等规则,匹配到对应的service和端口,然后把流量转发到service的端口,service再转发流量给pod。

参考文档:

安装Ingress Controller

本节中,我们使用helm在K8S集群中安装Ingress NGINX Controller。

参考文档:

官方推荐一键安装:

1
2
3
helm upgrade --install ingress-nginx ingress-nginx \
--repo https://kubernetes.github.io/ingress-nginx \
--namespace ingress-nginx --create-namespace

因为郝同学喜欢安装指定版本,并且对配置做一些了解,因此本节使用稍微麻烦一点的方式。

1、添加chart仓库

1
2
3
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm repo update
helm repo list

2、导出配置,chart4.1.4 对应 app1.2.1

1
2
helm search repo ingress-nginx/ingress-nginx -l
helm show values ingress-nginx/ingress-nginx --version 4.1.4 > values-4.1.4.yaml

3、修改配置
values-4.1.4.yaml按需修改,这里主要修改一下镜像:

  • controller.image.registry ,改为registry.cn-hangzhou.aliyuncs.com
  • controller.image.image,改为google_containers/nginx-ingress-controller
  • controller.image.tag,保持不变v1.2.1
  • 注释掉 controller.image.digest 和 controller.image.digestChroot

4、安装ingress nginx controller

1
2
kubectl create ns ingress-nginx
helm install ingress-nginx ingress-nginx/ingress-nginx -f values-4.1.4.yaml -n ingress-nginx

5、查看安装

1
2
kubectl get all -n ingress-nginx
kubectl get ingressclass

KS中的Ingress Controller

如果k8s集群中安装了kubesphere,那么可以直接启用kubesphere的网关,本质也是ingress nginx controller。
开启办法:admin用户登录控制台,集群设置,网关设置,启用网关。

参考文档:

配置Ingress

参考文档:

Ingress Controller配置

可以认为Ingress Controller就是一个K8S内部的Nginx。
查看 Ingress Controller 的 service 配置,找到80和433端口对应的NodePort,用于访问Nginx。
假设一个节点IP为192.168.56.102,service的80端口对应30490,443端口对应30499。

创建测试服务

1、创建测试服务(Nginx)

1
2
3
4
kubectl create deployment test --image=nginx --dry-run=client -oyaml > deployment.yaml
kubectl create service clusterip test --tcp=80:80 --tcp=443:443 --dry-run=client -oyaml > service.yaml
kubectl apply -f deployment.yaml
kubectl apply -f service.yaml

2、查看测试服务

1
2
kubectl get pods
kubectl get svc

创建Ingress

1、准备 minimal-ingress.yaml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: minimal-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
ingressClassName: nginx
rules:
- http:
paths:
- path: /testpath
pathType: Prefix
backend:
service:
name: test
port:
number: 80

其中,ingressClassName可以省略,省略后会使用默认的ingressClass。
因为配置了rewrite-target,所以请求到达service时,/testpath会被替换为/

2、创建ingress

1
2
kubectl apply -f minimal-ingress.yaml
kubectl get ingress

3、通过ingress controller访问测试服务

1
curl 192.168.56.102:30490/testpath

访问链路为:ip+port(ingress) -> nginx service

多个Ingress Controller

怎样在k8s集群中配置多个Ingress Controller?
答:多个Ingress Controller的--controller-class--ingress-class设置成不同的值。

如果k8s集群中存在多个Ingress Controller,哪个会生效呢?
答:在Ingress的spec中指定ingressClassName,或者在Ingress的annotations中指定kubernetes.io/ingress.class(即将废弃)。
如果不指定,那么将会使用默认的ingressClass,默认的ingressClass中会包含一个annotations:

1
2
annotations:
ingressclass.kubernetes.io/is-default-class: "true"

Ingress NGINX Controller的--controller-class默认值为k8s.io/ingress-nginx--ingress-class的默认值为nginx

参考文档:

常用Ingress配置

支持websocket

推荐方法:

1
2
3
4
5
6
7
8
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: minimal-ingress
annotations:
nginx.ingress.kubernetes.io/proxy-http-version: "1.1"
nginx.ingress.kubernetes.io/proxy-read-timeout: "3600"
nginx.ingress.kubernetes.io/proxy-send-timeout: "3600"

参考文档:

历史方法:

1
2
3
4
5
6
7
8
9
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: minimal-ingress
annotations:
nginx.ingress.kubernetes.io/configuration-snippet: |
proxy_http_version 1.1;
proxy_set_header Upgrade "websocket";
proxy_set_header Connection "Upgrade";

域名证书配置

普通域名配置证书

1、创建secret

1
2
3
4
5
kubectl create secret tls cert \
--cert=/etc/letsencrypt/live/voidking.com/fullchain.pem \
--key=/etc/letsencrypt/live/voidking.com/privkey.pem \
--dry-run=client \
-oyaml > secret.yaml
1
2
3
4
5
6
7
8
apiVersion: v1
data:
tls.crt: xxx
tls.key: yyy
kind: Secret
metadata:
name: cert
type: Opaque

其中,tls.crt是base64加密后的证书,tls.key是base64加密后的key。

2、ingress添加tls定义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
spec:
ingressClassName: nginx
rules:
- host: test.voidking.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: test
port:
number: 80
tls:
- hosts:
- test.voidking.com
secretName: cert

泛域名配置证书

泛域名的证书配置方法,和普通域名的证书配置方法完全一致。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
spec:
ingressClassName: nginx
rules:
- host: *.voidking.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: test
port:
number: 80
tls:
- hosts:
- '*.voidking.com'
secretName: cert

参考文档:

多个域名配置泛域名证书

多个域名使用同一个泛域名证书,建议集中配置泛域名证书。

1、域名证书配置

1
2
3
4
5
6
7
8
9
10
spec:
ingressClassName: nginx
rules:
- host: test0.voidking.com
- host: test1.voidking.com
tls:
- hosts:
- 'test0.voidking.com'
- 'test1.voidking.com'
secretName: cert

2、路由配置

1
2
3
4
5
6
7
8
9
10
11
12
13
spec:
ingressClassName: nginx
rules:
- host: test0.voidking.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: test
port:
number: 80

批量修改域名证书

已知条件:

  • k8s集群中,使用ingress配置了很多四级域名,例如 test0.intl.voidking.com 和 test1.intl.voidking.com
  • 每个域名都有一个自己的ingress配置文件,包含tls配置
  • ingress位于不同的namespace

需求:*.intl.voidking.com域名证书过期,需要批量修改k8s中的域名证书。

1、准备脚本 patch.sh

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#!/bin/bash
domain=$1
if [[ -z "$domain" ]];then
echo "domain can not be null!"
exit 1
fi
crt="/etc/letsencrypt/live/${domain}/fullchain.pem"
key="/etc/letsencrypt/live/${domain}/privkey.pem"
if [[ ! (-e $crt && -e $key) ]];then
echo "$crt or $key does not exist!"
exit 1
fi
tlscrt=$(cat $crt | base64 | tr -d '\n')
tlskey=$(cat $key | base64 | tr -d '\n')

kubectl get ingress -A | grep "$domain" | awk '{print $1" "$2" "$4}' > ingress.txt
cat ingress.txt
read -p "is the content right?[Y/N]" input
if [[ ! ($input = "y" || $input = "Y") ]];then
"exit!"
exit 0
fi

while read line;do
echo "$line"
namespace=$(echo "$line" | awk '{print $1}')
ingressname=$(echo "$line" | awk '{print $2}')
secretname=$(kubectl get ingress $ingressname -n $namespace -o=jsonpath='{.spec.tls[0].secretName}')
echo "secret: $secretname"
if [[ -z "$secretname" ]];then
echo "ingress $ingressname does not link secret!"
continue
fi
kubectl patch secret $secretname \
-p "{\"data\": {\"tls.crt\": \"$tlscrt\"}}" \
-n $namespace
kubectl patch secret $secretname \
-p "{\"data\": {\"tls.key\": \"$tlskey\"}}" \
-n $namespace
done < ingress.txt

2、执行脚本

1
bash patch.sh intl.voidking.com

前后端分离

需求描述:前端后端是两个服务,位于两个namespace,要配置ingress,使发往路由/的流量打到前端服务,发往/api的流量打到后端服务。

方法一:
在一个namespace中,创建一个ingress和一个externalname类型的service。在ingress中配置两个path。

方法二:
在两个namespace中,分别创建一个ingress。host相同,配置不同的path,ingress-controller会自动合并这两个配置。

设置max_client_body_size

nginx-ingress-controller有一个全局配置文件(configmap),类似于nginx中的nginx.conf,通过它可以配置一些通用配置,例如max_client_body_size。

1、编辑配置文件

1
kubectl edit cm nginx-configuration -n ingress-nginx

修改data部分的配置:

1
2
data:
proxy-body-size: "1000m"

2、重启nginx-ingress-controller

1
kubectl rollout restart deployment nginx-ingress-controller -n ingress-nginx

路径重写

参考文档:

方法一:nginx.ingress.kubernetes.io/use-regex

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /$1
nginx.ingress.kubernetes.io/use-regex: true
spec:
ingressClassName: nginx
rules:
- host: test0.voidking.com
http:
paths:
- path: /(site/.*)
backend:
serviceName: backend-service
servicePort: 8080
- path: /(cms/.*)
backend:
serviceName: cms-service
servicePort: 8080

方法二:nginx.ingress.kubernetes.io/configuration-snippet

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: fe
namespace: default
annotations:
kubernetes.io/ingress.class: "nginx"
nginx.ingress.kubernetes.io/rewrite-target: /
nginx.ingress.kubernetes.io/configuration-snippet: |
rewrite ^/api/(.*)$ /api/v1/$1 redirect;
rewrite ^/api-v2/(.*)$ /api/v2/$1 redirect;
spec:
ingressClassName: nginx
rules:
- host: test0.voidking.com
http:
paths:
- path: /api
backend:
serviceName: api-service
servicePort: 3000

方法三:nginx.org/rewrites

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: cafe-ingress
annotations:
nginx.org/rewrites: "serviceName=tea-svc rewrite=/;serviceName=coffee-svc rewrite=/beans/"
spec:
rules:
- host: cafe.example.com
http:
paths:
- path: /tea/
pathType: Prefix
backend:
service:
name: tea-svc
port:
number: 80
- path: /coffee/
pathType: Prefix
backend:
service:
name: coffee-svc
port:
number: 80

查看最终的nginx配置

我们编写的ingress,实际上最终会生成nginx.conf,可以在nginx-ingress-controller中查看是否符合预期。

1
2
3
kubectl exec -it nginx-ingress-controller-xxx -- /bin/bash
cd /etc/nginx
cat nginx.conf

Ingress推荐链路

LB -> Service

1
Domain -> LB(Ingress) -> Service -> Pod

这种链路,适用于云厂商提供的k8s集群。
在创建ingress-controller的service时,直接给这个service分配一个LB可供外部访问。
这种链路最大的优点是链路短,速度快。

LB -> Ingress

1
Domain -> LB -> Ingress -> Service -> Pod

这种链路,适用于云厂商提供的k8s集群。
通过云厂商提供的LB,可以配置四层或者七层负载均衡到Ingress,还可以在LB层加一些安全防护产品。
如果使用的是七层负载均衡,还可以统一配置泛域名证书。

Nginx -> Ingress

1
Domain -> Nginx -> Ingress -> Service -> Pod

这种链路,适用于所有k8s集群。
通过Nginx,可以配置四层或者七层负载均衡到Ingress。
如果使用的是七层负载均衡,还可以统一配置泛域名证书。

  • 本文作者: 好好学习的郝
  • 本文链接: https://www.voidking.com/dev-k8s-ingress/
  • 版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!源站会及时更新知识点及修正错误,阅读体验也更好。欢迎分享,欢迎收藏~