访问Kubernetes集群

根据用户部署和暴露方式不同,有很多种方式可以用来访问Kubernetes集群。

  • 最简单和直接的方式是使用kubectl命令;
  • 其次可以使用kubeconfig文件来认证授权访问API Server;
  • 通过各种proxy经过端口转发访问kubernetes集群中的服务;
  • 使用Ingress,在集群外部访问kubernetes集群内的Service;

4.5.1 访问集群

使用下面的命令检查kubectl已知的集群的地址和凭证:

  1. kubectl config view

在Pod中访问API
在Pod中访问API时,定位和认证到API Server的方式有所不同。在Pod中找到apiserver地址的推荐方法是使用kubernetes DNS名称,将它解析为服务IP,后者又被路由到apiserver。

向apiserver认证的推荐方法是使用service account凭据。通过kube-system,pod与service account相关联,并且将该service account的凭据(token)放入到该Pod中每个容器的文件系统树中,位于/var/run/secrets/kubernetes.io/serviceaccount/token。

如果可用,证书包将位于每个容器的文件系统树的/var/run/secrets/kubernetes.io/serviceaccount/ca.crt位置,并用于验证apiserver的服务证书。

最后,用于namespace API操作的默认namespace放在每个容器中的/var/run/secrets/kubernetes.io/serviceaccount/namespace中。

在Pod中,连接到API的推荐方法是:

  • 将kubectl proxy作为Pod中的一个容器来运行,或作为在容器内运行的后台进程。它将Kubernetes API代理到Pod的本地主机接口,以便其他任何Pod中的容器内的进程都可以访问它。
  • 使用Go客户端库,并使用rest.InClusterConfig()和kubernetes.NewForConfig()函数创建一个客户端。

访问集群中运行的Service
在Kubernetes中,node、pod和services都有它们自己的IP。
很多情况下,集群中node的IP、Pod的IP、service的IP都是不可路由的。因此在集群外部的集群都无法访问到它们。

连接的方式
可以采用如下几种方式从集群外部连接到node、pod和service。

  • 通过public IP访问service

    1)使用NodePort和LoadBalancer类型的service,以使service能够在集群外部被访问到。<br />      2)将Pod放在服务后面。要从一组副本(例如为了调试)访问一个特定的Pod,请在Pod上放置一个唯一的label,并创建一个选择该label的新服务。
    
  • 通过Proxy规则访问Service、node、pod

    1)在访问远程服务之前,请执行apiserver认证和授权。如果服务不够安全,无法暴露给互联网,或者为了访问节点IP上的端口或进行调试,请使用这种方式。

  • 在集群内部访问node和Pod

    1)运行一个Pod,然后使用kubectl exec命令连接到shell。从该shell中连接到其他node、pod和service。

4.5.2 使用kubeconfig文件配置跨集群认证

Kubernetes的认证方式对于不同的人来说可能有所不同。

  • 运行kubelet可能有一种认证方式(即证书)
  • 用户可能有不同的认证方式(即令牌)
  • 管理员可能具有他们为个人用户提供的证书列表
  • 我们可能有多个集群,并希望在同一个地方将其全部定义——这样用户就能使用自己的证书并重用相同的全局配置

所以为了能够让用户轻松在多个集群之间切换,对于多个用户的情况下,我们将其定义在了一个kubeconfig文件中。
此文件包含一系列与昵称相关联的身份验证机制和集群连接信息。它还引入了一个(用户)认证信息元组和一个被称为上下文的与昵称相关联的集群连接信息的概念。

如果明确指定,则允许使用多个kubeconfig文件。
在运行时,它们与命令行中指定的覆盖选项一起加载并合并。

Kubeconfig文件的组成
Kubeconfig文件示例

current-context: federal-context
apiVersion: v1
clusters:
- cluster:
    api-version: v1
    server: http://cow.org:8080
  name: cow-cluster
- cluster:
    certificate-authority: path/to/my/cafile
    server: https://horse.org:4443
  name: horse-cluster
- cluster:
    insecure-skip-tls-verity: true
    server: https://pig.org:443
  name: pig-cluster
contexts:
- context:
    cluster: horse-cluster
    namespace: chisel-ns
    user: federal-context
- context:
    cluster: pig-cluster
    namespace: saw-ns
    user: black-user
  name: queen-anne-context
kind: Config
preferences:
  colors: true
users:
- name: blue-user
  user:
     token: blue-token
- name: green-user
  user:
     client-certificate: path/to/my/client/cert
     client-key: path/to/my/client/key

各个组件的拆解、释意

Cluster**
cluster中包含kubernetes集群的端点数据,包括kubernetes apiserver的完整URL以及集群的证书颁发机构或者当集群的服务证书未被系统信任的证书颁发机构签名时,设置insecure-skip-tls-verity: true。

cluster的名称(昵称)作为该kubeconfig文件中的集群字典的key。
可以使用kubectl config set-cluster添加或者修改cluster条目。

user
user定义用于向kubernetes集群进行身份验证的客户端凭据。在加载、合并kubeconfig之后,user将有一个名称(昵称)作为用户条目列表中的key。可用凭证有client-certificate、client-key、token和username/password。
username/password和token是二者只能选择一个,但client-certificate和client-key可以分别与它们组合。

可以使用kubectl config set-credentials添加或者修改user条目。

context

contexts:
- context:
    cluster: horse-cluster
    namespace: chisel-ns
    user: green-user
  name: federal-context

context定义了一个命名的cluster、user、namespace元组,用于使用提供的认证信息和命名空间将请求发送到指定的集群。三个都是可选的;仅使用cluser、user、namespace之一指定上下文,或指定none。未指定的值或在加载的kubeconfig中没有响应条目的命名值将被替换为默认值。

可以使用kubectl config set-context添加或修改上下文条目。

current-context

current-context: federal-context

current-context是昵称或者说是作为cluster、user、namespace元组的key,当kubectl从该文件中加载配置时会被默认使用。可以在kubectl命令行里覆盖这些值,通过分别传入—context=CONTEXT、—cluster=CLUSTER、—user=USER和 —namespace=NAMESPACE。

可以使用kubectl config use-context更改current-context。

4.5.3 通过端口转发访问集群中的应用程序

将展示如何使用kubectl port-forward命令连接到运行在Kubernetes集群中的Redis服务器。

创建一个Pod来运行Redis服务器
1.创建一个Pod:

kubectl create -f https://k8s.io/docs/tasks/access-application-cluster/redis-master.yaml

2.检查Pod是否正在运行且处于就绪状态

kubectl get pods

3.验证Redis服务器是否已在Pod中运行,并监听6379端口

kubectl get pods redis-master --template='{{index (index .spec.containers 0).ports 0).containerPort}}{{"\n"}}'

将本地端口转发到Pod中的端口
1.将本地工作站上的6379端口转发到redis-master pod的6379端口

kubectl port-forward redis-master 6379:6379

4.5.4 使用service访问集群中的应用程序

创建一个暴露该Deployment的Service对象

kubectl expose deployment hello-world --type=NodePort --name=example-service

4.5.5 从外部访问Kubernetes中的Pod

访问Kubernetes中的Pod和Service的几种方式,包括如下几种:

  • hostNetwork
  • hostPort
  • NodePort
  • LoadBalancer
  • Ingress

hostNetwork:true
是一种直接定义Pod网络的方式。
如果在Pod中使用hostNetwork:true配置的话,在这种Pod中运行的应用程序可以直接看到Pod启动的主机的网络接口。在主机的所有网络接口上都可以访问到该应用程序。

apiVersion: v1
kind: Pod
metadata:
  name: influxdb
spec:
  hostNetwork: true
  containers:
    - name: influxdb
      image: influxdb

hostPort
hostPort是直接将容器的端口与所调度的节点上的端口路径,这样用户就可以通过宿主机的IP加上端口来访问Pod了。

apiVersion: v1
kind: Pod
metadata:
  name: influxdb
spec:
  containers:
    - name: influxdb
      image: influxdb
      ports:
        - containerPort: 8086
          hostPort: 8086

这么做的缺点:因为Pod重新调度的时该Pod被调度到的宿主机可能会变动,这样就变化了,用户必须自己维护一个Pod与所在宿主机的对应关系。

NodePort
NodePort在Kubernetes中是一个广泛应用的服务暴露方式。
Kubernetes中的Service默认情况下都是使用的ClusterIP这种类型,这样的service会产生一个ClusterIP,这个IP只能在集群内部访问,要想让外部能直接访问Service,需要将service type修改为nodePort。

apiVersion: v1
kind: Pod
metadata:
  name: influxdb
  labels:
    name: influxdb
spec:
  containers:
    - name: influxdb
      image: influxdb
      ports:
        - containerPort: 8086

同时还可以给service指定一个nodePort值,范围是30000~32767,这个值在API Server的配置文件中,用—service-node-port-range定义。

kind: Service
apiVersion: v1
metadata: 
  name: influxdb
spec:
  type: NodePort
  ports:
    - port: 8086
      nodePort: 30000
  selector:
    name: influxdb

集群外就可以使用Kubernetes任意一个节点的IP加上30000端口访问该服务了。
kube-proxy会自动将流量以round-robin的方式转发给该service的每一个Pod。

缺点:这种服务暴露方式,无法让你指定自己想要的应用常用端口,不过可以在集群上再部署一个反向代理作为流量入口。

LoadBalancer
LoadBalancer只能在Service上定义。公有云提供的负载均衡器,如AWS、Azure、CloudStack。

Kind: Service
apiVersion: v1
metadata:
  name: influxdb
spec:
  type: LoadBalancer
  ports:
   - port: 8086
  selector:
   name: influxdb

内部可以使用ClusterIP加端口来访问服务。
外部可以用以下方式访问该服务:

  • 使用任一节点的IP加30051端口访问该服务;
  • 使用EXTERNAL-IP来访问,这是一个VIP,是云供应商提供的负载均衡IP。

Ingress
必须要部署Ingress Controller才能创建Ingress资源,Ingress Controller是以一种插件形式提供。
Ingress Controller是部署在Kubernetes之上的Docker容器。它的Docker镜像包含一个像nginx或HAProxy的负载均衡器和一个控制器守护进程。

控制器守护程序从Kubernetes接收所需的Ingress配置。它会生成一个nginx或HAProxy配置文件,并重新启动负载均衡器进程以使更改生效。

Ingress Controller是由Kubernetes管理的负载均衡器。

Kubernetes Ingress提供了负载均衡器的典型特性:HTTP路由、粘性会话、SSL终止、SSL直通,TCP和UDP负载均衡等。

apiVersion: extension/v1beta1
kind: Ingress
metadata:
  name: influxdb
spec:
  rules:
    - host: influxdb.kube.example.com
      http:
        paths:
          - backend:
              serviceName: influxdb
              servicePort: 8086

外部访问URL http://influxdb.kube.example.com/ping访问该服务,入口就是80端口,然后Ingress controller直接将流量转发给后端Pod,不需再经过kube-proxy的转发,比LoadBalancer方式更高效。

总的来说Ingress是一个非常灵活和越来越得到厂商支持的服务暴露方式,包括Nginx、HAProxy、Traefik,还有各种Service Mesh,而其它服务暴露方式可以更适用于服务调试、特殊应用的部署。