解決 WebAPI 在容器中的啟動初始化問題
在產(chǎn)品或項目的部署中,如果和下面場景類似,那么本文可能對您有所幫助。
場景
- WebAPI 和 MySql 數(shù)據(jù)部署在同一服務(wù)器(通常是測試環(huán)境)。
- WebAPI 和 MySql 使用 docker-compose 進(jìn)行部署。
- WebAPI 啟動時有一些初始化的操作要做,而初始化需要從 MySql 中獲取數(shù)據(jù)。
問題
- 第一次部署,執(zhí)行 docker-compose up -d 后,WebAPI 不能正常啟動。
- 斷電、或其他原因?qū)е碌姆?wù)器重啟或 docker 重啟,WebAPI 不能正常啟動。
原因
- docker 容器啟動時,WebAPI 程序啟動的速度比 MySql 快,導(dǎo)致程序去連接 MySql 時,MySql 服務(wù)器還沒有啟動完成,自然是連不上。
假象
在 docker-compose.yml 文件中可以添加 depends_on 來設(shè)置依賴,如下:
api:
restart: always
image: netapi
ports:
- "5000:5000"
environment:
- TZ=Asia/Shanghai
depends_on:
- mysql
networks:
s2_net:
ipv4_address: 172.66.9.5
在 api 的 depends_on 設(shè)置 mysql ,表示 api 依賴 mysql ,只有當(dāng) mysql 啟動后,api 才會啟動。
但很可惜,這里的 mysql 啟動指的是 mysql 的容器是否啟動了,而不是 mysql 的服務(wù)是否啟動。所以,這種配置只能控制容器的啟動順序,并不能解決問題。
解決
要解決這個問題,有兩種方式:
- 在 WebAPI 項目中使用 Polly 庫,它是一個 .NET 的彈性和瞬態(tài)故障處理庫,可以實(shí)現(xiàn)重試、斷路器、超時等策略來處理網(wǎng)絡(luò)請求失敗的情況。可以使用 Polly 來嘗試連接 mysql 服務(wù),并在失敗時進(jìn)行重試或等待。
- 優(yōu)化 depends_on 配置。
本文著重介紹的是第二種方式,進(jìn)行 depends_on 配置的優(yōu)化。
優(yōu)化思路
- mysql 服務(wù)添加 healthcheck 檢查,用來判斷 mysql 的服務(wù)是否正常啟動。
- api 服務(wù)的 depends_on 監(jiān)聽這個檢查,只有當(dāng) mysql 服務(wù)正常啟動后,api 才會啟動。
完整 docker-compose.yml
version: "3"
networks:
s2_net:
driver: bridge
ipam:
driver: default
config:
- subnet: 172.66.9.0/24
services:
mysql:
restart: always
image: mysql/mysql-server:latest
ports:
- "3306:3306"
environment:
- TZ=Asia/Shanghai
- MYSQL_ROOT_PASSWORD=123456
healthcheck:
test: ["CMD", "mysqladmin" ,"ping", "-h", "localhost", "-u", "root", "--password=123456"]
interval: 3s
timeout: 5s
retries: 3
start_period: 5s
command: mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_general_ci --default-authentication-plugin=mysql_native_password
networks:
s2_net:
ipv4_address: 172.66.9.2
api:
restart: always
image: netapi
ports:
- "5000:5000"
environment:
- TZ=Asia/Shanghai
depends_on:
mysql:
condition: service_healthy
networks:
s2_net:
ipv4_address: 172.66.9.5
mysql 服務(wù)中添加 healthcheck 屬性,子屬性解釋如下:
- test:設(shè)置健康檢查的命令。
- interval:定義健康檢查的間隔時間,上面配置為間隔 3 秒。
- timeout:健康檢查的超時時間。
- retries:定義了健康檢查失敗后的重試次數(shù)。
- start_period:默認(rèn)值為 0 秒,表示容器啟動后立即進(jìn)行健康檢查。如果將 start_period 設(shè)置為非零值,則 Docker 會在容器啟動后先等待一段時間,然后再開始進(jìn)行健康檢查。
api 服務(wù)的配置為固定寫法。
注意事項
如果您的 docker-compose 安裝的是 1.27 以下的版本,需要升級到 1.27 或以上版本。
因為 docker-compose 3 不支持 depends_on 的條件設(shè)置, 但從 1.27.0 開始,2.x 和 3.x 與 COMPOSE_SPEC 架構(gòu)合并,版本現(xiàn)在是兼容的。
可以使用下面命令進(jìn)行 docker-compose 版本的查看:
docker-compose -v
安裝 docker-compose 可以使用下面命令:
curl -L https://github.com/docker/compose/releases/download/1.28.0/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
升級到 1.28.0 后,執(zhí)行 docker-compose 的命令時可能會出現(xiàn)錯誤,錯誤提示如下:
[29250] Error loading Python lib '/tmp/_MEIYmY20a/libpython3.9.so.1.0': dlopen: /lib64/libc.so.6: version `GLIBC_2.28' not found (required by /tmp/_MEIYmY20a/libpython3.9.so.1.0)
按照提示 google 下,會有很多方式解決,或者直接參考這個鏈接:https://blog.csdn.net/wangying202/article/details/113178159。
總結(jié)
在 docker-compose 中進(jìn)行設(shè)置是一種偷懶的做法,適用于測試環(huán)境,因為生產(chǎn)環(huán)境程序和數(shù)據(jù)庫通常在不同的服務(wù)器。
最好的方式還是應(yīng)該在 WebAPI 程序中進(jìn)行處理。