Search code examples
flaskdocker-composewkhtmltopdf

wkhtmltopdf in docker-compose: No such file or directory: b'/usr/bin/wkhtmltopdf'


I am trying to install wkhtmltopdf in docker-compose. The package is installing correctly, but when I try to use it in flask app, I get an error:

Exception in thread Thread-1:
server_1  | Traceback (most recent call last):
server_1  |   File "/usr/local/lib/python3.8/site-packages/pdfkit/configuration.py", line 21, in __init__
server_1  |     with open(self.wkhtmltopdf) as f:
server_1  | FileNotFoundError: [Errno 2] No such file or directory: b'/usr/bin/wkhtmltopdf'

Outside the docker-compose it works properly and this package path is /usr/bin/wkhtmltopdf:

$ which wkhtmltopdf
/usr/bin/wkhtmltopdf

Server Dockerfile

FROM debian:buster

RUN apt-get update \
    && apt-get install -y \
        curl \
        libxrender1 \
        libjpeg62-turbo \
        fontconfig \
        libxtst6 \
        xfonts-75dpi \
        xfonts-base \
        xz-utils

RUN curl "https://github.com/wkhtmltopdf/packaging/releases/download/0.12.6-1/wkhtmltox_0.12.6-1.buster_amd64.deb" -L -o "wkhtmltopdf.deb"
RUN dpkg -i wkhtmltopdf.deb

ENTRYPOINT ["wkhtmltopdf"]

FROM python:3.8.5
RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app
COPY . /usr/src/app
RUN pip install -r requirements.txt
CMD ["python", "api.py"]

docker-compose.yml

version: "3"
services:
    server:
        build: ./api
        expose: 
            - 5000
    client:
        build: ./
        ports:
        - "7000:80"

Solution

  • So I came back to this issue after over a year and found the solution so thought I'd share, might be useful to someone.

    This is the the Dockerfile of python service (flask to be precise) running with wkhtmltopdf installed inside of a container:

    FROM python:3.9-slim
    
    WORKDIR /app
    COPY . .
    
    RUN apt-get update \
        && apt-get install -y wget fontconfig libfreetype6 libjpeg62-turbo libpng16-16 \
        libx11-6 libxcb1 libxext6 libxrender1 xfonts-75dpi xfonts-base libfontconfig1 \
        fontconfig-config libx11-data libxau6 libxdmcp6 xfonts-utils ucf fonts-dejavu-core \
        ttf-bitstream-vera fonts-liberation libbsd0 libfontenc1 libxfont2 \
        x11-common xfonts-encodings \
        && wget https://github.com/wkhtmltopdf/packaging/releases/download/0.12.6-1/wkhtmltox_0.12.6-1.buster_arm64.deb \
        && dpkg -i wkhtmltox_0.12.6-1.buster_arm64.deb
    
    RUN pip install gunicorn
    RUN pip install -r requirements.txt
    
    ENTRYPOINT ["gunicorn", \
        "--bind", "0.0.0.0:5000", \
        "--workers", "8", \
        "--threads", "2", \
        "--access-logfile", "-", \
        "--log-file", "-", \
        "main:app"]
    

    I install necessary dependencies and wkhtmltopdf from github releases. I use arm64 build but if you need you can change architecture.

    e.g. amd64 arch: https://github.com/wkhtmltopdf/packaging/releases/download/0.12.6-1/wkhtmltox_0.12.6-1.buster_arm64.deb

    Then you can use it in the python service with a library like pdfkit:

    import pdfkit
    pdfkit.from_string(pdf_content, 'output.pdf')
    

    If the library will have difficulties with finding an executable installed in the container, here's a solution too:

    import subprocess
    import pdfkit
    
    executable = subprocess.run(['which', 'wkhtmltopdf'], stdout=subprocess.PIPE).stdout.decode().strip()
    config = pdfkit.configuration(wkhtmltopdf=bytes(executable, 'utf-8'))
    pdfkit.from_string(pdf_content, 'output.pdf', configuration=config)
    

    Hope it helps!