kubernetes ingress 在物理機上的nodePort和hostNetwork兩種部署方式解析及比較

ingress controller在物理機上的兩種部署方式

ingress controller(ingress-nginx)負責k8s中的7層負載均衡。其在物理機中有多種部署方式。本文中主要選擇了nodePort和hostNetwork兩種部署方式進行介紹。主要緣由是這兩種部署方式不須要藉助於其餘組件,直接使用的是k8s的基礎組件和使用方式,較爲容易理解和排障。html

注:本文中的kube-proxy使用的是iptablesnode

本文使用的ingress-nginx的commit版本是51ad0bc54b1475384b67bee9e8a8e41e26b18bc4。該版本的部署方式是在NGINX: 0.24.1版本後重構了deploy文件夾中的ingress-nginx的部署相關文件。採用了kustomize進行部署配置。所以推薦使用kubectl 1.14以上的版本。且特別注意,下面的命令都是使用了kubectl apply -k的方式運行,而不是-f參數。nginx

deploy各個文件夾走讀

ingress-nginx項目deploy文件夾下有多個文件夾,爲不一樣的環境提供支持。這裏咱們主要介紹的是與在物理機部署相關的幾個文件夾。git

cluster-wide
├── cluster-wide
│   ├── cluster-role-binding.yaml
│   ├── cluster-role.yaml
│   └── kustomization.yaml

cluster-wide文件夾主要用於建立cluster-role和cluster-role-binding,爲ingress-controller提供apiserver的cluster訪問權限。這裏cluster-role-binding.yaml要做一下修改,指定namespace: ingress-nginx。由於在後面建立的ServiceAccount等其餘資源都是默認在該namespace下。github

[root@local cluster-wide]# cat cluster-role-binding.yaml
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
  name: nginx-ingress-clusterrole-nisa-binding
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: nginx-ingress-clusterrole
subjects:
  - kind: ServiceAccount
    name: nginx-ingress-serviceaccount
    namespace: ingress-nginx
cloud-generic
├── cloud-generic
│   ├── deployment.yaml
│   ├── kustomization.yaml
│   ├── role-binding.yaml
│   ├── role.yaml
│   ├── service-account.yaml
│   └── service.yaml

cloud-generic文件夾提供了通用的一些部署文件。其中deployment.yaml是負責建立ingress-controller的deployment,默認副本數爲1,能夠進行調節。service.yaml是爲ingress-controller建立的service。其餘的主要是與帳戶相關的內容。web

baremetal
├── baremetal
│   ├── kustomization.yaml
│   └── service-nodeport.yaml

baremetal文件夾主要是建立了一個NodePort類型的svc,而後向ingress-controller的容器進行導流的。由於該部署方式須要依賴cloud-generic裏的資源,所以在kustomization.yaml中描述了對cloud-generic的依賴。能夠參看kustomization.yaml中的bases。api

[root@local baremetal]# cat deploy/baremetal/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
bases:
- ../cloud-generic
patchesStrategicMerge:
- service-nodeport.yaml

大體瞭解了相關部署文件的功能,那麼結合具體的兩種部署圖(部署圖來自官網),來進行一下具體介紹。網絡

nodePort部署

nodePort

nodePort的部署思路就是經過在每一個節點上開闢nodePort的端口,將流量引入進來,然後經過iptables首先轉發到ingress-controller容器中(圖中的nginx容器),然後由nginx根據ingress的規則進行判斷,將其轉發到對應的應用web容器中。所以採用nodePort部署較爲簡單,直接使用如下命令便可。app

kubectl apply -k deploy/baremetal/
kubectl apply -k deploy/cluster-wide/

hostNetwork部署

hostNetwork

相比較起來,hostNetwork模式再也不須要建立一個nodePort的svc,而是直接在每一個節點都建立一個ingress-controller的容器,並且將該容器的網絡模式設爲hostNetwork。也就是說每一個節點物理機的80和443端口將會被ingress-controller中的nginx容器佔用。當流量經過80/443端口進入時,將直接進入到nginx中。然後nginx根據ingress規則再將流量轉發到對應的web應用容器中。負載均衡

這裏須要對cloud-generic/deployment.yaml進行一下改動,將其資源類型從deployment改成daemonset,而且在spec中添加hostNetwork: true,從而使其能夠使用物理機網絡。

[root@local deploy]# cat cloud-generic/deployment.yaml 
apiVersion: extensions/v1beta1
kind: DaemonSet
metadata:
  name: nginx-ingress-controller
spec:
  template:
    metadata:
      annotations:
        prometheus.io/port: "10254"
        prometheus.io/scrape: "true"
      labels:
        nginx-ingress-controller: 0.24.1
    spec:
      serviceAccountName: nginx-ingress-serviceaccount
      hostNetwork: true
      ...

修改完成後,使用如下命令便可完成hostNetwork模式的部署。

kubectl apply -k deploy/cloud-generic/
kubectl apply -k deploy/cluster-wide/

兩種部署方式的比較

相比較起來,nodePort部署模式中須要部署的ingress-controller容器較少。一個集羣能夠部署幾個就能夠了。而hostNetwork模式須要在每一個節點部署一個ingress-controller容器,所以總起來消耗資源較多。另一個比較直觀的區別,nodePort模式主要佔用的是svc的nodePort端口。而hostNetwork則須要佔用物理機的80和443端口。

從網絡流轉來講,經過nodePort訪問時,該node節點不必定部署了ingress-controller容器。所以還須要iptables將其轉發到部署有ingress-controller的節點上去,多了一層流轉。

另外,經過nodePort訪問時,nginx接收到的http請求中的source ip將會被轉換爲接受該請求的node節點的ip,而非真正的client端ip。

而使用hostNetwork的方式,ingress-controller將會使用的是物理機的DNS域名解析(即物理機的/etc/resolv.conf)。而沒法使用內部的好比coredns的域名解析。

所以具體使用哪一種部署方式,須要根據實際狀況和需求進行選擇。

ingress controller試用

在部署好ingress controller後,能夠經過一個樣例進行測試使用。首選建立一個應用容器和以及一個對應的svc。

kubectl run web --image=gcr.azk8s.cn/google-samples/hello-app:1.0 --port=8080
kubectl expose deployment web --target-port=8080

而後建立ingress,將經過hello-world.info域名訪問ingress的請求轉發到該容器中去。

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: example-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
 rules:
 - host: hello-world.info
   http:
     paths:
     - path: /*
       backend:
         serviceName: web
         servicePort: 8080

這一切完成後,在/etc/hosts裏綁定域名,127.0.0.1 hello-world.info

sed -i '$a 127.0.0.1 hello-world.info' /etc/hosts

而後經過curl命令進行測試。

root@i-5i2mhmaus9v67pz19zmahp07u:~# curl 127.0.0.1
<html>
<head><title>404 Not Found</title></head>
<body>
<center><h1>404 Not Found</h1></center>
<hr><center>nginx/1.15.10</center>
</body>
</html>

root@i-5i2mhmaus9v67pz19zmahp07u:~# curl hello-world.info 
Hello, world!
Version: 1.0.0
Hostname: web-77f97c6cc7-g7qft

這裏能夠看到,咱們訪問本地127.0.0.1的時候,會返回404錯誤。而訪問綁定的域名,就能夠正確導流了,返回正確結果。

參考資料

相關文章
相關標籤/搜索