SlideShare a Scribd company logo
(without introducing more risk)
The Challenges of Container
Configuration
Puppet
Gareth Rushgrove
New capabilities and associated problems
(without introducing more risk)
Gareth Rushgrove
@garethr
(without introducing more risk)
Gareth Rushgrove
(without introducing more risk)
Configuration
What is it and why should I care
(without introducing more risk)
Gareth Rushgrove
(without introducing more risk)
synonyms: design, grouping, marshalling
Gareth Rushgrove
(without introducing more risk)
Marshalling your containers
Gareth Rushgrove
(without introducing more risk)
- Immutability and containers
- Runtime vs build time
- Who configures the orchestrator?
Gareth Rushgrove
(without introducing more risk)
Mainly Docker and Kubernetes
examples, but should be
generally applicable
Gareth Rushgrove
(without introducing more risk)
Everything is
immutable now?
Assumptions vs reality
(without introducing more risk)
Gareth Rushgrove
(without introducing more risk)
Gareth Rushgrove
ker run -d ubuntu:16.04 /bin/sh 
c "while true; do echo hello world; sleep 1; done"
(without introducing more risk)
Gareth Rushgrove
$ docker exec a7a01beb14de touch /tmp/surprise
(without introducing more risk)
Gareth Rushgrove
$ docker diff a7a01beb14de
C /tmp
A /tmp/surprise
(without introducing more risk)
Containers are not
immutable by default
Gareth Rushgrove
(without introducing more risk)
Containers are not
immutable by default
Gareth Rushgrove
(without introducing more risk)
Gareth Rushgrove
$ docker run --read-only -d ubuntu:16.04 /bin/sh 
-c "while true; do echo hello world; sleep 1; done"
(without introducing more risk)
Gareth Rushgrove
$ docker exec 379150b2cf05 touch /tmp/surprise
touch: cannot touch '/tmp/surprise': Read-only file syste
(without introducing more risk)
Suggestion
Enable read-only where possible
Gareth Rushgrove
(without introducing more risk)
Many applications won’t start with
a read-only filesystem
Gareth Rushgrove
(without introducing more risk)
Gareth Rushgrove
1 import logging
2 from logging.handlers import RotatingFileHandler
3
4 from flask import Flask
5
6 app = Flask(__name__)
7
8 @app.route('/')
9 def home():
10 app.logger.info('log request')
11 return "We'll never get to here"
12
13 if __name__ == '__main__':
14 handler = RotatingFileHandler('app.log', maxBytes=10000, backupCount
15 handler.setLevel(logging.INFO)
16 app.logger.addHandler(handler)
17 app.run(debug=True, host='0.0.0.0')
(without introducing more risk)
Gareth Rushgrove
1 import logging
2 from logging.handlers import RotatingFileHandler
3
4 from flask import Flask
5
6 app = Flask(__name__)
7
8 @app.route('/')
9 def home():
10 app.logger.info('log request')
11 return "We'll never get to here"
12
13 if __name__ == '__main__':
14 handler = RotatingFileHandler('app.log', maxBytes=10000, backupCount
15 handler.setLevel(logging.INFO)
16 app.logger.addHandler(handler)
17 app.run(debug=True, host='0.0.0.0')
(without introducing more risk)
Gareth Rushgrove
$ docker run --read-only -p 5000:5000 garethr/flaskapp
Traceback (most recent call last):
File "app.py", line 14, in <module>
handler = RotatingFileHandler('app.log', maxBytes=10000, backupCount=1)
File "/usr/lib/python2.7/logging/handlers.py", line 117, in __init__
BaseRotatingHandler.__init__(self, filename, mode, encoding, delay)
File "/usr/lib/python2.7/logging/handlers.py", line 64, in __init__
logging.FileHandler.__init__(self, filename, mode, encoding, delay)
File "/usr/lib/python2.7/logging/__init__.py", line 913, in __init__
StreamHandler.__init__(self, self._open())
File "/usr/lib/python2.7/logging/__init__.py", line 943, in _open
stream = open(self.baseFilename, self.mode)
IOError: [Errno 30] Read-only file system: '/app/app.log'
(without introducing more risk)
tmpfs support added in
Docker 1.10
Gareth Rushgrove
(without introducing more risk)
Gareth Rushgrove
$ docker run --read-only --tmpfs /tmp 
-d ubuntu:16.04 /bin/sh 
-c "while true; do echo hello world; sleep 1; done"
(without introducing more risk)
Gareth Rushgrove
$ docker exec 222331443d28 touch /tmp/surprise
(without introducing more risk)
Gareth Rushgrove
$ docker diff 222331443d28
(without introducing more risk)
Gareth Rushgrove
$ docker exec 222331443d28 ls /tmp
surprise
(without introducing more risk)
Suggestion
Use tmpfs only where needed
Gareth Rushgrove
(without introducing more risk)
Remember
Without technical controls you
only have social guarantees
of immutability
Gareth Rushgrove
(without introducing more risk)
Build vs Run
And the relationship between them
(without introducing more risk)
Given an image
- What machine built this image?
- Are all the licenses compatible?
- Who supports this image?
- Does this image contain malware?
Gareth Rushgrove
(without introducing more risk)
Given a running container
- Who built it?
- How was it built?
- What software does it contain?
- Is the software up-to-date?
Gareth Rushgrove
(without introducing more risk)
Gareth Rushgrove
FROM ubuntu:16.04
RUN apt-get update && 
apt-get install -y python-pip python-dev build-essent
apt-get clean && 
rm -rf /var/lib/apt/lists/*
RUN pip install flask
COPY . /app
WORKDIR /app
ENTRYPOINT ["python"]
CMD ["app.py"]
(without introducing more risk)
Gareth Rushgrove
FROM ubuntu:16.04
RUN apt-get update && 
apt-get install -y python-pip python-dev build-essent
apt-get clean && 
rm -rf /var/lib/apt/lists/*
RUN pip install flask
COPY . /app
WORKDIR /app
ENTRYPOINT ["python"]
CMD ["app.py"]
Where did this base image come from?
(without introducing more risk)
Gareth Rushgrove
FROM ubuntu:16.04
RUN apt-get update && 
apt-get install -y python-pip python-dev build-essent
apt-get clean && 
rm -rf /var/lib/apt/lists/*
RUN pip install flask
COPY . /app
WORKDIR /app
ENTRYPOINT ["python"]
CMD ["app.py"]
What packages are installed? At what version?
Where are those packages from?
(without introducing more risk)
Gareth Rushgrove
FROM ubuntu:16.04
RUN apt-get update && 
apt-get install -y python-pip python-dev build-essent
apt-get clean && 
rm -rf /var/lib/apt/lists/*
RUN pip install flask
COPY . /app
WORKDIR /app
ENTRYPOINT ["python"]
CMD ["app.py"]
What version of flask is this?
(without introducing more risk)
Gareth Rushgrove
FROM ubuntu:16.04
RUN apt-get update && 
apt-get install -y python-pip python-dev build-essent
apt-get clean && 
rm -rf /var/lib/apt/lists/*
RUN pip install flask
COPY . /app
WORKDIR /app
ENTRYPOINT ["python"]
CMD ["app.py"]
What was in this folder at build time?
(without introducing more risk)
The importance of time
Gareth Rushgrove
(without introducing more risk)
How often are images rebuilt?
Gareth Rushgrove
(without introducing more risk)
Rebuilding only on code change
ignores environmental factors
Gareth Rushgrove
(without introducing more risk)
Versioning and metadata
Gareth Rushgrove
(without introducing more risk)
Gareth Rushgrove
LABEL vendor="ACME Incorporated" 
com.example.is-beta 
com.example.version="0.0.1-beta" 
com.example.release-date="2015-02-12"
(without introducing more risk)
Gareth Rushgrove
LABEL vendor="ACME Incorporated" 
com.example.is-beta 
com.example.version="0.0.1-beta" 
com.example.release-date="2015-02-12"
What time? What timezone?
(without introducing more risk)
Gareth Rushgrove
$ docker inspect -f "{{json .Config.Labels }}" 
4fa6e0f0c678 | jq
{
"vendor": "ACME Incorporated",
"com.example.is-beta": "",
"com.example.version": "0.0.1-beta",
"com.example.release-date": "2015-02-12"
}
(without introducing more risk)
Suggestion
Decide upon and enforce
metadata standards
Gareth Rushgrove
(without introducing more risk)
Gareth Rushgrove
LABEL com.example.git.repository="https://github.com/pupp
com.example.git.sha="dc123cfb5ed4dca43a84be34a99d7c
com.example.build.time="2016-04-24T15:43:05+00:00"
com.example.build.builder=“jenkins1.example.com" 
com.example.docs="https://github.com/puppetlabs/doc
...
(without introducing more risk)
Suggestion
Embed Dockerfiles in images
Gareth Rushgrove
(without introducing more risk)
Gareth Rushgrove
$ docker inspect -f "{{json .Config.Labels }}" 
garethr/alpine 
| jq
{
"net.morethanseven.dockerfile": "/Dockerfile",
}
(without introducing more risk)
Gareth Rushgrove
$ docker run -i -t garethr/alpine cat /Dockerfile
FROM alpine
LABEL net.morethanseven.dockerfile="/Dockerfile"
RUN apk add --update bash && rm -rf /var/cache/apk/*
COPY Dockerfile /
(without introducing more risk)
Suggestion
Provide an API for your containers
Gareth Rushgrove
(without introducing more risk)
Gareth Rushgrove
$ docker inspect -f "{{json .Config.Labels }}" 
garethr/alpine 
| jq
{
"com.example.api.packages": "apk info -vv"
}
(without introducing more risk)
Gareth Rushgrove
$ docker run -i -t garethr/alpine apk info -vv
musl-1.1.11-r2 - the musl c library (libc) implementation
busybox-1.23.2-r0 - Size optimized toolbox of many common UNIX
alpine-baselayout-2.3.2-r0 - Alpine base dir structure and init
openrc-0.15.1-r3 - OpenRC manages the services, startup and shu
alpine-conf-3.2.1-r6 - Alpine configuration management scripts
(without introducing more risk)DEMO
(without introducing more risk)
Who configures the
scheduler?
Higher level configuration
(without introducing more risk)
Schedulers/orchestrators abstract
you from
- Where individual containers run
- Balancing due to new resources
- Balancing due to failed resources
Gareth Rushgrove
(without introducing more risk)
This results in a constraints
based system
Gareth Rushgrove
(without introducing more risk)
Which means those constraints
need to be explicit and correct
Gareth Rushgrove
(without introducing more risk)
Gareth Rushgrove
$ docker daemon 
--label com.example.environment="production" 
--label com.example.storage="ssd"
(without introducing more risk)
Gareth Rushgrove
$ docker run -d -P 
-e constraint:storage==ssd --name db mysql
(without introducing more risk)
Gareth Rushgrove
1 template:
2 metadata:
3 labels:
4 app: guestbook
5 tier: frontend
6 spec:
7 containers:
8 - name: php-redis
9 image: gcr.io/google_samples/gb-frontend:v4
10 resources:
11 requests:
12 cpu: 100m
13 memory: 100Mi
14 env:
15 - name: GET_HOSTS_FROM
16 value: dns
17 # If your cluster config does not include a dns service, th
18 # instead access environment variables to find service host
19 # info, comment out the 'value: dns' line above, and uncomm
(without introducing more risk)
How do you manage properties
for all of your hosts?
Gareth Rushgrove
(without introducing more risk)
Gareth Rushgrove
$ docker daemon 
--label com.example.environment="production" 
--label com.example.storage="ssd"
Does this machine really have an SSD?
What if someone swaps the drive?
(without introducing more risk)
Suggestion
Use properties of hosts as labels
Gareth Rushgrove
(without introducing more risk)
Gareth Rushgrove
$ facter | head -n 20
architecture => x86_64
domain => local
facterversion => 2.4.6
fqdn => Pro.local
gid => staff
hardwareisa => i386
hardwaremodel => x86_64
hostname => Pro
id => garethr
interfaces =>
lo0,gif0,stf0,en0,p2p0,awdl0,en1,en2,bridge0,vboxnet0,vboxnet1,v
ipaddress => 192.168.0.5
ipaddress_en0 => 192.168.0.5
(without introducing more risk)
Gareth Rushgrove
$ facter -j os | jq
{
"os": {
"name": "Darwin",
"family": "Darwin",
"release": {
"major": "14",
"minor": "5",
"full": "14.5.0"
}
}
}
(without introducing more risk)
Gareth Rushgrove
$ docker daemon 
--label net.example.os=`facter operatingsystem` 
--label net.example.virtual=`facter is_virtual` 
--label net.example.kernel=`facter kernelversion` 
...
(without introducing more risk)
Orchestrators also tend to
introduce new higher-level
primitives
Gareth Rushgrove
(without introducing more risk)
Docker Networks, Kubernetes
Services, ReplicationControllers,
Chronos Jobs
Gareth Rushgrove
(without introducing more risk)
Many with imperative interfaces
Gareth Rushgrove
(without introducing more risk)
Gareth Rushgrove
$ kubectl get pod mypod -o yaml 
| sed 's/(image: myimage):.*$/1:v4/' 
| kubectl replace -f -
(without introducing more risk)
Gareth Rushgrove
$ docker network create bob
c0a0f4538d259515813b771264688d37aaedb41098379a0d73ec0ca08
$ docker network create bob
Error response from daemon: network with name bob already
And everything configured
in YAML
Gareth Rushgrove
Code plus data has advantages
over data alone
Gareth Rushgrove
The language to represent the data should
be a simple, data-only format such as JSON
or YAML, and programmatic modification of
this data should be done in a real
programming language
Gareth Rushgrove
Borg, Omega, and Kubernetes, ACM Queue,Volume 14, issue 1 http://queue.acm.org/detail.cfm?id=2898444
“
Avoid repetition
Combine external inputs
Correctness
Abstractions
Gareth Rushgrove
-
-
-
-
Suggestion
Use a higher level programming
tool for generating config data
Gareth Rushgrove
(without introducing more risk)
Gareth Rushgrove
jsonnet.org
(without introducing more risk)
Gareth Rushgrove
$ cat test.jsonnet
// Example jsonnet file
{
person1: {
name: "Alice",
welcome: "Hello " + self.name + "!",
},
person2: self.person1 { name: "Bob" },
}
(without introducing more risk)
Gareth Rushgrove
$ jsonnet test.jsonnet | jq
{
"person1": {
"name": "Alice",
"welcome": "Hello Alice!"
},
"person2": {
"name": "Bob",
"welcome": "Hello Bob!"
}
}
(without introducing more risk)
Gareth Rushgrove
$ jsonnet test.jsonnet | json2yaml
---
person1:
name: "Alice"
welcome: "Hello Alice!"
person2:
name: "Bob"
welcome: "Hello Bob!"
(without introducing more risk)DEMO
(without introducing more risk)
Gareth Rushgrove
garethr/kubernetes
(without introducing more risk)
Gareth Rushgrove
kubernetes_pod { 'sample-pod':
ensure => present,
metadata => {
namespace => 'default',
},
spec => {
containers => [{
name => 'container-name',
image => 'nginx',
}]
},
}
(without introducing more risk)
Gareth Rushgrove
apiVersion: v1
kind: Pod
metadata:
namespace: default
name: sample-pod
spec:
container:
- image: nginx
name: container-name
(without introducing more risk)
Gareth Rushgrove
controller_service_pair { 'redis-master':
app => 'redis',
role => 'master',
tier => 'backend',
port => 6379,
}
(without introducing more risk)
Gareth Rushgrove
apiVersion: v1
kind: Service
metadata:
name: redis-master
labels:
app: redis
tier: backend
role: master
spec:
ports:
# the port that this service should serve on
- port: 6379
targetPort: 6379
selector:
app: redis
tier: backend
role: master
---
apiVersion: v1
kind: ReplicationController
metadata:
name: redis-master
# these labels can be applied automatically
# from the labels in the pod template if not set
labels:
app: redis
role: master
tier: backend
spec:
# this replicas value is default
# modify it according to your case
replicas: 1
# selector can be applied automatically
# from the labels in the pod template if not set
# selector:
# app: guestbook
# role: master
# tier: backend
(without introducing more risk)DEMO
(without introducing more risk)
Conclusions
New technology means old problems
(without introducing more risk)
The difference between how you
think something works and how
it actually works risks
hard-to-debug production issues
Gareth Rushgrove
(without introducing more risk)
Containers introduce new and old
configuration problems
Gareth Rushgrove
(without introducing more risk)
Configuration management
is the discipline aimed at
minimising those risks
Gareth Rushgrove
(without introducing more risk)
Start with principles
Gareth Rushgrove
(without introducing more risk)
- Identification
- Control
- Status accounting
- Verification
Gareth Rushgrove
Military Handbook Configuration Management Guidance MIL-HDBK-61B
(without introducing more risk)
Apply them to your
container based
infrastructure today
Gareth Rushgrove
(without introducing more risk)
Questions?
And thanks for listening

More Related Content

PDF
Test Driven Development with Puppet - PuppetConf 2014
PDF
Hiveminder - Everything but the Secret Sauce
PDF
Build microservice with gRPC in golang
PDF
Beaker: Automated, Cloud-Based Acceptance Testing - PuppetConf 2014
PDF
Orchestrated Functional Testing with Puppet-spec and Mspectator - PuppetConf ...
KEY
PyCon AU 2012 - Debugging Live Python Web Applications
PDF
GDG Devfest 2019 - Build go kit microservices at kubernetes with ease
PDF
Job Queue in Golang
Test Driven Development with Puppet - PuppetConf 2014
Hiveminder - Everything but the Secret Sauce
Build microservice with gRPC in golang
Beaker: Automated, Cloud-Based Acceptance Testing - PuppetConf 2014
Orchestrated Functional Testing with Puppet-spec and Mspectator - PuppetConf ...
PyCon AU 2012 - Debugging Live Python Web Applications
GDG Devfest 2019 - Build go kit microservices at kubernetes with ease
Job Queue in Golang

What's hot (20)

PDF
用 Go 語言打造多台機器 Scale 架構
PDF
Node.js cluster
PDF
Continuously Testing Infrastructure - Beyond Module Testing - PuppetConf 2014
PPTX
The Gradle in Ratpack: Dissected
PDF
Big query - Command line tools and Tips - (MOSG)
PDF
Gradle Introduction
PDF
Rest, sockets em golang
PDF
Drone CI/CD 自動化測試及部署
PDF
Real-Time Web Apps & Symfony. What are your options?
PDF
Global Interpreter Lock: Episode III - cat &lt; /dev/zero > GIL;
PDF
Gradle build tool that rocks with DSL JavaOne India 4th May 2012
PDF
Puppet Continuous Integration with PE and GitLab
PDF
Gradle in 45min
PDF
10 Cool Facts about Gradle
PDF
Managing dependencies with gradle
PDF
Using the Groovy Ecosystem for Rapid JVM Development
PDF
Large scale machine learning projects with r suite
PDF
[Image Results] Java Build Tools: Part 2 - A Decision Maker's Guide Compariso...
PPT
Groovy & Grails: Scripting for Modern Web Applications
PDF
GraphQL IN Golang
用 Go 語言打造多台機器 Scale 架構
Node.js cluster
Continuously Testing Infrastructure - Beyond Module Testing - PuppetConf 2014
The Gradle in Ratpack: Dissected
Big query - Command line tools and Tips - (MOSG)
Gradle Introduction
Rest, sockets em golang
Drone CI/CD 自動化測試及部署
Real-Time Web Apps & Symfony. What are your options?
Global Interpreter Lock: Episode III - cat &lt; /dev/zero > GIL;
Gradle build tool that rocks with DSL JavaOne India 4th May 2012
Puppet Continuous Integration with PE and GitLab
Gradle in 45min
10 Cool Facts about Gradle
Managing dependencies with gradle
Using the Groovy Ecosystem for Rapid JVM Development
Large scale machine learning projects with r suite
[Image Results] Java Build Tools: Part 2 - A Decision Maker's Guide Compariso...
Groovy & Grails: Scripting for Modern Web Applications
GraphQL IN Golang
Ad

Viewers also liked (20)

PDF
Communications Between Tribes
PDF
Puppet and Openshift
PDF
Thinking Evil Thoughts
PDF
Two Sides of Google Infrastructure for Everyone Else
PDF
Puppet Data Mining
PDF
OlinData Puppet Presentation for MOSC 2012
PDF
Puppet User Group Presentation - 15 March 2012
PDF
PuppetConf 2016: Device-Based Modules: Making Them as Simple as a Light Switc...
PPTX
Introduction to Puppet Enterprise
PPTX
Adopting Kubernetes with Puppet
PDF
What to Build with Google App Engine
PDF
Config managament for development environments ii
PPT
Social Media Risk and Reputation Management
PDF
Dev opsdays scriptcode
PDF
Developing IoT devices. Creating wearables with the new LinkIt™ 2523 HDK by SAC
ODP
PDF
introduction to python
PPTX
DevOps at DreamLab
PDF
OlinData Puppet Presentation for DevOps Singapore meet-up
PDF
Getting Started With Puppet - Chad Metcalf
Communications Between Tribes
Puppet and Openshift
Thinking Evil Thoughts
Two Sides of Google Infrastructure for Everyone Else
Puppet Data Mining
OlinData Puppet Presentation for MOSC 2012
Puppet User Group Presentation - 15 March 2012
PuppetConf 2016: Device-Based Modules: Making Them as Simple as a Light Switc...
Introduction to Puppet Enterprise
Adopting Kubernetes with Puppet
What to Build with Google App Engine
Config managament for development environments ii
Social Media Risk and Reputation Management
Dev opsdays scriptcode
Developing IoT devices. Creating wearables with the new LinkIt™ 2523 HDK by SAC
introduction to python
DevOps at DreamLab
OlinData Puppet Presentation for DevOps Singapore meet-up
Getting Started With Puppet - Chad Metcalf
Ad

Similar to The Challenges of Container Configuration (20)

PDF
PuppetConf 2016: Running Puppet Software in Docker Containers – Gareth Rushgr...
PDF
Container (Docker) Orchestration Tools
PDF
Zero Downtime Deployment with Ansible
PDF
KubeCon EU 2016: Kubernetes and the Potential for Higher Level Interfaces
PDF
Gdg cloud taipei ddt meetup #53 buildpack
PDF
DevOps(4) : Ansible(2) - (MOSG)
PDF
Tensorflow in Docker
PDF
Swift Cloud Workshop - Swift Microservices
PDF
Docker for Ruby Developers
PPTX
Introduction to Docker
PDF
Greach - The Groovy Ecosystem
PDF
Bare Metal to OpenStack with Razor and Chef
PPTX
How to go the extra mile on monitoring
PPTX
How to lock a Python in a cage? Managing Python environment inside an R project
PPTX
Docker practice
PPTX
Control your deployments with Capistrano
ODP
RichFaces - Testing on Mobile Devices
PDF
The 2016 Android Developer Toolbox [NANTES]
PPTX
Toolbox of a Ruby Team
PDF
Grunt & Front-end Workflow
PuppetConf 2016: Running Puppet Software in Docker Containers – Gareth Rushgr...
Container (Docker) Orchestration Tools
Zero Downtime Deployment with Ansible
KubeCon EU 2016: Kubernetes and the Potential for Higher Level Interfaces
Gdg cloud taipei ddt meetup #53 buildpack
DevOps(4) : Ansible(2) - (MOSG)
Tensorflow in Docker
Swift Cloud Workshop - Swift Microservices
Docker for Ruby Developers
Introduction to Docker
Greach - The Groovy Ecosystem
Bare Metal to OpenStack with Razor and Chef
How to go the extra mile on monitoring
How to lock a Python in a cage? Managing Python environment inside an R project
Docker practice
Control your deployments with Capistrano
RichFaces - Testing on Mobile Devices
The 2016 Android Developer Toolbox [NANTES]
Toolbox of a Ruby Team
Grunt & Front-end Workflow

More from Gareth Rushgrove (20)

PDF
Web operations
PDF
Learnings from govuk
PDF
Varnish Caching
PDF
Vagrant and Configuration Management
PDF
Metrics with Ganglia
PDF
You're Going To Need A Bigger Toolbox
PDF
PDF
Automating web site deployment
PDF
Message Queues for Web Applications
PDF
Beyond basic web development
PDF
Self Education for Web Professionals
PDF
App Engine for Python Developers
PDF
Testing Django Applications
PDF
Design Strategies for a Distributed Web
PDF
A First Class Web Citizen
PDF
Parsing Microformats
PDF
Things you probably don't do (or tying to make project automation sexy)
PDF
Notes from (Web 2.0) Revolution
PDF
Rails flavoured OpenId
PDF
Shiny Content Management with Radiant
Web operations
Learnings from govuk
Varnish Caching
Vagrant and Configuration Management
Metrics with Ganglia
You're Going To Need A Bigger Toolbox
Automating web site deployment
Message Queues for Web Applications
Beyond basic web development
Self Education for Web Professionals
App Engine for Python Developers
Testing Django Applications
Design Strategies for a Distributed Web
A First Class Web Citizen
Parsing Microformats
Things you probably don't do (or tying to make project automation sexy)
Notes from (Web 2.0) Revolution
Rails flavoured OpenId
Shiny Content Management with Radiant

Recently uploaded (20)

PDF
Electronic commerce courselecture one. Pdf
PDF
Empathic Computing: Creating Shared Understanding
PDF
KodekX | Application Modernization Development
PDF
Bridging biosciences and deep learning for revolutionary discoveries: a compr...
PPTX
Effective Security Operations Center (SOC) A Modern, Strategic, and Threat-In...
PDF
Unlocking AI with Model Context Protocol (MCP)
PDF
Architecting across the Boundaries of two Complex Domains - Healthcare & Tech...
PPTX
Cloud computing and distributed systems.
PDF
The Rise and Fall of 3GPP – Time for a Sabbatical?
PPTX
20250228 LYD VKU AI Blended-Learning.pptx
PPT
“AI and Expert System Decision Support & Business Intelligence Systems”
PDF
Spectral efficient network and resource selection model in 5G networks
DOCX
The AUB Centre for AI in Media Proposal.docx
PPTX
PA Analog/Digital System: The Backbone of Modern Surveillance and Communication
PDF
NewMind AI Monthly Chronicles - July 2025
PDF
Peak of Data & AI Encore- AI for Metadata and Smarter Workflows
PDF
Mobile App Security Testing_ A Comprehensive Guide.pdf
PDF
Reach Out and Touch Someone: Haptics and Empathic Computing
PDF
Machine learning based COVID-19 study performance prediction
PDF
Dropbox Q2 2025 Financial Results & Investor Presentation
Electronic commerce courselecture one. Pdf
Empathic Computing: Creating Shared Understanding
KodekX | Application Modernization Development
Bridging biosciences and deep learning for revolutionary discoveries: a compr...
Effective Security Operations Center (SOC) A Modern, Strategic, and Threat-In...
Unlocking AI with Model Context Protocol (MCP)
Architecting across the Boundaries of two Complex Domains - Healthcare & Tech...
Cloud computing and distributed systems.
The Rise and Fall of 3GPP – Time for a Sabbatical?
20250228 LYD VKU AI Blended-Learning.pptx
“AI and Expert System Decision Support & Business Intelligence Systems”
Spectral efficient network and resource selection model in 5G networks
The AUB Centre for AI in Media Proposal.docx
PA Analog/Digital System: The Backbone of Modern Surveillance and Communication
NewMind AI Monthly Chronicles - July 2025
Peak of Data & AI Encore- AI for Metadata and Smarter Workflows
Mobile App Security Testing_ A Comprehensive Guide.pdf
Reach Out and Touch Someone: Haptics and Empathic Computing
Machine learning based COVID-19 study performance prediction
Dropbox Q2 2025 Financial Results & Investor Presentation

The Challenges of Container Configuration

  • 1. (without introducing more risk) The Challenges of Container Configuration Puppet Gareth Rushgrove New capabilities and associated problems
  • 2. (without introducing more risk) Gareth Rushgrove @garethr
  • 3. (without introducing more risk) Gareth Rushgrove
  • 4. (without introducing more risk) Configuration What is it and why should I care
  • 5. (without introducing more risk) Gareth Rushgrove
  • 6. (without introducing more risk) synonyms: design, grouping, marshalling Gareth Rushgrove
  • 7. (without introducing more risk) Marshalling your containers Gareth Rushgrove
  • 8. (without introducing more risk) - Immutability and containers - Runtime vs build time - Who configures the orchestrator? Gareth Rushgrove
  • 9. (without introducing more risk) Mainly Docker and Kubernetes examples, but should be generally applicable Gareth Rushgrove
  • 10. (without introducing more risk) Everything is immutable now? Assumptions vs reality
  • 11. (without introducing more risk) Gareth Rushgrove
  • 12. (without introducing more risk) Gareth Rushgrove ker run -d ubuntu:16.04 /bin/sh c "while true; do echo hello world; sleep 1; done"
  • 13. (without introducing more risk) Gareth Rushgrove $ docker exec a7a01beb14de touch /tmp/surprise
  • 14. (without introducing more risk) Gareth Rushgrove $ docker diff a7a01beb14de C /tmp A /tmp/surprise
  • 15. (without introducing more risk) Containers are not immutable by default Gareth Rushgrove
  • 16. (without introducing more risk) Containers are not immutable by default Gareth Rushgrove
  • 17. (without introducing more risk) Gareth Rushgrove $ docker run --read-only -d ubuntu:16.04 /bin/sh -c "while true; do echo hello world; sleep 1; done"
  • 18. (without introducing more risk) Gareth Rushgrove $ docker exec 379150b2cf05 touch /tmp/surprise touch: cannot touch '/tmp/surprise': Read-only file syste
  • 19. (without introducing more risk) Suggestion Enable read-only where possible Gareth Rushgrove
  • 20. (without introducing more risk) Many applications won’t start with a read-only filesystem Gareth Rushgrove
  • 21. (without introducing more risk) Gareth Rushgrove 1 import logging 2 from logging.handlers import RotatingFileHandler 3 4 from flask import Flask 5 6 app = Flask(__name__) 7 8 @app.route('/') 9 def home(): 10 app.logger.info('log request') 11 return "We'll never get to here" 12 13 if __name__ == '__main__': 14 handler = RotatingFileHandler('app.log', maxBytes=10000, backupCount 15 handler.setLevel(logging.INFO) 16 app.logger.addHandler(handler) 17 app.run(debug=True, host='0.0.0.0')
  • 22. (without introducing more risk) Gareth Rushgrove 1 import logging 2 from logging.handlers import RotatingFileHandler 3 4 from flask import Flask 5 6 app = Flask(__name__) 7 8 @app.route('/') 9 def home(): 10 app.logger.info('log request') 11 return "We'll never get to here" 12 13 if __name__ == '__main__': 14 handler = RotatingFileHandler('app.log', maxBytes=10000, backupCount 15 handler.setLevel(logging.INFO) 16 app.logger.addHandler(handler) 17 app.run(debug=True, host='0.0.0.0')
  • 23. (without introducing more risk) Gareth Rushgrove $ docker run --read-only -p 5000:5000 garethr/flaskapp Traceback (most recent call last): File "app.py", line 14, in <module> handler = RotatingFileHandler('app.log', maxBytes=10000, backupCount=1) File "/usr/lib/python2.7/logging/handlers.py", line 117, in __init__ BaseRotatingHandler.__init__(self, filename, mode, encoding, delay) File "/usr/lib/python2.7/logging/handlers.py", line 64, in __init__ logging.FileHandler.__init__(self, filename, mode, encoding, delay) File "/usr/lib/python2.7/logging/__init__.py", line 913, in __init__ StreamHandler.__init__(self, self._open()) File "/usr/lib/python2.7/logging/__init__.py", line 943, in _open stream = open(self.baseFilename, self.mode) IOError: [Errno 30] Read-only file system: '/app/app.log'
  • 24. (without introducing more risk) tmpfs support added in Docker 1.10 Gareth Rushgrove
  • 25. (without introducing more risk) Gareth Rushgrove $ docker run --read-only --tmpfs /tmp -d ubuntu:16.04 /bin/sh -c "while true; do echo hello world; sleep 1; done"
  • 26. (without introducing more risk) Gareth Rushgrove $ docker exec 222331443d28 touch /tmp/surprise
  • 27. (without introducing more risk) Gareth Rushgrove $ docker diff 222331443d28
  • 28. (without introducing more risk) Gareth Rushgrove $ docker exec 222331443d28 ls /tmp surprise
  • 29. (without introducing more risk) Suggestion Use tmpfs only where needed Gareth Rushgrove
  • 30. (without introducing more risk) Remember Without technical controls you only have social guarantees of immutability Gareth Rushgrove
  • 31. (without introducing more risk) Build vs Run And the relationship between them
  • 32. (without introducing more risk) Given an image - What machine built this image? - Are all the licenses compatible? - Who supports this image? - Does this image contain malware? Gareth Rushgrove
  • 33. (without introducing more risk) Given a running container - Who built it? - How was it built? - What software does it contain? - Is the software up-to-date? Gareth Rushgrove
  • 34. (without introducing more risk) Gareth Rushgrove FROM ubuntu:16.04 RUN apt-get update && apt-get install -y python-pip python-dev build-essent apt-get clean && rm -rf /var/lib/apt/lists/* RUN pip install flask COPY . /app WORKDIR /app ENTRYPOINT ["python"] CMD ["app.py"]
  • 35. (without introducing more risk) Gareth Rushgrove FROM ubuntu:16.04 RUN apt-get update && apt-get install -y python-pip python-dev build-essent apt-get clean && rm -rf /var/lib/apt/lists/* RUN pip install flask COPY . /app WORKDIR /app ENTRYPOINT ["python"] CMD ["app.py"] Where did this base image come from?
  • 36. (without introducing more risk) Gareth Rushgrove FROM ubuntu:16.04 RUN apt-get update && apt-get install -y python-pip python-dev build-essent apt-get clean && rm -rf /var/lib/apt/lists/* RUN pip install flask COPY . /app WORKDIR /app ENTRYPOINT ["python"] CMD ["app.py"] What packages are installed? At what version? Where are those packages from?
  • 37. (without introducing more risk) Gareth Rushgrove FROM ubuntu:16.04 RUN apt-get update && apt-get install -y python-pip python-dev build-essent apt-get clean && rm -rf /var/lib/apt/lists/* RUN pip install flask COPY . /app WORKDIR /app ENTRYPOINT ["python"] CMD ["app.py"] What version of flask is this?
  • 38. (without introducing more risk) Gareth Rushgrove FROM ubuntu:16.04 RUN apt-get update && apt-get install -y python-pip python-dev build-essent apt-get clean && rm -rf /var/lib/apt/lists/* RUN pip install flask COPY . /app WORKDIR /app ENTRYPOINT ["python"] CMD ["app.py"] What was in this folder at build time?
  • 39. (without introducing more risk) The importance of time Gareth Rushgrove
  • 40. (without introducing more risk) How often are images rebuilt? Gareth Rushgrove
  • 41. (without introducing more risk) Rebuilding only on code change ignores environmental factors Gareth Rushgrove
  • 42. (without introducing more risk) Versioning and metadata Gareth Rushgrove
  • 43. (without introducing more risk) Gareth Rushgrove LABEL vendor="ACME Incorporated" com.example.is-beta com.example.version="0.0.1-beta" com.example.release-date="2015-02-12"
  • 44. (without introducing more risk) Gareth Rushgrove LABEL vendor="ACME Incorporated" com.example.is-beta com.example.version="0.0.1-beta" com.example.release-date="2015-02-12" What time? What timezone?
  • 45. (without introducing more risk) Gareth Rushgrove $ docker inspect -f "{{json .Config.Labels }}" 4fa6e0f0c678 | jq { "vendor": "ACME Incorporated", "com.example.is-beta": "", "com.example.version": "0.0.1-beta", "com.example.release-date": "2015-02-12" }
  • 46. (without introducing more risk) Suggestion Decide upon and enforce metadata standards Gareth Rushgrove
  • 47. (without introducing more risk) Gareth Rushgrove LABEL com.example.git.repository="https://github.com/pupp com.example.git.sha="dc123cfb5ed4dca43a84be34a99d7c com.example.build.time="2016-04-24T15:43:05+00:00" com.example.build.builder=“jenkins1.example.com" com.example.docs="https://github.com/puppetlabs/doc ...
  • 48. (without introducing more risk) Suggestion Embed Dockerfiles in images Gareth Rushgrove
  • 49. (without introducing more risk) Gareth Rushgrove $ docker inspect -f "{{json .Config.Labels }}" garethr/alpine | jq { "net.morethanseven.dockerfile": "/Dockerfile", }
  • 50. (without introducing more risk) Gareth Rushgrove $ docker run -i -t garethr/alpine cat /Dockerfile FROM alpine LABEL net.morethanseven.dockerfile="/Dockerfile" RUN apk add --update bash && rm -rf /var/cache/apk/* COPY Dockerfile /
  • 51. (without introducing more risk) Suggestion Provide an API for your containers Gareth Rushgrove
  • 52. (without introducing more risk) Gareth Rushgrove $ docker inspect -f "{{json .Config.Labels }}" garethr/alpine | jq { "com.example.api.packages": "apk info -vv" }
  • 53. (without introducing more risk) Gareth Rushgrove $ docker run -i -t garethr/alpine apk info -vv musl-1.1.11-r2 - the musl c library (libc) implementation busybox-1.23.2-r0 - Size optimized toolbox of many common UNIX alpine-baselayout-2.3.2-r0 - Alpine base dir structure and init openrc-0.15.1-r3 - OpenRC manages the services, startup and shu alpine-conf-3.2.1-r6 - Alpine configuration management scripts
  • 55. (without introducing more risk) Who configures the scheduler? Higher level configuration
  • 56. (without introducing more risk) Schedulers/orchestrators abstract you from - Where individual containers run - Balancing due to new resources - Balancing due to failed resources Gareth Rushgrove
  • 57. (without introducing more risk) This results in a constraints based system Gareth Rushgrove
  • 58. (without introducing more risk) Which means those constraints need to be explicit and correct Gareth Rushgrove
  • 59. (without introducing more risk) Gareth Rushgrove $ docker daemon --label com.example.environment="production" --label com.example.storage="ssd"
  • 60. (without introducing more risk) Gareth Rushgrove $ docker run -d -P -e constraint:storage==ssd --name db mysql
  • 61. (without introducing more risk) Gareth Rushgrove 1 template: 2 metadata: 3 labels: 4 app: guestbook 5 tier: frontend 6 spec: 7 containers: 8 - name: php-redis 9 image: gcr.io/google_samples/gb-frontend:v4 10 resources: 11 requests: 12 cpu: 100m 13 memory: 100Mi 14 env: 15 - name: GET_HOSTS_FROM 16 value: dns 17 # If your cluster config does not include a dns service, th 18 # instead access environment variables to find service host 19 # info, comment out the 'value: dns' line above, and uncomm
  • 62. (without introducing more risk) How do you manage properties for all of your hosts? Gareth Rushgrove
  • 63. (without introducing more risk) Gareth Rushgrove $ docker daemon --label com.example.environment="production" --label com.example.storage="ssd" Does this machine really have an SSD? What if someone swaps the drive?
  • 64. (without introducing more risk) Suggestion Use properties of hosts as labels Gareth Rushgrove
  • 65. (without introducing more risk) Gareth Rushgrove $ facter | head -n 20 architecture => x86_64 domain => local facterversion => 2.4.6 fqdn => Pro.local gid => staff hardwareisa => i386 hardwaremodel => x86_64 hostname => Pro id => garethr interfaces => lo0,gif0,stf0,en0,p2p0,awdl0,en1,en2,bridge0,vboxnet0,vboxnet1,v ipaddress => 192.168.0.5 ipaddress_en0 => 192.168.0.5
  • 66. (without introducing more risk) Gareth Rushgrove $ facter -j os | jq { "os": { "name": "Darwin", "family": "Darwin", "release": { "major": "14", "minor": "5", "full": "14.5.0" } } }
  • 67. (without introducing more risk) Gareth Rushgrove $ docker daemon --label net.example.os=`facter operatingsystem` --label net.example.virtual=`facter is_virtual` --label net.example.kernel=`facter kernelversion` ...
  • 68. (without introducing more risk) Orchestrators also tend to introduce new higher-level primitives Gareth Rushgrove
  • 69. (without introducing more risk) Docker Networks, Kubernetes Services, ReplicationControllers, Chronos Jobs Gareth Rushgrove
  • 70. (without introducing more risk) Many with imperative interfaces Gareth Rushgrove
  • 71. (without introducing more risk) Gareth Rushgrove $ kubectl get pod mypod -o yaml | sed 's/(image: myimage):.*$/1:v4/' | kubectl replace -f -
  • 72. (without introducing more risk) Gareth Rushgrove $ docker network create bob c0a0f4538d259515813b771264688d37aaedb41098379a0d73ec0ca08 $ docker network create bob Error response from daemon: network with name bob already
  • 73. And everything configured in YAML Gareth Rushgrove
  • 74. Code plus data has advantages over data alone Gareth Rushgrove
  • 75. The language to represent the data should be a simple, data-only format such as JSON or YAML, and programmatic modification of this data should be done in a real programming language Gareth Rushgrove Borg, Omega, and Kubernetes, ACM Queue,Volume 14, issue 1 http://queue.acm.org/detail.cfm?id=2898444 “
  • 76. Avoid repetition Combine external inputs Correctness Abstractions Gareth Rushgrove - - - -
  • 77. Suggestion Use a higher level programming tool for generating config data Gareth Rushgrove
  • 78. (without introducing more risk) Gareth Rushgrove jsonnet.org
  • 79. (without introducing more risk) Gareth Rushgrove $ cat test.jsonnet // Example jsonnet file { person1: { name: "Alice", welcome: "Hello " + self.name + "!", }, person2: self.person1 { name: "Bob" }, }
  • 80. (without introducing more risk) Gareth Rushgrove $ jsonnet test.jsonnet | jq { "person1": { "name": "Alice", "welcome": "Hello Alice!" }, "person2": { "name": "Bob", "welcome": "Hello Bob!" } }
  • 81. (without introducing more risk) Gareth Rushgrove $ jsonnet test.jsonnet | json2yaml --- person1: name: "Alice" welcome: "Hello Alice!" person2: name: "Bob" welcome: "Hello Bob!"
  • 83. (without introducing more risk) Gareth Rushgrove garethr/kubernetes
  • 84. (without introducing more risk) Gareth Rushgrove kubernetes_pod { 'sample-pod': ensure => present, metadata => { namespace => 'default', }, spec => { containers => [{ name => 'container-name', image => 'nginx', }] }, }
  • 85. (without introducing more risk) Gareth Rushgrove apiVersion: v1 kind: Pod metadata: namespace: default name: sample-pod spec: container: - image: nginx name: container-name
  • 86. (without introducing more risk) Gareth Rushgrove controller_service_pair { 'redis-master': app => 'redis', role => 'master', tier => 'backend', port => 6379, }
  • 87. (without introducing more risk) Gareth Rushgrove apiVersion: v1 kind: Service metadata: name: redis-master labels: app: redis tier: backend role: master spec: ports: # the port that this service should serve on - port: 6379 targetPort: 6379 selector: app: redis tier: backend role: master --- apiVersion: v1 kind: ReplicationController metadata: name: redis-master # these labels can be applied automatically # from the labels in the pod template if not set labels: app: redis role: master tier: backend spec: # this replicas value is default # modify it according to your case replicas: 1 # selector can be applied automatically # from the labels in the pod template if not set # selector: # app: guestbook # role: master # tier: backend
  • 89. (without introducing more risk) Conclusions New technology means old problems
  • 90. (without introducing more risk) The difference between how you think something works and how it actually works risks hard-to-debug production issues Gareth Rushgrove
  • 91. (without introducing more risk) Containers introduce new and old configuration problems Gareth Rushgrove
  • 92. (without introducing more risk) Configuration management is the discipline aimed at minimising those risks Gareth Rushgrove
  • 93. (without introducing more risk) Start with principles Gareth Rushgrove
  • 94. (without introducing more risk) - Identification - Control - Status accounting - Verification Gareth Rushgrove Military Handbook Configuration Management Guidance MIL-HDBK-61B
  • 95. (without introducing more risk) Apply them to your container based infrastructure today Gareth Rushgrove
  • 96. (without introducing more risk) Questions? And thanks for listening