擁抱雲原生,如何將開源專案用k8s部署?
k8s以及雲原生相關概念近年來一直比較火熱,阿丸最近搞了個相關專案,小結一下。
本文將重點分享阿里開源專案otter適配k8s部署的改造過程,其中的改造過程和技巧應該適用於將大多數開源專案改造到k8s進行部署。
1.背景
otter是阿里開源的分散式資料庫同步系統,基於資料庫增量日誌解析,並準實時同步到本機房或異地機房的mysql/oracle資料庫(相關內容可以參考https://github.com/alibaba/otter,本文不做過多贅述)。
為了充分利用物理資源、快速擴容同步節點、擁抱雲原生,決定使用k8s部署otter。
otter的專案整體上自成一體,出於改造成本考慮,儘量在專案已有基礎上,做一些適配,不改動原始碼。
本文將重點分享對於otter適配k8s部署的改造過程,有不當之處,還請多多指教。
涉及到幾個核心內容:
- otter基本架構
- dockerfile編寫
- deployment編寫
- 啟動指令碼改造
- K8s中固定ip/port訪問
2.otter的基本架構
典型管理系統架構,manager(web管理)+node(工作節點)
- manager執行時推送同步配置到node節點
- node節點將同步狀態反饋到manager上
- 基於zookeeper,解決分散式狀態排程的,允許多node節點之間協同工作
- 基於Canal開源產品,獲取資料庫增量日誌資料。當然,otter採用了canal的嵌入式模式,不是獨立的canal節點。
基於以上部署架構,我們只需要將otter-manager和otter-node部署到k8s上。
尤其是otter-node,需要利用k8s實現節點快速水平擴充套件、計算效能彈性擴縮容。
2.Dockerfile編寫
2.1 otter-manager的Dockerfile
otter-manager比較簡單,包括幾個步驟:
- 使用一個centos的基礎映象
- 設定時區
- 建立目錄
- 拷貝下載好的manager.deployer-4.2.18到指定目錄
- 使用啟動startup-new.sh指令碼啟動(這裡對原本的啟動指令碼做了一些改造,後文進行詳述)
具體如下所示:
2.2 otter-node的Dockerfile
otter-node稍微有所不同,根據官方文件說明,需要安裝aria2來做檔案傳輸。
注意注意,由於aria2安裝非常慢,因此,我們需要先安裝aria2作為一個新的基礎映象,然後在新的基礎映象上構建otter-node映象,能大大提高後續映象構建速度。
新的基礎映象如下,命名為 registry.xxx.com/xxx/otter-node-base:1.0。
然後在此基礎上構建新的otter-node映象。
注意,otter-node的配置方式比較特殊,需要先在otter-admin上獲取一個nid,然後才能執行一個otter-node。
所以,我們在dockerfile中以ARG 宣告一個nid,然後在後續構建映象的時候,通過 --docker-arg 傳入nid具體的值。
當然,如果把nid看作一個配置檔案的話,也可以用下文提到的configmap的形式在Deployment中掛載進去
3.Deployment編寫
什麼是Deployment?
k8s的一個Deployment控制器為 Pods 和 ReplicaSets 提供宣告式的更新能力。我們通過編寫Deployment描述期望的目標狀態,然後 Deployment 控制器更改Pods或者ReplicaSets的實際狀態, 使其變為期望狀態。
具體關於Deployment的知識不展開說明,可以參考k8s官方文件。
我們需要部署測試環境與生產環境兩套叢集,而無論是otter-manager還是otter-node,都依賴於讀取 conf/otter.properties 作為配置。
因此,我們需要根據環境,修改不同的otter.properties。
那麼,對於k8s部署來說,可以採用同一份映象,然後在不同環境(k8s的不同namespace)中將otter.properties作為configmap寫入,最後通過volume的形式掛載到pod的指定路徑上。
這裡對幾個名詞做簡單介紹,詳細內容可以參考k8s官方文件。
- Configmap:一種 API 物件,用來將非機密性的資料儲存到健值對中。使用時,Pods可以將其用作環境變數、命令列引數或者儲存卷中的配置檔案。(如果想儲存的資料是機密的,可以使用 Secret,而不是configmap)
- Volume:卷的核心是包含一些資料的一個目錄,Pod 中的容器可以訪問該目錄。 所採用的特定的卷型別將決定該目錄如何形成的、使用何種介質儲存資料以及目錄中存放 的內容。使用卷時, 在 .spec.volumes 欄位中設定為 Pod 提供的卷,並在 .spec.containers[*].volumeMounts 欄位中宣告卷在容器中的掛載位置。
所以,首先在指定環境(namespace中)建立configmap,以otter.properties作為key,以檔案內容作為value。
具體命令如下
kubectl create configmap otter-manager-dev-config --from-file=otter.properties=conf/otter-dev.properties -n otter-system
- 在namespace為otter-system中建立一個名字為otter-manager-dev-config的configmap,其中,以otter.properties作為key,以檔案內容作為value。
產生的configmap如下圖所示
然後,將這個configmap在Deployment中用volume進行引用,然後通過volumeMounts掛載到指定目錄,Deployment具體如下所示。
這裡需要特別注意volumeMounts的路徑覆蓋問題,需要在volumeMounts中配置subPath為具體檔名。
4.啟動指令碼改造
Otter包括兩個部分,管理控制檯manager和工作執行節點node,正常情況下都是用各自的啟動指令碼startup.sh啟動的。
為了適配k8s,我們需要對啟動指令碼做改造,本文以otter-manager的啟動指令碼為例,otter-node也是類似。
將啟動指令碼startup.sh改造為 startup-moon.sh,重點解決兩個問題
- 前臺程式保持執行
- jvm引數自定義改造
4.1 前臺程式保持執行
由於容器中用entrypoint啟動的程式為1號程式,一旦1號程式執行結束,容器就會退出了。
而原本的startup.sh中,用java啟動後,使用 “&” 將java程式轉換為後臺程式,所以startup.sh作為1號程式會很快執行結束,容器就會自動退出了。
所以我們需要將1號程式保持住,不要退出。
這裡考慮了兩個方案:
- Startup.sh指令碼中增加一個前臺程式進行保持,比如 tail -f /dev/null 命令
- 將“&”去掉,讓java啟動後就作為前臺程式一直保持
後來考慮了一下,還是選擇了方案二。主要原因是為了利用pod自動重啟的特性。
如果Java程式意外退出了,那麼方案二就能使得1號程式也結束,然後pod就能自動重啟了。而方案一的話,由於startup.sh指令碼仍然在執行tail,所以即使java程式退出,1號程式也不會結束。
具體修改如下:
最終pod中的程式如圖所示
- 1號程式是啟動指令碼
- 1號程式的子程式是otter的java應用程式(前臺程式)
4.2 虛擬機器大小自定義配置
由於otter專案中,將jvm的啟動引數配置在了start.sh中,不方便進行手動配置。
因此,將start.sh的配置jvm引數的邏輯註釋掉,採用自己配置的環境變數JAVA_OPTIONS進行注入。
這個環境變數的注入方式也比較簡單,就是在上面的Deployment中的env配置的(藍色框部分),方便以後手動修改jvm引數大小而不用修改映象。
5.k8s上固定IP/Port訪問
otter-node的部署中,有個比較特殊的地方。
不同於普通的微服務的無狀態擴充套件,otter-node的部署必須指定nid、ip、port,這種設計據說是為解決單機部署多例項而設計的,允許單機多node指定不同的埠(具體可以參考官方wiki,https://github.com/alibaba/otter/wiki/Node_Quickstart,這裡不展開說明)。
還是直接看看如何在k8s上進行適配吧。
這裡採用了k8s的NodePort進行處理。
NodePort 服務是引導外部流量到你的服務的最原始方式。NodePort,正如這個名字所示,在所有節點(虛擬機器)上開放一個特定埠,任何傳送到該埠的流量都被轉發到對應服務。如下圖所示。
在上面的配置中,可以使用IP1:3000 或者 IP2:3000 或者 IP3:3000 訪問service。
當然,為了保證不繫結特定KVM的IP,我們在前面掛一個SLB服務,通過訪問SLB的 虛擬IP:PORT 的形式訪問。
對於otter部署來說,otter-manager需要兩組 IP:PORT、每個node需要三組 IP:PORT。
注意,由於otter部署中,每個node需要暴露的port都是不同的,所以每次新增一個otter-node,都需要新增三組 IP:PORT。
我們以otter-node為例,來看下NodePort型別的Service的yml檔案吧。
- kind為service
- type為NodePort
- 配置了三組埠。port/targetport都是應用暴露埠,而nodePort是對外訪問埠。
6.總結
經過這樣的改造,我們就能用k8s的部署otter-manager和otter-node了,並且能夠快速擴容節點、彈性使用機器資源。
我們回顧一下其中的關鍵問題和技巧:
- Dockerfile編寫中,可以把環境相關依賴打成一個新的基礎映象,提高後續應用映象的構建速度。
- Dockerfile中,可以通過ARG定義一些構建過程中的變數,進行替換。
- 對於不同環境的配置檔案,可以在不同環境(k8s的namespace)下配置不同的configmap,然後在Deployment檔案中通過volumeMounts的方式掛載進去。
- 對於後臺程式,需要改造為前臺程式使得pod能夠保持
- 對於一些特定的環境變數,可以在Deployment中通過env進行傳入。
其他開源專案如果有需要上k8s的,這些技巧應該都能用上。
如果你有更好的一些方式和技巧分享,歡迎留言交流~~~
看到這裡了,原創不易,來個三連吧!!!你最好看了~
知識碎片重新梳理,構建Java知識圖譜:https://github.com/saigu/JavaKnowledgeGraph (歷史文章查閱非常方便)
相關文章
- 擁抱開源,浪潮將OpenStack之路踐行到底!
- Apache Kyuubi & Celeborn,助力 Spark 擁抱雲原生ApacheSpark
- 阿里雲 Serverless 助力企業全面擁抱雲原生阿里Server
- 如何加速雲原生資料應用?這個開源專案備受關注
- 擁抱雲原生,Fluid 結合 JindoFS:阿里雲 OSS 加速利器UI阿里
- 雲原生領域再添重磅開源專案:騰訊釋出 K8s 多叢集管理開源專案 ClusternetK8S
- 在騰訊雲上部署開源專案
- 全面擁抱雲原生應用研發的拐點已經到來
- 微軟開始擁抱開源社群 exFAT檔案系統向Linux開源微軟Linux
- 擁抱雲原生,作業幫多雲架構實踐之路架構
- Fluid 進入 CNCF Sandbox,加速大資料和 AI 應用擁抱雲原生UI大資料AI
- 擁抱雲原生,騰訊釋出TCSS容器安全服務!CSS
- 擁抱雲原生,騰訊釋出TCSS容器安全服務CSS
- 雲原生那些頂級開源專案,你都用過哪些?
- 擁抱開源,共建生態 - 開源生態與效能提升專場 | CIF 精彩看點
- 擁抱雲原生,EMQ X Kubernetes Operator v1.0 正式釋出MQ
- 【熱門IT技術專案分享】-雲原生應用部署-電商網站網站
- 擁抱 Docker!Laravel 老專案開發環境從 Homestead 遷移到 SailDockerLaravel開發環境AI
- 擁抱開源更省錢「GitHub 熱點速覽」Github
- 大資料擁抱雲原生 HashData助力資管數字化轉型大資料
- 網易雲音樂全面開源一款雲原生應用部署平臺:Horizon
- 雲原生系列2 部署你的第一個k8s應用K8S
- k8s 部署 Java 專案K8SJava
- Fluid: 讓大資料和 AI 擁抱雲原生的一塊重要拼圖UI大資料AI
- K8S 部署 SpringBoot 專案(一篇夠用)K8SSpring Boot
- 如何將專案部署到伺服器上伺服器
- 小白觀察:開源專案如何在雲端生存
- 阿里雲釋出雲原生加速器,攜手生態企業擁抱數字時代阿里
- 擁抱人工智慧競賽,但不要忽略專案審計人工智慧
- GitHub實用開源專案Github
- 擁抱智慧,IT運維將有哪些變化?運維
- 螞蟻金服 3 個專案進入 CNCF 雲原生全景圖 | 開源
- 重磅!阿里巴巴開源首個邊緣計算雲原生專案 OpenYurt阿里
- 擁抱未來:GPT-4將如何改變我們的世界GPT
- 重磅 | 騰訊雲服務網格開源專案 Aeraki Mesh 加入 CNCF 雲原生全景圖
- Atlas是一個為雲原生應用程式構建的開源部署管道平臺
- 如何擁有專案經驗
- 雲原生時代,應用架構將如何演進?應用架構