View
1.190
Download
1
Category
Preview:
Citation preview
Building Efficient Parallel Testing Platforms with Docker
Laura Frank @rhein_wein Software Engineer @codeship
laura@codeship.com
codeship.com/resources
• The why and how of parallel testing • DIY with LXC
• Using Docker and the Docker ecosystem
Agenda
Spend less time waiting around for your automated testing steps and deployments to finish.
• Ship newest code to production faster • Be alerted quickly when tests fail
Why?
If you’re still not sure why testing is important… let’s have a different conversation. 😊
Developers should have full autonomy over testing environments, and the way tests are executed.
• Move testing commands to separate pipelines • Designate commands to be run serially or in parallel • Declare specific dependencies for each service
Why?
• For local testing, e.g. unit and integration tests run by a development team
• On internal CI/CD systems • As part of a hosted CI/CD solution (like Codeship)
Where?
• Split up testing tasks • Give developer full control of dependencies per task • Use containers to run multiple tests at once
How?
Distributed Task Parallelism
A distributed system of containerized computing environments takes the place
of a single multiprocessor machine
A container is a process, not a small VM
Why not VMs?
• Isolation of running builds on infrastructure • Challenges with dependency management • No clean interface for imposing resource limits • Infrastructure is underutilized which makes it
expensive • People use containers!
Containers, duh!
• Impose resource limits and increase virtualization density
• Run customer code in isolation
• Provide consistent build environment across many build runs
• Run testing tasks in parallel 👍
codeship.com/resources
Codeship’s LXC-based Platform
40K builds per day 8M builds per year
Architecture
• Universal container with provided dependencies • Fixed amount of available containers per VM • Implement parallel testing pattern using
pipelines with ParallelCI • Users can have N pipelines running in isolation
during a build
User Commands
Universal Container
Pipeline
Heroku
Deployment Provider
Capistrano
AppEngine
Elastic Beanstalk
etc…
User Commands
Universal Container
Pipeline
User Commands
Universal Container
Pipeline
High-level Build Workflow
test pipelines deploy pipeline
build worker
build dispatcher• receives webhooks • transforms payload (keep the good bits) • send payload to account/project service
• read config and start workload • sends updates upstream
account/project service• receives payload • identifies build configuration • sends config to build machines
infrastructure service• keep track of infra utilization • upscale/downscale
worker
Compute Instance
container container
container container
container container
container container
container container
worker
Compute Instance
container container
container container
container container
container container
container container
worker
Compute Instance
container container
container container
container container
container container
container container
worker
Compute Instance
container container
container container
container container
container container
container container
worker
Compute Instance
container container
container container
container container
container container
container container
worker
Compute Instance
container container
container container
container container
container container
container container
Good Stuff
• Extremely simple implementation (no extra scheduler) • Just Works™ • Pretty okay virtualization density • No allocation time for builds — slots are always open
Not So Good Stuff
• Parity between dev and test • Can’t really debug locally • No useable interface between user and container • All pipelines run all services and dependencies
Big Wins with Docker
Even before 1.0, Docker was a clear choice
• Support and tooling • Standardization • Community of motivated developers
A Docker-based Testing Platform
• Different enough from the LXC-based platform to be a new tool
• Development started in 2014, beta in 2015 • Official launch February 2016 • Written in golfing (LXC-based platform is in Ruby)
A New Parallel Workflow
• Introducing services adds additional layer of flexibility • Loosen coupling between steps and services — execute
N steps against M services • Parallel and serial steps can be grouped and ordered in
any way
Services
• Pull image from any registry or build from Dockerfile • Optimize service for testing tasks • Fully customizable by the user
Steps
• Each step is executed in an independent environment • Has own set of containers (services)
• Can be nested in serial and parallel groups
Steps
• Two functions • Run: execute a command against a service • Push: push image to registry
• Tag matching (simple string or regex) to run steps on certain branches or tagged releases
T1 T1 T1
User Commands
Universal Container
Pipeline
User Commands
Universal Container
Pipeline
User Commands
Universal Container
Pipeline
High-Level Build Workflow: The “Old” Way
Step
post
gres
redi
s
command
web
Step
command
ruby
T1 T2 T3
Step
post
gres
redi
s
command
web
Step
post
gres
redi
s
command
web
High-Level Build Workflow: The New Way
build worker
build dispatcher• receives webhooks • transforms payload (keep the good bits)
• send payload to central service
• run build steps and services via Docker • sends updates upstream
account/project service• identifies build configuration
build orchestrator• build machine allocation and provisioning • handles logs • starts build and sends config to build
machines
SQS queue
Compute Instance
build processor
Step
cont
aine
r
cont
aine
r
cont
aine
r
Step
cont
aine
r
cont
aine
r
cont
aine
r
Stepco
ntai
ner
cont
aine
r
cont
aine
r
Compute Instance
build processor
Step
cont
aine
r
cont
aine
r
cont
aine
r
Step
cont
aine
r
cont
aine
r
cont
aine
r
Stepco
ntai
ner
cont
aine
r
cont
aine
r
Docker Workflow Tools
• Docker Compose: service and step definition syntax • Docker Registry: storage for images; previously used
for remote caching • Docker for Mac and Windows: give users ability to
reproduce CI environments locally
services.ymldb: image: postgres:9.5
app: encrypted_dockercfg_path: dockercfg.encrypted build: image: user/some-image dockerfile: Dockerfile.test cached: true links: - db
deploy: encrypted_dockercfg_path: dockercfg.encrypted build: dockerfile: Dockerfile.deploy
- type: serial steps: - type: parallel steps: - name: rspec service: app command: bin/ci spec - name: rubocop service: app command: rubocop - name: haml-lint service: app command: haml-lint app/views - name: rails_best_practices service: app command: bin/railsbp - service: deploy type: push image_name: rheinwein/notes-app tag: ^master$ registry: https://index.docker.io/v1/ encrypted_dockercfg_path: dockercfg.encrypted
1
2
steps.yml
Docker for Mac and Windows
• All users can test locally • Jet CLI is available at bit.ly/codeship-jet-tool • Free, and you don’t need a Codeship account • Big advantage over the LXC implementation
codeship.com/resources
Your push or deploy step should never be part of a parallel step group
PRO TIP
Infrastructure
• Build allocation • Customers can choose specs for their build machines • Machine provisioning used to be part of the build process • Now we pool build machines • Allocation time is ~1 second!
Performance
• Image Caching • Old way: rely on the registry for caching • A pull gave us access to each parent layer; rebuilding the image
used the local cache • 1.10 content addressable breaking change
Performance
• Image Caching • Great news: 1.11 restored parent/child relationship when you
save the images via docker save • 1.13 will include --cache-from flag
• Double-edged sword of relying on external tools ¯\_( )_/¯
libcompose
• Currently use APIs directly for container-level operations (Jet was also born before Fig was popular)
• Minimal change for our users and builds, but much easier for our engineers
• Work is underway 🐳
Swarm!
• Jet was born pre-Swarm • We manage build machines on AWS via our
own service • Previous concerns about security — single tenancy • Swarm (and services like Carina) are
promising for the future
Swarm!
• Instead of using a single machine per build, we should schedule containers across a cluster
• Use the best parts of the LXC platform, but with Docker behind it
codeship.com/resources
You can create a highly efficient parallel testing platform with LXC
alone, but using Docker tools makes it more flexible
TL;DR
Wednesday — October 5th How Secure is your Container? A Docker Engine Security Update - Phil Estes Docker Orchestration: Beyond the Basics - Aaron Lehmann When the Going gets Tough, get TUF Going - Riyaz Faizullabhoy and Lily Guo
Thursday — October 6th Orchestrating Linux Containers while Tolerating Failures - Drew Erny Unikernels: When you Should and When you Shouldn’t - Amir Chaudhry Berlin Docker Meetup
Recommended