说明

我们知道,k8s在发布编译型语言的应用时,几乎不用多考虑,就会选择将编译好jar/war包(java语言)或者二进制文件(golang/c++)直接打到镜像当中,生成新的应用镜像,然后将镜像推到镜像仓库,再触发k8s完成应用发布或者版本更新。可是相反,解释型语言(php/lua/python)我们一般不会这么做。为什么呢?

因为我们知道,打镜像和推送镜像的一个过程是相对比较耗时的。对于编译型语言来讲,编译过程本身就比较耗时,在编译完成之后,再进行镜像打包和推送镜像的过程所消耗的时间跟编译过程本身相比,根本微不足道。对于开发人员来讲,他们有一个这样心理预期,多了这么一点点的时间,对于他们来讲,几乎是无感知的。

而对于解释型语言的应用开发者来讲则不然,我们以php为例来作说明。对于一个php开发者来讲,有的时候,一次发布,可能就只修改了一个文件,通过传统的发布方式,完成一次发布可能只需要10秒钟。而如果只是修改了一个文件却需要将整个代码完整打包,生成一个新的镜像,打镜像推镜像的时间可能就需要1分钟,再加上镜像替换,流动更新的时间,整个更新操作的时间就会拉的更长。虽然这在生产环境中的表现可能还并不明显,但在需要持续集成,频繁迭代的测试环境中,这种表现在发布时间上的巨大心理落差几乎无法让开发人员接受。事实上,这也是大多数解释型语言的开发者抵制docker的一个原因之一。

那么到底有没有更好的解决办法呢?

单独发布代码

事实上,有很多公司在实际使用中针对解释型语言的应用都选择了使用容器标准化运行时环境,代码单独发布的方式。

具体的做法是,使用镜像打包标准的php运行环境,然后将代码直接发布到k8s的所有node节点上,然后在任意节点上启动php标准镜像,并挂载所在节点的指定代码目录即可。因为所有节点上都有代码,所以php容器可以在任意节点之间漂移。如果不想把代码发布到所有节点,只想发布到某几个节点,也很好解决,只需要给这几个节点打上label,然后限定php容器只运行在带有该label的节点上即可。

这么做的优点显而易见:

  1. 通过容器的方式标准化了php环境,而且简化了php环境的部署操作。
  2. php代码发布仍然采用传统的发布方式独立发布,不受打镜像推镜像的时间影响,做到了快速迭代。

缺点同样显而易见:

  1. 首先镜像和代码拆开发布的方式本身就不是容器化标准所推荐的方法
  2. 我们需要通过label的方式严格对node和pod的对应关系做限定,一旦出错,就会出现pod正常运行,访问报错的现象,因为pod无法正常挂载代码。
  3. 因为一台宿主机上只有一份代码,如果该台宿主机上同时运行了同一个应用的多个pod,那么这些pod将会挂载同一份代码,当多个进程同时读写同一份代码时,需要代码自行解决冲突,虽然这种情况其实很少出现(绝大多数时候,应用程序的开发者都会避免在代码目录执行写操作,而对于读操作,多进程是可以共存的)。当然另一个可行的解决办法是通过pod的反亲和性调度避免将同一个应用的多个pod运行在同一个node节点上,毫无疑问,这也增加了配置的复杂性。

应用容器主动拉取代码

事实上,这是合乎容器化标准的一种实现。

而要实现这种方式,需要解决两个问题:

  1. 应用容器第一次启动时,如何获取代码
  2. 应用代码更新时,容器如何更新代码

第一个问题,我们使用kubernetes的init container技术来解决(在某些应用场中,使用pod启动后的钩子事件也可以解决,但在类似lua的应用场中,在应用容器启动之前就需要代码就位的情况下,这种方式并不合适,所以init container才是最好的选择)。其原理是在应用容器启动之前,先启动一个初始化容器,然后在初始化容器中执行从git仓库,或者从发布服务器拉取代码的操作,将代码直接拉取到应用容器的存储位置,然后启动应用容器,这样应用容器一启动,就有了代码。

第二个问题,可以直接调用k8s api,获取到当前应用的所有pod信息,然后触发循环调用pod上的rsync,执行主动拉取操作。

事实上,在我们当前的测试环境的lua代码的发布场景中,尤其适用。因为我们在测试环境中,持续集成的过程是自动完成的,每分钟执行一次持续集成操作。会先从git仓库将代码拉取到发布节点,发布节点启动rsync server端。然后各node节点上配置定时任务,每分钟从发布节点同步代码。对于lua应用来讲,每次代码更新就需要执行一次Nginx重载。通过这种发布方式,我们可以实现只有在有代码更新时,才执行nginx重载,而不是每分钟一次。

缺点:

  1. 增加了发布服务器的压力,所有pod不再共享宿主机代码,而是每个pod一套独立代码,所有pod都会从发布服务器拉取代码,在pod数量较大时,对发布服务器的io是个考验。另外如果某节点宕机时,所有pod漂移到新节点上重新启动,会同一时间向发布服务器拉取代码,对发布服务器的io压力也会较大

  2. 其配置相对于独立发布代码的方式其实是同样复杂的,但是其不用限定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发布解释型语言应用的最佳实践的更多相关文章

  1. kubernetes发布解释型语言应用的最佳实践

    说明 k8s在发布编译型语言的应用时,几乎不用多考虑,就会选择将编译好jar/war包(java语言)或者二进制文件(golang/c++)直接打到镜像当中,生成新的应用镜像,然后将镜像推到镜像仓库, ...

  2. 一款不错的 Go Server/API boilerplate,使用 K8S+DDD+CQRS+ES+gRPC 最佳实践构建

    Golang API Starter Kit 该项目的主要目的是使用最佳实践.DDD.CQRS.ES.gRPC 提供样板项目设置. 为开发和生产环境提供 kubernetes 配置.允许与反映生产的 ...

  3. 生产环境容器落地最佳实践 --JFrog 内部K8s落地旅程

    引言 Kubernetes已经成为市场上事实上领先的编配工具,不仅对技术公司如此,对所有公司都是如此,因为它允许您快速且可预测地部署应用程序.动态地伸缩应用程序.无缝地推出新特性,同时有效地利用硬件资 ...

  4. Asp.NetCore程序发布到CentOs(含安装部署netcore)--最佳实践(二)

    Asp.NetCore程序发布到CentOs(含安装部署netcore)--最佳实践(一) 接上一篇 3. Nginx配置反向代理 3.1 cnetos 安装nginx 首先,我们需要在服务器上安装N ...

  5. Asp.NetCore程序发布到CentOs(含安装部署netcore)--最佳实践(一)

    环境 本地 win7 服务器:Virtual Box 上的Centos ssh工具: Xshell 文件传输: xftp 1.在本地创建asp.net core应用发布 1.1 使用Vs2017 新建 ...

  6. Asp.NetCore程序发布到CentOs(含安装部署netcore)--最佳实践

    原文:Asp.NetCore程序发布到CentOs(含安装部署netcore)--最佳实践 环境 本地 win7 服务器:Virtual Box 上的Centos ssh工具: Xshell 文件传输 ...

  7. ELK:收集k8s容器日志最佳实践

    简介 关于日志收集这个主题,这已经是第三篇了,为什么一再研究这个课题,因为这个课题实在太重要,而当今优秀的开源解决方案还不是很明朗: 就docker微服务化而言,研发有需求标准输出,也有需求文件输出, ...

  8. 可能是Asp.net Core On host、 docker、kubernetes(K8s) 配置读取的最佳实践

    写在前面 为了不违反广告法,我竭尽全力,不过"最佳实践"确是标题党无疑,如果硬要说的话 只能是个人最佳实践. 问题引出 ​ 可能很多新手都会遇到同样的问题:我要我的Asp.net ...

  9. 阿里巴巴发布最佳实践 | 阿里巴巴DevOps实践指南

    编者按:本文源自阿里云云效团队出品的<阿里巴巴DevOps实践指南>,扫描上方二维码或前往:https://developer.aliyun.com/topic/devops,下载完整版电 ...

随机推荐

  1. Scrum Meeting 2 -2014.11.2

    今天大家读完代码后又聚在了一块讨论了许多.确定了重点的任务和分工细节.提出了许多问题和改进的方案.还有讨论分析了关于团队作业 - 软件分析和用户需求调查,初步决定目标软件为必应的输入法和词典,团队为争 ...

  2. 实验五Java网络编程及安全

    实验五 Java网络编程及安全 结对伙伴:20135231林涵锦(负责服务器方)http://www.cnblogs.com/20135213lhj/  实验目的与要求: 1.掌握Java网络编程的方 ...

  3. 蹭课神器NABCD分析

    特点:添加了课程分类,同学们可以根据自己的兴趣蹭课N(need):众所周知,大学是丰富多彩的自有天堂,学生能够在课余去旁听一些自己有兴趣的课,我们项目要解 决的就是同学们对校园课程有针对性的选择.A( ...

  4. vs2013 CodeLens

    那东西叫 CodeLens  只有VS2013 旗舰版 (update 2及以上) 才可以用,高级版 专业版都没有.如何打开CodeLens呢?在VS菜单栏 >> 工具 >> ...

  5. mabatis报错 Result Maps collection already contains value for gamedataserver.dao.one.ChargeRecordMapper.BaseResultMap

    1.解决这种报错看看英文"already ",也就是已经存在,其实是因为存在了两个id相同的返回,以下可以看看,根据这种例子看看自己项目是不是这种问题

  6. 为什么使彩色图变灰RGB的权重会固定(R:0.299 G:0.587 B:0.114)?

    人眼对绿色的敏感度最高,对红色的敏感度次之,对蓝色的敏感度最低,因此使用不同的权重将得到比较合理的灰度图像.根据实验和理论推导得出以下数值 R: 0.299. G:  0.587. B: 0.114.

  7. Week4-作业1

    第四章        这一章主要讲了代码规范.复审和团队合作这两项内容.        在关于代码设计规范方面,书中讲到了关于goto的使用:        “函数最好有单一的出口,为了达到这一目的, ...

  8. 001_JavaWeb之Servlet的路径映射问题

    001_JavaWeb之Servlet的路径映射问题 在web.xml中写入: <servlet> <servlet-name>DeleteStudent</servle ...

  9. grunt入门讲解7:项目脚手架grunt-init

    grunt-init是一个用于自动创建项目脚手架的工具.它会基于当前工作环境和你给出的一些配置选项构建一个完整的目录结构.至于其所生成的具体文件和内容,依赖于你所选择的模版和构建过程中你对具体信息所给 ...

  10. VIM 命令收藏

    1.vim#在命令行中输入vim,进入vim编辑器2.i#按一下i键,下端显示 --INSERT--#插入命令,在vim中可能任意字符都有作用3.Esc#退出i(插入)命令进行其它命令使用4.:r f ...