踩坑正文
今天部署开发要上一个新模块,此模块已经通过golang编译好的,而且在本地机器可以正常启动,现在需要将其容器化—-制作一个镜像,然后在根据这个镜像启动程序。
本着基础镜像最小的原则,就选择了alpine:latest
。先创建一个干净的alpine镜像挂载模块所在的文件夹,然后docker exec
进去执行启动脚本。发现启动脚本里涉及到了cpulimit
、rpm
、ps -p
、 sudo
等alpine非自带命令所以无法启动。alpine安装模块的命令即非yum
又非apt-get
,而是apk add
,于是在Dockerfile里添加一句:
1
RUN apk add cpulimit && apk add rpm && apk add sudo && apk --update add procps
新镜像制作完毕,进去启动还是失败。具体表现是./启动脚本
的时候报"no such file or directory"
,开始我以为是因为alpine没有/bin/bash
的缘故,把所有的shebang都改成了/bin/sh
。但是发现启动的时候报格式错误,我想到这是一个go编译好的脚本,那么./
就应该可以直接启动的。后来在https://github.com/gin-gonic/gin/issues/1178 里查到原来alpine里是没有稳定的libc,所以还要添加libc6-compat
和libstdc++
。
在镜像里apk add libc6-compat && apk add libstdc++
之后,发现启动脚本还有这样一句话:
1
echo './core_%e.%p' | sudo tee /proc/sys/kernel/core_pattern
这个命令是无法执行的,因为docker里/proc/sys/kernel/core_pattern
是只读文件,自然无法进行修改。但是宿主机上的这个文件是root用户可以修改的。这可怎么办?
我开始想既然宿主机的/proc/sys/kernel/core_pattern
可以修改,那么就把宿主机的/proc/sys/kernel/core_pattern
挂载给镜像不就得了?但是在执行的时候会报错:cannot be mounted because it is located inside “/proc”
,因为Docker不允许在proc
目录下随意挂文件,如果你有信心可以通过修改docker的源码来实现挂载的效果。
但是我觉得还是沉稳为上,于是就想出一个办法:在docker run的时候添加--privileged
,这样容器获得了额外的特权可以对系统变量的值进行修改。但是要注意如果容器发生了重启,那么值会恢复成原样,即无法持久化。不过在启动脚本里已经有了echo语句,这样每一次执行启动脚本都会更改/proc/sys/kernel/core_pattern
,于是就不用太担心这个问题了。
最后完整的Dockerfile如下:
1
2
3
4
5
6
7FROM alpine:latest
MAINTAINER ChrisChan <33664@dahuatech.com>
RUN apk update && apk add libc6-compat && apk add libstdc++ && apk add cpulimit && apk add rpm && apk add sudo && apk --update add procps
RUN mkdir -p /mnt/agentmizar #agentmizar这个就是工作的模块名
WORKDIR /mnt/agentmizar #设定工作目录
CMD ["sh", "control", "start"] #启动之
创建完镜像之后,启动语句如下:
1
docker run --name 容器名 -dit -v /opt/:/opt/:ro -v /etc/localtime:/etc/localtime:ro --privileged 镜像名 #别忘了对准时间
补充一句,最后镜像大小不到50MB。
参考资料
https://blog.csdn.net/qq_41980563/article/details/88876874
https://serverfault.com/questions/883625/alpine-shell-cant-find-file-in-docker
https://sq.163yun.com/blog/article/155817999160799232