-
Notifications
You must be signed in to change notification settings - Fork 0
/
chef-solo-quick-and-easy-cooking-for-one.html
213 lines (171 loc) · 9.68 KB
/
chef-solo-quick-and-easy-cooking-for-one.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
<!DOCTYPE html>
<!--[if lt IE 7]> <html class="no-js lt-ie9 lt-ie8 lt-ie7"> <![endif]-->
<!--[if IE 7]> <html class="no-js lt-ie9 lt-ie8"> <![endif]-->
<!--[if IE 8]> <html class="no-js lt-ie9"> <![endif]-->
<!--[if gt IE 8]><!--> <html class="no-js"> <!--<![endif]-->
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>Chef Solo: Quick and easy cooking for one ← Vinicius Horewicz</title>
<meta name="viewport" content="width=device-width">
<meta name="author" content="Vinicius Horewicz (wicz)">
<meta name="description" content="wicz' personal notes">
<link rel="alternate" type="application/atom+xml" href="/atom.xml" title="RSS feed" />
<link rel="stylesheet" href="/assets/stylesheets/normalize.css">
<link rel="stylesheet" href="/assets/stylesheets/monokai.css">
<link rel="stylesheet" href="/assets/stylesheets/main.css">
<link rel="stylesheet" href="/assets/stylesheets/screen.css">
<link href="//netdna.bootstrapcdn.com/font-awesome/4.0.0/css/font-awesome.css" rel="stylesheet">
<link href="//fonts.googleapis.com/css?family=Roboto:400,300,300italic|Roboto+Slab:300|Ubuntu+Mono" rel="stylesheet" type="text/css">
<script src="/assets/javascripts/modernizr-2.6.2.min.js"></script>
</head>
<body>
<div class="container">
<p><a href="/">← index</a></p>
<section class="post-content">
<header>
<h1>Chef Solo: Quick and easy cooking for one</h1>
<time datetime="2013-04-27T00:00:00+02:00" pubdate>27 April 2013</time>
</header>
<article>
<p>Chef is a configuration management tool. It allows us to manage and
automate servers configurations. It uses a Ruby DSL for writing
blueprints—called recipes—that defines actions to be taken on the
remote servers, e.g. install apache.</p>
<p>The <a href="http://docs.opscode.com/">Chef ecosystem</a> is immense. Servers,
nodes, workstations, agents, cookbooks; myriad of concepts. In this
article I will just scratch the surface and present examples to get you
running as quick as possible.</p>
<h3 id="about-chef">About Chef</h3>
<p>In a full Chef organization there must exist a <em>Chef server</em> that stores
configuration details of each server—or <em>node</em>—in the infrastructure.
Developers/users write <em>cookbooks</em> (and <em>recipes</em>) locally on their
<em>workstations</em>, and store the former in a <em>Chef repository</em>. Eventually,
users use the <em>knife</em> command to upload data from the local Chef
repository to the Chef server.</p>
<p>When running a small-sized infrastructure, chances are you do not need
or want to setup a full Chef organization. Luckly, Chef provides a
slimmer version called <em>chef-solo</em>, which allows configuring nodes
without the need of a Chef server.</p>
<p>There is a knife plugin called
<a href="http://matschaffer.github.io/knife-solo/">knife-solo</a>, that makes
working with chef-solo easier and as powerful as with a Chef server.</p>
<h3 id="set-up-your-kitchen">Set up your kitchen</h3>
<p>To keep everything organized, create a new project (git repo) and add
<code>knife-solo</code> to the <code>Gemfile</code>.</p>
<div class="highlight"><pre><code class="language-console"><span class="gp">$</span> git init chef-cookbooks
<span class="gp">$</span> <span class="nb">cd </span>chef-cookbooks
<span class="gp">$</span> bundle install --path vendor/bundle --binstubs</code></pre></div>
<p>Create a basic <code>knife</code> configuration. Knife uses a RSA key pair to
authenticate requests to the Chef Server. Even though you will not have
one, knife still needs this client key. Create one using <code>ssh-keygen</code>.
Ultimately, initialize your kitchen. Make sure to enable
<a href="https://github.com/applicationsonline/librarian-chef">Librarian</a> to
help you manage your cookbooks dependencies.</p>
<div class="highlight"><pre><code class="language-console"><span class="gp">$</span> bin/knife configure --defaults
<span class="gp">$</span> ssh-keygen -f ~/.chef/<span class="nv">$USER</span>.pem
<span class="gp">$</span> bin/knife solo init kitchen --librarian</code></pre></div>
<h3 id="managing-cookbooks">Managing cookbooks</h3>
<p>We will create a cookbook to install ruby using rbenv. Add the rbenv
cookbook to the Librarians <code>Cheffile</code>. The dependencies will be
installed in the <code>cookbooks</code> directory. There is no need to keep track
of these files in your repository. Create your own cookbooks in the
<code>site-cookbooks</code> directory.</p>
<div class="highlight"><pre><code class="language-ruby"><span class="c1"># Cheffile</span>
<span class="n">site</span> <span class="s2">"http://community.opscode.com/api/v1"</span>
<span class="n">cookbook</span> <span class="s2">"rbenv"</span><span class="p">,</span> <span class="ss">git</span><span class="p">:</span> <span class="s2">"https://github.com/RiotGames/rbenv-cookbook"</span></code></pre></div>
<div class="highlight"><pre><code class="language-console"><span class="gp">$</span> <span class="nb">cd </span>kitchen
<span class="gp">$</span> ../bin/librarian-chef install
<span class="gp">$</span> ../bin/knife cookbook create ruby -o site-cookbooks</code></pre></div>
<p>I will cover the creation of cookbooks in another article. For now,
will create the bare minimum to continue our example. Following the
<a href="https://github.com/RiotGames/rbenv-cookbook">rbenv-cookbook</a>
documentation, add the rbenv dependency to your cookbook <code>metadata.rb</code>
and in the default recipe use the <code>rbenv_ruby</code> command—aka lightweight
resource and provider (LWRP).</p>
<div class="highlight"><pre><code class="language-ruby"><span class="c1"># kitchen/site-cookbooks/ruby/metadata.rb</span>
<span class="n">depends</span> <span class="s2">"rbenv"</span>
<span class="c1"># kitchen/site-cookbooks/ruby/recipes/default.rb</span>
<span class="n">include_recipe</span> <span class="s2">"rbenv::default"</span>
<span class="n">include_recipe</span> <span class="s2">"rbenv::ruby_build"</span>
<span class="n">rbenv_ruby</span> <span class="s2">"1.9.3-p392"</span> <span class="k">do</span>
<span class="n">global</span> <span class="kp">true</span>
<span class="k">end</span></code></pre></div>
<h3 id="setup-node-and-cook">Setup node and cook</h3>
<p>I like to configure my servers in my SSH client in a way that is easy
to remember and use. Suppose I am working on a project called
PetProject (pp) and I have three EC2 instances: web, app and db. My
configuration looks like this:</p>
<div class="highlight"><pre><code># ~/.ssh/config
Host pp.*
User ubuntu
IdentityFile ~/.ssh/petproject.com/ubuntu
Host pp.web
HostName ec2-54-215-126-10.sa-east-1.compute.amazonaws.com
Host pp.app
HostName ec2-54-215-126-11.sa-east-1.compute.amazonaws.com
Host pp.db
HostName ec2-54-215-126-12.sa-east-1.compute.amazonaws.com
</code></pre></div>
<p>Now I can easily <code>ssh pp.web</code> to connect to my web server. No need to
remember IP addresses, DNS names, user names or passwords.</p>
<p>Use knife-solo to prepare your server. It will install in the server
all dependencies Chef requires, and will create a local configuration
file for this server in <code>nodes/<hostname>.json</code>.</p>
<p>Add your recipe to the <code>run_list</code> in the JSON file and <em>cook</em> your
server.</p>
<div class="highlight"><pre><code class="language-console"><span class="gp">$</span> ../bin/knife solo prepare pp.app
<span class="gp">#</span> edit nodes/pp.app.json as shown below
<span class="gp">$</span> ../bin/knife solo cook pp.app</code></pre></div>
<div class="highlight"><pre><code class="language-json"><span class="err">#</span> <span class="err">kitchen/nodes/pp.app.json</span>
<span class="p">{</span><span class="nt">"run_list"</span><span class="p">:[</span><span class="s2">"recipe[ruby]"</span><span class="p">]}</span></code></pre></div>
<p>Finally, you have got yourself a brand new server with the latest Ruby
1.9.3 installed on it. Even better, now you have an automated task for
it. In case you need to setup an <code>app02</code> server, all you need is
<em>prepare</em> and <em>cook</em> it and you are ready to go.</p>
</article>
</section>
<!-- Enable Disqus comments -->
<div id="disqus_thread"></div>
<script type="text/javascript">
var disqus_shortname = 'horewicz';
var disqus_identifier = '/chef-solo-quick-and-easy-cooking-for-one';
var disqus_url = 'http://horewi.cz/chef-solo-quick-and-easy-cooking-for-one.html';
(function() {
var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true;
dsq.src = 'http://' + disqus_shortname + '.disqus.com/embed.js';
(document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
})();
</script>
<footer>
<a href="about.html">
<i class="fa fa-info-circle fa-fw fa-lg"></i>
</a>
<a href="https://www.linkedin.com/in/viniciushorewicz">
<i class="fa fa-l1nkedin fa-fw fa-lg"></i>
</a>
<a href="https://github.com/wicz">
<i class="fa fa-github fa-fw fa-lg"></i>
</a>
<a href="https://twitter.com/wicz">
<i class="fa fa-tw1tter fa-fw fa-lg"></i>
</a>
<a href="https://stackoverflow.com/users/3243455/wicz">
<i class="fa fa-stack-overflow fa-fw fa-lg"></i>
</a>
<a href="/assets/wicz.pub.asc">
<i class="fa fa-lock fa-fw fa-lg"></i>
</a>
<a href="/atom.xml">
<i class="fa fa-rss fa-fw fa-lg"></i>
</a>
</footer>
</div>
<script type="text/javascript">
var _gaq=[['_setAccount','UA-8480243-3'],['_trackPageview']];
(function(d,t){var g=d.createElement(t),s=d.getElementsByTagName(t)[0];
g.src=('https:'==location.protocol?'//ssl':'//www')+'.google-analytics.com/ga.js';
s.parentNode.insertBefore(g,s)}(document,'script'));
</script>
</body>
</html>