前端圈

分享与交流前端开发相关知识

如何使用服务访问Kubernetes应用程序

欢迎来到“坚果壳中的Kubernetes”博客系列的另一期👋在这一部分中,我们将深入研究Kubernetes Services。您将了解:

  • 内部和外部通信的Kubernetes服务类型
  • 集群内服务发现技术
  • 如何访问外部服务等

《如何使用服务访问Kubernetes应用程序》

与往常一样,代码(和YAML!)在GitHub上可用

很高兴通过Twitter获得您的反馈或发表评论🙏🏻

Kubernetes Pod是短暂的,即它们不会在重新启动或重新安排时保留其属性。这适用于容器存储(卷),标识(Pod名称),甚至IP地址。这在应用程序访问方面提出了挑战。像Deployments 这样的较高层抽象控制多个Pods并将它们视为无状态实体-客户端如何访问这些Pods 组?客户是否需要了解Poda下的每个坐标Deployment?另外,您不能指望Pod重启后获得相同的IP-客户端应用程序将如何继续访问Pod

输入Kubernetes服务!

Kubernetes服务

Service是可访问一堆Pods 的更高级别的组件。它将客户端应用程序与一个Deployment(或一组Pods)的细节分离开来,以实现可预测和稳定的访问。

Kubernetes定义了以下服务类型:

  • ClusterIP -仅在Kubernetes集群内访问
  • NodePort -使用IP和Kubernetes节点本身的端口进行访问
  • LoadBalancer —使用外部负载平衡器(通常是特定于云提供商的),例如,AKS中Azure负载平衡器
  • ExternalName —将a映射Service到外部DNS名称

可以将访问模式分为两大类:

  • 外部访问
  • 内部访问

外部访问

如果希望外部客户端访问Kubernetes集群中的应用程序,则可以使用NodePortLoadBalancer服务。

节点端口

NodePort听起来确实像是-使得可以使用节点的IP(已在其Pod上调度)和Kubernetes分配的随机端口(例如,对于HTTP端点)访问集群中的应用程序http://<node_ip>:<port>

这是一个例子:

apiVersion: v1
kind: Service
metadata:
  name: kin-nodeport-service
spec:
  type: NodePort
  ports:
    - port: 80
      targetPort: 8080
  selector:
    app: kin-service-app

尽管NodePort从概念上讲很简单,但是您应该注意以下几点

  • 随机端口分配限制为范围- 30000–32767
  • 集群中每个节点的端口都相同
  • 可以指定一个静态端口号,但是Service由于端口分配,无效端口等原因,创建可能会失败。

负载均衡器

在云提供商中运行时,LoadBalancer服务类型会触发外部负载均衡器的配置,该负载均衡器会在后备服务器之间分配流量Pod

为了了解这一点,让我们在Azure Kubernetes Service上部署应用程序,并使用LoadBalancer服务公开它。

使用基于多节点(至少两个)的基于云的Kubernetes集群可以很容易地演示这个概念。随意使用其他任何云提供商(例如GKE尝试这种情况)

如果要使用Azure进行尝试,请遵循以下一些先决条件,然后再阅读本文中的教程:

设置完群集后,请确保kubectl使用以下az aks get-credentials命令配置连接到该群集-这将下载凭据并配置Kubernetes CLI以使用它们。

az aks get-credentials --name <AKS-cluster-name> --resource-group <AKS-resource-group>

您应该已经准备就绪。让我们从创建Service一起以及示例应用程序开始。

为简单起见,直接从GitHub存储库中引用了YAML文件,但是您也可以将文件下载到本地计算机上,并以相同的方式使用它。

kubectl apply -f https://raw.githubusercontent.com/abhirockzz/kubernetes-in-a-nutshell/master/services/loadbalancer/service.yaml

kubectl apply -f https://raw.githubusercontent.com/abhirockzz/kubernetes-in-a-nutshell/master/services/app/app.yaml

示例应用程序实际上是简单的Go程序

确认Service已创建

kubectl get svc/kin-lb-service

您应该返回类似以下的回复

NAME             TYPE           CLUSTER-IP     EXTERNAL-IP     PORT(S)        AGE
kin-lb-service   LoadBalancer   10.0.149.217   <pending>        80:31789/TCP   1m

pending状态为EXTERNAL-IP临时-这是因为AKS 在幕后置备Azure负载平衡器

一段时间后,您应该看到EXTERNAL-IP填充了负载均衡器的公共IP

NAME             TYPE           CLUSTER-IP     EXTERNAL-IP     PORT(S)        AGE
kin-lb-service   LoadBalancer   10.0.149.217   242.42.420.42   80:31789/TCP   2m

检查应用程序是否也已部署-您应该看到两个PodRunning状态

kubectl get pod -l=app=kin-service-app

NAME                              READY   STATUS    RESTARTS   AGE
kin-service-app-775f989dd-gr4jk   1/1     Running   0          5m
kin-service-app-775f989dd-rmq6r   1/1     Running   0          5m

您可以使用负载平衡器IP来访问应用程序,如下所示:

curl http://242.42.420.42/

请注意,您的IP地址会有所不同。此外,负载平衡器端口是80按照spec.ports.port在属性Service清单。

您应该看到类似于以下内容的响应:

Hello from Pod IP 10.244.0.151 on Node aks-agentpool-37379363-0

此输出显示:

  • 的知识产权Pod,并且,
  • NodePod所在的名称

如果您尝试再次访问该应用程序(curl http://242.42.420.42/),则很可能将负载均衡到另一个实例上Pod,该实例可能位于另一个实例上,Node并且您可能会看到如下响应:

Hello from Pod IP 10.244.1.139 on Node aks-agentpool-37379363-1

您可以扩展(扩展)应用程序,并继续使用Load Balancer IP对其进行访问。

如果要使用CLI获取Azure负载平衡器详细信息,请使用以下命令:

export AZURE_RESOURCE_GROUP=[enter AKS resource group]
export  AKS_CLUSTER_NAME=[enter AKS cluster name]

使用以下az aks show命令获取AKS集群基础资源组名称

INFRA_RG=$(az aks show --resource-group $AZURE_RESOURCE_GROUP --name $AKS_CLUSTER_NAME --query nodeResourceGroup -o tsv)

使用它通过az network lb list命令列出负载均衡器(您将返回一个带有负载均衡器信息的JSON响应)

az network lb list -g $INFRA_RG

内部访问 ClusterIP

ClusterIP服务类型,并且可以在群集内进行通信-只需ClusterIP在中指定spec.type,您就可以使用了!

ClusterIP 是默认服务类型

即使对于具有ClusterIP Service类型的集群内部通信,也必须有一种方法可以让应用程序A调用应用程序B(通过Service)。群集中应用的服务发现方式有两种:

  • 环境变量
  • DNS

环境变量

每一个Pod都填充了一组特定于的环境变量Service。让我们看看这个动作!ClusterIP如下创建服务,并确认已创建服务

kubectl apply -f https://raw.githubusercontent.com/abhirockzz/kubernetes-in-a-nutshell/master/services/clusterip/service.yaml

kubectl get svc/kin-cip-service

还记得我们部署来探索LoadBalancer Service类型的应用程序吗?好吧,再次删除并重新创建它(稍后我将解释为什么这样做)

kubectl delete -f https://raw.githubusercontent.com/abhirockzz/kubernetes-in-a-nutshell/master/services/app/app.yaml

kubectl apply -f https://raw.githubusercontent.com/abhirockzz/kubernetes-in-a-nutshell/master/services/app/app.yaml

应用程序进入Running状态(选中kubectl get pod -l=app=kin-service-app)后,exec(直接在中执行命令Pod)进入,Pod以检查其环境变量

kubectl exec <enter-pod-name> -- env | grep KIN_CIP

您将看到类似以下的结果:

KIN_CIP_SERVICE_PORT_9090_TCP_ADDR=10.0.44.29
KIN_CIP_SERVICE_SERVICE_PORT=9090
KIN_CIP_SERVICE_PORT_9090_TCP_PROTO=tcp
KIN_CIP_SERVICE_PORT_9090_TCP=tcp://10.0.44.29:9090
KIN_CIP_SERVICE_PORT=tcp://10.0.44.29:9090
KIN_CIP_SERVICE_SERVICE_HOST=10.0.44.29
KIN_CIP_SERVICE_PORT_9090_TCP_PORT=9090

注意环境变量名称的格式吗?它们包括ClusterIP Service本身的名称(即kin-cip-service),-由代替,_其余部分为大写。这是一种预定义的格式,可以在与Service支持它的名称的情况下用于与另一个应用程序进行通信。

需要注意的Pod是:只有在环境变量a Service之前创建时,环境变量才能作为a 的种子!这就是为什么我们必须重新创建应用程序才能看到效果的原因。

让我们Pod使用环境变量从另一个应用程序访问该应用程序。只要运行另一个Podcurl

kubectl run --rm --generator=run-pod/v1 curl --image=radial/busyboxplus:curl -i --tty

您很快就会看到命令提示符

确认它Pod也具有环境变量(使用env | grep KIN_CIP),然后简单地curl使用环境变量来应用程序端点

curl http://$KIN_CIP_SERVICE_SERVICE_HOST:$KIN_CIP_SERVICE_SERVICE_PORT

您应该看到与LoadBalancer示例相同的响应,即

Hello from Pod IP 10.244.0.153 on Node aks-agentpool-37379363-0

再尝试几次,以确认各个Pod之间的负载正在平衡!因此,我们得出基础上,环境变量Service名称,即kin-cip-service转变为KIN_CIP_SERVICE并加入部分的其余部分- _SERVICE_HOST_SERVICE_PORT分别在主机和端口。

域名解析

Kubernetes具有内置的DNS服务器(例如CoreDNS),该服务器维护每个DNS服务器的DNS记录Service。就像环境变量一样,DNS技术提供了一致的命名方案,您可以在知道Service名称(以及namespace需要时提供的其他信息)的基础上访问应用程序。

好消息是,这种技术不依赖的顺序SerivcePod创作一样,与环境变量的情况下

您可以立即尝试:

curl Pod再次运行

kubectl run --rm --generator=run-pod/v1 curl --image=radial/busyboxplus:curl -i --tty

要访问该应用程序:

curl http://kin-cip-service.default.svc.cluster.local:9090

一切都应该以相同的方式工作!FQDN格式为<service-name>.<namespace>.<cluster-domain-suffix>。在我们的情况下,它映射到:

  • service-name – kin-cip-service
  • namespace – default
  • cluster-domain-suffix – svc.cluster.local

对于相同的应用程序,namespace您实际上可以跳过其中的大部分,而仅使用服务名称!

映射外部服务

在某些情况下,您需要从Kubernetes集群中的应用程序引用外部服务。您可以通过以下几种方法

  • 以静态方式使用Endpoints资源
  • 使用ExternalName服务类型

静态的 Endpoints

现在是时候揭示Kubernetes会EndpointsService您创建的每一个创建资源(如果使用a selector,那么大多数情况下都会出现这种情况,除了少数情况)。Endpoints实际上是捕获后备IP 的对象Pod。您可以使用查看现有的kubectl get endpoints

如果要访问外部服务,则需要:

  • 创建一个Service没有任何内容selector-Kubernetes不会创建Endpoints对象
  • 手动创建与您要访问的服务(具有相同名称)和IP /端口Endpoints相对应的资源Service

这给您带来相同的好处,即您可以保持Service常数并在需要时在幕后更新实际实体。例如,我们将http://demo.nats.io:8222/使用此技术抽象化对公共HTTP端点的访问。

首先创建 Service

kubectl apply -f https://raw.githubusercontent.com/abhirockzz/kubernetes-in-a-nutshell/master/services/external/static/service.yaml

这是什么Service样子。请注意,我们正在映射port 8080到我们要访问的实际(目标)端口8222

kind: Service
apiVersion: v1
metadata:
  name: demo-nats-public-service
spec:
  type: ClusterIP
  ports:
    - port: 8080
      targetPort: 8222

让我们看一下Endpoints资源。

kind: Endpoints
apiVersion: v1
metadata:
  name: demo-nats-public-service
subsets:
  - addresses:
      - ip: 107.170.221.32
    ports:
      - port: 8222

请注意以下几点:

  • 资源(demo-nats-public-service)的名称与Service
  • 我们使用subsets属性指定ipport(我们通过使用来找到了ip支持)demo.nats.ioping demo.nats.io

使用以下方法创建它:

kubectl apply -f https://raw.githubusercontent.com/abhirockzz/kubernetes-in-a-nutshell/master/services/external/static/endpoints.yaml

而已!让我们看看这是否有效。只需运行一个curl Pod

kubectl run --rm --generator=run-pod/v1 curl --image=radial/busyboxplus:curl -i --tty

现在,我们只需要使用Serviceie 的名称demo-nats-public-service(以及port 8080)就可以了。

curl http://demo-nats-public-service:8080

您应该看到以下响应(就像您浏览到一样http://demo.nats.io:8222

<html lang="en">
   <head>
    <link rel="shortcut icon" href="http://nats.io/img/favicon.ico">
    <style type="text/css">
      body { font-family: "Century Gothic", CenturyGothic, AppleGothic, sans-serif; font-size: 22; }
      a { margin-left: 32px; }
    </style>
  </head>
  <body>
    <img src="http://nats.io/img/logo.png" alt="NATS">
    <br/>
    <a href=/varz>varz</a><br/>
    <a href=/connz>connz</a><br/>
    <a href=/routez>routez</a><br/>
    <a href=/gatewayz>gatewayz</a><br/>
    <a href=/leafz>leafz</a><br/>
    <a href=/subsz>subsz</a><br/>
    <br/>
    <a href=https://docs.nats.io/nats-server/configuration/monitoring.html>help</a>
  </body>
</html>

ExternalName

ExternalName是另Service一种可以用于将a映射Service到DNS名称的类型。请注意,这是一个DNS名称,而不是上述策略(使用手动创建Endpoints)的IP /端口组合。

Serivce清单中:

  • 不要包括 selector
  • 使用externalName属性指定DNS名称,例如test.example.com
  • 不允许使用IP地址

这是一个例子:

apiVersion: v1
kind: Service
metadata:
  name: demo-nats-public-service2
spec:
  type: ExternalName
  externalName: demo.nats.io

我们正在创建一个Service名为demo-nats-public-service2映射到DNS名称demo.nats.io使用的spec.typeExternalName

它的工作方式相同,即您需要使用Service名称来访问外部实体。唯一的区别(与手动Endpoints方法相比)是,您还需要知道端口。尝试一下:

创建 Service

kubectl apply -f https://raw.githubusercontent.com/abhirockzz/kubernetes-in-a-nutshell/master/services/external/external-name/service.yaml

只需运行一个 curl Pod

kubectl run --rm --generator=run-pod/v1 curl --image=radial/busyboxplus:curl -i --tty

现在,我们需要使用的只是我们的名字(Servicedemo-nats-public-service2port 8222

curl http://demo-nats-public-service2:8222

您应该会看到与先前场景相同的响应

Headless 服务

你可以得到负载均衡组中Pod使用S LoadBalancerNodePortClusterIP服务类型。A Headless Service允许访问单个Pods-在这种情况下不涉及代理。这在许多情况下都很有用,例如

  • 考虑一个点对点系统,其中各个实例(Pods)需要彼此访问。
  • 从属实例需要了解主Pod的主从样式服务

为了创建一个Headless Service,您需要显式指定None为的值.spec.clusterIP。这是一个例子:

apiVersion: v1
kind: Service
metadata:
  name: kin-hl-service
spec:
  clusterIP: None
  ports:
    - port: 9090
      targetPort: 8080
  selector:
    app: kin-service-app

与其他类型相比,您使用无头服务的方式有所不同。针对服务(例如<service-name>.<namespace>.svc.cliuster.local)的DNS查找返回对应于不同IP的多个IP Pods(与其他服务类型的单个虚拟IP相比)。让我们看看这个动作

创建 Service

kubectl apply -f https://raw.githubusercontent.com/abhirockzz/kubernetes-in-a-nutshell/master/services/headless/service.yaml

跑过 curl Pod

kubectl run --rm --generator=run-pod/v1 curl --image=radial/busyboxplus:curl -i --tty

检查备用PodIP

nslookup kin-hl-service.default.svc.cluster.local

您将收到类似于以下的回复

[ [email protected]:/ ]$ nslookup kin-hl-service
Server:    10.0.0.10
Address 1: 10.0.0.10 kube-dns.kube-system.svc.cluster.local

Name:      kin-hl-service
Address 1: 10.244.0.153 10-244-0-153.kin-hl-service.default.svc.cluster.local
Address 2: 10.244.1.141 10-244-1-141.kin-hl-service.default.svc.cluster.local

10-244-0-153.kin-hl-service.default.svc.cluster.local10.244.1.141 10-244-1-141.kin-hl-service.default.svc.cluster.local与个体Pods 的坐标相对应-传统Service类型无法实现。现在,您可以使用此访问具体Pod

curl http://10-244-0-153.kin-hl-service.default.svc.cluster.local:8080

//response
Hello from Pod IP 10.244.0.153 on Node aks-agentpool-37379363-0

curl http://10-244-1-141.kin-hl-service.default.svc.cluster.local:8080

//response
Hello from Pod IP 10.244.1.141 on Node aks-agentpool-37379363-1

入口

我们确实介绍了Kubernetes的基础知识Service,但我确实想强调一下,Ingress它完全值得单独发表。Ingress不是Service类型(例如ClusterIP等)-可以认为是上的抽象Service。就像Services的前端是一堆Pods一样,Ingress可以将其配置为与多个支持Services一起使用,并按照您可以定义的规则转发请求。

an提供的智能Ingress实际上是以IngressController 的形式实现的。例如,Minikube带有基于NGINX的Ingress Controller。控制器负责Service在评估Ingress规则后提供对适当支持的访问。

这就是“坚果壳中的Kerernetes”系列的这一部分。敬请期待更多!

温馨提示,如果您有兴趣使用Azure学习Kubernetes和容器只需创建一个免费帐户就可以开始!一个很好的起点是使用文档中的快速入门,教程和代码示例来熟悉该服务。我还强烈建议您查看50天的Kubernetes学习之路。高级用户可能希望参考Kubernetes最佳实践,或观看一些视频以获取演示,主要功能和技术讲座。

我真的希望您喜欢这篇文章并从中学到一些东西🙌请喜欢并关注,如果您做得到!

点赞

发表评论

电子邮件地址不会被公开。 必填项已用*标注