Skip to content

Latest commit

 

History

History
192 lines (153 loc) · 7.89 KB

File metadata and controls

192 lines (153 loc) · 7.89 KB

Going to Production

Is all fun and game until you are need of put it in production.

It’s time to deploy the first version of our site and make it public. They say that if you wait until you feel ready to ship, then you’ve waited too long.

Is our site usable? Is it better than nothing? Can we make lists on it? Yes, yes, yes.

No, you can’t log in yet. No, you can’t mark tasks as completed. But do we really need any of that stuff? Not really—​and you can never be sure what your users are actually going to do with your site once they get their hands on it. We think our users want to use the site for to-do lists, but maybe they actually want to use it to make "top 10 best fly-fishing spots" lists, for which you don’t need any kind of "mark completed" function. We won’t know until we put it out there.

Over the next couple of chapters we’re going to go through and actually deploy our site to a real, live web server.

You might be tempted to skip this bit—​there’s lots of daunting stuff in it, and maybe you think this isn’t what you signed up for. But I strongly urge you to give it a go. This is one of the sections of the book I’m most pleased with, and it’s one that people often write to me about saying they were really glad they stuck through it.

If you’ve never done a server deployment before, it will demystify a whole world for you, and there’s nothing like the feeling of seeing your site live on the actual internet. Give it a buzzword name like "DevOps" if that’s what it takes to convince you it’s worth it.

The Danger Areas of Deployment

Deploying a site to a live web server can be a tricky topic. Oft heard is the forlorn cry, "but it works on my machine!"

Some of the danger areas of deployment include:

Networking

Once we’re off our own machine, networking issues come in: making sure that DNS is routing our domain to the correct IP address for our server, making sure our server is configured to listen to traffic coming in from the world, making sure it’s using the right ports, and making sure any firewalls in the way are configured to let traffic through.

Dependencies

We need to make sure that the packages our software relies on (Python, Django, and so on) are installed on the server and have the correct versions.

The database

There can be permissions and path issues, and we need to be careful about preserving data between deploys.

Static files (CSS, JavaScript, images, etc.)

Web servers usually need special configuration for serving these.

Security and configuration

Once we’re on the public internet, we need to worry more about security. Various settings that are really useful for local development (like the Django debug page) become dangerous in production (because they expose our source code in tracebacks).

Reproducibility and divergence between local dev and prod

All of the above add up to differences between your local development environment and the way code runs in production. We want to be able to reproduce the way things work on our machine, as closely as possible, in production (and vice versa) to give us as much confidence as possible that "it works on my machine" means "it’s going to work in production".

One way to approach the problem is to get a server and start manually configuring and installing everything, hacking about until it works, and maybe think about automating things later.[1]

But if there’s one thing we’ve learned in the world of Agile/Lean software development, it’s that taking smaller steps usually pays off.

How can we take smaller, safer steps towards a production deployment? Can we simulate the process of moving to a server so that we can iron out all the bugs before we actually take the plunge? Can we then make small changes one at a time, solving problems one by one, rather than having to bite off everything in one mouthful? Can we use our existing test suite to make sure things work on the server, as well as locally?

Absolutely we can. And if you’ve looked at the table of contents, I’m sure you’re already guessing that Docker is going to be part of the answer.

An Overview of Our Deployment Procedure

Over the next three chapters, I’m going to go through a deployment procedure. It isn’t meant to be the perfect deployment procedure, so please don’t take it as being best practice or a recommendation—​it’s meant to be an illustration, to show the kinds of issues involved in putting code into production, and where testing fits in.

[chapter_09_docker]
  • Adapt our functional tests (FTs) so they can run against a container.

  • Build a minimal Dockerfile with everything we need to run our site.

  • Learn how to build and run a container on our machine.

  • Get a first cut of our code up and running inside Docker, with passing tests.

[chapter_10_production_readiness]
  • Gradually, incrementally change the container configuration to make it production-ready.

  • Regularly rerun the FTs to check we didn’t break anything.

  • Address issues to do with the database, static files, secrets, and so on.

[chapter_11_server_prep]
  • Set up a "staging" server,[2] using the same infrastructure that we plan to use for production.

  • Set up a real domain name and point it at this server.

  • Install Ansible and flush out any networking issues.

[chapter_12_ansible]
  • Gradually build up an Ansible playbook to deploy our containers on a real server.

  • Again, use our FTs to check for any problems.

  • Learn how to SSH (Secure Shell) into the server to debug things, locate logs, and find other useful information.

  • Confidently deploy to production once we have a working deployment script for staging.

TDD and Docker Versus the Danger Areas of Deployment

Hopefully you can start to see how the combination of TDD, Docker, staging, and automation are going to help minimise the risk of the various "danger areas":

Containers as mini servers

Containers will act as mini servers letting us flush out issues with dependencies, static files, and so on. A key advantage is that they’ll give us a way of getting faster feedback cycles; because we can spin them up locally almost instaneously, we can very quicly see the effect of any changes.

Packaging Python and system dependencies

Our containers will package up both our Python and system dependencies, including a production-ready web server and static files system, as well as many production settings and configuration differences. This minimises the difference between what we can test locally, and what we will have on our servers. As we’ll see, it will give us a reliable way to reproduce bugs we see in production, on our local machine.

Fully automated FTs

Our FTs mean that we’ll have a fully automated way of checking that everything works.

Running FTs on staging server

Later, when we deploy our containers to a staging server, we can run the FTs against that too. It’ll be slightly slower and might involve some fiddly compromises, but it’ll give us one more layer of reassurance.

Automating build and deployment

Finally, by fully automating container creation and deployment, and by testing the end results of both these things, we maximise reproducibility, thus minimising the risk of deployment to production.

Oh, but there’s lots of fun stuff coming up! Just you wait!


1. This was, more or less, the approach I took in earlier editions of the book. With a fair bit of testing thrown in, of course.
2. Some people prefer the term pre-prod or test environment. It’s all the same idea.