需求:
在docker容器codecombat中写个脚本,每次只要一运行容器就自动执行,脚本内容为:
cd /home/coco/codecombat/data/
./bin/coco-mongodb
cd /home/coco
sh start.sh
解决:
在 Docker 里“一启动容器就自动执行”只有两条路:
-
写一条 CMD/ENTRYPOINT 命令,替换掉镜像原来的启动进程;
-
把脚本塞进 镜像里,然后让 原来的启动进程 去“顺带”执行它(比如 rc.local、supervisord、npm script …)。
codecombat 官方镜像默认启动的是 npm start
(一个 Node 进程),
如果你直接把 CMD 换成你自己的脚本,就等于把 Node 服务掐掉,容器里就只剩 mongo 和你的 shell 了——这不是你想要的。
所以正确姿势是:
保留原来的启动流程,只把“额外要跑的脚本”插进去。
下面给出两种常见做法,你按场景挑一个即可。
方案 A:最干净——重新打包镜像(推荐)
-
在本地任意目录新建文件
auto-run.sh
#!/bin/bash # 1. 启动 mongo cd /home/coco/codecombat/data ./bin/coco-mongodb &# 后台跑 # 2. 启动主服务 cd /home/coco ./start.sh &# 如果你希望它也后台跑 # 3. 千万别让容器退出,把主进程挂住 wait
-
同目录新建
Dockerfile
FROM operepo/ope-codecombat:latest COPY auto-run.sh /usr/local/bin/auto-run.sh RUN chmod +x /usr/local/bin/auto-run.sh # 用 exec 形式,保证 PID 1 接管信号 ENTRYPOINT ["/usr/local/bin/auto-run.sh"]
-
构建并运行
docker build -t my-codecombat . docker run -d --name codecombat -p 3000:3000 my-codecombat
容器启动后会先拉起 mongo,再跑你自己的
start.sh
,并且 Node 服务依旧存活。
方案 B:不想打包——运行时挂脚本
如果你只是临时调试,不想重新 build,可以把脚本挂进去,再用 docker start
启动:
-
写本地脚本
local-init.sh
bash
#!/bin/bash cd /home/coco/codecombat/data && ./bin/coco-mongodb & cd /home/coco &&sh start.sh &
-
拷贝到容器里
powershell
docker cp local-init.sh codecombat:/usr/local/bin/init.sh docker exec codecombat chmod +x /usr/local/bin/init.sh
-
让容器每次启动时都执行它
官方入口是 npm,我们借~/.bashrc
(或/etc/profile.d/
)来“顺带”执行:powershell
docker exec codecombat bash -c \ 'echo "/usr/local/bin/init.sh" >> /home/coco/.bashrc'
这样只要容器启动后 有人进入 shell,脚本就会跑;
如果希望 真正无人值守,还是回到方案 A 重新打包镜像最稳妥。
一句话总结
-
想一劳永逸 → 用方案 A,重新
docker build
一个带启动脚本的镜像。 -
临时玩一下 → 用方案 B,把脚本拷进去,再改
.bashrc
或手动执行。