chef-tutorial.scrbl 48.1 KB
Newer Older
1 2 3 4
#lang scribble/manual

@(require "defs.rkt")

5
@title[#:tag "chef-tutorial" #:version apt-version]{@(tb) Chef Tutorial}
6

7 8
This tutorial will walk you through the process of creating and using
an instance of the Chef configuration management system on @(tb).
9

10 11 12 13 14 15 16 17
@not-clab{
Since this tutorial was originally developed for CloudLab,
you will find the screenshots below that have the CloudLab name and logo in
them. When you use @(tb) to build Chef, the process is exactly the same;
the only difference is that you will see the @(tb) name and logo instead in the portal pages you will open and use.
}

@margin-note{Chef is both the name of a company and the name of a popular modern configuration management system
18
written in Ruby and Erlang. A large variety of tutorials, articles, technical docs and training opportunities
19
is available at the @link["https://learn.chef.io/"]{Chef official website}.
20 21 22 23 24 25 26 27 28
Also, refer to the @link["https://www.chef.io/customers/"]{Customer Stories} page to see how Chef is used
in production environments, including very large installations (e.g., at Facebook, Bloomberg, and Yahoo!).}

@section{Objectives}

In the process of taking this tutorial, you will learn to:

@itemlist[
    @item{Create your own instance of Chef using a pre-defined profile}
29
    @item{Explore profile parameters allowing to customize components of your Chef deployments}
30
    @item{Access monitoring and management capabilities provided by Chef}
Dmitry Duplyakin's avatar
Dmitry Duplyakin committed
31 32 33 34 35 36 37
    @item{Use Chef to perform two exercises:
      @itemlist[
        @item{Install and configure NFS, the Network File System, on experiment nodes}
        @item{Install and configure an instance of the Apache web server, as well as run a benchmark against it}
      ]
    }
    @item{Terminate your experiment}
38 39 40
    @item{Learn where to get more information}
]

Dmitry Duplyakin's avatar
Dmitry Duplyakin committed
41 42 43
@section{Motivation}

This tutorial will demonstrate how experiments can be managed on @(tb), as well as show
44
how experiment resources can be administered using Chef.
45
By following the instructions provided below, you will learn how to take advantage of the powerful features of Chef
Dmitry Duplyakin's avatar
Dmitry Duplyakin committed
46
for configuring multi-node software environments.
47 48 49 50
The exercises included in this tutorial are built around simple but realistic
configurations. In the process of recreating these configurations on nodes running
default images, you will explore individual components of Chef and
follow the configuration management workflow applicable to more complex configurations and experiments.
Dmitry Duplyakin's avatar
Dmitry Duplyakin committed
51

52 53 54 55 56 57
@section{Prerequisites}

This tutorial assumes that:

@itemlist[
    @item{You have an existing account on @bold{either}: @itemlist[
58
        @item{@(tb) (Instructions for getting an account can
59 60 61 62 63 64 65
            be found @seclink["register"]{here}.)}
        @item{The @link["https://portal.geni.net"]{GENI portal}.
            (Instructions for getting an account can be found
        @link["http://groups.geni.net/geni/wiki/SignMeUp"]{here}.)}
        ]}
]

Dmitry Duplyakin's avatar
Dmitry Duplyakin committed
66 67
@include-section["tutorial-login-common.scrbl"]

68
@section[#:tag "chef-tutorial-body"]{Launching Chef Experiments}
69 70 71 72 73 74 75 76 77 78 79 80 81 82 83

Once you have logged in to @(tb), you will ``instantiate'' a @seclink["profiles"]{``profile''}
to create an @seclink["experiments"]{experiment}. (An experiment in @(tb) is similar
to a @link["http://groups.geni.net/geni/wiki/GENIConcepts#Slice"]{``slice''} in
GENI.) Profiles are @(tb)'s way of packaging up configurations and experiments
so that they can be shared with others. Each experiment is separate:
the experiment that you create for this tutorial will be an instance of a profile provided by
the facility, but running on resources that are dedicated to you, which you
have complete control over. This profile uses local disk space on the nodes, so
anything you store there will be lost when the experiment terminates.

@margin-note{The Chef cluster we are building in this tutorial is very small, but @(tb)
has @seclink["hardware"]{large clusters} that can be used for larger-scale
experiments.}

84 85 86
For this tutorial, we will use a profile that launches a Chef cluster --- a set of
interconnected nodes running Chef components such as Chef server, workstation, clients.
The @(tb) staff have built this profile by scripting installation procedures for
Dmitry Duplyakin's avatar
Dmitry Duplyakin committed
87
these components. The developed scripts will run on the experiment nodes after they boot
88
and customize them (create necessary user accounts, install packages, establish authentication
89
between the nodes, etc.) to create a fully functional Chef cluster with a
90 91 92 93 94 95
multi-node, production-like structure.

See this manual's @seclink["profiles"]{section on profiles} for more
information about how they work.

@itemlist[#:style 'ordered
96 97 98 99 100 101 102 103 104 105

    @instructionstep["Start Experiment"]{
        @clab-screenshot["tutorial/start-experiment-menu.png"]

        After logging in, you are taken to your main status
        @link[@apt-url["user-dashboard.php"]]{dashboard}.
        Select ``Start Experiment'' from
        the ``Experiments'' menu.
    }

106 107
    @instructionstep["Select a profile"]{

108
        By default, the ``Start an Experiment'' page suggests launching the OpenStack profile which
109
        is discribed in detail in the @seclink["openstack-tutorial"]{OpenStack tutorial}.
110

111 112 113
        Go to the list of available profile by clicking ``Change Profile'':

        @clab-screenshot["chef-tutorial/change-profile.png"]
114

Dmitry Duplyakin's avatar
Dmitry Duplyakin committed
115
        Find the profile by typing @bold{ChefCluster} in the search bar. Then, select the profile with the
116 117 118 119 120
        specified name in the list displayed below the search bar.
        A 2-node preview should now be shown along with high-level profile information.
        Click ``Select Profile'' at the bottom of the page:

        @clab-screenshot["chef-tutorial/find-chefcluster.png"]
121

Dmitry Duplyakin's avatar
Dmitry Duplyakin committed
122
        After you select the correct profile, click ``Next'':
123

124
        @clab-screenshot["chef-tutorial/instantiate-next.png"]
125 126 127
    }

    @instructionstep["Set parameters"
128 129
                     #:screenshot "chef-tutorial/params-next.png"
                     #:screenshot-where "clab"]{
130

131
    Profiles in @(tb) can have @emph{parameters} that affect how they are
132
    configured; for example, this profile has parameters that allow you to
Dmitry Duplyakin's avatar
Dmitry Duplyakin committed
133
    set the number of client nodes, specify the repository with the infrastructure
134 135
    code we plan to use, obtain copies of the application-specific infrastructure code developed
    by the global community of Chef developers, etc.
136 137 138

    For this tutorial, we will leave all parameters at their defaults and
    just click ``Next''.
139 140
    }

141
    @instructionstep["Choose experiment name"]{
142

Dmitry Duplyakin's avatar
Dmitry Duplyakin committed
143 144
        You may optionally give your experiment a meaningful name, e.g., ``chefdemo''.
        This is useful if you have many experiments running at once.
145 146

        @clab-screenshot["chef-tutorial/experiment-name.png"]
147 148 149 150
    }


    @instructionstep["Select a cluster"
151 152
                     #:screenshot "chef-tutorial/select-cluster.png"
                     #:screenshot-where "clab"]{
153 154
        @(tb) has multiple clusters available to it. Some profiles can run
        on any cluster, some can only run on specific ones due to specific hardware
Dmitry Duplyakin's avatar
Dmitry Duplyakin committed
155
        constraints. @bold{ChefCluster} can only run on the x86-based clusters.
156
        This excludes the @(tb) Utah cluster which is built on ARMv8 nodes.
157 158 159 160 161 162 163 164 165 166 167 168
        Refer to the @seclink["hardware"]{Hardware} section for more information.

        @bold{Note:} If you are at an in-person tutorial, the instructor will
        tell you which cluster to select. Otherwise, you may select any compatible and available
        cluster.

        @margin-note{The dropdown menu for the clusters shows you both the
        health (outer ring) and available resources (inner dot) of each
        cluster. The ``Check Cluster Status'' link opens a page (in a new
        tab) showing the current utilization of all @(tb) clusters.}
    }

Dmitry Duplyakin's avatar
Dmitry Duplyakin committed
169 170
    @instructionstep["Click Finish!"]{
        When you click the ``Finish'' button, @(tb) will start
171 172 173 174
        provisioning the resources that you requested on the cluster that
        you selected.
    }

175
    @instructionstep["@(tb) instantiates your profile"]{
176 177 178 179
        @(tb) will take a few minutes to bring up your experiment, as
        many things happen at this stage, including selecting suitable
        hardware, loading disk images on local storage, booting bare-metal
        machines, re-configuring the network topology, etc. While this is
Dmitry Duplyakin's avatar
Dmitry Duplyakin committed
180
        happening, you will see the topology with yellow node icons:
181

182 183 184
        @clab-screenshot["chef-tutorial/booting.png"]

        @margin-note{Provisioning is done using the
185 186 187 188 189 190 191 192 193 194
        @link["http://groups.geni.net/geni/wiki/GeniApi"]{GENI APIs}; it
        is possible for advanced users to bypass the @(tb) portal and
        call these provisioning APIs from their own code. A good way to
        do this is to use the @link["https://geni-lib.readthedocs.org"]{@tt{geni-lib} library for Python.}}

        As soon as a set of resources have been assigned to you, you will see
        details about them if you switch to the "List View" tab (though you will not be
        able to log in until they have gone through the process of imaging and
        booting.) While you are waiting for your resources to become available,
        you may want to have a look at the
195
        @link[apt-doc-url]{@(tb)
196 197 198 199
        user manual}, or use the ``Sliver'' button to watch the logs of the
        resources (``slivers'') being provisioned and booting.
    }

Dmitry Duplyakin's avatar
Dmitry Duplyakin committed
200
    @instructionstep["Your resources are ready!"]{
201
         Shortly, the web interface will report the state as ``Booted''.
202 203 204

         @clab-screenshot["chef-tutorial/booted.png"]

205 206 207 208 209 210
         @bold{Important:} A ``Booted'' status indicates that resources are
         provisioned and booted; this particular profile runs scripts to
         complete the Chef setup, and it will be a few more minutes before
         Chef becomes fully functional. You will be able to tell that the configuration process
         has finished when the status changes from ``Booted'' to ``Ready''. Until then,
         you will likely see that the startup scripts (i.e. programs that run at the beginning
Dmitry Duplyakin's avatar
Dmitry Duplyakin committed
211 212
         of the experiment to set it up) run longer on @tt{head} than on
         @tt{node-0}  --- a lot more work is required to install the Chef server than the client.
213 214 215 216
         In the Topology View tab, mouse over the circle in the @tt{head}'s icon,
         to confirm the current state of the node.

         @clab-screenshot["chef-tutorial/head-running.png"]
217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234
    }
]

@section{Exploring Your Experiment}

While the startup scripts are still running,
you will have a few minutes to look at various parts
of the @(tb) experiment page and learn what resources you now have access to and what
you can do with them.

@subsection{Experiment Status}

The panel at the top of the page shows the status of your experiment --- you can
see which profile it was launched with, when it will expire, etc. The
buttons in this area let you make a copy of the profile (so that you can
@seclink["creating-profiles"]{customize it}), ask to hold on to the resources
for longer, or release them immediately.

235
@clab-screenshot["chef-tutorial/experiment-status.png"]
236 237 238 239 240 241 242 243 244 245 246 247 248 249 250

Note that the default lifetime for experiments on @(tb) is less than a day;
after this time, the resources will be reclaimed and their disk contents will
be lost. If you need to use them for longer, you can use the ``Extend'' button
and provide a description of why they are needed. Longer extensions require
higher levels of approval from @(tb) staff. You might also consider
@seclink["creating-profiles"]{creating a profile} of your own if you might need
to run a customized environment multiple times or want to share it with others.

You can click on the title of the panel to expand or collapse it.

@subsection{Profile Instructions}

Profiles may contain written instructions for their use. Clicking on the title
of the ``Profile Instructions'' panel will expand or collapse it. In this
251 252
case, the instructions provide a link to the Chef server web console.
(Don't click on the link yet --- it is likely that Chef is still being configured;
253 254
for now, let's keep exploring the @(tb) interface.)

Dmitry Duplyakin's avatar
Dmitry Duplyakin committed
255 256 257 258
Also, notice the list of private and public hostnames of the experiment nodes
included in the instructions. You will use the public hostnames (shown in bold)
in the exercise with the Apache web server and apache benchmark.

259
@clab-screenshot["chef-tutorial/experiment-instructions.png"]
260 261 262 263 264 265 266 267 268 269 270

@subsection{Topology View}

We have already used the topology viewer to see the node status; let's take a closer look
at the topology of this experiment. This
profile has two nodes connected by a 10 Gigabit LAN, which is represented by
a gray box in the middle of the topology. The names given for each node are
the names assigned as part of the profile; this way, every time you instantiate
a profile, you can refer to the nodes using the same names, regardless of which
physical hardware was assigned to them. The green boxes around each node
indicate that they are up; click the ``Refresh Status'' button to initiate a
271
fresh check.
272

273
@margin-note{You can also run several networking tests
274 275 276
by clicking the ``Run Linktest'' button at the bottom of the page. The available tests include:
@itemlist[
    @item{Level 1 --- Connectivity and Latency}
Dmitry Duplyakin's avatar
Dmitry Duplyakin committed
277
    @item{Level 2 --- Plus Static Routing}
278 279 280 281 282 283
    @item{Level 3 --- Plus Loss}
    @item{Level 4 --- Plus Bandwidth}
]
Higher levels will take longer to complete and require patience.
}

284
@clab-screenshot["chef-tutorial/topology-view.png"]
285 286

If an experiment has startup services, their statuses are indicated by small icons in
Dmitry Duplyakin's avatar
Dmitry Duplyakin committed
287
the upper right corners of the node icons. You can mouse over this icon to see a
288
description of the current status. In this profile, the startup services
Dmitry Duplyakin's avatar
Dmitry Duplyakin committed
289
on the client node(s), such as @tt{node-0}, typically complete quickly, but
290
the scripts on @tt{head} take much longer. The screenshot above shows the state of the
Dmitry Duplyakin's avatar
Dmitry Duplyakin committed
291
experiment when all startup scripts complete.
292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314

It is important to note that every node in @(tb) has at least two
network interfaces: one ``control network'' that carries public IP
connectivity, and one ``experiment network'' that is isolated from the Internet
and all other experiments. It is the experiment net that is shown in this
topology view.  You will use the control network to @(ssh) into your nodes,
interact with their web interfaces, etc. This separation gives you more
freedom and control in the private experiment network, and sets up a clean
environment for @seclink["repeatable-research"]{repeatable research}.


@subsection{List View}

The list view tab shows similar information to the topology view, but in a
different format. It shows the identities of the nodes you have been
assigned, and the full @(ssh) command lines to connect to them. In some
browsers (those that support the @tt{ssh://} URL scheme), you can click on the
SSH commands to automatically open a new session. On others, you may need to
cut and paste this command into a terminal window. Note that only public-key
authentication is supported, and you must have set up an @(ssh) keypair on your
account @bold{before} starting the experiment in order for authentication to
work.

315
@clab-screenshot["chef-tutorial/list-view.png"]
316 317 318 319 320 321 322 323

@subsection{Manifest View}

The final default tab shows a
@link["http://groups.geni.net/geni/wiki/GENIExperimenter/RSpecs#ManifestRSpec"]{manifest} detailing the hardware that has been assigned to you. This is the
@seclink["rspecs"]{``request'' RSpec} that is used to define the profile,
annotated with details of the hardware that was chosen to instantiate your
request. This information is available on the nodes themselves using the
324
@link["http://groups.geni.net/geni/wiki/GeniGet"]{@tt{geni-get}} command,
325 326 327 328 329 330
enabling you to do rich scripting that is fully aware of both the requested
topology and assigned resources.

@margin-note{Most of the information displayed on the @(tb) status page comes
directly from this manifest; it is parsed and laid out in-browser.}

331
@clab-screenshot["chef-tutorial/manifest-view.png"]
332

333
@subsection[#:tag "chef-tutorial-actions"]{Actions}
334 335 336 337 338 339 340 341

In both the topology and list views, you have access to several actions that
you may take on individual nodes. In the topology view, click on the node to
access this menu; in the list view, it is accessed through the icon in the
``Actions'' column. Available actions include rebooting (power cycling) a node,
and re-loading it with a fresh copy of its disk image (destroying all data on
the node).  While nodes are in the process of rebooting or re-imaging, they
will turn yellow in the topology view. When they have completed, they will
342
become green again. The @seclink["chef-tutorial-web-shell"]{shell}
Dmitry Duplyakin's avatar
Dmitry Duplyakin committed
343 344
action is described in more detail below and will be used as
the main method for issuing commands on the experiment nodes throughout this tutorial.
345

346
@clab-screenshot["chef-tutorial/experiment-actions.png"]
347 348 349

@section{Brief Introduction to Chef}

350
While the startup scripts are running, let's take a quick look at the architecture of a typical
351 352 353 354 355 356
Chef intallation. The diagram provided at the official @link["https://docs.chef.io/chef_overview.html"]{Overview of Chef} page
demonstrates the relationships between individual Chef components. While there is a number of optional, advanced
components that we don't use in this tutorial, it is worth noting the following:

@itemlist[
  @item{Chef clients can run on a variety of resources: virtual and physical servers, cloud instances,
357
  storage and networking devices, containers, etc. All clients connect and listen to
358 359
  the central, infrastructure-wide Chef server.}

360 361 362 363
  @item{The Chef server has a web interface. The server manages @bold{cookbooks}, which are fundamental
  units of configuration management that define configurations and contain
  everything that is required to instantiate those configurations. Additionally,
  the server manages @bold{run lists}, which can be viewed as mappings between collections of cookbooks
364 365 366
  and the clients on which they need to execute.}

  @item{A workstation represents a machine from which a Chef administrator
367
  connects to and controls the server. It typically has a copy of @bold{chef-repo},
368 369 370 371 372 373
  the repository which contains cookbooks and other code artifacts. The administrator
  modifies cookbooks locally and submits them to the server to make them available
  to all clients.}

  @item{@bold{Recipes}, shown next to cookbooks on the workstation, are the "building blocks" from which
  cookbooks are assembled. Recipes can be viewed as individual scripts accomplishing specific
374
  fine-grained tasks, such as create a user, install a package, clone a repository, configure a network interface, etc.
375
  Cookbooks, which include one or more recipes, are responsible for "bigger" tasks:
376
  install and configure a database, install and run a web server, and so on.}
377

Dmitry Duplyakin's avatar
Dmitry Duplyakin committed
378
  @item{Another type of Chef code artifacts (not shown in the diagram) is called @bold{role}.
Dmitry Duplyakin's avatar
Dmitry Duplyakin committed
379
  A role can include one or more cookbooks and specific recipes (each cookbook and recipe can be used
380
  in several roles if necessary). Roles typically define complete node configurations;
381
  for instance, in a simple case, one role corresponds to a master node on a cluster with a set of specific services,
Dmitry Duplyakin's avatar
Dmitry Duplyakin committed
382
  while another role defines how the rest of the cluster nodes, so-called ``worker'' nodes, should be configured.
383
  After being created on the workstation, these roles are submitted to the server by the administrator
384 385 386
  and then assigned to specific nodes via the run lists.}
]

Dmitry Duplyakin's avatar
Dmitry Duplyakin committed
387 388 389
In the experiment we have launched, @tt{head} runs all three: the server, the workstation, and the client
(there is no conflict between these components), while @tt{node-0} runs only the client. If this profile is instantiated
with the arbitrary number N of clients, there will be N ``client-only'' nodes
390 391
named @tt{node-0},@tt{node-1},...,@tt{node-(N-1)}.
Another profile parameter allows choosing the repository from which chef-repo is cloned;
Dmitry Duplyakin's avatar
Dmitry Duplyakin committed
392 393
by default, it points to @link["https://github.com/emulab/chef-repo"]{emulab/chef-repo}.
The startup scrips in this profile also obtain and install copies of public cookbooks
394 395
hosted at the respository called @link["https://supermarket.chef.io"]{Supermarket}.
Specifically, the exercises in this tutorial rely on the @link["https://supermarket.chef.io/cookbooks/nfs"]{nfs}
Dmitry Duplyakin's avatar
Dmitry Duplyakin committed
396 397 398
and @link["https://supermarket.chef.io/cookbooks/apache2"]{apache2} cookbooks --- both
should be installed on your experiment now in accordance with the default value of the
corresponding profile parameter we have used.
399 400 401

@section{Logging in to the Chef Web Console}

Dmitry Duplyakin's avatar
Dmitry Duplyakin committed
402 403
As soon as the startup scripts complete, you will likely recieve an email confirming that Chef is installed and operational.

Dmitry Duplyakin's avatar
Dmitry Duplyakin committed
404 405
@verbatim{Dear User,

406
Chef server and workstataion should now be
Dmitry Duplyakin's avatar
Dmitry Duplyakin committed
407 408
installed on head.chefdemo.utahstud.emulab.net.

409 410 411
To explore the web management console, copy
this hostname and paste it into your browser.
Installation log can be found at /var/log/init-chef.log
Dmitry Duplyakin's avatar
Dmitry Duplyakin committed
412 413
on the server node.

414
To authenticate, use the unique credentials
Dmitry Duplyakin's avatar
Dmitry Duplyakin committed
415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448
saved in /root/.chefauth on the server node.

Below are several Chef commands which detail the launched experiment:

# chef -v
Chef Development Kit Version: 0.7.0
chef-client version: 12.4.1
berks version: 3.2.4
kitchen version: 1.4.2

# knife cookbook list
apache2               3.1.0
apt                   2.9.2
emulab-apachebench    1.0.0
emulab-nfs            0.1.0
...
nfs                   2.2.6

# knife node list
head
node-0

# knife role list
apache2
apachebench
...
nfs

# knife status -r
1 minute  ago, head, [], ubuntu 14.04.
0 minutes ago, node-0, [], ubuntu 14.04.

Happy automation with Chef!
}
449

450
In some cases, you will not be able to see this email ---
Dmitry Duplyakin's avatar
Dmitry Duplyakin committed
451
email filters (e.g., if you are using a university email account) may classify it as spam.
452
This will not be a problem since the email is supposed to provide useful but noncritical information.
Dmitry Duplyakin's avatar
Dmitry Duplyakin committed
453 454
You can still access the Chef web console using the link included in the profile instructions
and also obtain the credentials as described in the instructions.
455

Dmitry Duplyakin's avatar
Dmitry Duplyakin committed
456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494
When you receive this email or see in the topology viewer that the startup scripts completed,
you can proceed to the following step.

@subsection[#:tag "chef-tutorial-web-shell"]{Web-based Shell}

@(tb) provides a browser-based shell for logging into your nodes, which is
accessed through the action menu described above. While this shell is
functional, it is most suited to light, quick tasks; if you are going to do
serious work, on your nodes, we recommend using a standard terminal
and @(ssh) program.

This shell can be used even if you did not establish an @(ssh) keypair with
your account.

Three things of note:

@itemlist[
    @item{Your browser may require you to click in the shell window before
        it gets focus.}

    @item{Depending on your operating system and browser, cutting and pasting into
        the window may not work. If keyboard-based pasting does not
        work, try right-clicking to paste.}

    @item{@bold{The recommended browsers are Chrome and Firefox.}
          The web-based shell does not work reliably in Safari.
          It is not guaranteed that it works smoothly in other browsers.}
]

Create a shell tab for @tt{head} by choosing ``Shell'' in the
Actions menu for @tt{head} in either the topology or the list view.
The new tab will be labeled ``head''. It will allow typing shell commands
and executing them on the node. All shell commands used throughout this tutorial
should be issued using this shell tab.

While you are here, switch to the @italic{root} user by typing:

@verbatim{@bold{sudo su -}}

495
@clab-screenshot["chef-tutorial/experiment-shell.png"]
Dmitry Duplyakin's avatar
Dmitry Duplyakin committed
496 497 498 499 500 501 502 503

Your prompt, the string which is printed on every line before the cursor,
should change to @tt{root@"@"head}.
All commands in the rest of the tutorial should be executed under @italic{root}.

@subsection{Chef Web Console}

Type the following to print Chef credentials:
504

Dmitry Duplyakin's avatar
Dmitry Duplyakin committed
505
@verbatim{@bold{cat /root/.chefauth}}
Dmitry Duplyakin's avatar
Dmitry Duplyakin committed
506

507
You should see the unique login and password that have been
Dmitry Duplyakin's avatar
Dmitry Duplyakin committed
508
generated by the startup scripts specifically for your instance of Chef:
509

510
@clab-screenshot["chef-tutorial/shell-chefauth.png"]
511 512

Expand the ``Profile Instructions'' panel and
513
click on the ``Chef web console'' link.
514

515
@bold{Warning:} When your browser first points to this link, you will see a warning
Dmitry Duplyakin's avatar
Dmitry Duplyakin committed
516
about using a self-signed SSL certificate. Using self-signed certificates
517 518
is not a good option in production scenarios, but it is totally acceptable
in this short-term experimentation environment. We will ignore this warning and proceed to using the Chef console.
Dmitry Duplyakin's avatar
Dmitry Duplyakin committed
519 520
The sequence of steps for ignoring it depends on your browser.
In Chrome, you will see a message saying "Your connection is not private". Click ``Advanced''
521
at the bottom of the page and choose ``Proceed to <hostname> (unsafe)''. In Firefox,
Dmitry Duplyakin's avatar
Dmitry Duplyakin committed
522 523 524 525
the process is slightly different: click ``Advanced'', choose ``Add Exception'', and
click ``Confirm Security Exception''.

When the login page is finally displayed, use the credentials you have printed in the shell:
526

527 528
@clab-screenshot["chef-tutorial/chef-wui-login.png"]
@clab-screenshot["chef-tutorial/chef-wui-nodelist.png"]
529

Dmitry Duplyakin's avatar
Dmitry Duplyakin committed
530
If you see a console like the one above, with both @tt{head} and @tt{node-0} listed on the ``Nodes'' tab,
531 532
you have a working Chef cluster! You can now proceed to managing your nodes using
Chef recipes, cookbooks, and roles.
533 534 535 536

In the rest of the tutorial, we demonstrate how you can use several pre-defined cookbooks and roles.
Development of cookbooks and roles is a subject of another tutorial (many such tutorials can be
found online). Our goal in the following sections is to walk you through
537 538
the process of using existing cookbooks and roles --- the process which is the same for simple
and more complex configurations. You will learn how to modify run lists and
539
apply cookbooks and roles to your nodes, run them, check their status,
540
and explore individual components of cookbooks and roles.
541 542 543

@section{Configuring NFS}

544 545 546 547
Now that you have a working instance of Chef where both @tt{head} and @tt{node-0}
can be controlled using Chef, let's start modifying the software stacks
on these nodes by installing NFS and exporting a directory from @tt{head} to
@tt{node-0}.
548 549 550

@itemlist[#:style 'ordered
  @instructionstep["Modify the run list on head"]{
Dmitry Duplyakin's avatar
Dmitry Duplyakin committed
551
    Click on the row for @tt{head} in the node list (so the entire row is highlighted in orange),
552 553 554
    and then click "Edit" in the Run List panel in the bottom right corner of the page:

    @clab-screenshot["chef-tutorial/head-edit-runlist.png"]
555 556
  }
  @instructionstep["Apply nfs role:"]{
Dmitry Duplyakin's avatar
Dmitry Duplyakin committed
557
    In the popup window, find the role called @tt{nfs} in the Available Roles list on the left, drag and drop it into
558 559 560
    the "Current Run List" field on the right. When this is done, click "Save Run List".

    @clab-screenshot["chef-tutorial/head-nfs-drag.png"]
561 562
  }
  @instructionstep["Repeat the last two steps for node-0:"]{
563 564
    @clab-screenshot["chef-tutorial/node0-edit-runlist.png"]
    @clab-screenshot["chef-tutorial/node0-nfs-drag.png"]
565

Dmitry Duplyakin's avatar
Dmitry Duplyakin committed
566
    At this point, @tt{nfs} role is assigned to both nodes, but nothing has executed yet.
567 568
  }
  @instructionstep["Check the status from the shell"]{
569 570

    Before proceeding to applying these updates,
Dmitry Duplyakin's avatar
Dmitry Duplyakin committed
571
    let's check the role assignment from the shell by typing:
Dmitry Duplyakin's avatar
Dmitry Duplyakin committed
572 573 574

    @verbatim{@bold{knife status -r}}

Dmitry Duplyakin's avatar
Dmitry Duplyakin committed
575
    The run lists for your nodes should be printed inside square brackets:
576

577 578
    @clab-screenshot["chef-tutorial/shell-knife-status.png"]

579
    The output of this command also conveniently shows when Chef applied changes to your
580
    nodes last (first column) and what operating systems run on the nodes (last column).
581
  }
Dmitry Duplyakin's avatar
Dmitry Duplyakin committed
582
  @instructionstep["Trigger the updates"]{
583 584

    Run the assigned role on @tt{head} by typing:
Dmitry Duplyakin's avatar
Dmitry Duplyakin committed
585
    @verbatim{@bold{chef-client}}
586 587 588

    @clab-screenshot["chef-tutorial/head-chef-client.png"]

Dmitry Duplyakin's avatar
Dmitry Duplyakin committed
589
    As a part of the startup procedure,
590
    passwordless @tt{ssh} connections are enabled between the nodes.
Dmitry Duplyakin's avatar
Dmitry Duplyakin committed
591 592
    Therefore, you can use @tt{ssh} to run commands remotely,
    on the nodes other than @tt{head}, from the same shell.
593
    Execute the same command on @tt{node-0} by typing:
Dmitry Duplyakin's avatar
Dmitry Duplyakin committed
594 595

    @verbatim{@bold{ssh node-0 chef-client}}
596 597 598 599

    @clab-screenshot["chef-tutorial/node0-chef-client.png"]

    When nodes execute the ``@code{chef-client}'' command,
Dmitry Duplyakin's avatar
Dmitry Duplyakin committed
600
    they contact the server and request the cookbooks, recipes, and roles have been
601 602
    assigned to them in their run lists. The server responds with those artifacts,
    and the nodes execute them in the specified order.
603 604 605
  }
  @instructionstep["Verify that NFS is working"]{

Dmitry Duplyakin's avatar
Dmitry Duplyakin committed
606 607 608 609 610
    After updating both nodes, you should have a working NFS configuration in which
    the @code{/exp-share} directory is exported from @tt{head} and mounted on @tt{node-0}.

    @margin-note{The name of the NFS directory is one of the attributes that is set in the @tt{nfs} role.
    To explore other attributes and see how this role is implemented, take a look at
611
    the @code{/chef-repo/roles/nfs.rb} file on @tt{head}}
Dmitry Duplyakin's avatar
Dmitry Duplyakin committed
612

613
    The simplest way to test that this configuration is functioning properly
Dmitry Duplyakin's avatar
Dmitry Duplyakin committed
614
    is to create a file on one node and check that this file becomes
615 616
    available on the other node.
    Follow these commands to test it (the lines that start with the # sign are comments):
Dmitry Duplyakin's avatar
Dmitry Duplyakin committed
617 618 619 620 621 622 623 624 625 626 627 628 629 630

    @verbatim{
    # List files in the NFS directory /exp-share on head; should be empty
    @bold{ls /exp-share/}

    # List the same directory remotely on node-0; also empty
    @bold{ssh node-0 ls /exp-share/}

    # Create an empty file in this derectory locally
    @bold{touch /exp-share/NFS-is-configured-by-Chef}

    # Find the same file on node-0
    @bold{ssh node-0 ls /exp-share/}
    }
631

632
    @clab-screenshot["chef-tutorial/nfs-is-working.png"]
633

634 635
    If you can see the created file on @tt{node-0}, your NFS is working as expected.
    Now you can easily move files between your nodes using the @code{/exp-share} directory.
636 637 638
  }
]

Dmitry Duplyakin's avatar
Dmitry Duplyakin committed
639
@bold{Summary:} You have just installed and configured NFS by assigning a Chef
640 641
role and running it on your nodes.
You can create much more complex software environments
642
by repeating these simple steps and installing more software components on your nodes.
Dmitry Duplyakin's avatar
Dmitry Duplyakin committed
643
Additionally, installing NFS on a set of nodes is not a subject of
644
a research experiment but rather an infrastructure prerequisite for
Dmitry Duplyakin's avatar
Dmitry Duplyakin committed
645 646
many distributed systems. You can automate installation and configuration procedures
in those systems using a system like Chef and save a lot of time
647
when you need to periodically recreate them or create multiple instances of those systems.
648 649 650

@subsection{Exploring The Structure}

651 652
It is worth looking at how the role you have just used is implemented. Stored at
@code{/chef-repo/roles/nfs.rb} on @tt{head}, it should include the following code:
653

Dmitry Duplyakin's avatar
Dmitry Duplyakin committed
654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674
@verbatim{
#
# This role depends on the emulab-nfs cookbook;
# emulab-nfs depends on the nfs cookbook
# available at: https://supermarket.chef.io/cookbooks/nfs
# Make sure it is installed; If it is not, try: knife cookbook site install nfs
#
name "nfs"
description "Role applied to all NFS nodes - server and client"
override_attributes(
  "nfs" => {
    "server" => "head",
    "dir" => "/exp-share",
    "export" => {
      "network" => "10.0.0.0/8",
      "writeable" => true
    }
  }
)
run_list [ "emulab-nfs" ]
}
675

676
You can see a number of domain-specific Ruby attributes in this file.
677 678 679
@code{name} and @code{description} are self-describing attributes.
The @code{override_attribute} attribute allows you to control high-level configuration
parameters, including (but not limited to) the name of the node running the NFS server,
680 681 682
the directory being exported and mounted, the network in which this directory is
shared, and the ``write'' permission in this directory (granted or not).
The @code{run_list} attribute includes a single cookbook called @code{emulab-nfs}.
683 684 685

You are probably wondering now about how the same cookbook
can perform different actions on different nodes.
Dmitry Duplyakin's avatar
Dmitry Duplyakin committed
686 687 688 689
Indeed, the @tt{emulab-nfs} cookbook has just installed NFS server on @tt{head} and
NFS client on @tt{node-0}. You can take a look at the implementation
of the @code{default.rb}, the default recipe in the @tt{emulab-nfs} cookbook which
gets called when the cookbook is executed. You should find the following code
690
at @code{/chef-repo/cookbooks/emulab-nfs/recipes/default.rb}:
691

Dmitry Duplyakin's avatar
Dmitry Duplyakin committed
692 693 694 695 696 697 698 699 700 701 702 703
@verbatim{
#
# Cookbook Name:: emulab-nfs
# Recipe:: default
#

if node["hostname"] == node["nfs"]["server"]
  include_recipe "emulab-nfs::export"
else
  include_recipe "emulab-nfs::mount"
end
}
704

Dmitry Duplyakin's avatar
Dmitry Duplyakin committed
705 706 707 708
The @code{if} statement above allows comparing the hostname of the node on which
the cookbook is running with one of the attributes specified in the role.
Based on this comparison, the recipe takes the appropriate actions by
calling the code from two other recipes in this cookbook.
709
Optionally, you can explore @code{/chef-repo/cookbooks/emulab-nfs/recipes/export.rb} and
Dmitry Duplyakin's avatar
Dmitry Duplyakin committed
710 711 712
@code{/chef-repo/cookbooks/emulab-nfs/recipes/mount.rb}
to see how these recipes are implemented.

713
Obviously, this is not the only possible structure for this configuration.
Dmitry Duplyakin's avatar
Dmitry Duplyakin committed
714
You can alternatively create two roles, such as @tt{nfs-server} and @tt{nfs-client},
715 716 717
that will call the corresponding recipes without the need for the described comparison.
Since a single model cannot fit perfectly all scenarios, Chef provides
the developer with enough flexibility to organize the code into structures
Dmitry Duplyakin's avatar
Dmitry Duplyakin committed
718 719 720
that match specific environment and application needs.

@section{Apache Web Server and ApacheBench Benchmarking tool}
721

722
In this exercise, we are going to switch gears and experiment with
Dmitry Duplyakin's avatar
Dmitry Duplyakin committed
723 724
different software --- @code{apache2}, the Apache HTTP web server, and the @code{ab} benchmarking tool.
You will explore more Chef capabilities and perform administrative
725
tasks, primarily from the command line.
Dmitry Duplyakin's avatar
Dmitry Duplyakin committed
726 727 728

We recommend you to continue using the shell tab for @tt{head} (again, make sure that your commands are
executed as @italic{root}). Run the commands described below in that shell.
729 730

@itemlist[#:style 'ordered
Dmitry Duplyakin's avatar
Dmitry Duplyakin committed
731
  @instructionstep["Add a role to the head's run list"]{
732
    Issue the command in bold (the rest is the expected output):
Dmitry Duplyakin's avatar
Dmitry Duplyakin committed
733

734 735 736 737 738
    @verbatim{@bold{knife node run_list add head "role[apache2]"}
    head:
      run_list:
        role[nfs]
        role[apache2]
Dmitry Duplyakin's avatar
Dmitry Duplyakin committed
739
    }
740
  }
Dmitry Duplyakin's avatar
Dmitry Duplyakin committed
741
  @instructionstep["Add two roles to the node-0's run list"]{
742
    Run the two @code{knife} commands listed below (also on @tt{head}) in order to assign two roles to @tt{node-0}:
Dmitry Duplyakin's avatar
Dmitry Duplyakin committed
743 744

    @verbatim{@bold{knife node run_list add node-0 "role[apache2]"}
745
    run_list:
Dmitry Duplyakin's avatar
Dmitry Duplyakin committed
746 747 748 749 750 751 752 753 754 755 756
    head:
      run_list:
        role[nfs]
        role[apache2]
    @bold{knife node run_list add node-0 "role[apachebench]"}
    run_list:
    head:
      run_list:
        role[nfs]
        role[apache2]
        role[apachebench]
757 758 759 760
    }

    Notice that we did not exclude the @tt{nfs} role from the run lists.
    Configuration updates in Chef are @italic{idempotent}, which means that an update can be applied to a node
Dmitry Duplyakin's avatar
Dmitry Duplyakin committed
761
    multiple times, and every time the update will yield identical configuration (regardless of the node’s previous state)
762 763 764
    Thus, this time, when you run ``@code{chef-client}'' again, Chef will do the right thing:
    the state of each individual component will be inspected, and
    all NFS-related tasks will be silently skipped because NFS is already installed.
765 766
  }
  @instructionstep["Trigger updates on all nodes"]{
767 768 769
    In the previous section, we updated one node at a time.
    Try the ``batch'' update - run a single command that
    will trigger configuration procedures on all client nodes:
Dmitry Duplyakin's avatar
Dmitry Duplyakin committed
770 771

    @verbatim{@bold{knife ssh "name:*" chef-client}
772
    apt155.apt.emulab.net resolving cookbooks for run list:
Dmitry Duplyakin's avatar
Dmitry Duplyakin committed
773
      ["emulab-nfs", "apache2", "apache2::mod_autoindex", "emulab-apachebench"]
774
    apt154.apt.emulab.net resolving cookbooks for run list:
Dmitry Duplyakin's avatar
Dmitry Duplyakin committed
775 776 777 778 779
      ["emulab-nfs", "apache2", "apache2::mod_autoindex"]
    apt155.apt.emulab.net Synchronizing Cookbooks:
    ....
    apt155.apt.emulab.net Chef Client finished, 5/123 resources updated in 04 seconds
    }
780 781

    You should see interleaved output from the ``@code{chef-client}''
Dmitry Duplyakin's avatar
Dmitry Duplyakin committed
782
    command running on both nodes at the same time.
783

Dmitry Duplyakin's avatar
Dmitry Duplyakin committed
784
    The last command uses a node search based on the ``@code{name:*}'' criteria.
Dmitry Duplyakin's avatar
Dmitry Duplyakin committed
785
    As a result, every node will execute ``@code{chef-client}''. In cases where it is necessary,
Dmitry Duplyakin's avatar
Dmitry Duplyakin committed
786 787
    you can use more specific search strings, such as, for instance, ``@code{name:head}''
    and ``@code{name:node-*}''.
788 789
  }
  @instructionstep["Check that the webservers are running"]{
790

Dmitry Duplyakin's avatar
Dmitry Duplyakin committed
791
    One of the attributes in the @code{apache2} role configures the web server
792
    such that it runs on the port @code{8080}. Let's check that the web servers
Dmitry Duplyakin's avatar
Dmitry Duplyakin committed
793
    are running via checking the status of that port:
Dmitry Duplyakin's avatar
Dmitry Duplyakin committed
794 795

    @verbatim{@bold{knife ssh "name:*" "netstat -ntpl | grep 8080" }
796
    pc765.emulab.net tcp6 0 0 :::8080 :::* LISTEN 9415/apache2
Dmitry Duplyakin's avatar
Dmitry Duplyakin committed
797
    pc768.emulab.net tcp6 0 0 :::8080 :::* LISTEN 30248/apache2 }
798

Dmitry Duplyakin's avatar
Dmitry Duplyakin committed
799
    Note that this command sends an arbitrary command (unrelated to Chef)
800 801
    to a group of nodes. With this functionality, the @code{knife} command-line utility
    can be viewed as an orchestration tool for managing groups of nodes that is capable
Dmitry Duplyakin's avatar
Dmitry Duplyakin committed
802
    of replacing @code{pdsh}, the Parallel Distributed Shell utility, that is often used on computing clusters.
Dmitry Duplyakin's avatar
Dmitry Duplyakin committed
803

804 805 806 807
    The output that is similar to the one above indicates that both @code{apache2} web servers are running.
    The command that you have just issued uses @code{netstat}, a command-line tool that displays network connections,
    routing tables, interface statistics, etc. Using @code{knife}, you have run
    @code{netstat} in combination with a Linux pipe and a @code{grep} command
808
    for filtering output and displaying the information only on the port @code{8080}.
809

810 811
  }
  @instructionstep["Check benchmarking results on node-0"]{
Dmitry Duplyakin's avatar
Dmitry Duplyakin committed
812

813
    Many different actions have taken place on @tt{node-0}, including:
814
    @itemlist[
Dmitry Duplyakin's avatar
Dmitry Duplyakin committed
815 816 817
      @item{@code{apache2} has been installed and configured}
      @item{@code{ab}, a benchmarking tool from the @code{apache2-utils} package, has been installed and executed}
      @item{benchmarking results have been saved, and plots have been created using the @code{gnuplot} utility}
818
      @item{the plots have been made available using the installed web server}
819
    ]
Dmitry Duplyakin's avatar
Dmitry Duplyakin committed
820 821

    To see how the last three tasks are performed using Chef, you can take a look at the
822 823 824 825
    @link["https://github.com/emulab/chef-repo/blob/master/cookbooks/emulab-apachebench/recipes/default.rb"]{default.rb} recipe inside
    the @code{emulab-apachebench} cookbook. In the in-person tutorial, let's proceed to
    the following steps and leave the discussion of this specific recipe
    and abstractions used in Chef recipes in general to the end of the tutorial.
826

827 828
    Obtain the @tt{node-0}'s public hostname (refer to the list included in the profile instructions),
    and construct the following URL:
Dmitry Duplyakin's avatar
Dmitry Duplyakin committed
829
    @verbatim{http://<node-0's public hostname>:8080}
830
    With the right hostname, copy and paste this URL into your browser to access the web server running on @tt{node-0}
Dmitry Duplyakin's avatar
Dmitry Duplyakin committed
831
    and serving the benchmarking graphs. You should see a directory listing like this:
832

833 834 835
    @clab-screenshot["chef-tutorial/apache-dir-listing-0.png"]

    You can explore the benchmarking graphs by clicking at the listed links.
Dmitry Duplyakin's avatar
Dmitry Duplyakin committed
836
    So far, @code{ab} has run against the local host (i.e. @tt{node-0}), therefore the
837 838 839
    results may not be so interesting. Do not close the window with your browser
    since one of the following steps will ask you to go back to it to see more results.
  }
Dmitry Duplyakin's avatar
Dmitry Duplyakin committed
840
  @instructionstep["Modify a role"]{
841

Dmitry Duplyakin's avatar
Dmitry Duplyakin committed
842 843 844 845 846
    Just like the @tt{nfs} role described in the previous section, @tt{apachebench} has a number of
    attributes that define its behavior. We will use the Chef web console to update the value
    for one of its attributes.

    In the console, click on the Policy tab at the top of the page, choose ``Roles'' in the panel on the left,
847
    and select ``apachebench'' in the displayed list of roles.
Dmitry Duplyakin's avatar
Dmitry Duplyakin committed
848
    Select the Attributes tab in the middle of the page.
849 850 851 852
    At the bottom of the page, you should now see
    a panel called ``Override Attributes''. Click the ``Edit'' button inside that panel:

    @clab-screenshot["chef-tutorial/console-apachebench-edit.png"]
853 854

    In the popup window, change the @code{target_host} attribute from @code{null}
Dmitry Duplyakin's avatar
Dmitry Duplyakin committed
855
    to the @tt{head}'s public hostname (refer to the hostnames listed in the profile instructions).
856
    Don't forget to use double quotes around the hostname. Also, let's modify the list of
857
    ports against which we will run the benchmark. Change @code{80} to @code{8080} since nothing interesting is running
858 859 860 861 862 863 864 865 866 867
    on port @code{80}, while the @code{apache2} server you have just installed
    is listening on the port @code{8080}. Leave the port @code{443} in the list --- this
    is the port on which the Chef web console is running.
    Here is an example of the recommended changes:

    @clab-screenshot["chef-tutorial/console-apachebench-change-attr.png"]

    When these changes are complete, click "Save Attributes".

    @bold{Alternative:} It turns out that you don't have to use the Chef web console for modifying this role.
Dmitry Duplyakin's avatar
Dmitry Duplyakin committed
868 869
    Take a look at the two steps described below to see how we can modify this role from the shell
    or @bold{skip} to running the benchmark.
870

Dmitry Duplyakin's avatar
Dmitry Duplyakin committed
871 872
    This is what you need to make the described changes without using the web console:
    @itemlist[#:style 'ordered
Dmitry Duplyakin's avatar
Dmitry Duplyakin committed
873 874 875 876
      @item{Edit the file @code{/chef-repo/roles/apachebench.rb} on @tt{head} using a text editor of your choice (e.g., @code{vi})}
      @item{After making the suggested changes, ``push'' the updated role to the server by typing:
            @code{knife role from file /chef-repo/roles/apachebench.rb}}
    ]
877
    }
Dmitry Duplyakin's avatar
Dmitry Duplyakin committed
878
    @instructionstep["Run the benchmark against head"]{
879

880 881 882
    The updated version of the role is available on the server now.
    You can run it on @tt{node-0} using the following command:

Dmitry Duplyakin's avatar
Dmitry Duplyakin committed
883
    @verbatim{@bold{knife ssh "role:apachebench" chef-client}}
884

Dmitry Duplyakin's avatar
Dmitry Duplyakin committed
885
    This command, unlike the @code{knife} commands you issued in the previous steps, uses a search based on the assigned roles.
886 887
    In other words, it will find the nodes to which the @tt{apachebench} role has been assigned by now --- in our case, only
    @tt{node-0} --- and execute ``@code{chef-client}'' on them.
888 889
  }
  @instructionstep["Check benchmarking results again"]{
890 891