原文

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

三种常用的部署模式

Deployment+LoadBalancer模式的service
用Deployment部署igress-controller,创建一个type为LoadBalancer的service关联这组pod。大部分公有云,都会为LoadBalancer的service自动创建一个负载均衡器,通常还绑定了公网地址。只要把域名解析指向改地址,就实现了集群服务的对外暴露

Deployment+NodePort模式的service
同样用deployment模式部署ingress-controller,然后创建对应的ingress svc,type为NodePort。这样,ingress就会暴露在集群节点ip的特定端口上。由于nodeport暴露的端口是随机端口,一般会在前面再搭建一套负载均衡器来转发请求。改方式一般用于宿主机是相对固定的环境ip地址不变的场景。
NodePort方式暴露ingress虽然简单方便,但是NodePort多了一层NAT,在请求量级很大时可能对性能会有一定的影响

DaemonSet+HostNetwork(+nodeSelector)
用DaemonSet 结合nodeselector来部署ingress-controller到特定的Node上,然后使用HostNetwork直接把该pod与宿主机node的网络打通,直接使用宿主机的80/443端口就能访问服务。这时,ingress-controller所在的node机器就很类似传统架构的边缘节点,比如机房的入口nginx服务器。该方式整个请求链路最简单,性能相对nodeport模式更好。缺点是由于直接利用宿主机节点的网络和端口,一个node只能部署一个ingress-controller pod。比较适合大并发的生产环境使用。

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 地址:

img

获取到 IP 地址后,选择一个IP地址,配置本地hosts解析:

[root@k8s-master ~]# echo "185.199.108.153 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 --version 4.0.1

# 以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

img

修改 hostNetwork 的值为 true

img

dnsPolicy的值改为: ClusterFirstWithHostNet

img

nodeSelector 添加标签: ingress: "true",用于部署 ingress-controller 到指定节点

img

kind类型更改为:DaemonSet

img

kube-webhook-certgen的镜像地址改为国内仓库地址 registry.aliyuncs.com/google_containers/kube-webhook-certgen

img

3.4 执行安装

资源清单文件修改完成后,执行helm安装:

# 先创建一个名称空间
[root@k8s-master ~]# kubectl create ns ingress-nginx

[root@k8s-master ~]# kubectl label node node-01 ingress=true

# 进入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 node-01 ingress=true
node/node-01 labeled

# k8s默认集群中,出于安全考虑,默认配置下Kubernetes不会将Pod调度到Master节点。测试环境无所谓,所以执行下面命令去除master的污点:
[root@k8s-master ingress-nginx]# kubectl taint node master1 node-role.kubernetes.io/master-

注意: 如果安装失败,比如一直卡着不动,那就把下图中的 enabled: true 改为 enabled: false
另外执行 kubectl delete validatingwebhookconfigurations.admissionregistration.k8s.io ingress-nginx-admission

在这里插入图片描述

执行完成之后,就可以看到 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上了。

img

至此,一个简单的ingress示例就完成了,本文over。

4 参考资料

Logo

K8S/Kubernetes社区为您提供最前沿的新闻资讯和知识内容

更多推荐