说明

我们知道,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. Final阶段中间产物

    空天猎功能说明书:https://git.coding.net/liusx0303/Plane.git 空天猎代码控制:https://coding.net/u/MR__Chen/p/SkyHunte ...

  2. No.10_分数分配

    C#队一共有7名成员,因此团队贡献分一共350分. 分配方式应当反映绝大部分组员的真实贡献情况,即由贡献决定分数. 另外保证一定的奖惩措施,充分调动组员的积极性,鞭策团队向前迈进. 对于团队贡献分数的 ...

  3. WebGL学习笔记二

    前一章就是第二章主要学的是通过WebGL实现先是在webGL内赋值,但是不实用后来通过定义attribute和uniform存储限定符来将javascript中的数据传到webGL中,大致的流程是1. ...

  4. 45度炸队Alpha冲刺博客集

    博客集如下: Alpha冲刺Day1:第一天冲刺记录 Alpha冲刺Day2:第二天冲刺记录 Alpha冲刺Day3:第三天冲刺记录 Alpha冲刺Day4:第四天冲刺记录 Alpha冲刺Day5:第 ...

  5. beta冲刺7/7

    队名:Boy Next Door 燃尽图 代码写入 https://github.com/mangoqiqi/paybook/tree/master/Desktop/Web%E8%B4%A6%E5%8 ...

  6. 关于supervisor无法监控golang代码的解决方法

    之前一直都是使用如下方式运行go代码 # go run test.go 这种运行方式是直接编译运行go代码,虽然在调试的时候没出什么问题,但是在使用supervisor监控的时候,会提示如下错误:(b ...

  7. windows多线程(二) 等待线程返回

    多线程编程中,有时我们需要等待某一线程完成了特定的操作后再继续做其他事情,要实现这个目的,可以使用Windows API函数WaitForSingleObject,或者WaitForMultipleO ...

  8. PBS命令和使用

    PBS是公开源代码的作业管理系统,在此环境下运行,用户不需要指定程序在哪些节点上运行,程序所需的硬件资源由PBS管理和分配. PBS(Portable Batch System)是由NASA开发的灵活 ...

  9. windows结束端口对应的进程

    netstat -ano |findstr " //window查看端口占用 taskkill /pid 54828taskkill /F /pid 54828 //强制中止 转载请注明博客 ...

  10. SOA (面向服务的架构)-Service Oriented Architecture

    SOA (面向服务的架构) 编辑 面向服务的架构(SOA)是一个组件模型,它将应用程序的不同功能单元(称为服务)通过这些服务之间定义良好的接口和契约联系起来.接口是采用中立的方式进行定义的,它应该独立 ...