1 概述
NGINX Ingress Controller 是使用 Kubernetes Ingress 資源對象構建的,用 ConfigMap 來存儲 Nginx 配置的一種 Ingress Controller 實現。
安裝 ingress-nginx 有多種方式,本文使用 helm3.6 方式進行安裝。
其他安裝方式可以參考文檔:https://kubernetes.github.io/ingress-nginx/deploy/
本文 k8s 集群環境是在 centos7 系統上由 kubeadm 搭建的單 master 集群:
[root@k8s-master ~]# kubectl get nodes -o wide
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
master1 Ready master 36d v1.19.3 192.168.5.60 <none> CentOS Linux 7 (Core) 3.10.0-1160.el7.x86_64 docker://19.3.11
node1 Ready <none> 36d v1.19.3 192.168.5.61 <none> CentOS Linux 7 (Core) 3.10.0-1160.el7.x86_64 docker://19.3.11
node2 Ready <none> 36d v1.19.3 192.168.5.62 <none> CentOS Linux 7 (Core) 3.10.0-1160.el7.x86_64 docker://19.3.11
2 helm介紹
Helm 是一個用於對需要在 k8s 上部署的復雜應用進行定義、安裝和更新。Helm 以 Char 的方式對應用軟件進行描述,可以方便地創建、版本化、共享和發布復雜的應用軟件。
- 官方英文文檔:https://helm.sh/docs/
- 官方中文文檔:https://helm.sh/zh/docs/
2.1 helm的主要概念
- Chart
Helm的應用包,采用tgz格式。類似於 Yum 的 RPM 包,其包含了一組定義 Kubernetes 資源相關的 YAML 文件,也稱為應用 Chart。
- Repoistory
Helm 的應用倉庫,Repository 本質上是一個 Web 服務器,該服務器保存了一系列的 Chart 應用包以供用戶下載,並且提供了一個該 Repository 的 Chart 包的清單文件以供查詢,Helm可以同時管理多個不同的Repository。
Helm社區官方提供了stable和incubator倉庫,但Helm社區沒有打算獨占倉庫,而是允許其他人和組織也可以搭建倉庫。倉庫可以是公共倉庫,也可以是私有倉庫。
- Release
在 Kubernetes 集群上運行的 Chart 的一個實例。在同一個集群上,一個 Chart 可以安裝很多次。每次安裝都會創建一個新的 Release。例如一個 MySQL Chart,如果想在服務器上運行兩個 MySQL 數據庫,就可以把這個 Chart 安裝兩次。每次安裝都會生成一個新的Release。
2.2 helm安裝
Helm安裝官方文檔:https://helm.sh/docs/intro/install/
這里安裝 helm v3 版本,直接從 github 下載源碼包:
# 下載
[root@k8s-master ~]# wget https://get.helm.sh/helm-v3.6.0-linux-amd64.tar.gz
# 解壓
[root@k8s-master ~]# tar -zxvf helm-v3.6.0-linux-amd64.tar.gz
# 移動到環境變量目錄里面即可
[root@k8s-master ~]# mv linux-amd64/helm /usr/local/bin/helm
# 輸出版本
[root@k8s-master ~]# helm version
version.BuildInfo{Version:"v3.6.3", GitCommit:"d506314abfb5d21419df8c7e7e68012379db2354", GitTreeState:"clean", GoVersion:"go1.16.5"}
2.3 chart包的目錄結構
# 創建一個chart,chart的名稱叫 helm-test
[root@k8s-master ~]# helm create helm-test
Creating helm-test
[root@k8s-master ~]# cd helm-test/
# 查看 chart 的目錄結構
[root@k8s-master helm-test]# tree .
.
├── charts
├── Chart.yaml
├── templates
│ ├── deployment.yaml
│ ├── _helpers.tpl
│ ├── hpa.yaml
│ ├── ingress.yaml
│ ├── NOTES.txt
│ ├── serviceaccount.yaml
│ ├── service.yaml
│ └── tests
│ └── test-connection.yaml
└── values.yaml
3 directories, 10 files
[root@k8s-master helm-test]#
chart 是 Helm 的應用打包格式。chart 由一系列文件組成,這些文件描述了 Kubernetes 部署應用時所需要的資源。上面通過 helm 命令創建了一個 chart 包,目錄結構說明如下:
helm-test:是 chart 包的名稱charts目錄: 保存依賴文件的目錄,如果依賴其他的 chart,則會保存在這里Chart.yaml文件:用於描述 chart 信息的 yaml 文件,如版本信息等values.yaml文件:chart 支持在安裝的時根據參數進行定制化配置,而 values.yaml 則提供了這些配置參數的默認值,可以在安裝前根據需要修改 values.yaml 的參數templates目錄:各類 Kubernetes 資源的配置模板都放置在這里。Helm 會將 values.yaml 中的參數值注入到模板中生成標准的 YAML 配置文件
3 helm 安裝 ingress-nginx
3.1 添加 ingress-nginx 官方helm倉庫
[root@k8s-master ~]# helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
[root@k8s-master ~]# helm repo update
執行這一步的時候,我報錯了:
[root@k8s-master ~]# helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
Error: looks like "https://kubernetes.github.io/ingress-nginx" is not a valid chart repository or cannot be reached: Get "https://kubernetes.github.io/ingress-nginx/index.yaml": dial tcp [::1]:443: connect: connection refused
可以看到是無法訪問到 https://kubernetes.github.io ,估計是被牆了。ping 一下域名發現解析到了 127.0.0.1:
[root@k8s-master ~]# ping kubernetes.github.io
PING kubernetes.github.io (127.0.0.1) 56(84) bytes of data.
64 bytes from localhost (127.0.0.1): icmp_seq=1 ttl=64 time=0.084 ms
64 bytes from localhost (127.0.0.1): icmp_seq=2 ttl=64 time=0.055 ms
64 bytes from localhost (127.0.0.1): icmp_seq=3 ttl=64 time=0.068 ms
^C
--- kubernetes.github.io ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2000ms
rtt min/avg/max/mdev = 0.055/0.069/0.084/0.011 ms
本地檢查沒有配置 hosts 信息,所以這應該是 DNS 解析的問題,嘗試更換 DNS 服務器,114.114.144.144 或者 8.8.8.8 都是一樣不能訪問。於是找到站長之家,獲取一下 kubernetes.github.io 域名的 IP 地址:

獲取到 IP 地址后,選擇一個IP地址,配置本地hosts解析:
[root@k8s-master ~]# echo "https://ip.tool.chinaz.com/kubernetes.github.io" >> /etc/hosts
然后重新添加倉庫,可以看到已添加成功。
# 添加倉庫
[root@k8s-master ~]# helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
"ingress-nginx" has been added to your repositories
# 更新
[root@k8s-master ~]# helm repo update
Hang tight while we grab the latest from your chart repositories...
...Successfully got an update from the "ingress-nginx" chart repository
Update Complete. ⎈Happy Helming!⎈
3.2 下載ingress-nginx的chart包
[root@k8s-master ~]# cd /usr/local/src/
# 查找ingress-nginx的chart包
[root@k8s-master src]# helm search repo ingress-nginx
NAME CHART VERSION APP VERSION DESCRIPTION
ingress-nginx/ingress-nginx 4.0.1 1.0.0 Ingress controller for Kubernetes using NGINX a...
# 下載下來
[root@k8s-master src]# helm pull ingress-nginx/ingress-nginx
# 以tgz為后綴的包就是我們下載的chart包
[root@k8s-master src]# ls
helm-v3.6.3-linux-amd64.tar.gz ingress-nginx-4.0.1.tgz linux-amd64
# 解壓
[root@k8s-master src]# tar -zxvf ingress-nginx-4.0.1.tgz
# 目錄結構如下
[root@k8s-master src]# cd ingress-nginx
[root@k8s-master ingress-nginx]# ls
CHANGELOG.md Chart.yaml ci OWNERS README.md templates values.yaml
3.3 修改 values.yaml 文件
下載下來的 chart 包,需要修改一下資源清單配置文件,修改 values.yaml 文件如下:
修改 ingress-nginx-contorller 的鏡像倉庫地址,默認是 k8s.gcr.io 國內無法訪問,這里用到github上一個同步 ingress-nginx-contorller 的倉庫 docker.io/willdockerhub/ingress-nginx-controller

修改 hostNetwork 的值為 true:

dnsPolicy的值改為: ClusterFirstWithHostNet

nodeSelector 添加標簽: ingress: "true",用於部署 ingress-controller 到指定節點

kind類型更改為:DaemonSet

kube-webhook-certgen的鏡像地址改為國內倉庫地址 registry.aliyuncs.com/google_containers/kube-webhook-certgen

3.4 執行安裝
資源清單文件修改完成后,執行helm安裝:
# 先創建一個名稱空間
[root@k8s-master ~]# kubectl create ns ingress-nginx
namespace/ingress-nginx created
# 進入chart目錄
[root@k8s-master ~]# cd /usr/local/src/ingress-nginx
# helm安裝
[root@k8s-master ingress-nginx]# helm install ingress-nginx -n ingress-nginx .
NAME: ingress-nginx
LAST DEPLOYED: Wed Sep 15 10:17:09 2021
NAMESPACE: ingress-nginx
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
The ingress-nginx controller has been installed.
It may take a few minutes for the LoadBalancer IP to be available.
You can watch the status by running 'kubectl --namespace ingress-nginx get services -o wide -w ingress-nginx-controller'
An example Ingress that makes use of the controller:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
kubernetes.io/ingress.class:
name: example
namespace: foo
spec:
rules:
- host: www.example.com
http:
paths:
- backend:
serviceName: exampleService
servicePort: 80
path: /
# This section is only required if TLS is to be enabled for the Ingress
tls:
- hosts:
- www.example.com
secretName: example-tls
If TLS is enabled for the Ingress, a Secret containing the certificate and key must also be provided:
apiVersion: v1
kind: Secret
metadata:
name: example-tls
namespace: foo
data:
tls.crt: <base64 encoded cert>
tls.key: <base64 encoded key>
type: kubernetes.io/tls
[root@k8s-master ingress-nginx]#
出現上面的命令輸出表示安裝完成了,安裝完成后,需要給節點打上剛剛設置的標簽ingress=true,讓 Pod 調度到指定的節點,比如調度到 master 節點:
# 給master節點打上標簽 ingress=ture
[root@k8s-master ingress-nginx]# kubectl label node master1 ingress=true
node/master1 labeled
# k8s默認集群中,出於安全考慮,默認配置下Kubernetes不會將Pod調度到Master節點。測試環境無所謂,所以執行下面命令去除master的污點:
[root@k8s-master ingress-nginx]# kubectl taint node master1 node-role.kubernetes.io/master-
執行完成之后,就可以看到 ingress-nginx 部署到了master節點了:
[root@k8s-master ~]# kubectl get all -n ingress-nginx
NAME READY STATUS RESTARTS AGE
pod/ingress-nginx-controller-nldt4 1/1 Running 0 3m45s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/ingress-nginx-controller LoadBalancer 10.103.248.36 <pending> 80:30318/TCP,443:30865/TCP 3m45s
service/ingress-nginx-controller-admission ClusterIP 10.104.51.205 <none> 443/TCP 3m46s
NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE
daemonset.apps/ingress-nginx-controller 1 1 1 1 1 ingress=true,kubernetes.io/os=linux 3m45s
Pod也是部署在了master節點:
[root@k8s-master ~]# kubectl get pods -n ingress-nginx -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
ingress-nginx-controller-nldt4 1/1 Running 0 4m12s 192.168.5.60 master1 <none> <none>
3.5 測試 ingress-nginx
創建后端的 nginx 的 Pod 和 Service:
apiVersion: apps/v1
kind: Deployment
metadata:
name: svc-demo
spec:
replicas: 2
selector:
matchLabels:
app: myapp
template:
metadata:
labels:
app: myapp
spec:
containers:
- image: nginx:1.18.0
name: svc-demo
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: svc-demo
spec:
selector:
app: myapp
ports:
- targetPort: 80 # 后端Pod的端口
port: 8080 # 服務要暴露的端口
查看 Pod 和 Service:
[root@k8s-master service]# kubectl get pods,svc
NAME READY STATUS RESTARTS AGE
pod/svc-demo-f9785fc46-hz6db 1/1 Running 1 7d22h
pod/svc-demo-f9785fc46-m99mj 1/1 Running 1 7d22h
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 36d
service/svc-demo NodePort 10.106.152.13 <none> 8080:31195/TCP 29d
創建 ingress 規則,ingress-nginx.yaml:
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
annotations:
kubernetes.io/ingress.class: "nginx"
name: example
spec:
rules: # 一個ingress可以配置多個rules
- host: foo.bar.com # 域名配置,可以不寫,匹配*,或者寫 *.bar.com
http:
paths: # 相當於nginx的location,同一個host可以配置多個path
- backend:
serviceName: svc-demo # 代理到哪個svc
servicePort: 8080 # svc的端口
path: /
創建ingress:
[root@k8s-master service]# kubectl apply -f ingress-nginx.yaml
[root@k8s-master service]# kubectl get ingress
Warning: extensions/v1beta1 Ingress is deprecated in v1.14+, unavailable in v1.22+; use networking.k8s.io/v1 Ingress
NAME CLASS HOSTS ADDRESS PORTS AGE
example <none> foo.bar.com 80 21m
window的 hosts 配置解析:
192.168.5.60 foo.bar.com
瀏覽器訪問,可以看到已經成功通過ingress將請求轉發到后端Pod上了。

至此,一個簡單的ingress示例就完成了,本文over。
