k8s学习笔记三(Service)

Service的概念

service定义了这样一种抽象: 一个Pod的逻辑分组,一种可以访问它们的策略----通常称为微服务, 这一组Pod能够被Service访问到,通常是通过 Label Selector

在这里插入图片描述

Service能够提供负载均衡的能力,只提供4层负载均衡能力,而没有7层功能.

Service的类型

Service在K8s中有以下四种类型:

  1. Clusterlp:默认类型, 自动分配一个仅Cluster内部可以访问的虚拟IP
  2. NodePort:在ClusterlP基础上为Service在每台机器上绑定一个端口, 这样就可以通过:NodePort来访问该服务(比较常见),需要在外部再做个负载均衡,到每个node
  3. LoadBalancer:在NodePort的基础上, 借助cloudprovider创建一个外部负载均衡器, 并将请求转发 到:NodePort,和NodePort实现原理一下,需要在外部再做个负载均衡到每个node,但这个负载均衡是由云供应商来提供
  4. ExternalName:把集群外部的服务引入到集群内部来, 在集群内部直接使用。没有任何类型代理被创建, 这只有kubernetes 1.7或更高版本的kube-dns才支持. (类似配置中心的功能,把需要访问外部某个集群的地址和端口写在这里,内部pod只要访问这里即可拿到地址,如果外部的地址更新了,不需要变更pod的配置,只要修改这个service的配置即可)

VIP和Service代理

在Kubernetes集群中, 每个Node运行一个 kube-proxy进程。 kube-proxy负责为Service实现了一种 VIP(虚拟IP) 的形式, 而不是ExternalName 的形式。在Kubernetes v1.0版本, 代理完全在userspace。在 Kubernetes v 1.1版本, 新增了iptables代理, 但并不是默认的运行模式。 从Kubernetes v1.2起, 默认就是 iptables代理。在Kubernetes v1.8.0-beta.0中, 添加了ipvs代理
在Kubernetes v1.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:不排队调度

注: ipvs模式假定在运行 kube-proxy 之前在节点上都已经安装了IPVS内核模块.当kube-proxy以ipvs代理模式启动时,kube-proxy将验证节点上是否安装了ipvs模块,如果未安装,则kube-proxy将回退到iptables代理模式
在这里插入图片描述

Ingress代理模式(7层)

ingress-Nginx github: https://github.com/kubenetes/ingress-nginx
ingress-Nginx 官网: https://kubernetes.github.io/ingress-nginx

在这里插入图片描述

Ingress配置

# 官网 - deployment - install页面能看到类似这样一行命令
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.4.0/deploy/static/provider/cloud/deploy.yaml  # 云部署,阿里云用的也是AWS
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.4.0/deploy/static/provider/baremetal/deploy.yaml  # 裸机
# 如果您运行的是旧版本的Kubernetes(1.18或更早版本),请阅读本段了解具体说明。由于api被弃用,默认清单可能无法在集群上运行。
# 使用对应k8s 1.15版本的ingress-nginx的清单文件
https://raw.githubusercontent.com/kubernetes/ingress-nginx/nginx-0.25.0/deploy/static/mandatory.yaml
https://raw.githubusercontent.com/kubernetes/ingress-nginx/nginx-0.25.0/deploy/baremetal/service-nodeport.yaml
# mandatory.yaml 
#    spec:
#      # wait up to five minutes for the drain of connections
#      terminationGracePeriodSeconds: 300
#	  hostNetwork: true  # 这句一定要加上,直接从官网下载的没有这句,否则liveness检测会不通过
#      serviceAccountName: nginx-ingress-serviceaccount
# service-nodeport.yaml
# 官方下载的service-nodeport.yaml也要在spec下面加上,选择器,否则不会绑定转发规则
#   selector:
#    app.kubernetes.io/name: ingress-nginx
#    app.kubernetes.io/part-of: ingress-nginx
kubectl apply -f mandatory.yaml  
kubectl apply -f service-nodeport.yaml

ingress HTTP代理访问

# deployment
apiVersion: extensions/v1beta1 
kind: Deployment 
metadata: 
  name: nginx-dm 
spec: 
  replicas: 2
  template: 
    metadata: 
      labels: 
        name: nginx 
    spec: 
      containers: 
      - name: nginx 
        image: nginx 
        imagePullPolicy: IfNotPresent 
        ports: 
        - containerPort: 80 
---       
# Service
apiVersion: v1 
kind: Service 
metadata: 
  name: nginx-svc 
spec: 
  ports: 
  - port: 80 
    targetPort: 80 
    protocol: TCP 
  selector: 
    name: nginx
---
# ingress
apiVersion: extensions/v1beta1 
kind: Ingress 
metadata: 
  name: nginx-test 
spec: 
  rules: 
  - host: my.example.com 
    http: 
      paths: 
      - path: / 
        backend: 
          serviceName: nginx-svc 
          servicePort: 80

kubectl get svc -A
拿到ingress-nginx的暴露的端口
DNS解析域名
my.example.com:端口 访问了

Ingress HTTPS代理访问

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 tls-secret --key tls.key --cert tls.crt 

** Ingress Yaml配置文件 **

apiVersion: extensions/v1beta1 
kind: Ingress 
metadata: 
  name: nginx-test 
spec: 
  tls: 
  - hosts: 
    - foo.bar.com 
    secretName: tls-secret 
  rules: 
  - host:foo.bar.com 
    http: 
      paths: 
      - path: / 
        backend: 
          serviceName: nginx-svc 
          servicePort: 80 

Nginx进行BasicAuth

yum -y install httpd 
htpasswd -c auth foo  # auth是文件名 foo是用户名,还需要录入用户密码
kubectl create secret generic basic-auth --from-file=auth 
apiVersion: extensions/v1beta1 
kind: Ingress 
metadata: 
  name: ingress-with-auth 
  annotations: 
    nginx.ingress.kubernetes.io/auth-type: basi 
    nginx.ingress.kubernetes.io/auth-secret: basic-auth 
    nginx.ingress.kubernetes.io/auth-realm 1: 'Authentication Required-foo' 
spec: 
  rules: 
  - host: foo2.bar.com 
    http: 
      paths: 
      - path: / 
        backend: 
          serviceName: nginx-svc 
          servicePort: 80

Nginx进行重写

名称描述
nginx.ingress.kubernetes.io/rewrte-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上定义的路径是否使用正则表达式布尔
apiVersion: extensions/v1beta1 
kind:Ingress 
metadata: 
  name: nginx-test 
  annotations: 
    nginx.ingress.kubernetes.io/rewrite-target: http://foo.bar.com:31795/hostname.html 
spec: 
  rules: 
  - host: foo10.bar.com 
    http: 
      paths: 
      - path: / 
        backend: 
          serviceName: nginx-svc 
          servicePort: 80

Service配置

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规则中
  • iptables使用NAT等技术将virtualIP的流量转至endpoint中

Deployment配置文件


apiVersion: apps/v1 
kind: Deployment 
metadata: 
  name: myapp-deploy 
  namespace: default 
spec: 
  replicas: 3 
  selector: 
    matchLabels: 
      app: myapp 
      release: stabel 
  template: 
    metadata: 
      labels: 
        app: myapp 
        release: stabel 
        env: test 
    spec: 
      containers: 
      - name: myapp 
        image: myapp:v2 
        imagePullPolicy: IfNotPresent 
        ports: 
        - name: http 
          containerPort: 80 

Service配置文件

apiVersion: v1 
kind: Service 
metadata: 
  name: mvapp 
  namespace: default 
spec: 
  type: ClusterIP 
  selector: 
    app: myapp 
    release: stabel 
  ports: 
  - name: http 
    port: 80 
    targetPort: 80

Headless Service(无头服务)

有时不需要或不想要负载均衡, 以及单独的Service IP。遇到这种情况, 可以通过指定ClusterIP(spec.clusterIP) 的值为“None"来创建Headless Service。这类Service并不会分配Cluster IP, kube- proxy不会处理它们, 而且平台也不会为它们进行负载均衡和路由

apiVersion: v1 
kind: Service 
metadata: 
  name: myapp-headless 
  namespace: default 
spec: 
  selector: 
    app: myapp 
  clusterIP: "None" 
  ports: 
  - port: 80 
    targetPort: 80 
dig -t A myapp-headless.default.svc.cluster.local. @10.96.0.10
# myapp-headless  svc名称
# default 名称空间
# svc.cluster.local 默认配置的名称
# @10.96.0.10 coreDNS的IP, 从kubectl get pod -n kube-system -o wide中查询
# dig命令在 bind-utils 包中
# local后面的.和@之间有个空格

NodePort配置

nodePort的原理在于在node上开了一个端口, 将向该端口的流量导入到kube-proxy, 然后由kube-proxy进一步到给对应的pod

apiVersion: v1 
kind: Service 
metadata: 
  name: myapp 
  namespace: default 
spec: 
  type: NodePort 
  selector: 
    app: myapp 
    release: stabel 
  ports: 
  - name: http 
    port: 80 
    targetPort: 80 

查询流程

iptables -t nat -nvL

LoadBalancer配置

loadBalancer和nodePort其实是同一种方式, 区别在于LoadBalancer比nodePort多了一步,就是可以调用cloud provider 去创建LB来向节点导流

ExternalName配置

这种类型的Service通过返回CNAME和它的值, 可以将服务映射到externalName字段的内容(例如: my.database.example.com) 。ExternalName Service是Service的特例, 它没有selector, 也没有定义任何的端口和 Endpoint。相反的, 对于运行在集群外部的服务, 它通过返回该外部服务的别名这种方式来提供服务

kind: Service 
apiVersion: v1 
metadata: 
  name: my-service-1 
  namespace: default 
spec: 
  type: ExternalName 
  externalName: my.database.example.com

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值