OwnCloud On Kubernetes On OpenStack
背景
研究kubernetes有一段时间了,k8s作为容器编排领域的标准,相比传统架构,在应用发布,运行,维护上具有颠覆性的变革,这场变革以“云原生”为口号,如火如荼的发展起来。可以想象,在不远的将来,大家的应用都以标准的形式,运行在以k8s为代表容器平台上,k8s让devops真正融合在了一起,尤其对运维,k8s定义了对应用的标准运维方式,平台替人做了很多toil的运维工作,通过各种机制保障应用的可用性,这对运维来说,是最激动人心的。在IaaS平台上构建起来的容器平台,还可以通过API的方式消费IaaS平台的网络和存储等资源,真正将IaaS平台的弹性、灵活性利用起来,容器平台将作为最接近应用的基础平台,是一个公司非常重要的IT基础设施,这一如当年的Linux给业界带来的变革。
K8S相比OpenStack来说,我感觉其复杂度有过之而无不及,毕竟都是基础平台,功能强大,就意味着复杂,光是把里面的概念搞清楚,就需要花费一些时间,为了更深刻的理解这些概念,最好的办法,就是动手做,本篇就以OwnCloud在Kubernetes上的部署为例,掌握下Kubernetes涉及到的一些核心概念,OwnCloud是一个开源的文件共享系统,说通俗点,就是一个“网盘”系统,之所以选择用它做实验,主要有以下几个原因:
- 最近想给公司搭建一个内部网盘,让大家可以把一些资料集中到一起,方便存储和共享
- OwnCloud是一个典型的LMAP架构的应用,会用到负载均衡,代理,数据库,Web Server等,具有代表性
- OwnCloud有一个非常不错的helm chart,可以用来学习
- OwnCloud还可以跟S3对接,将数据存储到对象存储中,这个可以用来跑我们的Ceph RGW的业务
此外,本次测试使用的Kubernetes是运行在OpenStack平台上,PaaS和IaaS的结合,看看会擦出怎么样的火花。
环境准备
首先是有一个OpenStack环境,为了更好的跟Kubernetes结合,这个OpenStack平台有以下特点:
- OpenStack后端接的Ceph,这是为了让k8s通过storageclass功能,消费OpenStack平台的块存储资源
- 部署了负载均衡功能,使用的octavia,模式是active standby模式,这是为了测试k8s的load balancer类型的service
- 提供VLAN类型的网络,因为k8s本身的网络就已经有了封装,其底层的网络就尽量让其简单
- 还部署了Ceph的RGW功能,后面可以让owncloud和rgw进行对接
然后是Kubernetes环境,有如下特点:
- Kubernetes平台是起在OpenStack里的虚拟机
- 虚拟机运行在VLAN网络里,共有6台,3个master节点,3个node节点
- Kubernetes使用kubespary部署,这是一个部署生产环境使用的ansible项目,功能很强大,几乎支持k8s的各种功能
- Kubernetes的网络使用calico的ipip模式,这是kubespray的默认网络模式
- Kubernetes的service proxy mode使用ipvs
- Kubernetes和OpenStack进行了对接,即k8s平台的cloud provider是openstack,这样k8s就可以消费openstack的api,使用其上的资源了,本次测试主要是使用块存储和负载均衡。
- Kubernetes部署了nginx ingress controller和helm,ingress通过load balancer service暴露出去,因为owncloud是使用helm部署的,而且也支持ingress的方式,所以部署上了这两个功能。
- 创建了一个叫cinder的storageclass,跟openstack的cinder进行了集成
架构规划
本次测试,目的是尽量让其接近生产环境,owncloud是一个LAMP架构的应用,数据库使用MariaDB,采用主备模式,并且数据库的部署也是通过helm的方式,owncloud(Apache+PHP)则被ingress代理,ingress又通过load balancer类型的service暴露出去,其整体架构如下图:
node-1, node-2, node-3分别是kubernetes平台里的三个worker node,是openstack里的三个虚拟机;LB是load balancer类型的service,会对应的在openstack平台里创建出来octavia的lb;LB通过round robin的方式,通过ingress的service的nodeport,代理ingress实例,ingress是replica为1的deployment;Apache是跑在bitnami提供的owncloud镜像里的,里面包含了apache+php,是我们的app程序,也是一个replica为1的deployment,其又被ingress所代理;最后是数据库,数据库是一个主从架构的集群,使用statefulset运行,数据库又通过默认的ClusterIP类型的service的方式暴露给集群内部使用。
Helm Chart
本次测试使用到两个helm chart,mariadb和owncloud,owncloud里面依赖了mariadb chart,部署owncloud chart时,会自动安装mariadb的chart,为了解耦,我们分开部署,把mariadb当成external db去部署,owncloud里也支持external database。
MariaDB的chart里面构成如下:
- 数据库实例使用statefulset部署,主从的replica都为1
- 通过service将数据库实例暴露给集群
- 数据库配置使用configmap保存
- 数据库密码使用secret保存
- 数据库使用到的数据目录,通过storageclass和pvc的形式进行申明挂载
OwnCloud的chart构成如下:
- owncloud的app实例使用deployment部署,replica为1
- owncloud deployment通过service暴露给集群内部
- ingress代理了owncloud service
- owncloud的密码,使用secret保存
- 使用到了两个pvc,一个是apache的数据目录,一个是owncloud的数据目录
综上,以上两个chart,有statefulset, deployment, service, cofigmap, secret, storageclass, pvc, ingress等概念,基本上包含了kubernetes里面最主要的核心概念。具体细节,可以直接看代码,这里就不展开讨论了。
部署测试
因为helm已经做了很好的封装,在前置条件都准备好的前提下,部署其实是非常简单的,我们只需要定制helm使用到的参数即可。本次测试,使用到的参数如下:
部署mariadb,使用到如下参数:
1 | # cat mariadb-values.yaml |
这里的重点是使用之前已经预定义好的cinder storageclass,为master和slave分配存储资源。
部署owncloud,使用到如下参数:
1 | # cat owncloud-values.yaml |
这里的重点是开启了ingress,它默认是关闭的,ingress的host写上域名,数据库使用的是external database,填写上mariadb的service clusterip,owncloud的service类型定义成ClusterIP,默认是Load Balancer,为的是让它被ingress代理,最后分配两个存储资源。
部署只需要两条命令就可以搞定:
1 | helm install -f mariadb-values.yaml stable/mariadb --name mariadb |
然后可以通过如下命令查看部署状态:
1 | helm list |
观察到pod都是running并且ready之后,说明部署完成,在本地为lb的vip做域名解析到owncloud.ustack.com,然后访问 http://owncloud.ustack.com 即可。
遇到问题
在测试的时候,遇到两个问题:
- externalDatabase里面的host不能写成service对应的域名,即
mariadb.default.svc.cluster.local
,使用域名的话,在owncloud的pod启动时,会卡在数据库初始化上,观察了下,这个初始化,是使用nodejs写的,还不清楚为什么卡住,换成service的clusterip,就好了,理论上,应该填写service对应的域名,会比较好些。 - owncloud这里的初始化好像没什么作用,我们已经在externalDatabase里传了数据库用户名和密码等信息,然后owncloud的用户名和密码,把这些当成环境变量传给了容器,但是在访问url时,还是会让你在界面上填写这些参数,而且进pod里看这些配置,都是没有配置上的,得在面板填写,安装之后,才会生成,感觉它这个初始化的脚本有问题。
概念解析
像service, ingress, pv, pvc这些概念相近,很容易让人迷惑,下面结合本次测试,对这些概念做一个梳理,确定下关键点,其次,最让人感兴趣的就是OpenStack里面资源是如何被Kubernetes使用的,这个测试主要用到了两种OpenStack资源,一个是cinder的块存储,一个是octavia的lb。
1. StorageClass, PVC, PV
上面的每一个pvc,都对应的创建了一个pv,每一个pv都对应一个cinder云硬盘,并且被挂载到了pod所在的node上:
1 | [root@kube-node-3 ~]# lsblk |
1 | [root@kube-master-1 ~]# kubectl get pvc |
StorageClass是最高度的抽象,它定义了要使用的存储的具体类型,比如是使用块存储,还是nfs,而pvc则是storageclass的消费者,pvc只关心需要多少存储资源,至于这个存储资源,怎么来,是由storageclass来定义的,pv则是具体的创建出来的存储资源了,pv会和对应的pvc进行绑定。
2. Ingress
上面创建的ingress对象,最终表现出来的是对应的在ingress nginx的nginx.conf中添加了配置:
1 | ## start server owncloud.ustack.com |
添加完配置之后,nginx会自动通过lua进行重载,使配置生效,可见,ingress的工作其实非常轻量级。Ingress其实就是一个反向代理,代理后端的service,之前一直理解的是每一个ingress都会创建一个nginx实例,其实并不是,而是所有的service都使用同一个nginx,通过host参数,来为每一个service在nginx.conf中添加vhost,然后对其进行代理,这样做的好处显而易见,就是可以通过一个统一的入口,代理后端的多个服务,ingress有点类似于是service的service,明白这一点,是理解ingress的关键。
Ingress的另一个关键点是,ingress其实也是一个集群内对象,默认是不对集群外暴露的,而如果你想将ingress暴露出去,还是要通过service的方式进行,即给ingress之前再加一个service,可以是nodeport,或者是lb。
1 | [root@kube-master-1 ~]# kubectl get ingress |
本例使用lb类型的service将ingress暴露到集群外,而lb则是使用的openstack的lb功能。
3. Service
Service这个概念在Kubernetes中,是使用最广泛的一个概念了,从服务的角度来讲,每一个服务都需要对外暴露一个统一的入口,比如本例中的数据库,owncloud等。Service本质上,其实也是一个代理,代理后端的pod,有3种代理模式:userspace, iptables, ipvs,其中ipvs是通过lvs实现的,在大规模场景下,会简化管理,提高性能。在本例中,使用ipvs模式,可以通过如下命令看到ipvs的代理效果:
1 | [root@kube-master-1 ~]# ipvsadm -ln |
此外,service对集群外进行暴露,通过有两种方式,一个是nodeport,一个是load balancer,nodeport只在kubernetes集群内部就可以实现,通过iptables+ipvs规则实现,效果就是可以通过任一一个节点的IP地址+自动分配的node port,就可以访问到这个service,如上例中31659就是一个node port,需要注意的一个关键点是,这些规则会在每一个k8s的节点添加,由于节点之间是内网联通的,因此访问任一一个节点的ip地址,都可以访问到这个service。而load balancer类型的service,则需要依赖集群外部的load balancer服务去实现,这种通常是需要有cloud provider的,即依赖于底层IaaS平台的负载均衡服务,为其创建LB,然后通过node port将节点添加到lb的member中,其中的关键点是,lb类型的service,是构建在nodeport基础上的,它是先建立了node port,然后通过node port,将node添加到lb的后端服务中,如本例中,将ingress通过lb service进行暴露的方式,在OpenStack LB服务中,会看到如下的内容:
1 | [root@kube-master-1 ~]# kubectl get svc -n ingress-nginx |
可以看到,ingress nginx controller通过两个listener,将80和443端口暴露出去,对应的有两pool,每个pool中有3个member,分别就是3个work node,而member中,又通过service的node port,将其添加到pool的member中,这样就完美实现了OpenStack为Kubernetes中的Ingress对象提供负载均衡的功能。
此外,还有statefulset, deployment等概念,这里就不再阐述了,比较好理解,官方文档解释的也比较清楚。
总结
本文通过对OwnCloud在Kubernetes上进行部署为例,介绍了Kubernetes中的几个重点概念,同时,也展示了Kubernetes在OpenStack平台上展示出来的威力,真心感觉,构建在IaaS平台之上的PaaS才是未来的主流发展方向,IaaS为PaaS提供了各种资源,而PaaS又像最终的应用提供了编排能力,以及对资源进行了进一步的抽象,IaaS应该由像Kubernetes这样的PaaS平台通过API的方式进行消费,而不是由人直接消费,这才是运维自动化的核心。
附录
- openstack cinder storage class
1 | # cat cinder-storage-class.yaml |
- openstack loadbalancer service for ingress nginx
1 | # cat openstack-lb-ingress.yaml |
OwnCloud On Kubernetes On OpenStack
https://hackerain.me/2019/04/08/kubernetes/owncloudon-kubernetes-on-openstack.html