制作基于CentOS7的Node镜像
前几天基于CentOS6.9的镜像安装无头浏览器Puppeteer,装上后问题很多,无法成功运行,装好这个依赖发现又缺少那个依赖,依赖全部装完后又提示版本不兼容。最终我还是选择放弃CentOS6,改为升级到CentOS7来构建Puppeteer的镜像。
构建Node+OpenResty的基础镜像
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的镜像
# 安装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进程:
ENTRYPOINT ["/init"]
sandbox
Chrome推荐用户通过sandbox的模式,以非root用户运行程序:
https://chromium.googlesource.com/chromium/src/+/master/docs/linux/suid_sandbox_developm
然后我根据网上的教程配置sandbox:
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无解:
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:
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镜像,就不行了。