Running Puppeteer under Docker
Tags: docker
Published: 2022-01-15 00:12:00

---
title: Running Puppeteer under Docker
published: true
date: 2022-01-14 23:54:00 UTC
tags: docker
canonical_url: https://jason.sultana.net.au/docker/2022/01/15/running-puppeteer-under-docker.html
---

G’day guys!

I recently tried to dockerise an old hobby project and unsurprisingly, a couple of things broke. Some of these were fairly simple fixes so I won’t go into their details - but I will go into a fairly obscure one, which was caused by puppeteer. Regarding the application itself, it does a few things, but for the purposes of this article, let’s just say that it renders some reports using Puppeteer and NodeJS (while running as a .NET app).

### Dance monkey, dance monkey, dance…wait, what?

![](https://jason.sultana.net.au/static/img/dance-puppet.jpeg)

If you haven’t heard of [Puppeteer](https://github.com/puppeteer/puppeteer), it’s basically a NodeJS library that allows you to run (and control) an instance of headless chrome. i.e - an instance of Google chrome without a UI. In this project, I was using it to render PDF exports of reports. Running natively, it worked like a charm. But under docker, well…I’m writing this article after all, aren’t I?

### Hold up, let’s see your docker setup first.

I thought you might say that! Well, first here’s the dockerfile.

```
FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base
WORKDIR /app
EXPOSE 80

FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
WORKDIR /src
COPY ["MyApplication.API/MyApplication.API.csproj", "MyApplication.API/"]
COPY ["MyApplication.Common/MyApplication.Common.csproj", "MyApplication.Common/"]
COPY ["MyApplication.Data/MyApplication.Data.csproj", "MyApplication.Data/"]
COPY ["MyApplication.Logic/MyApplication.Logic.csproj", "MyApplication.Logic/"]
RUN dotnet restore "MyApplication.API/MyApplication.API.csproj"
COPY . .
WORKDIR "/src/MyApplication.API"
RUN dotnet build "MyApplication.API.csproj" -c Release -o /app/build

FROM build AS publish
RUN dotnet publish "MyApplication.API.csproj" -c Release -o /app/publish

FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "MyApplication.API.dll", "--environment", "Docker"]

# Install node and npm
RUN apt-get update
RUN apt-get install nodejs=12.22.5~dfsg-2~11u1 -y
RUN apt-get install npm=7.5.2+ds-2 -y
ENV NODE_ENV=production

# Install node modules for reports
WORKDIR "/app/Reports/jsreport"
RUN npm install

# Set the directory back so dotnet is able to run the application
WORKDIR "/app"

```

Basically I load the ASP.NET 6 base image, build the solution, publish it, install require node modules and set the `dotnet` program as the entry point of the container.

Then I build an image using `docker build -t myimage -f ./MyApplication.API/Dockerfile .`

Note that in order for the build step in the docker file to work, the image has to be created at the solution level and not the project level - since all of the projects need to be built. Hence why I’m using the solution directory when we build the image.

Then I run a container using `docker run -p 127.0.0.1:80:80/tcp myimage`.

So far so good! But after invoking one of the reports yields an internal server error.

### Show me the errors!

![](https://jason.sultana.net.au/static/img/show-me-the-money.jpeg)

Well, since this is running under docker (and this is just a hobby app, so I’m using old-school rolling file logs), I actually need to `sh` into the container first to see the logs. So first to get the id of the container: `docker ps`, and once we have the id of the container: `docker exec -it CONTAINER_ID /bin/bash`. Opening the error log reveals:

```
  Jering.Javascript.NodeJS.InvocationException: Failed to launch chrome!
/app/Reports/jsreport/node_modules/puppeteer/.local-chromium/linux-609904/chrome-linux/chrome: error while loading shared libraries: libnss3.so: cannot open shared object file: No such file or directory

TROUBLESHOOTING: https://github.com/GoogleChrome/puppeteer/blob/master/docs/troubleshooting.md

Error: Failed to launch chrome!

```

Interesting! Following the link provided and scrolling down to _Running Puppeteer under Docker_ tells you that we basically need to add a step in our dockerfile to install the necessary libraries (particularly `libnss3.so`) in order for headless chrome to run. The dockerfile in their example is a bit verbose with some unnecessary steps, but the real magic is basically just:

```
# Install latest chrome dev package and fonts to support major charsets (Chinese, Japanese, Arabic, Hebrew, Thai and a few others)
# Note: this installs the necessary libs to make the bundled version of Chromium that Puppeteer
# installs, work.
RUN apt-get update \
    && apt-get install -y wget gnupg \
    && wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add - \
    && sh -c 'echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google.list' \
    && apt-get update \
    && apt-get install -y google-chrome-stable fonts-ipafont-gothic fonts-wqy-zenhei fonts-thai-tlwg fonts-kacst fonts-freefont-ttf libxss1 \
      --no-install-recommends \
    && rm -rf /var/lib/apt/lists/*

```

And voila! Puppeteer is now working under Docker. Hope this helped someone out, or was at least an interesting read :)

Catch ya!