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

2024-06-21 23:44

本文主要是介绍记一次通过脚本来实现自定义容器的自动重启,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

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

  • 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.chinasem.cn/article/1082675

相关文章

C++对象布局及多态实现探索之内存布局(整理的很多链接)

本文通过观察对象的内存布局,跟踪函数调用的汇编代码。分析了C++对象内存的布局情况,虚函数的执行方式,以及虚继承,等等 文章链接:http://dev.yesky.com/254/2191254.shtml      论C/C++函数间动态内存的传递 (2005-07-30)   当你涉及到C/C++的核心编程的时候,你会无止境地与内存管理打交道。 文章链接:http://dev.yesky

UE3脚本UnrealScript UC语法点滴

持续更新 目录 类定义修饰符  1.dependson(CLASSNAME) 2.config(ININAME) 3.native 4.notplaceable 5.inherits(CLASSNAME1[,CLASSNAME2,...]) 类对象实例创建 类默认属性设置 变量 1.声明 var local 2.修饰符 config  3.array 类型变量 以及

LeetCode11. 盛最多水的容器题解

LeetCode11. 盛最多水的容器题解 题目链接: https://leetcode.cn/problems/container-with-most-water 示例 思路 暴力解法 定住一个柱子不动,然后用其他柱子与其围住面积,取最大值。 代码如下: public int maxArea1(int[] height) {int n = height.length;int

通过SSH隧道实现通过远程服务器上外网

搭建隧道 autossh -M 0 -f -D 1080 -C -N user1@remotehost##验证隧道是否生效,查看1080端口是否启动netstat -tuln | grep 1080## 测试ssh 隧道是否生效curl -x socks5h://127.0.0.1:1080 -I http://www.github.com 将autossh 设置为服务,隧道开机启动

ROS话题通信流程自定义数据格式

ROS话题通信流程自定义数据格式 需求流程实现步骤定义msg文件编辑配置文件编译 在 ROS 通信协议中,数据载体是一个较为重要组成部分,ROS 中通过 std_msgs 封装了一些原生的数据类型,比如:String、Int32、Int64、Char、Bool、Empty… 但是,这些数据一般只包含一个 data 字段,结构的单一意味着功能上的局限性,当传输一些复杂的数据,比如:

时序预测 | MATLAB实现LSTM时间序列未来多步预测-递归预测

时序预测 | MATLAB实现LSTM时间序列未来多步预测-递归预测 目录 时序预测 | MATLAB实现LSTM时间序列未来多步预测-递归预测基本介绍程序设计参考资料 基本介绍 MATLAB实现LSTM时间序列未来多步预测-递归预测。LSTM是一种含有LSTM区块(blocks)或其他的一种类神经网络,文献或其他资料中LSTM区块可能被描述成智能网络单元,因为

亮相WOT全球技术创新大会,揭秘火山引擎边缘容器技术在泛CDN场景的应用与实践

2024年6月21日-22日,51CTO“WOT全球技术创新大会2024”在北京举办。火山引擎边缘计算架构师李志明受邀参与,以“边缘容器技术在泛CDN场景的应用和实践”为主题,与多位行业资深专家,共同探讨泛CDN行业技术架构以及云原生与边缘计算的发展和展望。 火山引擎边缘计算架构师李志明表示:为更好地解决传统泛CDN类业务运行中的问题,火山引擎边缘容器团队参考行业做法,结合实践经验,打造火山

vue项目集成CanvasEditor实现Word在线编辑器

CanvasEditor实现Word在线编辑器 官网文档:https://hufe.club/canvas-editor-docs/guide/schema.html 源码地址:https://github.com/Hufe921/canvas-editor 前提声明: 由于CanvasEditor目前不支持vue、react 等框架开箱即用版,所以需要我们去Git下载源码,拿到其中两个主

android一键分享功能部分实现

为什么叫做部分实现呢,其实是我只实现一部分的分享。如新浪微博,那还有没去实现的是微信分享。还有一部分奇怪的问题:我QQ分享跟QQ空间的分享功能,我都没配置key那些都是原本集成就有的key也可以实现分享,谁清楚的麻烦详解下。 实现分享功能我们可以去www.mob.com这个网站集成。免费的,而且还有短信验证功能。等这分享研究完后就研究下短信验证功能。 开始实现步骤(新浪分享,以下是本人自己实现

基于Springboot + vue 的抗疫物质管理系统的设计与实现

目录 📚 前言 📑摘要 📑系统流程 📚 系统架构设计 📚 数据库设计 📚 系统功能的具体实现    💬 系统登录注册 系统登录 登录界面   用户添加  💬 抗疫列表展示模块     区域信息管理 添加物资详情 抗疫物资列表展示 抗疫物资申请 抗疫物资审核 ✒️ 源码实现 💖 源码获取 😁 联系方式 📚 前言 📑博客主页: