django and heroku

Production Django Deployments on Heroku

Production Django Deployments on Heroku




We use Heroku to host the TestDriven.io learning platform so that we can focus on application development rather than configuring web servers, installing Linux packages, setting up load balancers, and everything else that goes along with infrastructure management on a traditional server.

This article aims to simplify the process of deploying, maintaining, and scaling a production-grade Django app on Heroku. We'll also review some tips and tricks for simplifying the deployment process.

Contents

Heroku

Why Heroku? Like Django, Heroku embraces the "batteries included" philosophy. It's an opinionated environment, but it's also an environment that you don't have to manage—so you can focus on application development rather than the environment supporting it.

If you use your own infrastructure or an Infrastructure as a Service (IaaS) solution—like Digital Ocean, Amazon EC2, Google Compute Engine, to name a few—you must either hire a sys admin/devops person or take on that role yourself. The former costs money while the latter slows down your velocity. Heroku will probably end up costing you more in hosting than an IaaS solution, but you will save money since you don't need to hire someone to administer the infrastructure and you can move faster on the application, which is what matters most at the the end of the day.

Tips:

  1. Make sure you're using Heroku with the latest Heroku Stack.
  2. Use either uWSGI or Gunicorn as your production WSGI server. Either is fine. If you don't know why you'd prefer one WSGI server over another, it doesn't really matter. It's not difficult to switch later on either.
  3. Run long-running or CPU-intensive processes, like email delivery or PDF report generation, outside of the web application asynchronously with either Celery or RQ along with the Heroku Redis add-on. For reference, we use Django-RQ.
  4. Run at least two web and background processes for redundancy.
  5. Use SSL.
  6. Follow the Twelve-Factor App methodology.
  7. Add caching.

Database

Tips:

  1. Use a Heroku standard (or higher) tier Postgres database. Review the disc space, memory, and concurrent connection limits for each tier as well as the Concurrency and Database Connections in Django article.
  2. Schedule daily backups of the production database via Heroku PGBackups.
  3. Keep your migrations clean and manageable by squashing or resetting them from time to time.

Continuous Integration and Delivery

The Heroku runtime is both stateless and immutable, which helps enable continuous delivery. On each application deploy, a new virtual machine is constructed, configured, and moved into production.

Because of this, you do not need to worry about:

  1. Using a process manager to stand up your services as Heroku handles this for you via a Dyno Manager.
  2. Configuring a deployment mechanism for updating and restarting the app.

Heroku works with a number of Continuous Integration (CI) services, like Circle and Travis, and they also offer their own CI solution—Heroku CI.

Tips:

  1. Set up automatic deployments. Manual deployments are error prone due to human error.
  2. Run the Django deployment checklist (manage.py check --deploy) in your production CI build.
  3. At TestDriven.io, we use a form of GitOps where the state of the app is always kept in git and changes to the staging and production environments only happen in CI. Consider using this approach to help speed up development and introduce a stable rollback system.
  4. Deploy regularly, at a scheduled time when developers are available in case something goes wrong.
  5. Use release tags so you know exactly which version of the code is running in production—i.e., git tag -a "$ENVIRONMENT/${VERSION}".

Static and Media Files

Tips:

  1. Use WhiteNoise for static files and then throw a CDN, like Cloudflare or CloudFront, in front of it.
  2. For user-uploaded media files, use S3 and django-storages.

Environments

Tips:

  1. For staging, use a different Heroku app. Make sure to turn maintenance mode on when it's not in use so that Google's crawlers don't inadvertently come across it.

Testing

Write tests. Tests are a safeguard, so you don't accidentally change the functionality of your application. It's much better to catch a bug locally from your test suite than by a customer in production.

Tips:

  1. Ignore the traditional testing pyramid. Spend half your time writing Django unit tests (with both pytest and Hypothesis). Spend the other half writing browser-based integration and end-to-end tests with Cypress. Compared to Selenium, Cypress tests are much easier to write and maintain. We recommend incorporating Cypress into your everyday TDD workflow. Review Modern Front-End Testing with Cypress for more info on this.

Monitoring and Logging

Monitoring and logging are a crucial part of a your app's reliability, making it easier to:

  1. Discover errors at an early stage.
  2. Understand how your app works.
  3. Analyze performance.
  4. Determine if your app is running correctly.

Your logs should always have a timestamp and a log level. They should also be human readable and easy to parse.

On the monitoring side of things, set up alerts to help reduce and preempt downtimes. Set up notifications so you can fix issues and address bottlenecks before your customers start to complain.

As you have seen, Heroku provides a number of services via the add-on system. This system is one of the powerful tools that you get out of the box from Heroku. You have hundreds of services at your disposable that take minutes to configure, many of which are useful for logging, monitoring, and error tracking.

Tips:

  1. Heroku retains only the most recent 1500 lines of consolidated logs, which will just be a couple of seconds of logs. So, you'll need to send logs to a remote logging service, like Logentries, to aggregate all of your logs.
  2. Use Scout for application performance monitoring in order to track down performance issues.
  3. Use Sentry for exception monitoring to get notifications when errors occur in your application.
  4. You can monitor the basics like memory usage and CPU load directly from Heroku's Application Metrics dashboard.
  5. Use Uptime Robot, which does not have a Heroku add-on, to ensure your site is up.

Conclusion

Hopefully, this article provided some useful information that will help simplify the process of deploying and maintaining a production Django app on Heroku.

Remember: Web development is complex because of all the moving pieces. You can counter that by:

  1. Breaking things up into small, easily-digestible pieces.
  2. Removing pieces altogether by using Django and Heroku—both of which make it easier to develop and deploy secure, scalable, and maintainable web apps since they embrace stability and a "batteries included" philosophy.

Curious about what the full architecture looks like with Heroku?

django architecture

Once you have Celery and Gunicorn configured, you can focus the majority, if not all, of your time on developing your application—everything else is an add-on.

Recommended resources:

  1. How to Deploy Software
  2. Thoughts on Web Application Deployment





Join our mailing list to be notified about course updates and new tutorials.

 

Microservices with Docker, Flask, and React

Get the full course. Learn how to build, test, and deploy microservices to Amazon ECS powered by Docker, Flask, and React!

View the Course

Microservices with Docker, Flask, and React

Get the full course. Learn how to build, test, and deploy microservices to Amazon ECS powered by Docker, Flask, and React!


Table of Contents