Deploy Rails and Sidekiq to Render.com using YAML
Tags: rails, render, devops, yaml
Published: 2021-10-26 21:07:58

[Render.com](https://render.com) is a new Platform-as-a-service offering that's a great alternative to Heroku. Rather than think in terms of "apps" as Heroku does; Render has the concept of "services". So your Rails app would be a service; your database would be another service; Redis would be another service etc. Services could also potentially be shared between multiple apps.  
  
Any non-trivial Rails app these days needs [Background Jobs](https://guides.rubyonrails.org/active_job_basics.html) and a popular framework for this is [Sidekiq](http://github.com/mperham/sidekiq/). Sidekiq uses Redis as a data store. This means we need to deploy 4 services to Render to run our app:  
  

1. Rails web service
2. Sidekiq background service
3. PostgreSQL database
4. Redis

  
Render supports "infrastructure as code" so we're going to define these services in a YAML file so it's tracked in `git` along with our application code. Ruby environments are supported natively and they also have a managed PostgreSQL database offering. For anything else we need to use a Docker image, so using Redis is a tiny bit trickier.  
  

> _At the time of writing,_ [_Render is working on a managed Redis offering_](https://feedback.render.com/features/p/managed-redis)_. When that's live, it should be easier to deploy and manage a Redis service._

  
Render supports 3 service types:  
  

- Web service [_exposed to the internet via_ `https` _on port 80_]
- Private service [_exposed only to all your other services_]
- Background worker [_not exposed to the network at all_]

  

## Rails on Render

  
We'll deploy the Rails web app as a web service, the Sidekiq worker as a background worker and Redis as a private service using a [Render maintained `Dockerfile`](http://github.com/render-examples/redis).  
  
Firstly, we need to update our database and Puma configurations for production. Follow [this section from Render's Rails deployment guide](https://render-web.onrender.com/docs/deploy-rails#go-production-ready) and then return to this post.  
  
Then, we need to add a build script that will be run when the app is deployed. Create a file called `render-build.sh` in your `bin` directory and add the following contents:  
  
```shell
#!/usr/bin/env bash
# exit on error
set -o errexit

bundle install
bundle exec rake assets:precompile
bundle exec rake assets:clean
bundle exec rake db:migrate
```

> _This script is also from Render's_ [_Rails deployment guide_](https://render-web.onrender.com/docs/deploy-rails#create-a-build-script)_._

Ensure the script is executable by running the following command:  
  
```shell
chmod a+x bin/render-build.sh
```

Lastly, we create our infrastructure specification. In your project root, create a file called `render.yaml` and paste in the following:  
  
```yaml
services:
  - type: web
    name: myapp-web
    env: ruby
    region: frankfurt # or oregon
    plan: starter
    numInstances: 1
    buildCommand: ./bin/render-build.sh
    startCommand: REDIS_URL="redis://${REDIS_HOST}" bundle exec puma -C config/puma.rb
    domains:
      - example.com # replace with your domain name
    envVars:
      - key: DATABASE_URL
        fromDatabase:
          name: myapp-db
          property: connectionString
      - key: REDIS_HOST
        fromService:
          name: myapp-redis
          type: pserv
          property: hostport
      - key: RAILS_MASTER_KEY
        sync: false

  - type: worker
    name: myapp-sidekiq
    env: ruby
    region: frankfurt # or oregon
    plan: starter
    buildCommand: bundle install && bundle exec rake assets:precompile
    startCommand: REDIS_URL="redis://${REDIS_HOST}" bundle exec sidekiq -e production
    envVars:
      - key: DATABASE_URL
        fromDatabase:
          name: myapp-db
          property: connectionString
      - key: REDIS_HOST
        fromService:
          name: myapp-redis
          type: pserv
          property: hostport
      - key: RAILS_MASTER_KEY
        sync: false

  - type: pserv
    name: myapp-redis
    env: docker
    region: frankfurt # or oregon
    repo: https://github.com/render-examples/redis.git
    numInstances: 1
    disk:
      name: myapp-redis-data
      mountPath: /var/lib/redis
      sizeGB: 1

databases:
  - name: myapp-db
    plan: starter
    region: frankfurt # or oregon

```

> _The full Render YAML specification is_ [_available here_](https://render-web.onrender.com/docs/yaml-spec)_._

Most of the above file should be self explanatory. I recommend changing the service names to something specific to your app. The only tricky bit is providing the `REDIS_URL` environment variable to our Rails and Sidekiq services. Unlike PostgreSQL which is a managed service, Redis is a generic private service; so the only the host name and port is given to us in environment variables by the Render platform. This means we need to add the `redis://` protocol directive to the URL on our own.   
  
I found that the easiest way to do this was interpolate the `REDIS_HOST` environment variable that Render gives us to create a `REDIS_URL` variable in the `startCommand` for our services. You can how this is done in the Rails and Sidekiq services above.  

> _If you run the Rails console in the Render dashboard, you'll need to invoke it using_ `REDIS_URL="redis://${REDIS_HOST}" bundle exec rails console` otherwise the console process won't be able to find the Redis service.
  
And finally, all we need to do is connect this YAML file to Render. Go to the Render dashboard, click **New** in the top right corner and select **Blueprint**.   
  
<figure class="attachment attachment--preview attachment--png">
  <img src="https://cdn.chapter24.blog/1634677726VzxY8lo8FiZM-AkRYp7Ygw">
</figure>  
  
Follow the on screen instructions to connect your repository and you should be good to go!  
  
## Conclusion

I'm using the above approach in my app: [Scattergun](https://scattergun.email). So far I'm really happy with it. I'm excited to see what the Render team has in store for the future and personally I plan to use them for all my projects in the foreseeable future.

## Further reading

- [Render's guide to deploying Rails](https://render-web.onrender.com/docs/deploy-rails)
- [Render's guide to deploying Sidekiq](https://render-web.onrender.com/docs/deploy-sidekiq-worker)
- [Render's guide to deploy persistent Redis](https://github.com/render-examples/redis)
- [Render vs Heroku](https://render.com/render-vs-heroku-comparison)

  
_Scattergun is the easiest way to collect email addresses on your landing page and send emails to your mailing list._ [_Get started for free_](https://scattergun.email)_!_