K8S发布解释型语言应用的最佳实践
说明
我们知道,k8s在发布编译型语言的应用时,几乎不用多考虑,就会选择将编译好jar/war包(java语言)或者二进制文件(golang/c++)直接打到镜像当中,生成新的应用镜像,然后将镜像推到镜像仓库,再触发k8s完成应用发布或者版本更新。可是相反,解释型语言(php/lua/python)我们一般不会这么做。为什么呢?
因为我们知道,打镜像和推送镜像的一个过程是相对比较耗时的。对于编译型语言来讲,编译过程本身就比较耗时,在编译完成之后,再进行镜像打包和推送镜像的过程所消耗的时间跟编译过程本身相比,根本微不足道。对于开发人员来讲,他们有一个这样心理预期,多了这么一点点的时间,对于他们来讲,几乎是无感知的。
而对于解释型语言的应用开发者来讲则不然,我们以php为例来作说明。对于一个php开发者来讲,有的时候,一次发布,可能就只修改了一个文件,通过传统的发布方式,完成一次发布可能只需要10秒钟。而如果只是修改了一个文件却需要将整个代码完整打包,生成一个新的镜像,打镜像推镜像的时间可能就需要1分钟,再加上镜像替换,流动更新的时间,整个更新操作的时间就会拉的更长。虽然这在生产环境中的表现可能还并不明显,但在需要持续集成,频繁迭代的测试环境中,这种表现在发布时间上的巨大心理落差几乎无法让开发人员接受。事实上,这也是大多数解释型语言的开发者抵制docker的一个原因之一。
那么到底有没有更好的解决办法呢?
单独发布代码
事实上,有很多公司在实际使用中针对解释型语言的应用都选择了使用容器标准化运行时环境,代码单独发布的方式。
具体的做法是,使用镜像打包标准的php运行环境,然后将代码直接发布到k8s的所有node节点上,然后在任意节点上启动php标准镜像,并挂载所在节点的指定代码目录即可。因为所有节点上都有代码,所以php容器可以在任意节点之间漂移。如果不想把代码发布到所有节点,只想发布到某几个节点,也很好解决,只需要给这几个节点打上label,然后限定php容器只运行在带有该label的节点上即可。
这么做的优点显而易见:
- 通过容器的方式标准化了php环境,而且简化了php环境的部署操作。
- php代码发布仍然采用传统的发布方式独立发布,不受打镜像推镜像的时间影响,做到了快速迭代。
缺点同样显而易见:
- 首先镜像和代码拆开发布的方式本身就不是容器化标准所推荐的方法
- 我们需要通过label的方式严格对node和pod的对应关系做限定,一旦出错,就会出现pod正常运行,访问报错的现象,因为pod无法正常挂载代码。
- 因为一台宿主机上只有一份代码,如果该台宿主机上同时运行了同一个应用的多个pod,那么这些pod将会挂载同一份代码,当多个进程同时读写同一份代码时,需要代码自行解决冲突,虽然这种情况其实很少出现(绝大多数时候,应用程序的开发者都会避免在代码目录执行写操作,而对于读操作,多进程是可以共存的)。当然另一个可行的解决办法是通过pod的反亲和性调度避免将同一个应用的多个pod运行在同一个node节点上,毫无疑问,这也增加了配置的复杂性。
应用容器主动拉取代码
事实上,这是合乎容器化标准的一种实现。
而要实现这种方式,需要解决两个问题:
- 应用容器第一次启动时,如何获取代码
- 应用代码更新时,容器如何更新代码
第一个问题,我们使用kubernetes的init container技术来解决(在某些应用场中,使用pod启动后的钩子事件也可以解决,但在类似lua的应用场中,在应用容器启动之前就需要代码就位的情况下,这种方式并不合适,所以init container才是最好的选择)。其原理是在应用容器启动之前,先启动一个初始化容器,然后在初始化容器中执行从git仓库,或者从发布服务器拉取代码的操作,将代码直接拉取到应用容器的存储位置,然后启动应用容器,这样应用容器一启动,就有了代码。
第二个问题,可以直接调用k8s api,获取到当前应用的所有pod信息,然后触发循环调用pod上的rsync,执行主动拉取操作。
事实上,在我们当前的测试环境的lua代码的发布场景中,尤其适用。因为我们在测试环境中,持续集成的过程是自动完成的,每分钟执行一次持续集成操作。会先从git仓库将代码拉取到发布节点,发布节点启动rsync server端。然后各node节点上配置定时任务,每分钟从发布节点同步代码。对于lua应用来讲,每次代码更新就需要执行一次Nginx重载。通过这种发布方式,我们可以实现只有在有代码更新时,才执行nginx重载,而不是每分钟一次。
缺点:
增加了发布服务器的压力,所有pod不再共享宿主机代码,而是每个pod一套独立代码,所有pod都会从发布服务器拉取代码,在pod数量较大时,对发布服务器的io是个考验。另外如果某节点宕机时,所有pod漂移到新节点上重新启动,会同一时间向发布服务器拉取代码,对发布服务器的io压力也会较大
其配置相对于独立发布代码的方式其实是同样复杂的,但是其不用限定pod与node的对应关系,增加了调度的灵活性。
下面是一个应用容器主动拉取代码的k8s deployment配置文件示例:
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: dyland-lua-api-pre
namespace: php
spec:
replicas: 1
selector:
matchLabels:
name: dyland-lua-api-pre
envrion: php
template:
metadata:
annotations:
prometheus.io/scrape: "true"
prometheus.io/port: "9913"
prometheus.io/scheme: "http"
prometheus.io/path: "/metrics"
labels:
name: dyland-lua-api-pre
envrion: php
version: ""
spec:
initContainers:
- name: rsync-code
image: hub.dz11.com/op-base/rsync:v3.1.3
command:
- "sh"
- "-c"
- >
/bin/echo '123456' > /home/www/server/rsync.pwd;
chmod 400 /home/www/server/rsync.pwd;
/usr/bin/rsync -avzLu --password-file=/home/www/server/rsync.pwd www@$(RSYNC_SERVER)::pre-lua/dyland-lua-api.pre.wh03 /home/www/server/ > /dev/stdout 2>&1;
env:
- name: RSYNC_SERVER
value: 192.168.1.10
volumeMounts:
- name: www-root
mountPath: "/home/www/server"
containers:
- name: dyland-lua-api-pre
image: hub.dz11.com/op-base/openresty:1.11.2.4
imagePullPolicy: Always
lifecycle:
postStart:
exec:
command:
- "sh"
- "-c"
- >
/bin/echo 'options single-request-reopen' >> /etc/resolv.conf;
ports:
- containerPort: 80
env:
- name: APP_NAME
value: dyland-lua-api.pre.wh03
volumeMounts:
- name: nginx-conf
mountPath: /usr/local/ngx_openresty/nginx/conf/vhost
- name: applogdir
mountPath: /home/www/logs/applogs
- name: srvlogdir
mountPath: /home/www/logs/srvlogs
- name: www-root
mountPath: /home/www/server
# mountPath: /home/www/server/dyland-lua-api.pre.wh03
- name: nginx-vts-exporter
image: hub.dz11.com/library/nginx-vts-exporter:v0.10.3
ports:
- containerPort: 9913
env:
- name: NGINX_HOST
value: "http://localhost/status/format/json"
volumes:
- name: nginx-conf
configMap:
name: dyland-lua-api-pre-configmap
- name: applogdir
hostPath:
path: /home/www/logs/applogs
- name: srvlogdir
hostPath:
path: /home/www/logs/srvlogs
- name: www-root
emptyDir: {}
# hostPath:
# path: /home/www/server/dyland-lua-api.pre.wh03
imagePullSecrets:
- name: dk-reg
nodeSelector:
testenv: pre
K8S发布解释型语言应用的最佳实践的更多相关文章
- kubernetes发布解释型语言应用的最佳实践
说明 k8s在发布编译型语言的应用时,几乎不用多考虑,就会选择将编译好jar/war包(java语言)或者二进制文件(golang/c++)直接打到镜像当中,生成新的应用镜像,然后将镜像推到镜像仓库, ...
- 一款不错的 Go Server/API boilerplate,使用 K8S+DDD+CQRS+ES+gRPC 最佳实践构建
Golang API Starter Kit 该项目的主要目的是使用最佳实践.DDD.CQRS.ES.gRPC 提供样板项目设置. 为开发和生产环境提供 kubernetes 配置.允许与反映生产的 ...
- 生产环境容器落地最佳实践 --JFrog 内部K8s落地旅程
引言 Kubernetes已经成为市场上事实上领先的编配工具,不仅对技术公司如此,对所有公司都是如此,因为它允许您快速且可预测地部署应用程序.动态地伸缩应用程序.无缝地推出新特性,同时有效地利用硬件资 ...
- Asp.NetCore程序发布到CentOs(含安装部署netcore)--最佳实践(二)
Asp.NetCore程序发布到CentOs(含安装部署netcore)--最佳实践(一) 接上一篇 3. Nginx配置反向代理 3.1 cnetos 安装nginx 首先,我们需要在服务器上安装N ...
- Asp.NetCore程序发布到CentOs(含安装部署netcore)--最佳实践(一)
环境 本地 win7 服务器:Virtual Box 上的Centos ssh工具: Xshell 文件传输: xftp 1.在本地创建asp.net core应用发布 1.1 使用Vs2017 新建 ...
- Asp.NetCore程序发布到CentOs(含安装部署netcore)--最佳实践
原文:Asp.NetCore程序发布到CentOs(含安装部署netcore)--最佳实践 环境 本地 win7 服务器:Virtual Box 上的Centos ssh工具: Xshell 文件传输 ...
- ELK:收集k8s容器日志最佳实践
简介 关于日志收集这个主题,这已经是第三篇了,为什么一再研究这个课题,因为这个课题实在太重要,而当今优秀的开源解决方案还不是很明朗: 就docker微服务化而言,研发有需求标准输出,也有需求文件输出, ...
- 可能是Asp.net Core On host、 docker、kubernetes(K8s) 配置读取的最佳实践
写在前面 为了不违反广告法,我竭尽全力,不过"最佳实践"确是标题党无疑,如果硬要说的话 只能是个人最佳实践. 问题引出 可能很多新手都会遇到同样的问题:我要我的Asp.net ...
- 阿里巴巴发布最佳实践 | 阿里巴巴DevOps实践指南
编者按:本文源自阿里云云效团队出品的<阿里巴巴DevOps实践指南>,扫描上方二维码或前往:https://developer.aliyun.com/topic/devops,下载完整版电 ...
随机推荐
- 如何将office卸载干净
我试了控制面板卸载office软件等方法,发现一直卸载不干净. 后发现这个office的官方链接,根据这个链接的步骤就很轻松的卸载好了. https://support.office.com/zh-c ...
- (第十周)新NABCD
项目名:食物链教学工具 组名:奋斗吧兄弟 组长:黄兴 组员:李俞寰.杜桥.栾骄阳.王东涵 新的NABCD模型: Need:可以辅助教师课堂讲授食物链相关的知识.软件的界面要漂亮,操作要简单,要给出软件 ...
- 编写了几个Java类,但是一直运行某一个class,这种是因为:main方法写错
编写了几个Java类,但是一直运行某一个class,这种是因为:main方法写错
- mvc的过滤器学习-资料查询
标题:Filtering in ASP.NET MVC 地址:https://docs.microsoft.com/en-us/previous-versions/aspnet/gg416513(v= ...
- C#编程之神奇程序找数
C#编程之神奇程序找数 问题1:这个程序要找的是符合什么条件的数? 问题2:这样的数存在么?符合这一条件的最小的数是什么? 问题3:在电脑上运行这一程序,你估计多长时间才能输出第一个结果?时间精确到分 ...
- Linux操作系统(一)
操作系统:介于硬件与用户之间的一组程序,方便用户操作,用以管理计算机的所有活动及硬件资源. 1.硬件->内核->系统调用(shell.命令)->应用程序. 只要具备以下几点,即可称为 ...
- Linux上的free命令详解-收藏
解释一下Linux上free命令的输出. 下面是free的运行结果,一共有4行.为了方便说明,我加上了列号.这样可以把free的输出看成一个二维数组FO(Free Output).例如: FO[2][ ...
- TCP/IP协议三次握手和四次挥手大白话解说
前言 昨天晚上被一位师傅问到了TCP/IP的工作机制,心里很清楚三次握手,然而对于四次挥手却忘了,这是大学习里学过的,奋而翻阅书籍和网络对之前所学的做一个温顾,算是夯实自我吧. TCP(Transmi ...
- Tomcat 总体结构
一.Tomcat 总体结构 1.Server(服务器)是Tomcat构成的顶级构成元素,所有一切均包含在Server中,Server的实现类StandardServer可以包含一个到多个Service ...
- js 添加事件兼容性
var tools = { //添加事件 addHandle: function (e, type, handle) { if (e.addEventListener) { e.addEventLis ...