Reliable and scalable applications need repeatable, automated application deployment. Configuration management tools like Chef, Puppet and others make it easy to deploy an entire application stack, but support for Perl applications has lagged behind other popular, dynamic languages.
The Perl community has responded to these challenges with tools like perlbrew, local::lib, carton and others to make it easier to manage an application and its dependencies in isolation. This presentation will show you how to make those tools work with Chef for complete automation of Perl application deployment.
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
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
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
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
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
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)
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
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)
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
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
99.
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
106.
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)
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
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])
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