本文作者:YashanDB中級服務工程師鮑健昕
為什麼需要Docker部署資料庫
常規使用 yasboot 部署資料庫的方法,操作流程複雜,需要配置許多配置檔案以及環境變數,不同使用者使用的環境不同,那麼環境配置也會存在差異,每當更換機器或者有新系統開發時都要就要重複不熟⼀次。
使用 Docker 後,只需要⼀次配置好環境,換到別的機器上就可以一鍵部署好,能夠大大簡化操作。Docker 容器與虛擬機器不同,不需要捆綁⼀整套作業系統,只需要軟體工作所需的庫資源和設定。系統因此而變得高效輕量並保證部署在任何環境中的軟體都能始終如一地執行。
什麼是資料庫映象與容器
資料庫映象(image)是一種輕量級、可執行的獨立軟體包,它包含執行資料庫所需的所有內容,把作業系統、資料庫打包好形成⼀個可交付的執行環境,這個打包好的執行環境就是image映象檔案。只有透過這個映象檔案才能生成 Docker 容器例項,類似 Java 中 new 出來一個物件。資料庫映象是分層的,以 MySQL 映象為例,在下載映象的過程中是一層層下載的:
Docker File是什麼
Dockerfile 是⼀個用來構建映象的文字檔案,文字內容包含了⼀條條構建映象所需的指令和說明。
• FROM:定製的映象都是基於 FROM 的映象,FROM centos:8.1.1911 表示後續的操作都是基於
centos:8.1.1911。
• COPY:從上宿主機中複製檔案或者目錄到映象中。
• RUN:構建映象的過程中,在基礎映象命令列中執行的命令。
• CMD:建立容器時的預設命令,與RUN的區別在於,CMD是建立容器時執行,而RUN是在構建映象時執行,程式執行結束,容器也就結束。
• ENV:在容器內設定環境變數,設定環境變數,可以在後續的指令中使用這個環境變數。
怎麼用Docker File構建YashanDB映象
點選檢視程式碼
FROM centos:8.1.1911
RUN rm -rf /etc/yum.repos.d/*
COPY CentOS-Base.repo /etc/yum.repos.d/
RUN yum -y install glibc-locale-source glibc-langpack-en net-tools \
&& yum clean all \
&& ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \
&& localedef -c -f UTF-8 -i en_US en_US.UTF-8 \
&& echo 'export LANG=zh_CN.utf8' > /etc/locale.conf \
&& echo 'export LANG=zh_CN.utf8' >> /etc/profile \
&& echo 'Asia/Shanghai' > /etc/timezone \
&& source /etc/profile \
&& echo "root:123456" | chpasswd \
&& groupadd -g 1000 YASDBA \
&& useradd yashan -G YASDBA \
&& echo "yashan:yasdb_123" | chpasswd \
&& echo 'yashan ALL=(ALL:ALL) NOPASSWD:ALL' >> /etc/sudoers
COPY yashandb-23.2.1.100-linux-x86_64.tar.gz /home/yashan
COPY initYashanDB.sh /home/yashan/
RUN chown yashan:yashan /home/yashan/*
USER yashan
WORKDIR /home/yashan/
ENV YASDB_HOME /home/yashan/
ENV YASDB_DATA /home/yashan/yashandb/yasdb_data/db-1-1
ENV PATH $PATH:${YASDB_HOME}/bin
ENV LD_LIBRARY_PATH $LD_LIBRARY_PATH:${YASDB_HOME}/lib
RUN cd ~ \
&& tar -zxf yashandb-*.tar.gz \
&& rm -rf yashandb-* \
&& echo "YASDB_HOME=${YASDB_HOME}" >> ~/.bashrc \
&& echo "YASDB_DATA=${YASDB_DATA}" >> ~/.bashrc \
&& echo "PATH=\$PATH:\${YASDB_HOME}/bin" >> ~/.bashrc \
&& echo "LD_LIBRARY_PATH=\$LD_LIBRARY_PATH:\${YASDB_HOME}/lib" >> ~/.bashrc
CMD ["./initYashanDB.sh"]
點選檢視程式碼
#!/bin/bash
cd /home/yashan/bin
yasboot package se gen --cluster yashandb -L --data-path $YASDB_DATA --begin-port 1688 --node 1
yasboot package install -t hosts.toml -i /home/yashan/yashandb-23.2.1.100-linux-x86_64.tar.gz
yasboot cluster deploy -t yashandb.toml
yasboot cluster password set -n yasdb_123 -c yashandb
while pgrep -x "yasdb" >/dev/null; do
echo "check pgrep success, goto sleep!"
sleep 360000
done
注意點:
-
容器掛載宿主機目錄的時候,是覆蓋操作,如果宿主機目錄是空的,會清空容器內的目錄,所以將initYashanDB放在了CMD中,而不是RUN中
-
CMD執行結束,容器也就會退出,所以在./initYashanDB.sh中最後新增了迴圈,避免CMD中的指令碼執行完
點選檢視程式碼
docker build -t registry.cn-shenzhen.aliyuncs.com/jesseatyashan/yashandb:X . --no-cache
docker run -itd -p 1688:1688 -u 1000:1000 registry.cn-shenzhen.aliyuncs.com/jesseatyashan/yashandb:X
docker exec -it b bash
YashanDB Docker映象的釋出
在阿里雲登入後,可以在阿里雲容器映象服務ACR中建立一個個人例項,然後將資料庫映象按照下面的操作釋出到阿里雲上:
執行下面的命令將本地構建的映象釋出推送至遠端:
點選檢視程式碼
[root@localhost YLab]# docker push registry.cn-shenzhen.aliyuncs.com/jesseatyashan/yashandb:X
The push refers to repository [registry.cn-shenzhen.aliyuncs.com/jesseatyashan/yashandb]
c781b4b05ce5: Pushing [=> ] 15.93MB/518MB
5f70bf18a086: Layer already exists
2e8a116c1b21: Pushing [> ] 3.869MB/198.7MB
c499bfff3090: Pushed
6326c26c34ad: Pushing [> ] 2.754MB/198.7MB
5f69ac739040: Pushing [===> ] 4.385MB/64.98MB
825123261bfe: Waiting
3e0aca5b6ad0: Waiting
0683de282177: Waiting
映象釋出成功後可以在映象倉庫中找到這個映象:
YashanDB容器啟動新增初始化指令碼
在Docker中,可以使用繫結掛載來實現容器內部檔案與宿主機檔案系統中檔案的對映。以數聯網一體機專案的應用場景為例,客戶希望容器在資料庫啟動之後,能夠自動執行指定資料夾中的SQL檔案初始化資料庫環境,這個SQL檔案可能會發生變更,如果沒有檔案系統對映的話,那麼就需要為每套SQL檔案單獨構建一個映象,有了檔案系統對映之後,可以將SQL檔案放在宿主機的指定資料夾中,將這個資料夾與容器內的資料夾對映。
點選檢視程式碼
#!/bin/bash
cd /home/yashan/bin
yasboot package se gen --cluster yashandb -L --data-path $YASDB_DATA --begin-port 1688 --node 1
yasboot package install -t hosts.toml -i /home/yashan/yashandb-23.2.1.100-linux-x86_64.tar.gz
yasboot cluster deploy -t yashandb.toml
yasboot cluster password set -n yasdb_123 -c yashandb
while pgrep -x "yasdb" >/dev/null; do
echo "check pgrep success, goto sleep!"
sleep 360000
done
DIRECTORY="/home/yashan/sql"
if [ ! -d "$DIRECTORY" ]; then
echo "Error: SQL directory '$DIRECTORY' does not exist."
exit 1
fi
if [ -f "${DIRECTORY}/ignoresql.pid" ] ; then
echo "Ignore executing sql files"
else
for sql_file in $(ls -v "$DIRECTORY"/*.sql); do
if [ -f "$sql_file" ] ; then
echo "Processing ${sql_file}..."
${YASDB_HOME}/bin/yasql sys/yasdb_123 -f $sql_file
if [ $? -ne 0 ]; then
echo "Error executing yasql on $sql_file"
exit 1
fi
fi
done
echo "ignore" > "${DIRECTORY}/ignoresql.pid"
echo "All sql files processed."
fi
while pgrep -x "yasdb" >/dev/null; do
echo "check pgrep success, goto sleep!"
sleep 360000
done
點選檢視程式碼
docker run -itd -p 1688:1688 -v /home/yashan/sql:/home/yashan/sql:rw registry.cn-shenzhen.aliyuncs.com/jesseatyashan/yashandb:X
YashanDB容器資料庫資料檔案的複用
數聯網一體機專案的應用場景中,客戶希望在容器啟動時複用以往容器的yasdb_data,此時不能再用yasboot的方式部署資料庫,而應該使用以往的指令碼部署方式:
點選檢視程式碼
#!/bin/bash
cd ~/scripts
bash /home/yashan/scripts/install.sh
bash /home/yashan/scripts/initDB.sh
.....
while pgrep -x "yasdb" >/dev/null; do
echo "check pgrep success, goto sleep!"
sleep 360000
done
點選檢視程式碼
#!/bin/bash
#initDB.sh
if [ -f "$YASDB_DATA"/config/yasdb.ini ]; then
yashan_exists=1
else
yashan_exists=0
fi
FILE_PATH=$(dirname "$(readlink -f "$0")")
YASDB_TEMP_FILE="${FILE_PATH}/.temp.ini"
INSTALL_INI_FILE="${FILE_PATH}/install.ini"
YASDB_PASSWORD="yasdb_123"
# shellcheck disable=SC1090
source "${YASDB_TEMP_FILE}"
YASDB_ENV_FILE="${YASDB_HOME}/conf/yasdb.bashrc"
YASDB_HOME_BIN_PATH="${YASDB_HOME}/bin"
YASDB_BIN="${YASDB_HOME_BIN_PATH}/yasdb"
YASQL_BIN="${YASDB_HOME_BIN_PATH}/yasql"
YASPWD_BIN="${YASDB_HOME_BIN_PATH}/yaspwd"
# shellcheck disable=SC1090
source "${YASDB_ENV_FILE}"
if [ ! -d "$YASDB_HOME" ] || [ ! -d "$YASDB_DATA" ]; then
echo -e "Software installation \"./install.sh\" is not performed."
exit 1
fi
if [ $yashan_exists -eq 0 ]; then
e_i=$(sed -n '$=' "$INSTALL_INI_FILE")
s_i=$(sed -n -e '/\<instance\>/=' "$INSTALL_INI_FILE")
n_i=$((s_i + 1))
sed -n "${n_i},${e_i} p" "$INSTALL_INI_FILE" >>"$YASDB_DATA"/config/yasdb.ini
##建立密碼檔案
if [ ! -f "$YASDB_HOME/admin/yasdb.pwd" ]; then
"$YASPWD_BIN" file="$YASDB_HOME"/admin/yasdb.pwd password="$YASDB_PASSWORD"
else
rm -f "$YASDB_HOME"/admin/yasdb.pwd
"$YASPWD_BIN" file="$YASDB_HOME"/admin/yasdb.pwd password="$YASDB_PASSWORD"
fi
cp "$YASDB_HOME"/admin/yasdb.pwd "$YASDB_DATA"/instance/yasdb.pwd
REDOFILE="("
for ((i = 0; i < "$REDO_FILE_NUM"; i++)); do
if [ $i == $((REDO_FILE_NUM - 1)) ]; then
REDOFILE=${REDOFILE}"'redo${i}'"" size $REDO_FILE_SIZE)"
else
REDOFILE=${REDOFILE}"'redo${i}'"" size $REDO_FILE_SIZE,"
fi
done
fi
##建立資料庫
START_LOG_FILE="$YASDB_DATA/log/start.log"
rm -rf "${START_LOG_FILE}"
"${YASDB_BIN}" nomount -D "$YASDB_DATA" >"$START_LOG_FILE" 2>&1 &
i=0
while ((i < 5))
do
sleep 2
# shellcheck disable=SC2002 disable=SC2126
alive=$(cat "$START_LOG_FILE" | grep "Instance started" | wc -l)
if [ "$alive" -ne 0 ]; then
echo "process started!"
break
fi
i=$((i+1))
done
if [ "$i" -eq "5" ];then
echo "start process failed. read $START_LOG_FILE"
cat "$START_LOG_FILE"
exit 1
fi
if [ $yashan_exists -eq 0 ]; then
"${YASQL_BIN}" sys/$YASDB_PASSWORD >>"$START_LOG_FILE" <<EOF
create database yasdb CHARACTER SET $NLS_CHARACTERSET logfile $REDOFILE;
exit;
EOF
fi
if [ $yashan_exists -eq 1 ]; then
$YASQL_BIN sys/$YASDB_PASSWORD -c "alter database open"
fi
i=0
while ((i < 60))
do
sleep 1
alive=$($YASQL_BIN sys/$YASDB_PASSWORD -c "select open_mode from v\$database" | grep -c READ_WRITE)
if [ "$alive" -eq 1 ]; then
echo "Database open succeed !"
break
fi
i=$((i+1))
done
if [ "$i" -eq "60" ];then
echo "Failed ! please check logfile $START_LOG_FILE ."
exit 1
fi
if [ $yashan_exists -eq 0 ]; then
##建立樣例資料:sales
if [ "$INSTALL_SIMPLE_SCHEMA_SALES" == 'Y' ] || [ "$INSTALL_SIMPLE_SCHEMA_SALES" == 'y' ]; then
"${YASQL_BIN}" sys/$YASDB_PASSWORD -f "$YASDB_HOME"/admin/simple_schema/sales.sql >>"$START_LOG_FILE"
fi
fi
exit 0