Search code examples
dockerflaskwkhtmltopdfpdfkit

Library wkhtmltopdf is not working inside Docker


I have a code in Python Flask where I generate pdf files using an HTML template. The code works just fine when I run it alone, but when I try to run it inside a Docker container, as soon as I call the endpoint that generates the report the docker crashes and resets. It just stays loading then it returns an error (in Postman which I'm using to test).

The code for the PDF is as follows:

def create_report(download_uuid):
    transactions = get_transaction_for_report(download_uuid)
    config = pdfkit.configuration(wkhtmltopdf=environ.get('WKHTMLTOPDF'))

    file_obj = io.BytesIO()
    with zipfile.ZipFile(file_obj, 'w') as zip_file:
        for transaction in transactions:
            html = render_template("report.html", transaction=transaction)
            pdf = pdfkit.from_string(html, False, configuration=config)
            data = zipfile.ZipInfo('{}.pdf'.format(transaction['control_number']))
            data.compress_type = zipfile.ZIP_DEFLATED
            zip_file.writestr(data, pdf)
    file_obj.seek(0)
    return send_file(file_obj, attachment_filename="forms.zip", as_attachment=True)

It is returning a zip file, but inside the zip file are pdf files. Furthermore, if I remove the pdf generating part, the zip file returns just fine. This is my Dockerfile:

FROM madnight/docker-alpine-wkhtmltopdf as wkhtmltopdf_image
FROM python:3.9-alpine

RUN adduser -D custom

WORKDIR /home/Project

COPY requirements.txt requirements.txt
RUN python -m venv venv
RUN venv/bin/pip install --upgrade pip
RUN apk add make automake gcc g++ subversion python3-dev jpeg-dev zlib-dev libffi-dev musl-dev openssl-dev freetype freetype-dev ttf-freefont libxrender qt5-qtbase-dev
RUN venv/bin/pip install -r requirements.txt
RUN venv/bin/pip install gunicorn

COPY Project Project
COPY boot.sh app.py .env run.py create_database.py config.py ./
COPY templates templates
COPY static static
COPY --from=wkhtmltopdf_image /bin/wkhtmltopdf /usr/local/bin/wkhtmltopdf
RUN chmod +x boot.sh

ENV FLASK_APP app.py

USER root
RUN chown -R custom ./
USER custom

EXPOSE 9001
ENTRYPOINT ["./boot.sh"]

I should say that this is the last iteration of many, MANY attempts to try to get this to work. Essentially, I've tried getting wkhtmltox by curl, I've tried putting wkhtmltopdf in different directories. So far nothing has worked. I don't know what I'm missing. This is basically what I need to fix in order to finish this project so any help at all will be immensely appreciated.

EDIT: docker-compose.yml

version: '2'
services:
  app:
    build: .
    networks:
      - custom
    ports:
      - "9001:9001"
    volumes:
      - "./static:/home/EventismedEquipmentAPI/static"
    external_links:
      - eventismed-equipment:db
networks:
  custom:
    external: true

Solution

  • Let's fix this.

    I've managed to run wkhtmltopdf isolated on a docker container.

    Dockerfile:

    # https://stackoverflow.com/a/62737156/152016
    # Create image based on the official openjdk 8-jre-alpine image from the dockerhub
    FROM openjdk:8-jre-alpine
    
    # Install wkhtmltopdf
    # https://stackoverflow.com/a/56925361/152016
    RUN apk add --no-cache wkhtmltopdf ttf-dejavu
    
    ENTRYPOINT ["sh"]
    

    docker-compose.yml:

    version: '3.8'
    
    services:
      wkhtmltopdf:
        image: wkhtmltopdf
        container_name: wkhtmltopdf
        build:
          dockerfile: Dockerfile
          context: .
    

    Then:

    docker-compose build
    docker run -ti --rm -v /tmp:/tmp wkhtmltopdf
    

    Inside the container:

    $ cd /tmp
    $ wkhtmltopdf https://www.google.com test.pdf
    

    Then you will see the pdf on your mac at /tmp/test.pdf

    First let me know if this works.