Using NGiNX for release automation at The Atlantic

Frankie Dintino
Frankie DintinoSenior Web Developer & Interactive Lead at The Atlantic
Using NGiNX for release
automation at The Atlantic
About the speakers
Mike Howsden is the DevOps Lead at
The Atlantic
Frankie Dintino is a Senior Full-Stack
Developer at The Atlantic
One Virtual Machine
Nearly Unlimited QA environments
Our development workflow
• Two week sprints
• New code is committed to a branch in git
• When coding is complete, a Pull Request is opened in GitHub for review
• Branch can be staged onto a beta server for QA
• PR is merged into a branch named develop when code review and QA is
complete
• The develop branch is merged into the master branch when it's time for
a deployment
Discontinuous Integration (the old way)
ssh betaserver

cd /www/beta5

source bin/activate

git fetch origin && git reset --hard && git checkout -t origin/my-branch

pip install --upgrade -r requirements.txt

(cd frontend && npm install && gulp build)

importdb atl_db_beta5

django-admin collectstatic -l --noinput

touch wsgi.py

ohpleasegod --help
• Tedious!
Discontinuous Integration
Why was this bad?
• Tedious!
• Error prone!
Discontinuous Integration
Why was this bad?
Why was this bad?
Discontinuous Integration
• Tedious!
• Error prone!
• Stateful!
Why was this bad?
Discontinuous Integration
• Tedious!
• Error prone!
• Stateful!
• Enough instances to waste resources, not enough to ensure
one is always available
Why was this bad?
Discontinuous Integration
• Tedious!
• Error prone!
• Stateful!
• Enough instances to waste resources, not enough to ensure
one is always available
• Worst of all, NGINX played only a minor role
We can do better!
Business Need
• Developers need to easily stage their work for peer and
stakeholder review.
•
Beta architecture overview
Infinite* beta environments—components
• Jenkins
• Reflinks
• supervisord managing uWSGI emperor mode
• nginx-mod-passenger for NodeJS apps
• NGiNX and uWSGI socket files
• Database snapshots
• External proxy
* ish—as many as we need
New process
Two common use-cases, with different requirements:
1. Simple bug fixes and minor features
2. Long-running feature branches
New process—typical setup
Open a pull request
Jenkins build (roughly 10 minutes)
~10:00
1
2
3
Using NGiNX for release automation at The Atlantic
Using NGiNX for release automation at The Atlantic
New process—“named betas”
• Uses a distinct, persistent copy of the database (to allow for
schema changes and feature-specific data)
• Accessible outside the internal network with authentication
New process—“named betas”
Push out a branch: beta/my-feature
Jenkins build (roughly 10 minutes)
~10:00
1
2
3
Business Value
• Efficiency: Cuts down on developer time spent on tasks
unrelated to business goals.
• Morale: Automates repetitive/monotonous work.
• Improves Coverage/Consistency: No barriers to manual
testing, even for trivial changes. Each build environment is
created with the exact same process.
Infinite* beta environments—components
• Jenkins
• Reflinks
• supervisord managing uWSGI emperor mode
• nginx-mod-passenger for NodeJS apps
• NGiNX and uWSGI socket files
• Database snapshots
• External proxy
* ish—as many as we need
Jenkins—stage beta
Jenkinsfile
• A declarative build and deployment script, committed to
source control in the root of the repo
• Hooked into github notifications for pull request opens and
branch pushes
• Reasonably powerful control over conditional logic,
parallelization, pass/fail conditions, etc.
Jenkinsfile
pipeline {

// ...

stage('stage beta') {

when { anyOf {

expression { BRANCH_NAME ==~ /PR-[0-9]+/ } // a pull request

branch 'develop' // development branch

expression { BRANCH_NAME.startsWith('beta/') } // 'beta/feature'

} }

steps {

// Initialize database

sh """ ssh devdbserver "create_beta_db $BRANCH_NAME" """

// If the workspace doesn't exist, create a reflink copy

sh """ssh betaserver 

"[ -d ${WORKSPACE} ] || cp -ar --reflink=auto 

/www/builds/theatlantic/develop.base ${WORKSPACE}" """

// ...continued
Jenkinsfile (continued)
// ...

stage('stage beta') {

// ...

steps {

// Copy current build to remote workspace dir

sh """rsync -acvzhO --delete 

--exclude "*.pyc" --exclude .git --exclude ... 

$WORKSPACE/ betaserver:$WORKSPACE/ """



// Create wsgi files, which will initialize uWSGI emperor processes

sh """ssh betaserver "$WORKSPACE/support/beta/create_wsgi.py" """

}

}
Infinite* beta environments—components
• Jenkins
• Reflinks
• supervisord managing uWSGI emperor mode
• nginx-mod-passenger for NodeJS apps
• NGiNX and uWSGI socket files
• Database snapshots
• External proxy
* ish—as many as we need
Jenkins—stage beta
• Initializes with a reflink copy of a previous build to save on
disk space (1.2G => 3M)
• Uses rsync to copy the newly created environment to the
betas server over top of this copy
Reflinks (copy-on-write)
• BTRFS on debian or ubuntu
• XFS on RHEL, CentOS, or Fedora
• mkfs.xfs must be called with reflink=1
• cp -ar --reflink=auto
• only uses the space required for differences between builds
• considered “experimental”—requires custom-built kernel
(may be enabled by default in Fedora 29)
Infinite* beta environments—components
• Jenkins
• Reflinks
• supervisord managing uWSGI emperor mode
• nginx-mod-passenger for NodeJS apps
• NGiNX and uWSGI socket files
• Database snapshots
• External proxy
* ish—as many as we need
uWSGI emperor + supervisord
[program:zerg_server]

command = /sbin/uwsgi

--master --thunder-lock

--emperor "/www/builds/theatlantic/*/uwsgi/master.*.ini"

autorestart = true



[program:workers]

command = /sbin/uwsgi

--master --thunder-lock

--emperor "/www/builds/theatlantic/*/uwsgi/workers.*.ini"

autorestart = true
Infinite* beta environments—components
uWSGI zerg master uWSGI zerg workers
uWSGI emperor + supervisord
; /www/builds/theatlantic/pr-1234/uwsgi/master.theatlantic.ini

[uwsgi]

; %n: current config filename, without the .ini extension

; Strip off the leading 'master.' part of the filename to determine the app.

app = @(exec:///usr/bin/perl -e '$_ = "%n"; s/^master.//g; print')



subdomain = %3 ; the 4th path component (0-indexed); eg pr-1234



thunder-lock = true

master = true

processes = 0



http = /var/run/uwsgi/%(app)-%(subdomain).sock

zerg-server = /var/run/uwsgi/%(app)-%(subdomain)-workers.sock
uWSGI zerg server
; /www/builds/theatlantic/pr-1234/uwsgi/master.theatlantic.ini

[uwsgi]

; %n: current config filename, without the .ini extension

; Strip off the leading 'master.' part of the filename to determine the app.

app = @(exec:///usr/bin/perl -e '$_ = "%n"; s/^master.//g; print')



subdomain = %3 ; the 4th path component (0-indexed); eg pr-1234



thunder-lock = true

master = true

processes = 0



http = /var/run/uwsgi/%(app)-%(subdomain).sock

zerg-server = /var/run/uwsgi/%(app)-%(subdomain)-workers.sockzerg-server = /var/run/uwsgi/%(app)-%(subdomain)-workers.sock
uWSGI zerg workers
; /www/builds/theatlantic/pr-1234/uwsgi/worker.theatlantic.ini

[uwsgi]

; attach to zerg pool

zerg = /var/run/uwsgi/%(app)-%(subdomain)-workers.sock



cheaper-algo = busyness

cheaper = 1 ; minimum number of workers to keep at all times

cheaper-initial = 2 ; starts with minimal workers

cheaper-step = 2 ; spawn at most 2 workers at a time

cheaper-overload = 30 ; seconds between busyness checks

cheaper-busyness-multiplier = 50

cheaper-busyness-penalty = 2



; how many requests are in backlog before quick response triggered

cheaper-busyness-backlog-alert = 33

cheaper-busyness-backlog-step = 1

idle = 86400 ; workers shut down if the beta is idle for a day



wsgi-file = %(env_dir)/apps/wsgi.py

env = DJANGO_SETTINGS_MODULE=settings.%(app).live
NGiNX, proxying to uWSGI socket files
server {
server_name "~^(?<subdomain>.+).beta.theatlantic.com$";
root /www/builds/theatlantic/$subdomain;



location / {

try_files /assets/$uri @django;

}



location @django { 

internal;

include includes/proxypass.conf;

proxy_pass http://unix:/var/run/uwsgi/theatlantic-$subdomain.sock;

}

}
nginx-mod-passenger for nodejs
server {

server_name "~^(?<subdomain>.+).ampbeta.theatlantic.com$";



root /www/builds/amp/${subdomain}/public;



passenger_enabled on;

passenger_app_type node;

passenger_app_root /www/builds/amp/${subdomain};

passenger_restart_dir /www/builds/amp/${subdomain};

passenger_startup_file dist/host/bin/www.js;

}
Questions?
Thank you!
github.com/theatlantic/nginxconf-2018
frankie@theatlantic.com
mhowsden@theatlantic.com

1 of 39

Recommended

2 + 2 = 5: Monkey-patching CPython with ctypes to conform to Party doctrine by
2 + 2 = 5: Monkey-patching CPython with ctypes to conform to Party doctrine2 + 2 = 5: Monkey-patching CPython with ctypes to conform to Party doctrine
2 + 2 = 5: Monkey-patching CPython with ctypes to conform to Party doctrineFrankie Dintino
617 views34 slides
High Availability Django - Djangocon 2016 by
High Availability Django - Djangocon 2016High Availability Django - Djangocon 2016
High Availability Django - Djangocon 2016Frankie Dintino
1.6K views32 slides
ChatGPT and the Future of Work - Clark Boyd by
ChatGPT and the Future of Work - Clark Boyd ChatGPT and the Future of Work - Clark Boyd
ChatGPT and the Future of Work - Clark Boyd Clark Boyd
20.3K views69 slides
Getting into the tech field. what next by
Getting into the tech field. what next Getting into the tech field. what next
Getting into the tech field. what next Tessa Mero
5K views22 slides
Google's Just Not That Into You: Understanding Core Updates & Search Intent by
Google's Just Not That Into You: Understanding Core Updates & Search IntentGoogle's Just Not That Into You: Understanding Core Updates & Search Intent
Google's Just Not That Into You: Understanding Core Updates & Search IntentLily Ray
5.8K views99 slides
How to have difficult conversations by
How to have difficult conversations How to have difficult conversations
How to have difficult conversations Rajiv Jayarajah, MAppComm, ACC
4.3K views19 slides

More Related Content

Recently uploaded

LAVADORA ROLO.docx by
LAVADORA ROLO.docxLAVADORA ROLO.docx
LAVADORA ROLO.docxSamuelRamirez83524
7 views1 slide
DSD-INT 2023 Delft3D FM Suite 2024.01 2D3D - New features + Improvements - Ge... by
DSD-INT 2023 Delft3D FM Suite 2024.01 2D3D - New features + Improvements - Ge...DSD-INT 2023 Delft3D FM Suite 2024.01 2D3D - New features + Improvements - Ge...
DSD-INT 2023 Delft3D FM Suite 2024.01 2D3D - New features + Improvements - Ge...Deltares
16 views12 slides
Upgrading Incident Management with Icinga - Icinga Camp Milan 2023 by
Upgrading Incident Management with Icinga - Icinga Camp Milan 2023Upgrading Incident Management with Icinga - Icinga Camp Milan 2023
Upgrading Incident Management with Icinga - Icinga Camp Milan 2023Icinga
36 views17 slides
DSD-INT 2023 FloodAdapt - A decision-support tool for compound flood risk mit... by
DSD-INT 2023 FloodAdapt - A decision-support tool for compound flood risk mit...DSD-INT 2023 FloodAdapt - A decision-support tool for compound flood risk mit...
DSD-INT 2023 FloodAdapt - A decision-support tool for compound flood risk mit...Deltares
12 views34 slides
DSD-INT 2023 Simulation of Coastal Hydrodynamics and Water Quality in Hong Ko... by
DSD-INT 2023 Simulation of Coastal Hydrodynamics and Water Quality in Hong Ko...DSD-INT 2023 Simulation of Coastal Hydrodynamics and Water Quality in Hong Ko...
DSD-INT 2023 Simulation of Coastal Hydrodynamics and Water Quality in Hong Ko...Deltares
10 views23 slides
DSD-INT 2023 Baseline studies for Strategic Coastal protection for Long Islan... by
DSD-INT 2023 Baseline studies for Strategic Coastal protection for Long Islan...DSD-INT 2023 Baseline studies for Strategic Coastal protection for Long Islan...
DSD-INT 2023 Baseline studies for Strategic Coastal protection for Long Islan...Deltares
10 views30 slides

Recently uploaded(20)

DSD-INT 2023 Delft3D FM Suite 2024.01 2D3D - New features + Improvements - Ge... by Deltares
DSD-INT 2023 Delft3D FM Suite 2024.01 2D3D - New features + Improvements - Ge...DSD-INT 2023 Delft3D FM Suite 2024.01 2D3D - New features + Improvements - Ge...
DSD-INT 2023 Delft3D FM Suite 2024.01 2D3D - New features + Improvements - Ge...
Deltares16 views
Upgrading Incident Management with Icinga - Icinga Camp Milan 2023 by Icinga
Upgrading Incident Management with Icinga - Icinga Camp Milan 2023Upgrading Incident Management with Icinga - Icinga Camp Milan 2023
Upgrading Incident Management with Icinga - Icinga Camp Milan 2023
Icinga36 views
DSD-INT 2023 FloodAdapt - A decision-support tool for compound flood risk mit... by Deltares
DSD-INT 2023 FloodAdapt - A decision-support tool for compound flood risk mit...DSD-INT 2023 FloodAdapt - A decision-support tool for compound flood risk mit...
DSD-INT 2023 FloodAdapt - A decision-support tool for compound flood risk mit...
Deltares12 views
DSD-INT 2023 Simulation of Coastal Hydrodynamics and Water Quality in Hong Ko... by Deltares
DSD-INT 2023 Simulation of Coastal Hydrodynamics and Water Quality in Hong Ko...DSD-INT 2023 Simulation of Coastal Hydrodynamics and Water Quality in Hong Ko...
DSD-INT 2023 Simulation of Coastal Hydrodynamics and Water Quality in Hong Ko...
Deltares10 views
DSD-INT 2023 Baseline studies for Strategic Coastal protection for Long Islan... by Deltares
DSD-INT 2023 Baseline studies for Strategic Coastal protection for Long Islan...DSD-INT 2023 Baseline studies for Strategic Coastal protection for Long Islan...
DSD-INT 2023 Baseline studies for Strategic Coastal protection for Long Islan...
Deltares10 views
DSD-INT 2023 Wave-Current Interaction at Montrose Tidal Inlet System and Its ... by Deltares
DSD-INT 2023 Wave-Current Interaction at Montrose Tidal Inlet System and Its ...DSD-INT 2023 Wave-Current Interaction at Montrose Tidal Inlet System and Its ...
DSD-INT 2023 Wave-Current Interaction at Montrose Tidal Inlet System and Its ...
Deltares9 views
DSD-INT 2023 Modelling litter in the Yarra and Maribyrnong Rivers (Australia)... by Deltares
DSD-INT 2023 Modelling litter in the Yarra and Maribyrnong Rivers (Australia)...DSD-INT 2023 Modelling litter in the Yarra and Maribyrnong Rivers (Australia)...
DSD-INT 2023 Modelling litter in the Yarra and Maribyrnong Rivers (Australia)...
Deltares9 views
Cycleops - Automate deployments on top of bare metal.pptx by Thanassis Parathyras
Cycleops - Automate deployments on top of bare metal.pptxCycleops - Automate deployments on top of bare metal.pptx
Cycleops - Automate deployments on top of bare metal.pptx
A first look at MariaDB 11.x features and ideas on how to use them by Federico Razzoli
A first look at MariaDB 11.x features and ideas on how to use themA first look at MariaDB 11.x features and ideas on how to use them
A first look at MariaDB 11.x features and ideas on how to use them
Federico Razzoli44 views
Citi TechTalk Session 2: Kafka Deep Dive by confluent
Citi TechTalk Session 2: Kafka Deep DiveCiti TechTalk Session 2: Kafka Deep Dive
Citi TechTalk Session 2: Kafka Deep Dive
confluent17 views
El Arte de lo Possible by Neo4j
El Arte de lo PossibleEl Arte de lo Possible
El Arte de lo Possible
Neo4j34 views
Roadmap y Novedades de producto by Neo4j
Roadmap y Novedades de productoRoadmap y Novedades de producto
Roadmap y Novedades de producto
Neo4j43 views
Unmasking the Dark Art of Vectored Exception Handling: Bypassing XDR and EDR ... by Donato Onofri
Unmasking the Dark Art of Vectored Exception Handling: Bypassing XDR and EDR ...Unmasking the Dark Art of Vectored Exception Handling: Bypassing XDR and EDR ...
Unmasking the Dark Art of Vectored Exception Handling: Bypassing XDR and EDR ...
Donato Onofri643 views
Elevate your SAP landscape's efficiency and performance with HCL Workload Aut... by HCLSoftware
Elevate your SAP landscape's efficiency and performance with HCL Workload Aut...Elevate your SAP landscape's efficiency and performance with HCL Workload Aut...
Elevate your SAP landscape's efficiency and performance with HCL Workload Aut...
HCLSoftware6 views

Featured

The six step guide to practical project management by
The six step guide to practical project managementThe six step guide to practical project management
The six step guide to practical project managementMindGenius
36.6K views27 slides
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright... by
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...RachelPearson36
12.6K views21 slides
Unlocking the Power of ChatGPT and AI in Testing - A Real-World Look, present... by
Unlocking the Power of ChatGPT and AI in Testing - A Real-World Look, present...Unlocking the Power of ChatGPT and AI in Testing - A Real-World Look, present...
Unlocking the Power of ChatGPT and AI in Testing - A Real-World Look, present...Applitools
55.4K views138 slides
12 Ways to Increase Your Influence at Work by
12 Ways to Increase Your Influence at Work12 Ways to Increase Your Influence at Work
12 Ways to Increase Your Influence at WorkGetSmarter
401.6K views64 slides
ChatGPT webinar slides by
ChatGPT webinar slidesChatGPT webinar slides
ChatGPT webinar slidesAlireza Esmikhani
30.3K views36 slides

Featured(20)

The six step guide to practical project management by MindGenius
The six step guide to practical project managementThe six step guide to practical project management
The six step guide to practical project management
MindGenius36.6K views
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright... by RachelPearson36
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...
RachelPearson3612.6K views
Unlocking the Power of ChatGPT and AI in Testing - A Real-World Look, present... by Applitools
Unlocking the Power of ChatGPT and AI in Testing - A Real-World Look, present...Unlocking the Power of ChatGPT and AI in Testing - A Real-World Look, present...
Unlocking the Power of ChatGPT and AI in Testing - A Real-World Look, present...
Applitools55.4K views
12 Ways to Increase Your Influence at Work by GetSmarter
12 Ways to Increase Your Influence at Work12 Ways to Increase Your Influence at Work
12 Ways to Increase Your Influence at Work
GetSmarter401.6K views
Ride the Storm: Navigating Through Unstable Periods / Katerina Rudko (Belka G... by DevGAMM Conference
Ride the Storm: Navigating Through Unstable Periods / Katerina Rudko (Belka G...Ride the Storm: Navigating Through Unstable Periods / Katerina Rudko (Belka G...
Ride the Storm: Navigating Through Unstable Periods / Katerina Rudko (Belka G...
DevGAMM Conference3.6K views
Barbie - Brand Strategy Presentation by Erica Santiago
Barbie - Brand Strategy PresentationBarbie - Brand Strategy Presentation
Barbie - Brand Strategy Presentation
Erica Santiago25.1K views
Good Stuff Happens in 1:1 Meetings: Why you need them and how to do them well by Saba Software
Good Stuff Happens in 1:1 Meetings: Why you need them and how to do them wellGood Stuff Happens in 1:1 Meetings: Why you need them and how to do them well
Good Stuff Happens in 1:1 Meetings: Why you need them and how to do them well
Saba Software25.2K views
Introduction to C Programming Language by Simplilearn
Introduction to C Programming LanguageIntroduction to C Programming Language
Introduction to C Programming Language
Simplilearn8.4K views
The Pixar Way: 37 Quotes on Developing and Maintaining a Creative Company (fr... by Palo Alto Software
The Pixar Way: 37 Quotes on Developing and Maintaining a Creative Company (fr...The Pixar Way: 37 Quotes on Developing and Maintaining a Creative Company (fr...
The Pixar Way: 37 Quotes on Developing and Maintaining a Creative Company (fr...
Palo Alto Software88.3K views
9 Tips for a Work-free Vacation by Weekdone.com
9 Tips for a Work-free Vacation9 Tips for a Work-free Vacation
9 Tips for a Work-free Vacation
Weekdone.com7.2K views
How to Map Your Future by SlideShop.com
How to Map Your FutureHow to Map Your Future
How to Map Your Future
SlideShop.com275.1K views
Beyond Pride: Making Digital Marketing & SEO Authentically LGBTQ+ Inclusive -... by AccuraCast
Beyond Pride: Making Digital Marketing & SEO Authentically LGBTQ+ Inclusive -...Beyond Pride: Making Digital Marketing & SEO Authentically LGBTQ+ Inclusive -...
Beyond Pride: Making Digital Marketing & SEO Authentically LGBTQ+ Inclusive -...
AccuraCast3.4K views
Exploring ChatGPT for Effective Teaching and Learning.pptx by Stan Skrabut, Ed.D.
Exploring ChatGPT for Effective Teaching and Learning.pptxExploring ChatGPT for Effective Teaching and Learning.pptx
Exploring ChatGPT for Effective Teaching and Learning.pptx
Stan Skrabut, Ed.D.57.6K views
How to train your robot (with Deep Reinforcement Learning) by Lucas García, PhD
How to train your robot (with Deep Reinforcement Learning)How to train your robot (with Deep Reinforcement Learning)
How to train your robot (with Deep Reinforcement Learning)
Lucas García, PhD42.5K views
4 Strategies to Renew Your Career Passion by Daniel Goleman
4 Strategies to Renew Your Career Passion4 Strategies to Renew Your Career Passion
4 Strategies to Renew Your Career Passion
Daniel Goleman122K views
The Student's Guide to LinkedIn by LinkedIn
The Student's Guide to LinkedInThe Student's Guide to LinkedIn
The Student's Guide to LinkedIn
LinkedIn87.9K views

Using NGiNX for release automation at The Atlantic

  • 1. Using NGiNX for release automation at The Atlantic
  • 2. About the speakers Mike Howsden is the DevOps Lead at The Atlantic Frankie Dintino is a Senior Full-Stack Developer at The Atlantic
  • 3. One Virtual Machine Nearly Unlimited QA environments
  • 4. Our development workflow • Two week sprints • New code is committed to a branch in git • When coding is complete, a Pull Request is opened in GitHub for review • Branch can be staged onto a beta server for QA • PR is merged into a branch named develop when code review and QA is complete • The develop branch is merged into the master branch when it's time for a deployment
  • 5. Discontinuous Integration (the old way) ssh betaserver
 cd /www/beta5
 source bin/activate
 git fetch origin && git reset --hard && git checkout -t origin/my-branch
 pip install --upgrade -r requirements.txt
 (cd frontend && npm install && gulp build)
 importdb atl_db_beta5
 django-admin collectstatic -l --noinput
 touch wsgi.py
 ohpleasegod --help
  • 7. • Tedious! • Error prone! Discontinuous Integration Why was this bad?
  • 8. Why was this bad? Discontinuous Integration • Tedious! • Error prone! • Stateful!
  • 9. Why was this bad? Discontinuous Integration • Tedious! • Error prone! • Stateful! • Enough instances to waste resources, not enough to ensure one is always available
  • 10. Why was this bad? Discontinuous Integration • Tedious! • Error prone! • Stateful! • Enough instances to waste resources, not enough to ensure one is always available • Worst of all, NGINX played only a minor role
  • 11. We can do better!
  • 12. Business Need • Developers need to easily stage their work for peer and stakeholder review. •
  • 14. Infinite* beta environments—components • Jenkins • Reflinks • supervisord managing uWSGI emperor mode • nginx-mod-passenger for NodeJS apps • NGiNX and uWSGI socket files • Database snapshots • External proxy * ish—as many as we need
  • 15. New process Two common use-cases, with different requirements: 1. Simple bug fixes and minor features 2. Long-running feature branches
  • 16. New process—typical setup Open a pull request Jenkins build (roughly 10 minutes) ~10:00 1 2 3
  • 19. New process—“named betas” • Uses a distinct, persistent copy of the database (to allow for schema changes and feature-specific data) • Accessible outside the internal network with authentication
  • 20. New process—“named betas” Push out a branch: beta/my-feature Jenkins build (roughly 10 minutes) ~10:00 1 2 3
  • 21. Business Value • Efficiency: Cuts down on developer time spent on tasks unrelated to business goals. • Morale: Automates repetitive/monotonous work. • Improves Coverage/Consistency: No barriers to manual testing, even for trivial changes. Each build environment is created with the exact same process.
  • 22. Infinite* beta environments—components • Jenkins • Reflinks • supervisord managing uWSGI emperor mode • nginx-mod-passenger for NodeJS apps • NGiNX and uWSGI socket files • Database snapshots • External proxy * ish—as many as we need
  • 24. Jenkinsfile • A declarative build and deployment script, committed to source control in the root of the repo • Hooked into github notifications for pull request opens and branch pushes • Reasonably powerful control over conditional logic, parallelization, pass/fail conditions, etc.
  • 25. Jenkinsfile pipeline {
 // ...
 stage('stage beta') {
 when { anyOf {
 expression { BRANCH_NAME ==~ /PR-[0-9]+/ } // a pull request
 branch 'develop' // development branch
 expression { BRANCH_NAME.startsWith('beta/') } // 'beta/feature'
 } }
 steps {
 // Initialize database
 sh """ ssh devdbserver "create_beta_db $BRANCH_NAME" """
 // If the workspace doesn't exist, create a reflink copy
 sh """ssh betaserver 
 "[ -d ${WORKSPACE} ] || cp -ar --reflink=auto 
 /www/builds/theatlantic/develop.base ${WORKSPACE}" """
 // ...continued
  • 26. Jenkinsfile (continued) // ...
 stage('stage beta') {
 // ...
 steps {
 // Copy current build to remote workspace dir
 sh """rsync -acvzhO --delete 
 --exclude "*.pyc" --exclude .git --exclude ... 
 $WORKSPACE/ betaserver:$WORKSPACE/ """
 
 // Create wsgi files, which will initialize uWSGI emperor processes
 sh """ssh betaserver "$WORKSPACE/support/beta/create_wsgi.py" """
 }
 }
  • 27. Infinite* beta environments—components • Jenkins • Reflinks • supervisord managing uWSGI emperor mode • nginx-mod-passenger for NodeJS apps • NGiNX and uWSGI socket files • Database snapshots • External proxy * ish—as many as we need
  • 28. Jenkins—stage beta • Initializes with a reflink copy of a previous build to save on disk space (1.2G => 3M) • Uses rsync to copy the newly created environment to the betas server over top of this copy
  • 29. Reflinks (copy-on-write) • BTRFS on debian or ubuntu • XFS on RHEL, CentOS, or Fedora • mkfs.xfs must be called with reflink=1 • cp -ar --reflink=auto • only uses the space required for differences between builds • considered “experimental”—requires custom-built kernel (may be enabled by default in Fedora 29)
  • 30. Infinite* beta environments—components • Jenkins • Reflinks • supervisord managing uWSGI emperor mode • nginx-mod-passenger for NodeJS apps • NGiNX and uWSGI socket files • Database snapshots • External proxy * ish—as many as we need
  • 31. uWSGI emperor + supervisord [program:zerg_server]
 command = /sbin/uwsgi
 --master --thunder-lock
 --emperor "/www/builds/theatlantic/*/uwsgi/master.*.ini"
 autorestart = true
 
 [program:workers]
 command = /sbin/uwsgi
 --master --thunder-lock
 --emperor "/www/builds/theatlantic/*/uwsgi/workers.*.ini"
 autorestart = true
  • 32. Infinite* beta environments—components uWSGI zerg master uWSGI zerg workers
  • 33. uWSGI emperor + supervisord ; /www/builds/theatlantic/pr-1234/uwsgi/master.theatlantic.ini
 [uwsgi]
 ; %n: current config filename, without the .ini extension
 ; Strip off the leading 'master.' part of the filename to determine the app.
 app = @(exec:///usr/bin/perl -e '$_ = "%n"; s/^master.//g; print')
 
 subdomain = %3 ; the 4th path component (0-indexed); eg pr-1234
 
 thunder-lock = true
 master = true
 processes = 0
 
 http = /var/run/uwsgi/%(app)-%(subdomain).sock
 zerg-server = /var/run/uwsgi/%(app)-%(subdomain)-workers.sock
  • 34. uWSGI zerg server ; /www/builds/theatlantic/pr-1234/uwsgi/master.theatlantic.ini
 [uwsgi]
 ; %n: current config filename, without the .ini extension
 ; Strip off the leading 'master.' part of the filename to determine the app.
 app = @(exec:///usr/bin/perl -e '$_ = "%n"; s/^master.//g; print')
 
 subdomain = %3 ; the 4th path component (0-indexed); eg pr-1234
 
 thunder-lock = true
 master = true
 processes = 0
 
 http = /var/run/uwsgi/%(app)-%(subdomain).sock
 zerg-server = /var/run/uwsgi/%(app)-%(subdomain)-workers.sockzerg-server = /var/run/uwsgi/%(app)-%(subdomain)-workers.sock
  • 35. uWSGI zerg workers ; /www/builds/theatlantic/pr-1234/uwsgi/worker.theatlantic.ini
 [uwsgi]
 ; attach to zerg pool
 zerg = /var/run/uwsgi/%(app)-%(subdomain)-workers.sock
 
 cheaper-algo = busyness
 cheaper = 1 ; minimum number of workers to keep at all times
 cheaper-initial = 2 ; starts with minimal workers
 cheaper-step = 2 ; spawn at most 2 workers at a time
 cheaper-overload = 30 ; seconds between busyness checks
 cheaper-busyness-multiplier = 50
 cheaper-busyness-penalty = 2
 
 ; how many requests are in backlog before quick response triggered
 cheaper-busyness-backlog-alert = 33
 cheaper-busyness-backlog-step = 1
 idle = 86400 ; workers shut down if the beta is idle for a day
 
 wsgi-file = %(env_dir)/apps/wsgi.py
 env = DJANGO_SETTINGS_MODULE=settings.%(app).live
  • 36. NGiNX, proxying to uWSGI socket files server { server_name "~^(?<subdomain>.+).beta.theatlantic.com$"; root /www/builds/theatlantic/$subdomain;
 
 location / {
 try_files /assets/$uri @django;
 }
 
 location @django { 
 internal;
 include includes/proxypass.conf;
 proxy_pass http://unix:/var/run/uwsgi/theatlantic-$subdomain.sock;
 }
 }
  • 37. nginx-mod-passenger for nodejs server {
 server_name "~^(?<subdomain>.+).ampbeta.theatlantic.com$";
 
 root /www/builds/amp/${subdomain}/public;
 
 passenger_enabled on;
 passenger_app_type node;
 passenger_app_root /www/builds/amp/${subdomain};
 passenger_restart_dir /www/builds/amp/${subdomain};
 passenger_startup_file dist/host/bin/www.js;
 }