Docker for Rails + Puma + Nginx + Pagespeed + PostgreSQL + Redis + Memcached on Heroku

This is a step by step solution for running rails on a docker instance with nginx and pagespeed.

Docker for Rails + Puma + Nginx + Pagespeed + PostgreSQL + Redis + Memcached on Heroku

This is a step by step solution for running rails on a docker instance with nginx and pagespeed.

For www.epicpxls.com we are running Rails 5.2 so I wanted to transition from using passenger to nginx and leverage some of the modules of pagespeed.

What I intended to do was to use docker images that already have what I needed implemented. I also used some blog posts and other tutorials I found as a guide and I’ll list them at the bottom.

All of the code is in a gist I made so it can easily be navigated and updated:
https://gist.github.com/Chocksy/f81a07c81ffa838c5d09b04901a28222

What we’ll use:

What is the structure?

We’ll have 5 docker instances, the rails app, the nginx server, the redis, the db & the memcached instance.

Create the docker structure

First create a folder called docker in the rails application root. The structure of the directory should be as follows:

The DockerFile for the app

Create the docker/app/DockerFile with the following contents:

Notice here that I’m using ruby 2.6.6 but you can change that to what version you need based on the docker image.

I’m also using the Aptfile packages and installing those in case there are any defined. So in your root rails app you can add the Aptfile with any packages you need.

I’m also copying the entrypoint.sh file that is used as a cleanup script. It goes in and removes any server.pid file inside the app structure.

Last steps are for gem installation and asset precompilation.

The DockerFile for the server

This DockerFile is using a docker image that has nginx + pagespeed built.

The main thing I’m doing here is copying the various nginx configuration files into the /etc/nginx folder.

The Nginx configuration

Here I made different files to hold each component. It makes the whole structure easier to read and navigate. The biggest one is the pagespeed.conf file. I copied the documentation and added that over each filter to easily understand what you might want on and off.

The main nginx configuration:

The performance configuration:

The routing configuration:

The pagespeed configuration:

Create the docker compose file

Let’s wrap all of the above together into a docker-compose.yml file that sits in the root of the app.

The file defines the configuration for all instances that we need. In our case: rails, nginx, postgresql, redis and memcached.

Bonus: create a Makefile

To make things faster and shorter to trigger I also made a MakeFile. It holds some of the commands I use the most.

What happened to our server?

We are running the most basic heroku.com dyno for epicpxls.com and after doing this transition from passenger to nginx + pagespeed the memory usage got really stable.

This is of course a short period of time but I wanted to show the difference.

For the heroku server for the sake of simplicity I decided to have 100% the same nginx structure and configuration as above but to utilise a buildpack (https://github.com/benmurden/nginx-pagespeed-buildpack).

We also have jemalloc but that was there before and it did not make a huge difference. https://github.com/gaffneyc/heroku-buildpack-jemalloc.git

Conclusion

This is the main structure that I made for the docker implementation. 
Next step after getting all of this together is to build the whole system. Using the Makefile above you can just run:

make build

Next you have to start all the docker instances with:

make start

You can access the application by opening the browser and typing http://localhost


Other tutorials/links that helped me: