Fork me on GitHub

《kubernetes in Action》读书笔记(1)

《kubernetes in Action》(中文版)读书笔记 1

1. 集群内如果使用服务

  1. K8s 可以通过创建 service 的方式,提供固定的 IP 和端口,当服务不受经常变动的 pod 的影响。

  2. k8s 可以根据 service 的 manifest 来创建新的服务,可以通过以下命令来访问service,

    1
    kubectl exec [podName] --curl -a [url]

    收到请求的 service 会从下辖的 pod 中用负载均衡的方式随机调一个pod 对请求进行响应。

    1. 配置sessionAffinityClientIp可以让特定客户端的请求每次都指向同一个 pod。
    2. service 是在 TCP 和 UDP 层进行工作的,所以不涉及 HTTP 协议中的 cookie 概念。
    3. service mainifest:指明 name:http;port:80;targetPort:8080(Pod 上的端口)。
      1. 也可以是 targetPort:someAliaName,然后再 pod 的 manifest 中指明 name:someAliaName,containerPort:8080.实现了解耦。
    4. 服务发现:
      1. 方法一:环境变量。先有 service后有 pod 时,pod 可以取到环境变量中的 serviceIp和 port 等信息。但若先有 pod 后有 service,信息就很难取到。
      2. 方法二:DNS 服务。k8s 中设置一个 DNS 服务的 pod,如此一来,—curl 时不再使用ip 地址的 url,而是使用 FQDN(全限定域名),请求先查 DNS 服务,然后就能找到服务了,再然后就找到真正工作的 pod 了。
  1. 但 service 也只能指向此集群内部的若干 pod,无法对外暴露,无法指向外部 IP 和端口。
    1. 所以可能需要手动创建 Endpoint 来完成。
      1. 在 create service 时,如果制定了 pod 选择器,那么 service 被创建,endpoint 也会自动创建,此时的 endpoint 携带着 pod 选择器选中的 pod 的信息(都属于内部 pod)。
      2. 手动创建时,需要 create 一个没有 pod 选择器的 service,那么将不会有 Endpoint 被自动创建,所以可以手动create一个,并将外部的 ip 及端口信息写入 endpoint 的 manifest中,这样一来,当请求 service 服务时,就可以关联到外部的 ip 地址及端口上了。
    2. 除了手动创建 Endpoint 外,还可以用创建别名的方式来做到。
      1. 对 service manifest 中的 type 字段设置为ExternalName,随后在 externalName自定义一个别名。
      2. 这样就可以通过此别名请求服务,即通过 CNAME 的方式定位到你想去的地方(需要 FQDN,而不是集群 IP),隐藏了实际的服务名称和服务的 pod 信息,可以完全绕过服务代理。

2. 服务对外暴露

service 的类型设置为 NodePort、LoadBalance,或者创建 Ingress 资源等三种机制。

这篇文章讲得不错:NodePort,LoadBalancer还是Ingress?我该如何选择

2.1. NodePort
  • 创建一个 NodePort 服务(type 为 NodePort),k8s 在每一个 node 上都可以保留一个 port(所有 node 上的此 port 都相同),传入此 port 的流量转发给服务部分(type 为 clusterIP)的 pod。

    • NodePort 服务可以跟服务部分 pod 互联。而且,node 之间,可以通过此 port 做到彼此互联。
    • 在 NodePort 的 manifest 中定义好了service port(service port 是跟背后的 pod 的 targetPort是一对多映射的),也就明确了能够提供的哪种服务。
    • 开放的 port 可以自定义,也可以不设置,交由 k8s 来决定。
  • 通过地址[any node's ip]:开放port 就可以访问服务。

    这种方式有一些不足:

    1. 一个端口只能供一个服务使用;
      1. 只能使用30000–32767的端口;
      2. 如果节点 / 虚拟机的IP地址发生变化,需要进行处理。
2.2 loadBalance
  • loadBalance 是 NodePort 的扩展,在部分不支持 loadBalance 的环境中,k8s 应该采取 NodePort 的方式。

  • type 为 LoadBalancer。

  • 这是默认方式。指定端口的所有流量都会转发到服务中,没有过滤,也没有路由。这意味着你几乎可以发送任意类型的流量到服务中,比如HTTP、TCP、UDP、Websockets、gRPC等等。

  • 这里最大的不足是,使用LoadBalancer发布的每个服务都会有一个独有的公有IP地址,你需要支付每个服务的LoadBalancer 费用,这是一笔不小的开支。

    可设置 spec 中 externalTrafficPolicyLocal,来让真正运行的 pod,就是接收连接的 node 上的 pod。可减少网络中不必要的跳数。

    举例:node1、node2、node3 上都有相同的 pod 提供对外服务。此时 node1被外部连接上了,通过 loadBalancer 后,外部通信需要重定向到执行的 pod 上,如果将 externalTrafficPolicy设置为Local了,那么将优先选择本地运行的 pod 来执行服务。

    1. 如果没有本地 pod 存在,则连接将被挂起(此情况应当被避免,所以负载均衡器要确保把连接转发到至少具有一个 pod 的 node 上)。
    2. 采用此策略可能导致负载分布的不均衡。LoadBalancer 在 node 间是均匀分布连接的,但nodes 之间的 pod 数量可能各有不同。
  • 因为发生了源网络地址转换(SNAT),所以最初连接时的客户端 IP 在数据包转发时发生更改,pod 将不会看到实际的客户端 IP。

2.3 Ingress
  • Ingress 是在多个服务前充当入口的角色,通过一个 Ingress 就可以暴露多个服务。

  • Ingress 只需要一个公网 IP 就能为许多服务提供访问。进入的 HTTP 请求,会根据请求的主机名和路径决定请求转发到的服务。

    • 想使用 Ingress的前提是需要一个 Ingress 控制器,有了控制器才可以创建 Ingress 资源,创建步骤:

      1. Ingress manifest 如下,说明是将 host 的所有 HTTP 请求,全都转发给80 端口上的 kubia-nodeport 服务。

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        # 省略了 apiVersion、kind、metadata 等 info
        ...
        spec:
        rules:
        - host: kubia.example.com
        http:
        paths:
        -path: /
        backend:
        serviceName: kubia-nodeport
        servicePort: 80
        1. rules 和 paths 都是数组,说明可以将多个主机和路径映射到多个服务
      2. 创建后使用命令:kubectl get ingresses,查看 Ingress 的 IP 地址。

    • 需要在 Ingress 中配置 Host 指向 Ingress 的 IP 地址

    • 之后就可以curl http://kubia.example.com访问服务了。

      • 原理:Ingress 通过此 host 知道 client 想连接的是哪个服务,然后通过服务关联的 endpoint查看 podIp,并将 client 的请求转发给其中的一个 pod。
  • Ingress 甚至可以创建TLS认证,支持 HTTPS 服务。

    • Ingress 控制器负责处理与 TLS 相关的内容,而后面的服务以及 Pod 都只需处理 Http 的内容即可。

    • 需要将证书和私钥附加到 Ingress 上,做法:这两个东西存储在 Secret 的资源中,然后在 Ingress manifest 中引用它。

      1
      2
      3
      4
      5
      6
      7
      ...
      spec:
      tls:
      - hosts:
      - kubia.example.com
      secretName: tls-secret # 先创建证书和私钥,然后创建一个 Secret,可以取名为 tls-secret
      ...
  • Ingress目前只支持 L7 层的负载均衡。

-------------The End-------------