8

解决 WebAPI 在容器中的启动初始化问题

 1 year ago
source link: https://www.51cto.com/article/760450.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

解决 WebAPI 在容器中的启动初始化问题

作者:不止dotNET 2023-07-13 09:13:18
Docker 容器启动时,WebAPI 程序启动的速度比 MySQL 快,导致程序去连接 MySQL 时,MySQL 服务器还没有启动完成,自然是连不上。
b38207a53d2a0febe76128601ff8267a6fd3aa.png

在产品或项目的部署中,如果和下面场景类似,那么本文可能对您有所帮助。

  • WebAPI 和  MySql  数据部署在同一服务器(通常是测试环境)。
  • WebAPI 和  MySql  使用  docker-compose  进行部署。
  • WebAPI  启动时有一些初始化的操作要做,而初始化需要从  MySql  中获取数据。
  • 第一次部署,执行  docker-compose up -d  后,WebAPI  不能正常启动。
  • 断电、或其他原因导致的服务器重启或  docker  重启,WebAPI  不能正常启动。
  • docker  容器启动时,WebAPI  程序启动的速度比  MySql  快,导致程序去连接  MySql  时,MySql  服务器还没有启动完成,自然是连不上。

在  docker-compose.yml 文件中可以添加 depends_on 来设置依赖,如下:

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 设置 mysql ,表示 api  依赖  mysql ,只有当  mysql  启动后,api  才会启动。

但很可惜,这里的  mysql  启动指的是  mysql  的容器是否启动了,而不是  mysql  的服务是否启动。所以,这种配置只能控制容器的启动顺序,并不能解决问题。

要解决这个问题,有两种方式:

  • 在 WebAPI 项目中使用 Polly 库,它是一个 .NET 的弹性和瞬态故障处理库,可以实现重试、断路器、超时等策略来处理网络请求失败的情况。可以使用 Polly 来尝试连接 mysql 服务,并在失败时进行重试或等待。
  • 优化 depends_on 配置。

本文着重介绍的是第二种方式,进行 depends_on 配置的优化。

  • mysql  服务添加 healthcheck 检查,用来判断  mysql 的服务是否正常启动。
  • api  服务的 depends_on 监听这个检查,只有当 mysql 服务正常启动后,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  服务中添加 healthcheck 属性,子属性解释如下:

  • test:设置健康检查的命令。
  • interval:定义健康检查的间隔时间,上面配置为间隔  3  秒。
  • timeout:健康检查的超时时间。
  • retries:定义了健康检查失败后的重试次数。
  • start_period:默认值为 0 秒,表示容器启动后立即进行健康检查。如果将 start_period 设置为非零值,则 Docker 会在容器启动后先等待一段时间,然后再开始进行健康检查。

api  服务的配置为固定写法。

如果您的  docker-compose  安装的是  1.27  以下的版本,需要升级到  1.27  或以上版本。

因为 docker-compose 3  不支持 depends_on  的条件设置, 但从 1.27.0 开始,2.x 和 3.x 与 COMPOSE_SPEC 架构合并,版本现在是兼容的。

可以使用下面命令进行  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 后,执行  docker-compose  的命令时可能会出现错误,错误提示如下:

[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。

在  docker-compose  中进行设置是一种偷懒的做法,适用于测试环境,因为生产环境程序和数据库通常在不同的服务器。

最好的方式还是应该在  WebAPI  程序中进行处理。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK