制作基于CentOS7的Node镜像

前几天基于CentOS6.9的镜像安装无头浏览器Puppeteer,装上后问题很多,无法成功运行,装好这个依赖发现又缺少那个依赖,依赖全部装完后又提示版本不兼容。最终我还是选择放弃CentOS6,改为升级到CentOS7来构建Puppeteer的镜像。

构建Node+OpenResty的基础镜像

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
docker pull centos:7

docker run -tid centos:7
docker exec -ti xxxx /bin/bash


# 创建安装目录
mkdir -p /tmp/install
cd /tmp/install

# 更换yum源
mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.backup
curl "https://mirrors.aliyun.com/repo/Centos-7.repo" -o /etc/yum.repos.d/Centos-7.repo
yum clean all
yum makecache

# 安装依赖库
yum install pcre-devel perl openssl-devel zlib-devel telnet wget which make -y

# 安装并升级gcc和gcc-c++(Node 12.18.3 requires gcc and g++ >= 6.3 or newer)
yum install gcc gcc-c++ -y
yum install -y centos-release-scl
yum install -y devtoolset-7-gcc devtoolset-7-gcc-c++
source /opt/rh/devtoolset-7/enable

# 安装Node
wget https://nodejs.org/dist/v12.18.3/node-v12.18.3.tar.gz
tar -xvzf node-v12.18.3.tar.gz
cd node-v12.18.3

./configure --prefix=/usr/local/node
make -j4
make install

ln -s /usr/local/node/bin/node /usr/bin/node
ln -s /usr/local/node/bin/npm /usr/bin/npm

# 安装OpenResty
cd /tmp/install
wget https://openresty.org/download/openresty-1.17.8.2.tar.gz
tar -xvzf openresty-1.17.8.2.tar.gz
cd openresty-1.17.8.2

./configure --prefix=/usr/local/openresty
gmake
gmake install
useradd www

# 设置时区(这个需要覆盖)
cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime

# 安装s6(TODO,没跑起来,是因为我少了ENTRYPOINT ["/init"])
docker cp s6 695c769703a1:/tmp/install/
docker cp root 695c769703a1:/tmp/install/


制作专属Puppeteer的镜像

1
2
3
4
5
6
7
8
9
10
# 安装Chrome浏览器的依赖
#依赖库
yum install pango.x86_64 libXcomposite.x86_64 libXcursor.x86_64 libXdamage.x86_64 libXext.x86_64 libXi.x86_64 libXtst.x86_64 cups-libs.x86_64 libXScrnSaver.x86_64 libXrandr.x86_64 GConf2.x86_64 alsa-lib.x86_64 atk.x86_64 gtk3.x86_64 -y

#字体
yum install ipa-gothic-fonts xorg-x11-fonts-100dpi xorg-x11-fonts-75dpi xorg-x11-utils xorg-x11-fonts-cyrillic xorg-x11-fonts-Type1 xorg-x11-fonts-misc -y

# 全局安装Chrome浏览器
npm config set registry 'https://registry.npm.taobao.org'
npm install -g puppeteer

遇到的问题

S6进程管理没有生效

这是因为我在构建镜像的Dockerfile中,缺少了这一行,没有启动S6进程:

1
ENTRYPOINT ["/init"]

sandbox

Chrome推荐用户通过sandbox的模式,以非root用户运行程序:

https://chromium.googlesource.com/chromium/src/+/master/docs/linux/suid_sandbox_developm

然后我根据网上的教程配置sandbox:

https://github.com/puppeteer/puppeteer/blob/main/docs/troubleshooting.md#setting-up-chrome-linux-sandbox

1
2
3
4
5
6
cd /var/www/resource/server/node_modules/puppeteer/.local-chromium/linux-782078/chrome-linux/
chown root:root chrome_sandbox
chmod 4755 chrome_sandbox
cp -p chrome_sandbox /usr/local/sbin/chrome-devel-sandbox
export CHROME_DEVEL_SANDBOX=/usr/local/sbin/chrome-devel-sandbox
echo "export CHROME_DEVEL_SANDBOX=/usr/local/sbin/chrome-devel-sandbox" >> ~/.bashrc

配置后发现程序还是不能正常运行,后来找到网上的一个内容,说docker无解:

1
2
3
4
5
After researching extensively internet I think I found the answer:

Sandboxing For security reasons, Google Chrome is unable to provide sandboxing when it is running in the container-based environment. To use Chrome in the container-based environment, pass the --no-sandbox flag to the chrome executable

So it looks like there is no better solution than --no-sandbox for me, even though its not being very secure, there are people on the internet claiming that it is still safe to use "--no-sandbox" as its running within container which is extra protected any way.

因此最终还是在程序中设置不启用sandbox:

1
const browser = await puppeteer.launch({args: ['--no-sandbox', '--disable-setuid-sandbox']});

这样就可以正常运行了。也不用非root用户了,直接root也能跑起来。

docker启动后会自动退出

发现node程序没跑起来,排查过程又花了4个小时,最终发现是因为我解决文件编码问题的时候,是直接/bin/bash进入容器修改,然后commit生成新的镜像,导致新镜像里面带进去了/bin/bash,然后跑新镜像的时候,执行完内部脚本,就会执行/bin/bash,然后就退出了。

一定要通过Dockerfile来构建镜像,别手动修改,不然后续想部分重来,但是我又修改了中间的docker镜像,就不行了。