记一次通过脚本来实现自定义容器的自动重启

通过脚本来实现自定义容器的自动重启

  • 1. 场景还原
  • 2. 自定义启动脚本
  • 3. 使用自定义脚本来作为容器启动的脚本
  • 4. 制作自定义脚本作为入口点的新镜像
  • 5. 测试新镜像启动是否走自定义启动脚本

1. 场景还原

现在我有一个自定义的Docker镜像,是基于基础镜像来构建的带有多个服务的镜像,镜像里面包含了两个服务,其中需要A服务先启动,然后B服务依赖A服务,需要等A服务启动成功后,才能正常对外提供服务。其中A服务启动成功后,可以通过 5005 端口来判断,A服务的端口就是 5005;

在刚开始使用的时候,每次都是先启动一个这个镜像的容器,然后进入容器内部,手动执行A服务的启动命令,然后等待A服务启动完成,再执行B服务的启动命令。

这种场景,如果在服务器不关机的情况下,服务一直是正常运行的。但是如果服务器关机重启了,或者需要更新镜像版本了,这就得人工来重复操作了。这就显得有点不太智能了,于是想着折腾一番,能不能整一个在容器启动的时候,执行某个脚本,这个启动脚本里面包含A服务、B服务的启动命令,并且还能维护下启动顺序,如果能把启动服务的日志输出到Docker容器的日志里,使用 docker logs 命令能实时的查看服务的日志,这样也是极好的。于是带着这个目的,开始折腾了。

2. 自定义启动脚本

针对上面的场景,先写一个shell脚本,来启动需要启动的服务;
其中 A服务的启动命令是:

rasa run --enable-api

A服务启动成功后,可以对外提供 5005 端口的 web服务;但是 A服务的启动过程有点慢,比如要几十秒或者一分钟,这个时间不确定;

B服务的启动命令是:

python3 /home/rasa_dev/bot_api.py

B服务启动成功后,可以对外提供 5006 端口的 web服务;

自定义脚本 wait_for_port.sh 内容如下:

#!/bin/bash# 第一步:运行 rasa run --enable-api 命令
nohup rasa run --enable-api &# 第二步:等待端口5005可用
while ! nc -z localhost 5005; doecho "Waiting for port 5005 to become available..."sleep 5
done# 第三步:一旦端口可用,执行 bot_api.py
python3 /home/rasa_dev/bot_api.py &# 防止容器退出
sleep infinity
[root@VM-0-5-centos aikg-bot_build]# 

脚本包含了需要启动的命令,并且有个判断A服务 5005端口的过程,在端口可用之后再启动 B 服务

在这个脚本中,nc(netcat)命令用于检查端口是否可访问。while循环将持续检测端口,直到它变为可访问状态。一旦端口可用,脚本将执行bot_api.py

刚开始我将上面两个启动命令的日志重定向到 /logs 文件夹下、比如 启动 B服务的命令为:

python3 /home/rasa_dev/bot_api.py >> /logs/bot_api.log 2>&1 &

这样在 B服务启动时,启动日志就会追加到 /logs/bot_api.log 文件中了。

然后启动镜像的时候将日志目录挂载出来,这样就可以在宿主机上查看服务的启动日志了,但是我还是感觉麻烦,所以又改成了上面的命令,移除了/logs/bot_api.log 2>&1 这个日志重定向的内容,这样就不会将日志重定向到文件,而是直接输出到stdoutstderr。当容器运行时,所有输出都会被捕获,这样就可以使用docker logs命令来查看它们:

docker logs <container-name-or-id>

如果日志文件很重要,需要留痕或者方便后面追溯的话,可以将日志重定向到文件中,这样方便追溯或者排查原因,不过不考虑日志内容丢失的话,直接输出到stdoutstderr是最简便的方式。

刚开始我的镜像里面是不包含 nc 这个命令的,我先使用当前版本的镜像,启动一个容器,然后进入容器内部安装这个nc命令:

比如我之前的镜像是:test-bot:1.0.0 ,使用下面命令直接启动一个容器:

docker run -itd --name test-bot x-bot:1.0.0 /bin/bash

上面命令已交互式的方式来运行一个容器,容器启动后,自动进入容器内部,接着来安装这个 nc工具;

这里需要检查下基础镜像底层是Centos还是Ubuntu或者其他的基础镜像,这个决定我们接下来要如何安装新的工具。

可以直接运行 yum 命令 或者 apt-get 命令,看下哪个可以正常运行,则接下来用哪个命令来安装 nc 工具;

我这里支持 apt-get 的方式来安装:

root@aikg-bot-build:/home/rasa_dev# yum
bash: yum: command not found
root@aikg-bot-build:/home/rasa_dev# 
root@aikg-bot-build:/home/rasa_dev# apt-get
apt 1.8.2.3 (amd64)
Usage: apt-get [options] commandapt-get [options] install|remove pkg1 [pkg2 ...]apt-get [options] source pkg1 [pkg2 ...]apt-get is a command line interface for retrieval of packages
and information about them from authenticated sources and
for installation, upgrade and removal of packages together
with their dependencies.

如果是支持 yum 命令的话,执行 yum 命令,应该是:

[root@VM-0-5-centos ~]# yumFile "/usr/bin/yum", line 30except KeyboardInterrupt, e:^
SyntaxError: invalid syntax
[root@VM-0-5-centos ~]# 
[root@VM-0-5-centos ~]# apt-get
-bash: apt-get: command not found
[root@VM-0-5-centos ~]# 

安装 nc 工具的话,直接在容器内执行:apt-get update && apt-get install -y netcat

在执行 apt-get install 之前,通常建议先执行 apt-get update,主要有以下几个原因:

  • 更新软件包列表:
    apt-get update 命令会从配置的源服务器下载最新的软件包列表。这些列表包含了每个软件包的最新版本和依赖关系信息。通过更新这些列表,你的系统就能够获取到当前最新的软件包信息。

  • 确保安装最新版本的软件:
    如果不执行 apt-get update,你的系统可能仍然使用旧的软件包列表,这意味着你可能无法安装到最新版本的软件包。在这种情况下,执行 apt-get install 可能会安装旧版本的软件包,甚至可能会导致安装失败或出现依赖性问题。

  • 解决依赖关系:
    软件包之间可能有复杂的依赖关系,新的软件包版本可能会改变这些依赖关系。通过执行 apt-get update,你能确保所有依赖关系都基于最新的信息,从而避免在安装过程中遇到问题。

  • 安全性:
    最新的软件包列表通常包括了最新的安全修复。如果你不更新列表,可能会错过一些重要的安全更新,导致系统存在潜在的安全风险。

  • 系统稳定性:
    最新的软件包列表还包含了各种错误修复和改进,通过保持列表的更新,可以提高系统的稳定性和性能。

一个典型的软件包安装流程如下:

sudo apt-get update          # 更新软件包列表
sudo apt-get upgrade         # 升级已安装的软件包(可选)
sudo apt-get install <package-name>  # 安装新的软件包

这样做可以确保你安装的是最新版本的软件包,并且系统依赖关系是最新的,减少安装过程中遇到问题的可能性。

总的来说,执行 apt-get update 是一个确保安装过程顺利并且系统安全和稳定的好习惯。

上面工具安装完成,可以先测试下,是否能正常执行

root@aikg-bot-build:/home/rasa_dev# nc -zv localhost 80
localhost [127.0.0.1] 80 (http) : Connection refused
root@aikg-bot-build:/home/rasa_dev# 
root@aikg-bot-build:/home/rasa_dev# nc -zv localhost 5005
localhost [127.0.0.1] 5005 (?) open
root@aikg-bot-build:/home/rasa_dev#

可以看到当运行 nc -zv localhost 80,得到了 “Connection refused” 的消息。这意味着端口80上没有服务正在监听。

当运行 nc -zv localhost 5005,得到了 “open” 的消息,这表示端口5005上有一个服务正在监听。这通常意味着有一个服务(可能是某个应用或某个后台服务)正在使用这个端口。

nc-v 选项提供了详细的输出,这有助于诊断网络连接问题。当它说 “open” 或者 “Connection refused”,它实际上是在告诉你 nc 尝试与指定端口建立连接的结果。如果端口是开放的,nc 能够成功建立连接;如果端口被拒绝连接,那通常意味着没有服务在那里监听,或者防火墙阻止了连接。

这里还有一个小 tips 就是脚本的最后一行:sleep infinity,刚开始没有加这个得时候,我发现容器启动完成后,就自动 Down 掉了,并不能一直停留在启动成功的状态。

解决这个问题呢,有两种方式,其目的就是让启动脚本在启动服务完成后,进入一个无限循环的状态,一直来维持住现状。

  • 方式一:使用tail -f /dev/null
    tail -f /dev/null命令会让脚本进入一个无限循环,读取/dev/null文件的末尾,实际上什么也不做,但是这会保持一个前台进程运行,从而防止容器因缺乏前台进程而自动退出。
  • 方式二:使用 sleep infinity
    sleep infinity表示让脚本进入无限期睡眠,这样即使所有其他命令都已完成,容器也不会退出;

3. 使用自定义脚本来作为容器启动的脚本

由于这里要修改镜像的启动命令,就得需要重新构建一个新的镜像了,先整个 Dockerfile,内容如下:

[root@VM-0-5-centos ~]# cat Dockerfile 
FROM test-bot:1.0.0LABEL MAINTAINER="linmm"# 设置工作目录
WORKDIR /home/rasa_dev# 定义环境启动时执行的脚本
ADD wait_for_port.sh /wait_for_port.sh
RUN chmod +x /wait_for_port.sh# 设置 ENTRYPOINT 和 CMD
ENTRYPOINT ["/wait_for_port.sh"][root@VM-0-5-centos aikg-bot_build]# 

这里我们自定义的脚本 wait_for_port.sh 其实内容很简单,只包含几个固定的命令,没有涉及到动态的参数什么的。

如果复杂一点,脚本里面需要动态参数,比如要监听的端口 5005 是动态的,这样就可以在 Dockerfile 文件的最后,来使用 CMD 命令来给脚本传入参数;

比如在文件的最后一行添加内容:CMD ["5005"]

CMD指令提供了容器启动时ENTRYPOINT所指定的命令需要的参数。这里,CMD指定了参数5005,这通常会被传递给ENTRYPOINT指定的脚本作为参数使用。

如果wait_for_port.sh不需要额外参数,那么CMD指令可以省略,或者可以设置成CMD []表示没有参数。

4. 制作自定义脚本作为入口点的新镜像

现在自定义脚本也有了,Dockerfile 也有了,那就开整新镜像吧。

[root@VM-0-5-centos test-bot_build]# ll
-rw-r--r-- 1 root root      286 Jun 20 19:40 Dockerfile
-rwxr--r-- 1 root root      360 Jun 19 17:50 wait_for_port.sh
[root@VM-0-5-centos aikg-bot_build]#

直接在当前目录下执行:

[root@VM-0-5-centos aikg-bot_build]# docker build -t test-bot:1.0.1 .
Sending build context to Docker daemon  61.07MB
Step 1/6 : FROM test-bot:1.0.3_r3_1---> f6d10507d2f2
Step 2/6 : LABEL MAINTAINER="linmm"---> Running in 5a9275d08c2e
Removing intermediate container 5a9275d08c2e---> 91ee1346c000
Step 3/6 : WORKDIR /home/rasa_dev---> Running in 25a410ccf9f9
Removing intermediate container 25a410ccf9f9---> 18b42a453605
Step 4/6 : ADD wait_for_port.sh /wait_for_port.sh---> cf6136d5fa86
Step 5/6 : RUN chmod +x /wait_for_port.sh---> Running in 12a6ba7675b3
Removing intermediate container 12a6ba7675b3---> f6e9e1cbd2d7
Step 6/6 : ENTRYPOINT ["/wait_for_port.sh"]---> Running in 18ea0cd27bc4
Removing intermediate container 18ea0cd27bc4---> 0c8e946b6409
Successfully built 0c8e946b6409
Successfully tagged test-bot:1.0.1

新镜像顺利构建完成。

5. 测试新镜像启动是否走自定义启动脚本

直接运行

docker run -itd --name test-bot x-bot:1.0.1 

接着使用 docker logs 命令来查看启动日志:

[root@VM-0-5-centos ~]# docker logs -f --tail 20  test-bot
Waiting for port 5005 to become available...
/usr/local/lib/python3.10/site-packages/rasa/core/tracker_store.py:1042: MovedIn20Warning: Deprecated API features detected! Base: DeclarativeMeta = declarative_base()
/usr/local/lib/python3.10/site-packages/rasa/shared/utils/validation.py:134: DeprecationWarning: pkg_resources is deprecatedimport pkg_resources
2024-06-20 12:31:53 INFO     root  - Starting Rasa server on http://0.0.0.0:5005
2024-06-20 12:31:54 INFO     rasa.core.processor  - Loading model models/nlu-20240620-122934-future-sharp.tar.gz...
Waiting for port 5005 to become available...
Waiting for port 5005 to become available...
Waiting for port 5005 to become available...
Waiting for port 5005 to become available...
Waiting for port 5005 to become available...
Waiting for port 5005 to become available...
Waiting for port 5005 to become available...
Waiting for port 5005 to become available...rasa.shared.utils.io.raise_warning(
2024-06-20 12:32:32 INFO     root  - Rasa server is up and running.* Serving Flask app 'bot_api'* Debug mode: off
WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.* Running on all addresses (0.0.0.0)* Running on http://127.0.0.1:5006* Running on http://172.27.100.24:5006
Press CTRL+C to quit

可以看到容器启动后,限制行了启动A服务,在 A服务启动完成前,通过监听 5005 端口来循环阻塞,接着再启动 B服务;并且容器不会自动停止。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/857115.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【React】React 的StrictMode作用是什么,怎么使用?

React的<StrictMode>是一个用于在开发环境中检测潜在问题的工具,它可以帮助开发者在开发阶段识别并解决一些常见的编码问题,从而提高代码质量和应用的可靠性。以下是<StrictMode>的详细作用和使用方法: 作用 检测潜在问题:<StrictMode>会启用一些额外的…

Windows 图像处理组件(WIC)读写位深度24位的 bmp 文件

我写了类封装了一下。只是作业需要&#xff0c;缺少错误处理。 #include <wincodec.h>enum PixColor { B, G, R };struct ComEnv {ComEnv(){CoInitialize(nullptr);CoCreateInstance(CLSID_WICImagingFactory, nullptr, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&fac));…

一文了解HarmonyOSNEXT发布重点内容

华为在2024年6月21日的开发者大会上正式发布了HarmonyOS NEXT版&#xff0c;这是华为在操作系统领域的一次重大飞跃&#xff0c;标志着华为在构建全场景智能生态方面的卓越成就。HarmonyOS NEXT版不仅带来了全新的系统架构和性能提升&#xff0c;还首次将AI能力融入系统&#x…

docker方式启动的redis如何使用自定义配置文件

本文参考这篇文章&#xff1a;参考 一、首先先下载默认的配置文件 wget http://download.redis.io/redis-stable/redis.conf 然后下载备份数据目录&#xff08;这个是用来做备份的&#xff0c;放在宿主机上&#xff09; mkdir -p /usr/local/docker/data 二、启动redis 下…

鸿蒙正在跨越“生态繁荣阈值”

作者 | 曾响铃 文 | 响铃说 先讲一个故事。 一个朋友曾经做了一个本地互联网装修平台&#xff0c;一边是装修服务的提供者——各工种工人等&#xff0c;一边是有装修需求的业主。这个平台要做独立生态&#xff0c;绕过旧有的装修公司渠道垄断&#xff0c;直接提供服务&#…

Android开发系列(六)Jetpack Compose之Box

Box是一个用来组合和控制子元素布局的组件。它可以在一个矩形区域内排列一个或多个子元素&#xff0c;并根据所提供的参数来控制它们的位置、大小和样式。 Box的功能类似传统的FrameLayout。 下面通过示例了解Box的使用方法&#xff0c;首先看一个最简单的示例&#xff0c;如下…

【自动驾驶】通过下位机发送的速度计算机器人在世界坐标系中的位置和朝向

文章目录 1. 计算X方向的位移原理公式解释2. 计算Y方向的位移原理公式解释3. 绕Z轴的角位移原理公式解释总结Robot_Pos.X+=(Robot_Vel.X * cos(Robot_Pos.Z) - Robot_Vel.Y * sin(Robot_Pos.Z)) * Sampling_Time; //Calculate the displacement in the X direction, unit: m /…

React useContext

useContext 允许父组件向其下层无论多深的任何组件提供信息&#xff0c;而无需通过 props 显式传递。 // 1. LevelContext.js 创建 context&#xff0c;将其从文件中导出 import { createContext } from react; export const LevelContext createContext(1);// 2. Section.j…

内核学习——4、并发、竞争、同步与互斥

linux中四种进程或线程同步互斥的方法&#xff1a; 1、临界区&#xff1a;多线程串行化访问公共资源的一段代码 2、互斥量&#xff1a;互斥对象只有一个 3、信号量&#xff1a;控制一个有限数量的用户资源&#xff0c;进程上下文&#xff0c;适合长时间访问共享资源情况 4、自…

永磁同步电机驱动死区补偿

1 死区效应及补偿 1. 1 死区效应 在本文的电机控制嵌入式系统中,逆变器为三 相电压型桥式逆变电路,如图 1 所示。 在理想状态 下,上桥臂和下桥臂的控制信号满足互补通断原则, 即上桥臂开通时,下桥臂关断,反之亦然。 而在实际 应用中,开关管的通断需要一定的开通时…

Nginx HTTPS(证书) 部署实战

一、申请证书与认证 要搭建https服务首先需有SSL证书&#xff0c;证书通常是在第三方申请&#xff0c;在阿里云的安全服务中有SSL证书这一项&#xff0c;可以在里面申请免费的证书。也可以在自己电脑中生成&#xff0c;虽然也能完成加密&#xff0c;但是浏览器是不认可的&…

【重要】《HTML趣味编程》专栏内资源的下载链接

目录 关于专栏 博主简介 专栏内资源的下载链接 写在后面 关于专栏 本专栏将持续更新,至少含有30个案例,后续随着案例的增加可能会涨价,欢迎大家尽早订阅!(订阅后可查看专栏内所有文章,并且可以下载专栏内的所有资源) 博主简介 ⭐ 2024年百度文心智能体大赛 Top1⭐…

华为仓颉语言介绍

文章目录 1.简介2.初识仓颉语言3.基本概念3.1标识符3.2程序结构3.3变量3.4表达式3.4.1if 表达式3.4.2while语句3.4.3do-while表达式3.4.4 for-in 表达式3.4.5 where条件3.4.6 break和continue 3.5 函数 1.简介 随着万物互联以及智能时代的到来&#xff0c;软件的形态将发生巨大…

Redisson-Lock-加锁原理

归档 GitHub: Redisson-Lock-加锁原理 Unit-Test RedissonLockTest 说明 源码类&#xff1a;RedissonLock // 加锁入口 Override public void lock() { lock(-1, null, false); }/*** 加锁实现 */ private void lock(long leaseTime, TimeUnit unit, boolean interruptib…

低代码平台教你两步把SQL直接转换为RESTful API

文章目录 前言一、简介1. 项目亮点2. 技术栈3. 核心功能4. 数据库设计二、搭建教程1. 目录结构2. 下载2.1 下载2.2 上传2.3 解压3. 配置3.1 创建并切换数据库3.2 执行sql文件3.3 修改配置文件4. 启动/停止4.1 启动4.2 停止4.3 重启5. 浏览器访问三、配置教程1. 数据源配置1.1 创…

Java面试题:讨论synchronized关键字和java.util.concurrent包中的同步工具,如Lock和Semaphore

在 Java 中&#xff0c;synchronized 关键字和 java.util.concurrent 包中的同步工具都是用来控制多线程环境下的并发访问&#xff0c;以防止数据竞争和确保线程安全。下面是对 synchronized 关键字和 java.util.concurrent 包中的一些同步工具的讨论&#xff0c;包括它们的特点…

基于自适应融合和偏置消除的鲁棒松耦合视觉惯性里程计

预印本中文版论文 基于自适应融合和偏置消除的鲁棒松耦合视觉惯性里程计 Frank Fan1 电子邮件: fanzexuan135163.com 摘要 本文提出了一种新颖的松耦合视觉惯性里程计(VIO)算法,该算法解决了MEMS IMU中的显著偏置问题,并在具有挑战性的环境中提供了稳健的性能。我们的方法…

Leetcode Java学习记录——代码随想录哈希表篇

文章目录 哈希表几种哈希实现 Java数组HashSetmap方法charAt()toCharArray()for 遍历长度 哈希表 当需要快速判断一个元素是否出现在集合里的时候&#xff0c;就要用到哈希表。 无限循环就意味着重复出现。 几种哈希实现 数组&#xff1a;大小固定set&#xff1a;只存keymap…

美创科技入选“2024年度浙江省工业信息安全服务支撑单位”

近日&#xff0c;浙江省经济和信息化厅公布“2024年度浙江省工业信息安全服务支撑单位”名单。 经单位自愿申报、各市经信主管部门初审推荐、专家评审等环节&#xff0c;凭借在工业数据安全领域长期深耕和产品服务实力&#xff0c;美创科技成功入选&#xff01; “2024年度浙江…