大多数人在生产环境中运行Docker,是把它作为构建和移动部署配置的一种方式。然而,他们的部署模型要么非常整体化,要么有几个大的服务模块组成。使用真实的容器化微服务最大的障碍在于,很多人不太清楚如何管理和协调容器大规模负载。今天我们将探讨如何基于微服务部署来构建Kubernetes。作为google 长期经营的Borg项目的开源的继承者,Kubernetes有将近10年的运行大规模负载的历史了。虽然也存在一些缺点,但Kubernetes是现今最成熟的容器编排系统之一。
启动Kubernetes环境
在Kubernetes官方文档中可以找到如何在不同环境下创建Kubernetes集群,本文中我主要讲解使用Rancher容器管理平台来部署Kubernetes。首先设置Rancher server,选择环境/默认>环境管理>添加环境。从容器编排选项中选择并创建环境。然后选择基础设施(Infrastructure)>主机(Hosts) >添加主机(Add Host),且为Kubernetes创立几个节点以便运行。
注意:为了运行Rancher 代理容器,我们建议至少添加3台主机。当主机创建成功,你将会看到以下屏幕内容,几分钟内集群创建成功并准备就绪。
使用Rancher来运行Kubernetes有很多优势。大多数情况下能使用户和IT团队部署和管理工作更加方便。Rancher自动在Kubernetes后端实现etcd 的HA,并且将所需要的服务部署到此环境下的任何主机中。在设置访问控制,可以轻易连接到现有的LDAP和AD基础构架。Rancher还可以自动实现容器联网以及为Kubernetes提供负载均衡服务。通过使用Rancher,你将会在几分钟内有拥有Kubernetes的HA实现。
命名空间
现在我们的集群已经运行了,让我们进入并查看一些基本的Kubernetes资源吧。你可以访问Kubernetes集群也可以直接通过kubectl CLI访问,或者通过Rancher UI 访问。Rancher的访问管理图层控制可以访问集群,所以你需要在访问CLI前从Rancher UI那里生成API密匙。
我们来看下第一个Kubernetes资源命名空间,在给定的命名空间中,所有资源名称必须有唯一性。此外,标签是用来连接划定到单个命名空间的资源。这就是为什么同一个Kubernetes集群上可以用命名空间来隔离环境。例如,你想为应用程序创建Alpha, Beta和生产环境,以便可以测试最新的更改且不会影响到真正的用户。最后创建命名空间,复制下面的文本到namespace.yaml文件,并且运行kubectl -f namespace.yaml
命令,来创建一个beta命名空间。
kind: Namespace
apiVersion: v1
metadata:
name: beta
labels:
name: beta
当然你还可以使用顶部的命名空间菜单栏从Rancher UI上创建、查看和选择命名空间。
你可以使用下面的命令,用kubectl来为CLI交互设置命名空间:
$ kubectl config set-context Kubernetes --namespace=beta.
为了验证目前context是否已经被设置好,你可以使用config view命令,验证一下输出的命名空间是否满足你的期望。
$ kubectl config view | grep namespace command
namespace: beta
Pods
现在我们已经定义好了命名空间,接下来开始创建资源。首先我们要看的资源是Pod。一组一个或者多个容器的Kubernetes称为pod,容器在pod 里按组来部署、启动、停止、和复制。在给定的每个主机种类里,只能有一个Pod,所有pod里的容器只能在同一个主机上运行,pods可以共享网络命名空间,通过本地主机域来连接。Pods也是基本的扩展单元,不能跨越主机,因此理想状况是使它们尽可能接近单个工作负载。这将消除pod在扩展或缩小时产生的副作用,以及确保我们创建pods不太耗资源而影响到主机。
我们来给名为mywebservice的pod定义,在规范命名web-1-10中它有一个容器并使用nginx容器镜像,然后把端口为80下的文本添加至pod.yaml文档中。
apiVersion: v1
kind: Pod
metadata:
name: mywebservice
spec:
containers:
- name: web-1-10
image: nginx:1.10
ports:
- containerPort: 80
使用kubetl create命令创建pod,如果您使用set-context command设置了您的命名空间,pods将会在指定命名空间中被创立。在通过运行pods命令去验证pod状态。完成以后,我们可以通过运行kubetl delete命令删除pod。
$ kubectl create -f ./pod.yaml
pod "mywebservice" created
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
mywebservice 1/1 Running 0 37s
$ kubectl delete -f pod.yaml
pod "mywebservice" deleted
在Rancher UI 中查看pod,通过顶端的菜单栏选择Kubernetes > Pods。
Replica Sets
Replica Sets,顾名思义,它定义了每个pod副本运行有多少。Replica Sets还能监控并保障所需要pods数量正在运行,并将那些停止的pods替换掉。需要注意的一点是,Replica Sets是Replication Controllers的替代者,然而,在大部分案例中将不能直接使用Replica Sets设置,而是要使用Deployments。Deployments包装了Replica Sets,在应用程序中设置并添加回滚更新升级功能。
部署
部署是一个用于管理你的应用程序回滚及更新的声明机制。基于这点,我们用上述对pod 的定义来定义我们的第一次部署。唯一的区别是,我们采用name parameter作为我们容器的名称,这个名称将会被部署自动收集。下面的文本显示我们用于部署的配置。你可以将它复制到deployment.yaml的文档中。
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: mywebservice-deployment
spec:
replicas: 2 # We want two pods for this deployment
template:
metadata:
labels:
app: mywebservice
spec:
containers:
- name: web-1-10
image: nginx:1.10
ports:
- containerPort: 80
用kubectl create命令启动你的部署,然后验证你的部署是否使用get deployments命令而成功了。
$ kubectl create -f ./deployment.yaml
deployment "mywebservice-deployment" create
$ kubectl get deployments
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
mywebservice-deployment 2 2 2 2 7m
你可以使用describe deployment命令来显示deployment的细节。在describe命令下,其中一个有用的输出项目是一组事件。由describe命令得出的输出,请见以下经删减的例子。目前你的部署应显示以下信息:Scaled up replica set ... to 2
。
$ kubectl describe deployment mywebservice
Name: mywebservice-deployment
Namespace: beta
CreationTimestamp: Sat, 13 Aug 2016 06:26:44 -0400
Labels: app=mywebservice
.....
..... Scaled up replica set mywebservice-deployment-3208086093 to 2
扩展部署
你可以及早的更新deployment.yaml文档,用replicas:3替换replicas:2,来修改部署的规模,然后如下图展示:运行apply命令。如果你再次运行describe deployment 命令,将会第二次看到这个信息:Scaled up replica set mywebservice-deployment-3208086093 to 3
。
$ kubectl apply -f deployment.yaml
deployment "mywebservice-deployment" configured
更新部署
你可以靠改变镜像版本来使用apply命令更新你的应用程序。先将镜像nginx:1.10 替换成镜像nginx:1.11,运行kubectl apply命令来修改deployment.yaml 文档。如果你再次运行了describe deployment命令,你会看到如下信息。你可以看出来新的deployment (2303032576)是如何一步步进行扩展的,也可以看到旧的deployment (3208086093)如何缩小的。虽然围绕在deployment的pod总数保持不变,但pods正逐渐从旧的deployment向新的deployment移动,这使得我们不中断服务的情况下运行负载deployment。
Scaled up replica set mywebservice-deployment-2303032576 to 1
Scaled down replica set mywebservice-deployment-3208086093 to 2
Scaled up replica set mywebservice-deployment-2303032576 to 2
Scaled down replica set mywebservice-deployment-3208086093 to 1
Scaled up replica set mywebservice-deployment-2303032576 to 3
Scaled down replica set mywebservice-deployment-3208086093 to 0
如果在部署过程中或之后你意识到出现错误或者已经出现问题,可以使用rollout命令来取消之前的部署,这将执行反向操作,将负载移动至之前版本的容器。
$ kubectl rollout undo deployment/mywebservice-deployment
deployment "mywebservice-deployment" rolled back
Health check
利用部署,我们已经了解如何扩展我们的service,以及如何对他们进行部署。然而,当在生产环境中运行服务的时候,其中实时监控或更换服务实例也是非常重要的。Kubernetes提供Health check来解决问题。你可以在规定部分添加livenessProbe配置,来更新deployment.yaml文档。有三种liveness probe可供选择:http、tcp和container exec。前两者检查Kubernetes是否能使http或者tcp连接至指定端口。container exec probe可用来运行容器里的指定命令,并维护容器里的停止响应代码。如下所示的代码片段中,我们使用http probe发送Root URL,使用 GET请求到端口80。
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: mywebservice-deployment
spec:
replicas: 3
template:
metadata:
labels:
app: mywebservice
spec:
containers:
- name: web-1-11
image: nginx:1.11
ports:
- containerPort: 80
livenessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 30
timeoutSeconds: 1
如果你用额外的health check重新创建你的部署,并且运行describe deployment的话,你将会看到Kubernetes现在会辨认出有3个replicas是不能使用的。如果你在初始延迟30秒后再次运行deployment,你会发现replicas现在标记为可用。在Kubernetes 开始路由拥堵前给你的应用程序启动时间,这是为了确保你的容器是健康的。
$ kubectl create -f deployment.yaml
deployment "mywebservice-deployment" created
$ kubectl describe deployment mywebservice
...
Replicas: 3 updated | 3 total | 0 available | 3 unavailable
服务
既然现在我们拥有了在负载情况下可更新可扩展并且被监控着了的部署,现在是时候将这些服务展现给真实用户了。拷贝以下内容至service.yaml的文档中。你的集群中的每个节点暴露的端口都可使用Kube Proxy将路由堵塞转移至replicas。
apiVersion: v1
kind: Service
metadata:
name: mywebservice
labels:
run: mywebservice
spec:
type: NodePort
ports:
- port: 80
protocol: TCP
name: http
selector:
app: mywebservice
通过service.yaml文档,我们创建一个create命令服务,然后我们可以使用describe service 命令查找Node Port。例如,在我们服务中可以使用任何 Kubernetes/Rancher 代理节点(agent nodes)访问端口31673的应用程序。如果节点规模变大或者缩小,或变得不健康甚至重新启动,Kubernetes将自动将流量路由到可用节点。
$ kubectl create -f service.yaml
service "mywebservice" created
$ kubectl describe service mywebservice | grep NodePort
NodePort: http 31673/TCP
这篇文章研究了命名空间、pods、deployments和Services等一些基本的Kubernetes资源,还有如何手动扩展或缩小应用程序的规模,以及如何执行应用程序的回滚更新。最后为了从外部展示我们的应用程序,我们看了配置服务。在后续文章中,我们将关注如何协调使用这些资源并编排一个更实际的部署。我们将更细致地探讨如何设置SSL / TLS终端、多服务部署、服务发现、及应用要如何应对失败场景等。
点击这里报名参加11月6日成都「Docker & CI/CD技术沙龙」