应用容器化是部署与迁移的第一步,需要设计并规划好镜像的构建方案,由于Docker镜像分层的特性,通常建议使用分层方式进行Docker镜像构建。
操作系统层:制作公司常用的系统版本如CentOS、Ubuntu,可以在官方镜像的基础上添加自己需要的软件包。
运行环境层:在已经构建的操作系统层的基础上,把业务常用的运行环境都打包好,如JDK7、JDK8、JDK8+Tomcat8、Python2、Python3等通用模板。
应用层:在已经构建好了通用运行环境的基础上,根据应用再进行调整,然后将代码放进去即可。
应用容器化后,就需要考虑如何在Pod中运行,因为Pod是Kubernetes管理的最小单元,Kubernetes不直接管理容器,而是管理Pod,Pod里面包含容器。需要考虑是一个Pod中放置多个容器,还是一个Pod中放置一个容器,同时需要考虑Pod的资源限制,健康检查,数据持久化等。
单一Pod如果出现故障,就会影响业务连续性,所以需要多副本,就像我们给一个Web应用做集群是一样的。Kubernetes提供了不同的Controller,需要根据应用的实际情况选择使用Deployment、DaemonSet、StatefulSet、Job、CronJob等,只需要在Pod的YAML模板上封装上对应的配置即可。
Deployment:封装了Pod的副本管理、部署更新、回滚、扩容、缩容等。
DaemonSet:保证所有的Node上有且只有一个Pod在运行。
StatefulSet:有状态的应用,为Pod提供唯一的标识,它可以保证部署和scale的顺序。
Job:使用Kubernetes运行单一任务。
CronJob:使用Kubernetes运行定时任务。
使用Deployment通过多副本的方式保证了Pod的高可用和横向扩展,那么就需要考虑负载均衡,Kubernetes Service就是实现此功能,为应用创建对应的Service。目前Service的负载均衡支持两种实现方式:iptable 和 ipvs。
集群内部可以直接使用Service Name进行通信,因为在集群中定义的每个 Service,都会被指派一个 DNS 名称,外部要访问到Kubernetes集群,由于网络路由不通(也可以使用其它手段打通),可以通过Node Port、LoadBlancer、外部IP等对外暴露访问。不过这些都可以理解为4层的负载均衡,如果要实现7层的负载均衡,Kubernetes提供了Ingress。
在Kubernetes中由Ingress Controller来实现Ingress的功能,这个控制器比较特殊,因为其它的控制器基本上都是kube-controller-manager这个服务的一部分,而Ingress Controller确是独立的。
容器中的存储都是临时的,因此Pod重启的时候,内部的数据会发生丢失。实际应用中,我们有些应用是无状态,有些应用则需要保持状态数据,确保Pod重启之后能够读取到之前的状态数据,有些应用则作为集群提供服务。这三种服务归纳为无状态服务、有状态服务以及有状态的集群服务,其中后面两个存在数据保存与共享的需求,因此就要采用容器外的存储方案。
在DevOps的部署流水线中,我们强调代码和配置的分离,这样更容易实现流水线的编排。在Kubernetes中提供了ConfigMap资源对象,其实ConfigMap和Secret都是一种卷类型,可以从文件、文件夹等途径创建ConfigMap。然后再Pod中挂载使用。