SlideShare a Scribd company logo
Cooking Perl with Chef
        David Golden
           @xdg

      http://perlchef.com/

             July 2012
Configuration
    Management
(e.g. chef, puppet, cfengine, ...)
Unknown state

     ↓
 Target state
New machine

    ↓
Deployed app
Infrastructure as code
            automated!
            repeatable!
              testable!

 (no manual steps, checklist, etc.)
One tool to deploy
 the whole stack
(DB, caching, messaging, ...)
But wait!
Isn't that hard to do for Perl apps?
Perl applications are complex
Dependency hell
App = perl + CPAN + your code
CHI
             DateTime
             DBI
             JSON
App = perl + CPAN + your code
             Moose
             Plack
             POE
             Try::Tiny
             ...
CHI
                            DateTime
                            DBI
                            JSON
App = perl + CPAN + your code
                            Moose
                            Plack
                            POE
                            Try::Tiny
                            ...




 your application is the versioned set of all its compontents
CHI
                              DateTime
                              DBI
                              JSON
App
v1.0.0   = perl + CPAN + your code
                              Moose
                              Plack
                              POE
                              Try::Tiny
                              ...




   your application is the versioned set of all its compontents
CHI
                              DateTime
                              DBI
                              JSON
App
v1.0.0   = Perl + CPAN + your code
           v5.14.2            Moose
                              Plack
                              POE
                              Try::Tiny
                              ...




   your application is the versioned set of all its compontents
0.55
                              0.76
                              1.622
                              2.53
App
v1.0.0   = Perl + CPAN + your code
           v5.14.2            2.0603
                              0.9989
                              1.354
                              0.11
                              ...




   your application is the versioned set of all its compontents
0.55
                              0.76
                              1.622
                              2.53
App
v1.0.0   = Perl + CPAN + your code
           v5.14.2       v1.0 2.0603
                              0.9989
                              1.354
                              0.11
                              ...




   your application is the versioned set of all its compontents
0.55
                     0.76
                     1.622
                     2.53
App
v1.0.0   = Perl + CPAN + your code
           v5.14.2       v1.0
                     2.0603
                     0.9989
                     1.354
                     0.11
                     ...




              change one piece...
0.55
                     0.76
                     1.622
                     2.53
App
v1.0.0   = Perl + CPAN + your code
           v5.16.0       v1.0
                     2.0603
                     0.9989
                     1.354
                     0.11
                     ...




              change one piece...
0.55
                              0.76
                              1.622
                              2.53
App
v1.0.1    = Perl + CPAN + your code
            v5.16.0       v1.02.0603
                              0.9989
                              1.354
                              0.11
                              ...




         … and you have a new version of your application
Repeatable deployment means...
Repeatable deployment means...

        ... the same Perl
Repeatable deployment means...

        ... the same Perl
        ... the same modules
Repeatable deployment means...

        ... the same Perl
        ... the same modules
        ... the same code
Repeatable deployment means...

        ... the same Perl
        ... the same modules
        ... the same code
        ... on demand
Easy...
If we have the right tools
Use one-size fits all distribution packagers like
               apt, yum, etc...?

       (How much do you like your system perl?!)
This problem is not
  unique to Perl
Let's be inspired by Larry
[larry hat pic]
Or better yet, Paul
Cooking Perl with Chef
YARRR!
Great hackers steal!
Great hackers steal ideas
Consider Chef...
Chef ❤ Ruby
(written in ruby; various ruby app stacks)
Chef ❤ Python
(virtualenv; pip; django apps)
Common patterns emerge
python → virtualenv + pip
 ruby → rvm + Bundler
We've built tools like these, too
Kang-min Liu (gugod)

 Matt S Trout (mst)

Tatsuhiko Miyagawa
(and a big community helping them)
perlbrew – multiple perl manager

       Matt S Trout (mst)

      Tatsuhiko Miyagawa
      (and a big community helping them)
perlbrew – multiple perl manager

local::lib – custom @INC manager

      Tatsuhiko Miyagawa
      (and a big community helping them)
perlbrew – multiple perl manager

  local::lib – custom @INC manager

carton – versioned dependency installer
         (and a big community helping them)
So we have the pieces
Repeatable deployment in five parts
Repeatable deployment in five parts

      application-specific Perl

      application-specific @INC path

      versioned application code

      versioned module dependencies

      automate the previous four
Repeatable deployment in five parts

      perlbrew

      application-specific @INC path

      versioned application code

      versioned module dependencies

      automate the previous four
Repeatable deployment in five parts

      perlbrew

      local::lib

      versioned application code

      versioned module dependencies

      automate the previous four
Repeatable deployment in five parts

      perlbrew

      local::lib

      git

      versioned module dependencies

      automate the previous four
Repeatable deployment in five parts

      perlbrew

      local::lib

      git

      carton

      automate the previous four
Repeatable deployment in five parts

      perlbrew

      local::lib

      git

      carton

      @&$%!
[swedish chef FAIL pic]
No support in Chef...
So I implemented it
(In Ruby)
(After I learned some Ruby)
Now...


         Chef ❤ Perl
    (perlbrew; local::lib; carton)
Time for a quick Chef glossary...

 (see http://wiki.opscode.com/)
“Cookbook”

A collection of components to configure
a particular application

Typically includes recipes, providers,
templates, etc.

(CPAN analogy → “distribution”)
“Recipe”

Component applied that deploys an
application or service

Typically declarative, specifying desired
resources and associated configuration
“Resource”

An abstraction of something to be deployed
“Provider”

Platform-specific implementation to deliver a
resource
“Node”

A host computer managed with Chef

Often means the configuration file that
defines recipes, attributes and roles that
define the target state of a host
“Attribute”

A variable used in a recipe and/or provider
that customizes the configuration of a
resource

Attributes have defaults, but can be
customized for nodes or roles
“Role”

A collection of recipes and attributes used to
apply common configuration across multiple
nodes
Summary...


    cookbooks include recipes and providers

roles, recipes and attributes get applied to nodes

recipes specify desired resources and customize
               them with attributes

 providers do the work of deploying resources
I wrote two Perl Chef cookbooks
for the Chef community repository
     (which is like CPAN circa 1996 or so)


       http://community.opscode.com/
1. perlbrew – for managing perls

2. carton – for deploying apps


Also available here: https://github.com/dagolden/perl-chef
perlbrew cookbook resources:

  perlbrew_perl – install a perl

  perlbrew_lib – create a local::lib

  perlbrew_cpanm – install modules to perl or lib

  perlbrew_run – run shell commands under a
  particular perlbrew and/or lib
carton cookbook resource:

  carton_app – deploy an app with carton

    – start in directory with the app source
    – configure for a specific perlbrew perl
    – install versioned dependencies with carton
    – create a runit service for the app
    – start the app
Time for an example:

Deploying a “Hello World” Plack app

     https://github.com/dagolden/zzz-hello-world
Steps for creating Hello World

    1. Write the application

    2. Use carton to create a carton.lock file with
       versioned dependency info

    3. Write a simple cookbook for the application

    4. Check it all into git

    5. Deploy the application with Chef
$ tree
.
├── Changes
├── Makefile.PL
├── app.psgi
├── carton.lock
├── cookbook
│   └── hello-world
│       ├── README.md
│       ├── attributes
│       │    └── default.rb
│       ├── metadata.rb
│       └── recipes
│            └── default.rb
└── lib
    └── ZZZ
        └── Hello
             └── World.pm
$ tree
.
├── Changes
├── Makefile.PL
├── app.psgi
├── carton.lock
├── cookbook
│   └── hello-world
│       ├── README.md
│       ├── attributes
│       │    └── default.rb
│       ├── metadata.rb
│       └── recipes
│            └── default.rb
└── lib
    └── ZZZ
        └── Hello
             └── World.pm
use strict;
use warnings;
use ZZZ::Hello::World;
my $app = sub { ZZZ::Hello::World->run_psgi(@_) };




                             (this Plack app just invokes a simple module)
$ tree
.
├── Changes
├── Makefile.PL
├── app.psgi
├── carton.lock
├── cookbook
│   └── hello-world
│       ├── README.md
│       ├── attributes
│       │    └── default.rb
│       ├── metadata.rb
│       └── recipes
│            └── default.rb
└── lib
    └── ZZZ
        └── Hello
             └── World.pm
use 5.008001;
use strict;
use warnings;

package ZZZ::Hello::World;
our $VERSION = "1.0";

use Plack::Request;

sub run_psgi {
  my $self = shift;
  my $req = Plack::Request->new(shift);
  my $res = $req->new_response(200);
  $res->content_type('text/html');
  $res->body(<<"HERE");
<html>
<head><title>Hello World</title></head>
<body>
<p>Hello World. It is @{[scalar localtime]}</p>
...
</body>
</html>
HERE
  return $res->finalize;
}

1;
                                   (the module just returns some dynamic HTML)
$ tree
.
├── Changes
├── Makefile.PL
├── app.psgi
├── carton.lock
├── cookbook
│   └── hello-world
│       ├── README.md
│       ├── attributes
│       │    └── default.rb
│       ├── metadata.rb
│       └── recipes
│            └── default.rb
└── lib
    └── ZZZ
        └── Hello
             └── World.pm
use inc::Module::Install;
name 'ZZZ-Hello-World';
version '1.0';

requires 'Plack';
requires 'Starman';

WriteAll;




            (the Makefile.PL also includes deployment dependencies like Starman)
During development, carton installs
dependencies locally and creates a versioned
dependency file called carton.lock

$ carton install
# installs dependencies into a local directory
# creates carton.lock if it doesn't exist
# carton.lock is a JSON file of dependency info
During deployment, carton installs dependencies
from carton.lock and runs the app with them

$ carton install
# installs dependencies into a local directory

$ carton exec ­Ilib ­­ starman ­p 8080 app.psgi
# runs the app using carton installed deps
$ tree
.
├── Changes
├── Makefile.PL
├── app.psgi
├── carton.lock
├── cookbook
│   └── hello-world
│       ├── README.md
│       ├── attributes
│       │    └── default.rb
│       ├── metadata.rb
│       └── recipes
│            └── default.rb
└── lib
    └── ZZZ
        └── Hello
             └── World.pm
# carton.lock JSON
{
   "modules" : {
      "Class::Inspector" : {
          "dist" : "Class-Inspector-1.27",
          "module" : "Class::Inspector",
          "pathname" :
              "A/AD/ADAMK/Class-Inspector-1.27.tar.gz",
          ...
      }.
      "Data::Dump" : {
          ...
      },
      "Devel::StackTrace" : {
          ...
      },
      "Encode::Locale" : {
          ...
      },
      ...
}
        (carton.lock associates module names to specific versions of those module)
$ tree
.
├── Changes
├── Makefile.PL
├── app.psgi
├── carton.lock
├── cookbook
│   └── hello-world
│       ├── README.md
│       ├── attributes
│       │    └── default.rb
│       ├── metadata.rb
│       └── recipes
│            └── default.rb
└── lib
    └── ZZZ
        └── Hello
             └── World.pm
# perlbrew to execute with
 default['hello-world']['perl_version'] = 'perl-5.16.0'

 # Install directory, repo and tag
 default['hello-world']['deploy_dir'] = '/opt/hello-world'
 default['hello-world']['deploy_repo'] =
       'https://github.com/dagolden/zzz-hello-world.git'
 default['hello-world']['deploy_tag'] = 'master'

 # Service user/group/port
 default['hello-world']['user'] = "nobody"
 default['hello-world']['group'] = "nogroup"
 default['hello-world']['port'] = 8080




(attributes are variables used in the recipe; can be customized per-node during deployment)
$ tree
.
├── Changes
├── Makefile.PL
├── app.psgi
├── carton.lock
├── cookbook
│   └── hello-world
│       ├── README.md
│       ├── attributes
│       │    └── default.rb
│       ├── metadata.rb
│       └── recipes
│            └── default.rb
└── lib
    └── ZZZ
        └── Hello
             └── World.pm
include_recipe 'carton'

package 'git-core'

git node['hello-world']['deploy_dir'] do
  repository node['hello-world']['deploy_repo']
  reference node['hello-world']['deploy_tag']
  notifies :restart, "carton_app[hello-world]"
end

carton_app "hello-world" do
  perlbrew node['hello-world']['perl_version']
  command "starman -p #{node['hello-world']['port']} app.psgi"
  cwd node['hello-world']['deploy_dir']
  user node['hello-world']['user']
  group node['hello-world']['group']
end

carton_app "hello-world" do
  action :start
end



                                (recipe ensures carton and git are available...)
include_recipe 'carton'

package 'git-core'

git node['hello-world']['deploy_dir'] do
  repository node['hello-world']['deploy_repo']
  reference node['hello-world']['deploy_tag']
  notifies :restart, "carton_app[hello-world]"
end

carton_app "hello-world" do
  perlbrew node['hello-world']['perl_version']
  command "starman -p #{node['hello-world']['port']} app.psgi"
  cwd node['hello-world']['deploy_dir']
  user node['hello-world']['user']
  group node['hello-world']['group']
end

carton_app "hello-world" do
  action :start
end



                          (git resource specifies where application code goes...)
include_recipe 'carton'

package 'git-core'

git node['hello-world']['deploy_dir'] do
  repository node['hello-world']['deploy_repo']
  reference node['hello-world']['deploy_tag']
  notifies :restart, "carton_app[hello-world]"
end

carton_app "hello-world" do
  perlbrew node['hello-world']['perl_version']
  command "starman -p #{node['hello-world']['port']} app.psgi"
  cwd node['hello-world']['deploy_dir']
  user node['hello-world']['user']
  group node['hello-world']['group']
end

carton_app "hello-world" do
  action :start
end



                              (attributes parameterize the resource statement...)
include_recipe 'carton'

package 'git-core'

git node['hello-world']['deploy_dir'] do
  repository node['hello-world']['deploy_repo']
  reference node['hello-world']['deploy_tag']
  notifies :restart, "carton_app[hello-world]"
end

carton_app "hello-world" do
  perlbrew node['hello-world']['perl_version']
  command "starman -p #{node['hello-world']['port']} app.psgi"
  cwd node['hello-world']['deploy_dir']
  user node['hello-world']['user']
  group node['hello-world']['group']
end

carton_app "hello-world" do
  action :start
end



                     (carton_app resources installs deps and sets up runit service...)
include_recipe 'carton'

package 'git-core'

git node['hello-world']['deploy_dir'] do
  repository node['hello-world']['deploy_repo']
  reference node['hello-world']['deploy_tag']
  notifies :restart, "carton_app[hello-world]"
end

carton_app "hello-world" do
  perlbrew node['hello-world']['perl_version']
  command "starman -p #{node['hello-world']['port']} app.psgi"
  cwd node['hello-world']['deploy_dir']
  user node['hello-world']['user']
  group node['hello-world']['group']
end

carton_app "hello-world" do
  action :start
end



                               (again, attributes parameterize the resource...)
include_recipe 'carton'

package 'git-core'

git node['hello-world']['deploy_dir'] do
  repository node['hello-world']['deploy_repo']
  reference node['hello-world']['deploy_tag']
  notifies :restart, "carton_app[hello-world]"
end

carton_app "hello-world" do
  perlbrew node['hello-world']['perl_version']
  command "starman -p #{node['hello-world']['port']} app.psgi"
  cwd node['hello-world']['deploy_dir']
  user node['hello-world']['user']
  group node['hello-world']['group']
end

carton_app "hello-world" do
  action :start
end



                                (finally, the resource is idempotently started...)
These files – and the Perl Chef
 cookbooks – are all you need
Enough code... let's see how to deploy it
Steps for deployment of Hello World


    1. Set up a Vagrant virtual machine

    2. Prepare Pantry to manage Chef Solo

    3. Get Hello World cookbook and dependencies

    4. Configure virtual machine for Hello World

    5. Deploy
Steps for deployment of Hello World


    1. Set up a Vagrant virtual machine

    2. Prepare Pantry to manage Chef Solo

    3. Get Hello World cookbook and dependencies

    4. Configure virtual machine for Hello World

    5. Deploy
Cooking Perl with Chef
Vagrant is a tool for managing virtual machines


   “Can I have a VirtualBox now, please?”
Vagrant is a tool for managing virtual machines


$ vagrant box add base 
  http://files.vagrantup.com/lucid32.box

$ vagrant init

$ vagrant up
Vagrant is great for testing Chef deployment

            (and other things, besides)
Steps for deployment of Hello World


    1. Set up a Vagrant virtual machine

    2. Prepare Pantry to manage Chef Solo

    3. Get Hello World cookbook and dependencies

    4. Configure virtual machine for Hello World

    5. Deploy
Chef Solo is Chef without a central
      configuration server

 (good for demos and smaller deployments)
Chef        – you push config data to Chef Server
            – nodes run Chef Client to pull config
              from Chef Server and execute it



Chef Solo   – you push config data to nodes
            – you run Chef Solo remotely
Cooking Perl with Chef
One advantage of Chef Solo...

        Your config repo is canonical

(i.e. you don't have to track what you've pushed to the central server)
One dis-advantage of Chef Solo...

Manual rsync/ssh required (yuck!)
Steps for deployment of Hello World


    1. Set up a Vagrant virtual machine

    2. Prepare Pantry to manage Chef Solo

    3. Get Hello World cookbook and dependencies

    4. Configure virtual machine for Hello World

    5. Deploy
Pantry is a tool for automating Chef Solo
Pantry is a tool for automating Chef Solo


$ pantry create node server.example.com

$ pantry apply node server.example.com 
  --role web --recipe myapp

$ pantry sync node server.example.com
Pantry is written in Perl and available on CPAN

   (Similar to pocketknife [Ruby] and littlechef [Python])
Finally, a demonstration...



   Screencast available at
http://youtu.be/H93rt-KtwBE
Steps for deployment of Hello World


    1. Set up a Vagrant virtual machine

    2. Prepare Pantry to manage Chef Solo

    3. Get Hello World cookbook and dependencies

    4. Configure virtual machine for Hello World

    5. Deploy
$ vagrant init
# create config file

$ vim Vagrantfile
# edit to forward local port 8080 to
# virtual machine port 8080

$ vagrant up
# launch it

$ vagrant ssh
# check that it's up, then exit
Steps for deployment of Hello World


    1. Set up a Vagrant virtual machine

    2. Prepare Pantry to manage Chef Solo

    3. Get Hello World cookbook and dependencies

    4. Configure virtual machine for Hello World

    5. Deploy
$ pantry init
# create directories to hold Chef Solo config

$ pantry create node vagrant 
    ­­host localhost 
    ­­port 8080      
    ­­user vagrant
# create a node config file

$ ssh­add ~/.vagrant.d/insecure_private_key
# allow pantry to ssh to vagrant machine 




         (Important tip: remove the insecure_private_key after you no longer
         need it because Github chokes on it.)
Steps for deployment of Hello World


    1. Set up a Vagrant virtual machine

    2. Prepare Pantry to manage Chef Solo

    3. Get Hello World cookbook and dependencies

    4. Configure virtual machine for Hello World

    5. Deploy
Four cookbooks must be downloaded
and copied to the 'cookbooks' directory

 – hello-world
 – carton
 – perlbrew
 – runit
Steps for deployment of Hello World


    1. Set up a Vagrant virtual machine

    2. Prepare Pantry to manage Chef Solo

    3. Get Hello World cookbook and dependencies

    4. Configure virtual machine for Hello World

    5. Deploy
$ pantry apply node vagrant ­­recipe hello­world
# apply recipe to node configuration

$ pantry apply node vagrant ­­default 
    hello­world.perl_version=perl­5.14.2
# override a default attribute

$ pantry show node vagrant
# see the resulting JSON config file
{
   "hello­world" : {
      "perl_version" : "perl­5.14.2"
   },
   "run_list" : [
      "recipe[hello­world]"
   ],
   "name" : "vagrant",
   "pantry_user" : "vagrant",
   "pantry_port" : "2222",
   "pantry_host" : "localhost"
}
Steps for deployment of Hello World


    1. Set up a Vagrant virtual machine

    2. Prepare Pantry to manage Chef Solo

    3. Get Hello World cookbook and dependencies

    4. Configure virtual machine for Hello World

    5. Deploy
$ pantry sync node vagrant
# ... wait for everything to deploy ...
# then load browser and test it!
It works
You can do this, too
Don't be afraid. Try it out. Get involved.

   tutorial and screencast → http://perlchef.com

  mailing list → perl-devops-subscribe@perl.org

More Related Content

PDF
Cooking Perl with Chef: Real World Tutorial with Jitterbug
KEY
From Dev to DevOps - FOSDEM 2012
PDF
Workshop: Know Before You Push 'Go': Using the Beaker Acceptance Test Framewo...
PDF
Continuous Infrastructure: Modern Puppet for the Jenkins Project - PuppetConf...
PDF
Continuous Delivery with Maven, Puppet and Tomcat - ApacheCon NA 2013
KEY
From Dev to DevOps - Apache Barcamp Spain 2011
PDF
Beaker: Automated, Cloud-Based Acceptance Testing - PuppetConf 2014
PDF
Portland PUG April 2014: Beaker 101: Acceptance Test Everything
Cooking Perl with Chef: Real World Tutorial with Jitterbug
From Dev to DevOps - FOSDEM 2012
Workshop: Know Before You Push 'Go': Using the Beaker Acceptance Test Framewo...
Continuous Infrastructure: Modern Puppet for the Jenkins Project - PuppetConf...
Continuous Delivery with Maven, Puppet and Tomcat - ApacheCon NA 2013
From Dev to DevOps - Apache Barcamp Spain 2011
Beaker: Automated, Cloud-Based Acceptance Testing - PuppetConf 2014
Portland PUG April 2014: Beaker 101: Acceptance Test Everything

What's hot (20)

KEY
From Dev to DevOps - ApacheCON NA 2011
KEY
Puppet for Java developers - JavaZone NO 2012
PDF
Puppet at GitHub / ChatOps
PDF
Puppet at Pinterest
PDF
PuppetCamp SEA 1 - Using Vagrant, Puppet, Testing & Hadoop
PDF
Building kubectl plugins with Quarkus | DevNation Tech Talk
PDF
Antons Kranga Building Agile Infrastructures
PDF
Test Driven Development with Puppet - PuppetConf 2014
PDF
Kubernetes Java Operator
PDF
Take control of your Jenkins jobs via job DSL.
PDF
DevOps(4) : Ansible(2) - (MOSG)
PPTX
Docker Starter Pack
PDF
Test Driven Development with Puppet
PDF
Ansible 實戰:top down 觀點
PDF
The Modern Developer Toolbox
PDF
Testing Your Automation Code (Docker Version)
PDF
PuppetCamp SEA 1 - Puppet Deployment at OnApp
PDF
Configuring Highly Scalable Compile Masters, Vasco Cardoso, AWS
PDF
Chef for beginners module 5
PDF
A Tale of a Server Architecture (Frozen Rails 2012)
From Dev to DevOps - ApacheCON NA 2011
Puppet for Java developers - JavaZone NO 2012
Puppet at GitHub / ChatOps
Puppet at Pinterest
PuppetCamp SEA 1 - Using Vagrant, Puppet, Testing & Hadoop
Building kubectl plugins with Quarkus | DevNation Tech Talk
Antons Kranga Building Agile Infrastructures
Test Driven Development with Puppet - PuppetConf 2014
Kubernetes Java Operator
Take control of your Jenkins jobs via job DSL.
DevOps(4) : Ansible(2) - (MOSG)
Docker Starter Pack
Test Driven Development with Puppet
Ansible 實戰:top down 觀點
The Modern Developer Toolbox
Testing Your Automation Code (Docker Version)
PuppetCamp SEA 1 - Puppet Deployment at OnApp
Configuring Highly Scalable Compile Masters, Vasco Cardoso, AWS
Chef for beginners module 5
A Tale of a Server Architecture (Frozen Rails 2012)
Ad

Similar to Cooking Perl with Chef (20)

PDF
CPAN 模組二三事
PDF
PDF
Packaging perl (LPW2010)
ODP
30 Minutes To CPAN
PDF
Authoring CPAN modules
PDF
System Programming and Administration
PDF
Perl 5.10 for People Who Aren't Totally Insane
PDF
Making My Own CPAN
PDF
What's New in Perl? v5.10 - v5.16
PDF
Modern Perl Toolchain
PDF
perlbrew yapcasia 2010
PDF
CPAN For Private Code
PDF
Carton
PDF
Perl at SkyCon'12
ODP
Perl - laziness, impatience, hubris, and one liners
PDF
Building a raku module
KEY
Rails Hardware (no conclusions!)
KEY
Perlbrew
PPTX
Lecture 3 Perl & FreeBSD administration
PDF
CPAN 模組二三事
Packaging perl (LPW2010)
30 Minutes To CPAN
Authoring CPAN modules
System Programming and Administration
Perl 5.10 for People Who Aren't Totally Insane
Making My Own CPAN
What's New in Perl? v5.10 - v5.16
Modern Perl Toolchain
perlbrew yapcasia 2010
CPAN For Private Code
Carton
Perl at SkyCon'12
Perl - laziness, impatience, hubris, and one liners
Building a raku module
Rails Hardware (no conclusions!)
Perlbrew
Lecture 3 Perl & FreeBSD administration
Ad

More from David Golden (16)

PDF
Slice Recycling Performance and Pitfalls
PDF
Free QA!
PDF
Eversion 101: An Introduction to Inside-Out Objects
PDF
Perl 5 Version 13
PDF
IsTrue(true)?
PDF
One BSON to Rule Them
PDF
Adventures in Optimization
PDF
Make Comments Stand Out
PDF
State of the Velociraptor Mini-Keynote: Perl Toolchain
PDF
Practical Consistency
PDF
How I get to the ☞
PDF
Real World Optimization
PDF
Safer Chainsaw Juggling (Lightning Talk)
PDF
Taking Perl to Eleven with Higher-Order Functions
PDF
Juggling Chainsaws: Perl and MongoDB
PDF
Cooking Perl with Chef: Hello World Tutorial
Slice Recycling Performance and Pitfalls
Free QA!
Eversion 101: An Introduction to Inside-Out Objects
Perl 5 Version 13
IsTrue(true)?
One BSON to Rule Them
Adventures in Optimization
Make Comments Stand Out
State of the Velociraptor Mini-Keynote: Perl Toolchain
Practical Consistency
How I get to the ☞
Real World Optimization
Safer Chainsaw Juggling (Lightning Talk)
Taking Perl to Eleven with Higher-Order Functions
Juggling Chainsaws: Perl and MongoDB
Cooking Perl with Chef: Hello World Tutorial

Recently uploaded (20)

PPTX
KOM of Painting work and Equipment Insulation REV00 update 25-dec.pptx
DOCX
The AUB Centre for AI in Media Proposal.docx
PDF
Diabetes mellitus diagnosis method based random forest with bat algorithm
PDF
Chapter 3 Spatial Domain Image Processing.pdf
PDF
Empathic Computing: Creating Shared Understanding
PPTX
Spectroscopy.pptx food analysis technology
PDF
Network Security Unit 5.pdf for BCA BBA.
PPTX
sap open course for s4hana steps from ECC to s4
PDF
Profit Center Accounting in SAP S/4HANA, S4F28 Col11
PDF
Advanced methodologies resolving dimensionality complications for autism neur...
PDF
Architecting across the Boundaries of two Complex Domains - Healthcare & Tech...
PDF
Blue Purple Modern Animated Computer Science Presentation.pdf.pdf
PPTX
MYSQL Presentation for SQL database connectivity
PDF
Reach Out and Touch Someone: Haptics and Empathic Computing
PDF
NewMind AI Weekly Chronicles - August'25 Week I
PDF
KodekX | Application Modernization Development
PDF
Electronic commerce courselecture one. Pdf
PDF
The Rise and Fall of 3GPP – Time for a Sabbatical?
PDF
Optimiser vos workloads AI/ML sur Amazon EC2 et AWS Graviton
PDF
7 ChatGPT Prompts to Help You Define Your Ideal Customer Profile.pdf
KOM of Painting work and Equipment Insulation REV00 update 25-dec.pptx
The AUB Centre for AI in Media Proposal.docx
Diabetes mellitus diagnosis method based random forest with bat algorithm
Chapter 3 Spatial Domain Image Processing.pdf
Empathic Computing: Creating Shared Understanding
Spectroscopy.pptx food analysis technology
Network Security Unit 5.pdf for BCA BBA.
sap open course for s4hana steps from ECC to s4
Profit Center Accounting in SAP S/4HANA, S4F28 Col11
Advanced methodologies resolving dimensionality complications for autism neur...
Architecting across the Boundaries of two Complex Domains - Healthcare & Tech...
Blue Purple Modern Animated Computer Science Presentation.pdf.pdf
MYSQL Presentation for SQL database connectivity
Reach Out and Touch Someone: Haptics and Empathic Computing
NewMind AI Weekly Chronicles - August'25 Week I
KodekX | Application Modernization Development
Electronic commerce courselecture one. Pdf
The Rise and Fall of 3GPP – Time for a Sabbatical?
Optimiser vos workloads AI/ML sur Amazon EC2 et AWS Graviton
7 ChatGPT Prompts to Help You Define Your Ideal Customer Profile.pdf

Cooking Perl with Chef

  • 1. Cooking Perl with Chef David Golden @xdg http://perlchef.com/ July 2012
  • 2. Configuration Management (e.g. chef, puppet, cfengine, ...)
  • 3. Unknown state ↓ Target state
  • 4. New machine ↓ Deployed app
  • 5. Infrastructure as code automated! repeatable! testable! (no manual steps, checklist, etc.)
  • 6. One tool to deploy the whole stack (DB, caching, messaging, ...)
  • 7. But wait! Isn't that hard to do for Perl apps?
  • 10. App = perl + CPAN + your code
  • 11. CHI DateTime DBI JSON App = perl + CPAN + your code Moose Plack POE Try::Tiny ...
  • 12. CHI DateTime DBI JSON App = perl + CPAN + your code Moose Plack POE Try::Tiny ... your application is the versioned set of all its compontents
  • 13. CHI DateTime DBI JSON App v1.0.0 = perl + CPAN + your code Moose Plack POE Try::Tiny ... your application is the versioned set of all its compontents
  • 14. CHI DateTime DBI JSON App v1.0.0 = Perl + CPAN + your code v5.14.2 Moose Plack POE Try::Tiny ... your application is the versioned set of all its compontents
  • 15. 0.55 0.76 1.622 2.53 App v1.0.0 = Perl + CPAN + your code v5.14.2 2.0603 0.9989 1.354 0.11 ... your application is the versioned set of all its compontents
  • 16. 0.55 0.76 1.622 2.53 App v1.0.0 = Perl + CPAN + your code v5.14.2 v1.0 2.0603 0.9989 1.354 0.11 ... your application is the versioned set of all its compontents
  • 17. 0.55 0.76 1.622 2.53 App v1.0.0 = Perl + CPAN + your code v5.14.2 v1.0 2.0603 0.9989 1.354 0.11 ... change one piece...
  • 18. 0.55 0.76 1.622 2.53 App v1.0.0 = Perl + CPAN + your code v5.16.0 v1.0 2.0603 0.9989 1.354 0.11 ... change one piece...
  • 19. 0.55 0.76 1.622 2.53 App v1.0.1 = Perl + CPAN + your code v5.16.0 v1.02.0603 0.9989 1.354 0.11 ... … and you have a new version of your application
  • 21. Repeatable deployment means... ... the same Perl
  • 22. Repeatable deployment means... ... the same Perl ... the same modules
  • 23. Repeatable deployment means... ... the same Perl ... the same modules ... the same code
  • 24. Repeatable deployment means... ... the same Perl ... the same modules ... the same code ... on demand
  • 26. If we have the right tools
  • 27. Use one-size fits all distribution packagers like apt, yum, etc...? (How much do you like your system perl?!)
  • 28. This problem is not unique to Perl
  • 29. Let's be inspired by Larry
  • 37. Chef ❤ Ruby (written in ruby; various ruby app stacks)
  • 38. Chef ❤ Python (virtualenv; pip; django apps)
  • 40. python → virtualenv + pip ruby → rvm + Bundler
  • 41. We've built tools like these, too
  • 42. Kang-min Liu (gugod) Matt S Trout (mst) Tatsuhiko Miyagawa (and a big community helping them)
  • 43. perlbrew – multiple perl manager Matt S Trout (mst) Tatsuhiko Miyagawa (and a big community helping them)
  • 44. perlbrew – multiple perl manager local::lib – custom @INC manager Tatsuhiko Miyagawa (and a big community helping them)
  • 45. perlbrew – multiple perl manager local::lib – custom @INC manager carton – versioned dependency installer (and a big community helping them)
  • 46. So we have the pieces
  • 48. Repeatable deployment in five parts application-specific Perl application-specific @INC path versioned application code versioned module dependencies automate the previous four
  • 49. Repeatable deployment in five parts perlbrew application-specific @INC path versioned application code versioned module dependencies automate the previous four
  • 50. Repeatable deployment in five parts perlbrew local::lib versioned application code versioned module dependencies automate the previous four
  • 51. Repeatable deployment in five parts perlbrew local::lib git versioned module dependencies automate the previous four
  • 52. Repeatable deployment in five parts perlbrew local::lib git carton automate the previous four
  • 53. Repeatable deployment in five parts perlbrew local::lib git carton @&$%!
  • 55. No support in Chef...
  • 58. (After I learned some Ruby)
  • 59. Now... Chef ❤ Perl (perlbrew; local::lib; carton)
  • 60. Time for a quick Chef glossary... (see http://wiki.opscode.com/)
  • 61. “Cookbook” A collection of components to configure a particular application Typically includes recipes, providers, templates, etc. (CPAN analogy → “distribution”)
  • 62. “Recipe” Component applied that deploys an application or service Typically declarative, specifying desired resources and associated configuration
  • 63. “Resource” An abstraction of something to be deployed
  • 65. “Node” A host computer managed with Chef Often means the configuration file that defines recipes, attributes and roles that define the target state of a host
  • 66. “Attribute” A variable used in a recipe and/or provider that customizes the configuration of a resource Attributes have defaults, but can be customized for nodes or roles
  • 67. “Role” A collection of recipes and attributes used to apply common configuration across multiple nodes
  • 68. Summary... cookbooks include recipes and providers roles, recipes and attributes get applied to nodes recipes specify desired resources and customize them with attributes providers do the work of deploying resources
  • 69. I wrote two Perl Chef cookbooks for the Chef community repository (which is like CPAN circa 1996 or so) http://community.opscode.com/
  • 70. 1. perlbrew – for managing perls 2. carton – for deploying apps Also available here: https://github.com/dagolden/perl-chef
  • 71. perlbrew cookbook resources: perlbrew_perl – install a perl perlbrew_lib – create a local::lib perlbrew_cpanm – install modules to perl or lib perlbrew_run – run shell commands under a particular perlbrew and/or lib
  • 72. carton cookbook resource: carton_app – deploy an app with carton – start in directory with the app source – configure for a specific perlbrew perl – install versioned dependencies with carton – create a runit service for the app – start the app
  • 73. Time for an example: Deploying a “Hello World” Plack app https://github.com/dagolden/zzz-hello-world
  • 74. Steps for creating Hello World 1. Write the application 2. Use carton to create a carton.lock file with versioned dependency info 3. Write a simple cookbook for the application 4. Check it all into git 5. Deploy the application with Chef
  • 75. $ tree . ├── Changes ├── Makefile.PL ├── app.psgi ├── carton.lock ├── cookbook │ └── hello-world │ ├── README.md │ ├── attributes │ │ └── default.rb │ ├── metadata.rb │ └── recipes │ └── default.rb └── lib └── ZZZ └── Hello └── World.pm
  • 76. $ tree . ├── Changes ├── Makefile.PL ├── app.psgi ├── carton.lock ├── cookbook │ └── hello-world │ ├── README.md │ ├── attributes │ │ └── default.rb │ ├── metadata.rb │ └── recipes │ └── default.rb └── lib └── ZZZ └── Hello └── World.pm
  • 77. use strict; use warnings; use ZZZ::Hello::World; my $app = sub { ZZZ::Hello::World->run_psgi(@_) }; (this Plack app just invokes a simple module)
  • 78. $ tree . ├── Changes ├── Makefile.PL ├── app.psgi ├── carton.lock ├── cookbook │ └── hello-world │ ├── README.md │ ├── attributes │ │ └── default.rb │ ├── metadata.rb │ └── recipes │ └── default.rb └── lib └── ZZZ └── Hello └── World.pm
  • 79. use 5.008001; use strict; use warnings; package ZZZ::Hello::World; our $VERSION = "1.0"; use Plack::Request; sub run_psgi { my $self = shift; my $req = Plack::Request->new(shift); my $res = $req->new_response(200); $res->content_type('text/html'); $res->body(<<"HERE"); <html> <head><title>Hello World</title></head> <body> <p>Hello World. It is @{[scalar localtime]}</p> ... </body> </html> HERE return $res->finalize; } 1; (the module just returns some dynamic HTML)
  • 80. $ tree . ├── Changes ├── Makefile.PL ├── app.psgi ├── carton.lock ├── cookbook │ └── hello-world │ ├── README.md │ ├── attributes │ │ └── default.rb │ ├── metadata.rb │ └── recipes │ └── default.rb └── lib └── ZZZ └── Hello └── World.pm
  • 81. use inc::Module::Install; name 'ZZZ-Hello-World'; version '1.0'; requires 'Plack'; requires 'Starman'; WriteAll; (the Makefile.PL also includes deployment dependencies like Starman)
  • 82. During development, carton installs dependencies locally and creates a versioned dependency file called carton.lock $ carton install # installs dependencies into a local directory # creates carton.lock if it doesn't exist # carton.lock is a JSON file of dependency info
  • 83. During deployment, carton installs dependencies from carton.lock and runs the app with them $ carton install # installs dependencies into a local directory $ carton exec ­Ilib ­­ starman ­p 8080 app.psgi # runs the app using carton installed deps
  • 84. $ tree . ├── Changes ├── Makefile.PL ├── app.psgi ├── carton.lock ├── cookbook │ └── hello-world │ ├── README.md │ ├── attributes │ │ └── default.rb │ ├── metadata.rb │ └── recipes │ └── default.rb └── lib └── ZZZ └── Hello └── World.pm
  • 85. # carton.lock JSON { "modules" : { "Class::Inspector" : { "dist" : "Class-Inspector-1.27", "module" : "Class::Inspector", "pathname" : "A/AD/ADAMK/Class-Inspector-1.27.tar.gz", ... }. "Data::Dump" : { ... }, "Devel::StackTrace" : { ... }, "Encode::Locale" : { ... }, ... } (carton.lock associates module names to specific versions of those module)
  • 86. $ tree . ├── Changes ├── Makefile.PL ├── app.psgi ├── carton.lock ├── cookbook │ └── hello-world │ ├── README.md │ ├── attributes │ │ └── default.rb │ ├── metadata.rb │ └── recipes │ └── default.rb └── lib └── ZZZ └── Hello └── World.pm
  • 87. # perlbrew to execute with default['hello-world']['perl_version'] = 'perl-5.16.0' # Install directory, repo and tag default['hello-world']['deploy_dir'] = '/opt/hello-world' default['hello-world']['deploy_repo'] = 'https://github.com/dagolden/zzz-hello-world.git' default['hello-world']['deploy_tag'] = 'master' # Service user/group/port default['hello-world']['user'] = "nobody" default['hello-world']['group'] = "nogroup" default['hello-world']['port'] = 8080 (attributes are variables used in the recipe; can be customized per-node during deployment)
  • 88. $ tree . ├── Changes ├── Makefile.PL ├── app.psgi ├── carton.lock ├── cookbook │ └── hello-world │ ├── README.md │ ├── attributes │ │ └── default.rb │ ├── metadata.rb │ └── recipes │ └── default.rb └── lib └── ZZZ └── Hello └── World.pm
  • 89. include_recipe 'carton' package 'git-core' git node['hello-world']['deploy_dir'] do repository node['hello-world']['deploy_repo'] reference node['hello-world']['deploy_tag'] notifies :restart, "carton_app[hello-world]" end carton_app "hello-world" do perlbrew node['hello-world']['perl_version'] command "starman -p #{node['hello-world']['port']} app.psgi" cwd node['hello-world']['deploy_dir'] user node['hello-world']['user'] group node['hello-world']['group'] end carton_app "hello-world" do action :start end (recipe ensures carton and git are available...)
  • 90. include_recipe 'carton' package 'git-core' git node['hello-world']['deploy_dir'] do repository node['hello-world']['deploy_repo'] reference node['hello-world']['deploy_tag'] notifies :restart, "carton_app[hello-world]" end carton_app "hello-world" do perlbrew node['hello-world']['perl_version'] command "starman -p #{node['hello-world']['port']} app.psgi" cwd node['hello-world']['deploy_dir'] user node['hello-world']['user'] group node['hello-world']['group'] end carton_app "hello-world" do action :start end (git resource specifies where application code goes...)
  • 91. include_recipe 'carton' package 'git-core' git node['hello-world']['deploy_dir'] do repository node['hello-world']['deploy_repo'] reference node['hello-world']['deploy_tag'] notifies :restart, "carton_app[hello-world]" end carton_app "hello-world" do perlbrew node['hello-world']['perl_version'] command "starman -p #{node['hello-world']['port']} app.psgi" cwd node['hello-world']['deploy_dir'] user node['hello-world']['user'] group node['hello-world']['group'] end carton_app "hello-world" do action :start end (attributes parameterize the resource statement...)
  • 92. include_recipe 'carton' package 'git-core' git node['hello-world']['deploy_dir'] do repository node['hello-world']['deploy_repo'] reference node['hello-world']['deploy_tag'] notifies :restart, "carton_app[hello-world]" end carton_app "hello-world" do perlbrew node['hello-world']['perl_version'] command "starman -p #{node['hello-world']['port']} app.psgi" cwd node['hello-world']['deploy_dir'] user node['hello-world']['user'] group node['hello-world']['group'] end carton_app "hello-world" do action :start end (carton_app resources installs deps and sets up runit service...)
  • 93. include_recipe 'carton' package 'git-core' git node['hello-world']['deploy_dir'] do repository node['hello-world']['deploy_repo'] reference node['hello-world']['deploy_tag'] notifies :restart, "carton_app[hello-world]" end carton_app "hello-world" do perlbrew node['hello-world']['perl_version'] command "starman -p #{node['hello-world']['port']} app.psgi" cwd node['hello-world']['deploy_dir'] user node['hello-world']['user'] group node['hello-world']['group'] end carton_app "hello-world" do action :start end (again, attributes parameterize the resource...)
  • 94. include_recipe 'carton' package 'git-core' git node['hello-world']['deploy_dir'] do repository node['hello-world']['deploy_repo'] reference node['hello-world']['deploy_tag'] notifies :restart, "carton_app[hello-world]" end carton_app "hello-world" do perlbrew node['hello-world']['perl_version'] command "starman -p #{node['hello-world']['port']} app.psgi" cwd node['hello-world']['deploy_dir'] user node['hello-world']['user'] group node['hello-world']['group'] end carton_app "hello-world" do action :start end (finally, the resource is idempotently started...)
  • 95. These files – and the Perl Chef cookbooks – are all you need
  • 96. Enough code... let's see how to deploy it
  • 97. Steps for deployment of Hello World 1. Set up a Vagrant virtual machine 2. Prepare Pantry to manage Chef Solo 3. Get Hello World cookbook and dependencies 4. Configure virtual machine for Hello World 5. Deploy
  • 98. Steps for deployment of Hello World 1. Set up a Vagrant virtual machine 2. Prepare Pantry to manage Chef Solo 3. Get Hello World cookbook and dependencies 4. Configure virtual machine for Hello World 5. Deploy
  • 100. Vagrant is a tool for managing virtual machines “Can I have a VirtualBox now, please?”
  • 101. Vagrant is a tool for managing virtual machines $ vagrant box add base http://files.vagrantup.com/lucid32.box $ vagrant init $ vagrant up
  • 102. Vagrant is great for testing Chef deployment (and other things, besides)
  • 103. Steps for deployment of Hello World 1. Set up a Vagrant virtual machine 2. Prepare Pantry to manage Chef Solo 3. Get Hello World cookbook and dependencies 4. Configure virtual machine for Hello World 5. Deploy
  • 104. Chef Solo is Chef without a central configuration server (good for demos and smaller deployments)
  • 105. Chef – you push config data to Chef Server – nodes run Chef Client to pull config from Chef Server and execute it Chef Solo – you push config data to nodes – you run Chef Solo remotely
  • 107. One advantage of Chef Solo... Your config repo is canonical (i.e. you don't have to track what you've pushed to the central server)
  • 108. One dis-advantage of Chef Solo... Manual rsync/ssh required (yuck!)
  • 109. Steps for deployment of Hello World 1. Set up a Vagrant virtual machine 2. Prepare Pantry to manage Chef Solo 3. Get Hello World cookbook and dependencies 4. Configure virtual machine for Hello World 5. Deploy
  • 110. Pantry is a tool for automating Chef Solo
  • 111. Pantry is a tool for automating Chef Solo $ pantry create node server.example.com $ pantry apply node server.example.com --role web --recipe myapp $ pantry sync node server.example.com
  • 112. Pantry is written in Perl and available on CPAN (Similar to pocketknife [Ruby] and littlechef [Python])
  • 113. Finally, a demonstration... Screencast available at http://youtu.be/H93rt-KtwBE
  • 114. Steps for deployment of Hello World 1. Set up a Vagrant virtual machine 2. Prepare Pantry to manage Chef Solo 3. Get Hello World cookbook and dependencies 4. Configure virtual machine for Hello World 5. Deploy
  • 116. Steps for deployment of Hello World 1. Set up a Vagrant virtual machine 2. Prepare Pantry to manage Chef Solo 3. Get Hello World cookbook and dependencies 4. Configure virtual machine for Hello World 5. Deploy
  • 118. Steps for deployment of Hello World 1. Set up a Vagrant virtual machine 2. Prepare Pantry to manage Chef Solo 3. Get Hello World cookbook and dependencies 4. Configure virtual machine for Hello World 5. Deploy
  • 119. Four cookbooks must be downloaded and copied to the 'cookbooks' directory – hello-world – carton – perlbrew – runit
  • 120. Steps for deployment of Hello World 1. Set up a Vagrant virtual machine 2. Prepare Pantry to manage Chef Solo 3. Get Hello World cookbook and dependencies 4. Configure virtual machine for Hello World 5. Deploy
  • 122. Steps for deployment of Hello World 1. Set up a Vagrant virtual machine 2. Prepare Pantry to manage Chef Solo 3. Get Hello World cookbook and dependencies 4. Configure virtual machine for Hello World 5. Deploy
  • 125. You can do this, too
  • 126. Don't be afraid. Try it out. Get involved. tutorial and screencast → http://perlchef.com mailing list → perl-devops-subscribe@perl.org