【概念解说】

当pod被实例化出来,如果运行 一段时间会销毁,虽然deployment和ds会注意管理和维护pod的数目,但是pod销毁后再重建,ip会发生变化,这对于服务来说,是很麻烦的。所以需要有一个中间层来屏蔽后端的这些变化,为前端提供一个稳定的环境。大家要访问服务的时候,都是先访问这个中间层,只要它不改变ip,那么我们访问服务的时候,就永远只要访问这个IP即可。另外,这个中间层收了流量,肯定需要转发出去,如果可以自动进行负载均衡,就再好不过了,比如像LVS,但是这不是云原生的,所以Kubernetes 又专门定义了一个新的对象:Service,在集群内部,做这个中间层,并负责负载均衡。

客户只用访问serveice的固定IP,service会根据iptables来转发请求,这个iptables,是每个节点的kube-proxy组件自动维护的。

【YAML描述】

service创建YAML的方式,为kubectl expose,这个命令同样适用于创建pod,deployment,daemonset的YAML。

apiVersion: v1
kind: Service
metadata:
name: xxx-svc

使用 kubectl expose 指令时还需要用参数 --port 和 --target-port 分别指定映射端口和容器端口,而 Service 自己的 IP 地址和后端 Pod 的 IP 地址可以自动生成。

export out="--dry-run=client -o yaml"
kubectl expose deploy ngx-dep --port=80 --target-port=80 $out

如下是一个service YAML示例:

apiVersion: v1
kind: Service
metadata:
name: ngx-svc spec:
selector:
app: ngx-dep ports:
- port: 80
targetPort: 80
protocol: TCP

1)selector:用来过滤出要代理的那些 Pod。因为我们指定要代理ngx-dep这个 Deployment,所以 Kubernetes 就为我们自动填上了 ngx-dep 的标签,会选择这个 Deployment 对象部署的所有 Pod;

2)ports:分别代表外部端口、内部端口和使用的协议。

 【如何使用】

1、创建一个configmap的YAML文件cm.yml,定义一个nginx的配置片段,输出服务器的地址、主机名、请求的URL等信息。kubectl apply -f cm.yml;

apiVersion: v1
kind: ConfigMap
metadata:
name: ngx-conf data:
default.conf: |
server {
listen 80;
location / {
default_type text/plain;
return 200
'srv : $server_addr:$server_port\nhost: $hostname\nuri : $request_method $host $request_uri\ndate: $time_iso8601\n';
}
}

2、将cm注入到deployment中:创建一个deployment的YAML文件deployment.yml,在“template.volumes”里定义存储卷,再用“volumeMounts”把配置文件加载进 Nginx 容器里。kubectl apply -f deployment.yml:

apiVersion: apps/v1
kind: Deployment
metadata:
name: ngx-dep spec:
replicas: 2
selector:
matchLabels:
app: ngx-dep template:
metadata:
labels:
app: ngx-dep
spec:
volumes:
- name: ngx-conf-vol
configMap:
name: ngx-conf containers:
- image: nginx:alpine
name: nginx
ports:
- containerPort: 80 volumeMounts:
- mountPath: /etc/nginx/conf.d
name: ngx-conf-vol

3、使用svc.yml创建service对象:创建一个svc的YAML文件svc.yml,kubectl apply后,使用get svc查看状态。可以看到,Kubernetes 为 Service 对象自动分配了一个 IP 地址“10.103.92.97”,这个地址段是独立于 Pod 地址段的。而且 Service 对象的 IP 地址还有一个特点,它是一个“虚地址”,不存在实体,只能用来转发流量。

apiVersion: v1
kind: Service
metadata:
name: ngx-svc spec:
selector:
app: ngx-dep ports:
- port: 80
targetPort: 80
protocol: TCP

4、查看service对象代理了哪些后端的pod。截图里显示 Service 对象管理了两个 endpoint,分别是10.244.1.15:80和10.244.1.16:80,与 Service、Deployment 的定义相符。进入其中一个pod,curl代理ip10.103.92.97,看到返回的信息中,Service 确实用一个静态 IP :10.103.92.97,代理了两个 Pod 的动态 IP 地址。

5、delete一个pod,ip应该会变化,之后我们重复第四步的操作

6、如果ping 10.103.92.97,是ping不通的,因为这是一个虚ip,仅仅有从来做流量转发用的,ping它是不会回reply包的,所以不会ping通的。

【一点扩展】

service这个工作原理,是不是很容易让我们想到url访问的时候,我们也是输入一个域名,然后这个域名会有很多A记录,让我们最终可以解析了这个域名,进而和这个ip进行真实的业务交互。所以service提供的这个虚ip,可不可以也是个域名呢?毕竟文字肯定要比数字好记住。这里有一个新的概念:namespace(ns)。使用kubectl get ns可以看到当前集群里有哪些ns。

其中,有一个默认的ns,叫default,如果不显式指定,API对象都会在这个default ns里。其他的ns也都有各自的用途,比如kube-system,就有apiserver,etcd等核心组件的pod。而service的域名形式就是:对象.名字空间.svc.cluster.local,很多时候我们也可以省略为:对象.名字空间,甚至简化为:对象名。

我们再次进入上面的ngx-dep pod,curl一下这个域名:ngx-svc,同样可以访问到。即,我们可以通过域名的方式,访问后端服务。(Kubernetes 也为每个 Pod 分配了域名,形式是“IP 地址. 名字空间.pod.cluster.local”,但需要把 IP 地址里的 . 改成 - 。比如地址 10.10.1.87,它对应的域名就是 10-10-1-87.default.pod。)

 【service如何对外暴露服务】

Service 对象有一个关键字段“type”,表示 Service 是哪种类型的负载均衡。前面我们看到的用法都是对集群内部 Pod 的负载均衡,所以这个字段的值就是默认的“ClusterIP”,Service 的静态 IP 地址只能在集群内访问。除了“ClusterIP”,Service 还支持其他三种类型,分别是“ExternalName”“LoadBalancer”“NodePort”。不过前两种类型一般由云服务商提供,我们的实验环境用不到,所以接下来就重点看“NodePort”这个类型。

如果我们在使用命令 kubectl expose 的时候加上参数 --type=NodePort,或者在 YAML 里添加字段 type:NodePort,那么 Service 除了会对后端的 Pod 做负载均衡之外,还会在集群里的每个节点上创建一个独立的端口,用这个端口对外提供服务,这也正是“NodePort”这个名字的由来。get svc看到“TYPE”变成了“NodePort”,而在“PORT”列里的端口信息也不一样,除了集群内部使用的“80”端口,还多出了一个“32135”端口,这就是 Kubernetes 在节点上为 Service 创建的专用映射端口。

实验一下:访问我们worker1 ip的32135端口,看看是否可以访问到ngx-dep这两个pod的服务。红框中看到,访问到的pod信息是正确的。 不过,Kubernetes 为了避免端口冲突,默认只在“30000~32767”这个范围内随机分配,只有 2000 多个可以使用,所以可能不够用。另外登录master和worker,netstat会看到,原来k8s集群里的每个节点都开放了32135端口,然后通过kube-proxy路由到最终的后端服务,如果业务量大,这无疑也增加了网络通信的成本。但 NodePort 仍然是 Kubernetes 对外提供服务的一种简单易行的方式,在其他更好的方式出现之前,我们也只能使用它。

最新文章

  1. 静态属性,直接把iis搞垮掉 Http error 503 Service Unavailable
  2. [javascript] 对象拷贝
  3. ionic导航之后返回功能的说明
  4. 基于canvas的前端图片压缩
  5. 蓝凌表单的表体调用Javascript
  6. 4.Maven概念模型,maven的生命周期,Maven坐标,依赖管理(依赖范围,依赖声明),仓库管理,私服概念
  7. Lake Counting(poj 2386)
  8. JQuery打印
  9. 下载文件downloadFile
  10. Unity Editor 下创建Lua和Text文件
  11. 解决VS打开文件出现No EditorOptionDefinition export found for the given option name问题
  12. C#会对于未赋值的变量/成员变量,给予一个初始值吗?
  13. JSch远程执行脚本
  14. Office 365 Pass-through身份验证及Seamless Single Sign-On
  15. Kafka设计解析(十五)Kafka controller重设计
  16. easyui动态生成双列头
  17. 树莓派与微信公众号对接(python)
  18. Ubuntu16.04使用Tarball安装ntp
  19. ADO.net笔记
  20. cf1043D. Mysterious Crime(枚举)

热门文章

  1. Portainer功能使用之开启远程访问
  2. 【TS】object类型
  3. 郁金香 用C写一个定时器来循环获取阳光
  4. 云小课|MRS数据分析-通过Spark Streaming作业消费Kafka数据
  5. vue-cli 更新遇到的问题,卸载不掉旧版本2.9.6(可行)
  6. PostGIS之几何有效性
  7. JavaScript之void
  8. vue3 使用watch 监听多个数据
  9. 基于TDSQL-C对OOM问题进行优化
  10. Android MVP框架 详细代码