如果你浏览过 Kubernetes 101, 你能够学习到kubectl,pods,卷,多容器的概念。 在 Kubernetes 201中,我们将学习201剩下的部分, 包含一些Kubernetes稍微高级的主题, 讨论关于应用的生产环境化, 部署以及扩容。
为了让kubectl操作的示例可以正常工作,确保本地存在示例的目录, 从发布版 或者 源代码获取。
已经学习了Pods以及如何创建他们, 你可能会在紧急的情况下创建许多,许多pods。去做吧!但是最终你需要一个系统来通过组管理这些pods。为了实现这个功能,在Kubernetes系统中使用标签。标签是一个键值对,在Kubernetes中会标记到每一个对象上。标签选择器将RESTful list
请求传递给 apiserver 来获取和标签选择器匹配的对象列表。
增加一个标签,在 pod 定义文件中的元数据下增加一个标签部分:
labels:
app: nginx
例如,下面是一个带标签的 nginx pod 定义 (pod-nginx-with-label.yaml):
pod-nginx-with-label.yaml |
---|
|
创建一个标签过的 pod (pod-nginx-with-label.yaml):
kubectl create -f docs/user-guide/walkthrough/pod-nginx-with-label.yaml
列出所有标签app=nginx
的 pod:
kubectl get pods -l app=nginx
更多信息,参考 Labels。 其他两个 Kubernetes 构建部分:Deployment 和 Service,使用标签作为其核心概念。
现在你知道如何做到完美,多容器,给 Pod 标记标签 并且想用他们构建应用程序,也许你刚刚建立以一大堆 pod,但是如果你这样做,会出现很多运维问题。例如:如何扩容 pod? 如何滚动更新?
这些答案,还有更多使用Deployment来管理和维护运行中的 Pod。
Deployment 对象创建一个模板来定义 pod 并且指定副本的数量。 Deployment 使用标签选择器来管理 pod,并且会创建指定数量的 pod。Deployments 还用于管理运行中 pod 安全的滚动更新。
下面两个 nginx pod 实例的 Deployment(部署) :
deployment.yaml |
---|
|
创建一个 nginx Deployment:
点击上面的链接并下载 deployment.yaml
到本地文件夹中。
kubectl create -f ./deployment.yaml
列出所有 Deployment:
kubectl get deployment
列出这个 Deployment 创建的 Pod 列表:
kubectl get pods -l app=nginx
通过改变deployment来让 nginx 容器从1.7.9升级到1.8,并调用apply
,所有的配置如下:
deployment-update.yaml |
---|
|
下载 ./deployment-update.yaml 到你的文件夹中。
kubectl apply -f ./deployment-update.yaml
查看 Deployment 创建的 Pod 的新名字,并且删掉旧的 pod。
kubectl get pods -l app=nginx
通过名字删除 Deployment:
kubectl delete deployment nginx-deployment
更多信息,例如如何回滚 Deployment 请看 Deployment.
一旦你拥有一个 pod 的副本集合,你需要在能够在应用程序层之间提供连接的抽象。 例如,如果你已经有一个Deployment来管理后端任务,当你需要重新扩展你的后端应用的时候,你不需要重新配置你的前端应用。 同样,如果后端的 pod 被调度(或者重新调度)到不同的机器上,你也不需要重新配置前端应用。 在Kubernetes中,对服务的抽象能够达到这个目标。 一个服务会提供一个指向 pod 集合(通过标签选择)的IP地址。如果支持的话,它同时能够提供负载均衡功能。
例如,这里有一个在之前例子中通过 nginx 副本控制器创建的 pod 之间提供负载均衡功能的服务 (service.yaml):
service.yaml |
---|
|
创建一个nginx服务 (service.yaml):
kubectl create -f docs/user-guide/walkthrough/service.yaml
列出所有的服务
kubectl get services
对于大多数供应商,服务的IP地址外部无法访问。测试服务可以访问的最简单的方式为创建一个busybox pod在上面远程执行命令。详细内容查看命令执行文档 。
一旦提供的服务IP地址可以访问,你便可以通过 http 来访问:
$ export SERVICE_IP=$(kubectl get service nginx-service -o go-template='{{.spec.clusterIP}}')
$ export SERVICE_PORT=$(kubectl get service nginx-service -o go-template='{{(index .spec.ports 0).port}}')
$ echo "$SERVICE_IP:$SERVICE_PORT"
$ kubectl run busybox --generator=run-pod/v1 --image=busybox --restart=Never --tty -i --env "SERVICE_IP=$SERVICE_IP,SERVICE_PORT=$SERVICE_PORT"
u@busybox$ wget -qO- http://$SERVICE_IP:$SERVICE_PORT # Run in the busybox container
u@busybox$ exit # Exit the busybox container
$ kubectl delete pod busybox # Clean up the pod we created with "kubectl run"
通过名称删除服务:
kubectl delete service nginx-service
一旦服务被创建,就会分配一个唯一的IP地址。这个地址同服务的生命周期绑定,服务存活期间不会发生变化。通过配置Pods来和服务通信,并且能够同一些自动被负载均衡的pods进行通信,这些服务中的pod是由标签选择器识别出来的集合中的一员。
更多信息,查看 Services。
我写的代码,永远不会崩溃,对不对?不幸的是,Kubernetes问题列表中另有说明…
一个更好的方法是使用管理系统来进行定期的应用程序健康检查和修复工作,而不是尝试编写无bug的代码。你的应用程序之外本身有一套监控系统负责监控和修复工作。很重要的一点是这个系统必须放置在应用程序外部,应用程序一旦失败以及健康检查代理是应用程序的一部分,这个代理也会失败并且你永远不会知道。在Kubernetes中, 这个健康检查监控代理是Kubelet。
最简单形式的健康检查是进程级别的健康检查。Kubelet不停的问Docker进程容器进程是不是还在运行,如果不在运行,容器进程就会被重启。 至今为止,在你运行的全部Kubernetes示例中,这种健康检查已经开启。所有在Kubernetes中运行的单个容器都存在这种机制。
然而,多数情况下底层健康检查是不够的,例如,考虑下面的代码:
lockOne := sync.Mutex{}
lockTwo := sync.Mutex{}
go func() {
lockOne.Lock();
lockTwo.Lock();
...
}()
lockTwo.Lock();
lockOne.Lock();
这是计算机科学中典型的“Deadlock”问题。 从Docker的角度看,你的应用仍然在进行操作并且进程仍然在运行,但是从应用程序角度来看,你的代码锁死了,再也会不正确响应了。
为了解决这个问题,Kubernetes支持用户自己实现应用程序健康检查。这些检查通过Kubelet来确保应用程序按照 你 定义的“正确方式”来操作。
目前,有三种应用程序健康检查机制你可以选择:
所有情况下,如果Kubelet一旦发现失败,容器会被重启。
可以在容器配置文件的livenessProbe
部分配置你的容器的健康检查功能。你也可以指定initialDelaySeconds
参数,这个参数指的是从容器启动到进行健康检查的宽松期。让你的容器有足够的时间进行任何初始化工作。
这里有一个HTTP健康检查的pod配置示例 (pod-with-http-healthcheck.yaml):
pod-with-http-healthcheck.yaml |
---|
|
更多关于健康检查信息,参考容器探针.
一个完整的应用程序,查看guestbook 示例。