alpine安装wkhtmltopdf构建Docker容器
引言
项目需要将HTML页面转换为PDF,由于使用laravel
开发,选用了laravel-snappy,它是snappy的laravel版本。snappy是一个PHP库,可以从 url 或 HTML页面生成缩略图、快照或PDF,底层调用的是wkhtmltopdf。wkhtmltopdf是一个开源软件,可以将HTML页面转换为PDF或图片。
wkhtmltopdf有2种安装方法,一种是用命令行直接在服务器上安装,另一种是使用composer安装。如果采用composer安装,会有如下的二进制文件/vendor/h4cc/wkhtmltoimage-amd64/bin/wkhtmltoimage-amd64
和 /vendor/h4cc/wkhtmltopdf-amd64/bin/wkhtmltopdf-amd64
。
Docker
为了让镜像尽量小一些,这里采用了alpine
构建镜像。但是遇到的问题是在alpine
内无法使用wkhtmltopdf-amd64
,会报如下错误
The exit status code '127' says something went wrong:\nstderr: \"sh: /www/my-protect/vendor/h4cc/wkhtmltopdf-amd64/bin/wkhtmltopdf-amd64: not found
原因不是很清楚,可以看看这里。所以要采用第一种安装方式,Dockerfile文件如下
FROM php:7.2.24-fpm-alpine
# 更改为阿里的镜像源
RUN sed -i "s/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g" /etc/apk/repositories
# install unpatched wkhtmltopdf
RUN apk add --no-cach wkhtmltopdf
这里需要说明wkhtmltopdf有with unpatched qt和with patched qt两个版本,alpine默认安装的是unpatched版本,这个版本不能支持例如页眉、页脚、边距等高级操作,所以我们需要安装patched版本。
安装wkhtmltopdf with patched qt
网上有大佬已经造好了轮子,真香!!!基本原理是先通过容器把wkhtmltopdf with patched qt的二进制文件编译好,然后从容器内考出来,构建自己镜像的时候COPY
进去替换默认的wkhtmltopdf二进制文件,为了支持中文,把字体文件一起拷进去就好了。上面Dockerfile中的wkhtmltopdf和wkhtmltoimage就是这样来的,至于字体文件可以从原宿主机上拷贝出来。
本地构建用于编译wkhtmltopdf的镜像可能比较慢,大佬已经将构建好的镜像传到docker hub上了,看这里。步骤如下
$ docker pull aantonw/alpine-wkhtmltopdf-patched-qt
$ docker run -d --name wkhtmltopdf aantonw/alpine-wkhtmltopdf-patched-qt
$ docker cp wkhtmltopdf:/bin/wkhtmltopdf wkhtmltopdf
$ docker cp wkhtmltopdf:/bin/wkhtmltoimage wkhtmltoimage
最后完整版的Dockerfile如下
FROM php:7.2.24-fpm-alpine
# 更改为阿里的镜像源
RUN sed -i "s/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g" /etc/apk/repositories
# install unpatched wkhtmltopdf
RUN apk add --no-cach wkhtmltopdf
# replace binary and lib
COPY wkhtmltopdf /usr/bin/wkhtmltopdf
COPY wkhtmltoimage /usr/bin/wkhtmltoimage
# 拷贝宋体字体文件
COPY ./wkhtmltopdf/fonts/simsun.ttc /usr/share/fonts/simsun.ttc
最后需要修改配置文件
return array(
'pdf' => array(
'enabled' => true,
'binary' => base_path('/usr/bin/wkhtmltopdf'),
'timeout' => false,
'options' => array(),
'env' => array(),
),
'image' => array(
'enabled' => true,
'binary' => base_path('/usr/bin/wkhtmltoimage'),
'timeout' => false,
'options' => array(),
'env' => array(),
),
);