A Puppet Approach To Application Deployment And Automation In Nokia. Oliver Hookins Principal Engineer Services & Developer Experience

Similar documents
How to extend Puppet using Ruby

A central continuous integration platform

Puppet Firewall Module and Landb Integration

Web Developer Toolkit for IBM Digital Experience

developing sysadmin - sysadmining developers

DevOps with Containers. for Microservices

Azure Day Application Development

Configuration Management Evolution at CERN. Gavin

depl Documentation Release depl contributors

Automated Configuration of Open Stack Instances at Boot Time

Rake Task Management Essentials

What new with Informix Software as a Service and Bluemix? Brian Hughes IBM

When flexibility met simplicity: The friendship of OpenStack and Ansible

Secure Linux Administration Conference Bernd Strößenreuther

Agile Delivery Framework Automation & Deployment With Puppet

The Cordova Development Lifecycle

SUCCESFUL TESTING THE CONTINUOUS DELIVERY PROCESS

MarkLogic 8: Samplestack

Four Reasons Your Technical Team Will Love Acquia Cloud Site Factory

Managing and Maintaining Windows Server 2008 Servers

VOCOLLECT VOICEARTISAN. Extending Your Vocollect Configuration

Google

Integrating Cloud File Sharing Platforms with Enterprise Applications & Intelligent Workflow

Testing Tools using Visual Studio. Randy Pagels Sr. Developer Technology Specialist Microsoft Corporation

Web Application Platform for Sandia

This Conference brought to you by

Version Control Your Jenkins Jobs with Jenkins Job Builder

Chef Patterns at Bloomberg Scale HADOOP INFRASTRUCTURE TEAM. Freenode: #chef-bach

Managing Applications: How much money can you save with a Collaborative Workflow tool?

Ansible. Configuration management tool and ad hoc solution. Marcel Nijenhof

Beyond Spreadsheets. How Cloud Computing for HR Saves Time & Reduces Costs. January 11, 2012

PostgreSQL administration using Puppet. Miguel Di Ciurcio Filho

Meister Going Beyond Maven

Our Puppet Story Patterns and Learnings

GECKO Software. Introducing FACTORY SCHEMES. Adaptable software factory Patterns

StriderCD Book. Release 1.4. Niall O Higgins

Java CPD (I) Frans Coenen Department of Computer Science

JobSuite Sample Workflow and Template

Accenture Cloud Platform Unlocks Agility and Control

Servers. Servers. NAT Public Subnet: /20. Internet Gateway. VPC Gateway VPC: /16

MS 20246C Monitoring and Operating a Private Cloud

SharePoint 2010 Interview Questions-Architect

Security challenges for internet technologies on mobile devices

The road to lazy monitoring with Icinga2 & Puppet. Tom De

CARRIOTS TECHNICAL PRESENTATION

Open source framework for interactive data exploration in server based architecture

Penetration Testing Report Client: Business Solutions June 15 th 2015

A Study of Android Application Security

Installation Guide ARGUS Symphony 1.6 and Business App Toolkit. 6/13/ ARGUS Software, Inc.

The AppSec How-To: Achieving Security in DevOps

TypeScript for C# developers. Making JavaScript manageable

BAPI. Business Application Programming Interface. Compiled by Y R Nagesh 1

Developing for the App Store. (Legacy)

In this Lecture you will Learn: Implementation. Software Implementation Tools. Software Implementation Tools

IBM Rational Rapid Developer Components & Web Services

Chapter 9 Software Evolution

White Paper Take Control of Datacenter Infrastructure

Dry Dock Documentation

Best Practices for Sharing Imagery using Amazon Web Services. Peter Becker

A multi-purpose and multi-network compliance management software package

Paul Boisvert. Director Product Management, Magento

Getting Started Developing JavaScript Web Apps. this = that. VT Geospatial Forum 2015

Software Engineering. So(ware Evolu1on

Working With Virtual Hosts on Pramati Server

WHITEPAPER. Managing Design Changes in Enterprise SBM Installations

IBM InfoSphere MDM Server v9.0. Version: Demo. Page <<1/11>>

Development at the Speed and Scale of Google. Ashish Kumar Engineering Tools

Document Lifecycle Management for Engineering and Resources

How can Identity and Access Management help me to improve compliance and drive business performance?

Using GitHub for Rally Apps (Mac Version)

DevOps on AWS: Best Practices for Enterprise IT Teams

Office 365 SharePoint Online

OpenStack CI: flow, tools and more

From TruQC and Carboline

INTEGRATION STRATEGIES FOR HEALTHCARE IT VENDORS COST-EFFECTIVE INTEROPERABILITY SOLUTIONS

Releasing High Quality Applications More Quickly with vrealize Code Stream

Introduction. Software Development and Change Management Recommendations

Open Source Multi-Cloud, Multi- Tenant Automation in the cloud with SlipStream PaaS

SUCCESFUL TESTING THE CONTINUOUS DELIVERY PROCESS

Category: Business Process and Integration Solution for Small Business and the Enterprise

Application for Splunk Enterprise

Mobile Application Platform

Exam Name: IBM InfoSphere MDM Server v9.0

WHITEPAPER. SBM Path to Production for Enterprises

The SAS Solution for Enterprise Marketing Automation - Opening Session Demo

Transcription:

A Puppet Approach To Application Deployment And Automation In Nokia Oliver Hookins Principal Engineer Services & Developer Experience

Who am I? - Rockstar SysAdmin

Who am I? - Puppet User since 0.23 - Working in Nokia's Location-Based Services for 1.5 years - Previously at Anchor Systems (manages GitHub infrastructure with Puppet) - Love/Hate Relationship with Ruby

What do we do? - Location Based Services - Diverse collection of applications - Rapidly moving environment, competing directly with well-known giants in the services arena - Large, traditionally-organised company with heavy change control

What do we do?

What do we do?

The Problem Domain - Deployment consistent across environments - Reduce duplication of effort (and as a by-product, human errors) - Increase testing, feedback of errors, reliability.

The Legacy System

The 1.0 Puppet System

New Problems - Node definitions - Lack of trust built-in - Code constantly evolving - Not enough testing to counter poor Puppet knowledge - Victim of our own success

BDD

Goals - Approach more like traditional software development - Better versioning of components - Testing, testing, testing! - Automation using Jenkins - Easier deployments - Better developer tools

Testing

Jenkins - CI/build tool - Split testing into stages - simple tests (lint, --parseonly, templates) take < 2min to run - compile tests (Puppet Faces) should take < 10min - integration (full-deploy) -?? - Use in production! (canary) - Eventually: continuous deployment

API Approach - Expose a well-defined interface - Remove host-, role-, DC- (etc) specifics from modules - Drive configuration through the front door - Remove need to look at the code (basically reverse engineering)

ENC - Write one! or try Dashboard - Seriously, it unlocks Puppet's potential

Why not use extlookup? - Equivalent of global variables in programming, bad! - No well-defined interface to classes/defines - Requires that you code-dive to find out how to use a class/define - Well-defined API and general documentation should be sufficient - Can't easily test code in isolation

Class Introspection # Prepare a hash to dump out the API h = {} h['class'] = {} h['define'] = {} # Inspect the PP file file = 'foo.pp' Puppet[:manifest] = file File.open(file, 'r').readlines().each do l if /^(class define)\s+([^\({\s]+)/ tipe = $~[1] # capture the type of object we found id = $~[2] # we want the class/define name # Grab the arguments and class/define name args = Puppet::Resource::Type.find(id).to_pson_data_hash['arguments'] klass = Puppet::Resource::Type.find(id).to_pson_data_hash['name'] end end h[tipe][klass] = args

Class Introspection # Prepare a hash to dump out the API h = {} h['class'] = {} h['define'] = {} # Inspect the PP file file = 'foo.pp' Puppet[:manifest] = file File.open(file, 'r').readlines().each do l if /^(class define)\s+([^\({\s]+)/ tipe = $~[1] # capture the type of object we found id = $~[2] # we want the class/define name # Grab the arguments and class/define name args = Puppet::Resource::Type.find(id).to_pson_data_hash['arguments'] klass = Puppet::Resource::Type.find(id).to_pson_data_hash['name'] end end h[tipe][klass] = args

Class Introspection # Prepare a hash to dump out the API h = {} h['class'] = {} h['define'] = {} # Inspect the PP file file = 'foo.pp' Puppet[:manifest] = file File.open(file, 'r').readlines().each do l if /^(class define)\s+([^\({\s]+)/ tipe = $~[1] # capture the type of object we found id = $~[2] # we want the class/define name # Grab the arguments and class/define name args = Puppet::Resource::Type.find(id).to_pson_data_hash['arguments'] klass = Puppet::Resource::Type.find(id).to_pson_data_hash['name'] end end h[tipe][klass] = args

Class Introspection # Prepare a hash to dump out the API h = {} h['class'] = {} h['define'] = {} # Inspect the PP file file = 'foo.pp' Puppet[:manifest] = file File.open(file, 'r').readlines().each do l if /^(class define)\s+([^\({\s]+)/ tipe = $~[1] # capture the type of object we found id = $~[2] # we want the class/define name # Grab the arguments and class/define name args = Puppet::Resource::Type.find(id).to_pson_data_hash['arguments'] klass = Puppet::Resource::Type.find(id).to_pson_data_hash['name'] end end h[tipe][klass] = args

Class Introspection # Prepare a hash to dump out the API h = {} h['class'] = {} h['define'] = {} # Inspect the PP file file = 'foo.pp' Puppet[:manifest] = file File.open(file, 'r').readlines().each do l if /^(class define)\s+([^\({\s]+)/ tipe = $~[1] # capture the type of object we found id = $~[2] # we want the class/define name # Grab the arguments and class/define name args = Puppet::Resource::Type.find(id).to_pson_data_hash['arguments'] klass = Puppet::Resource::Type.find(id).to_pson_data_hash['name'] end end h[tipe][klass] = args

Class Introspection Now you have a YAML interface definition: class: postfix: root_email: /dev/null relayhost: inet_interfaces: localhost alias_maps: hash:/etc/aliases mynetworks: ""

Class Introspection - Canary testing - Interface documentation (have a look at the :doc string as well) - Generate web forms

Module Organisation Dist - Provides platform services, as well as APIs for application modules to use - Stable, defined release cycle - Should be of sufficient quality that app teams cannot resist using it - Eventually delegate maintenance to specialist teams

Module Organisation Dist - Pull in things from Moduleforge, or just use Moduleforge (in future)

Module Organisation App - Blueprints for how to deploy applications - Uses Dist APIs rather than reimplement functionality - Sets up development environments for application still unsure of correct approach for this

Packaging

Packaging http://hunnur.com/blog/2010/10/dynamic-git-branch-puppet-environments/ - Modules under /etc/puppet/modules - Each has metadata files (version of app, version of dist) - Module path: $confdir/environments/$environment/app: $confdir/environments/$environment/dist - Spec file creates symlinks from actual app and dist to above locations

Environment Change def get_node_previous_environment(fqdn) factsdir = File.join(get_node_yamldir(), 'facts') File.directory?(factsdir) or raise NoFactsDirectoryError, factsdir # Inspect the client machine's facts factsfile = File.join(factsdir, "#{fqdn}.yaml") if [nil, ''].include?fqdn or not File.exist?(factsfile) raise(noclientfactserror,factsfile) end # Create a Puppet::Node object from the stored YAML object y = YAML.load_file(factsfile) p = Puppet::Node::Facts.new(y.name, y.values) p.values['environment'] end

Environment Change def get_node_previous_environment(fqdn) factsdir = File.join(get_node_yamldir(), 'facts') File.directory?(factsdir) or raise NoFactsDirectoryError, factsdir # Inspect the client machine's facts factsfile = File.join(factsdir, "#{fqdn}.yaml") if [nil, ''].include?fqdn or not File.exist?(factsfile) raise(noclientfactserror,factsfile) end # Create a Puppet::Node object from the stored YAML object y = YAML.load_file(factsfile) p = Puppet::Node::Facts.new(y.name, y.values) p.values['environment'] end

Environment Change def get_node_previous_environment(fqdn) factsdir = File.join(get_node_yamldir(), 'facts') File.directory?(factsdir) or raise NoFactsDirectoryError, factsdir # Inspect the client machine's facts factsfile = File.join(factsdir, "#{fqdn}.yaml") if [nil, ''].include?fqdn or not File.exist?(factsfile) raise(noclientfactserror,factsfile) end # Create a Puppet::Node object from the stored YAML object y = YAML.load_file(factsfile) p = Puppet::Node::Facts.new(y.name, y.values) p.values['environment'] end

Environment Change def get_node_previous_environment(fqdn) factsdir = File.join(get_node_yamldir(), 'facts') File.directory?(factsdir) or raise NoFactsDirectoryError, factsdir # Inspect the client machine's facts factsfile = File.join(factsdir, "#{fqdn}.yaml") if [nil, ''].include?fqdn or not File.exist?(factsfile) raise(noclientfactserror,factsfile) end # Create a Puppet::Node object from the stored YAML object y = YAML.load_file(factsfile) p = Puppet::Node::Facts.new(y.name, y.values) p.values['environment'] end

Environment Change if node_puppetenvironment!= oldenv then Puppet.notice("Changing environment from #{oldenv} to #{node_puppetenvironment} for node #{fqdn}") y = {} y['parameters'] = {} y['environment'] = node_puppetenvironment y['classes'] = {} y['classes']['puppet::client'] = {} y['classes']['puppet::client']['puppet_environment'] = node_puppetenvironment.clone # YAML catches duplicate references y['classes']['puppet::client']['puppetmaster'] = node_puppetmaster end

Environment Change if node_puppetenvironment!= oldenv then Puppet.notice("Changing environment from #{oldenv} to #{node_puppetenvironment} for node #{fqdn}") y = {} y['parameters'] = {} y['environment'] = node_puppetenvironment y['classes'] = {} y['classes']['puppet::client'] = {} y['classes']['puppet::client']['puppet_environment'] = node_puppetenvironment.clone # YAML catches duplicate references y['classes']['puppet::client']['puppetmaster'] = node_puppetmaster end

Environment Change if node_puppetenvironment!= oldenv then Puppet.notice("Changing environment from #{oldenv} to #{node_puppetenvironment} for node #{fqdn}") y = {} y['parameters'] = {} y['environment'] = node_puppetenvironment y['classes'] = {} y['classes']['puppet::client'] = {} y['classes']['puppet::client']['puppet_environment'] = node_puppetenvironment.clone # YAML catches duplicate references y['classes']['puppet::client']['puppetmaster'] = node_puppetmaster end

Our ENC

Our ENC vars: puppet_version: 2.6.7 ntp_servers: - 192.0.2.1-192.0.2.2-192.0.2.3 repo_server: repo.ny.example.com accounts: - bofh - peon myapp_version: 3.0.0 classes: platform: puppet_version: ${puppet_version} ntp_servers: ${ntp_servers} repo_server: ${repo_server} accounts: ${accounts} myapp: version: ${myapp_version}

Future

Future - Deployment strategy not entirely worked out - Developer workflows still could be improved (some promising work in this area, e.g. cloudsmith/geppetto (IDE integration))

Thank You! oliver.hookins@nokia.com ohookins@gmail.com http://paperairoplane.net/ P.S. We're Hiring!

Attributions - Photo on slide 8 by dandeluca, available under a Creative Commons Attribution licence - Photo on slide 9 by graemenewcomb, available under a Creative Commons Attribution licence - Photo on slide 11 by seenful, available under a Creative Commons Attribution licence - Photo on slide 13 by f-oxymoron, available under a Creative Commons Attribution licence - Photo on slide 28 by oskay, available under a Creative Commons Attribution licence - Photo on slide 39 by kirrilyrobert, available under a Creative Commons Attribution licence