Kubernetes使用指南
摘要:Kubernetes是由谷歌发起的开源容器编排工具。本文档解释了Kubernetes中常用的概念并结合我们的使用环境给出部署解决方案。知识基础:Docker,容器。
推荐: 也可直接阅读官方文档。可先阅读完 Tutorials 的Kubernetes Basics
之后,再阅读Concepts中的Overview
和Workloads
,Services,Load Balancing,and Networking
。即可快速上手kubernetes。
安装集群操作命令工具
通过 kubectl 连接 Kubernetes 集群
-
从 Kubernetes 版本页面 下载最新的 kubectl 客户端。
-
安装和设置 kubectl 客户端。有关详细信息,参见 安装和设置 kubectl
-
配置集群凭据:
mkdir $HOME/.kube
scp root@master-ip:/etc/kubernetes/kube.conf $HOME/.kube/config
# 对于阿里云可以在容器服务/Kubernetst/集群列表,点击管理找到这个master-ip。对于rancher上搭建的k8s,也是类似的,不过rancher本身会提供kubectl的终端,可以用那个,也可以自己参照此方法进行配置
基础概念
容器组
概念:容器组(Pod)是kubernetes调度的基本单位,一个容器组可以运行一个或者多个docker容器。 一般容器组只运行一个容器,运行多个容器是较为高级的用法。容器组是没有自愈能力的,如果容器组被调度到一个失败的主机节点,或者调度器本身就故障,那么容器组会被删除。如果是由于计算资源不足或者是主机节点的维护而导致的驱逐,容器组并不会从驱逐中存活下来,会被删掉。 在Kubernetes里面,我们使用更高级的抽象概念,控制器,来管理相对来说可随时丢弃的容器组实例。因此,尽管我们可以直接使用容器组,但是在Kubernetes内部更一般的做法是使用控制器去管理容器组,而且一般只使用部署这种控制器去调度和管理容器组,使用其他控制器来调度和管理容器组,请在十分熟悉控制器,容器组,标签选择器,各个控制器的概念之后再进行操作。 注意:重启容器组里面的容器不应该和重启容器组混淆,容器组本身并不运行所以没有重启的概念更不会有重启按钮,它只是容器运行和持久化的环境而已。 容器组模板示例:
apiVersion: v1
kind: Pod
metadata:
name: myapp-pod
labels:
app: myapp
spec:
containers:
- name: myapp-container
image: busybox
command: ['sh', '-c', 'echo Hello Kubernetes! && sleep 3600']
apiVersion:api版本号
kind:kubetnetes对象类型,又称REST对象,k8s提供了很多REST对象,例如部署(Deployment),服务(Service),副本集(ReplicatSet)等等。
metadata:元数据,存放名字,标签,uid,注释等信息
spec:指定的内容状态信息,包括容器所使用的镜像,启动命令,环境变量,容器名字等等。不同kubernetes对象类型的spec的模板格式会不一样。
容器组和控制器: 控制器可以为我们创建和管理容器组,管理副本,并提供集群范围内自愈的能力。如果节点宕机了,那么控制器就会在其他的节点上启动一个新的容器组来替代它。实验为:停止两台主机,然后运行在该主机上的Pod会处于不可用状态,之后控制器就会在其他主机上创建新的容器组来取代这些不可用的容器组。
下面是一些控制器的例子:
模板格式详情参考: kubernetes-api
删除容器组
# 此操作需要先装好kubectl
kubectl get pods # 列出默认的命名空间下的pod
kubectl delete -f $pod-id # -f为强制删除,更多用法请在终端输入:man kubectl
容器组详细概念参考: Pod Overview
控制器
副本集
副本集是下一代的副本集控制器,目前(k8s版本v1.10)除了标签选择匹配可以使用基于集合的匹配之外,其余的和副本集控制器一样。
副本集控制器
如果有非常多的容器组,那么它会终止额外的容器组。如果不够,那么它会启动更多的容器组。不像手动创建的容器组,如果容器组挂了,由副本集控制器创建的容器组会被自动替代。副本集控制器就像监督人一样,不同的是,它不监督进程而是监督多个节点的多个容器组。
模板例子:
apiVersion: v1
kind: ReplicationController
metadata:
name: nginx
spec:
replicas: 3
selector:
app: nginx
template:
metadata:
name: nginx
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
部署
注意:我们不应该直接操作属于部署的副本集,而是通过操作部署来完成,其他对部署的子对象的操作也是如此。如果一个副本集或者是容器组属于部署,那么都应该通过部署这个控制器去对副本集和容器组进行更新,删除。
详情参考:
创建部署控制器
例子:
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
app: nginx
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.7.9
ports:
- containerPort: 80
在这个例子中:
- 部署的名字是nginx-deployment.通过metadata:name指定
- 部署创建了副本集容器组,通过replicas指定,这里指定容器组副本数为3。这会创建一个副本集控制器和三个容器组。
- selector通过标签的匹配(参考Label and selectors)定义了部署要操作的容器组。在这个例子中,我们选择了容器组中标签键值对为app:nginx的容器组,这意味着,nginx-deployment这个控制器会在集群中筛选出所有有app:nginx这个键值对的容器组,并负责对他们进行控制和管理。当然,对于选择器还有高级的用法。只要容器组模板满足这些规则。(更高级的用法指,不同于这里选择器是等值选择,我们还可以使用非等值选择等基于集合的对标签的键值对的选择来选择控制器要具体要控制哪些容器组。是不是很绕,没事,目前我们还用不到这个)。 参考 Labels and Selectors
- 容器组模板的详述(模板键值含义参考API Reference ),或者说template:spec部分,指明了容器组要运行的容器,nginx,这会运行Docker Hub镜像,版本1.7.9.部署控制器模板中的.template就是容器组的模板,只是这里少了apiVersion和kind。
- 部署开放容器组使用的80端口 template部分包含了如下指令
- 容器组被贴标签 app:nginx
- 创建一个容器名为:nginx
- 运行nginx镜像,版本1.7.9
- 开放端口80为了让容器可以发送和接受流量.不过这里这个containerPort写不写都无所谓,只是个记录而已,不会影响真实的流量转发功能。
创建部署控制器可以通过控制台(对初学者比较友好),也可以通过命令行
kubectl create -f https://raw.githubusercontent.com/kubernetes/website/master/docs/concepts/workloads/controllers/nginx-deployment.yaml
注意:我们可以添加参数--record将我们这次执行的命令记录在Annotations当中。这十分有用。
接着,用kubectl get deployments 输出如下:
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
nginx-deployment 3 0 0 0 1s
- NAME 列出集群中部署的名字
- DESIRED 应用的副本指定的数量,这是我们创建部署的时候就设定的,是一种指定的状态
- CURRENT 显示当前正在运行的副本数
- UP-TO-DATE 显示被更新到指定状态的副本数
- AVAILABLE 显示对用户可用的副本数
- AGE 显示应用运行的时间
要清楚以上的值对应是模板中的哪个值
- spec:replicas 对应 desired
- .status.replicas 对应current
- .status.updatedReplicas 对应up-to-date
- .state.availableReplicas对应available
查看滚动更新的状态 kubectl rollout status deploymetnt/nginx-deployment。显示如下
Waiting for rollout to finish: 2 out of 3 new replicas have been updated...
deployment "nginx-deployment" successfully rolled out
kubectl get deployments
# 或者是 kubectl get deploy
查看副本集
kubectl get rs
#查看容器组
kubectl get pods --show-labels
注意:对于部署控制器,要通过selector指定它要控制的容器组,不同的部署控制器或者是守护集控制器不要控制同一个容器组,这会导致混乱,尽管目前kubernetes并不会阻止你这么做。
注意:不要改变Pod-template-hash的值 label这个值。这个值是部署控制器给它所创建或者接管的每一个副本集添加的。 这个标签是的子副本集不会重叠。它由副本集的PodTemplate哈希得到。
更新部署
注意:一个部署的容器组模板(.spec.template)被改变的时候会触发rollout(rollout指启动新的副本集并创建启动新的容器组,停止旧的副本集停止并删除旧的容器组。这是一个新的副本集慢慢增加,旧的副本集慢慢减少的过程。),例如容器镜像改变和标签改变。其他配置项的更新,例如伸缩部署,不会触发rollout。
部署模板中 .spec.strategy指定了更新的策略,默认的策略如下
"strategy": {
"type": "RollingUpdate",
"rollingUpdate": {
"maxUnavailable": "25%",
"maxSurge": "25%"
}
上面解释如下:
- type指定类型为滚动更新
- maxUnavailable:更新过程中,控制不可用容器组的百分比。
- maxSurge:更新过程中,控制新建容器组个数的百分比。
同时有多个更新行为
Rollvoer又叫做多个更新同时进行。
假设你创建了一个部署:5个副本的nginx:1.7.9,但是又立马更新部署到5个副本的nginx:1.9.1,此时只有3个副本的nginx:1.7.9被创建好。在这种情况下,部署会立马杀死这3个nginx:1.7.9,接着开始创建nging:1.9.1.它并不会等待5个副本的nginx:1.7.9创建好之后再去更新到:nginx:1.9.1
标签选择器更新
一般来说不推荐此用法,用这个之前要确保你对所有的概念都十分清楚 详细参考:
回滚部署
有时候,当你想回滚一个部署的时候,例如部署不够稳定,或者是反复崩溃的时候。部署会默认记下所有滚动更新的历史,因此我们可以回滚到到任何时间的版本(阿里云上的历史版本默认保留10个,当然这个是可以设置的,可以通过部署模板的.spec.revisionHistoryLimit设置)
注意:当部署的rollout被触发的时候,部署的版本会被创建。这意味着只有当容器组模板.spec.template中的内容被修改的时候新版本才会被创建,例如你更新了容器组模板的标签或者是镜像。其他的更新,例如伸缩部署,并不会创建部署版本。这意味着当你回滚到更更早版本的时候,只有部署的容器组的模板这一部分会被回滚。
更新镜像
$ kubectl set image deployment/nginx-deployment nginx=nginx:1.91
deployment "nginx-deployment" image updated
查看更新
$ kubectl rollout status deployments nginx-deployment
Waiting for rollout to finish: 2 out of 3 new replicas have been updated...
# 查看副本集
kubectl get rs
# 查看容器组
kubectl get pods
注意:部署控制器会自动中止失败的rollout,停止扩展出新的副本集。这取决于滚动更新的参数设置(maxUnavailable),阿里云上这个参数默认设置成25%,这相当于,更新过程中最多允许有25%的容器组处于不可用状态,一旦达到了这个阈值,更新过程就会停止,这保证了当前服务还有75%的旧容器组还处于可以提供服务的状态,不至于整个服务不可用。
查看部署的版本
$ kubectl rollout history deployment/nginx-deployment
deployments "nginx-deployment"
REVISION CHANGE-CAUSE
1 kubectl create -f docs/user-guide/nginx-deployment.yaml --record
2 kubectl set image deployment/nginx-deployment nginx=nginx:1.9.1
3 kubectl set image deployment/nginx-deployment nginx=nginx:1.91
查看具体的某个版本
$ kubectl rollout history deployment/nginx-deployment --revision=2
deployments "nginx-deployment" revision 2
Labels: app=nginx
pod-template-hash=1159050644
Annotations: kubernetes.io/change-cause=kubectl set image deployment/nginx-deployment nginx=nginx:1.9.1
Containers:
nginx:
Image: nginx:1.9.1
Port: 80/TCP
QoS Tier:
cpu: BestEffort
memory: BestEffort
Environment Variables: <none>
No volumes.
回滚到之前的版本
回滚到上一个版本
$ kubectl rollout undo deployment/nginx-deployment
deployment "nginx-deployment" rolled back
回滚到指定的一个版本
$ kubectl rollout undo deployment/nginx-deployment --to-revision=2
deployment "nginx-deployment" rolled back
详细的rollout命令,请参考kubectl rollout
检查回滚后的部署
kubectl get deployment
kubectl describe deployment
伸缩部署
$ kubectl scale deployment nginx-deployment --replicas=10
deployment "nginx-deployment" scaled
配置容器组自动伸缩,前提是集群有开启了该功能 详情参考:
$ kubectl autoscale deployment nginx-deployment --min=10 --max=15 --cpu-percent=80
deployment "nginx-deployment" autoscaled
停止和恢复部署的更新过程
你可以在触发一个或者多个rollout之前停止一个部署然后恢复它,这使得你可以在停止到恢复之间的这段时间进行多次修改而避免rollout。例如在停止更新过程中可以修改容器组的.spec.template中的内容或者部署模板的其他内容。
$ kubectl get deploy
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
nginx 3 3 3 3 1m
$ kubectl get rs
NAME DESIRED CURRENT READY AGE
nginx-2142116321 3 3 3 1m
停止和恢复部署的更新过程
$ kubectl rollout pause deployment/nginx-deployment
deployment "nginx-deployment" paused
对部署进行修改,不会触发rollout
$ kubectl set image deploy/nginx-deployment nginx=nginx:1.9.1
deployment "nginx-deployment" image updated
确认确实没有触发rollout
$ kubectl rollout history deploy/nginx-deployment
deployments "nginx"
REVISION CHANGE-CAUSE
1 <none>
$ kubectl get rs
NAME DESIRED CURRENT READY AGE
nginx-2142116321 3 3 3 2m
继续对部署做其他修改,这里设置资源使用限制
$ kubectl set resources deployment nginx-deployment -c=nginx --limits=cpu=200m,memory=512Mi
deployment "nginx-deployment" resource requirements updated
在停止命令下达之前的部署的更新会继续完成更新内容,停止命令下达之后的更新不会生效。
恢复rollout
$ kubectl rollout resume deploy/nginx-deployment
deployment "nginx" resumed
$ kubectl get rs -w
NAME DESIRED CURRENT READY AGE
nginx-2142116321 2 2 2 2m
nginx-3926361531 2 2 0 6s
nginx-3926361531 2 2 1 18s
nginx-2142116321 1 2 2 2m
nginx-2142116321 1 2 2 2m
nginx-3926361531 3 2 1 18s
nginx-3926361531 3 2 1 18s
nginx-2142116321 1 1 1 2m
nginx-3926361531 3 3 1 18s
nginx-3926361531 3 3 2 19s
nginx-2142116321 0 1 1 2m
nginx-2142116321 0 1 1 2m
nginx-2142116321 0 0 0 2m
nginx-3926361531 3 3 3 20s
^C
$ kubectl get rs
NAME DESIRED CURRENT READY AGE
nginx-2142116321 0 0 0 2m
nginx-3926361531 3 3 3 28s
注意:在恢复部署之前,你不能回滚停止部署这个操作。
部署的状态
变更中的部署(Progressing Deployment)
创建,伸缩容器组或者容器组(可设置MinReadySeconds)正在变得可用的过程中就属于这个状态 查看部署的状态
kubectl rollout status deploy/deploy-name
成功的部署
- 所有副本集都更新到最新版本
- 所有副本集可用
- 没有旧版本的副本集
失败的部署
可能有下面原因导致
- 计算资源不足
- 准备就绪的探针出错
- 镜像拉取错误
- 权限不足
- 限制范围
- 应用运行时配置错误
可以设置.spec.progressDeadlineSeconds这个状态确定的超时时间。超过这个时间之后,部署的状态就会被确定,并写入到.status中。所以这个status在创建部署的时候无需填写,创建后k8s系统会自填写到模板上。(同样地,k8s对象的UID在创建的时候也无需填写,系统自动分配。)
$ kubectl patch deployment/nginx-deployment -p '{"spec":{"progressDeadlineSeconds":600}}'
deployment "nginx-deployment" patched
详细的失败的信息描述,参考 Failed Deployment
操作失败的部署
和完成的部署一样,失败的部署可以执行任何成功的部署可以执行的操作。
清理策略
我们可以通过设置部署中的.spec.revisionHistoryLimit来指定想保存多少部署中的副本集,其余的副本集会被后端垃圾回收,默认为10.所以不要随便删除副本集列表中的副本集,因为这是作为历史版本为方便回滚部署而存在的。 如果我们设置这个参数为0,那么会清理掉部署所有的历史版本,因此会导致部署无法回滚。
用户案例
金丝雀发布 在初始的部署上,再创建一个部署,两个部署除了原本的应用label键值对一致之外,还要有代表版本的标签键值对来区别金丝雀发布中的不同版本。为了方便运维和沟通在规划前期就应确定好这个label的键以及label的值的取值范围的,这个时候要通过标签指定哪一个是稳定版(一般就是之前运行的版本),哪一个是金丝雀版本。在服务的模板中通过标签选择器指定要接管的容器组。即让两个不同个版本(通常是镜像版本不同)同时在线上运行并接受流量。详情参考managing resources
书写部署
完整的模板参数解释,请查看API Reference
服务发现与负载均衡
服务是kubernetes的一个REST对象,类似容器组,我们可以通过模板来定义一个服务。 服务实现了负载均衡的功能,它作为容器组的前端,容器组作为服务的后端,在服务模板中通过标签选择器决定要接管的容器组,并引入了 port(集群内部可访问的端口),targetPort(容器内部的端口),nodePort(主机端口,端口取值范围:30000-32767)的概念。使得服务之间的访问既可以在集群内部调用亦可在集群外部互相调用。
例子:
{
"kind": "Service",
"apiVersion": "v1",
"metadata": {
"name": "test-grpc",
"namespace": "default",
"selfLink": "/api/v1/namespaces/default/services/test-grpc",
"uid": "8a6555a5-3bc4-11e8-8f30-00163e0ca75d",
"resourceVersion": "2738399",
"creationTimestamp": "2018-04-09T07:06:35Z",
"labels": {
"k8s-app": "session-grpc"
}
},
"spec": {
"ports": [
{
"name": "tcp-50056-50056-nwj6v",
"protocol": "TCP",
"port": 50056,
"targetPort": 50056,
"nodePort": 30016
}
],
"selector": {
"k8s-app": "test-grpc"
},
"clusterIP": "172.21.14.11",
"type": "NodePort",
"sessionAffinity": "None",
"externalTrafficPolicy": "Cluster"
},
"status": {
"loadBalancer": {}
}
}
- 该例子同时提供了集群内部访问的端口port:50056和集群外部访问的端口nodePort:30016,目标端口为targetPort:50056
- 服务名字为test-grpc,命名空间为default,同一个命名空间下的服务之间的互相调用可以直接使用这个test-grpc来调用,完整的调用路径是: http://test-grpc:50056 这里的50056是port,而不是targetPort.而如果是同一个集群的不通命名空间之间的服务调用,服务的域名格式为:
<service-name>.<namespace-name>.svc.cluster.local
完整的服务调用路径应该是:http://test-grpc.default.svc.cluster.local:50056 - 服务的标签是: "k8s-app": "test-grpc",这个一般设置成它的后端容器组的标签,就算不同也不影响,这只是单纯的标签而已,而且目前并没有控制器对服务进行标签匹配。参考DNS for Services and Pods
- spec中指定了port,targetPort,nodePort.注意要暴露nodePort,下面有个type,它的值必须是NodePort,其他可选参数参考srevicespec,有任何不懂的都可以参考API,可以获得全面详细的认知。
- clusterIP:是集群内部给该服务分配的IP(类似于阿里云负载均衡器的IP,但仅限在集群内部可以访问),后端节点就是容器组(类似云阿里云的主机)
- type:可选值:ExternalName, ClusterIP, NodePort, and LoadBalancer.这里解释几个我们常用的,ClusterIP:指定这个参数会分配一个集群内部的IP给这个服务作为负载均衡的端点。端点Endpoints由标签选择器指定或者不指定(不通过标签选择器指定时需要手动创建端点对象)。NodePort是基于ClusterIP的,它会在每一个非主节点上(主节点称之为master,工作节点称之为node)分配一个路由到ClusterIP的端口,此模式相当于可以直接通云主机的IP加上nodePort就可以访问到此服务。"LoadBalancer"是基于NodePort的并且创建集群外部的负载均衡器到clusterIP(若果云厂商支持的话,阿里云是支持的。这个功能很方便,测试中十分实用。当我们在创建部署的时候如果选择了【外部服务】,那么就会创建一个按量付费的公网SLB,可以直接在因特网上访问。) 其他参数含义参考servicespec-v1-core
- sessionAffinity:会话保持
- externalTrafficPolicy:外部流量策略,可选值: Local,Cluster。Local会保留客户端源IP,同时对于type为LoadBalancer和NodePort的服务不会再进行第二跳。如果我们外部的负载均衡器,例如SLB,已经做了负载均衡轮转的策略,这里用Local是合适的。Cluster,会模糊客户端IP,因为某个容器组接受到这个请求之后它并不一定会在本地就处理响应这个请求,而是会通过服务的ClusterIP进行一次负载均衡(引起下一跳到其他节点)。
通过控制面板创建部署的时候,服务选项框上可以选择是否创建服务以及创建内部或者是外部服务,一般集群内部服务选择内部, 对于需要提供给集群外部访问的服务选择外部(但是在阿里云上,这里会创建按量付费的公网SLB,价格比较贵,所以我们对于外部需要被访问到的服务也选择使用内部选项,然后暴露端口到主机上,在手动购买包年包月的SLB,手动添加监听端口和后端节点。)。此时就会自动创建服务,并在[服务与负载均衡]栏目那里可以找到服务的访问地址。
如果你很熟悉服务模板的书写,也可以选择不创建服务,在部署创建好之后再手动创建服务,通过标签选择器选择要接管的容器组以及要暴露的端口。
详情参考: Services
控制面板操作
控制台位置
创建部署
可以通过文本,文件或者配置创建部署,下面通过配置创建。 通过配置创建的功能比较有限,但使用较为简单。
填写应用名称,镜像名称,容器数量,服务类型。对于服务类型,如果无需暴露监听端口,那么无,否则选择内部。对于要暴露到公网的服务,也选择内部服务,后续再通过修改Service的模板将内部服务暴露到公网。命名空间选择默认的即可。
镜像拉取保密字典要选上,选择regcred-vpc,对于每一个kubernetes都要创建私有镜像库的保密字典才能拉到私有镜像仓库的镜像,保密字典生成方式可参考Secrets
填写环境变量。 对于启动命令(command)和运行命令参数(args),可以不填写.不填写将使用Dockerfile里面默认的Cmd(对应K8s的args,这个参数的主要目的是为了提供默认的可启动命令的参数,当然本身也可以附上启动命令)或者是Entrypoint(对应k8s的command,这个参数的主要目的是给出可执行文件,提供程序的入口点,当然也可以附上启动命令的其他参数。) 详情参考:
Kubernetes部分
Define a Command and Arguments for a Container
Docker 部分
注意:Kubernetes中的command,args在对应到Docker分别是entrypoint,cmd
因为现在通过配置模板传入command和args的时候,解析到模板会出问题,它总是把command或者是args解析成一个字符串,而解析成字符串的问题是,当你在可执行文件后附加了多个参数,这个时候启动会报错,因为格式不对。 目前无法解析成:
"command": [
"./myserver",
"-serverName=myserver",
"-pprof=1",
"max_idle_conns_per_host=1000"
],
这种格式。
所以或者你一开始创建的时候就直接使用模板创建,直接指定command,或者可以在创建好之后更新一次部署,把command改成如上格式的内容。 注意:command既然对应于Docker中的Entrypoint,那么它的主要目的也就是提供可执行文件,当然也可以附加上额外参数。而args对应于Docker中的Cmd,它的主要目的就是提供可执行文件的默认的参数(注意不是提供可执行文件,当然如果你提供了也是没问题的,可以支持。) 所以,如果你的应用场景如果不是十分复杂,没有填写args的必要,那么就统一使用command。将启动命令以及附加参数都放在command中。
修改服务模板
切换到服务发现与负载均衡界面
设置.spec.type
对于要暴露到集群外部的服务,可以修改配置
.spec.type设置为:
type:"NodePort"
设置.spce.ports
在.spec.ports数组的元素中添加:
"nodePort":$映射到主机的端口号(取值范围30000-32767)
设置.spec.externalTrafficPolicy
- 对于网关,推送等需要直接暴露到公网的服务,设置externalTrafficPolicy为Local而不是Cluster是为了避免在已经经过SLB负载均衡过一次之后再进行集群内部负载均衡一次。两次负载均衡可能会导致不均衡的后果。当然应该以实测得到的情况为准。
- 使用Cluster会在进行集群内部的一次负载均衡,而且直接访问集群的任何一个工作节点都可以访问到服务,它是通过一个kube-proxy进行负载,将流量转发到正常运行的容器上。
- 使用Local不会在进行集群内部的负载均衡,但是如果该节点上没有运行应用的容器,那么该节点就不能提供服务。而且目前kubernnetes上通过调整部署的副本数时,副本数可以超过工作节点的数目,也就是说,同一工作节点可以创建出两个甚至更多个提供一模一样服务的容器组,到最后表现来也就是一个节点运行多个提供相同服务的容器。
.spec.externalTrafficPolicy设置为
"externalTrafficPolicy": "Local"
对于其他服务,服务之间的调用会使用K8s内部的服务发现,无需使用云厂商的负载均衡。但是为了开发人员便于调试,也通过将端口映射到主机上让这些内部服务暴露到集群外部,接着再将k8s工作节点(node)放到云厂商的内网负载均衡下,建立监听端口,进行流量转发,并在云厂商和公司内部进行DNS解析。
命令使用指南
详情参考: