Kubernetes在1.3版本里发布了beta版的Federation功能。在云计算环境中,服务的作用距离范围从近到远一般可以有:同主机(Host,Node)、跨主机同可用区(Available Zone)、跨可用区同地区(Region)、跨地区同服务商(Cloud Service Provider)、跨云平台。Kubernetes的设计定位是单一集群在同一个地域内,因为同一个地区的网络性能才能满足Kubernetes的调度和计算存储连接要求。而联合集群服务就是为提供跨Region跨服务商Kubernetes集群服务而设计的。
Examples:
+ # Create a new configmap named my-config based on folder bar
+ kubectl create configmap my-config --from-file=path/to/bar
+
+ # Create a new configmap named my-config with specified keys instead of file basenames on disk
+ kubectl create configmap my-config --from-file=key1=/path/to/bar/file1.txt --from-file=key2=/path/to/bar/file2.txt
+
+ # Create a new configmap named my-config with key1=config1 and key2=config2
+ kubectl create configmap my-config --from-literal=key1=config1 --from-literal=key2=config2
+
很可能,通过在一个指定目录下编写文件来创建 Pod,该目录受 Kubelet 所监视。这些 Pod 被称为 静态 Pod。
+不像 DaemonSet,静态 Pod 不受 kubectl 和 其它 Kubernetes API 客户端管理。静态 Pod 不依赖于 apiserver,这使得它们在集群启动的情况下非常有用。
+而且,未来静态 Pod 可能会被废弃掉。
+
Replication Controller
+
DaemonSet 与 Replication Controller 非常类似,它们都能创建 Pod,这些 Pod 都具有不期望被终止的进程(例如,Web 服务器、存储服务器)。
+为无状态的 Service 使用 Replication Controller,像 frontend,实现对副本的数量进行扩缩容、平滑升级,比之于精确控制 Pod 运行在某个主机上要重要得多。需要 Pod 副本总是运行在全部或特定主机上,并需要先于其他 Pod 启动,当这被认为非常重要时,应该使用 Daemon Controller。
$ kubectl get deployments
+NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
+nginx-deployment 3 3 3 3 18s
+
+
我们可以看到Deployment已经创建了3个 replica,所有的 replica 都已经是最新的了(包含最新的pod template),可用的(根据Deployment中的.spec.minReadySeconds声明,处于已就绪状态的pod的最少个数)。执行kubectl get rs和kubectl get pods会显示Replica Set(RS)和Pod已创建。
+
$ kubectl get rs
+NAME DESIRED CURRENT READY AGE
+nginx-deployment-2035384211 3 3 0 18s
+
$ kubectl rollout status deployment/nginx-deployment
+Waiting for rollout to finish: 2 out of 3 new replicas have been updated...
+deployment "nginx-deployment" successfully rolled out
+
+
Rollout 成功后,get Deployment:
+
$ kubectl get deployments
+NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
+nginx-deployment 3 3 3 3 36s
+
$ kubectl describe deployment
+Name: nginx-deployment
+Namespace: default
+CreationTimestamp: Tue, 15 Mar 2016 14:48:04 -0700
+Labels: app=nginx
+Selector: app=nginx
+Replicas: 2 updated | 3 total | 2 available | 2 unavailable
+StrategyType: RollingUpdate
+MinReadySeconds: 0
+RollingUpdateStrategy: 1 max unavailable, 1 max surge
+OldReplicaSets: nginx-deployment-1564180365 (2/2 replicas created)
+NewReplicaSet: nginx-deployment-3066724191 (2/2 replicas created)
+Events:
+ FirstSeen LastSeen Count From SubobjectPath Type Reason Message
+ --------- -------- ----- ---- ------------- -------- ------ -------
+ 1m 1m 1 {deployment-controller } Normal ScalingReplicaSet Scaled up replica set nginx-deployment-2035384211 to 3
+ 22s 22s 1 {deployment-controller } Normal ScalingReplicaSet Scaled up replica set nginx-deployment-1564180365 to 1
+ 22s 22s 1 {deployment-controller } Normal ScalingReplicaSet Scaled down replica set nginx-deployment-2035384211 to 2
+ 22s 22s 1 {deployment-controller } Normal ScalingReplicaSet Scaled up replica set nginx-deployment-1564180365 to 2
+ 21s 21s 1 {deployment-controller } Normal ScalingReplicaSet Scaled down replica set nginx-deployment-2035384211 to 0
+ 21s 21s 1 {deployment-controller } Normal ScalingReplicaSet Scaled up replica set nginx-deployment-1564180365 to 3
+ 13s 13s 1 {deployment-controller } Normal ScalingReplicaSet Scaled up replica set nginx-deployment-3066724191 to 1
+ 13s 13s 1 {deployment-controller } Normal ScalingReplicaSet Scaled down replica set nginx-deployment-1564180365 to 2
+ 13s 13s 1 {deployment-controller } Normal ScalingReplicaSet Scaled up replica set nginx-deployment-3066724191 to 2
+
+
为了修复这个问题,我们需要回退到稳定的 Deployment revision。
+
检查 Deployment 升级的历史记录
+
首先,检查下 Deployment 的 revision:
+
$ kubectl rollout history deployment/nginx-deployment
+deployments "nginx-deployment":
+REVISION CHANGE-CAUSE
+1 kubectl create -f https://kubernetes.io/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 get deployment
+NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
+nginx-deployment 3 3 3 3 30m
+
+$ kubectl describe deployment
+Name: nginx-deployment
+Namespace: default
+CreationTimestamp: Tue, 15 Mar 2016 14:48:04 -0700
+Labels: app=nginx
+Selector: app=nginx
+Replicas: 3 updated | 3 total | 3 available | 0 unavailable
+StrategyType: RollingUpdate
+MinReadySeconds: 0
+RollingUpdateStrategy: 1 max unavailable, 1 max surge
+OldReplicaSets: <none>
+NewReplicaSet: nginx-deployment-1564180365 (3/3 replicas created)
+Events:
+ FirstSeen LastSeen Count From SubobjectPath Type Reason Message
+ --------- -------- ----- ---- ------------- -------- ------ -------
+ 30m 30m 1 {deployment-controller } Normal ScalingReplicaSet Scaled up replica set nginx-deployment-2035384211 to 3
+ 29m 29m 1 {deployment-controller } Normal ScalingReplicaSet Scaled up replica set nginx-deployment-1564180365 to 1
+ 29m 29m 1 {deployment-controller } Normal ScalingReplicaSet Scaled down replica set nginx-deployment-2035384211 to 2
+ 29m 29m 1 {deployment-controller } Normal ScalingReplicaSet Scaled up replica set nginx-deployment-1564180365 to 2
+ 29m 29m 1 {deployment-controller } Normal ScalingReplicaSet Scaled down replica set nginx-deployment-2035384211 to 0
+ 29m 29m 1 {deployment-controller } Normal ScalingReplicaSet Scaled up replica set nginx-deployment-3066724191 to 2
+ 29m 29m 1 {deployment-controller } Normal ScalingReplicaSet Scaled up replica set nginx-deployment-3066724191 to 1
+ 29m 29m 1 {deployment-controller } Normal ScalingReplicaSet Scaled down replica set nginx-deployment-1564180365 to 2
+ 2m 2m 1 {deployment-controller } Normal ScalingReplicaSet Scaled down replica set nginx-deployment-3066724191 to 0
+ 2m 2m 1 {deployment-controller } Normal DeploymentRollback Rolled back deployment "nginx-deployment" to revision 2
+ 29m 2m 2 {deployment-controller } Normal ScalingReplicaSet Scaled up replica set nginx-deployment-1564180365 to 3
+
$ kubectl get deploy
+NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
+nginx 3 3 3 3 1m
+[mkargaki@dhcp129-211 kubernetes]$ kubectl get rs
+NAME DESIRED CURRENT READY AGE
+nginx-2142116321 3 3 3 1m
+
$ kubectl rollout status deploy/nginx
+Waiting for rollout to finish: 2 of 3 updated replicas are available...
+deployment "nginx" successfully rolled out
+$ echo $?
+0
+
$ kubectl rollout status deploy/nginx
+Waiting for rollout to finish: 2 out of 3 new replicas have been updated...
+error: deployment "nginx" exceeded its progress deadline
+$ echo $?
+1
+
操作失败的 Deployment
+
所有对完成的 Deployment 的操作都适用于失败的 Deployment。您可以对它扩/缩容,回退到历史版本,您甚至可以多次暂停它来应用 Deployment pod template。
.spec.revisionHistoryLimit 是一个可选配置项,用来指定可以保留的旧的ReplicaSet数量。该理想值取决于心Deployment的频率和稳定性。如果该值没有设置的话,默认所有旧的Replicaset或会被保留,将资源存储在etcd中,是用kubectl get rs查看输出。每个Deployment的该配置都保存在ReplicaSet中,然而,一旦您删除的旧的RepelicaSet,您的Deployment就无法再回退到那个revison了。
应用的资源使用率通常都有高峰和低谷的时候,如何削峰填谷,提高集群的整体资源利用率,让service中的Pod个数自动调整呢?这就有赖于Horizontal Pod Autoscaling了,顾名思义,使Pod水平自动缩放。这个Object(跟Pod、Deployment一样都是API resource)也是最能体现kubernetes之于传统运维价值的地方,不再需要手动扩容了,终于实现自动化了,还可以自定义指标,没准未来还可以通过人工智能自动进化呢!
+
Horizontal Pod Autoscaling仅适用于Deployment和ReplicationController(ReplicaSet已经被ReplicationController取代),在V1版本中仅支持根据Pod的CPU利用率扩所容,在v1alpha版本中,支持根据内存和用户自定义的metric扩缩容。
+
如果你不想看下面的文章可以直接看下面的示例图,组件交互、组件的配置、命令示例,都画在图上了。
+
Horizontal Pod Autoscaling由API server和controller共同实现。
在 Kubernetes 1.6中删除了对这些注释的支持,有利于autoscaling/v2alpha1 API。 虽然旧的收集自定义 metric 的旧方法仍然可用,但是这些 metric 将不可供 Horizontal Pod Autoscaler 使用,并且用于指定要缩放的自定义 metric 的以前的注释也不在受 Horizontal Pod Autoscaler 认可。
+
Kubernetes 1.6增加了在 Horizontal Pod Autoscale r中使用自定义 metric 的支持。
+
您可以为autoscaling/v2alpha1 API 中使用的 Horizontal Pod Autoscaler 添加自定义 metric 。
+
Kubernetes 然后查询新的自定义 metric API 来获取相应自定义 metric 的值。
+
前提条件
+
为了在 Horizontal Pod Autoscaler 中使用自定义 metric,您必须在您集群的 controller manager 中将 --horizontal-pod-autoscaler-use-rest-clients 标志设置为 true。然后,您必须通过将 controller manager 的目标 API server 设置为 API server aggregator(使用--apiserver标志),配置您的 controller manager 通过 API server aggregator 与API server 通信。 Resource metric API和自定义 metric API 也必须向 API server aggregator 注册,并且必须由集群上运行的 API server 提供。
$ kubectl get pods -l environment=production,tier=frontend
+$ kubectl get pods -l'environment in (production),tier in (frontend)'
+$ kubectl get pods -l'environment in (production, qa)'
+$ kubectl get pods -l'environment,environment notin (frontend)'
+
The use of collective APIs as the primary user-facing primitive is relatively common among cluster scheduling systems, including Borg, Marathon, Aurora, and Tupperware.
+
Pod is exposed as a primitive in order to facilitate:
+
+
scheduler and controller pluggability
+
support for pod-level operations without the need to "proxy" them via controller APIs
+
decoupling of pod lifetime from controller lifetime, such as for bootstrapping
+
decoupling of controllers and services — the endpoint controller just watches pods
+
clean composition of Kubelet-level functionality with cluster-level functionality — Kubelet is effectively the "pod controller"
+
high-availability applications, which will expect pods to be replaced in advance of their termination and certainly in advance of deletion, such as in the case of planned evictions, image prefetching, or live pod migration #3949
执行 kubectl describe pod FooPodName,可以看到为什么pod处于pending状态。输出的event列表中将显示:
+Error validating pod "FooPodName"."FooPodNamespace" from api, ignoring: spec.containers[0].securityContext.privileged: forbidden '<*>(0xc2089d3248)true'
apiVersion: extensions/v1beta1
+kind: ReplicaSet
+metadata:
+ name: frontend
+ # these labels can be applied automatically
+ # from the labels in the pod template if not set
+ # labels:
+ # app: guestbook
+ # tier: frontend
+spec:
+ # this replicas value is default
+ # modify it according to your case
+ replicas:3
+ # selector can be applied automatically
+ # from the labels in the pod template if not set,
+ # but we are specifying the selector here to
+ # demonstrate its usage.
+ selector:
+ matchLabels:
+ tier: frontend
+ matchExpressions:
+ - {key: tier, operator: In, values: [frontend]}
+ template:
+ metadata:
+ labels:
+ app: guestbook
+ tier: frontend
+ spec:
+ containers:
+ - name: php-redis
+ image: gcr.io/google_samples/gb-frontend:v3
+ resources:
+ requests:
+ cpu:100m
+ memory:100Mi
+ env:
+ - name: GET_HOSTS_FROM
+ value: dns
+ # If your cluster config does not include a dns service, then to
+ # instead access environment variables to find service host
+ # info, comment out the 'value: dns' line above, and uncomment the
+ # line below.
+ # value: env
+ ports:
+ - containerPort:80
+
Kubernetes Pod 是有生命周期的,它们可以被创建,也可以被销毁,然而一旦被销毁生命就永远结束。
+通过 ReplicationController 能够动态地创建和销毁 Pod(例如,需要进行扩缩容,或者执行 滚动升级)。
+每个 Pod 都会获取它自己的 IP 地址,即使这些 IP 地址不总是稳定可依赖的。
+这会导致一个问题:在 Kubernetes 集群中,如果一组 Pod(称为 backend)为其它 Pod (称为 frontend)提供服务,那么那些 frontend 该如何发现,并连接到这组 Pod 中的哪些 backend 呢?
+
关于 Service
+
Kubernetes Service 定义了这样一种抽象:一个 Pod 的逻辑分组,一种可以访问它们的策略 —— 通常称为微服务。
+这一组 Pod 能够被 Service 访问到,通常是通过 Label Selector(查看下面了解,为什么可能需要没有 selector 的 Service)实现的。
上述配置将创建一个名称为 “my-service” 的 Service 对象,它会将请求代理到使用 TCP 端口 9376,并且具有标签 "app=MyApp" 的 Pod 上。
+这个 Service 将被指派一个 IP 地址(通常称为 “Cluster IP”),它会被服务的代理使用(见下面)。
+该 Service 的 selector 将会持续评估,处理结果将被 POST 到一个名称为 “my-service” 的 Endpoints 对象上。
+
需要注意的是, Service 能够将一个接收端口映射到任意的 targetPort。
+默认情况下,targetPort 将被设置为与 port 字段相同的值。
+可能更有趣的是,targetPort 可以是一个字符串,引用了 backend Pod 的一个端口的名称。
+但是,实际指派给该端口名称的端口号,在每个 backend Pod 中可能并不相同。
+对于部署和设计 Service ,这种方式会提供更大的灵活性。
+例如,可以在 backend 软件下一个版本中,修改 Pod 暴露的端口,并不会中断客户端的调用。
在 Service 创建的请求中,可以通过设置 spec.clusterIP 字段来指定自己的集群 IP 地址。
+比如,希望替换一个已经已存在的 DNS 条目,或者遗留系统已经配置了一个固定的 IP 且很难重新配置。
+用户选择的 IP 地址必须合法,并且这个 IP 地址在 service-cluster-ip-range CIDR 范围内,这对 API Server 来说是通过一个标识来指定的。
+如果 IP 地址不合法,API Server 会返回 HTTP 状态码 422,表示值不合法。
第二个 annotation 指定了 Pod 使用的协议。
+对于 HTTPS 和 SSL,ELB 将期望该 Pod 基于加密的连接来认证自身。
+
HTTP 和 HTTPS 将选择7层代理:ELB 将中断与用户的连接,当转发请求时,会解析 Header 信息并添加上用户的 IP 地址(Pod 将只能在连接的另一端看到该 IP 地址)。
+
TCP 和 SSL 将选择4层代理:ELB 将转发流量,并不修改 Header 信息。
+
外部 IP
+
如果外部的 IP 路由到集群中一个或多个 Node 上,Kubernetes Service 会被暴露给这些 externalIPs。
+通过外部 IP(作为目的 IP 地址)进入到集群,打到 Service 的端口上的流量,将会被路由到 Service 的 Endpoint 上。
+externalIPs 不会被 Kubernetes 管理,它属于集群管理员的职责范畴。
+
根据 Service 的规定,externalIPs 可以同任意的 ServiceType 来一起指定。
+在下面的例子中,my-service 可以在 80.11.12.10:80(外部 IP:端口)上被客户端访问。
为了使用户能够为他们的 Service 选择一个端口号,我们必须确保不能有2个 Service 发生冲突。
+我们可以通过为每个 Service 分配它们自己的 IP 地址来实现。
+
为了保证每个 Service 被分配到一个唯一的 IP,需要一个内部的分配器能够原子地更新 etcd 中的一个全局分配映射表,这个更新操作要先于创建每一个 Service。
+为了使 Service 能够获取到 IP,这个映射表对象必须在注册中心存在,否则创建 Service 将会失败,指示一个 IP 不能被分配。
+一个后台 Controller 的职责是创建映射表(从 Kubernetes 的旧版本迁移过来,旧版本中是通过在内存中加锁的方式实现),并检查由于管理员干预和清除任意 IP 造成的不合理分配,这些 IP 被分配了但当前没有 Service 使用它们。
+
IP 和 VIP
+
不像 Pod 的 IP 地址,它实际路由到一个固定的目的地,Service 的 IP 实际上不能通过单个主机来进行应答。
+相反,我们使用 iptables(Linux 中的数据包处理逻辑)来定义一个虚拟IP地址(VIP),它可以根据需要透明地进行重定向。
+当客户端连接到 VIP 时,它们的流量会自动地传输到一个合适的 Endpoint。
+环境变量和 DNS,实际上会根据 Service 的 VIP 和端口来进行填充。
+
Userspace
+
作为一个例子,考虑前面提到的图片处理应用程序。
+当创建 backend Service 时,Kubernetes master 会给它指派一个虚拟 IP 地址,比如 10.0.0.1。
+假设 Service 的端口是 1234,该 Service 会被集群中所有的 kube-proxy 实例观察到。
+当代理看到一个新的 Service, 它会打开一个新的端口,建立一个从该 VIP 重定向到新端口的 iptables,并开始接收请求连接。
# This role allows to read pods in the namespace "default"
+kind: Role
+apiVersion: rbac.authorization.k8s.io/v1alpha1
+metadata:
+ namespace: default
+ name: pod-reader
+rules:
+ - apiGroups: [""] # The API group "" indicates the core API Group.
+ resources: ["pods"]
+ verbs: ["get", "watch", "list"]
+ nonResourceURLs: []
+---
+# This role binding allows "default" to read pods in the namespace "default"
+kind: RoleBinding
+apiVersion: rbac.authorization.k8s.io/v1alpha1
+metadata:
+ name: read-pods
+ namespace: default
+subjects:
+ - kind: ServiceAccount # May be "User", "Group" or "ServiceAccount"
+ name: default
+roleRef:
+ kind: Role
+ name: pod-reader
+ apiGroup: rbac.authorization.k8s.io
+
如果Pod配置了emptyDir类型Volume, Pod 被分配到Node上时候,会创建emptyDir,只要Pod运行在Node上,emptyDir都会存在(容器挂掉不会导致emptyDir丢失数据),但是如果Pod从Node上被删除(Pod被删除,或者Pod发生迁移),emptyDir也会被删除,并且永久丢失。