weixueyuan-Nginx在Kubernetes10
https://www.weixueyuan.net/nginx/kubernetes/
Kubernetes(k8s)分布式容器管理系统简述
Kubernetes 是分布式容器管理系统,它提供了对容器快速部署、网络规划、负载调度及宿主机节点自动化更新和维护的管理机制,使容器自动化按照用户期望的方式运行。
图:Kubernetes 架构
具体说明如下。
一个 Kubernetes 集群可包括多个 Node 节点,每个 Node 节点上运行了网络、代理及管理组件。Kubernetes 节点架构如下图所示。
图:Kubernetes 节点架构
具体说明如下。
Kubernetes 中被管理的资源对象会因版本不同而变化,如下所示。
标签键值(value)的长度最多 63 个字符,必须以字母或数字为首字符,也可以为空。每个资源实例与标签是多对多的关系,可以在资源实例初始时定义标签,也可以动态添加或删除。
Kubernetes 通过管理控制服务来管理资源对象,管理控制服务由一系列资源控制器(Controller)组成,有如下几种。
本章涉及资源配置的资源接口版本(apiVersion)、资源类型(kind)、元数据(metadata)、规范(spec)四个部分。
资源配置样例如下。
创建名为 nginx-svc 的服务资源实例,将资源实例 nginx-svc 以 NodePort 类型对外开放端口 30080,对应的 Service 端口为 8080,Pod 端口为 80。
执行 kubeadm init 命令时自动执行如下动作。
该命令的其他参数如下。
当 Master 节点被 kubeadm 初始化成功后,会提示将 /etc/kubernetes/admin.conf 复制到 kubectl 控制机或非 root 用户的 Home 目录中。该命令的其他参数如下。
使用
图:Helm 工作逻辑
关于 Helm 的几点说明如下。
常用的 Helm 命令如下。
1、Kubernetes架构简述
与大多数分布式系统一样,Kubernetes 集群由主节点(Master)和多个从节点(Node)组成,集群中运行多个应用组件,是计算、存储、网络资源的集合,为运行的各种应用提供资源管理、调度和维护等功能。Kubernetes 架构如下图所示。图:Kubernetes 架构
具体说明如下。
- Kubernetes 集群中被操作控制的资源称为资源对象,如 Pod、Node、Service 都被看作资源对象;
- kubectl 是 Kubernetes 的命令行管理工具,该工具与 Web UI 一样,可以通过 Kuber-netes 主节点的接口服务(API Server)查看及进行创建、删除或更新资源对象等操作;
- Kubernetes 主节点的核心组件包括接口服务(API Server)、调度服务(Scheduler)、控制管理服务(Controller Manager)和存储服务(etcd);
- 接口服务提供了资源对象操作的统一入口,提供认证、授权、访问控制等功能,以 REST API 方式对外提供服务,允许各类组件创建、删除、更新或监视资源;
- 调度服务按照编排的调度策略将运行容器(Pod)根据集群资源和状态选择合适的 Node 进行创建;
- 控制管理服务负责维护整个集群的状态,包括滚动更新、自动扩缩容、故障检测等;
- 存储服务用于存储整个集群各种配置及资源实例的状态,实现配置共享和服务发现等功能。
一个 Kubernetes 集群可包括多个 Node 节点,每个 Node 节点上运行了网络、代理及管理组件。Kubernetes 节点架构如下图所示。
图:Kubernetes 节点架构
具体说明如下。
- kube-proxy 负责为 Pod 提供网络代理和负载均衡等功能;
- Kubernetes 并未提供专门的网络组件实现网络功能,目前常用的是 flannel,它通过 CNI(Container Network Interface,容器网络接口)方式与 Kubernetes 集成,提供网络功能;
- kubelet 是运行在每个节点上的节点代理服务,可以实现每个节点上的 Pod 管理及监控,并接收主节点组件下发的各种管理任务;
- Pod 是 Kubernetes 中最基本的管理单位,是在 Docker 容器上的一层封装,一个 Pod 可包含多个容器,可以实现内部运行容器的资源共享;
- CRI(Container Runtime Interface,容器运行时接口)是 Kubernetes 中用来与底层容器(如 Docker)进行通信的接口,可对容器执行启停等操作。
2、Kubernetes相关术语
Kubernetes 提供了容器运行时各种资源自动化调度与管理的强大功能,为应对各种复杂环境的自动化管理操作,Kubernetes 系统中定义了很多术语,可分为资源对象、资源控制器、资源配置和管理工具 4 类。1) 资源对象
资源对象指 Kubernetes 中所有被管理的资源,如 Pod、节点、服务都属于资源对象。可以通过接口服务对 Kubernetes 集群中的所有资源对象进行增、删、改、查操作,资源对象相关数据被持久化保存在存储服务中。Kubernetes 中被管理的资源对象会因版本不同而变化,如下所示。
① Pod
Pod 是 Kubernetes 中的核心资源,每个 Pod 可包含多个容器,每个运行的 Pod 由一个名为 pause 的沙盒容器(Sandbox Container,也称基础容器)与一个或多个应用容器组成。基础容器为 Pod 中的应用容器提供如下功能。- 共享 PID 命名空间,Pod 中的应用程序可以查看彼此的进程 ID;
- 共享网络命名空间,Pod 中的不同容器共同使用一个 IP 和端口范围;
- 共享 IPC 命名空间,Pod 中的不同容器的应用可以使用 SystemV IPC 或 POSIX 消息队列进行通信;
- 共享 UTS 命名空间,Pod 中的所有容器共享同一个主机名及共享 Pod 级别定义的存储卷(Volume)。
② Node
Node 是指 Kubernetes 集群中运行 Pod 的宿主机,每个 Node 都会运行节点代理服务(kubelet),负责各 Node 运行 Pod 容器的管理、监控,并向主节点汇报运行容器的状态,同时接收并执行主节点下发的任务。通过管理工具可对 Node 资源进行添加、删除及隔离等操作。③ 标签
标签(Label)是与资源对象关联的键值对,用以标识资源实例的特征,方便用户对资源实例通过自定义标识进行归类。标签键(key)的长度最多 63 个字符,必须以字母或数字为开始和结束的字符,中间可以有“_”“-”“.”做连接符。标签键值(value)的长度最多 63 个字符,必须以字母或数字为首字符,也可以为空。每个资源实例与标签是多对多的关系,可以在资源实例初始时定义标签,也可以动态添加或删除。
④ 注解
注解(Annotation)也是与资源对象关联的键值对,用以对资源实例的内置属性进行描述。注解键值对不能用于资源实例的标识及选择,但资源实例被描述的属性数据可以被管理工具或系统扩展使用。注解键值对可以使用标签不允许的字符,可用于资源实例运行时的外部设置,使资源实例在注解值不同时实现不同的运行状态。⑤ 服务
服务(Service)定义了由多个具有相同服务名称标签的 Pod 组成的虚拟网络集群,其负责虚拟集群内 Pod 的负载均衡和自动发现,每个服务会被分配一个全局唯一固定的虚拟 IP(Cluster IP),Kubernetes 集群内的所有应用都可以通过 Cluster IP 与这个服务实现 TCP 通信。⑥ 端点
资源对象端点(Endpoint)表示一个由 Pod IP 和端口组成的可被访问的网络访问点,是构成 Service 的基础单位,每个 Service 负责实现端点列表中端点的负载均衡和网络请求转发。⑦ 配置映射
配置映射(ConfigMap)提供了一种类似于配置中心的配置使用方法。应用容器的内容是在制作镜像时打包好的,如果要修改容器的内容,通常都需要重新制作镜像。日常使用中,会遇到很多只简单修改应用配置文件的需求,通过配置映射将配置变量或文件存储在存储服务 etcd 中,应用容器可以在运行的系统中以环境变量或挂载文件的方式使用这些配置变量。⑧ 命名空间
命名空间(Namespace)是 Kubernetes 集群用于对资源进行管理的逻辑集合,不同命名空间的资源实例逻辑间是彼此隔离的。不同命名空间可通过设定资源配额、网络策略、RBAC 策略进行资源实例的管控。网络策略需要网络插件的支持,如 Flannel 并没有提供网络策略的支持,所以无法实现网络隔离。2) 资源控制器
资源控制器用以实现每个资源对象的具体操作,每个资源对象都由对应的控制器进行管理和控制。Kubernetes 通过各种控制器跟踪和对比存储服务中已保存资源实例的期望状态与当前集群中运行的资源实例的实际状态的差异来实现自动控制和纠错。Kubernetes 通过管理控制服务来管理资源对象,管理控制服务由一系列资源控制器(Controller)组成,有如下几种。
① 副本控制器
副本控制器(Replication Controller,RC)与进程管理器类似,用以监控集群中所有节点上的 Pod,并确保每个 Pod 都有设定数量的副本在运行。如果运行的 Pod 数量大于设定的数量,则关闭多余的 Pod;反之,则启用足够数量的新 Pod。② 副本集
副本集(Replica Set,RS)在 RC 原有功能的基础上提供了更多的增强工具,它主要被部署控制器(Deployment Controller)作为协调 Pod 创建、删除和更新使用。RS 也被称为下一代副本控制器,官方已经推荐使用部署控制器管理 RS(而不是 RC)。③ 部署控制器
部署控制器用来管理无状态应用,它通过资源对象 Deployment 的配置与 RS 组合来管理 Pod 的多个副本,确保 Pod 按照资源配置描述的状态运行。部署控制器完成资源对象 Deployment 实例的创建过程,由 RS 协助实现 Pod 副本的创建,并随时监控 Deployment 资源实例的部署状态,当部署状态不稳定时,可将 Pod 回滚到之前的 Deployment 资源实例版本。④ DaemonSet控制器
DaemonSet 控制器可确保以该模式部署的 Pod 应用,在集群中的每个 Node 上都有一个 Pod 副本在运行,如果集群中增加了新的 Node,也会自动在该 Node 创建该应用的 Pod 副本,常用来部署全局使用的日志采集、监控、系统管理等容器应用。⑤ StatefulSet控制器
StatefulSet 控制器是用来管理有状态应用的,能够保证其管理的 Pod 的每个副本在整个生命周期中名称不变。通常每个 Pod 在被删除重建或重启后名称(PodName和HostName)都会变化,而 StatefulSet 控制器可以使 Pod 副本相关信息不变,也可以按照固定的顺序启动、更新或删除。StatefulSet 控制器通常用来解决有状态服务的管理和维护。⑥ 端点控制器
端点控制器(Endpoint Controller)负责与服务对应端点列表的生成和维护,监听服务及其对应 Pod 的变化。服务被创建或修改时,端点控制器根据服务信息获得其所有 Pod 的 IP 和端口信息,并创建或更新同名的端点对象列表。当服务被删除时,同名的端点列表也会被删除。kube-proxy 服务通过获取每个服务对应的端点列表,实现服务的负载均衡和数据转发配置。⑦ 服务控制器
服务控制器(Service Controller)是属于 Pod 应用对外发布服务的一个接口控制器,可通过 ClusterIP、NodePort、LoadBalancer、ExternalName 和 externalIPs 方式实现 Pod 应用的对外服务访问。服务控制器监听资源对象服务的变化,当服务是 LoadBalancer 类型时,确保外部的云平台上对该服务对应的 LoadBalancer 实例被相应地创建、删除及路由转发表的更新。3) 资源配置
资源配置是由用户编写来描述资源实例期望状态的 Yaml 格式数据或文本,每个资源对象被通过对应的资源接口创建或修改资源实例,并通过资源控制器使资源实例按照资源配置文件中描述的期望状态运行。本章涉及资源配置的资源接口版本(apiVersion)、资源类型(kind)、元数据(metadata)、规范(spec)四个部分。
① 资源接口版本
因 Kubernetes 本身也在快速迭代,所以 Kubernetes 每次更新一个版本时,就会为被改变内容的资源接口创建一个新的版本,所以在编写资源配置时,需要先声明被操作资源接口的版本,以确保所描述的操作内容可被正常解析和执行。可使用如下命令查看当前 Kubernetes 集群接口服务支持的接口版本。kubectl api-versions
② 资源类型
资源类型用以声明需要操作的资源类型名称,资源类型包括一个或多个可被操作的资源对象,常见的资源类型有 Service、Deployment、Pod、Ingress。可使用如下命令查看当前 Kubernetes 集群接口服务可操作的资源对象名称和所属资源类型。kubectl api-resources
③ 元数据
元数据用以对当前操作的资源实例进行标识,元数据可以包括实例名称(name)、实例所在命名空间(namespace)、实例标签(label)、实例注解(Annotation)等信息。④ 规范
规范用以描述被操作的资源实例在 Kubernetes 集群中的执行规范和被期望达成的状态。资源配置样例如下。
创建名为 nginx-svc 的服务资源实例,将资源实例 nginx-svc 以 NodePort 类型对外开放端口 30080,对应的 Service 端口为 8080,Pod 端口为 80。
apiVersion: v1 # 调用资源接口版本为v1 kind: Service # 资源类型为Service metadata: name: nginx-svc # 资源实例名称为nginx-svc namespace: webapps # 资源实例所属命名空间为webapps labels: app: nginx-svc # 资源实例的标签为nginx-svc spec: type: NodePort # 服务类型为NodePort ports: - port: 8080 # 服务的端口为8080 nodePort: 30080 # NodePort对外开放的端口为30080 targetPort: 80 # Pod应用的端口为80 selector: app: nginx-web # 服务用于筛选对应Pod的标签名为nginx-web
4) 管理工具
管理工具是用于与 Kubernetes 交互来实现资源对象操作的执行程序,资源配置文件就是通过管理工具提交给 Kubernetes 接口服务完成相关资源对象操作的。① 集群部署工具kubeadm
kubeadm 是 Kubernetes 官方推荐的部署工具之一,可以实现 Kubernetes 集群容器化的快速部署。Master 节点只需执行 kubeadm init 即可完成 Master 组件的自动化部署,Node 节点只需执行 kubeadm join 即可完成加入指定 Kubernetes 集群的操作。执行 kubeadm init 命令时自动执行如下动作。
- 系统环境检查;
- 生成 Master token;
- 生成自签名的 CA 和 Client 证书;
- 生成 kubeconfig 用于 kubelet 服务连接 API server;
- 初始化并启动 kubelet 服务;
- 为 Master 各组件生成静态 Pod 配置(Static Pod manifests)并创建 Pod 应用,Master 组件运行命名空间为 kube-system;
- 配置 RBAC;
- 添加 kube-proxy 和 CoreDNS 附加服务。
该命令的其他参数如下。
# 初始化主节点 kubeadm init # 查看token kubeadm token list # 重新生成token kubeadm token generate # 清空kubeadm设置 kubeadm reset
② 资源管理工具kubectl
kubectl 是 Kubernetes 的资源管理客户端程序,可以通过 Kubernetes Master 的接口服务(API Server)查看及进行创建、删除或更新资源对象等操作。通常建议在非 Master 节点主机运行或在 Master 节点上以非 root 权限用户运行。当 Master 节点被 kubeadm 初始化成功后,会提示将 /etc/kubernetes/admin.conf 复制到 kubectl 控制机或非 root 用户的 Home 目录中。该命令的其他参数如下。
# 查看节点状态 kubectl get nodes # 查看集群状态 kubectl get cs # 查看所有事件 kubectl get events --all-namespaces # 查看所有Pod kubectl get pods --all-namespaces -o wide # 查看所有服务 kubectl get services --all-namespaces -o wide # 扩缩容,将以deployment部署方式部署的Pod资源实例nginx的副本数设定为3 kubectl scale --replicas=3 deployment/nginx # 编辑配置,编辑资源对象Service实例名为nginx的资源配置 kubectl edit service/nginx为了更方便地扩展资源管理工具的功能,kubectl 通过插件机制允许开发者以独立文件的形式发布自定义的 kubectl 子命令。kubectl 插件可以使用任意语言开发,可以是一个 Bash 或 Python 的脚本,也可以是其他语言开发编译的二进制可执行文件,只要最终将脚本或二进制可执行文件以 kubectl- 为前缀命名,并存放到 /root/.krew/bin/ 目录中即可。
使用
kubectl plugin list
命令可以查看有哪些插件。krew 是 kubectl 插件的管理器,使用 krew 可以轻松查找、安装和管理 kubectl 插件。krew 本身也是一个 kubectl 插件。krew 相关的命令如下。# 安装kubectl插件krew curl -fsSLO "https://storage.googleapis.com/krew/v0.2.1/krew.{tar.gz,yaml}" tar zxvf krew.tar.gz ./krew-linux_amd64 install --manifest=krew.yaml --archive=krew.tar.gz echo "export PATH=\"\${KREW_ROOT:-\$HOME/.krew}/bin:\$PATH\"" >>/etc/profile source /etc/profile # 更新插件列表 kubectl krew update # 查看插件列表 kubectl krew list
③ 应用部署工具Helm
Helm 并非官方提供的工具,而是 Deis 公司(已被微软收购)开发的用于 Kubernetes 下应用部署、更新、卸载的管理工具。Helm 类似于 Linux 操作系统中的包管理工具,如 CentOS 下使用的 yum。Helm 让 Kubernetes 的用户可以像安装软件包一样,轻松查找、部署、升级或卸载各种应用。Helm 的工作逻辑如下图所示。图:Helm 工作逻辑
关于 Helm 的几点说明如下。
- Helm 管理的安装包被称为 Chart;
- Chart 存储在远端的 Charts 仓库(Repository);
- Tiller 是 Helm 的服务端,以 Pod 方式部署在 Kubernetes 中,负责接收 Helm 客户端的控制命令,解析 Chart 并调用接口服务完成应用的部署和配置。
常用的 Helm 命令如下。
# 初始化Helm helm init # 查看当前安装的应用 helm list # 安装应用 helm install --namespace kubeapps --name kubeapps bitnami/kubeapps # 删除应用 helm delete --purge kubeapps
Kubernetes(k8s)集群部署详解
Kubernetes 集群支持多种方式部署,kubeadm 是 Kubernetes 官方提供的用于快速部署 Kubernetes 集群的工具,本节将使用 kubeadm 实现 Kubernetes 集群样例的快速部署。部署规划如下表所示。
图:Flannel 接口信息
用如下命令可以查看主节点运行 Pod 的状态。
名称 | IP | 主机名 |
---|---|---|
Master 节点 | 10.10.4.17 | vm417centos-master.kube |
从节点 | 10.10.4.26 | vm426centos-node01.kube |
Pod 网络 | 172.172.0.0/16 | -- |
1、系统初始化
分别在 Master 和 Node 主机进行系统初始化,此处使用的操作系统版本为 CentOS 7.2。# 关闭setenforce setenforce 0 sed -i "s/SELINUX=enforcing/SELINUX=disabled/g" /etc/selinux/config # 关闭默认防火墙 systemctl stop firewalld systemctl disable firewalld # 配置hosts,实现本地主机名解析 echo "10.10.4.17 vm417centos-master.kube 10.10.4.26 vm426centos-node01.kube" >> /etc/hosts # 配置系统内核参数,因网桥工作于数据链路层,数据默认会直接经过网桥转发,为避免iptables的FORWARD # 设置失效,需要启用bridge-nf机制 cat <<EOF > /etc/sysctl.d/k8s.conf net.bridge.bridge-nf-call-ip6tables = 1 net.bridge.bridge-nf-call-iptables = 1 net.ipv4.ip_forward = 1 vm.swappiness=0 EOF # 使内核参数配置生效 sysctl --system # 关闭交换内存,如果不关闭,kubelet服务将无法启动 swapoff -a # 安装docker-ce,Kubernetes与Docker存在版本兼容问题,Kubernetes最新版本v1.15,最高支持 # Docker 18.09版本,所以需要安装指定的Docker版本 yum install -y yum-utils yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo yum install -y docker-ce-18.09.0-3.el7 docker-ce-cli-18.09.0-3.el7 containerd.io-1.2.0-3.el7 ebtables ethtool systemctl enable docker systemctl start docker # 优化Docker cgroup驱动,Kubernetes文档指出,使用systemd作为init system的Linux系统中, # cgroup driver为systemd模式可以确保服务器节点在资源紧张时的稳定性 yum install -y systemd cat >/etc/docker/daemon.json<<EOF { "exec-opts": ["native.cgroupdriver=systemd"] } EOF systemctl restart docker # 查看确认 docker info | grep Cgroup # 配置kubernetes yum源,用以安装Kubernetes基础服务及工具,此处使用阿里云镜像仓库源 cat > /etc/yum.repos.d/kubernetes.repo <<EOF [kubernetes] name=Kubernetes baseurl=https://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64/ enabled=1 gpgcheck=0 EOF # 安装Kubernetes基础服务及工具 yum install -y kubeadm kubelet kubectl kompose kubernetes-cni systemctl enable kubelet.service
2、部署Master节点
Master 节点理论上只需要接口服务、调度服务、控制管理服务、状态存储服务,但 kubeadm 以 Pod 形式部署 Master 组件,所以在 Master 节点主机上仍需要部署 kubelet 服务,kubeadm 在初始化时会自动对 kubelet 服务进行配置和管理。# 设置主机名,kubeadm识别主机名时有严格的规范,主机名中需要有“-”或“.” hostnamectl --static set-hostname vm417centos-master.kube # 使用kubeadm初始化Master节点,建议使用阿里云镜像仓库 kubeadm init --pod-network-cidr=172.172.0.0/16 \ # 设置Pod网段IP为172.172.0.0/16 --image-repository registry.cn-hangzhou.aliyuncs.com/google_containers \ # 设置从阿里云镜像仓库下载 --kubernetes-version v1.15.1 # 下载Kubernetes的v1.15.1版本Master 节点初始化成功后,会提示成功并输出 token 和 discovery-token-ca-cert-hash,用于将 Node 加入所指定 Master 的 Kubernetes 集群。Kubernetes 本身并没有集成网络功能,需要单独安装网络插件实现 Kubernetes 集群中 Pod 的网络功能,此处安装网络组件 Flannel。
# 初始化kubectl配置,建议在非root或单独的管理机上配置kubectl管理环境 echo "export KUBECONFIG=/etc/kubernetes/admin.conf" >> ~/.bash_profile source ~/.bash_profile # 获取网络组件Flannel的资源配置文件 wget https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml # 修改Pod网段IP为自定义的172.172.0.0/16 sed -i "s#10.244.0.0/16#172.172.0.0/16#g" kube-flannel.yml # 创建应用 kubectl apply -f kube-flannel.yml网络组件安装后,可以在网络接口上看到 cni0 和 flannel.1,如下图所示。
图:Flannel 接口信息
用如下命令可以查看主节点运行 Pod 的状态。
kubectl get pods --all-namespaces -o wide
3、部署Node
# 设置主机名,kubeadm识别主机名时有严格的规范,主机名中需要有“-”或“.” hostnamectl --static set-hostname vm426centos-node01.kube # 加入Kubernetes集群 kubeadm join 10.10.4.17:6443 --token rk1zux.esj6fnjz3xlms3rv \ --discovery-token-ca-cert-hash sha256:f8371d489b9f67f630199a03754ceffa83d850f06db039a60fc9b170c20e5826 # 在Master节点通过命令查看节点状态 kubectl get nodes
4、部署kubernetes-dashboard
kubernetes-dashboard 是 Kubernetes 社区中一个很受欢迎的项目,它为 Kubernetes 用户提供了一个可视化的 Web 前端,通过 Web 前端可以查看当前集群的各种信息,为用户管理维护 Kubernetes 集群提供帮助。# 获取资源配置文件 wget https://raw.githubusercontent.com/kubernetes/dashboard/v1.10.1/src/deploy/recommended/kubernetes-dashboard.yaml # 修改镜像仓库为阿里云仓库 sed -i "s/k8s.gcr.io/registry.cn-hangzhou.aliyuncs.com\/google_containers/g" kubernetes-dashboard.yaml # 设置端口映射方式为NodePort,映射端口为31443 sed -i '/spec:/{N;s/ ports:/ type: NodePort\n&/g}' kubernetes-dashboard.yaml sed -i "/targetPort: 8443/a\ nodePort: 31443" kubernetes-dashboard.yaml # 部署Pod应用 kubectl apply -f kubernetes-dashboard.yamlkubernetes-dashboard 有 Kubeconfig 和 Token 两种认证登录方式,此处选择 Token 方式认证登录。此处 Kubernetes 的资源类型——服务账户(Service Account)创建 admin-user 账户并授权为 Cluster-Role 的管理角色。
# 创建admin-user账户及授权的资源配置文件 cat>dashboard-adminuser.yml<<EOF apiVersion: v1 kind: ServiceAccount metadata: name: admin-user namespace: kube-system --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: admin-user roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: cluster-admin subjects: - kind: ServiceAccount name: admin-user namespace: kube-system EOF # 创建资源实例 kubectl create -f dashboard-adminuser.yml # 获取账户admin-user的Token用于登录 kubectl -n kube-system describe secret $(kubectl -n kube-system get secret | grep admin-user | awk '{print $1}')kubernetes-dashboard 的 Pod 运行成功后,可以在浏览器上通过集群中的任意 Node IP 和 31443 端口访问 kubernetes-dashboard,通过 Token 登录后就可以通过 Web 界面进行 Kubernetes 集群的管理和维护。
5、部署管理工具Helm
Helm 客户端程序需要使用 Kubernetes 管理工具 kubectl,所以要先确认安装 Helm 主机的 kubectl 可用,如果不可用则需要先安装。1) 安装kubectl
配置样例如下:# 配置Kubernetes安装源 cat > /etc/yum.repos.d/kubernetes.repo <<EOF [kubernetes] name=Kubernetes baseurl=https://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64/ enabled=1 gpgcheck=0 EOF # 安装kubectl yum install -y kubectl # 初始化配置目录 mkdir -p $HOME/.kube # 将Master节点主机的文件/etc/kubernetes/admin.conf复制到kubectl控制机 scp Master:/etc/kubernetes/admin.conf $HOME/.kube/config
2) 安装Helm
配置样例如下:# 下载Helm客户端 wget https://get.helm.sh/helm-v2.14.2-linux-amd64.tar.gz tar -zxvf helm-v2.14.2-linux-amd64.tar.gz mv linux-amd64/helm /usr/sbin/ mv linux-amd64/tiller /usr/sbin/ helm help # 添加阿里云仓库 helm repo add aliyun-stable https://acs-k8s-ingress.oss-cn-hangzhou.aliyuncs.com/charts helm repo update # 将Tiller应用安装到Kubernetes集群并使用阿里云的charts仓库 helm init --upgrade -i registry.cn-hangzhou.aliyuncs.com/google_containers/tiller:v2.14.2 --stable-repo-url https://kubernetes.oss-cn-hangzhou.aliyuncs.com/charts # 添加Tiller授权 kubectl create serviceaccount --namespace kube-system tiller kubectl create clusterrolebinding tiller-cluster-rule --clusterrole=cluster-admin --serviceaccount=kube-system:tiller kubectl patch deploy --namespace kube-system tiller-deploy -p '{"spec":{"template": {"spec":{"serviceAccount":"tiller"}}}}'
3) 安装Helm的Web管理工具Kubeapps
Kubeapps 是 Helm 的 Web 化管理工具,提供了比命令行更丰富的应用安装说明和更便捷的安装方式。# 添加bitnami的charts仓库 helm repo add bitnami https://charts.bitnami.com/bitnami # 安装Kubeapps,命名为kubeapps,所属命名空间为kubeapps helm install --namespace kubeapps --name kubeapps bitnami/kubeapps # 创建Kubeapps账号 kubectl create serviceaccount kubeapps-operator kubectl create clusterrolebinding kubeapps-operator --clusterrole=cluster-admin --serviceaccount=default:kubeapps-operator # 创建服务,提供NodePort类型的访问端口30080 cat>kubeapps-service.yml<<EOF apiVersion: v1 kind: Service metadata: name: kubeapps-svc namespace: kubeapps labels: app: kubeapps spec: type: NodePort ports: - port: 8080 nodePort: 30080 selector: app: kubeapps EOF # 在集群中创建资源实例 kubectl create -f kubeapps-service.yml # 获取登录token kubectl get secret $(kubectl get serviceaccount kubeapps-operator -o jsonpath= '{.secrets[].name}') -o jsonpath='{.data.token}' | base64 --decode在浏览器上通过端口 30080 就可以访问应用 Kubeapps。
Kubernetes(k8s)网络通信详解
计算机间的信息和数据在网络中必须按照数据传输的顺序、数据的格式内容等方面的约定或规则进行传输,这种约定或规则称作协议。各种网络协议分布于不同的网络分层中,网络分层分为 OSI 七层模型和 TCP/IP 五层模型两种。TCP/IP 五层模型分别是应用层、传输层、网络层、链路层和物理层,其中应用层对应于 OSI 七层模型中的会话层、表示层、应用层,这也是二者的区别。
计算机网络数据是按照协议规范,采用分层的结构由发送端自上而下流动到物理层,再从物理层在网络分层中自下而上流动到接收端的应用层完成数据通信。网络分层中,高层级的应用模块仅利用低层级应用模块提供的接口和功能,低层级应用模块也仅使用高层级应用模块传来的参数响应相关操作,层次间每个应用模块都可能被提供相同功能的应用模块替代。
Kubernetes 网络通信也遵守 TCP/IP 五层模型的定义,通过不同的资源对象在相应的层级提供相应的模块功能。Kubernetes 资源对象在相应的网络层级与传统网络设备模块的对照表如下表所示。
Docker 容器间可以通过 IP 网络、容器名解析、joined 容器 3 种方式实现通信。IP 网络是在网络联通的基础上通过 IP 地址实现互访通信。容器名解析是在网络联通的基础上,由 Docker 内嵌的 DNS 进行容器名解析实现的互访通信方式,同一主机桥接模式的容器间需要启动时,可使用 --link 参数启用这一功能。
joined 容器方式可以使多个容器共享一个网络命名空间,多个容器间通过环回接口直接通信,这种方式容器间传输效率最高。
Flannel 在初始安装时,创建了网桥设备 cni0,网络空间 default 中创建的 Veth 虚拟接口都被加入网桥设备 cni0 中,相当于所有的 Pod 都被接入这个虚拟交换机中,在同一虚拟交换机中的 Pod 实现了链路层的互联并进行网络通信。工作原理如下图所示。
图:同节点的Pod间数据通信
可用如下命令查看当前节点服务器的网络命名空间和网桥信息。
Vxlan 协议是一种隧道协议,基于 UDP 协议传输数据。Flannel 的 Vxlan 虚拟网络比较简单,在每个 Kubernetes 的 Node 上只有 1 个 VTEP(Vxlan Tunnel Endpoint)设备(默认为 flannel.1)。Kubernetes 集群中整个 Flannel 网络默认配置网段为 10.244.0.0/16,每个节点都分配了唯一的 24 位子网,Flannel 在 Kubernetes 集群中类似于传统网络中的一个三层交换设备,每个 Node 节点的桥接设备通过 VTEP 设备接口互联,使运行在不同 Node 节点中不同子网 IP 的容器实现跨 Node 互通。
可用如下命令查看当前节点服务器的 arp 信息。
为使动态变化 IP 的 Pod 应用可以被其他应用访问,Kubernetes 通过标签筛选的形式将具有相同指定标签的一组 Pod 定义为 Service,每个 Service 的 Pod 成员信息通过端点控制器在 etcd 中保存及更新。Service 为 Pod 应用提供了固定的虚拟 IP 和端口实现固定访问,使得集群内其他 Pod 应用可以访问这个服务。
Service 是四层(TCP/UDP over IP)概念,其构建了一个有固定 ClusterIP(集群虚拟 IP,Virtual IP)和 Port 的虚拟集群,每个节点上运行的 kube-proxy 进程通过主节点的接口服务监听资源对象 Service 和 Endpoint 内 Pod 列表的变化。
kube-proxy 默认使用 iptables 代理模式,其通过对每个 Service 配置对应的 iptables 规则,在集群中的 Node 主机上捕获到达该 Service 的 ClusterIP 和 Port 的请求,当捕获到请求时,会将访问请求按比例随机分配给 Service 中的一个 Pod,如果被选择的 Pod 没有响应(取决于 readiness probes 的配置),则自动重试另一个 Pod。Service 访问逻辑如下图所示。
图:Service访问逻辑
具体说明如下。
kube-proxy 在集群中的每个节点都会配置集群中所有 Service 的 iptables 规则,iptables 规则设置如下。
Service 的负载均衡是由 iptables 的 statistic 模块实现的。statistic 模块的 random 模式可以将被设定目标的请求数在参数 probability 设定的概率范围内分配,参数设定值在 0.0~1.0 之间,当参数设定值为 0.5 时,表示该目标有 50% 的概率分配到请求。
kube-proxy 遍历 Service 中的 Pod 列表时,按照公式 1.0/float64(n-i) 为每个 Pod 计算概率值,n 是 Pod 的总数量,i 是当前计数。当有 3 个 Pod 时,计算值分别为 33%、50%、100%,3 个 Pod 的总流量负载分配分别为 33%、35%、32%。
Service 也支持会话保持功能,是应用 iptables 的 recent 模块实现的。recent 允许动态创建源地址列表,并对源地址列表中匹配的来源 IP 执行相应的 iptables 动作。recent 模块参数如下表所示。
配置 Service 会话保持,只需在 Service 中进行如下配置即可。
图:NodePort方式访问逻辑
具体说明如下。
NodePort 方式的资源配置如下:
由于是直接将 Service 端口绑定被路由的 IP 对外暴露服务,用户需要将整个集群对外服务的端口做好相应的规划,避免端口冲突。资源配置如下:
Node 与 Pod 间的关系可以使用 nodeAffinity 在资源配置文件中设置,在设置 Pod 资源对象时,可以将 Pod 部署到具有指定标签的集群 Node 上。Pod 间的关系可通过 podAntiAffinity 的配置尽量把同一 Service 下的 Pod 分配到不同的 Node 上,提高自身的高可用性,也可以把互相影响的不同 Service 的 Pod 分散到不同的集群 Node 上。
对于 Pod 间访问比较频繁的应用,可以使用 podAffinity 配置,尽量把被配置的 Pod 部署到同一 Node 服务器上。
Local 策略则会将请求只分配给请求 IP 主机中该 Service 的 Pod,而不会转发给 Service 中部署在其他 Node 中的 Pod,这样就保留了最初的源 IP 地址。但该方式不会对 Service 的 Pod 进行负载均衡,同时被访问 IP 的 Node 主机上如果没有该 Service 的 Pod,则会报错。Local 策略仅适用于 NodePort 和 LoadBalancer 类型的 Service。
Kubernetes 中通过 Service 实现 Pod 应用访问,在流量调度策略的 Cluster 调度策略下,对一个 Service 的访问请求会被随机分配到 Service 中的任意 Pod,即便该 Service 与发出请求的 Pod 在同一 Node 有可提供服务的 Pod,也不一定会被选中。
在 Kubernetes 计划的 1.16 版本中增加了服务拓扑感知的流量管理功能,设计了新的 Pod 定位器(PodLocator),实现了服务的拓扑感知服务路由机制,使得 Pod 总能优先使用本地访问的策略找到最近的服务后端,这种拓扑感知服务使本地访问具有更广泛的意义,包括节点主机、机架、网络、机房等,这样可以有效地减少网络延迟,提高访问效率及安全性,更加节约成本。
计算机网络数据是按照协议规范,采用分层的结构由发送端自上而下流动到物理层,再从物理层在网络分层中自下而上流动到接收端的应用层完成数据通信。网络分层中,高层级的应用模块仅利用低层级应用模块提供的接口和功能,低层级应用模块也仅使用高层级应用模块传来的参数响应相关操作,层次间每个应用模块都可能被提供相同功能的应用模块替代。
Kubernetes 网络通信也遵守 TCP/IP 五层模型的定义,通过不同的资源对象在相应的层级提供相应的模块功能。Kubernetes 资源对象在相应的网络层级与传统网络设备模块的对照表如下表所示。
网络分层 | 设备模块 | Kubernetes 资源对象 |
---|---|---|
应用层 | F5、HAProxy、Nginx | Ingress |
传输层 | F5、LVS | Service |
网络层 | 路由器、三层交换机 | Flannel、Calico、Pod(容器间通信) |
链路层 | 网桥、二层交换机、网卡 | vnet、bridge |
物理层 | 中继器、集线器、网线 | -- |
1、Docker网络模式
Kubernetes 是基于容器的管理系统,其使用的 Docker 容器版本的 Pod 由多个 Docker 容器组成,因此为便于理解 Pod 的网络通信方式,应首先了解 Docker 自有的网络模式。Docker 容器有如下 4 种常见的网络模式。1) 主机模式(host)
该模式下,因为容器与宿主机共享网络命名空间(network name-space,netns),所以该容器中可以共享使用宿主机的所有网卡设备。使用者可以通过访问宿主机 IP,访问容器中运行应用的所有网络端口。主机模式下网络传输效率最高,但宿主机上已经存在的网络端口无法被容器使用。2) 无网卡模式(none)
该模式下,容器中只有环回(Lookback,lo)接口,运行在容器内的应用仅能使用环回接口实现网络层的数据传输。3) 桥接模式(bridge)
该模式下,容器内会被创建 Veth(Virtual ETHernet)设备并接入宿主机的桥接网络,通过宿主机的桥接网络,容器内部应用可与宿主机及宿主机中接入同一桥接设备的其他容器应用进行通信。4) Macvlan网络模式(macvlan)
当宿主机的网络存在多个不同的VLAN时,可以通过该模式为容器配置 VLAN ID,使该容器与宿主机网络中同一 VLAN ID 的设备实现网络通信。Docker 容器间可以通过 IP 网络、容器名解析、joined 容器 3 种方式实现通信。IP 网络是在网络联通的基础上通过 IP 地址实现互访通信。容器名解析是在网络联通的基础上,由 Docker 内嵌的 DNS 进行容器名解析实现的互访通信方式,同一主机桥接模式的容器间需要启动时,可使用 --link 参数启用这一功能。
joined 容器方式可以使多个容器共享一个网络命名空间,多个容器间通过环回接口直接通信,这种方式容器间传输效率最高。
2、Pod内容器间的数据通信
Pod 是由多个 Docker 容器以 joined 容器方式构成的,多个容器共享由名为 pause 的容器创建的网络命名空间,容器内的进程彼此间通过环回接口实现数据通信。环回接口不依赖链路层和物理层协议,一旦传输层检测到目的端地址是环回接口地址,数据报文离开网络层时会被返回给本机的端口应用。这种模式传输效率较高,非常适用于容器间进程的频繁通信。3、同节点的Pod间数据通信
每个 Pod 拥有唯一的 IP 和彼此隔离的网络命名空间,在 Linux 系统中,Pod 间跨网络命名空间的数据通信是通过 Veth 设备实现的。Veth 设备工作在链路层,总是成对出现,也被称为 Veth-pair 设备。在网络插件是 Flannel 的虚拟网络结构中,Flannel 在被 Kubernetes 触发、接收到相关 Pod 参数时,会为 Pod 创建 Veth 设备并分配 IP,Veth 设备一端是 Pod 的 eth0 接口,一端是 Node 节点中网络空间名为 default 的 Veth 虚拟接口。Flannel 在初始安装时,创建了网桥设备 cni0,网络空间 default 中创建的 Veth 虚拟接口都被加入网桥设备 cni0 中,相当于所有的 Pod 都被接入这个虚拟交换机中,在同一虚拟交换机中的 Pod 实现了链路层的互联并进行网络通信。工作原理如下图所示。
图:同节点的Pod间数据通信
可用如下命令查看当前节点服务器的网络命名空间和网桥信息。
# 查看系统中的网络命名空间 ls /var/run/docker/netns # 查看每个命名空间的网络接口信息 nsenter --net=/var/run/docker/netns/default ifconfig -a # 查看网桥信息 brctl show
4、跨主机的Pod间数据通信
由 CoreOS 使用Go语言开发的 Flannel 实现了一种基于 Vxlan(Virtual eXtensible Local Area Network)封装的覆盖网络(Overlay Network),将 TCP 数据封装在另一种网络包中进行路由转发和通信。Vxlan 协议是一种隧道协议,基于 UDP 协议传输数据。Flannel 的 Vxlan 虚拟网络比较简单,在每个 Kubernetes 的 Node 上只有 1 个 VTEP(Vxlan Tunnel Endpoint)设备(默认为 flannel.1)。Kubernetes 集群中整个 Flannel 网络默认配置网段为 10.244.0.0/16,每个节点都分配了唯一的 24 位子网,Flannel 在 Kubernetes 集群中类似于传统网络中的一个三层交换设备,每个 Node 节点的桥接设备通过 VTEP 设备接口互联,使运行在不同 Node 节点中不同子网 IP 的容器实现跨 Node 互通。
可用如下命令查看当前节点服务器的 arp 信息。
# 本地桥arp表 bridge fdb bridge fdb show dev flannel.1
5、Pod应用在Kubernetes集群内发布服务
Kubernetes 通过副本集控制器能够动态地在集群中任意创建和销毁 Node,因为每个 Node 被分配的子网范围不同,所以 Pod IP 也会随之变化。Flannel 构建的虚拟网络使得集群中的每个 Pod 在网络上已经实现互联互通,由于 Pod IP 变化的不确定性,运行在 Pod 中的应用服务无法被其他应用固定访问。为使动态变化 IP 的 Pod 应用可以被其他应用访问,Kubernetes 通过标签筛选的形式将具有相同指定标签的一组 Pod 定义为 Service,每个 Service 的 Pod 成员信息通过端点控制器在 etcd 中保存及更新。Service 为 Pod 应用提供了固定的虚拟 IP 和端口实现固定访问,使得集群内其他 Pod 应用可以访问这个服务。
Service 是四层(TCP/UDP over IP)概念,其构建了一个有固定 ClusterIP(集群虚拟 IP,Virtual IP)和 Port 的虚拟集群,每个节点上运行的 kube-proxy 进程通过主节点的接口服务监听资源对象 Service 和 Endpoint 内 Pod 列表的变化。
kube-proxy 默认使用 iptables 代理模式,其通过对每个 Service 配置对应的 iptables 规则,在集群中的 Node 主机上捕获到达该 Service 的 ClusterIP 和 Port 的请求,当捕获到请求时,会将访问请求按比例随机分配给 Service 中的一个 Pod,如果被选择的 Pod 没有响应(取决于 readiness probes 的配置),则自动重试另一个 Pod。Service 访问逻辑如下图所示。
图:Service访问逻辑
具体说明如下。
- kube-proxy 根据集群中 Service 和 Endpoint 资源对象的状态初始化所在节点的 iptables 规则;
- kube-proxy 通过接口服务监听集群中 Service 和 Endpoint 资源对象的变化并更新本地的 iptables 规则;
- iptables 规则监听所有请求,将对应 ClusterIP 和 Port 的请求使用随机负载均衡算法负载到后端 Pod。
kube-proxy 在集群中的每个节点都会配置集群中所有 Service 的 iptables 规则,iptables 规则设置如下。
- kube-proxy 首先是建立 filter 表的 INPUT 规则链和 nat 表的 PREROUTING 规则链,将访问节点的流量全部跳转到 KUBE-SERVICES 规则链进行处理;
- kube-proxy 遍历集群中的 Service 资源实例,为每个 Service 资源实例创建两条 KUBE-SERVICES 规则;
- KUBE-SERVICES 中一条规则是将访问 Service 的非集群 Pod IP 交由 KUBE-MARK-MASQ 规则标记为 0x4000/0x4000,在执行到 POSTROUTING 规则链时由 KUBE-POSTROUTING 规则链对数据流量实现 SNAT;
- KUBE-SERVICES 中另一条规则将访问目标是 Service 的请求跳转到对应的 KUBE-SVC 规则链;
- KUBE-SVC 规则链由目标 Service 端点列表中每个 Pod 的处理规则组成,这些规则包括随机负载均衡策略及会话保持(Session Affinity)的实现;
- KUBE-SVC 每条规则链命名是将服务名 + 协议名按照 SHA256 算法生成哈希值后通过 base32 对该哈希值再编码,取编码的前 16 位与 KUBE-SVC 作为前缀组成的字符串;
- KUBE-SEP 每个 Pod 有两条 KUBE-SEP 规则,一条是将请求数据 DNAT 到 Pod IP,另一条用来将 Pod 返回数据交由 KUBE-POSTROUTING 规则链实现 SNAT;
- KUBE-SEP 每条规则链命名是将服务名 + 协议名 + 端口按照 SHA256 算法生成哈希值后通过 base32 对该哈希值再编码,取编码的前 16 位与 KUBE-SEP 为前缀组成的字符串。
Service 的负载均衡是由 iptables 的 statistic 模块实现的。statistic 模块的 random 模式可以将被设定目标的请求数在参数 probability 设定的概率范围内分配,参数设定值在 0.0~1.0 之间,当参数设定值为 0.5 时,表示该目标有 50% 的概率分配到请求。
kube-proxy 遍历 Service 中的 Pod 列表时,按照公式 1.0/float64(n-i) 为每个 Pod 计算概率值,n 是 Pod 的总数量,i 是当前计数。当有 3 个 Pod 时,计算值分别为 33%、50%、100%,3 个 Pod 的总流量负载分配分别为 33%、35%、32%。
Service 也支持会话保持功能,是应用 iptables 的 recent 模块实现的。recent 允许动态创建源地址列表,并对源地址列表中匹配的来源 IP 执行相应的 iptables 动作。recent 模块参数如下表所示。
参数 | 参数说明 |
---|---|
set | 把匹配动作的源 IP 添加到地址列表 |
name | 源地址列表名称 |
mask | 源地址列表中 IP 的掩码 |
rsource | 设置源地址列表中保存数据包的源 IP 地址 |
rcheck | 检查当前数据包源 IP 是否在源地址列表中 |
seconds | 与 rcheck 配合使用,设置对指定时间内更新的 IP 地址与数据包源 IP 进行匹配检查,单位为秒 |
rеaр | 与 seconds 配合使用,将清除源地址列表中指定时间内未被更新的 IP 地址 |
配置 Service 会话保持,只需在 Service 中进行如下配置即可。
spec: sessionAffinity: ClientIP sessionAffinityConfig: clientIP: timeoutSeconds: 10800kube-proxy 实现 Service 的方法有 4 种,分别是 userspace、iptables、IPVS 和 winuser-space。iptables 只是默认配置,因 kube-proxy 的其他实现方式非本教程重点,此处不深入探讨。
6、Pod应用在Kubernetes集群外发布服务
Service 实现了 Pod 访问的固定 IP 和端口,但 ClusterIP 并不是绑定在网络设备上的,它只是 kube-proxy 进程设定的 iptables 本地监听转发规则,只能在 Kubernetes 集群内的节点上进行访问。Kubernetes 系统默认提供两种方式实现 Pod 应用向集群外发布服务,一种是基于资源对象 Pod 的 hostPort 和 hostNetwork 方式,另一种是基于资源对象 Service 的 NodePort、Load-Balancer 和 ExternalIPs 方式。1) hostPort方式
hostPort 方式相当于创建 Docker 容器时使用 -p 参数提供容器的端口映射,只能通过运行容器的 Node 主机 IP 进行访问,属于资源对象 Pod 的运行方式,不支持多个 Pod 的 Service 负载均衡等功能。资源配置如下:apiVersion: v1 kind: Pod metadata: name: apps labels: app: web spec: containers: - name: apps image: apache ports: - containerPort: 80 hostPort: 8080
2) hostNetwork方式
hostNetwork 方式相当于创建 Docker 容器时以主机模式为网络模式的 Pod 运行方式,该方式运行的容器与所在 Node 主机共享网络命名空间,属于资源对象 Pod 的运行方式,不支持多个 Pod 的 Service 负载均衡等功能。资源配置如下:apiVersion: v1 kind: Pod metadata: name: nginx-web namespace: default labels: run: nginx-web spec: hostNetwork: true containers: - name: nginx-web image: nginx ports: - containerPort: 80
3) NodePort方式
NodePort 方式是在集群中每个节点监听固定端口(NodePort)的访问,外部用户对任意 Node 主机 IP 和 NodePort 的访问,都会被 Service 负载到后端的 Pod,全局 NodePort 的默认可用范围为 30000~32767。NodePort 方式访问逻辑如下图所示。图:NodePort方式访问逻辑
具体说明如下。
- kube-proxy 初始化时,会对 NodePort 方式的 Service 在 iptables nat 表中创建规则链 KUBE-NODEPORTS,用于监听本机 NodePort 的请求;
- 外部请求访问节点 IP 和端口(NodePort)后,被 iptables 规则 KUBE-NODEPORTS 匹配后跳转给对应的 KUBE-SVC 规则链执行负载均衡等操作;
- 选定 Pod 后,请求被转发到选定的 Pod IP 和目标端口(targetPod)。
NodePort 方式的资源配置如下:
apiVersion: v1 kind: Service metadata: name: nginx-web namespace: default labels: run: nginx-web spec: type: NodePort ports: - nodePort: 31804 port: 8080 protocol: TCP targetPort: 8080
4) LoadBalancer方式
LoadBalancer 方式是一种 Kubernetes 自动对外发布的解决方案,该方案是将外部负载均衡器作为上层负载,在创建 Service 时自动与外部负载均衡器互动,完成对 Kubernetes Service 负载均衡创建的操作,将 Service 按照外部负载均衡器的负载策略对外提供服务。该方案依赖外部负载均衡器的支持,阿里云、腾讯云等的容器云都提供了对这个方案的支持。资源配置如下:apiVersion: v1 kind: Service metadata: name: nginx-web namespace: default labels: run: nginx-web spec: type: LoadBalancer ports: - port: 8080 protocol: TCP targetPort: 8080具体说明如下。
- 不同的外部负载均衡器需要有对应的负载均衡控制器(Loadbalancer Controller);
- 负载均衡控制器通过接口服务实时监听资源对象 Service 的变化;
- LoadBalancer 类型的 Service 被创建时,Kubernetes 会为该 Service 自动分配 Node-Port;
- 当监听到 LoadBalancer 类型的 Service 创建时,负载均衡控制器将触发外部负载均衡器(LoadBalancer)创建外部 VIP、分配外部 IP 或将现有节点 IP 绑定 NodePort 端口添加到外部负载均衡器的负载均衡池,完成负载均衡的配置;
- 当外部用户访问负载均衡器的外部 VIP 时,外部负载均衡器会将流量负载到 Kubernetes 节点或 Kubernetes 集群中的 Pod(视外部负载均衡器的功能而定);
- 不能与 NodePort 方式同时使用。
5) ExternalIPs方式
ExternalIPs 方式提供了一种指定外部 IP 绑定 Service 端口的方法,该方法可以指定节点内某几个节点 IP 地址或绑定外部路由到节点网络的非节点 IP 对外提供访问。Kubernetes 通过 ExternalIPs 参数将被指定的 IP 与 Service 端口通过 iptables 监听,其使用与 Service 一致的端口,相较于 NodePort 方式配置更加简单灵活。由于是直接将 Service 端口绑定被路由的 IP 对外暴露服务,用户需要将整个集群对外服务的端口做好相应的规划,避免端口冲突。资源配置如下:
spec: externalIPs: - 192.168.1.101 - 192.168.1.102 ports: - name: http port: 80 targetPort: 80 protocol: TCP - name: https port: 443 targetPort: 443 protocol: TCP具体说明如下。
- ExternalIPs 设置的 IP 可以是集群中现有的节点 IP,也可以是上层网络设备路由过来的 IP。kube-proxy 初始化时,会对 ExternalIPs 方式的 Service 在 iptables nat 表中创建规则链 KUBE-SERVICES,用于访问 ExternalIPs 列表中 IP 及 Service port 请求的监听;
- 外部或本地访问 ExternalIPs 列表中 IP 及 port 的请求被匹配后,跳转给对应的 KUBE-SVC 规则链执行负载均衡等操作。
7、Service中Pod的调度策略
Kubernetes 系统中,Pod 默认是按照资源策略随机部署的,虽然用户可对调度策略进行一定的调整,但 Pod 的调度策略同样对 Pod 通信存在一定的影响,相关调度策略有如下两种。1) 部署调度策略(Affinity)
Kubernetes 集群中的 Pod 被随机调度并创建在集群中的 Node 上。在实际使用中,有时需要考虑 Node 资源的有效利用及不同应用间的访问效率等因素,也需要对这种调度设置相关期望的策略。主要体现在 Node 与 Pod 间的关系、同 Service 下 Pod 间的关系、不同 Service 下 Pod 间的关系这 3 个方面。Node 与 Pod 间的关系可以使用 nodeAffinity 在资源配置文件中设置,在设置 Pod 资源对象时,可以将 Pod 部署到具有指定标签的集群 Node 上。Pod 间的关系可通过 podAntiAffinity 的配置尽量把同一 Service 下的 Pod 分配到不同的 Node 上,提高自身的高可用性,也可以把互相影响的不同 Service 的 Pod 分散到不同的集群 Node 上。
对于 Pod 间访问比较频繁的应用,可以使用 podAffinity 配置,尽量把被配置的 Pod 部署到同一 Node 服务器上。
2) 流量调度策略(externalTrafficPolicy)
Service 的流量调度策略有两种,分别是 Cluster 和 Local。Cluster 是默认调度策略,依据 iptables 的随机负载算法,将用户请求负载均衡分配给 Pod,但该方式会隐藏客户端的源 IP。Local 策略则会将请求只分配给请求 IP 主机中该 Service 的 Pod,而不会转发给 Service 中部署在其他 Node 中的 Pod,这样就保留了最初的源 IP 地址。但该方式不会对 Service 的 Pod 进行负载均衡,同时被访问 IP 的 Node 主机上如果没有该 Service 的 Pod,则会报错。Local 策略仅适用于 NodePort 和 LoadBalancer 类型的 Service。
Kubernetes 中通过 Service 实现 Pod 应用访问,在流量调度策略的 Cluster 调度策略下,对一个 Service 的访问请求会被随机分配到 Service 中的任意 Pod,即便该 Service 与发出请求的 Pod 在同一 Node 有可提供服务的 Pod,也不一定会被选中。
在 Kubernetes 计划的 1.16 版本中增加了服务拓扑感知的流量管理功能,设计了新的 Pod 定位器(PodLocator),实现了服务的拓扑感知服务路由机制,使得 Pod 总能优先使用本地访问的策略找到最近的服务后端,这种拓扑感知服务使本地访问具有更广泛的意义,包括节点主机、机架、网络、机房等,这样可以有效地减少网络延迟,提高访问效率及安全性,更加节约成本。
Nginx Ingress简介
Kubernetes 通过 kube-proxy 服务实现了 Service 的对外发布及负载均衡,它的各种方式都是基于传输层实现的。在实际的互联网应用场景中,不仅要实现单纯的转发,还有更加细致的策略需求,如果使用真正的负载均衡器更会增加操作的灵活性和转发性能。
基于以上需求,Kubernetes 引入了资源对象 Ingress,Ingress 为 Service 提供了可直接被集群外部访问的虚拟主机、负载均衡、SSL 代理、HTTP 路由等应用层转发功能。
Kubernetes 官方发布了基于 GCE 和 Nginx 的 Ingress 控制器,Nginx Ingress 控制器能根据 Service 中 Pod 的变化动态地调整配置,结合 Nginx 的高稳定性、高性能、高并发处理能力等特点,使 Kubernetes 对集群中运行于容器的应用程序具有了更加灵活的应用层管理能力。
Nginx Ingress 因使用 Nginx 的不同版本,分为 Nginx 官方版本和 Kubernetes 社区版。Nginx 官方版本提供其基于Go语言开发的 Ingress 控制器,并与 Nginx 集成分为 Nginx 开源版和 Nginx Plus 版;开源版仅基于 Nginx 的原始功能,提供了 Nginx 原生配置指令的支持,相较于 Nginx Plus 版功能简单且不支持 Pod 变化的动态变更。
Nginx Plus 版则提供了诸多完善的商业功能,其支持 Nginx 原生配置指令、JWT 验证、Pod 变化的动态配置及主动健康检查等功能。Kubernetes 社区版是基于 Nginx 的扩展版 OpenResty 及诸多第三方模块构建的,其基于 OpenResty 的 Lua 嵌入式编程能力,扩展了 Nginx 的功能,并基于 balancer_by_lua 模块实现了 Pod 变化的动态变更功能。本节介绍的是基于 Kubernetes 社区版的 Nginx Ingress。
图:Nginx Ingress工作原理
Ingress 控制器通过同步循环机制实时监控接口服务 Ingress 等资源对象的变化,当相关 Service 对应的端点列表有变化时,会通过 HTTP POST 请求将变化信息发送到 Nginx 内部运行的 Lua 程序进行处理,实现对 Nginx Upstream 中后端 Pod IP 变化的动态修改。
每个后端 Pod 的 IP 及 targetPort 信息都存储在 Nginx 的共享内存区域,Nginx 对每个获取的请求将使用配置的负载均衡算法进行转发,Nginx 的配置中应用 Lua 模块的 balancer_by_lua 功能实现 upstream 指令域的动态操作,Pod IP 变化及资源对象 Ingress 对 upstream 指令域相关注解(annotation)的变化无须执行 Nginx 的 reload 操作。
当 Ingress 控制器监控的其他资源对象变化时,会对当前变化的内容创建 Nginx 配置模型,如果新的配置模型与当前运行的 Nginx 配置模型不一致,则将新的配置模型按照模板生成新的 Nginx 配置,并对 Nginx 执行 reload 操作。
Nginx 配置模型避免了 Nginx 的无效 reload 操作。为避免因 Nginx 配置语法错误导致意外中断,Ingress 控制器为 Nginx 的配置内容提供了冲突检测及合并机制,Ingress 控制器使用了准入控制插件(Validating Admission Webhook)做验证 Ingress 配置语法的准入控制,验证通过的 Ingress 资源对象才会被保存在存储服务 etcd 中,并被 Ingress 控制器生成确保没有语法错误的 Nginx 配置文件。
Nginx Ingress 通过 Lua 脚本编程,利用 OpenResty 的 balancer_by_lua 模块,可通过 nginx-ingress 控制器动态地修改 Nginx 上游服务器组的配置,无须 Nginx 进程的热加载,有效地解决了因 Pod 调度带来的 Pod IP 变化的问题。
Kubernetes 的 Nginx Ingress 在 OpenResty 基础上还集成了诸多的第三方模块,模块功能介绍如下。
模块网址:https://github.com/nginx-modules/nginx_ajp_module
模块网址:https://github.com/influxdata/nginx-influxdb-module
模块网址:https://github.com/nginx-modules/ngx_http_geoip2_module
模块网址:https://github.com/nginx-modules/nginx-http-auth-digest
模块网址:https://github.com/nginx-modules/ngx_http_substitutions_filter_module
分布式请求跟踪,也称分布式跟踪,是一种用于分析和监视应用程序的方法,特别是那些使用微服务体系结构构建的应用程序。分布式跟踪有助于查明故障发生的位置以及导致性能低下的原因。该模块是将 Nginx 的请求提供给 OpenTracing 项目的分布式跟踪系统用于应用的请求分析和监控。
Nginx Ingress 中集成了 jaeger 和 zipkin 两种分布式跟踪系统的 OpenTracing 项目插件,用户可根据实际情况进行选择使用。
模块网址:https://github.com/opentracing-contrib/nginx-opentracing
模块网址:https://github.com/google/ngx_brotli
模块网址:https://github.com/nginx-modules/ModSecurity-nginx
模块网址:https://github.com/p0pr0ck5/lua-resty-waf。
基于以上需求,Kubernetes 引入了资源对象 Ingress,Ingress 为 Service 提供了可直接被集群外部访问的虚拟主机、负载均衡、SSL 代理、HTTP 路由等应用层转发功能。
Kubernetes 官方发布了基于 GCE 和 Nginx 的 Ingress 控制器,Nginx Ingress 控制器能根据 Service 中 Pod 的变化动态地调整配置,结合 Nginx 的高稳定性、高性能、高并发处理能力等特点,使 Kubernetes 对集群中运行于容器的应用程序具有了更加灵活的应用层管理能力。
Nginx Ingress 因使用 Nginx 的不同版本,分为 Nginx 官方版本和 Kubernetes 社区版。Nginx 官方版本提供其基于Go语言开发的 Ingress 控制器,并与 Nginx 集成分为 Nginx 开源版和 Nginx Plus 版;开源版仅基于 Nginx 的原始功能,提供了 Nginx 原生配置指令的支持,相较于 Nginx Plus 版功能简单且不支持 Pod 变化的动态变更。
Nginx Plus 版则提供了诸多完善的商业功能,其支持 Nginx 原生配置指令、JWT 验证、Pod 变化的动态配置及主动健康检查等功能。Kubernetes 社区版是基于 Nginx 的扩展版 OpenResty 及诸多第三方模块构建的,其基于 OpenResty 的 Lua 嵌入式编程能力,扩展了 Nginx 的功能,并基于 balancer_by_lua 模块实现了 Pod 变化的动态变更功能。本节介绍的是基于 Kubernetes 社区版的 Nginx Ingress。
1、Nginx Ingress原理
Nginx Ingress 由资源对象 Ingress、Ingress 控制器、Nginx 三部分组成,Ingress 控制器用以将 Ingress 资源实例组装成 Nginx 配置文件(nginx.conf),并重新加载 Nginx 使变更的配置生效。当它监听到 Service 中 Pod 变化时通过动态变更的方式实现 Nginx 上游服务器组配置的变更,无须重新加载 Nginx 进程。工作原理如下图所示。- Ingress,一组基于域名或 URL 把请求转发到指定 Service 实例的访问规则,是 Kubernetes 的一种资源对象,Ingress 实例被存储在对象存储服务 etcd 中,通过接口服务被实现增、删、改、查的操作。
- Ingress 控制器(Ingress controller),用以实时监控资源对象 Ingress、Service、End-point、Secret(主要是 TLS 证书和 Key)、Node、ConfigMap 的变化,自动对 Nginx 进行相应的操作。
- Nginx,实现具体的应用层负载均衡及访问控制。
图:Nginx Ingress工作原理
Ingress 控制器通过同步循环机制实时监控接口服务 Ingress 等资源对象的变化,当相关 Service 对应的端点列表有变化时,会通过 HTTP POST 请求将变化信息发送到 Nginx 内部运行的 Lua 程序进行处理,实现对 Nginx Upstream 中后端 Pod IP 变化的动态修改。
每个后端 Pod 的 IP 及 targetPort 信息都存储在 Nginx 的共享内存区域,Nginx 对每个获取的请求将使用配置的负载均衡算法进行转发,Nginx 的配置中应用 Lua 模块的 balancer_by_lua 功能实现 upstream 指令域的动态操作,Pod IP 变化及资源对象 Ingress 对 upstream 指令域相关注解(annotation)的变化无须执行 Nginx 的 reload 操作。
当 Ingress 控制器监控的其他资源对象变化时,会对当前变化的内容创建 Nginx 配置模型,如果新的配置模型与当前运行的 Nginx 配置模型不一致,则将新的配置模型按照模板生成新的 Nginx 配置,并对 Nginx 执行 reload 操作。
Nginx 配置模型避免了 Nginx 的无效 reload 操作。为避免因 Nginx 配置语法错误导致意外中断,Ingress 控制器为 Nginx 的配置内容提供了冲突检测及合并机制,Ingress 控制器使用了准入控制插件(Validating Admission Webhook)做验证 Ingress 配置语法的准入控制,验证通过的 Ingress 资源对象才会被保存在存储服务 etcd 中,并被 Ingress 控制器生成确保没有语法错误的 Nginx 配置文件。
2、集成的第三方模块
Kubernetes 的 Nginx Ingress 当前版本是 0.25.1,其集成了 Nginx 的扩展版本 Open-Resty 的 1.15.8.1 版本,OpenResty 的最大特点是集成了 Lua 脚本的嵌入式编程功能,基于 Nginx 的优化,使 Nginx 具有更强的扩展能力。Nginx Ingress 通过 Lua 脚本编程,利用 OpenResty 的 balancer_by_lua 模块,可通过 nginx-ingress 控制器动态地修改 Nginx 上游服务器组的配置,无须 Nginx 进程的热加载,有效地解决了因 Pod 调度带来的 Pod IP 变化的问题。
Kubernetes 的 Nginx Ingress 在 OpenResty 基础上还集成了诸多的第三方模块,模块功能介绍如下。
1) Ajp协议模块(nginx_ajp_module)
Ajp 协议模块是一个使 Nginx 实现 Ajp 协议代理的模块,该模块可以使 Nginx 通过 Ajp 协议连接到被代理的 Tomcat 服务。模块网址:https://github.com/nginx-modules/nginx_ajp_module
2) InfluxDB输出模块(nginx-influxdb-module)
InfluxDB 输出模块可以使 Nginx 的每次请求记录以 InfluxDB 作为后端进行存储,其以非阻塞的方式对每个请求进行过滤,并使用 UDP 协议将处理后的数据发送到 InfluxDB 服务器。可以通过该模块实时监控 Nginx 的所有请求,获得每个请求的连接类型、请求状态,并通过 InfluxDB 实现相关故障状态的报警。模块网址:https://github.com/influxdata/nginx-influxdb-module
3) GeoIP2数据库模块(ngx_http_geoip2)
MaxMind 的 GeoIP 数据库已经升级到第二代,GeoIP2 数据库提供了准确的 IP 信息,包括 IP 地址的位置(国家、城市、经纬度)等数据。该模块增加了 GeoIP2 数据的支持。模块网址:https://github.com/nginx-modules/ngx_http_geoip2_module
4) 摘要认证模块(nginx-http-auth-digest)
摘要认证模块使 Nginx 的基本认证功能增加了摘要认证(Digest Authentication)的支持,这是一种简单的身份验证机制,是对基本认证的一种安全改进,仅通过服务端及客户端根据用户名和密码计算的摘要信息进行验证,避免了密码的明文传递,增加了认证过程的安全性。模块网址:https://github.com/nginx-modules/nginx-http-auth-digest
5) 内容过滤模块(ngx_http_substitutions_filter_module)
内容过滤模块是一个内容过滤功能的模块,其相对于 Nginx 自带的内容过滤模块(ngx_http_sub_module)增加了正则匹配的替换方式。模块网址:https://github.com/nginx-modules/ngx_http_substitutions_filter_module
6) 分布式跟踪模块(nginx-opentracing)
OpenTracing 由 API 规范、实现该规范的框架和库以及项目文档组成,是一个轻量级的标准化规范,其位于应用程序和跟踪分析程序之间,解决了不同分布式追踪系统API不兼容的问题。OpenTracing 允许开发人员使用 API 向应用程序代码中添加工具,实现业务应用中的分布式请求跟踪。分布式请求跟踪,也称分布式跟踪,是一种用于分析和监视应用程序的方法,特别是那些使用微服务体系结构构建的应用程序。分布式跟踪有助于查明故障发生的位置以及导致性能低下的原因。该模块是将 Nginx 的请求提供给 OpenTracing 项目的分布式跟踪系统用于应用的请求分析和监控。
Nginx Ingress 中集成了 jaeger 和 zipkin 两种分布式跟踪系统的 OpenTracing 项目插件,用户可根据实际情况进行选择使用。
模块网址:https://github.com/opentracing-contrib/nginx-opentracing
7) Brotli压缩模块(ngx_brotli)
Brotli 是 Google 推出的侧重于 HTTP 压缩的一种开源压缩算法,它使用 lz77 算法的现代变体、Huffman 编码和基于上下文的二阶建模的组合来压缩数据。在与 Deflate 相似的压缩与解压缩速度下,增加了 20% 的压缩密度。在与 gzip 的测试下,因压缩密度高其消耗的压缩时间要比 gzip 多,但在客户端解压的时间则相当。模块网址:https://github.com/google/ngx_brotli
8) ModSecurity连接器模块(ModSecurity-nginx)
ModSecurity 是一个开源的 Web 应用防火墙,其主要作用是增强 Web 应用的安全性并保护 Web 应用免受攻击。模块 ModSecurity-nginx 是一个 Nginx 的 ModSecurity 连接器,其提供了 Nginx 和 libmodsecurity(ModSecurity v3)之间的通信通道。Nignx Ingress 中已经集成了 ModSecurity 和 OWASP 规则集,在 Nginx 配置文件目录可以查看相关配置。模块网址:https://github.com/nginx-modules/ModSecurity-nginx
9) lua-resty-waf模块
lua-resty-waf 是一个基于 OpenResty 的高性能 Web 应用防火墙,它使用 Nginx Lua API 及灵活的规则架构分析和处理 HTTP 请求信息,并不断开发和测试一些自定义的规则补丁来应对不断出现的新的安全威胁。lua-resty-waf 提供了 ModSecurity 兼容的规则语法,支持 ModSecurity 现有规则的自动转换,用户无须学习新的语法规则就可以扩展 lua-resty-waf 的规则。模块网址:https://github.com/p0pr0ck5/lua-resty-waf。
Nginx Ingress安装部署
Helm 是一个非常方便的 Kubernetes 应用部署工具,支持 Nginx Ingress 的快速部署和卸载。通过 Helm 可快速将 Nginx Ingress 部署在 Kubernetes 集群中,Helm 中 Nginx Ingress 的 1.19.1 版本 Chart 部分参数如下表所示。
Nginx Ingress 的默认部署方式是 Deployment,只会部署一个副本,Service 对外发布类型是 LoadBalancer,安装参数如下:
图:NodePort方式
部署命令如下:
图:hostNetwork方式
部署命令如下:
也可以使用 DaemonSet 部署方式,在集群中的每个节点自动创建并运行一个 Nginx Ingress Pod,实现 Nginx Ingress 的自动扩展。
SSL 透传模式下,Nginx 不会对客户端的 HTTPS 请求进行解密,加密的请求会被直接转发到后端的被代理服务器,这种方式常被应用到后端的 HTTPS 服务器需要对客户端进行客户端证书验证的场景,相对也会降低 Nginx 对 TLS 证书加解密的负担。由于请求数据是保持加密传输的,HTTP 消息头将无法修改,所以消息头字段 X-forwarded-* 的客户端 IP 无法被添加。Nginx Ingress 默认部署方式没有开启 SSL 透传的支持,需要在部署时使用参数 --enable-ssl-passthrough 进行开启。
图:日志收集方案逻辑
具体说明如下:
参数 | 参数值选项 | 默认值 | 功能说明 |
---|---|---|---|
controller.service.type | ClusterIP 或 NodePort 或 LoadBalancer | LoadBalancer | 设置资源对象 Service 的服务类型 |
controller.hostNetwork | true 或 false | false | 设置资源对象 Pod 是否以 hostNet-work方式运行 |
controller.service.externalIPs | -- | -- | 设置资源对象 Service externalIPs 的 IP 地址 |
controller.kind | Deployment 或 Daemon-Set | Deployment | 设置部署方式 |
controller.service.external-TrafficPolicy | Local 或 Cluster | Cluster | 设置 Pod 流量调度方式 |
rbac.create | true 或 false | false | 是否为 nginx-ingress 创建 RBAC 资源 |
controller.autoscaling.enabled | true 或 false | false | 是否启用多副本支持,启用后最小副本数为 1,最大值为 11 |
controller.autoscaling.min-Replicas | -- | 1 | 设置创建的最小副本数 |
controller.metrics.enabled | true 或 false | false | 是否启用 Prometheus Exporter |
controller.containerPort.http | -- | 80 | Nginx Ingress 的默认 HTTP 端口 |
controller.containerPort.https | -- | 443 | Nginx Ingress 的默认 HTTP 端口 |
Nginx Ingress 的默认部署方式是 Deployment,只会部署一个副本,Service 对外发布类型是 LoadBalancer,安装参数如下:
helm install --name nginx-ingress stable/nginx-ingress --set rbac.create=true
具体说明如下:- Helm 安装的应用名称为 nginx-ingress;
- rbac.create 参数用以为 nginx-ingress 创建 RBAC 资源,获取与接口服务的访问授权。
1、Nginx Ingress部署
Nginx Ingress 以 Pod 形式运行在 Kubernetes 集群中,用户可根据 Kubernetes 的网络通信特点以及实际场景选择灵活的部署方式进行 Nginx Ingress 的部署,此处分别以基于资源对象 Service 的 NodePort 方式和 Pod 的 hostNetwork 方式举例介绍。1) Service的NodePort方式
以 NodePort 类型部署 Nginx Ingress,需要使用参数进行指定 controller.service.type 为 NodePort。为便于管理,可以为 Nginx Ingress 创建单独使用的命名空间 nginx-ingress,部署拓扑如下图所示。图:NodePort方式
部署命令如下:
# 安装nginx-ingress helm install --name nginx-ingress \ --namespace nginx-ingress \ stable/nginx-ingress \ --set "rbac.create=true,controller.autoscaling.enabled=true,controller. autoscaling.minReplicas=2,controller.service.type=NodePort,con-troller.service.externalTrafficPolicy=Local" # 也可以在创建后调整副本数 kubectl scale --replicas=3 deployment/nginx-ingress具体说明如下:
- Helm 安装的应用名称为 nginx-ingress,命名空间为 nginx-ingress;
- 以默认的 Deployment 方式部署,设置 Pod 副本数为 2,并以 Service 的 NodePort 方式对外发布服务,设置流量调度策略为 Local;
- Kubernetes 将为 nginx-ingress Service 随机创建范围在 30000~32767 之间的 Node-Port 端口;
- 用户将 Kubernetes 中节点 IP 和 NodePort 手动添加到传输层负载均衡中的虚拟服务器集群中;
- 外部请求发送到传输层负载均衡虚拟服务器,传输层负载将请求数据转发到 Kubernetes 集群节点的 NodePort;
- NodePort 类型的 Service 将请求负载到对应的 Nginx Pod;
- Nginx 将用户请求进行应用层负载转发到配置的应用 Pod;
- 在该部署方式下,Nginx Pod 需要使用 Local 的流量调度策略,获取客户端的真实 IP。
2) Pod的hostNetwork方式
主机网络(hostNetwork)方式可以使 Pod 与宿主机共享网络命名空间,外网传输效率最高。因 Pod 直接暴露外网,虽然存在一定的安全问题,但不存在客户端源 IP 隐藏的问题,部署拓扑如下图所示。图:hostNetwork方式
部署命令如下:
# 以Deployment方式部署 helm install --name nginx-ingress \ --namespace nginx-ingress \ stable/nginx-ingress \ --set "rbac.create=true,controller.service.type=ClusterIP,controller. hostNetwork=true"具体说明如下:
- Deployment 方式部署时,Nginx Ingress 的 Service 设置类型为 ClusterIP,仅提供内部服务端口;
- 用户将 Kubernetes 中节点 IP 及 80、443 端口手动添加到传输层负载均衡中的虚拟服务器集群中;
- 用户请求经传输层负载均衡设备转发到 Nginx,Nginx 将用户请求负载到 Kubernetes 集群内的 Pod 应用。
也可以使用 DaemonSet 部署方式,在集群中的每个节点自动创建并运行一个 Nginx Ingress Pod,实现 Nginx Ingress 的自动扩展。
# 以DaemonSet方式部署nginx-ingress并成为集群唯一入口 helm install --name nginx-ingress \ --namespace nginx-ingress \ stable/nginx-ingress \ --set "rbac.create=true,controller.kind=DaemonSet,controller.service.type=ClusterIP,controller.hostNetwork=true"
3) SSL终止(SSL Termination)和SSL透传(SSL Passthrough)
SSL 终止模式下,客户端的 TLS 数据会在代理服务器 Nginx 中解密,解密的数据由代理服务器直接或再次 TLS 加密后传递给被代理服务器,这种模式下,相对增加代理服务器的计算负担,但方便了 SSL 证书的统一管理。SSL 透传模式下,Nginx 不会对客户端的 HTTPS 请求进行解密,加密的请求会被直接转发到后端的被代理服务器,这种方式常被应用到后端的 HTTPS 服务器需要对客户端进行客户端证书验证的场景,相对也会降低 Nginx 对 TLS 证书加解密的负担。由于请求数据是保持加密传输的,HTTP 消息头将无法修改,所以消息头字段 X-forwarded-* 的客户端 IP 无法被添加。Nginx Ingress 默认部署方式没有开启 SSL 透传的支持,需要在部署时使用参数 --enable-ssl-passthrough 进行开启。
# 修改部署资源对象nginx-ingress-controller kubectl edit Deployment/nginx-ingress-controller -n nginx-ingress # 在规范部分添加容器启动参数--enable-ssl-passthrough spec: containers: - args: - /nginx-ingress-controller - --default-backend-service=nginx-ingress/nginx-ingress-default-backend - --election-id=ingress-controller-leader - --ingress-class=nginx - --configmap=nginx-ingress/nginx-ingress-controller - --enable-ssl-passthrough
4) 卸载Nginx Ingress
Nginx 的配置是以资源对象 ConfigMap 和 Ingress 方式存储在 etcd 服务中的,所以即便删除或重新部署 Nginx Ingress 也不会影响之前的配置。helm delete --purge nginx-ingress
2、管理工具
Nginx Ingress 提供了基于 kubectl 工具的管理插件 ingress-nginx,用于 Nginx Ingress 的日常维护。插件 ingress-nginx 安装方法如下:# 安装插件ingress-nginx kubectl krew install ingress-nginx 常见命令参数如下: # 显示所有的Ingress实例摘要 kubectl ingress-nginx ingresses # 查看所有的后端Service配置 kubectl ingress-nginx backends -n nginx-ingress # 查看Nginx的所有配置 kubectl ingress-nginx conf -n nginx-ingress # 查看指定主机名的Nginx配置 kubectl ingress-nginx conf -n nginx-ingress --host auth.nginxbar.org # 查看Nginx服务器的配置目录 kubectl ingress-nginx exec -i -n nginx-ingress -- ls /etc/nginx # 查看Nginx服务器的日志 kubectl ingress-nginx logs -n nginx-ingress
3、日志管理
Nginx Ingress 是以 Pod 方式运行的,在默认配置下,Nginx 的日志输出到 stdout 及 stderr。Kubernetes 下有很多日志收集解决方案,此处推荐使用 Filebeat 进行容器日志收集,并将容器日志实时发送到 ELK 集群,ELK 环境部署可参见《Nginx日志分析工具(ELK)配置》一节,日志收集方案逻辑如下图所示。图:日志收集方案逻辑
具体说明如下:
- Docker 的默认日志驱动是 json-driver,每个容器的日志输出到 stdout 及 stderr 中时,Docker 的日志驱动会将容器日志以 *-json.log 的命名方式保存在 /var/lib/docker/containers/ 目录下;
- 在 Kubernetes 集群中以 DaemonSet 方式部署 Filebeat 应用,会在每个 Node 节点运行一个 Filebeat 应用 Pod,进行每个 Node 节点的容器日志采集;
- Filebeat 采集的日志可以直接发送给 Logstash 服务器,也可以发送给 Kafka 后由 Logstash 服务器进行异步获取;
- 所有日志被 Logstash 转到 Elasticsearch 集群进行存储;
- 使用者通过 Kibana 进行日志查看和分析。
1) 部署Filebeat
# 获取官方的Filebeat资源配置文件 curl -L -O https://raw.githubusercontent.com/elastic/beats/7.3/deploy/kubernetes/filebeat-kubernetes.yaml # 修改filebeat输出目标为Logstash sed -i "s/ cloud.id/ #cloud.id/g" filebeat-kubernetes.yaml sed -i "s/ cloud.auth/ #cloud.auth/g" filebeat-kubernetes.yaml sed -i "s/ output.elasticsearch:/ output.logstash:/g" filebeat-kubernetes.yaml sed -i 's/ hosts:.*/ hosts: ["10\.10\.4\.37:5045"]/g' filebeat-kubernetes.yaml sed -i "s/ username/ #username/g" filebeat-kubernetes.yaml sed -i "s/ password/ #password/g" filebeat-kubernetes.yaml kubectl create -f filebeat-kubernetes.yaml
2) 配置Logstash
按照 kubernetes.labels.app 创建容器日志在 Elasticsearch 中的索引,配置文件内容如下:cat>logstash/pipeline/k8s.conf<<EOF input { beats { port => 5045 codec =>"json" } } filter { mutate { # 添加字段kubernetes_apps默认值为kubernetes_noapps add_field => { "kubernetes_apps" => "kubernetes_noapps" } } if [kubernetes][labels][app] { mutate { # 当存在kubernetes.labels.app时,将该字段复制为字段kubernetes_apps copy => { "[kubernetes][labels][app]" => "kubernetes_apps" } } } } output { elasticsearch { # 将log输出到ES服务器 hosts => ["http://10.10.4.37:9200"] # 根据字段kubernetes_apps的值创建ES索引 index => "k8slog-%{kubernetes_apps}-%{[@metadata][version]}-%{+YYYY.MM.dd}" } } EOFHelm 默认会为安装的应用添加 app 标签,通过 Helm 安装 Nginx Ingress 的 app 标签值为 nginx-ingress,因此 Elasticsearch 中自动创建的索引名前缀为 k8slog-nginx-ingress-*。
4、监控管理
Nginx Ingress 中已经集成了 Nginx 的 Prometheus Exporter,可以直接使用 Prometheus 或 Zabbix 获取监控数据。Nginx 监控支持可以在部署的时候使用部署参数 controller.metrics.enabled=true 启用。# 启用监控 helm install --name nginx-ingress \ --namespace nginx-ingress \ stable/nginx-ingress \ --set "rbac.create=true,controller.kind=DaemonSet,controller.service.type=ClusterIP,controller.hostNetwork=true,controller.metrics.enabled=true" curl http://节点IP:9913/metrics
Nginx Ingress配置映射ConfigMap
通过 Helm 安装 Nginx Ingress 的默认关联配置映射实例名称为 nginx-ingress-controller,用户可以通过修改资源对象 Deployment/DaemonSet 实例 nginx-ingress-controller 中的参数 --configmap 自定义关联配置映射实例的名称。
Nginx Ingress 控制器约定 Nginx Ingress 配置映射实例中的键值只能是字符串,即便是数字或布尔值时也要以字符串的形式书写,比如 "true"、"false"、"100","[]string" 或 "[]int" 的 Slice 类型则表示内部数据是以 "," 分隔的字符串。根据配置涉及的功能可以有如下分类。
配置样例如下:
配置样例如下:
Nginx Ingress 控制器约定 Nginx Ingress 配置映射实例中的键值只能是字符串,即便是数字或布尔值时也要以字符串的形式书写,比如 "true"、"false"、"100","[]string" 或 "[]int" 的 Slice 类型则表示内部数据是以 "," 分隔的字符串。根据配置涉及的功能可以有如下分类。
1、Nginx原生配置指令
用以提供向 Nginx 配置中添加 Nginx 原生配置指令,功能说明如下表所示。名称 | 类型 | 默认值 | 功能描述 |
---|---|---|---|
main-snippet | string | "" | 在 main 指令域添加 Nginx 配置指令 |
http-snippet | string | "" | 在 http 指令域添加 Nginx 配置指令 |
server-snippet | string | "" | 在 server 指令域添加 Nginx 配置指令 |
location-snippet | string | "" | 在 location 指令域添加 Nginx 配置指令 |
配置样例如下:
echo ' apiVersion: v1 kind: ConfigMap data: http-snippet: | ancient_browser "UCWEB"; ancient_browser_value oldweb; server { listen 8080; if ($ancient_browser) { rewrite ^ /${ancient_browser}.html; # 重定向到oldweb.html } } metadata: name: nginx-ingress-controller namespace: nginx-ingress ' | kubectl create -f -
2、通用配置
提供 Nginx 核心配置相关配置指令的配置,功能说明如下表所示。名称 | 类型 | 默认值 | Nginx 指令 | 功能描述 |
---|---|---|---|---|
worker-processes | string | auto | worker_processes | 参见《Nginx进程配置指令》一节 |
worker-cpu-affinity | string | "" | worker_cpu_affinity | 参见《Nginx进程配置指令》一节 |
worker-shutdown-timeout | string | 10s | worker_shutdown_timeout | 参见《Nginx进程配置指令》一节 |
max-worker-connections | string | -- | worker_connections | 参见《Nginx进程配置指令》一节 |
max-worker-open-files | string | -- | worker_rlimit_nofile | 参见《Nginx进程配置指令》一节 |
enable-multi-accept | bool | true | multi_accept | 参见《Nginx进程配置指令》一节 |
keep-alive | int | 75 | keepalive_timeout | -- |
keep-alive-requests | int | 100 | keepalive_requests | -- |
variables-hash-bucket-size | int | 128 | variables_hash_bucket_size | -- |
variables-hash-max-size | int | 2048 | variables_hash_max_size | -- |
server-name-hash-max-size | int | 1024 | server_names_hash_max_size | -- |
server-name-hash-bucket-size | int | CPU 缓存行的大小 | server_names_hash_bucket_size | -- |
map-hash-bucket-size | int | 64 | map_hash_bucket_size | -- |
bind-address | []string | "" | listen | 设置虚拟主机绑定的 IP 地址 |
reuse-port | bool | true | listen | 设置监听端口启用 reuseport 参数,由 Linux 内核以套接字分片方式实现进程调度 |
disable-ipv6 | bool | false | listen | -- |
disable-ipv6-dns | bool | false | resolver | 设置是否关闭域名解析的 IPv6 地址查找 |
enable-underscores-in-headers | bool | false | underscores_in_headers | 参见《Nginx处理HTTP请求》一节 |
ignore-invalid-headers | bool | true | ignore_invalid_headers | 参见《Nginx处理HTTP请求》一节 |
client-header-buffer-size | string | 1k | client_header_buffer_size | 参见《Nginx处理HTTP请求》一节 |
client-header-timeout | int | 60 | client_header_timeout | 参见《Nginx处理HTTP请求》一节 |
client-body-buffer-size | string | 8k | client_body_buffer_size | 参见《Nginx处理HTTP请求》一节 |
client-body-timeout | int | 69 | client_body_timeout | 参见《Nginx处理HTTP请求》一节 |
large-client-header-buffers | string | 4 8k | large_client_header_buffers | 参见《Nginx处理HTTP请求》一节 |
http-redirect-code | int | 308 | return | 设置 URL 跳转时的响应码,可选项为 301,302,307 和 308 |
use-geoip | bool | true | -- | 启用 geoip 功能 |
use-geoip2 | bool | false | -- | 启用 geoip2 功能,由第三方模块实现 |
nginx-status-ipv4-whitelist | []string | 127.0.0.1 | -- | 设置允许访问路径 /nginx_status 的 IPv4 地址 |
nginx-status-ipv6-whitelist | []string | ::1 | -- | 设置允许访问路径 /nginx_status 的 IPv6 地址 |
server-tokens | bool | true | server_tokens | 参见《Nginx处理HTTP请求》一节 |
lua-shared-dicts | string | "" | -- | 设置 Lua 共享内存字典,Oper_Resty 扩展指令 |
配置样例如下:
cat>test.yaml<<EOF apiVersion: v1 kind: ConfigMap data: keep-alive: "60" disable-ipv6: "true" metadata: name: nginx-ingress-controller namespace: nginx-ingress EOF kubectl create -f test.yaml
3、响应数据配置
提供响应信息头修改及响应数据压缩相关功能的配置,功能说明如下表所示。名称 | 类型 | 默认值 | Nginx指令 | 功能描述 |
---|---|---|---|---|
add-headers | string | "" | add_header | -- |
use-gzip | bool | true | gzip | 启用 gzip |
gzip-level | int | 5 | gzip_comp_level | 参见《Nginx开启gzip》一节 |
gzip-types | string | application/atom+xml application/javascript application/x-javascript application/json application/rss+xml application/vnd.ms-fontobject application/x-font-ttf application/x-web-app-manifest+json application/xhtml+xml application/xml font/opentype image/svg+xml image/x-icon text/css text/java-script text/plain text/x-component |
gzip_types | 参见《Nginx开启gzip》一节 |
enable-brotli | bool | false | -- | 设置是否加载 brotli 模块 |
brotli-level | int | 4 | -- | 设置 brotli 的压缩级别 |
brotli-types | string | application/xml+rss application/atom+xml application/javascript application/x-javascript application/json applica-tion/rss+xml application/vnd.ms-fontobject application/x-font-ttf application/x-web-app-manifest+json application/xhtml+xml application/xml font/opentype image/svg+xml image/x-icon text/css text/javascript text/plain text/x-com-ponent |
-- | 设置 brotli 的压缩类型 |
4、访问控制
提供限制连接数、访问速度、访问连接及防火墙的配置,功能说明如下表所示。名称 | 类型 | 默认值 | Nginx 指令 | 功能描述 |
---|---|---|---|---|
limit-conn-zone-variable | string | $binary_remote_addr | limit_conn_zone | 参见《Nginx并发连接数限制模块》一节 |
limit-conn-status-code | int | 503 | limit_conn_status | 参见《Nginx并发连接数限制模块》一节 |
limit-rate | int | 0 | limit_rate | -- |
limit-rate-after | int | 0 | limit_rate_after | -- |
limit-req-status-code | int | 503 | limit_req_status | 参见《Nginx请求频率限制模块》一节 |
whitelist-source-range | []string []string{} | -- | allow | 设置允许访问的源 IP 地址 |
block-cidrs | []string | "" | deny | 禁止设置 IP 地址的访问 |
block-user-agents | []string | "" | map | 禁止设置信息头字段 User-Agent 匹配值的访问 |
block-referers | []string | "" | map | 禁止设置信息头字段 Referer 匹配值的访问 |
enable-modsecurity | bool | false | -- | 设置是否加载 Mod-Security 连接模块 |
enable-owasp-modsecurity-crs | bool | false | -- | 设置是否加载 OWASP ModSecurity 核心规则库 |
5、HTTPS配置
提供与 HTTPS 相关的配置,功能说明如下表所示。名称 | 类型 | 默认值 | Nginx指令 | 功能描述 |
---|---|---|---|---|
ssl-ciphers | string | ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384: ECDHE-ECDSA-CHACHA20-POLY-1305:ECDHE-RSA-CHACHA20-POLY1305: ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256: ECDHE-ECDSA-AES256-SHA-384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA -AES-128-SHA256:ECDHE-RSA-AES-128-SHA256 |
ssl-ciphers | 参见《Nginx HTTPS服务器搭建》一节 |
ssl-ecdh-curve | string | auto | ssl_ecdh_curve | 参见《Nginx HTTPS服务器搭建》一节 |
ssl-dhparam | string | "" | ssl_dhparam | 参见《Nginx HTTPS服务器搭建》一节 |
ssl-protocols | string | TLSv1.2 | ssl_protocols | 参见《Nginx HTTPS服务器搭建》一节 |
ssl-early-data | bool | true | ssl_early_data | 参见《Nginx HTTPS服务器搭建》一节 |
ssl-session-cache | bool | true | ssl_session_cache | 参见《Nginx HTTPS服务器搭建》一节 |
ssl-session-cache-size | string | 10m | ssl_session_cache | 参见《Nginx HTTPS服务器搭建》一节 |
ssl-session-tickets | bool | true | ssl_session_tickets | 参见《Nginx HTTPS服务器搭建》一节 |
ssl-session-ticket-key | string | -- | ssl_session_tickets | 参见《Nginx HTTPS服务器搭建》一节 |
ssl-session-timeout | string | 10m | ssl_session_timeout | 参见《Nginx HTTPS服务器搭建》一节 |
ssl-buffer-size | string | 4k | ssl_buffer_size | 参见《Nginx HTTPS服务器搭建》一节 |
ssl-redirect | bool | true | -- | 当被配置的虚拟主机启用了 TLS 支持,则将虚拟主机的 HTTP 请求跳转到 HTTPS 请求 |
no-tls-redirect-locations | string | /.well-known/acme-challenge | -- | 一个以“,”分隔的 location 列表,对列表中 location 的 HTTP 请求永远不会跳转到 HTTPS 请求 |
6、HSTS配置
HSTS(HTTP Strict Transport Security)是一种新的 Web 安全协议,HSTS 配置启用后,将强制客户端使用 HTTPS 协议与服务器建立连接,配置映射提供的 HSTS 功能配置功能说明如下表所示。名称 | 类型 | 默认值 | Nginx指令 | 功能描述 |
---|---|---|---|---|
hsts | bool | true | add_header | 是否运行 SSL 时在消息头中添加 HSTS 属性字段 |
hsts-include-subdomains | bool | true | add_header | 是否在当前域名的所有子域中启用 HSTS |
hsts-max-age | string | 15724800 | add_header | 设置 HSTS Header 的过期时间 |
hsts-preload | bool | false | add_header | 设置是否启用 HSTS 的预加载支持 |
7、认证转发配置
提供认证转发功能的全局配置,功能说明如下表所示。名称 | 类型 | 默认值 | Nginx指令 | 功能描述 |
---|---|---|---|---|
global-auth-url | string | "" | auth_request | 设置外部身份验证的 URL |
global-auth-method | string | "" | proxy_method | 外部认证 URL 的 HTTP 方法 |
global-auth-signin | string | "" | -- | 当外部认证返回 401 时跳转的 URL,通常为提示输人用户名和密码的 URL |
global-auth-response-headers | string | "" | -- | 设置认证请求完成后传递到真实后端的头信息 |
global-auth-request-redirect | string | "" | -- | 设置发送给认证服务器请求头中 X-Auth-Request-Redirect 的值 |
global-auth-snippet | string | "" | -- | 可以自定义在外部认证指令区域添加 Nginx 配置指令 |
global-auth-cache-key | string | "" | -- | 启用认证缓存,并设置认证缓存的关键字 |
global-auth-cache-duration | string | 200 202 401 5m | -- | 基于响应码设置认证缓存的有效时间 |
no-auth-locations | string | /.well-known/acme-challenge | -- | 一个以“,”分隔的 location 列表,列表中被记录的请求将不进行身份认证 |
8、代理配置
设置 Nginx 的代理功能配置,相关配置说明如下表所示。名称 | 类型 | 默认值 | Nginx指令 | 功能描述 |
---|---|---|---|---|
retry-non-idempotent | bool | false | proxy_next_upstream | 参见《Nginx HTTP代理服务器》一节 |
proxy-set-header | string | "" | proxy_set_header | 参见《Nginx HTTP代理服务器》一节 |
proxy-headers-hash-max-size | int | 512 | proxy_headers_hash_max_size | 参见《Nginx HTTP代理服务器》一节 |
proxy-headers-hash-bucket-size | int | 64 | proxy_headers_hash_bucket_size | 参见《Nginx HTTP代理服务器》一节 |
hide-headers | string array | empty | proxy_hide_header | 参见《Nginx HTTP代理服务器》一节 |
proxy-body-size | string | 1m | client_max_body_size | -- |
allow-backend-server-header | bool | false | proxy_pass_header | 设置是否允许将被代理服务器的消息头字段 Server 的值代替 Nginx 的默认值返回给客户端 |
proxy-connect-timeout | int | 5 | proxy_connect_timeout | 参见《Nginx HTTP代理服务器》一节 |
proxy-read-timeout | int | 60 | proxy_read_timeout | 参见《Nginx HTTP代理服务器》一节 |
proxy-send-timeout | int | 60 | proxy_send_timeout | 参见《Nginx HTTP代理服务器》一节 |
proxy-buffers-number | int | 4 | proxy_buffers | 参见《Nginx HTTP代理服务器》一节 |
proxy-buffer-size | string | 4k | proxy_buffer_size | 参见《Nginx HTTP代理服务器》一节 |
proxy-cookie-path | string | off | proxy_cookie_path | 参见《Nginx HTTP代理服务器》一节 |
proxy-cookie-domain | string | off | proxy_cookie_domain | 参见《Nginx HTTP代理服务器》一节 |
proxy-next-upstream | string | error timeout | proxy_next_upstream | 参见《Nginx HTTP代理服务器》一节 |
proxy-next-upstream-timeout | int | 0 | proxy_next_upstream_timeout | 参见《Nginx HTTP代理服务器》一节 |
proxy-next-upstream-tries | int | 3 | proxy_next_upstream_tries | 参见《Nginx HTTP代理服务器》一节 |
proxy-redirect-from | string | off | proxy_redirect | 此处为添加要替换的源文本 |
proxy-redirect-to | string | off | proxy_redirect | 此处为添加要替换的目标文本 |
proxy-request-buffering | string | on | proxy_request_buffering | 参见《Nginx HTTP代理服务器》一节 |
proxy-buffering | string | off | proxy_buffering | 参见《Nginx HTTP代理服务器》一节 |
proxy-add-original-uri-header | bool | true | proxy_set_header | 为发送到后端的请求头添加一个头属性字段 X-Original-Uri,记录原始请求 |
use-forwarded-headers | bool | false | proxy_set_header | 设置是否使用传入的头属性字段 X-Forwarded |
forwarded-for-header | string | X-Forwarded-For | proxy_set_header | 设置用于标识客户端源 IP 的头属性字段名称 X-For-warded |
compute-full-forwarded-for | bool | false | proxy_set_header | 设置是否将远程地址附加到头属性字段 X-For-warded-For 中,而不是替换它 |
custom-http-errors | []int | off | error_page | 该配置会自动启用 Nginx 配置指令 proxy_intercept_errors,默认是关闭的 |
proxy-stream-timeout | string | 600s | proxy_timeout | 参见《Nginx TCP/UDP代理》一节 |
proxy-stream-responses | int | 1 | proxy_responses | 参见《Nginx TCP/UDP代理》一节 |
use-proxy-protocol | bool | false | listen | 启用 proxy_protocol 支持 |
proxy-protocol-header-timeout | string | 5d | proxy_protocol_timeout | 设置接收 proxy-protocol 头的超时时间,可防止 TLS 传递处理程序无限期地等待已断开的连接 |
proxy-real-ip-cidr | []string | 0.0.0.0/0 | set_real_ip_from | 当启用 proxy-protocol 时设置授信 IP,用于后端获得真实客户端 IP |
use-http2 | bool | true | listen | 启用 HTTP2 监听 |
http2-max-field-size | string | 4k | http2_max_field_size | 参见《Nginx HTTP2模块配置》一节 |
http2-max-header-size | string | 16k | http2_max_header_size | 参见《Nginx HTTP2模块配置》一节 |
http2-max-requests | int | 1000 | http2_max_requests | 参见《Nginx HTTP2模块配置》一节 |
9、负载均衡配置
Nginx Ingress 为方便上游服务器组的动态管理,其基于 Lua 实现了轮询调度及峰值指数加权移动平均(Peak Exponentially Weighted Moving-Average,Peak EWMA)负载均衡算法。配置映射的配置为全局负载均衡的配置,详见本节的注解负载均衡说明。配置映射还提供了被代理服务器长连接的配置支持,配置说明如下表所示。名称 | 类型 | 默认值 | Nginx指令 | 功能描述 |
---|---|---|---|---|
load-balance | string | round_robin | -- | 设置负载均衡算法,支持轮询 round_robin 和 Peak EWMA 两种模式,基于 OpenResty 的 balancer_by_lua 模块实现 |
upstream-keepalive-connections | int | 32 | keepalive | 参见《Nginx负载均衡模块》一节 |
upstream-keepalive-timeout | int | 60 | keepalive_timeout | 参见《Nginx负载均衡模块》一节 |
upstream-keepalive-requests | int | 100 | keepalive_requests | 参见《Nginx负载均衡模块》一节 |
10、日志配置
设置 Nginx 的日志功能配置,相关配置说明如下表所示。名称 | 类型 | 默认值 | Nginx指令 | 功能描述 |
---|---|---|---|---|
disable-access-log | bool | false | access-log | 设置 HTTP 指令域 access-log 的指令值为 off |
access-log-params | string | "" | access-log | 设置访问日志的参数 |
access-log-path | string | /var/log/nginx/access.log | access-log | 设置访问日志路径 |
log-format-escape-json | bool | false | log_format | 设置日志格式为 JSON |
log-format-upstream | string | %v-[$the_real_ip]-$remote_user[$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent" $request_length $request_time [$proxy_up-stream_name] $upstream_addr $upstream_response_length $upstream_response_time $upstream_status $req_id |
log_format | HTTP 日志模板 |
skip-access-log-urls | []string | []string{} | access-log | 设置不进行访问日志记录的 URL,access-log 的 if 参数 |
enable-access-log-for-default-backend | bool | false | access-log | 是否开启默认后端的访问日志记录 |
log-format-stream | string | [$time_local] $protocol $status $bytes_sent $bytes_received $session_time | log_format | TCP/UDP 日志模板 |
error-log-path | string | /var/log/nginx/error.log | error_log | 错误日志路径 |
error-log-level | string | notice | error_log | 错误日志级别 |
11、分布式跟踪配置
设置分布式跟踪功能的配置,配置键及功能描述如下表所示。名称 | 类型 | 默认值 | 功能描述 |
---|---|---|---|
generate-request-id | bool | true | 如果请求头中没有属性字段 X-Request-ID,则为该请求随机创建一个,用于分布式链路跟踪 |
enable-opentracing | bool | false | 设置是否加载 opentracing 模块,启用分布式跟踪支持 |
zipkin-collector-host | string | "" | 设置用于上传跟踪信息的 zipkin 主机地址 |
zipkin-collector-port | int | 9411 | 设置用于上传跟踪信息的 zipkin 主机端口 |
zipkin-service-name | string | nginx | 设置用于在 zipkin 中创建跟踪的服务名称 |
zipkin-sample-rate | float | 1.0 | 设置 zipkin 跟踪的采样率 |
jaeger-collector-host | string | "" | 设置用于上传跟踪信息的 jaeger 主机地址 |
jaeger-collector-port | int | 6831 | 设置用于上传跟踪信息的 jaeger 主机端口 |
jaeger-service-name | string | nginx | 设置用于在 jaeger 中创建跟踪的服务名称 |
jaeger-sampler-type | string | const | 设置 jaeger 的采样器名称,可选项为 const、probabilistic、ratelimiting、remote |
jaeger-sampler-param | string | 1 | 设置 jaeger 采样器的参数 |
jaeger-sampler-host | string | http://127.0.0.1 | 设置 jaeger 采样器为 remote 时的主机地址 |
jaeger-sampler-port | int | 5778 | 设置 jaeger 采样器为 remote 时的主机端口 |
Nginx Ingress注解Annotations
Nginx Ingress 注解使用在 Ingress 资源实例中,用以设置当前 Ingress 资源实例中 Nginx 虚拟主机的相关配置,对应配置的是 Nginx 当前虚拟主机的 server 指令域内容。在与 Nginx Ingress 配置映射具有相同功能配置时,将按照所在指令域层级遵循 Nginx 配置规则覆盖。
Nginx Ingress注解按照配置功能有如下分类。
配置样例如下:
配置样例如下:
基本认证配置如下:
配置样例如下:
子集模式的一致性哈希负载算法是将上游服务器组中的被代理服务器分成固定数量的分组,然后把每个分组当作一致性哈希计算的虚拟节点。默认一致性哈希是按照每个被代理服务器为虚拟节点进行计算的。
Peak EWMA 负载均衡算法,是对每个 Pod 请求的往返延时(Round-Trip Time,RTT)计算移动平均值,并用该 Pod 的未完成请求数对这个平均值加权计算,计算值最小的 Pod 端点将被分配新的请求。
配置样例如下:
HTTPS 配置样例如下:
HTTPS 客户端证书身份认证配置样例如下:
Nginx Ingress 支持 Header、cookie 和权重 3 种方式,可单独使用,也可以组合使用。“金丝雀”发布配置说明如下表所示。
“金丝雀”路由规则同时存在时的优先顺序是 canary-by-header、canary-by-cookie、canary-weight。
配置样例如下:
配置样例如下:
配置样例如下:
Nginx Ingress注解按照配置功能有如下分类。
1、Nginx原生配置指令
支持在注解中添加 Nginx 原生配置指令。配置说明如下表所示。注解 | 类型 | 功能描述 |
---|---|---|
nginx.ingress.kubernetes.io/server-snippet | string | 在 server 指令域添加 Nginx 配置指令 |
nginx.ingress.kubernetes.io/configuration-snippet | string | 在 location 指令域添加 Nginx 配置指令 |
配置样例如下:
apiVersion: extensions/v1beta1 kind: Ingress metadata: name: web-nginxbar-org annotations: nginx.ingress.kubernetes.io/server-snippet: | location / { return 302 /coffee; } spec: rules: - host: web.nginxbar.org http: paths: - path: /tea backend: serviceName: tea-svc servicePort: 80 - path: /coffee backend: serviceName: coffee-svc servicePort: 80
2、通用配置
Nginx 虚拟主机中的通用配置。通用配置说明如下表所示。注解 | 类型 | 功能描述 |
---|---|---|
nginx.ingress.kubernetes.io/enable-access-log | true 或 false | 对当前虚拟主机设置是否启用访问日志,默认为真 |
nginx.ingress.kubernetes.io/server-alias | string | 为 Nginx 添加更多的主机名,同 Nginx 配置指令 server name |
nginx.ingress.kubernetes.io/app-root | string | 将当前虚拟主机根目录的访问 302 跳转到当前指定的路径 |
nginx.ingress.kubernetes.io/client-body-buffer-size | string | 同 Nginx 配置指令 client_body_buffer_size |
nginx.ingress.kubernetes.io/use-regex | true 或 false | 是否对当前虚拟主机的 Nginx 指令 location 使用正则方式进行路径匹配,默认值为 false |
nginx.ingress.kubernetes.io/custom-http-errors | []int | 根据响应码状态定义为错误状态并跳转到设置的默认后端 |
nginx.ingress.kubernetes.io/default-backend | string | 自定义默认后端的资源对象 Service 名称,当客户端的请求没有匹配的 Nginx 规则或响应错误时,将被转发到默认后端 |
nginx.ingress.kubernetes.io/whitelist-source-range | CIDR | 功能同 ConfigMap 配置键 whitelist-source-range |
nginx.ingress.kubernetes.io/permanent-redirect | string | 设置永久重定向的目标地址 |
nginx.ingress.kubernetes.io/permanent-redirect-code | number | 自定义永久重定向的响应码,默认为 301 |
nginx.ingress.kubernetes.io/temporal-redirect | string | 设置临时重定向的目标地址 |
nginx.ingress.kubernetes.io/from-to-www-redirect | true 或 false | 设置是否将当前虚拟主机子域名为 www 的请求跳转到当前主机域名 |
nginx.ingress.kubernetes.io/rewrite-target | URI | 同 Nginx 配置指令 rewrite |
nginx.ingress.kubernetes.io/enable-rewrite-log | true 或 false | 同 Nginx 配置指令 rewrite log,默认为 false |
nginx.ingress.kubernetes.io/mirror-uri | string | 同 Nginx 配置指令 mirro |
nginx.ingress.kubernetes.io/mirror-request-body | true 或 false | 同 Nginx 配置指令 mirror_request_body,默认为 true |
配置样例如下:
apiVersion: extensions/v1beta1 kind: Ingress metadata: name: web-nginxbar-org namespace: default annotations: nginx.ingress.kubernetes.io/rewrite-target: /tea/$1 nginx.ingress.kubernetes.io/enable-rewrite-log: "true" spec: rules: - host: web.nginxbar.org # 此service的访问域名 http: paths: - backend: serviceName: nginx-web servicePort: 8080 path: /coffee/(.+)
3、访问控制
用以设置基于流量、请求连接数、请求频率的访问控制。访问控制配置说明如下表所示。注解 | 类型/选项 | 功能描述 |
---|---|---|
nginx.ingress.kubernetes.io/limit-rate | number | 访问流量速度限制,同 Nginx 配置指令 limit_rate |
nginx.ingress.kubernetes.io/limit-rate-after | number | 启用访问流量速度限制的最大值,同 Nginx 配置指令 limit_rate_after |
nginx.ingress.kubernetes.io/limit-connections | number | 节并发连接数限制,同 Nginx 配置指令 limit_conn |
nginx.ingress.kubernetes.io/limit-rps | number | 每秒请求频率限制,burst 参数为给定值的 5 倍,响应状态码由 ConfigMap 的 limit-req-status-code 设定 |
nginx.ingress.kubernetes.io/limit-rpm | number | 每分钟请求频率限制,burst 参数为给定值的 5 倍,响应状态码由 ConfigMap 的 limit-req-status-code 设定 |
nginx.ingress.kubernetes.io/limit-whitelist | CIDR | 对以上限制设置基于 IP 的白名单 |
4、认证管理
Nginx Ingress 提供了基本认证、摘要认证和外部认证 3 种方式,为被代理服务器提供认证支持。认证管理配置说明如下表所示。注解 | 类型 | 功能描述 |
---|---|---|
nginx.ingress.kubernetes.io/enable-global-auth | true 或 false | 如果 ConfigMap 的 global-auth-url 被设置,Nginx 会将所有的请求重定向到提供身份验证的 URL,默认为 true |
nginx.ingress.kubernetes.io/satisfy | string | 同 Nginx 配置指令 satisfy |
nginx.ingress.kubernetes.io/auth-type | basic 或 digest | 设置 HTTP 认证类型,支持基本和摘要两种类型 |
nginx.ingress.kubernetes.io/auth-secret | string | 指定关联资源对象 secret 的名称 |
nginx.ingress.kubernetes.io/auth-realm | string | 设置基本认证的提示信息 auth_basic |
nginx.ingress.kubernetes.io/auth-url | string | 设置提供外部身份认证的 URL,由 Nginx 配置指令 auth_request 提供该功能 |
nginx.ingress.kubernetes.io/auth-signin | string | 设置当外部认证返回 401 时跳转的 URL,通常为提示输入用户名和密码的 URL |
nginx.ingress.kubernetes.io/auth-method | string | 指定访问外部认证 URL 的 HTTP 方法,由 Nginx 配置指令 proxy_method 提供该功能 |
nginx.ingress.kubernetes.io/auth-request-redirect | string | 设置发送给认证服务器请求头中 X-Auth-Request-Redirect 的值 |
nginx.ingress.kubernetes.io/auth-cache-key | string | 启用认证缓存,并设置认证缓存的关键字 |
nginx.ingress.kubernetes.io/auth-cache-duration | string | 基于响应码设置认证缓存的有效时间 |
nginx.ingress.kubernetes.io/auth-response-headers | string | 设置认证请求完成后传递到真实后端的头信息 |
nginx.ingress.kubernetes.io/auth-snippet | string | 可以自定义在外部认证指令区域添加 Nginx 配置指令 |
基本认证配置如下:
# 创建基本认证用户名nginxbar、密码123456,输出文件名必须是auth htpasswd -bc auth nginxbar 123456 # 创建资源对象secret保存账号和密码 kubectl create secret generic basic-auth --from-file=auth # 查看创建的basic-auth kubectl get secret basic-auth -o yaml # 创建基本认证的Ingress实例 cat>auth-nginxbar-org.yaml<<EOF apiVersion: extensions/v1beta1 kind: Ingress metadata: name: auth-nginxbar-org namespace: default annotations: # 设置认证类型 nginx.ingress.kubernetes.io/auth-type: basic # 关联账号和密码 nginx.ingress.kubernetes.io/auth-secret: basic-auth # 显示认证提示信息 nginx.ingress.kubernetes.io/auth-realm: 'Authentication Required for web.nginxbar.org' spec: rules: - host: auth.nginxbar.org # 此service的访问域名 http: paths: - backend: serviceName: nginx-web servicePort: 8080 EOF kubectl create -f auth-nginxbar-org.yaml认证转发配置样例如下:
apiVersion: extensions/v1beta1 kind: Ingress metadata: name: auth-nginxbar-org namespace: default annotations: nginx.ingress.kubernetes.io/auth-url: "http://$host/auth2" nginx.ingress.kubernetes.io/auth-signin: "http://$host/auth/start" nginx.ingress.kubernetes.io/auth-method: "POST" nginx.ingress.kubernetes.io/auth-cache-key: "foo", nginx.ingress.kubernetes.io/auth-cache-duration": "200 202 401 30m" nginx.ingress.kubernetes.io/auth-snippet: | proxy_set_header Foo-Header 42; spec: rules: - host: auth.nginxbar.org # 此service的访问域名 http: paths: - backend: serviceName: nginx-web servicePort: 8080
5、跨域访问
跨域访问功能配置说明如下表所示。注解 | 类型 | 功能描述 |
---|---|---|
nginx.ingress.kubernetes.io/enable-cors | true 或 false | 是否启用跨域访问支持,默认为 false |
nginx.ingress.kubernetes.io/cors-allow-origin | string | 允许跨域访问的域名,默认为 *,表示接受任意域名的访问 |
nginx.ingress.kubernetes.io/cors-allow-methods | string | 允许跨域访问方法,默认为 GET、PUT、POST、DELETE、PATCH、OPTIONS |
nginx.ingress.kubernetes.io/cors-allow-headers | string | 允许跨域访问的请求头,默认为 DNT,X-CustomHeader、Keep-Alive、User-Agent、X-Requested-With、If-Modified-Since、Cache-Control、Content-Type、Authorization |
nginx.ingress.kubernetes.io/cors-allow-credentials | true 或 false | 设置在响应头中 Access-Control-Allow-Credentials 的值,设置是否允许客户端携带验证信息,如 cookie 等,默认为 true |
nginx.ingress.kubernetes.io/cors-max-age | number | 设置响应头中 Access-Control-Max-Age 的值,设置返回结果可以用于缓存的最长时间,默认为 1728000 秒 |
配置样例如下:
apiVersion: extensions/v1beta1 kind: Ingress metadata: name: web-nginxbar-org namespace: default annotations: nginx.ingress.kubernetes.io/cors-allow-headers: >- DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With, If-Modified-Since,Cache-Control,Content-Type,Authorization nginx.ingress.kubernetes.io/cors-allow-methods: 'PUT, GET, POST, OPTIONS' nginx.ingress.kubernetes.io/cors-allow-origin: '*' nginx.ingress.kubernetes.io/enable-cors: "true" nginx.ingress.kubernetes.io/cors-max-age: 600 spec: rules: - host: web.nginxbar.org http: paths: - backend: serviceName: nginx-web servicePort: 8080 path: /
6、代理配置
Nginx 代理相关功能配置说明如下表所示。注解 | 类型/选项 | 功能描述 |
---|---|---|
nginx.ingress.kubernetes.io/service-upstream | true 或 false | 默认 Nginx 以 Service 中 Pod 的 IP 和端口为 Upstream 中的成员列表,该参数为 true 时,将以 Service 的 ClusterIP 和端口为被代理入口,该功能避免了因 Pod 漂移带来的 Upstream 的配置变化 |
nginx.ingress.kubernetes.io/backend-protocol | НТТР 或 HTTPS 或 GRPC 或 GRPCS 或 AJP 或 FCGI |
设置代理后端服务器的代理协议类型,默认为 HTTP |
nginx.ingress.kubernetes.io/proxy-body-size | string | 同 Nginx 配置指令 client_max_body-size,默认为 1m |
nginx.ingress.kubernetes.io/proxy-cookie-do-main | string | 同 Nginx 配置指令 proxy_cookie_domain |
nginx.ingress.kubernetes.io/proxy-cookie-path | string | 同 Nginx 配置指令 proxy_cookie_path |
nginx.ingress.kubernetes.io/proxy-connect-timeout | number | 同 Nginx 配置指令 proxy_connect_timeout |
nginx.ingress.kubernetes.io/proxy-send-time-out | number | 同 Nginx 配置指令 proxy_send_timeout |
nginx.ingress.kubernetes.io/proxy-read-time-out | number | 同 Nginx 配置指令 proxy_read_timeout |
nginx.ingress.kubernetes.io/proxy-next-up-stream | string | 同 Nginx 配置指令 proxy_next_upstream |
nginx.ingress.kubernetes.io/proxy-next-up-stream-timeout | number | 同 Nginx 配置指令 proxy_next_upstream_timeout |
nginx.ingress.kubernetes.io/proxy-next-up-stream-tries | number | 同 Nginx 配置指令 proxy_next_upstream_tries |
nginx.ingress.kubernetes.io/proxy-buffering | string | 同 Nginx 配置指令 proxy_buffering |
nginx.ingress.kubernetes.io/proxy-buffers-number | number | 同 Nginx 配置指令 proxy_buffers |
nginx.ingress.kubernetes.io/proxy-buffer-size | string | 同 Nginx 配置指令 proxy_buffer_size |
nginx.ingress.kubernetes.io/proxy-request-buffering | string | 同 Nginx 配置指令 proxy_request_buffering |
nginx.ingress.kubernetes.io/proxy-http-ver-sion | 1.0 或 1.1 | 同 Nginx 配置指令 proxy_http_version,默认为 1.1 |
nginx.ingress.kubernetes.io/upstream-vhost | string | 自定义发送到上游服务器的信息头字段中 Host 的内容,相当于 Nginx 配置指令 proxy_set_header Host $host 的设置 |
nginx.ingress.kubernetes.io/proxy-redirect-from | string | 设置要替换的源文本,同 Nginx 配置指令 proxy_redirect |
nginx.ingress.kubernetes.io/proxy-redirect-to | string | 设置要替换的目标文本,同 Nginx 配置指 proxy redirect |
nginx.ingress.kubernetes.io/connection-proxy-header | string | 设置发送到被代理服务器请求头中字段属性 connection 的值,相当于 Nginx 配置指令 proxy_set_header Connection 的状态为 Keep-Alive |
nginx.ingress.kubernetes.io/x-forwarded-prefix | string | 创建并设置代理请求头属性字段 X-Forwarded-Prefix 属性,用以向后端传递请求路径 |
nginx.ingress.kubernetes.io/http2-push-pre-load | true 或 false | 同 Nginx 配置指令 http2-push-preload,默认值为 false |
7、负载均衡
为方便上游服务器组的动态管理,Nginx Ingress 基于 Lua 实现了一致性哈希、基于子集的一致性哈希、轮询调度及峰值指数加权移动平均(Peak Exponentially Weighted Moving-Average,Peak EWMA)负载均衡算法。负载均衡配置说明如下表所示。注解 | 类型/选项 | 功能描述 |
---|---|---|
nginx.ingress.kubernetes.io/upstream-hash-by | string | 同 Nginx 配置指令 hash,此处默认为一致性哈希负载算法,允许除了客户端 IP 或 cookie 之外的会话粘连 |
nginx.ingress.kubernetes.io/upstream-hash-by-subset | true 或 false | 设置是否使用子集模式的一致性哈希负载算法,默认为 false |
nginx.ingress.kubernetes.io/upstream-hash-by-subset-size | int | 设置子集模式中上游服务器分组的大小,默认为 3 |
nginx.ingress.kubernetes.io/load-balance | round_robin 或 ewma | 设置负载均衡算法,基于 balancer_by_lua 模块实现,支持轮询和 Peak EWMA 两种负载算法 |
子集模式的一致性哈希负载算法是将上游服务器组中的被代理服务器分成固定数量的分组,然后把每个分组当作一致性哈希计算的虚拟节点。默认一致性哈希是按照每个被代理服务器为虚拟节点进行计算的。
Peak EWMA 负载均衡算法,是对每个 Pod 请求的往返延时(Round-Trip Time,RTT)计算移动平均值,并用该 Pod 的未完成请求数对这个平均值加权计算,计算值最小的 Pod 端点将被分配新的请求。
8、会话保持配置
设置基于 cookie 的会话亲缘关系,也就是会话保持功能。启用基于 cookie 的会话保持功能时,可以使同一客户端的请求始终转发给同一后端服务器。Nginx Ingress 对启用会话保持功能的 Service 集群使用一致性哈希负载算法,即使后端 Pod 数量变化,也不会对会话保持功能产生太大的影响。会话保持配置说明如下表所示。注解 | 类型 | 功能描述 |
---|---|---|
nginx.ingress.kubernetes.io/affinity | cookie | 设置会话保持类型,目前只有 cookie 类型 |
nginx.ingress.kubernetes.io/session-cookie-name | string | 设置 cookie 名称,默认为 INGRESSCOOKIE |
nginx.ingress.kubernetes.io/session-cookie-path | string | 设置 cookie 字段 path 的值,默认值为当前资源实例 path 的设置。如果启用 use-regex 功能,使用正则匹配时,必须单独指定,不能使用默认值 |
nginx.ingress.kubernetes.io/session-cookie-max-age | -- | 设置 cookie 字段 max-age 的值,表示 cookie 过期时间 |
nginx.ingress.kubernetes.io/session-cookie-expires | -- | 为兼容旧的浏览器,设置 cookie 字段 expires 的值,表示 cookie 过期时间 |
nginx.ingress.kubernetes.io/session-cookie-change-on-failure | true 或 false | 当会话保持的被代理服务器请求失败时,如果设置值为 true,则将下次请求更改为向另一台被代理服务器转发,否则继续向当前被代理服务器转发请求 |
配置样例如下:
apiVersion: extensions/v1beta1 kind: Ingress metadata: name: web-nginxbar-org annotations: nginx.ingress.kubernetes.io/affinity: "cookie" nginx.ingress.kubernetes.io/session-cookie-name: "route" nginx.ingress.kubernetes.io/session-cookie-expires: "172800" nginx.ingress.kubernetes.io/session-cookie-max-age: "172800" spec: rules: - host: web.nginxbar.org http: paths: - backend: serviceName: nginx-web servicePort: 8080 path: /
9、HTTPS配置
HTTPS 功能的配置说明如下表所示。注解 | 类型 | 功能描述 |
---|---|---|
nginx.ingress.kubernetes.io/force-ssl-redirect | true 或 false | 当客户端的 HTTPS 被外部集群进行 SSL 卸载(SSL offloading)时,仍将 HTTP 的请求强制跳转到 HTTPS 端口 |
nginx.ingress.kubernetes.io/ssl-redirect | true 或 false | 设置当前虚拟主机支持 HTTPS 请求时,是否将 HTTP 的请求强制跳转到 HTTPS 端口,全局默认为 true |
nginx.ingress.kubernetes.io/ssl-passthrough | true 或 false | 设置是否启用 SSL 透传 |
nginx.ingress.kubernetes.io/auth-tls-secret | string | 设置客户端证书的资源对象名称 |
nginx.ingress.kubernetes.io/ssl-ciphers | string | 设置 TLS 用于协商使用的加密算法组合,同 Nginx 配置指令 ssl_ciphers |
nginx.ingress.kubernetes.io/auth-tls-verify-client | string | 是否启用客户端证书验证,同 Nginx 配置指令 ssl_verify_client |
nginx.ingress.kubernetes.io/auth-tls-verify-depth | number | 客户端证书链的验证深度同 Nginx 配置指令 ssl_verify_depth |
nginx.ingress.kubernetes.io/auth-tls-error-page | string | 设置客户端证书验证错误时的跳转页面 |
nginx.ingress.kubernetes.io/auth-tls-pass-certificate-to-upstream | true 或 false | 指定证书是否传递到上游服务器 |
nginx.ingress.kubernetes.io/secure-verify-ca-secret | string | 设置是否启用对被代理服务器的 SSL 证书验证功能 |
HTTPS 配置样例如下:
# 创建TLS证书 openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /data/apps/certs/dashboard.key -out /data/apps/certs/dashboard.crt -subj "/CN=dashboard.nginxbar.org/O=dashboard.nginxbar.org" kubectl -n kube-system create secret tls ingress-secret --key /data/apps/certs/dashboard.key --cert /data/apps/certs/dashboard.crt # 创建HTTPS服务 cat>dashboard-ingress.yaml<<EOF apiVersion: extensions/v1beta1 kind: Ingress metadata: name: dashboard-ingress namespace: kube-system annotations: nginx.ingress.kubernetes.io/ingress.class: nginx # 使用HTTPS协议代理后端服务器 nginx.ingress.kubernetes.io/backend-protocol: "HTTPS" # 启用SSL透传 nginx.ingress.kubernetes.io/ssl-passthrough: "true" spec: tls: - hosts: - dashboard.nginxbar.org secretName: ingress-secret rules: - host: dashboard.nginxbar.org http: paths: - path: / backend: serviceName: kubernetes-dashboard servicePort: 443 EOF kubectl create -f dashboard-ingress.yaml curl -k -H "Host:dashboard.nginxbar.org" https://10.103.196.209Nginx-ingress 在用户没有提供证书的情况下会提供一个内置的默认 TLS 证书,如果 secretName 参数没有配置或配置错误,Nginx 会使用系统默认的证书,所以配置后仍需检查确认。
HTTPS 客户端证书身份认证配置样例如下:
# 创建客户端证书资源对象default/ca-secret apiVersion: extensions/v1beta1 kind: Ingress metadata: annotations: # 启用客户端证书验证 nginx.ingress.kubernetes.io/auth-tls-verify-client: "on" # 绑定客户端证书的资源对象名称,是命名空间default的ca-secret nginx.ingress.kubernetes.io/auth-tls-secret: "default/ca-secret" # 客户端证书链的验证深度为1 nginx.ingress.kubernetes.io/auth-tls-verify-depth: "1" # 设置客户端证书验证错误时的跳转页面 nginx.ingress.kubernetes.io/auth-tls-error-page: "http://www.mysite.com/error-cert.html" # 指定证书传递到上游服务器 nginx.ingress.kubernetes.io/auth-tls-pass-certificate-to-upstream: "true" name: nginx-test namespace: default spec: rules: - host: mydomain.com http: paths: - backend: serviceName: http-svc servicePort: 80 path: / tls: - hosts: - mydomain.com secretName: tls-secret
10、“金丝雀”发布
“金丝雀”发布又称为灰度发布,灰度发布功能可以将用户请求按照指定的策略进行分割,并转发到不同的代理服务器组,通过不同的代理服务器部署应用不同版本可进行对照比较,因该方式对于新版本而言类似于使用“金丝雀”的方式进行测试,所以也叫“金丝雀”发布。Nginx Ingress 支持 Header、cookie 和权重 3 种方式,可单独使用,也可以组合使用。“金丝雀”发布配置说明如下表所示。
注解 | 类型 | 功能描述 |
---|---|---|
nginx.ingress.kubernetes.io/canary | true 或 false | 启用“金丝雀”发布功能 |
nginx.ingress.kubernetes.io/canary-by-header | string | 设置请求头属性字段的名称,用于根据该字段的值判断是否将请求路由到“金丝雀”服务器组,该字段值为 always 时则该请求被路由到“金丝雀”服务器组;该字段值为 never 时则不路由到“金丝雀”服务器组 |
nginx.ingress.kubernetes.io/canary-by-header-value | string | 自定义用于判断是否路由到“金丝雀”服务器组的请求头字段值,默认为 always,必须与 canary-by-header同时使用 |
nginx.ingress.kubernetes.io/canary-by-cookie | string | 设置 cookie 的字段名称,用于根据该字段的值判断是否将请求路由到“金丝雀”服务器组。always 则路由到“金丝雀”服务器组;never 则永远不路由到“金丝雀”服务器组 |
nginx.ingress.kubernetes.io/canary-weight | number | 将请求基于整数(0~100)的请求百分比随机路由到“金丝雀”服务器组;100 表示所有请求都路由到“金丝雀”服务器组;0 表示不路由任何请求到“金丝雀”服务器组 |
“金丝雀”路由规则同时存在时的优先顺序是 canary-by-header、canary-by-cookie、canary-weight。
配置样例如下:
# 创建主机web.nginxbar.org的Ingress资源配置 apiVersion: extensions/v1beta1 kind: Ingress metadata: name: web-nginxbar-org namespace: default annotations: nginx.ingress.kubernetes.io/ingress.class: "nginx" spec: rules: - host: web.nginxbar.org # 此service的访问域名 http: paths: - backend: serviceName: nginx-web servicePort: 8080 # 创建主机web.nginxbar.org金丝雀组的Ingress资源配置 apiVersion: extensions/v1beta1 kind: Ingress metadata: name: web-nginxbar-org-canary namespace: default annotations: nginx.ingress.kubernetes.io/ingress.class: "nginx" nginx.ingress.kubernetes.io/canary: "true", # 根据请求头字段CanaryByHeader的值进行判断 nginx.ingress.kubernetes.io/canary-by-header: "CanaryByHeader", # 请求头字段CanaryByHeader的值为DoCanary时,路由到“金丝雀”服务器组 nginx.ingress.kubernetes.io/canary-by-header-value: "DoCanary", # 根据Cookie字段CanaryByCookie的值进行判断 nginx.ingress.kubernetes.io/canary-by-cookie: "CanaryByCookie", # 随机10%的请求路由到“金丝雀”服务器组 nginx.ingress.kubernetes.io/canary-weight: "10", spec: rules: - host: web.nginxbar.org # 此service的访问域名 http: paths: - backend: serviceName: nginx-web-canary servicePort: 8080
11、lua-resty-waf模块
lua-resty-waf 是一个基于 OpenResty 的高性能 Web 应用防火墙,对当前虚拟主机的访问可以按照相关防火墙规则进行访问过滤。模块配置说明如下表所示。注解 | 类型 | 功能描述 |
---|---|---|
nginx.ingress.kubernetes.io/lua-resty-waf | string | 设置 WAF 防火墙的工作模式,inactive 表示不执行任何操作;active 表示启用:simulate 模式下,如果给定请求有匹配的规则,它将记录一条警告消息而不进行处理。这有助于在完全部署规则之前调试规则并消除可能的误报 |
nginx.ingress.kubernetes.io/lua-resty-waf-debug | true 或 false | 设置是否启用调试功能,默认值为 false |
nginx.ingress.kubernetes.io/lua-resty-waf-ignore-rulesets | string | 设置忽略规则集的名称,当某些规则集(如 sqli 或 xss crs 规则集)太容易误报或不适用时,可通过该设置进行忽略处理 |
nginx.ingress.kubernetes.io/lua-resty-waf-extra-rules | string | 设置自定义的规则 |
nginx.ingress.kubernetes.io/lua-resty-waf-allow-unknown-content-types | true 或 false | 设置在发送了不在允许内容类型表中的内容类型头时是否继续处理请求。默认允许的为 text/html、text/json、application/json 的文档类型,默认值为 false |
nginx.ingress.kubernetes.io/lua-resty-waf-score-threshold | number | 设置请求异常评分的阈值,如果超过这个阈值,则拒绝该请求,默认值为 5 |
nginx.ingress.kubernetes.io/lua-resty-waf-process-multipart-body | true 或 false | 设置是否使用 lua-resty-upload 模块对 multipart/form-data 类型请求体的处理,默认为 true |
12、ModSecurity模块配置
ModSecurity 是一个开源的 Web 应用防火墙。必须首先通过在 ConfigMap 中启用 Mod-Security 来加载 ModSecurity 模块。这将为所有路径启用 ModSecurity 过滤,可以手动在 Ingress 资源实例中禁用此功能。ModSecurity 模块配置说明如下表所示。注解 | 类型 | 功能描述 |
---|---|---|
nginx.ingress.kubernetes.io/enable-mod-security | bool | 设置是否启用 ModSecurity 过滤,启用时应用推荐的规则以仅检测(Detection-Only)模式运行 |
nginx.ingress.kubernetes.io/enable-owasp-core-rules | bool | 设置是否使用 OWASP 核心规则进行请求检测 |
nginx.ingress.kubernetes.io/modsecurity-transaction-id | string | 设置从 Nginx 传递事务 ID,而不是在库中自动生成,有利于在 ModSecurity 中跟踪查看检测的请求,对应模块配置指令为 modsecurity_transaction_id |
nginx.ingress.kubernetes.io/modsecurity-snippet | string | 添加模块配置指令 modsecurity_rules 的内容 |
配置样例如下:
apiVersion: extensions/v1beta1 kind: Ingress metadata: name: web-nginxbar-org annotations: nginx.ingress.kubernetes.io/enable-modsecurity: "true" nginx.ingress.kubernetes.io/enable-owasp-core-rules: "true" nginx.ingress.kubernetes.io/modsecurity-transaction-id: "$request_id" nginx.ingress.kubernetes.io/modsecurity-snippet: | SecRuleEngine On SecDebugLog /tmp/modsec_debug.log spec: rules: - host: web.nginxbar.org http: paths: - backend: serviceName: nginx-web servicePort: 8080 path: /
13、Influxdb模块配置
通过使用 Nginx Influxdb 模块,可以用 UDP 协议将请求记录实时发送到后端的 Influxdb 服务器。Influxdb 模块配置说明如下表所示。注解 | 类型 | 功能描述 |
---|---|---|
nginx.ingress.kubernetes.io/enable-influxdb | true 或 false | 是否启用 Influxdb 输出功能 |
nginx.ingress.kubernetes.io/influxdb-measurement | string | 指定 Influxdb 中的 measurement 名称 |
nginx.ingress.kubernetes.io/influxdb-port | string | 指定 Influxdb 的端口 |
nginx.ingress.kubernetes.io/influxdb-host | string | 指定 Influxdb 的 IP 地址 |
nginx.ingress.kubernetes.io/influxdb-server-name | string | 设置自己的应用标识 |
配置样例如下:
apiVersion: extensions/v1beta1 kind: Ingress metadata: name: web-nginxbar-org annotations: nginx.ingress.kubernetes.io/enable-influxdb: "true" nginx.ingress.kubernetes.io/influxdb-measurement: "nginxbar-reqs" nginx.ingress.kubernetes.io/influxdb-port: "8089" nginx.ingress.kubernetes.io/influxdb-host: "192.168.2.110" nginx.ingress.kubernetes.io/influxdb-server-name: "nginxbar-com" spec: rules: - host: web.nginxbar.org http: paths: - backend: serviceName: nginx-web servicePort: 8080 path: /