THE MIGRATION LINE
INCIDENT // GITHUB-2017MIGRATED

For eight years GitHub's main Ruby app ran on Unicorn processes managed by God on Puppet-configured servers, deployed over SSH. This is how they moved github.com's web and API traffic onto Kubernetes.

GITHUB·2017·INFRA / KUBERNETES / CONTAINERS / DEPLOYMENT·✓ Sourced — github.blog
System stress over timeNominal
github/github (Rails)App
~1 monthCutover
100+/dayReview-lab deploys
100 req/secRamp start
BEFORE

Eight years of Unicorn, God, Puppet, and SSH

GitHub’s core application — the Ruby on Rails codebase known internally as github/github — ran the way it had for about eight years: Unicorn worker processes, supervised by a process manager called God, on servers configured with Puppet. Shipping code meant Capistrano opening SSH connections to those machines to update the code in place and restart the processes.

It worked, and it had barely changed in nearly a decade. The problem was what it couldn’t do as GitHub grew.

AFTER

github.com's web and API traffic, all on Kubernetes

By the end of the effort, all web and API traffic for github.com and api.github.com was served by github/github running on Kubernetes. The payoff GitHub was after was self-service: engineers could experiment with, deploy, and scale new services in seconds rather than waiting on SRE provisioning, and dozens of applications were already deploying to similar clusters without needing an SRE to stand up servers for them.

That freed the SRE team to shift effort away from hand-maintaining machines and toward building infrastructure products that encode best practices for everyone else.

THE BRIDGE

Practice on throwaway environments, then ramp production by percentage

GitHub crossed the gap in two stages. First came “review lab” — a Kubernetes cluster in an AWS VPC, managed with Terraform and kops, that let engineers deploy any pull request into an isolated namespace via chatops. It required a Dockerfile for github/github, CI enhanced to build containers, more than fifty YAML Kubernetes resources, and a kube-me service to drive deploys. At peak the review lab was taking 100+ deployments a day, which meant the whole company was learning Kubernetes on a low-risk workload before it ever touched production.

Then production, on GitHub’s own metal cloud. They deployed Kubernetes on physical data-center hardware, wired container networking with Calico, and taught GitHub’s internal load balancer (GLB) to route to Kubernetes NodePort services. The cutover ramped by percentage — starting at around 100 requests per second, expanding to 10% of production traffic, then to the full frontend — and the complete migration from 0% to 100% took roughly a month.

WHAT IT COST

Nodes that still panic, and clusters designed around failure

GitHub was candid that this was not a finished, frictionless system. Under high load or high rates of container churn, some Kubernetes nodes would kernel panic and reboot — a situation they said they were not satisfied with and were investigating at high priority, relying meanwhile on Kubernetes automatically routing around the failures inside their error budget. Failure testing also surfaced unexpected cluster degradation when a single apiserver node went down, likely from how the various clients and the load balancer interacted.

That second finding directly shaped the design: GitHub ran multiple independent clusters per site as “cluster groups,” used custom resource annotations for per-cluster configuration, and automated diverting traffic away from unhealthy clusters — treating individual cluster failure as expected rather than exceptional.

Rehearse the migration on a workload you can afford to lose, so that by the time the crown jewels move, the only new thing is the stakes.

Source — read the original

A plain-language, AI-drafted and human-edited retelling of the article published on github.blog, reorganized and explained in our own structure and words, with original analysis in the editor's note above. The facts, numbers, and decisions belong to the original author and are not altered. For the full depth, read the source.

← All systems