前言:在本章的内容中,注意一些域名的访问,要在自己的win中hosts文件中做映射欧

一、Service 的概念

Kubernetes Service 定义了这样一种抽象:一个 Pod 的逻辑分组,一种可以访问它们的策略 – 通常称为微服务。 这一组 Pod 能够被 Service 访问到,通常是通过 Label Selector
在这里插入图片描述
因为这三个pod都有 标签app=webapprole-frontend,所以都爱莫能助最上面的那个 svc,所以我们可以通过svc提供的ip和端口来访问内部的三个pod,后续如果pod的ip发生改变,或者增加减少pod,都会在svc中记录,我们不需要关系,目前svc只有一个轮询的算法。

Service能够提供负载均衡的能力,但是在使用上有以下限制

  • 只提供 4 层负载均衡能力,而没有 7 层功能,但有时我们可能需要更多的匹配规则来转发请求,这点上 4 层负载均衡是不支持的。(后续可以使用 igneress模块来满足七层)

二、Service 的类型

Service 在 K8s 中有以下四种类型

项目Value
ClusterIp默认类型,自动分配一个仅 Cluster 内部可以访问的虚拟 IP,即other-pod也在当前节点,可以通过当前节点的svc来访问nginx-deployment的三个pod在这里插入图片描述
NodePort在 ClusterIP 基础上为 Service 在每台机器上绑定一个端口,这样就可以通过 : NodePort 来访问该服务;但是这个nginx这个地方就需要我们自己做了,对于下面一个类型LoadBalancer可以花钱让云厂商提供,这也是这两者的区别了。在这里插入图片描述
LoadBalancer在 NodePort 的基础上,借助 cloud provider 创建一个外部负载均衡器,并将请求转发到: NodePort;在这里插入图片描述
ExternalName把集群外部的服务引入到集群内部来,在集群内部直接使用。没有任何类型代理被创建,这只有 kubernetes 1.7 或更高版本的 kube-dns 才支持;在这里插入图片描述

三、Service 的实现

在这里插入图片描述

VIP 和 Service 代理

在 Kubernetes 集群中,每个 Node 运行一个 kube-proxy 进程。 kube-proxy 负责为 Service 实现了一种VIP(虚拟 IP)的形式,而不是 ExternalName 的形式。 在 Kubernetes v1.0 版本,代理完全在 userspace。在Kubernetes v1.1 版本,新增了 iptables代理,但并不是默认的运行模式。 从 Kubernetes v1.2 起,默认就是iptables 代理。 在 Kubernetes v1.8.0-beta.0 中,添加了 ipvs 代理
在 Kubernetes 1.14 版本开始默认使用 ipvs 代理在 Kubernetes v1.0 版本, Service 是 “4层”(TCP/UDP over IP)概念。 在 Kubernetes v1.1 版本,新增了Ingress API(beta 版),用来表示 “7层”(HTTP)服务

即三种方式

  • userspace
    在这里插入图片描述

  • iptables 即通过防火墙的方式实现。
    在这里插入图片描述

  • ipvs 最好的实现

这种模式,kube-proxy 会监视 Kubernetes Service 对象和 Endpoints ,调用 netlink 接口以相应地创建ipvs 规则并定期与 Kubernetes Service 对象和 Endpoints 对象同步 ipvs 规则,以确保 ipvs 状态与期望一致。访问服务时,流量将被重定向到其中一个后端 Pod与 iptables 类似,ipvs 于 netfilter 的 hook 功能,但使用哈希表作为底层数据结构并在内核空间中工作。这意味着 ipvs 可以更快地重定向流量,并且在同步代理规则时具有更好的性能。此外,ipvs 为负载均衡算法提供了更多选项,例如:
rr :轮询调度
lc :最小连接数
dh :目标哈希
sh :源哈希
sed :最短期望延迟
nq : 不排队调度

在这里插入图片描述

四、Service 类型实验

注意以下的实验的svc的实现,是根据你的svc的具体实现来处理的,比如下面的文章都是说使用iptables,如果你使用的是 ipvs ,那么把文章中对应的 iptables 的字段换成 ipvs,看文档即可

4.1、ClusterIP

clusterIP 主要在每个 node 节点使用 iptables(如这里换成ipvs),将发向 clusterIP 对应端口的数据,转发到 kube-proxy 中。然后 kube-proxy 自己内部实现有负载均衡的方法,并可以查询到这个 service 下对应 pod 的地址和端口,进而把数据转发给对应的 pod 的地址和端口

在这里插入图片描述
为了实现图上的功能,主要需要以下几个组件的协同工作:

  • apiserver

用户通过kubectl命令向apiserver发送创建service的命令,apiserver接收到请求后将数据存储到etcd中

  • kube-proxy

kubernetes的每个节点中都有一个叫做kube-porxy的进程,这个进程负责感知service,pod的变化,并将变化的信息写入本地的iptables (如这里换成ipvs)规则中

  • iptables

使用NAT等技术将virtualIP的流量转至endpoint中

先创建deployment

vim svc-deployment.yaml

内容如下:

apiVersion: apps/v1
kind: Deployment # 类型
metadata:
  name: myapp-deploy  # 名称
  namespace: default
spec:
  replicas: 3 # 副本数
  selector:
    matchLabels:
      app: myapp  # 当前 deployment 只管理 标签为 app=myapp 和 release=stabel的pod
      release: stabel
  template:
    metadata:
      labels:
        app: myapp  # 为当前pod 设置 标签,不然无法被当前deployment 管理,以及后面的svc管理
        release: stabel
        env: test
    spec:
      containers:
      - name: myapp
        image: wangyanglinux/myapp:v2
        imagePullPolicy: IfNotPresent
        ports:
        - name: http
          containerPort: 80

在这里插入图片描述

创建svc,注意svc的标签选择,一定要匹配到对应的pod

vim svc.yaml

内容如下

apiVersion: v1
kind: Service
metadata:
  name: myapp # 这个svc的名称
  namespace: default 
spec:
  type: ClusterIP  # 类型,这个类型只能集群内部访问
  selector:
    app: myapp  # 注意这里的标签选择,要能选择到前面的那些pod,不然这个svc就创建了个寂寞,没有可以映射的pod
    release: stabel
  ports:
  - name: http
    port: 80
    targetPort: 80

在这里插入图片描述

查看svc

ipvsadm -Ln

在这里插入图片描述
2.702.691.66 就是那三个对应的pod地址
在这里插入图片描述

4.2、headless(一种特殊的 clusterIp)

创建,至于deployment 采用4.1中的的即可

vim svc-none.yaml

具体内容如下:

piVersion: v1
kind: Service
metadata:
  name: myapp-headless
  namespace: default
spec:
  selector:
    app: myapp
  clusterIP: "None"  # 只有这里和 clusterIP 类型不同
  ports: 
  - port: 80
    targetPort: 80

在这里插入图片描述
我们每创建一个svc,都会在k8s的coredns中记录

kubectl ge pod -n kube-system -o wide

在这里插入图片描述

# 对 svcname.namespece.svc.cluster.local. 使用 10.224.0.7(选择10.244.0.6也行看上面截图,二个ip选一个)来解析
dig -t A myapp-headless.default.svc.cluster.local. @10.224.0.7

解析结果如下,意思就是我们也可以进行域名访问(em…感觉不是那么的靠谱,好像不是这个意思,哈哈哈哈
在这里插入图片描述

4.3、node port

一个pod可以对应多个 svc,即你可以通过一号svc访问这个pod,也可以根据二号svc来访问它,M-N(多对多)的关系。
至于deployment 采用4.1中的的即可

vim nodeport.yaml

内容如下

apiVersion: v1
kind: Service
metadata:
  name: myapp
  namespace: default
spec:
  type: NodePort
  selector:
    app: myapp # 当然这个标签的意义还是需要选择的对应的pod,不然这个svc下面是空的,没啥意义
    release: stabel
  ports:
  - name: http
    port: 80
    targetPort: 80

在这里插入图片描述
外网访问,并且是所有的节点都开放了这个端口,都可以访问
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
通过查看svc 的ipvs(这里使用的实现是ipvs)的路由规则也是能看出来的

ipvsadm -Ln

在这里插入图片描述

4.4、LoadBalancer

loadBalancer 和 nodePort 其实是同一种方式。区别在于 loadBalancer 比 nodePort 多了一步,就是可以调用 cloud provider 去创建 LB 来向节点导流,所以需要云供应商来提供,花钱。

在这里插入图片描述

4.4、ExternalName

这种类型的 Service 通过返回 CNAME 和它的值,可以将服务映射到 externalName 字段的内容( 例如:hub.atguigu.com )。ExternalName Service 是 Service 的特例,它没有 selector,也没有定义任何的端口和Endpoint。相反的,对于运行在集群外部的服务,它通过返回该外部服务的别名这种方式来提供服务。这样一旦你在k8s集群内部访问xxx就会访问到外部的 hub.atguigu.com(可以参考前面的几种类型的图示说明),意义就是把外部的流量引入到k8s内部,且当外部地址改变时,不需要在k8s内部应用的地方一个一个的去改,而内部只需要引用这个svc的名称,通过这个名称来访问,发生改变时修改这个svc的配置文件即可,其它都不需要动

创建

vim ex.yaml

具体内容

kind: Service
apiVersion: v1
metadata:
  name: my-service-1 # 我们直 svc 一旦创建,集群内部就可以根据 svc的名称访问
  namespace: default
spec:
  type: ExternalName
  externalName: hub.atguigu.com # 外部服务的域名,当然你也可以换成ip

在这里插入图片描述
当查询主机 my-service-1.defalut.svc.cluster.local (SVC_NAME.NAMESPACE.svc.cluster.local )时,集群的DNS 服务将返回一个值 my.database.example.com 的 CNAME 记录。访问这个服务的工作方式和其他的相同,唯一不同的是重定向发生在 DNS 层,而且不会进行代理或转发

# 对 svcname.namespece.svc.cluster.local. 使用 10.224.0.7(选择10.244.0.6也行看上面截图,二个ip选一个)来解析
dig -t A my-service-1.default.svc.cluster.local. @10.224.0.7

在这里插入图片描述

五、Service 增强之七层代理 Ingress

Ingress-Nginx github 地址:https://github.com/kubernetes/ingress-nginx
Ingress-Nginx 官方网站:https://kubernetes.github.io/ingress-nginx/

在这里插入图片描述
大致来说就是,我们写配置文件,它帮我们在nginx的conf文件中补充。

5.1、前置环境部署

如果有疑问,也可以看看网上其它的文章 https://blog.csdn.net/zhangjunli/article/details/107545984 这个还不错。

ingress-nginx的部署方式有多种,本文介绍nodeport方式(还有DaemonSet等等方式,这个上网搜索一下这个部署的文章就有很详细的说了,这里就不展开了),下面都是可以选择的方案在这里插入图片描述
总的来说我们前置的条件需要部署2个,一个官方的 ingress-nginx,另一个是官方的 svc(方式有很多,这里采用nodePort方式),这个两个官方都提供的模板yaml文件

1、下载mandatory.yaml文件:

wget https://raw.githubusercontent.com/kubernetes/ingressnginx/master/deploy/static/mandatory.yaml

然后修改文件中的镜像:registry.cn-hangzhou.aliyuncs.com/google_containers/nginx-ingress-controller:0.25.1 改为阿里云的,这样下载会快很多,而且可能国外的你下载不了。

在这里插入图片描述

#部署
kubectl apply -f mandatory.yaml

查看,注意,它创建在 ingress-nginx的名称空间中,如果想更改也可以,修改那个yaml文件,修改就行。
在这里插入图片描述

2、编辑service-nodeport.yaml(nodeport方式需要额外使用这个文件)
创建 ingress的node port 模式的svc ,下载,部署
在这里插入图片描述

wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.0.3/deploy/static/provider/baremetal/deploy.yaml

kubectl apply -f deploy.yaml

查看,注意它也创建在 ingress-nginx的名称空间中,后面这个端口31345就是后面我们访问的端口(域名加上端口),而对于https来说就是后面的31802
在这里插入图片描述

5.2、自己的服务(一个ingress对应一个我们的svc)

上面前置准备已经做好,那么接下来我们就可以部署自己的了,先部署一套如下
在这里插入图片描述

1、创建自己的 deployment 和 svc

vim ingress.http.yaml

内容如下,注意一个yaml文件里面可以有多个类型的控制器pod,或者非控制器pod,只要以---分割即可,这样可以让其他开发人员知道这两个组件是一起的,后续删除的时候,也可以根据文件删除。

apiVersion: extensions/v1beta1
kind: Deployment  # 先创建一个deployment 
metadata:
  name: nginx-dm
spec:
  replicas: 2
  template:
    metadata:
      labels:
        name: nginx  # 标签意义就不再重复说了
    spec:
      containers:
        - name: nginx
          image: wangyanglinux/myapp:v1
          imagePullPolicy: IfNotPresent
          ports:
            - containerPort: 80
---
apiVersion: v1
kind: Service   # 再创建一个自己的 svc
metadata:
  name: nginx-svc
spec:
  ports:
    - port: 80
      targetPort: 80
      protocol: TCP
  selector:
    name: nginx  # 管理上面的pod

在这里插入图片描述
2、配置后端程序的ingress

这个ingress就是会管理我们自己的svc和外部域名的关联的

vim ingress1.yaml

内容如下, 注意这里的kind是 ingress 的类型欧

apiVersion: extensions/v1beta1
kind: Ingress  # 注意这里是 ingress 的类型欧
metadata:
  name: nginx-test
spec:
  rules:
    - host: www1.atguigu.com
      http:
        paths:
        - path: /
          backend:
            serviceName: nginx-svc  # 说明外部访问 www1.atguigu.com 就是访问内部我们上面定义的那个 nginx-svc(前面定义的我们自己那个svc的名称)
            servicePort: 80

在这里插入图片描述

3、访问

  • 注意这里的域名是我们前面配置的,而且不要忘记防护墙以及win的host域名解析欧
  • 域名访问的时候需要加上端口,这个端口是我们前置准备里面的那个nodePort暴露的端口
    在这里插入图片描述

5.3、自己的服务(一个ingress对应多个我们的svc)

这中模式,就是对上面的5.2的一个加强而已,其实k8s也就是会在nginx里面多做一个域名的分流而已。

在这里插入图片描述

1、创建我们的一套服务(deployment1 和 svc1)

vim deploment1.yaml

内容如下,注意欧这里的标签名称不能等下和后面的第二套管理混淆了,不能一样,这个不用解释了把。

apiVersion: extensions/v1beta1
kind: Deployment  # 先创建一个deployment 
metadata:
  name: deployment1   # 名称为 deployment1 
spec:
  replicas: 2
  template:
    metadata:
      labels:
        name: nginx1  # 标签意义就不再重复说了
    spec:
      containers:
        - name: nginx
          image: wangyanglinux/myapp:v1
          imagePullPolicy: IfNotPresent
          ports:
            - containerPort: 80
---
apiVersion: v1
kind: Service   # 再创建一个自己的 svc
metadata:
  name: svc-1
spec:
  ports:
    - port: 80
      targetPort: 80
      protocol: TCP
  selector:
    name: nginx1  # 管理上面的pod

创建
在这里插入图片描述

2、创建我们的二套服务(deployment2 和 svc2)

vim deploment2.yaml

内容如下,注意欧这里的标签名称不能等下和后面的第一套管理混淆了,不能一样

apiVersion: extensions/v1beta1
kind: Deployment  # 先创建一个deployment 
metadata:
  name: deployment2   # 名称为 deployment2
spec:
  replicas: 2
  template:
    metadata:
      labels:
        name: nginx2  # 标签意义就不再重复说了
    spec:
      containers:
        - name: nginx
          image: wangyanglinux/myapp:v2
          imagePullPolicy: IfNotPresent
          ports:
            - containerPort: 80
---
apiVersion: v1
kind: Service   # 再创建一个自己的 svc
metadata:
  name: svc-2
spec:
  ports:
    - port: 80
      targetPort: 80
      protocol: TCP
  selector:
    name: nginx2  # 管理上面的pod

第二个svc以及下面关联的 deployment

在这里插入图片描述

3、创建ingress来管理上面的两套
这个ingress就是会管理我们自己的svc和外部域名的关联的

vim ingress-two.yaml

内容如下, 注意这里的kind是 ingress 的类型欧

apiVersion: extensions/v1beta1
kind: Ingress  # 注意这里是 ingress 的类型欧
metadata:
  name: nginx-test
spec:
  rules:
    - host: www1.atguigu.com
      http:
        paths:
        - path: /
          backend:
            serviceName: svc-1  # 说明外部访问 www1.atguigu.com 就是访问内部我们上面定义的那个 svc-1(前面定义的第一套我们自己那个svc的名称)
            servicePort: 80
     - host: www2.atguigu.com
      http:
        paths:
        - path: /
          backend:
            serviceName: svc-2  # 说明外部访问 www2.atguigu.com 就是访问内部我们上面定义的那个 svc-2(前面定义的第二套我们自己那个svc的名称)
            servicePort: 80

查看

在这里插入图片描述
其实这个ingress 就是帮忙我们在nginx增加映射分流关系。

5.4、配置https

1、创建一套我们的体系(即deployment 和 svc),这里以3为代号,前面的是1和2

apiVersion: extensions/v1beta1
kind: Deployment  # 先创建一个deployment 
metadata:
  name: deployment3   # 名称为 deployment3
spec:
  replicas: 2
  template:
    metadata:
      labels:
        name: nginx3  # 标签意义就不再重复说了
    spec:
      containers:
        - name: nginx
          image: wangyanglinux/myapp:v3
          imagePullPolicy: IfNotPresent
          ports:
            - containerPort: 80
---
apiVersion: v1
kind: Service   # 再创建一个自己的 svc
metadata:
  name: svc-3
spec:
  ports:
    - port: 80
      targetPort: 80
      protocol: TCP
  selector:
    name: nginx3  # 管理上面的pod

查看我们的体系
在这里插入图片描述
2、创建 ingress
创建证书,以及 cert 存储方式

# 创建证书 openssl req -x509 -sha256 -nodes -days 有效天数 -newkey rsa:2048 -keyout 输出文件 -out 输出证书 -subj "/CN=nginxsvc/O=nginxsvc"
openssl req -x509 -sha256 -nodes -days 365 -newkey rsa:2048 -keyout tls.key -out tls.crt -subj "/CN=nginxsvc/O=nginxsvc"
# 生成  kubectl create secret tls 类型(这个很重要,后面我们配置ingress的时候,类型指定要和这个一样) --key 上面生成的key --cert 上面生成的crt
kubectl create secret tls tls-secret --key tls.key --cert tls.crt

ingress的内容

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: nginx-test
spec:
  tls:
    - hosts:
      - www3.aiguigu.com
      secretName: tls-secret # 注意这个类型跟上面 kubectl 的那个说的类型必须一致
  rules:
    - host: www3.aiguigu.com
      http:
        paths:
        - path: /
          backend:
            serviceName: svc3
            servicePort: 80

查看,注意这里是https即443,所以我们访问的端口就是后面的31802
在这里插入图片描述
3、结果
在这里插入图片描述

5.5、http的验证

其实这里的http验证,就是nginx的验证,我们配置的就是nginx,也是因为我们选择的ingress的ingx的实现。

1、生成用户和密码凭证

# 下载nginx的基础验证的模块 httpd
yum -y install httpd
# 使用htpasswd生成证书  htpasswd -c 证书文件 用户名(后面会让你输入密码)
htpasswd -c auth foo
# 使用这个证书文件 kubectl create secret generic basic-auth --from-file=上面生成的证书文件
kubectl create secret generic basic-auth --from-file=auth

在这里插入图片描述

2、创建ingress
这里就不再创建一套我们的体系了,我们可以用前面的 svc1的体系,注意svc1的体系是80即http的是没有https的欧

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: ingress-with-auth # 这个ingress的名称
  annotations:
    nginx.ingress.kubernetes.io/auth-type: basic
    nginx.ingress.kubernetes.io/auth-secret: basic-auth
    nginx.ingress.kubernetes.io/auth-realm: 'Authentication Required - foo'
spec:
  rules:
  - host: auth.atguigu.com # 访问的域名
    http:
      paths:
      - path: /
        backend:
          serviceName: svc-1 # 使用svc-1的体系
          servicePort: 80

查看
在这里插入图片描述

5.6、Nginx 进行重写

意思我们可以把nginx的一些配置规则,放到yaml文件里面,k8s的ingress会帮我们写入它创建的Nginx里面

名称描述
nginx.ingress.kubernetes.io/rewrite-target必须重定向流量的目标URI字符串
nginx.ingress.kubernetes.io/ssl-redirect指示位置部分是否仅可访问SSL(当Ingress包含证书时默认为True)布尔
nginx.ingress.kubernetes.io/force-ssl-redirect即使Ingress未启用TLS,也强制重定向到HTTPS布尔
nginx.ingress.kubernetes.io/app-root定义Controller必须重定向的应用程序根,如果它在’/'上下文中字符串
nginx.ingress.kubernetes.io/use-regex指示Ingress上定义的路径是否使用正则表达式布尔

示例,当访问 www4.atguigu.com 时 跳转到 http://www.baidu.com

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: nginx-test
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: http://www.baidu.com
spec:
  rules:
  - host: www4.atguigu.com 
    http:
      paths:
      - path: /
        backend:
          serviceName: ngin
Logo

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

更多推荐