K8S发布解释型语言应用的最佳实践
說明
我們知道,k8s在發布編譯型語言的應用時,幾乎不用多考慮,就會選擇將編譯好jar/war包(java語言)或者二進制文件(golang/c++)直接打到鏡像當中,生成新的應用鏡像,然后將鏡像推到鏡像倉庫,再觸發k8s完成應用發布或者版本更新。可是相反,解釋型語言(php/lua/python)我們一般不會這么做。為什么呢?
因為我們知道,打鏡像和推送鏡像的一個過程是相對比較耗時的。對于編譯型語言來講,編譯過程本身就比較耗時,在編譯完成之后,再進行鏡像打包和推送鏡像的過程所消耗的時間跟編譯過程本身相比,根本微不足道。對于開發人員來講,他們有一個這樣心理預期,多了這么一點點的時間,對于他們來講,幾乎是無感知的。
而對于解釋型語言的應用開發者來講則不然,我們以php為例來作說明。對于一個php開發者來講,有的時候,一次發布,可能就只修改了一個文件,通過傳統的發布方式,完成一次發布可能只需要10秒鐘。而如果只是修改了一個文件卻需要將整個代碼完整打包,生成一個新的鏡像,打鏡像推鏡像的時間可能就需要1分鐘,再加上鏡像替換,流動更新的時間,整個更新操作的時間就會拉的更長。雖然這在生產環境中的表現可能還并不明顯,但在需要持續集成,頻繁迭代的測試環境中,這種表現在發布時間上的巨大心理落差幾乎無法讓開發人員接受。事實上,這也是大多數解釋型語言的開發者抵制docker的一個原因之一。
那么到底有沒有更好的解決辦法呢?
單獨發布代碼
事實上,有很多公司在實際使用中針對解釋型語言的應用都選擇了使用容器標準化運行時環境,代碼單獨發布的方式。
具體的做法是,使用鏡像打包標準的php運行環境,然后將代碼直接發布到k8s的所有node節點上,然后在任意節點上啟動php標準鏡像,并掛載所在節點的指定代碼目錄即可。因為所有節點上都有代碼,所以php容器可以在任意節點之間漂移。如果不想把代碼發布到所有節點,只想發布到某幾個節點,也很好解決,只需要給這幾個節點打上label,然后限定php容器只運行在帶有該label的節點上即可。
這么做的優點顯而易見:
缺點同樣顯而易見:
應用容器主動拉取代碼
事實上,這是合乎容器化標準的一種實現。
而要實現這種方式,需要解決兩個問題:
第一個問題,我們使用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-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轉載于:https://www.cnblogs.com/breezey/p/9242446.html
總結
以上是生活随笔為你收集整理的K8S发布解释型语言应用的最佳实践的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 超强、超详细Redis入门教程【转】
- 下一篇: docker-ce版本私有仓库搭建