iT邦幫忙

2024 iThome 鐵人賽

DAY 16
0
Odoo

Odoo 部署策略系列 第 16

odoo 建立一步到位:自動化資料庫初始流程

  • 分享至 

  • xImage
  •  

⚠️ 資訊:這篇文章的內容已在後續文章中被撤銷 ⚠️

🚫 請參考後續更新的內容,避免使用本篇提到的方法。 🚫

今天我們要改善的地方跟昨天一樣, entrypoint.sh,再加上裡面的 wait-for-psql.py

最初的問題點

在我還在初步調整 Dockerfile 的時候,每次清空資料庫後第一次啟動 odoo,都會出現錯誤訊息並且啟動失敗:

ERROR odoo odoo.modules.loading: Database odoo not initialized, you can force it with `-i base`

解決方法就是根據錯誤訊息,手動啟動 odoo 並加上 -i base 參數,才能成功啟動。


解決方案

雖然手動加上 -i 參數「一次」可以緩解問題,但這顯然不是一個好的部署實踐。接下來我想到最直覺的解決方案是:先檢查資料庫狀態,如果尚未初始化,就自動執行初始化,然後再重新啟動。

首先,我們看看原先的 entrypoint.sh

# 根據傳入的參數決定如何啟動 odoo
case "$1" in
    -- | odoo)
        shift
        if [[ "$1" == "scaffold" ]] ; then
            exec odoo "$@"  # 如果傳入的參數是 scaffold,直接執行 odoo scaffold 命令
        else
            wait-for-psql.py ${DB_ARGS[@]} --timeout=30  # 等待 PostgreSQL 就緒,然後啟動 odoo
            exec odoo "$@" "${DB_ARGS[@]}"
        fi
        ;;
    -*)
        wait-for-psql.py ${DB_ARGS[@]} --timeout=30  # 同樣等待資料庫準備就緒,然後啟動 odoo
        exec odoo "$@" "${DB_ARGS[@]}"
        ;;
    *)
        exec "$@"  # 如果傳入的不是 odoo 相關指令,則執行傳入的指令
esac

接著,修改後的 entrypoint.sh

case "$1" in
    odoo)
        shift # 移除 $1("odoo")

        if [[ "$1" == "scaffold" ]]; then
            echo "$HEADER Running scaffold command..."
            echo "$HEADER Executing: $ODOO_BIN $@"
            exec $ODOO_BIN "$@"

        else
            # 新增資料庫狀態檢查:替換了 wait-for-psql.py,改用 check-db-status.py,並在啟動前檢查資料庫是否已初始化
            echo "$HEADER Checking PostgreSQL readiness and database initialization..."
            check-db-status.py "${DB_ARGS[@]}" --timeout=30
            result=$?
            if [ $result -eq 2 ]; then
                # 自動初始化資料庫:如果 check-db-status.py 返回狀態碼 2(表示資料庫尚未初始化),則執行 odoo -i base --stop-after-init,自動初始化資料庫
                echo "$HEADER Database not initialized. Running initialization..."
                echo "$HEADER Executing: $ODOO_BIN -i base --stop-after-init ${DB_ARGS[@]}"
                exec $ODOO_BIN -i base --stop-after-init "${DB_ARGS[@]}"
            fi
            # 資料庫已初始化,啟動 odoo
            echo "$HEADER Database is initialized. Starting odoo..."
            echo "$HEADER Executing: $ODOO_BIN $@ ${DB_ARGS[@]}"
            exec $ODOO_BIN "$@" "${DB_ARGS[@]}"
        fi
        ;;
    *)
        echo "$HEADER Executing custom command: $@"
        echo "$HEADER Executing: $@"
        exec "$@"
        ;;
esac

接下來,修改後的 check-db-status.py

#!/usr/bin/env python3
import argparse
import psycopg2
import sys
import time

def check_db_initialized(conn):
    try:
        with conn.cursor() as cur:
            # 新增資料庫初始化檢查:透過查詢 ir_model 表,判斷資料庫是否已初始化
            cur.execute("SELECT 1 FROM ir_model LIMIT 1;")
        return True  # 資料庫已初始化
    except psycopg2.Error:
        return False  # 資料庫尚未初始化

if __name__ == '__main__':
    arg_parser = argparse.ArgumentParser()
    arg_parser.add_argument('--db_host', required=True)
    arg_parser.add_argument('--db_port', required=True)
    arg_parser.add_argument('--db_user', required=True)
    arg_parser.add_argument('--db_password', required=True)
    arg_parser.add_argument('--database', required=False)
    arg_parser.add_argument('--timeout', type=int, default=5)

    args = arg_parser.parse_args()

    start_time = time.time()
    while (time.time() - start_time) < args.timeout:
        try:
            # 連線參數調整:使用傳入的資料庫資訊嘗試連線,並在指定的超時時間內不斷重試
            conn = psycopg2.connect(user=args.db_user, host=args.db_host, port=args.db_port, password=args.db_password, dbname=args.database)
            error = ''
            db_initialized = check_db_initialized(conn)
            break
        except psycopg2.OperationalError as e:
            error = e
        else:
            conn.close()
        time.sleep(1)

    if error:
        print("Database connection failure: %s" % error, file=sys.stderr)
        sys.exit(1)

    if not db_initialized:
        # 自訂狀態碼:如果資料庫尚未初始化,程式以狀態碼 2 結束,供 entrypoint.sh 判斷
        sys.exit(2)  # Custom exit code to indicate uninitialized database

    sys.exit(0)

這樣一來,新部署的環境只要啟動後就會自動初始化資料庫,然後重新啟動,完成部署。


跳過手動步驟

後來,雖然直接啟動失敗的現象在我修改 Dockerfile 與官方高度相似後已經不再出現,而是會帶我到 /web/database/selector 頁面,需要手動填寫資料庫名稱、管理員密碼等資訊來建立資料庫。但這個功能剛好也可以讓我們跳過這個手動填寫的步驟,直接使用設定檔中的資料自動初始化,對我來說非常方便。


上一篇
entrypoint.sh 環境變數調整:微改善 odoo 部署流程
下一篇
開發 odoo module 的小工具:快速參數調整並重啟
系列文
Odoo 部署策略30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言