Docker, Node, Foreman and Varnish Fails to build

I am interested in running multiple processes in the same docker container - specifically, varnish caching and serving a node express app. I read through the Running Multiple Processes Inside A Fly.io App, tried the various options, and ultimately came up with a pretty straightforward approach using Foreman.

fly-varnish
A Varnish Docker Container using a Forman Procfile to run and cache multiple Node processes

It’s a simple Dockerfile building on docker:fresh-alpine. The Profile loads two processes, the node server on port 3000, and the varnish on 8080.

#./Procfile
web: PORT=3000 node server.js
cdn: /usr/sbin/varnishd -F -f /etc/varnish/default.vcl -a http=:8080,HTTP -a proxy=:8443,PROXY -T localhost:6082

Works great locally. (npm run docker:build && npm run docker:test)

Unfortunately, it fails to build on Fly.io. Hoping the community might have some ideas…

==> Monitoring deployment

 1 desired, 1 placed, 0 healthy, 1 unhealthy [health checks: 1 total, 1 critical]
Failed Instances

Failure #1
```

And here are the logs:

```
2022-02-19T14:50:16Z app[f6e3e7fb] atl [info]Starting init (commit: 0c50bff)...
2022-02-19T14:50:16Z app[f6e3e7fb] atl [info]Preparing to run: `/usr/local/bin/docker-varnish-entrypoint /bin/sh -c nf start` as root
2022-02-19T14:50:16Z app[f6e3e7fb] atl [info]2022/02/19 14:50:16 listening on [fdaa:0:4cc2:a7b:ac0:f6e3:e7fb:2]:22 (DNS: [fdaa::3]:53)
2022-02-19T14:50:17Z app[f6e3e7fb] atl [info]2:50:17 PM web.1 |  HelloNode app listening on port 3000!
2022-02-19T14:50:18Z app[f6e3e7fb] atl [info]2:50:18 PM cdn.1 |  Debug: Version: varnish-7.0.2 revision 9b5f68e19ca0ab60010641e305fd12822f18d42c
2022-02-19T14:50:18Z app[f6e3e7fb] atl [info]2:50:18 PM cdn.1 |  Debug: Platform: Linux,5.12.2,x86_64,-junix,-sdefault,-sdefault,-hcritbit
2022-02-19T14:50:18Z app[f6e3e7fb] atl [info]2:50:18 PM cdn.1 |  Debug: Child (543) Started
2022-02-19T14:50:18Z app[f6e3e7fb] atl [info]2:50:18 PM cdn.1 |  Info: Child (543) said Child starts
2022-02-19T14:55:28Z runner[f6e3e7fb] atl [info]Shutting down virtual machine
2022-02-19T14:55:29Z app[f6e3e7fb] atl [info]Sending signal SIGINT to main child process w/ PID 514
2022-02-19T14:55:29Z app[f6e3e7fb] atl [info][DONE] Killing all processes with signal  SIGINT
2022-02-19T14:55:29Z app[f6e3e7fb] atl [info][WARN] Interrupted by User
2022-02-19T14:55:29Z app[f6e3e7fb] atl [info]2:55:29 PM cdn.1 |  Error: Manager got SIGINT
2022-02-19T14:55:29Z app[f6e3e7fb] atl [info]2:55:29 PM cdn.1 |  Debug: Stopping Child
2022-02-19T14:55:29Z app[f6e3e7fb] atl [info]2:55:29 PM web.1 Exited with exit code SIGINT
2022-02-19T14:55:29Z app[f6e3e7fb] atl [info]2:55:29 PM cdn.1 |  Info: Child (543) ended
2022-02-19T14:55:29Z app[f6e3e7fb] atl [info]2:55:29 PM cdn.1 |  Info: Child (543) said Child dies
2022-02-19T14:55:29Z app[f6e3e7fb] atl [info]2:55:29 PM cdn.1 |  Debug: Child cleanup complete
2022-02-19T14:55:29Z app[f6e3e7fb] atl [info]2:55:29 PM cdn.1 |  Info: manager stopping child
2022-02-19T14:55:29Z app[f6e3e7fb] atl [info]2:55:29 PM cdn.1 |  Info: manager dies
2022-02-19T14:55:29Z app[f6e3e7fb] atl [info]2:55:29 PM cdn.1 Exited Successfully
2022-02-19T14:55:30Z app[f6e3e7fb] atl [info]Main child exited normally with code: 0
2022-02-19T14:55:30Z app[f6e3e7fb] atl [info]Starting clean up.
```

Ok. I think I might be getting closer. I read somewhere in this forum about problems running as root, and then I stumbled up on this post here that suggests running through an entrypoint.sh script.

So, I reworked the dockerfile to create an ‘appuser’ and install the forman globally as that user. Then transition to that user, when running the entrypoint.sh script.

FROM varnish:fresh-alpine as alpine

RUN apk add --update nodejs npm
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
RUN npm --global config set user appuser && \
  npm --global install foreman

RUN mkdir /app
RUN chown -R appuser:appgroup /app
WORKDIR /app

COPY default.vcl /etc/varnish/default.vcl
COPY . .

RUN chmod +x /app/entrypoint.sh
RUN npm install --production

EXPOSE 3000 8080 443

USER appuser
ENTRYPOINT ["sh","./entrypoint.sh", "nf", "start"]
USER root

And then in entrypoint.sh:

#!/bin/sh

chown -R appuser:appgroup /app
su - appuser
exec "$@"

Again, builds and runs locally, fails on Fly.io though.

After spending a day reading documentation, trying out different methods for running multiple processes on a single container, I discovered an unreleased, undocumented feature that does exactly what I wanted to do. :<- This is the way.

Good you’ve found a way to make it work.

The last time I wanted a multi-process (to run nginx and php-fpm) I did it with supervisor, based on the last Dockerfile from Run multiple services in a container | Docker Documentation Seemed to work for me. But perhaps that new process way is better.