k8s 中的服务如何沟通

https://www.jianshu.com/p/9fae09876eb7

本文将介绍 k8s 中的服务如何相互访问,例如后端服务访问数据库,不同类型的服务间的相互访问。并介绍用于实现这种访问的资源 服务service

挡在 pod 身前的 service

我们现在已经有了 pod ,那让他们相互访问不可以么?答案是,不可以,因为 pod 是有生命周期的,他可能随时被创建也可能随时被销毁,而 每次新建 pod 就会给其分配一个随机的 ip,并且 k8s 也会自动调控 pod 的数量。这就导致了 pod 之间直接访问是不现实的,如果有一个入口,可以动态绑定那些提供相同服务的 pod,并将其开放在固定端口上,这样访问起来不就方便很多了么?这个入口在 k8s 中被称为service

 
挡在 pod 前的 service

service(简称svc)是 k8s 中的一种常用资源。配置起来简单的很,现在我们来自己创建一个svc。首先,svc是不会自己提供服务的,他身后一定要有实质的应用来提供服务 (不一定是pod,后面会提到)。所以我们首先来通过一个rs来创建 pod。如果你对rs不是很了解的话,请参考 如何让你的应用活的更久 - rc 与 rs 。

首先新建kubia-replicaset.yaml文件,并填入如下内容:

apiVersion: apps/v1beta2
kind: ReplicaSet
metadata:
  name: kubia
spec:
  replicas: 3
  selector:
    matchLabels:
      app: kubia
  template:
    metadata:
      labels:
        app: kubia
    spec:
      containers:
      - name: kubia
        image: luksa/kubia
        ports:
        - containerPort: 8080

这个文件将创建 3 个 pod,每个 pod 都包含一个app: kubia的标签,并开放提供服务的8080端口。执行如下命令进行创建:

kubectl create -f kubia-replicaset.yaml

然后kubectl get po就可以看到创建出的三个 pod,接下来我们创建一个svc来提供对这三个 pod 的访问。新建kubia-svc.yaml文件,并填入如下内容:

apiVersion: v1
kind: Service
metadata:
  name: kubia
spec:
  ports:
  - name: http # 请为所有端口指定名称
    port: 80 # 对外开放的服务端口
    targetPort: 8080 # 后方 pod 的服务端口
  selector:
    app: kubia

可以看到基本svc的配置非常简单,只定义了两个端口和一个选择器,我们在选择器中注明了app: kubia,意思就是让这个svc去将所有携带app: kubia标签的 pod 纳入自己的后方。其实ports.name字段并不是必填项,但是为了方便维护,请为每个端口指定名称。然后我们使用下面命令创建这个svc

kubectl create -f

创建好了之后来看一下,执行kubectl get svc kubia,我们就可以看到他的信息了:

NAME    TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE
kubia   ClusterIP   10.98.237.175   <none>        80/TCP    127m

可以在CLUSTER-IP列看到这个当前的 ip 地址。也就是说,其他 pod 就可以通过这个 ip 访问到其后面的 pod。接下来我们随便使用一个 pod 访问下这个服务。执行kubectl get po并选择一个顺眼的 pod。然后使用下面的命令进行访问svc注意修改 pod 名和 svc 的 ip 地址

kubectl exec kubia-7rt2n -- curl -s 10.98.237.175

这条命令里的--是一个分隔符,之前的部分是属于kubectl的,之后的是属于要在 pod 内部执行的命令的。

然后就可以看到来自svc后方 pod 的响应了:

root@master1:~# kubectl exec kubia-7rt2n -- curl -s 10.98.237.175
You've hit kubia-pxfw7
root@master1:~# kubectl exec kubia-7rt2n -- curl -s 10.98.237.175
You've hit kubia-7rt2n
root@master1:~# kubectl exec kubia-7rt2n -- curl -s 10.98.237.175
You've hit kubia-7rt2n
root@master1:~# kubectl exec kubia-7rt2n -- curl -s 10.98.237.175
You've hit kubia-fxqcc

可以看到,svc同时也实现了负载均衡,合理的将请求平摊到了每一个 pod 上。

service 对 pod 的动态绑定

因为svc是通过我们事先定义好的标签选择器来查找 pod 的,所以 pod 的 ip 地址变动对于svc毫无影响,其实在svcpod之间还包含了一个资源叫做endpointendpoint(简称ep)是一组地址及其端口的合集,如下图,只要一个svc有标签选择器的话,他就会自动创建一个同名的ep来标记出自己的要管理的 pod。

 
svc、ep、pod之间的关系

我们可以通过如下命令来查看我们刚才创建的kubia服务的ep

root@master1:~# kubectl describe svc kubia
Name:              kubia
Namespace:         default
Labels:            <none>
Annotations:       <none>
Selector:          app=kubia
Type:              ClusterIP
IP:                10.98.237.175
Port:              <unset>  80/TCP
TargetPort:        8080/TCP
Endpoints:         10.244.1.18:8080,10.244.2.14:8080,10.244.3.14:8080
Session Affinity:  None
Events:            <none>

然后就可以在Endpoints列中找到他包含的地址及端口号,这三个用,分隔的地址正是三个 pod 的地址。你可以使用kubectl get pod -o wide来查看 pod 的地址。你可以执行如下命令来重建所有的kubia pod,然后再来查看ep,会发现其ENDPOINTS也会自动更换成这三个 pod 的值。

kubectl delete po -l app=kubia
root@master1:~# kubectl get endpoints kubia
NAME    ENDPOINTS                                            AGE
kubia   10.244.1.18:8080,10.244.2.14:8080,10.244.3.14:8080   169m

发现服务

你可能已经发现了,在上文的测试中,我们使用了curl http://x.x.x.x的方式访问的svc,这样的话如果svc重建导致 ip 地址改变了,那我们岂不是访问不到了?k8s 也想到了这一点,所以提供了通过FQDN(全限定域名)访问服务的方式,你可以在任意一个 pod 上直接使用服务的名称来访问服务:

root@master1:~# k exec kubia-5n2m2 -- curl -s http://kubia
You've hit kubia-bv2k8

这种方式可以访问同一命名空间中的服务,k8s 也支持访问其他命名空间的服务。不过域名要长很多。有兴趣的话可以自行了解。

如果你发现你访问不到服务的话请使用kubectl delete po -l app=kubia重建 pod。因为 k8s 只会在创建时间晚于服务的 pod 中注入服务域名。你可以在容器中查看/etc/resolv.conf文件来找到对应的解析。

顺带一提,这个功能是 k8s 的 dns 服务器coredns实现的,你可以在命名空间kube-system中找到它,让我们为它鼓掌!

访问集群外部的服务

现在问题又来了,对于一个集群内部的 pod 来说,如果他想访问一个集群外部的服务该怎么办呢?例如一个网站的公共 api,或者是一个云数据库。我们就没办法使用svc+标签选择器的方式来获取这些服务了,因为标签选择器只能监测集群内部的 pod 。而无法放眼外部。那么我们应该怎么做呢?

还记得我们之前介绍过的endpoint资源么,没错。我们可以 自定义一个endpoint资源,用它指定外部服务的 ip 及端口,然后绑定到一个svc上,这样内部的 pod 不就通过完全一样的方式访问外部服务了么?

 
使用ep手动指定外部资源

你可以把这张图拿去和"service 对 pod 的动态绑定"小节中的图做对比,你会发现最根本的service > endpoint > 服务提供者的传递流程是没有变的。ok,现在我们来动手操作一下,首先新建一个什么都不会做的呆萌svc,它只告诉别人自己有一个端口80可以提供访问:

external-service.yaml

apiVersion: v1
kind: Service
metadata:
  name: external-service
spec:
  ports:
  - port: 80

然后通过kubectl create -f external-service.yaml创建它。然后查看一下他的信息:

root@master1: ~# kubectl describe svc external-service
Name:              external-service
Namespace:         default
Labels:            <none>
Annotations:       <none>
Selector:          <none>
Type:              ClusterIP
IP:                10.103.101.18
Port:              <unset>  80/TCP
TargetPort:        80/TCP
Endpoints:         <none>
Session Affinity:  None
Events:            <none>

因为没有标签选择器,所以它不会自己去创建endpoint,现在我们来手动为它创建一个endpoint,只要是和svc同名,那么他们两个就会自动绑定在一起:

external-endpoint.yaml

apiVersion: v1
kind: Endpoints
metadata:
  # 和 svc 相同的名称
  name: external-service
subsets:
  - addresses:
    # 这里指定了外部服务的 ip
    - ip: 11.11.11.11
    # 可以指定多个
    - ip: 22.22.22.22
    # 还要指定端口号
    ports:
    - port: 80

然后使用命令kubectl create -f external-endpoint.yaml创建endpoint,之后再查看svc的详情,你会发现他们已经完成了绑定。

root@master1:~/k8s-yaml# kubectl describe svc external-service
Name:              external-service
Namespace:         default
Labels:            <none>
Annotations:       <none>
Selector:          <none>
Type:              ClusterIP
IP:                10.103.101.18
Port:              <unset>  80/TCP
TargetPort:        80/TCP
# 看这里!
Endpoints:         11.11.11.11:80,22.22.22.22:80
Session Affinity:  None
Events:            <none>

其实还有个更简单的方法,可以 通过在svc里的配置项中指定spec.typeExternalName,然后在使用spec.externalName字段来指定外部服务的完全限定域名,如下:

apiVersion: v1
kind: Service
metadata:
  name: external-service
spec:
  # 要先指定 svc 的类型
  type: ExternalName
  # 再在这里指定外部服务的完全限定域名
  externalName: someapi.some.company.com
  ports:
  - port: 80

这样就可以免于新建一个endpoint来直接实现对外部服务的访问。而且使用方式也完全没有变化。

总结

本篇文章讲解了 k8s 中服务的访问入口资源service以及请求的”终点“endpoint。任何可以提供实际请求处理能力的pod最终都要封装成统一的service才能对外提供服务。而service中的标签选择器则可以一直监测pod的状态,从而实现无论是pod增加还是减少对外部请求者来说都是无感知的。

[转帖]k8s 中的服务如何沟通的更多相关文章

  1. Docker & k8s 系列三:在k8s中部署单个服务实例

    本章将会讲解: pod的概念,以及如何向k8s中部署一个单体应用实例. 在上面的篇幅中,我们了解了docker,并制作.运行了docker镜像,然后将镜像发布至中央仓库了.然后又搭建了本机的k8s环境 ...

  2. 在k8s中的基本概念

    在k8s中的基本概念 一.Pod1. podk8s下最重要也最基本的概念,由一个根容器Pause和许多用户业务容器组成,是容器的载体. 2. pod的yaml定义格式及字段 apiVersion: v ...

  3. K8S中如何跨namespace 访问服务?为什么ping不通ClusterIP?

    1.K8S中如何跨namespace 访问服务? 2.在Pod中为什么ping不通ClusterIP? 简述: Rancher2.0中的一个用户,在K8S环境中,创建两个namespace,对应用进行 ...

  4. 在k8s中搭建可解析hostname的DNS服务

    2016-01-25更新 上篇文章总结k8s中搭建hbase时,遇到Pod中hostname的DNS解析问题,本篇将通过修改kube2sky源码来解决这个问题. 1 前言 kube2sky在Githu ...

  5. k8s中的dns服务发现

    一.dns服务 1.解决的问题 为了通过服务的名字在集群内进行服务相互访问,需要创建一个dns服务 2.k8s中使用的虚拟dns服务是skydns 二.搭建 1.创建并应用skydns-rc.yaml ...

  6. [转帖]在 k8s 中通过 Ingress 配置域名访问

    在 k8s 中通过 Ingress 配置域名访问 https://juejin.im/post/5db8da4b6fb9a0204520b310 在上篇文章中我们已经使用 k8s 部署了第一个应用,此 ...

  7. [转帖]在 k8s 中自动为域名配置 https

    在 k8s 中自动为域名配置 https https://juejin.im/post/5db8d94be51d4529f73e2833 随着 web 的发展,https 对于现代网站来说是必不可少的 ...

  8. k8s中yaml文常见语法

    在k8s中,所有的配置都是 json格式的.但为了读写方便,通常将这些配置写成yaml 格式,其运行的时候,还是会靠yaml引擎将其转化为json,apiserver 也仅接受json的数据类型. y ...

  9. 转 docker创建私有仓库和k8s中使用私有镜像

    docker私有仓库建立 环境说明我们选取192.168.5.2做私有仓库地址yum install docker -y1.启动docker仓库端口服务 docker run -d -p 5000:5 ...

随机推荐

  1. jieba分词原理-DAG(NO HMM)

    最近公司在做一个推荐系统,让我给论坛上的帖子找关键字,当时给我说让我用jieba分词,我周末回去看了看,感觉不错,还学习了一下具体的原理 首先,通过正则表达式,将文章内容切分,形成一个句子数组,这个比 ...

  2. CMake编译的VS工程,安装时遇到错误:error MSB3073: 命令“setlocal

    错误提示 70>CMake Error at src/base/cmake_install.cmake:63 (file): 70> file INSTALL cannot find 70 ...

  3. AOD.NET实现数据库事物Transaction

    在开始介绍文章主要内容前先简单说一下事务 1.事务介绍 事务是一种机制.是一种操作序列,它包含了一组数据库操作命令,这组命令要么全部执行,要么全部不执行.因此事务是一个不可分割的工作逻辑单元.在数据库 ...

  4. Android 实现系统分享

    使用手机上的程序,来分享/发送,比如QQ的“发送到我的电脑”. 1.分享/发送文本内容 Intent shareIntent = new Intent(); shareIntent.setAction ...

  5. X264-视频帧的存取

    X264的编码器结构体x264_t中的子结构体字段frames包含了4个临时视频帧序列空间:current.next.unused和reference,分别保存当前编码帧.将编码帧序列.未处理原始视频 ...

  6. 3-1 Pandas-概述

    Pandas章节应用的数据可以在以下链接下载: https://files.cnblogs.com/files/AI-robort/Titanic_Data-master.zip Pandas:数据分 ...

  7. Ubuntu14 关机重启、版本、网络、防火墙

    关机.重启: 立即关机:halt.poweroff.shutdown -h now 延迟关机:shutdown -h 10  十分钟后关机 立即重启:reboot.shutdown -r now 延迟 ...

  8. 10、shell编程+流程控制+分支嵌套

    SHELL 编程     shell 是一个命令解释器,侦听用户指令.启动这些指令.将结果返回给用户(交互式的shell)     shell 也是一种简单的程序设计语言.利用它可以编写一些系统脚本. ...

  9. node端console.log输出不同颜色文字

    我们知道console.log直接输出是按着终端的默认颜色来显示的, console.log('message') 那么如何指定他们的颜色显示呢?很简单,直接再加一个参数就可以了,例如: consol ...

  10. CSS中的父相子绝布局

    主要应用场景,就是我想要块的布局根据父级来定位,而不是根据页面. 例如,下面的例子中,我用两个半圆拼成一个正圆,思路是用一个父级标签把两个子标签包起来,父标签是一个正圆,然后子标签各占一半,先化成两个 ...