Kubernetes之Ingress-nginx部署使用

博文大綱:
一、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   <none>        80/TCP     13m
tomcat-svc   ClusterIP   10.99.184.215   <none>        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文件,方法如下:
Kubernetes之Ingress-nginx部署使用
Kubernetes之Ingress-nginx部署使用
Kubernetes之Ingress-nginx部署使用
Kubernetes之Ingress-nginx部署使用
Kubernetes之Ingress-nginx部署使用

[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 < nginx-ingress.tar 
#node01節點導入鏡像(也可自行下載)
[root@master ~]# kubectl apply -f mandatory.yaml 

關於上面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   <none>           <none>

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服務(自定義首頁內容):
Kubernetes之Ingress-nginx部署使用

訪問tomcat服務:
Kubernetes之Ingress-nginx部署使用

在上面的訪問測試中,雖然訪問到了對應的服務,但是有一個弊端,就是在做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文件,如圖:
Kubernetes之Ingress-nginx部署使用
創建這個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   <none>        80:30487/TCP,443:31117/TCP   21s
#可以看到service分別將80和443端口映射到了節點的30487和31111端口(隨機映射的,也可以修改yaml文件指定端口)

至此,這個www.lzj.com 的域名即可和羣集中任意節點的30487/31111端口進行綁定了。

測試如下(域名解析對應的IP可以是k8s羣集內的任意節點IP):
Kubernetes之Ingress-nginx部署使用
Kubernetes之Ingress-nginx部署使用
至此,就實現了最初的需求!

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提供的頁面(自行解決域名解析問題),如下:
Kubernetes之Ingress-nginx部署使用
Kubernetes之Ingress-nginx部署使用
Kubernetes之Ingress-nginx部署使用
Kubernetes之Ingress-nginx部署使用

Ingress-nginx資源的流程總結,如圖:
Kubernetes之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:       <none>
Annotations:  <none>

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 (<none>)
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部署使用
Kubernetes之Ingress-nginx部署使用
Kubernetes之Ingress-nginx部署使用
Kubernetes之Ingress-nginx部署使用
Kubernetes之Ingress-nginx部署使用

———————— 本文至此結束,感謝閱讀 ————————

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章