K8S发布解释型语言应用的最佳实践
說明
我們知道,k8s在發(fā)布編譯型語言的應(yīng)用時(shí),幾乎不用多考慮,就會(huì)選擇將編譯好jar/war包(java語言)或者二進(jìn)制文件(golang/c++)直接打到鏡像當(dāng)中,生成新的應(yīng)用鏡像,然后將鏡像推到鏡像倉庫,再觸發(fā)k8s完成應(yīng)用發(fā)布或者版本更新。可是相反,解釋型語言(php/lua/python)我們一般不會(huì)這么做。為什么呢?
因?yàn)槲覀冎?#xff0c;打鏡像和推送鏡像的一個(gè)過程是相對(duì)比較耗時(shí)的。對(duì)于編譯型語言來講,編譯過程本身就比較耗時(shí),在編譯完成之后,再進(jìn)行鏡像打包和推送鏡像的過程所消耗的時(shí)間跟編譯過程本身相比,根本微不足道。對(duì)于開發(fā)人員來講,他們有一個(gè)這樣心理預(yù)期,多了這么一點(diǎn)點(diǎn)的時(shí)間,對(duì)于他們來講,幾乎是無感知的。
而對(duì)于解釋型語言的應(yīng)用開發(fā)者來講則不然,我們以php為例來作說明。對(duì)于一個(gè)php開發(fā)者來講,有的時(shí)候,一次發(fā)布,可能就只修改了一個(gè)文件,通過傳統(tǒng)的發(fā)布方式,完成一次發(fā)布可能只需要10秒鐘。而如果只是修改了一個(gè)文件卻需要將整個(gè)代碼完整打包,生成一個(gè)新的鏡像,打鏡像推鏡像的時(shí)間可能就需要1分鐘,再加上鏡像替換,流動(dòng)更新的時(shí)間,整個(gè)更新操作的時(shí)間就會(huì)拉的更長(zhǎng)。雖然這在生產(chǎn)環(huán)境中的表現(xiàn)可能還并不明顯,但在需要持續(xù)集成,頻繁迭代的測(cè)試環(huán)境中,這種表現(xiàn)在發(fā)布時(shí)間上的巨大心理落差幾乎無法讓開發(fā)人員接受。事實(shí)上,這也是大多數(shù)解釋型語言的開發(fā)者抵制docker的一個(gè)原因之一。
那么到底有沒有更好的解決辦法呢?
單獨(dú)發(fā)布代碼
事實(shí)上,有很多公司在實(shí)際使用中針對(duì)解釋型語言的應(yīng)用都選擇了使用容器標(biāo)準(zhǔn)化運(yùn)行時(shí)環(huán)境,代碼單獨(dú)發(fā)布的方式。
具體的做法是,使用鏡像打包標(biāo)準(zhǔn)的php運(yùn)行環(huán)境,然后將代碼直接發(fā)布到k8s的所有node節(jié)點(diǎn)上,然后在任意節(jié)點(diǎn)上啟動(dòng)php標(biāo)準(zhǔn)鏡像,并掛載所在節(jié)點(diǎn)的指定代碼目錄即可。因?yàn)樗泄?jié)點(diǎn)上都有代碼,所以php容器可以在任意節(jié)點(diǎn)之間漂移。如果不想把代碼發(fā)布到所有節(jié)點(diǎn),只想發(fā)布到某幾個(gè)節(jié)點(diǎn),也很好解決,只需要給這幾個(gè)節(jié)點(diǎn)打上label,然后限定php容器只運(yùn)行在帶有該label的節(jié)點(diǎn)上即可。
這么做的優(yōu)點(diǎn)顯而易見:
缺點(diǎn)同樣顯而易見:
應(yīng)用容器主動(dòng)拉取代碼
事實(shí)上,這是合乎容器化標(biāo)準(zhǔn)的一種實(shí)現(xiàn)。
而要實(shí)現(xiàn)這種方式,需要解決兩個(gè)問題:
第一個(gè)問題,我們使用kubernetes的init container技術(shù)來解決(在某些應(yīng)用場(chǎng)中,使用pod啟動(dòng)后的鉤子事件也可以解決,但在類似lua的應(yīng)用場(chǎng)中,在應(yīng)用容器啟動(dòng)之前就需要代碼就位的情況下,這種方式并不合適,所以init container才是最好的選擇)。其原理是在應(yīng)用容器啟動(dòng)之前,先啟動(dòng)一個(gè)初始化容器,然后在初始化容器中執(zhí)行從git倉庫,或者從發(fā)布服務(wù)器拉取代碼的操作,將代碼直接拉取到應(yīng)用容器的存儲(chǔ)位置,然后啟動(dòng)應(yīng)用容器,這樣應(yīng)用容器一啟動(dòng),就有了代碼。
第二個(gè)問題,可以直接調(diào)用k8s api,獲取到當(dāng)前應(yīng)用的所有pod信息,然后觸發(fā)循環(huán)調(diào)用pod上的rsync,執(zhí)行主動(dòng)拉取操作。
事實(shí)上,在我們當(dāng)前的測(cè)試環(huán)境的lua代碼的發(fā)布場(chǎng)景中,尤其適用。因?yàn)槲覀冊(cè)跍y(cè)試環(huán)境中,持續(xù)集成的過程是自動(dòng)完成的,每分鐘執(zhí)行一次持續(xù)集成操作。會(huì)先從git倉庫將代碼拉取到發(fā)布節(jié)點(diǎn),發(fā)布節(jié)點(diǎn)啟動(dòng)rsync server端。然后各node節(jié)點(diǎn)上配置定時(shí)任務(wù),每分鐘從發(fā)布節(jié)點(diǎn)同步代碼。對(duì)于lua應(yīng)用來講,每次代碼更新就需要執(zhí)行一次Nginx重載。通過這種發(fā)布方式,我們可以實(shí)現(xiàn)只有在有代碼更新時(shí),才執(zhí)行nginx重載,而不是每分鐘一次。
缺點(diǎn):
增加了發(fā)布服務(wù)器的壓力,所有pod不再共享宿主機(jī)代碼,而是每個(gè)pod一套獨(dú)立代碼,所有pod都會(huì)從發(fā)布服務(wù)器拉取代碼,在pod數(shù)量較大時(shí),對(duì)發(fā)布服務(wù)器的io是個(gè)考驗(yàn)。另外如果某節(jié)點(diǎn)宕機(jī)時(shí),所有pod漂移到新節(jié)點(diǎn)上重新啟動(dòng),會(huì)同一時(shí)間向發(fā)布服務(wù)器拉取代碼,對(duì)發(fā)布服務(wù)器的io壓力也會(huì)較大
其配置相對(duì)于獨(dú)立發(fā)布代碼的方式其實(shí)是同樣復(fù)雜的,但是其不用限定pod與node的對(duì)應(yīng)關(guān)系,增加了調(diào)度的靈活性。
下面是一個(gè)應(yīng)用容器主動(dòng)拉取代碼的k8s deployment配置文件示例:
apiVersion: extensions/v1beta1 kind: Deployment metadata:name: dyland-lua-api-prenamespace: php spec:replicas: 1selector: matchLabels:name: dyland-lua-api-preenvrion: phptemplate:metadata:annotations: prometheus.io/scrape: "true"prometheus.io/port: "9913"prometheus.io/scheme: "http"prometheus.io/path: "/metrics"labels:name: dyland-lua-api-preenvrion: phpversion: ""spec:initContainers:- name: rsync-codeimage: hub.dz11.com/op-base/rsync:v3.1.3command:- "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_SERVERvalue: 192.168.1.10volumeMounts:- name: www-rootmountPath: "/home/www/server"containers:- name: dyland-lua-api-preimage: hub.dz11.com/op-base/openresty:1.11.2.4imagePullPolicy: Alwayslifecycle:postStart:exec:command:- "sh"- "-c"- >/bin/echo 'options single-request-reopen' >> /etc/resolv.conf;ports:- containerPort: 80env:- name: APP_NAMEvalue: dyland-lua-api.pre.wh03volumeMounts:- name: nginx-conf mountPath: /usr/local/ngx_openresty/nginx/conf/vhost- name: applogdirmountPath: /home/www/logs/applogs- name: srvlogdirmountPath: /home/www/logs/srvlogs- name: www-rootmountPath: /home/www/server# mountPath: /home/www/server/dyland-lua-api.pre.wh03- name: nginx-vts-exporterimage: hub.dz11.com/library/nginx-vts-exporter:v0.10.3ports:- containerPort: 9913env:- name: NGINX_HOSTvalue: "http://localhost/status/format/json"volumes:- name: nginx-confconfigMap:name: dyland-lua-api-pre-configmap- name: applogdirhostPath:path: /home/www/logs/applogs- name: srvlogdirhostPath:path: /home/www/logs/srvlogs- name: www-rootemptyDir: {}# hostPath:# path: /home/www/server/dyland-lua-api.pre.wh03imagePullSecrets:- name: dk-regnodeSelector:testenv: pre轉(zhuǎn)載于:https://www.cnblogs.com/breezey/p/9242446.html
總結(jié)
以上是生活随笔為你收集整理的K8S发布解释型语言应用的最佳实践的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 超强、超详细Redis入门教程【转】
- 下一篇: docker-ce版本私有仓库搭建