[转帖]k8s 中的服务如何沟通
k8s 中的服务如何沟通
https://www.jianshu.com/p/9fae09876eb7
本文将介绍 k8s 中的服务如何相互访问,例如后端服务访问数据库,不同类型的服务间的相互访问。并介绍用于实现这种访问的资源 服务service
。
挡在 pod 身前的 service
我们现在已经有了 pod ,那让他们相互访问不可以么?答案是,不可以,因为 pod 是有生命周期的,他可能随时被创建也可能随时被销毁,而 每次新建 pod 就会给其分配一个随机的 ip,并且 k8s 也会自动调控 pod 的数量。这就导致了 pod 之间直接访问是不现实的,如果有一个入口,可以动态绑定那些提供相同服务的 pod,并将其开放在固定端口上,这样访问起来不就方便很多了么?这个入口在 k8s 中被称为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
毫无影响,其实在svc
和pod
之间还包含了一个资源叫做endpoint
,endpoint
(简称ep
)是一组地址及其端口的合集,如下图,只要一个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 不就通过完全一样的方式访问外部服务了么?
你可以把这张图拿去和"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.type
为ExternalName
,然后在使用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 中的服务如何沟通的更多相关文章
- Docker & k8s 系列三:在k8s中部署单个服务实例
本章将会讲解: pod的概念,以及如何向k8s中部署一个单体应用实例. 在上面的篇幅中,我们了解了docker,并制作.运行了docker镜像,然后将镜像发布至中央仓库了.然后又搭建了本机的k8s环境 ...
- 在k8s中的基本概念
在k8s中的基本概念 一.Pod1. podk8s下最重要也最基本的概念,由一个根容器Pause和许多用户业务容器组成,是容器的载体. 2. pod的yaml定义格式及字段 apiVersion: v ...
- K8S中如何跨namespace 访问服务?为什么ping不通ClusterIP?
1.K8S中如何跨namespace 访问服务? 2.在Pod中为什么ping不通ClusterIP? 简述: Rancher2.0中的一个用户,在K8S环境中,创建两个namespace,对应用进行 ...
- 在k8s中搭建可解析hostname的DNS服务
2016-01-25更新 上篇文章总结k8s中搭建hbase时,遇到Pod中hostname的DNS解析问题,本篇将通过修改kube2sky源码来解决这个问题. 1 前言 kube2sky在Githu ...
- k8s中的dns服务发现
一.dns服务 1.解决的问题 为了通过服务的名字在集群内进行服务相互访问,需要创建一个dns服务 2.k8s中使用的虚拟dns服务是skydns 二.搭建 1.创建并应用skydns-rc.yaml ...
- [转帖]在 k8s 中通过 Ingress 配置域名访问
在 k8s 中通过 Ingress 配置域名访问 https://juejin.im/post/5db8da4b6fb9a0204520b310 在上篇文章中我们已经使用 k8s 部署了第一个应用,此 ...
- [转帖]在 k8s 中自动为域名配置 https
在 k8s 中自动为域名配置 https https://juejin.im/post/5db8d94be51d4529f73e2833 随着 web 的发展,https 对于现代网站来说是必不可少的 ...
- k8s中yaml文常见语法
在k8s中,所有的配置都是 json格式的.但为了读写方便,通常将这些配置写成yaml 格式,其运行的时候,还是会靠yaml引擎将其转化为json,apiserver 也仅接受json的数据类型. y ...
- 转 docker创建私有仓库和k8s中使用私有镜像
docker私有仓库建立 环境说明我们选取192.168.5.2做私有仓库地址yum install docker -y1.启动docker仓库端口服务 docker run -d -p 5000:5 ...
随机推荐
- jieba分词原理-DAG(NO HMM)
最近公司在做一个推荐系统,让我给论坛上的帖子找关键字,当时给我说让我用jieba分词,我周末回去看了看,感觉不错,还学习了一下具体的原理 首先,通过正则表达式,将文章内容切分,形成一个句子数组,这个比 ...
- CMake编译的VS工程,安装时遇到错误:error MSB3073: 命令“setlocal
错误提示 70>CMake Error at src/base/cmake_install.cmake:63 (file): 70> file INSTALL cannot find 70 ...
- AOD.NET实现数据库事物Transaction
在开始介绍文章主要内容前先简单说一下事务 1.事务介绍 事务是一种机制.是一种操作序列,它包含了一组数据库操作命令,这组命令要么全部执行,要么全部不执行.因此事务是一个不可分割的工作逻辑单元.在数据库 ...
- Android 实现系统分享
使用手机上的程序,来分享/发送,比如QQ的“发送到我的电脑”. 1.分享/发送文本内容 Intent shareIntent = new Intent(); shareIntent.setAction ...
- X264-视频帧的存取
X264的编码器结构体x264_t中的子结构体字段frames包含了4个临时视频帧序列空间:current.next.unused和reference,分别保存当前编码帧.将编码帧序列.未处理原始视频 ...
- 3-1 Pandas-概述
Pandas章节应用的数据可以在以下链接下载: https://files.cnblogs.com/files/AI-robort/Titanic_Data-master.zip Pandas:数据分 ...
- Ubuntu14 关机重启、版本、网络、防火墙
关机.重启: 立即关机:halt.poweroff.shutdown -h now 延迟关机:shutdown -h 10 十分钟后关机 立即重启:reboot.shutdown -r now 延迟 ...
- 10、shell编程+流程控制+分支嵌套
SHELL 编程 shell 是一个命令解释器,侦听用户指令.启动这些指令.将结果返回给用户(交互式的shell) shell 也是一种简单的程序设计语言.利用它可以编写一些系统脚本. ...
- node端console.log输出不同颜色文字
我们知道console.log直接输出是按着终端的默认颜色来显示的, console.log('message') 那么如何指定他们的颜色显示呢?很简单,直接再加一个参数就可以了,例如: consol ...
- CSS中的父相子绝布局
主要应用场景,就是我想要块的布局根据父级来定位,而不是根据页面. 例如,下面的例子中,我用两个半圆拼成一个正圆,思路是用一个父级标签把两个子标签包起来,父标签是一个正圆,然后子标签各占一半,先化成两个 ...