Oracle Database in Docker

雖然筆者之前有提過,Docker並不是萬能,Docker在管理有狀態應用(Stateful Application)的情況下,只能走單機路線。但因為Docker實在很方便,所以連Oracle Database這類強狀態應用也有出Docker版本。當然,它在預設的情況下,只能在單機下操作。

不過即使在單機操作下,還是有一些跟其他Docker Image有差異的地方,需要特別拿出來聊聊。

假設根據官方的教學,跑起了一個oracle19c的Docker Container。再查看當中的Process,你會發現有一個內部PID為1的runOracle.sh

sudo docker container exec -it oracle19c top
## top output
##    PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND
##      1 oracle    20   0   11712   2756   2480 S   0.0  0.0   0:00.04 runOracle.sh
sudo docker container top oracle19c
## UID                 PID                 PPID                C                   STIME               TTY                 TIME                CMD
## 54321               1069154             1069135             0                   Sep14               ?                   00:00:00            /bin/bash /opt/oracle/runOracle.sh

在Docker中這個PID為1的Process是很重要的,它是判斷整個Container有沒有運行的依據。它就是當初在Docker Image中Entrypoint或CMD指定的那個指令生起的Process。Docker daemon要進行停止指令,要停止container時,也是對著PID為1的那個process來處理。

一般的情況下,如果PID為1的那個process可以無腦地停了、重開,那一切都好辦。但在Oracle Database的情況下,就不適合。因為Database始乎都是有交易概念的(Transaction),它的停止並不是殺了process就了事,它還要考慮HDD操作中,有那些可以被考慮為完成,有那些下次要還原(undo)、重做(redo)。如果殺了process就等於Oracle 的Shutdown Abort,有機會下次開機會,就會有交易異常而且無法決定該如何操作。

大家需要先進入Docker container,經sqlplus進行必要的關閉Database指令。但此時,PID為1的那個process,其實還在進行中,在Docker 層面,它就像是Docker Container還在正常運行中,只是Database離線了。又因為sqlplus關閉Database並不是馬上有結果的,所以在整體關閉時可能需要串連command。就像

# in container
echo "shutdown immediate;" | sqlplus -s / as sysdba && kill 1

# in docker host, by script
sudo docker container exec -it oracle19c /bin/sh -c 'echo "shutdown immediate;" | sqlplus -s / as sysdba' \
	&& sudo docker container stop oracle19c