Kubernetes之Ingress-nginx部署使用

2021-06-03 18:02

阅读:298

标签:规则   create   重复   data   grep   详细信息   关联   sts   client   

博文大纲:
一、Ingress简介
1)Ingress组成
2)Ingress工作原理
3) Ingress可以解决什么问题?
二、配置Ingress-nginx
1)搭建registry私有仓库
2)创建用于测试的Pod
2)创建tomcat服务及其service
3)确保以上资源对象成功创建
4)创建Ingress-controller资源对象
5)创建Ingress资源对象
6)为Ingress-controller资源对象创建一个service资源对象
7)创建基于虚拟主机的Ingress规则
三、配置HTTPS

一、Ingress简介

在Kubernetes中,服务和Pod的IP地址仅在集群内部网络内部使用,对于集群的应用是不可见的。

为了使外部的应用能够访问集群内的服务,在Kubernetes目前提供了以下几种方案:
1)NodePort
2)LoadBalancer
3)Ingress

1)Ingress组成

Ingress 是反向代理规则,用来规定 HTTP/S 请求应该被转发到哪个 Service 上,比如根据请求中不同的 Host 和 url 路径让请求落到不同的 Service 上;
Ingress Controller 就是一个反向代理程序,它负责解析 Ingress 的反向代理规则,如果 Ingress 有增删改的变动,所有的 Ingress Controller 都会及时更新自己相应的转发规则,当 Ingress Controller 收到请求后就会根据这些规则将请求转发到对应的 Service;

2)Ingress工作原理

1)Ingress controller通过与Kubernetes api进行交互,动态的感知集群中Ingress规则的变化;
2)然后读取它,按照自定义的规则,规则就是写明了哪个域名对应哪个service,生成一段nginx配置;
3)再写到nginx-ingress-controller的pod里,这个Ingress controller的pod里运行着一个Nginx服务,控制器会把生成的nginx配置写入/etc/nginx.conf文件中;
4)然后reload一下使配置生效。以此达到域名分别配置和动态更新的问题;

3) Ingress可以解决什么问题?

1)动态配置服务
如果是按照传统方式,当新增加一个服务时,我们可能需要在流量入口部署一台反向代理服务器指向我们新的K8s服务,而如果使用了Ingress,则只需配置好这个服务,当服务启动时,便会自动注册到Ingress中,不需要额外的操作;
2)减少不必要的端口映射
配置过k8s的都清楚, 第一步是要关闭防火墙的, 主要原因是k8s的很多服务会以NodePort方式映射出去, 这样就相当于给宿主机打了很多孔, 既不安全也不优雅. 而Ingress可以避免这个问题, 除了Ingress自身服务可能需要映射出去, 其他服务都不用NodePort方式;

二、配置Ingress-nginx

1)搭建registry私有仓库

搭建私有仓库的目的,仅仅是为了更快的获取镜像,如果网络稳定,也可跳过此步骤!

[root@master ~]# docker run -itd --name registry --restart=always  -p 5000:5000 -v /registry:/var/lib/registry registry:2
#搭建registry私有仓库
[root@master ~]#  vim /usr/lib/systemd/system/docker.service 
#修改docker的配置文件,指向私有仓库
ExecStart=/usr/bin/dockerd --insecure-registry 192.168.1.4:5000
[root@master ~]# scp /usr/lib/systemd/system/docker.service root@node01:/usr/lib/systemd/system/
[root@master ~]# scp /usr/lib/systemd/system/docker.service root@node02:/usr/lib/systemd/system/
#将修改好的配置文件发送到Kubernetes集群中的各个节点
[root@master ~]# systemctl daemon-reload 
[root@master ~]# systemctl restart docker
#所有节点都需重新启动服务
[root@master ~]# docker pull httpd
[root@master ~]# docker pull tomcat:8.5.45
[root@master ~]# docker tag httpd:latest 192.168.1.4:5000/httpd:v1
[root@master ~]# docker tag tomcat:8.5.45 192.168.1.4:5000/tomcat:v1
[root@master ~]# docker push 192.168.1.4:5000/httpd:v1
[root@master ~]# docker push 192.168.1.4:5000/tomcat:v1
#下载使用的镜像,并将其上传到私有仓库

2)创建用于测试的Pod

1)创建httpd服务及其service

[root@master ~]# vim httpd01.yaml 
apiVersion: v1
kind: Namespace
metadata:
  name: test-ns
#创建名称空间test-ns
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: httpd01
  namespace: test-ns
spec:
  replicas: 2
  template:
    metadata:
      labels:
        app: httpd-01
    spec:
      containers:
      - name: httpd
        image: 192.168.1.4:5000/httpd:v1
#使用httpd的镜像创建Deployment资源,副本数量为2个,并打标签为httpd-01
---
apiVersion: v1
kind: Service
metadata:
  name: httpd-svc
  namespace: test-ns
spec:
  selector:
    app: httpd-01
  ports:
  - protocol: TCP
    port: 80
    targetPort: 80
#创建service资源对象与Deployment资源使用标签的方式进行关联
[root@master ~]# kubectl apply -f httpd01.yaml 

2)创建tomcat服务及其service

[root@master ~]# vim tomcat01.yaml
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: tomcat01
  namespace: test-ns
spec:
  replicas: 2
  template:
    metadata:
      labels:
        app: tomcat-01
    spec:
      containers:
      - name: tomcat
        image: 192.168.1.4:5000/tomcat:v1
#使用tomcat的镜像创建Deployment资源,副本数量为2个,并打标签为tomcat-01
---
apiVersion: v1
kind: Service
metadata:
  name: tomcat-svc
  namespace: test-ns
spec:
  selector:
    app: tomcat-01
  ports:
  - protocol: TCP
    port: 8080
    targetPort: 8080
#创建service资源对象与Deployment资源使用标签的方式进行关联
[root@master ~]# kubectl apply -f tomcat01.yaml

3)确保以上资源对象成功创建

[root@master ~]# kubectl get pod -n test-ns       #确保pod正常运行
NAME                        READY   STATUS    RESTARTS   AGE
httpd01-6575d9cdcd-kjcmm    1/1     Running   0          13m
httpd01-6575d9cdcd-tjkwk    1/1     Running   0          13m
tomcat01-65b74df4d4-6b9vz   1/1     Running   0          11m
tomcat01-65b74df4d4-wfhfz   1/1     Running   0          11m
[root@master ~]# kubectl get svc -n test-ns             #确保service创建成功
NAME         TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)    AGE
httpd-svc    ClusterIP   10.104.32.150           80/TCP     13m
tomcat-svc   ClusterIP   10.99.184.215           8080/TCP   11m
[root@master ~]# curl -I 10.104.32.150 
HTTP/1.1 200 OK
Date: Fri, 21 Feb 2020 11:09:16 GMT
Server: Apache/2.4.41 (Unix)
Last-Modified: Mon, 11 Jun 2007 18:53:14 GMT
ETag: "2d-432a5e4a73a80"
Accept-Ranges: bytes
Content-Length: 45
Content-Type: text/html
[root@master ~]# curl -I 10.99.184.215:8080
HTTP/1.1 200 
Content-Type: text/html;charset=UTF-8
Transfer-Encoding: chunked
Date: Fri, 21 Feb 2020 11:09:28 GMT
#访问SVC的clusterIP+端口,确定可以访问到后端Pod

4)创建Ingress-controller资源对象

创建ingress-nginx资源所使用的镜像链接:https://pan.baidu.com/s/1skhA3jSCH7-c-iStCXbuNQ
提取码:nx6o

获取Ingress-nginx的yaml文件,方法如下:
技术图片
技术图片
技术图片
技术图片
技术图片

[root@master ~]# wget  https://raw.githubusercontent.com/kubernetes/ingress-nginx/nginx-0.29.0/deploy/static/mandatory.yaml
[root@master ~]# vim mandatory.yaml 
#对下载的yaml文件进行简单的修改
    spec:                            #定位到212行,也就是该行
      hostNetwork: true             #添加该行,表示使用主机网络
      # wait up to five minutes for the drain of connections
      terminationGracePeriodSeconds: 300
      serviceAccountName: nginx-ingress-serviceaccount
      nodeSelector:
        Ingress: nginx               ##设置节点的标签选择器,指定在哪台节点上运行
      containers:
        - name: nginx-ingress-controller
          image: quay.io/kubernetes-ingress-controller/nginx-ingress-controller:0.29.0
#该资源使用的镜像,该镜像下载较慢,可使用步骤开头提供的网盘链接!
[root@master ~]# kubectl label nodes node01 Ingress=nginx
#对node01节点打相应的标签,以便指定Ingress-nginx运行在node01
[root@master ~]# kubectl get nodes node01 --show-labels
#查看node01的标签是否存在
[root@node01 ~]# docker load 

关于上面yaml文件中写入的“hostNetwork: true”具体解释:如果添加了此字段,意味着pod中运行的应用可以直接使用node节点的端口,这样node节点主机所在网络的其他主机,就可以通过访问该端口访问此应用。(类似于docker映射到宿主机的端口。)

[root@master ~]# kubectl get pod -n ingress-nginx -o wide
#确认Ingress-nginx容器正常运行
NAME                                        READY   STATUS    RESTARTS   AGE   IP            NODE     NOMINATED NODE   READINESS GATES
nginx-ingress-controller-577ffd8c54-zntwl   1/1     Running   0          9s    192.168.1.5   node01   

5)创建Ingress资源对象

[root@master ~]# vim ingress.yaml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: test-ingress
  namespace: test-ns
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  rules:
  - host: www.lzj.com
    http:
      paths:
      - path: /
        backend:
          serviceName: httpd-svc
          servicePort: 80
      - path: /tomcat
        backend:
          serviceName: tomcat-svc
          servicePort: 8080
#通过www.lzj.com 来访问到我们后端httpd容器提供的服务;
#通过www.lzj.com/tomcat 来访问我们后端tomcat提供的服务
[root@master ~]# kubectl apply -f ingress.yaml 
ingress.extensions/test-ingress created
[root@master ~]# kubectl get ingresses. -n test-ns 
#创建Ingress资源对象
NAME           HOSTS         ADDRESS   PORTS   AGE
test-ingress   www.lzj.com             80      23s

其实,至此已经实现了我们想要的功能,前提是自行配置DNS解析,或者直接修改client的hosts文件。访问页面如下(注意:一定要自己解决域名解析的问题,若不知道域名对应的是哪个IP,请跳过这两个图,看下面的文字解释):

访问httpd服务(自定义首页内容):
技术图片

访问tomcat服务:
技术图片

在上面的访问测试中,虽然访问到了对应的服务,但是有一个弊端,就是在做DNS解析的时候,只能指定Ingress-nginx容器所在的节点IP。而指定k8s集群内部的其他节点IP(包括master)都是不可以访问到的,如果这个节点一旦宕机,Ingress-nginx容器被转移到其他节点上运行(不考虑节点标签的问题,其实保持Ingress-nginx的yaml文件中默认的标签的话,那么每个节点都是有那个标签的)。随之还要我们手动去更改DNS解析的IP(要更改为Ingress-nginx容器所在节点的IP,通过命令“kubectl get pod -n ingress-nginx -o wide”可以查看到其所在节点),很是麻烦。

有没有更简单的一种方法呢?答案是肯定的,就是我们为Ingress-nginx规则再创建一个类型为nodePort的Service,这样,在配置DNS解析时,就可以使用www.lzj.com 绑定所有node节点,包括master节点的IP了,很是灵活。

6)为Ingress-controller资源对象创建一个service资源对象

在刚才获取Ingress-controller资源对象的yaml文件的页面,然后下拉页面,即可看到以下,可以根据k8s集群环境来选择适合自己的yaml文件。假如自己是在Azure云平台搭建的K8s集群,则选择复制Azure下面的命令即可,我这里是自己的测试环境,所以选择Bare-metal下面的yaml文件,如图:
技术图片
创建这个Service有两种方法:一是直接复制其web页面的命令到master节点上执行,二是将其链接地址复制到终端使用wget下载下来再执行,本次采用第二种方法,顺便可以查看文件中内容。

[root@master ~]# wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/nginx-0.29.0/deploy/static/provider/baremetal/service-nodeport.yaml
[root@master ~]# cat service-nodeport.yaml 
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
    - name: https
      port: 443
      targetPort: 443
      protocol: TCP
  selector:
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx

---
[root@master ~]# kubectl apply -f service-nodeport.yaml 
[root@master ~]# kubectl get svc -n ingress-nginx 
#查看运行的service对象
NAME            TYPE       CLUSTER-IP      EXTERNAL-IP   PORT(S)                      AGE
ingress-nginx   NodePort   10.96.121.169           80:30487/TCP,443:31117/TCP   21s
#可以看到service分别将80和443端口映射到了节点的30487和31111端口(随机映射的,也可以修改yaml文件指定端口)

至此,这个www.lzj.com 的域名即可和群集中任意节点的30487/31111端口进行绑定了。

测试如下(域名解析对应的IP可以是k8s群集内的任意节点IP):
技术图片
技术图片
至此,就实现了最初的需求!

7)创建基于虚拟主机的Ingress规则

如果需要将www.lzj.com 和www.zhj.com 都对应上后端的pod容器所运行的服务。应进行以下配置:

[root@master ~]# vim ingress.yaml 
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: test-ingress
  namespace: test-ns
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  rules:
  - host: www.lzj.com
    http:
      paths:
      - path: /
        backend:
          serviceName: httpd-svc
          servicePort: 80
      - path: /tomcat
        backend:
          serviceName: tomcat-svc
          servicePort: 8080
  - host: www.zhj.com             #就是将原本的域名对应的svc服务复制一份,更改一下域名而已!
    http:
      paths:
      - path: /
        backend:
          serviceName: httpd-svc
          servicePort: 80
      - path: /tomcat
        backend:
          serviceName: tomcat-svc
          servicePort: 8080
[root@master ~]# kubectl apply -f ingress.yaml

至此,即可实现访问www.lzj.com 和www.zhj.com 都可以访问到后端的httpd提供的页面(自行解决域名解析问题),如下:
技术图片
技术图片
技术图片
技术图片

Ingress-nginx资源的流程总结,如图:
技术图片
从图中可以看出:后端有多个pod,pod与service进行关联,service又被ingress规则发现并动态写入到ingress-nginx-controller容器中,然后又为ingress-nginx-controller创建了一个Service映射到群集节点上的端口,来供client来访问。

在真正的生产环境中,创建Ingress Controller肯定使用的是DaemonSet资源类型,来保证Ingress Controller的高可用!

三、配置HTTPS

在上面的操作中,实现了使用ingress-nginx为后端所有pod提供一个统一的入口,那么,有一个非常严肃的问题需要考虑,就是如何为我们的pod配置CA证书来实现HTTPS访问?在pod中直接配置CA么?那需要进行多少重复性的操作?而且,pod是随时可能被kubelet杀死再创建的。当然这些问题有很多解决方法,比如直接将CA配置到镜像中,但是这样又需要很多个CA证书。

在上面的一系列流程中,关键的点就在于ingress规则,我们只需要在ingress的yaml文件中,为域名配置CA证书即可,只要可以通过HTTPS访问到域名,至于这个域名是怎么关联到后端提供服务的pod,这就是属于k8s群集内部的通信了,即便是使用http来通信,也无伤大雅。

配置如下:

为了简单起见,以下配置在上述环境下执行以下配置:

[root@node01 ~]# openssl req -x509 -sha256 -nodes -days 365 -newkey rsa:2048 -keyout tls.key -out tls.crt -subj "/CN=nginxsvc/O=nginxsvc"
#创建CA证书
[root@node01 ~]# ls | grep tls               #确认产生了以下两个文件
tls.crt
tls.key
[root@master ~]# kubectl create secret tls tls-secret --key=tls.key --cert tls.crt
#创建secret资源对象
[root@master ~]# kubectl describe secrets tls-secret 
#查看secret资源对象详细信息
Name:         tls-secret
Namespace:    default
Labels:       
Annotations:  

Type:  kubernetes.io/tls

Data
====
tls.crt:  1143 bytes
tls.key:  1704 bytes
[root@master ~]# vim ingress.yaml
#对Ingresss资源对象进行修改
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: test-ingress
  namespace: test-ns
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  tls:                     #在原本的基础上添加以下内容即可
  - hosts:
    - www.lzj.com
    - www.zhj.com
    secretName: tls-secret                     #填写须使用该证书的域名及证书的名称
  rules:
  - host: www.lzj.com
    http:
      paths:
      - path: /
        backend:
          serviceName: httpd-svc
          servicePort: 80
      - path: /tomcat
        backend:
          serviceName: tomcat-svc
          servicePort: 8080
  - host: www.zhj.com
    http:
      paths:
      - path: /
        backend:
          serviceName: httpd-svc
          servicePort: 80
      - path: /tomcat
        backend:
          serviceName: tomcat-svc
          servicePort: 8080
[root@master ~]# kubectl apply -f ingress.yaml
[root@master ~]# kubectl describe ingresses.  test-ingress -n test-ns 
#查看Ingress-nginx的详细信息
Name:             test-ingress
Namespace:        test-ns
Address:          10.96.121.169
Default backend:  default-http-backend:80 ()
TLS:                       #确认该证书已经绑定到对应的域名上
  tls-secret terminates www.lzj.com,www.zhj.com
Rules:
  Host         Path  Backends
  ----         ----  --------
  www.lzj.com  
               /         httpd-svc:80 (10.244.1.9:80,10.244.2.8:80)
               /tomcat   tomcat-svc:8080 (10.244.1.10:8080,10.244.2.9:8080)
  www.zhj.com  
               /         httpd-svc:80 (10.244.1.9:80,10.244.2.8:80)
               /tomcat   tomcat-svc:8080 (10.244.1.10:8080,10.244.2.9:8080)

访问测试:

技术图片
技术图片
技术图片
技术图片
技术图片

———————— 本文至此结束,感谢阅读 ————————

Kubernetes之Ingress-nginx部署使用

标签:规则   create   重复   data   grep   详细信息   关联   sts   client   

原文地址:https://blog.51cto.com/14157628/2472849


评论


亲,登录后才可以留言!