容器的生态正在爆发!不仅仅应用层在快速变化,还有用于管理应用程序的平台:Kubernetes,也在快速变化。这就为Ops团队带来了一个必须要解决的难题。IT团队如何才能保证一款应用程序能够在各种不同版本的Kubernetes上都能良好运行呢?
PX-Motion演示:如何跨不同版本Kubernetes,为有状态的工作负载做蓝绿部署
蓝-绿部署是一种专门用于解决这一问题的技术,并能够降低生产环境部署的过程中的停机或错误风险。在蓝绿部署场景下,用户需要构建两个完全相同的生产环境(分别称为蓝与绿),这两个环境之间仅在需要部署的新的变更方面存在差异。每一次仅激活一个环境,两个环境之间的数据传输也是部署过程的一部分。该技术对于不含任何数据的无状态应用非常有效,但对于数据库这类有状态应用则存在一定的困难,因为用户不得不保留两份生产数据副本。这种情况下可能会需要使用Postgres、MySQL以及其他数据库备份和恢复脚本,或定制化操作手册或自动脚本等将数据从一个数据源人工移动到另一个数据源,这个过程将会非常复杂并且会耗费大量的时间。
Portworx采用PX-Motion解决了有状态应用程序的蓝绿部署过程中的数据管理问题。PX-Motion使IT团队能够很方便地在各种环境之间进行数据和应用配置的迁移,极大地简化了有状态应用的蓝绿部署。
本篇博文将对PX-Motion的功能与能力进行探讨。具体地说,笔者将展示如何对两个不同版本的Kubernetes上运行的有状态LAMP堆栈进行蓝绿部署。
总结来说,我们会:
1. 将两个Kubernetes集群(分别称为来源集群和目标集群)配对,从而使数据、配置和Pods能够这两个集群之间进行转移,这是蓝绿部署的一部分。
2. 使用Kubernetes将一个LAMP堆栈部署到来源集群上,并验证应用程序能够运行。
3. 使用PX-Motion可以将Kubernetes的部署、加密文件、副本集、服务、持久卷、持久卷连接以及数据等,从来源集群迁移到目标集群上进行测试和验证。在迁移完成之后,所有的Pods都能够在来源集群上继续运行。现在我们已经有了两个集群在运行,分别是蓝色和绿色。
4. 使用Kubernetes验证我们的应用以及自身数据是否正在目标集群上正常运行。
5. 在新集群上的部署验证完成之后,我们就可以更新我们的负载平衡设置,从而使所有的流量指向新集群。此时蓝绿部署就完成了。
我们开始吧!
安装PX-Motion
前提条件
如果你正在尝试PX-Migration,请确认已经满足所有的前提条件(https://docs.portworx.com/cloud-references/migration/migration-stork/#overview)。
配对Kubernetes集群为数据迁移做准备
从来源集群(Kubernetes 1.10.3)向目标集群(Kubernetes 1.12.0)进行工作载荷迁移之前,我们需要将这两个集群配对起来。配对的概念相当于将手机和蓝牙播放器进行配对,使两种不同的设备结合起来工作。
集群配对首先要做的是对目标集群进行配置。首先,建立对于pxctl (“pixie-cuttle”)的访问,即Portworx CLI。下面将介绍如何在可被kubectl访问的工作站上使用pxctl。
代码语言:javascript复制$ kubectl config use-context <destination-cluster>
代码语言:javascript复制$ PX_POD_DEST_CLUSTER=$(kubectl get pods --context
<DESTINATION_CLUSTER_CONTEXT> -l name=portworx -n kube-system
-o jsonpath='{.items[0].metadata.name}')
代码语言:javascript复制$ alias pxctl_dst="kubectl exec $PX_POD_DEST_CLUSTER
--context <DESTINATION_CLUSTER_CONTEXT>
-n kube-system /opt/pwx/bin/pxctl"
下一步,对目标集群对象存储进行设置,使其准备好与来源集群进行配对。我们需要在目标集群上设置一个对象存储端点,作为数据在迁移过程中进行分级的位置。
代码语言:javascript复制$ pxctl_dst -- volume create --size 100 objectstore
$ pxctl_dst -- objectstore create -v objectstore
$ pxctl_dst -- cluster token show
Token is <UUID>
下一步,创建一个集群配对YAML配置文档,从而对应到来源Kubernetes集群上。这个clusterpair.yaml(https://docs.portworx.com/cloud-references/migration/migration-stork/#overview)文档将包含如何与目标集群调度程序和Portworx存储进行验证的信息。运行如下命令并编辑YAML文档即可建立配对:
代码语言:javascript复制$ storkctl generate clusterpair --context <destination-cluster> > clusterpair.yaml
1. 说明:你可以用你自己的名称替换“metadata.name”。
2. 说明:在如下示例中,options.token可以使用通过上述“cluster tokenshow”命令生成的令牌。
3. 说明:在如下示例中,对于options.ip,将需要负载均衡器或Portworx节点的IP或者DNS,这样我们才能够访问9001和9010端口。
下一步,使用kubectl,将这个集群配对应用到来源集群上。
代码语言:javascript复制$ kubectl config use-context <source-cluster>
代码语言:javascript复制$ kubectl create -f clusterpair.yaml
在这种架构下,集群配对通过互联网(VPC至VPC)进行连接。这就需要确保我们的目标存储能够良好地与来源集群连接。 请参照如下说明。(https://docs.portworx.com/cloud-references/migration/)
1. 说明:这些步骤均是暂用措施,后续新版本的发布后将由自动化过程取代。
2. 说明: 云到云、本地环境到云、云到本地环境,都需要类似的步骤。
如果所有步骤均操作成功,则请使用storkctl列出集群配对,程序将显示存储和调度程序的Ready状态。如果显示Error,则请使用kubectl describe clusterpair,以获取更多信息。
代码语言:javascript复制$ storkctl get clusterpair
NAME STORAGE-STATUS SCHEDULER-STATUS CREATED
green Ready Ready 19 Nov 18 11:43 EST
代码语言:javascript复制$ kubectl describe clusterpair new-cluster | grep paired
Normal Ready 2m stork Storage successfully paired
Normal Ready 2m stork Scheduler successfully paired
pxctl也可以用于列出集群配对。
代码语言:javascript复制$ pxctl_src cluster pair list
CLUSTER-ID NAME ENDPOINT CREDENTIAL-ID
c604c669 px-cluster-testing http://portworx-api.com:9001 a821b2e2-788f
我们的集群现在已经配对成功了。
在Kubernetes 1.12.0上测试工作负载
目前Kubernetes 1.10.3来源集群已经和1.12.0目标集群完成了配对,我们可以将运行的工作负载、配置以及数据从一个集群迁移到另一个集群上,来测试目标集群1.12.0Kubernetes上的应用程序是否能够正常运行。在迁移过程中及完成后,所有的Pods都将继续在来源集群上运行。我们现在有了两个集群,即蓝色和绿色,只在其运行的Kubernetes版本上存在差异。
代码语言:javascript复制$ kubectl config use-context <1.10.3 source cluster context>
如果想要检查当前使用的Kubernetes版本,请运行kubectl version命令。这个命令能够输出当前的客户端和服务器版本。如下所示,服务器版本为1.10.3。
代码语言:javascript复制$ kubectl version --short | awk -Fv '/Server Version: / {print "Kubernetes Version: " $3}'
Kubernetes Version: 1.10.3-eks
在1.10.3上部署应用程序
在迁移工作负载时,我们需要一个来源集群上已经存在的工作负载。在演示中,我们将使用Heptio的示例LAMP堆栈在来源集群上创建一个LAMP堆栈(http://docs.heptio.com/content/tutorials/lamp.html),从而在MySQL卷上使用Portworx。这个堆栈包含了一个存储分类,包括Portworx、加密文件、HPH网页前端,以及一个具备Porworx卷副本的mySQL数据库。
代码语言:javascript复制$ kubectl create ns lamp
$ kubectl create -f . -n lamp
job.batch "mysql-data-loader-with-timeout" created
storageclass.storage.k8s.io "portworx-sc-repl3" created
persistentvolumeclaim "database" created
deployment.extensions "mysql" created
service "mysql" created
deployment.extensions "php-dbconnect" created
service "web" created
secret "mysql-credentials" created
使用kubectl对Pods进行检索,确保其处于Running状态下。
代码语言:javascript复制$ kubectl get po -n lamp
NAME READY STATUS RESTARTS AGE
mysql-6f95f464b8-2sq4v 1/1 Running 0 1m
mysql-data-loader-with-timeout-f2nwg 1/1 Running 0 1m
php-dbconnect-6599c648-8wnvf 1/1 Running 0 1m
php-dbconnect-6599c648-ckjqb 1/1 Running 0 1m
php-dbconnect-6599c648-qv2dj 1/1 Running 0 1m
提取Web服务。记录服务的CLUSTER-IP和EXTERNAL-IP。迁移完成后,这两个数据将会因为处于新的集群上而发生变化。
代码语言:javascript复制$ kubectl get svc web -n lamp -o wide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
web LoadBalancer 172.20.219.134 abe7c37c.amazonaws.com 80:31958/TCP 15m app=php-dbconnect
访问端点或使用curl确认WordPress已安装、运行正常且已连接至MySQL。
MySQL连接
代码语言:javascript复制$ curl -s abe7c37c.amazonaws.com/mysql-connect.php | jq
{
"outcome": true
}
验证是否也为MySQL容器创建了PVC。如下我们将看到PVC、数据库,各有三个副本用于部署。这个卷是MySQL的ReadWriteOnce卷块。
代码语言:javascript复制$ kubectl get pvc -n lamp
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
database Bound pvc-c572277d-ec15-11e8-9f4d-12563b3068d4 2Gi RWO portworx-sc-repl3 28m
卷信息也可以使用pxctl进行展示。Volume list命令的输出如下。
代码语言:javascript复制$ pxctl_src -- volume list
ID NAME SIZE HA STATUS
618216855805459265 pvc-c572277d-ec15-11e8-9f4d-12563b3068d4 2 GiB 3 attached on 10.0.3.145
将应用程序迁移至Kubernetes 1.12.0
对本地kubectl客户端进行配置,使其使用正在运行1.12.0的目标集群。
代码语言:javascript复制$ kubectl config use-context <1.12.0 destination cluster context>
运行kubectl Version命令,这个命令将输出当前的客户端和服务器版本,如下看到运行的1.12.0。
代码语言:javascript复制$ kubectl version --short | awk -Fv '/Server Version: / {print "Kubernetes Version: " $3}'
Kubernetes Version: 1.12.0
验证LAMP堆栈Pods是否正在运行中。如下所示,该集群的Namespace没有资源,即表示迁移还未发生。
代码语言:javascript复制$ kubectl get po
No resources found.
下一步,使用Stork客户端storkctl,创建一次迁移,将LAMP堆栈资源和卷从1.10.3集群迁移到1.12.0集群上。向storkctl create migration的命令的输入包括clusterPair、namespaces以及可选的includeResources和startApplications,从而将相关资源纳入并在迁移完成后启动应用程序。该命令的更多信息请点击这里(https://docs.portworx.com/cloud-references/migration/migration-stork/)。
代码语言:javascript复制$ storkctl --context <source-cluster-context>
create migration test-app-on-1-12
--clusterPair green
--namespaces lamp
--includeResources
--startApplications
Migration test-app-on-1-12 created successfully
迁移创建后,使用storkctl获取迁移状态。
代码语言:javascript复制$ storkctl --context <source-cluster-context> get migration
NAME CLUSTERPAIR STAGE STATUS VOLUMES RESOURCES CREATED
test-app-on-1-12 green Volumes InProgress 0/1 0/7 19 Nov 18 13:47 EST
pxctl也可以用于查看迁移状态。卷将显示出与迁移有关的STAGE和STATUS。
代码语言:javascript复制$ pxctl_src cloudmigrate status
CLUSTER UUID: 33293033-063c-4512-8394-d85d834b3716
TASK-ID VOLUME-ID VOLUME-NAME STAGE STATUS
85d3-lamp-database 618216855805459265 pvc-c572277d-ec15-11e8-9f4d-12563b3068d4 Done Initialized
完成后,迁移将显示STAGE → Final和 STATUS → Successful。
代码语言:javascript复制$ storkctl --context <source-cluster-context> get migration
NAME CLUSTERPAIR STAGE STATUS VOLUMES RESOURCES CREATED
test-app-on-1-12 green Final Successful 1/1 7/7 19 Nov 18 13:47 EST
现在从目标集群中获得Pods。如下所示,PHP与MySQL现在都在目的集群上运行。
代码语言:javascript复制$ kubectl get po -n lamp
NAME READY STATUS RESTARTS AGE
mysql-66d895ff69-z49jl 1/1 Running 0 11m
php-dbconnect-f756c7854-2fc2l 1/1 Running 0 11m
php-dbconnect-f756c7854-c48x8 1/1 Running 0 11m
php-dbconnect-f756c7854-h8tgh 1/1 Running 0 11m
注意CLUSTER-IP和EXTERNAL-IP现在已经发生了变化。这表示服务现在在新的Kubernetes 1.12集群上运行,并且因此包含了与此前不同的子网。
代码语言:javascript复制$ kubectl get svc web -n lamp -o wide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
web LoadBalancer 10.100.0.195 aacdee.amazonaws.com 80:31958/TCP 12m app=php-dbconnect
如果网站能够在1.12.0集群上被访问、运行正常并且数据已经正确迁移到了1.12.0集群,则将会返回相同的输出内容。
Web网页前端
MySQL连接
代码语言:javascript复制$ curl -s http://aacdee.amazonaws.com//mysql-connect.php | jq
{
"outcome": true
}
如下我们可以看到来源(下)和目标(上)集群上,kubectl get po -n lamp的输出。注意Pods的AGE,目的集群(上)中有最近迁移进来的LAMP堆栈。
两个集群在迁移后运行的是相同的程序和数据。
回顾整个过程:
1. 第一步,1.10.3 EKS集群与1.12.0集群配对。
2. LAMP堆栈(Linux, Apache, MySQL, PHP)部署到1.10.3集群上。
3. 使用PX-Motion将Kubernetes部署、加密文件、副本集、服务、持久卷、持久卷连接,以及LAMP堆栈数据迁移到1.12.0集群上。
4. 应用程序在1.12.0集群上被访问,并验证其是否正确运行。
持久卷和连接都使用PX-Motion(https://docs.portworx.com/cloud-references/migration)在各个集群之间进行迁移,Kubernetes资源和副本都使用Portworx Stork在目标集群上进行启动。
现在我们拥有了两个完全可运行的Kubernetes集群和两个环境,即蓝色和绿色部署环境。在实际操作中,你需要在绿色集群上进行所有测试,从而确保应用程序不会在新的集群上发生预期之外的问题。确认测试完成之后,将负载均衡从蓝色集群切换至新的绿色集群,此时部署就完成了!
结论
PX-Motion具有将Portworx卷和Kubernetes资源在集群之间进行迁移的能力。上述样例就是使用PX-Motion帮助团队实现蓝绿部署的过程:对其工作负载和数据在新版本的Kubernetes上进行测试,并帮助团队在新的绿色集群上运行应用程序。在不同版本的Kubernetes上进行真实负载和数据测试,使得运营团队能够在发布新版本的Kubernetes之前获得充足的信心。蓝绿部署并不是PX-Motion唯一的功能,请查看我们其他的PX-Motion博文了解更多。