📜 ⬆️ ⬇️

Chef Patterns and Antipatterns


Preface from the translator


One day, my colleague threw me a link to a source article. At first I did not take it seriously. But then, stepping on a bunch of rakes and stuffing a few of his cones, I realized what was going on.

Under the cut you will find some typical errors. At the same time, the correct approaches to writing and using the infrastructure code for Chef will be shown, which help to avoid problems in the future.

The article will be useful for both experienced "chefs" and for beginners.

')

Antipattern: changing (forking) the community cookbooks


I did that, probably you too. It all starts quite innocently and does not bode well for anything bad. You add a couple of attributes, change metadata.rb . Soon you need to add your recipe, and maybe even LWRP . Now you have porridge from your changes and community code, especially if cookbook is in active development on GitHub. Sooner or later you will have to correct conflicts. It will be difficult to isolate logical errors if both the original cookbook and your changes are almost the same. And how will you now version this "Frankenstein"? Use the same version as upstream? In short, this is an anti-pattern, which is then difficult to fix.

The only exception to the rule of “do not forcay the cookbook community” is if you are going to bring your changes back to the community. Then you need to create a ficher branch in git and send a pull request. This should be a living branch only until the changes merge with the main branch.

Pattern: Create your own wrapper (wrapper-cookbook) with your attributes and recipes


Instead of forking the Kukbuk community, it is better to use it "as is" with the Kukbuk wrapper. In this kukbuk-wrapper in metadata.rb, you need to register a dependency on this kukbook and use include_recipe to run recipes from the kukbook community. Need to change default attributes? Then you need to rewrite them in a wrapper book.

Gem Chef-Rewind can help with this pattern.

Antipattern: Using Attributes in Roles


Listing attributes in roles is a dangerous antipattern that can break your production. Imagine the following scenario. You have a web_server role with attributes for the names and settings of the two sites that need to be installed on this server. Now imagine that you need to separate these sites into two roles, app_server and blog_server . So how are you going to test it on the dev environment? You can take a chance and hope that everything will be OK or overwrite the attributes in Chef Environments (first on dev, then qa, etc.) and not forget to clean them after they get to production. Not the best option.

It is better to use the attributes in the kukbuk-wrapper.

Pattern: Setting Your Attributes in a Kukbuk-Wrapper


Roles do not know how to version Chef, but kukbuki - yes. By setting the necessary attributes in the wrapper and specifying the correct version of the cookbook in Chef Environment, you can push the changes from dev to production.

Ideally, this should be part of the CI process with tests and the gradual advancement of changes automatically. But this is another story.

Antipattern: Setting a start list (run list) in the role


Chef roles seem ideal for storing a list of recipes to run. However, this approach suffers from the same drawbacks as the previous antipattern. If you add or remove a recipe from the list of run_list in a role, these changes will be applied to all servers with this role, including production servers.

So do not need to:
 name "web_server" description "Role for web servers" run_list( "recipe[base_server::disk_configuration]", "recipe[base_server::dhcp_reservation]", "recipe[base_server::pagefile]", "recipe[utility::install_tools]", "recipe[web_server::web_sites]", "recipe[base_server::ssl_certs]" ) 


Pattern: Specify the run list in the recipe default in the cookbook e created specifically for this (so-called role-cookbook or application-cookbook)


Keep as a minimum list of recipes. A complete list of recipes should be stored in the application-cookbook. For example, the web_server role might look like this:
 name "web_server" description "Role for web servers" run_list( "role[base]", "recipe{web_server]" ) 

The recipe for your application-cookbook default will look something like this:
 # web_server cookbook recipes/default.rb include_recipe "base_server::disk_configuration", include_recipe "base_server::dhcp_reservation", include_recipe "base_server::pagefile", include_recipe "utility::install_tools", include_recipe "web_server::web_sites", include_recipe "base_server::ssl_certs" 


Again, this is so that you can easily manage the versions of the cookbooks and test changes to version 2.1.0 on the dev environment, while the production will have stable 1.5.0.

Conclusion


By following the above patterns, you will save a lot of time and effort. You will not need to do complicated murgi, since all changes are stored in a wrapper cookbook.

By setting the necessary attributes and run_list in the cookbooks, and not in the roles, you will not get problems with versioning and isolation of environments.

Source: https://habr.com/ru/post/209232/


All Articles