【技術解析】如何用Docker實現SequoiaDB叢集的快速部署

巨杉資料庫發表於2019-02-22

1. 背景

以Docker和Rocket為代表的容器技術現在正變得越來越流行,它改變著公司和使用者建立、釋出、執行分散式應用的方式,在未來5年將給雲端計算行業帶來它應有的價值。它的誘人之處在於:

1)資源獨立、隔離

資源隔離是雲端計算平臺的最基本需求。Docker通過Linux namespace, cgroup限制了硬體資源與軟體執行環境,與宿主機上的其他應用實現了隔離,做到了互不影響。不同應用或服務以“集裝箱”(container)為單位裝“船”或卸“船”,“集裝箱船”(執行container的宿主機或叢集 )上,數千數萬個“集裝箱”排列整齊,不同公司、不同種類的“貨物”(執行應用所需的程式、元件、執行環境、依賴)保持獨立。

2)環境的一致性

開發工程師完成應用開發後build一個docker image,基於這個image建立的container像是一個集裝箱,裡面打包了各種“散件貨物”(執行應用所需的程式、元件、執行環境、依賴)。無論這個集裝箱在哪裡:開發環境、測試環境、生產環境,都可以確保集裝箱裡面的“貨物”種類與個數完全相同,軟體包不會在測試環境缺失,環境變數不會在生產環境忘記配置,開發環境與生產環境不會因為安裝了不同版本的依賴導致應用執行異常。這樣的一致性得益於“發貨”(build docker image)時已經密封到“集裝箱”中,而每一個環節都是在運輸這個完整的、不需要拆分合並的“集裝箱”。

3)輕量化

相比傳統的虛擬化技術(VM),使用docker在cpu, memory, disk IO, network IO上的效能損耗都有同樣水平甚至更優的表現。Container的快速建立、啟動、銷燬受到很多讚譽。

4)Build Once, Run Everywhere

這個特性著實吸引了很多人,“貨物”(應用)在“汽車”、“火車”、“輪船”(私有云、公有云等服務)之間遷移交換時,只需要遷移符合標準規格和裝卸方式的“集裝箱”(docker container),削減了耗時費力的人工“裝卸”(上線、下線應用),帶來的是巨大的時間人力成本節約。這使未來僅有少數幾個運維人員運維超大規模裝載線上應用的容器叢集成為可能,如同60年代後少數幾個機器操作員即可在幾小時內連裝帶卸完一艘萬級集裝箱船。

容器技術現在也被廣泛應用於資料庫領域。它的“Build Once, Run Everywhere”的特性大大減少了花在安裝配置資料庫環境上的時間,因為即使對於從事資料庫多年的DBA而言,安裝配置資料庫環境依舊是一項看似簡單但卻經常不順利的工作。當然,容器技術的其他優勢也被很好的應用在資料庫的使用中。

SequoiaDB作為一款優秀的國產分散式NewSQL資料庫,已經得到了越來越多使用者的認可。本文以Docker為例,著重介紹如何用Dockerfile快速構建SequoiaDB映象,以及如何利用容器快速搭建和啟動SequoiaDB叢集供應用系統使用。

2. 構建SequoiaDB映象

如何安裝docker以及配置映象倉庫不是本文的重點,網上有很多相關的技術文章。需要指出的是本文采用阿里雲映象倉庫,因為將映象上傳到Docker官方倉庫的速度實在不敢恭維。如何註冊和使用阿里雲映象倉庫,可以參考文章(www.jb51.net/article/123…)。

STEP 1:建立Dockerfile,內容如下,只需要幾行簡單的指令即可

# Sequoiadb DOCKERFILES PROJECT

# --------------------------

# This is the Dockerfile for Sequoiadb
2.8.4

# 

# REQUIRED FILES TO BUILD THIS
IMAGE

#
----------------------------------

# (1)
sequoiadb-2.8.4-linux_x86_64-enterprise-installer.run

# (2) installSDB.sh

#

# HOW TO BUILD THIS IMAGE

# -----------------------

# Put all downloaded files in the
same directory as this Dockerfile

# Run: 

#      $ sudo docker build -t sequoiadb:2.8.4 . 

#

# Pull base image

FROM ubuntu

 

# Environment variables required
for this build

ENV
INSTALL_BIN_FILE="sequoiadb-2.8.4-linux_x86_64-enterprise-installer.run"
\

   
INSTALL_SDB_SCRIPT="installSDB.sh" \

   
INSTALL_DIR="/opt/sequoiadb"

         

# Copy binaries

ADD $INSTALL_BIN_FILE
$INSTALL_SDB_SCRIPT $INSTALL_DIR/

 

# Install SDB software binaries

RUN chmod 755 $INSTALL_DIR/$INSTALL_SDB_SCRIPT
\

   
&& $INSTALL_DIR/$INSTALL_SDB_SCRIPT \

    && rm
$INSTALL_DIR/$INSTALL_SDB_SCRIPT

 

其中installSDB.sh指令碼內容如下:

chmod 755
$INSTALL_DIR/$INSTALL_BIN_FILE

$INSTALL_DIR/$INSTALL_BIN_FILE
--mode unattended 

rm $INSTALL_DIR/$INSTALL_BIN_FILE

echo 'service sdbcm start'
>> /root/.bashrc複製程式碼


需要注意的是本例採用Sequoiadb企業版2.8.4,您也可以從巨杉官網下載社群版(選擇tar包,下載然後解壓),替換本例中的介質名稱。

巨杉官網下載地址:http://download.sequoiadb.com/cn/

STEP 2:建立映象

root使用者執行:

docker build -t
sequoiadb:2.8.4 .複製程式碼

如果是普通使用者,需要使用sudo:

sudo docker build -t
sequoiadb:2.8.4 .複製程式碼

STEP3:登陸阿里雲映象倉庫

docker login --username=xxx
registry.cn-hangzhou.aliyuncs.com複製程式碼

其中xxx為您在阿里雲註冊的賬號。

STEP4:檢視本地sequoiadb映象id

docker images複製程式碼

STEP5:標記本地映象,將其歸入阿里雲倉庫

docker tag 04dc528f2a6f registry.cn-hangzhou.aliyuncs.com/508mars/sequoiadb:latest複製程式碼

其中04dc528f2a6f是筆者本地sequoiadb映象id,新的標記格式有一定要求,registry.cn-hangzhou.aliyuncs.com為阿里雲倉庫地址,508mars是筆者在阿里雲的使用者名稱,sequoiadb是映象名,latest是tag。

STEP6:提交sequoiadb映象到映象庫

docker push registry.cn-hangzhou.aliyuncs.com/508mars/sequoiadb:latest複製程式碼

3. 利用容器啟動SequoiaDB叢集

Docker的網路預設採用bridge模式,採用bridge模式的容器有如下特點:

1)同一宿主機的容器之間可以互相ping通

2)不同宿主機的容器之間互相ping不同

但是SequoiaDB叢集要求所有節點之間是可以互通的,所以如果執行SequoiaDB的容器跑在不同宿主機上,docker的預設網路模式顯然不合適。有很多種方法可以解決不同宿主機容器之間的連通性問題,本文只介紹weave虛擬網路這個解決方案,因為weave同時提供了一個DNS server的功能,有了該功能,在利用容器部署SequoiaDB叢集時不再需要修改各個容器內部的/etc/hosts,大大簡化了自動化部署的步驟。

STEP1:安裝weave網路

curl -s -L git.io/weave -o
/usr/local/bin/weave

chmod a+x /usr/local/bin/weave複製程式碼

需要在所有宿主機安裝,筆者採用了三臺虛擬機器作為宿主機:sdb1, sdb2和sdb3。

STEP2:啟動weave網路

weave launch複製程式碼

第一次啟動時會下載weave映象。

STEP3:從阿里雲倉庫下載sequoiadb映象

docker pull registry.cn-hangzhou.aliyuncs.com/508mars/sequoiadb複製程式碼

STEP4:在所有宿主機建立docker的掛載卷

cd /home/sdbadmin

mkdir -p data/disk1
data/disk2 data/disk3

mkdir -p conf/local

chmod -R 777 data

chmod -R 777 conf複製程式碼

掛載卷的位置可以自定義,但總的來說需要建立兩大類掛載卷,一類用來存放集合資料,如本例中的data/disk1, data/disk2, data/disk3,一類用來存放節點配置資訊,如本例中的conf/local。這樣即使容器被誤刪了,依舊可以啟動一個新容器來扮演被誤刪的容器的角色。

STEP5:啟動容器

sdb1:

weave stop

weave launch

eval $(weave env)

docker run -dit --name
sdbserver1 -p 11810:11810 -v /home/sdbadmin/data:/data -v
/home/sdbadmin/conf/local:/opt/sequoiadb/conf/local
registry.cn-hangzhou.aliyuncs.com/508mars/sequoiadb複製程式碼

sdb2:

weave stop

weave launch 192.168.17.132

eval $(weave env)

docker run -dit --name
sdbserver2 -p 11810:11810 -v /home/sdbadmin/data:/data -v
/home/sdbadmin/conf/local:/opt/sequoiadb/conf/local
registry.cn-hangzhou.aliyuncs.com/508mars/sequoiadb複製程式碼

sdb3:

weave stop

weave launch 192.168.17.132

eval $(weave env)

docker run -dit --name
sdbserver3 -p 11810:11810 -v /home/sdbadmin/data:/data -v
/home/sdbadmin/conf/local:/opt/sequoiadb/conf/local
registry.cn-hangzhou.aliyuncs.com/508mars/sequoiadb複製程式碼

其中192.168.17.132是sdb1的IP地址,11810是對外暴露的叢集訪問埠。宿主機存放節點配置資訊的卷必須掛到容器的/opt/sequoiadb/conf/local目錄,存放表資料的卷可以掛載到使用者自定義的目錄,但是叢集一旦建立後,不可更改。啟動容器的時候必須指定機器名,因為在構建完叢集后,機器名會被儲存在SequoiaDB的系統表中,節點的機器名與系統表中不一致會導致無法加入到叢集。在使用weave的場景下,建議使用--name選項,不要使用--hostname設定機器名。後者會阻止weave將機器名新增到DNS伺服器,weave會自動根據--name的值來設定機器名,同時在機器名後增加weave.local域名,並新增到的DNS伺服器。

STEP6:將建立SequoiaDB叢集的指令碼拷貝到容器中

docker cp create_cluster.js
sdbserver1:/data複製程式碼

create_cluster.js內容如下:

var array_hosts =
["sdbserver1.weave.local", "sdbserver2.weave.local",
"sdbserver3.weave.local"];

var array_dbroot =
["/data/disk1/sequoiadb/database","/data/disk2/sequoiadb/database","/data/disk3/sequoiadb/database"];

var port_sdbcm = "11790";

var port_temp_coord =
"18888";

var cataloggroup = {gname:"SYSCatalogGroup",
gport:"11820", ghosts:["sdbserver1.weave.local",
"sdbserver2.weave.local", "sdbserver3.weave.local"]};

var array_coordgroups = [

        {gname:"SYSCoord",
gport:"11810", ghosts:["sdbserver1.weave.local",
"sdbserver2.weave.local", "sdbserver3.weave.local"]}

];

var array_datagroups = [

        {gname:"dg1",
gport:"11830", ghosts:["sdbserver1.weave.local",
"sdbserver2.weave.local", "sdbserver3.weave.local"],
goptions:{transactionon:true}}

       ,{gname:"dg2",
gport:"11840", ghosts:["sdbserver1.weave.local",
"sdbserver2.weave.local", "sdbserver3.weave.local"],
goptions:{transactionon:true}}

       ,{gname:"dg3",
gport:"11850", ghosts:["sdbserver1.weave.local",
"sdbserver2.weave.local", "sdbserver3.weave.local"],
goptions:{transactionon:true}}

];

var array_domains = [

        {dname:"allgroups",
dgroups:["dg1", "dg2", "dg3"],
doptions:{AutoSplit:true}}

];

 

println("啟動臨時協調節點");

var oma = new
Oma(array_coordgroups[0].ghosts[0], port_sdbcm);

oma.createCoord(port_temp_coord,
array_dbroot[0]+"/coord/"+port_temp_coord);

oma.startNode(port_temp_coord);

 

println("建立編目節點組:"+cataloggroup.ghosts[0]+"   "+cataloggroup.gport+"   
"+array_dbroot[0]+"/cata/"+cataloggroup.gport);

var db = new Sdb(array_coordgroups[0].ghosts[0],
port_temp_coord);

db.createCataRG(cataloggroup.ghosts[0],
cataloggroup.gport, array_dbroot[0]+"/cata/"+cataloggroup.gport);

var cataRG =
db.getRG("SYSCatalogGroup");

for (var i in cataloggroup.ghosts)
{

        if (i==0) {continue;}

   
println("建立編目節點: "+cataloggroup.ghosts[i]+"  "+cataloggroup.gport+"   
"+array_dbroot[0]+"/cata/"+cataloggroup.gport);

        var catanode =
cataRG.createNode(cataloggroup.ghosts[i], cataloggroup.gport,
array_dbroot[0]+"/cata/"+cataloggroup.gport);

 
      catanode.start();

}

 

println("建立協調節點組");

var db = new
Sdb(array_coordgroups[0].ghosts[0], port_temp_coord);

var coordRG = db.createCoordRG();

for (var i in array_coordgroups) {

        for (var j in
array_coordgroups[i].ghosts) {

                println("建立協調節點組:"+array_coordgroups[i].ghosts[j]+"   
"+array_coordgroups[i].gport+"   
"+array_dbroot[0]+"/coord/"+array_coordgroups[i].gport);

               
coordRG.createNode(array_coordgroups[i].ghosts[j],
array_coordgroups[i].gport, array_dbroot[0]+"/coord/"+array_coordgroups[i].gport);

        }

}

coordRG.start();

 

println("刪除臨時協調節點")

var oma = new
Oma(array_coordgroups[0].ghosts[0], port_sdbcm);

oma.removeCoord(port_temp_coord);

 

println("建立資料節點組")

var db = new Sdb(array_coordgroups[0].ghosts[0],
array_coordgroups[0].gport);

var k=0;

for (var i in array_datagroups) {

        var dataRG =
db.createRG(array_datagroups[i].gname);

        for (var j in
array_datagroups[i].ghosts) {

                println("建立資料節點:"+array_datagroups[i].gname+"   
"+array_datagroups[i].ghosts[j]+"   "+array_datagroups[i].gport+"    "+array_dbroot[k]+"/data/"+array_datagroups[i].gport+"    "+array_datagroups[i].goptions)

               
dataRG.createNode(array_datagroups[i].ghosts[j], array_datagroups[i].gport,
array_dbroot[k]+"/data/"+array_datagroups[i].gport,
array_datagroups[i].goptions);

        }

        dataRG.start();

        k++;

}

 

println("建立域");

var db = new
Sdb(array_coordgroups[0].ghosts[0], array_coordgroups[0].gport);

for (var i in array_domains) {

        println("建立域:"+array_domains[i].dname+"   "+array_domains[i].dgroups+"    "+array_domains[i].doptions)

        db.createDomain(array_domains[i].dname,
array_domains[i].dgroups, array_domains[i].doptions );

}複製程式碼

STEP7:建立SequoiaDB叢集

docker exec sdbserver1 su -
sdbadmin -c "sdb -f /data/create_cluster.js"複製程式碼

至此SequoiaDB叢集建立並啟動完成,後面再啟動容器的時候叢集會自動啟動。

4. 結論

SequoiaDB利用容器技術很好的實現了叢集快速部署,大大簡化了初學者安裝部署的難度。後期筆者還會在SequoiaDB映象製作上做一些優化,因為目前做出來的映象有點大,主要根源是採用ADD或COPY命令將安裝介質拷貝到Docker容器中會生成一個新的映象image1,最終生成的映象image2中雖然刪除了安裝介質,但是它在image1之上,所以image2的大小依舊包含安裝介質。最好採用ADD拷貝tar包(ADD會自動解壓)或者採用類似如下的方式:

RUN mkdir -p /usr/src/things
\

    && curl -SL
http://example.com/big.tar.xz \

    | tar -xJC /usr/src/things \

    && make -C /usr/src/things all複製程式碼

<END>


相關文章