class: center, middle, inverse, splash #Master Chef & Puppet Show .footnote[ [@francoisledroff](https://twitter.com/francoisledroff) & [@rpelisse](https://twitter.com/rpelisse) at [Devoxx fr 2014](http://cfp.devoxx.fr/devoxxfr2014/talk/QRF-934/Chez%20les%20barbus:%20master%20chef%20et%20puppet%20show)] --- class: center, middle, inverse ## [@rpelisse](https://twitter.com/rpelisse) ??? Alors, je suis Romain Pelisse, je suis "Cloud Architect" chez Red Hat, pour qui je travaille depuis presque plus de deux ans. J'ai toujours travaillé dans l'Open Source, ce qui m'a, d'une part, amener naturellement à travailler chez Red Hat, mais c'est aussi comme ça que j'ai rencontré François, quand nous avons travailler ensemble chez Atos Origin, au sein du centre de compétence Open Source. Bien que Puppet ne soit pas un produit Red Hat, on l'utilise beaucoup, car il se trouve très souvent au croissement de nombreux de produit - comme Satellite ou RHEL, mais est aussi l'acteur principale de l'intégration de ces derniers au sein de l'IT de nos clients. --- class: center, middle, inverse ## [@francoisledroff](https://twitter.com/francoisledroff) ??? Je m'appelle Francois, Francois Le Droff, Je vais du Java depuis le dernier millenaire, 1997 J'ai eu la chance de travailler et faire quelques conf avec Romain notamment au ParisJug je travaille maintenant chez Adobe, apres quelques années chez Adobe Consulting j'ai rejoint Adobe IT, je fais toujours du consulting en quelque sorte, mais Chez Adobe pour Adobe et souvent avec les produits Adobe, et toujours beaucoup de linux, de java et d'open source. --- class: center, middle, inverse # Quoi? # Comment? # et Pourquoi? ??? Francois Nous allons Commencer par quelques definitions utiles Puis Nous allons rapidement lever le voile sur la nature de ces deux solutions concurrentes de gestion de configuration que sont Chef et Puppet Pour voir ensemble quelques cas concret d'utilisation de chef et puppet dans des contextes liée à l'ecosysteme Java La conclusion devrait couler de source, si nous avons bien fait notre travail dans les 30 premieres minutes, vous aurez alors compris pourquoi Chef et/ou Puppet sont des solutions à considérer pour vous permettre * de simplifier, accélerer, sécuriser, scaler vos infra * de mettre en place une vraie solution de continuous delivery --- layout: false .left-column[ ## Quoi? ] .right-column[ .pull-left[ ![Puppet](img/puppet_logo.png) Puppet: - créé en 2005 - édité par PuppetLabs - license Apache - langage dédié (DSL) Pourquoi Puppet Romain ? ] .pull-right[ ![Chef](img/chef_logo.png) Chef: - créé en 2009 - édité par Opscode/Chef - license Apache - Ruby Pourquoi Chef François ? ] ** une communité active et ouverte ** ] ??? Romain: Bon, alors, Puppet est un logiciel Open Source, crée en 2005 et sous licence Apache. La compangie Puppetlabs fournit du support sur une version "entreprise" - dans un business model similaire au notre, chez Red Hat. La principale caractéristique de Puppet est de proposer un DSL, un langage de description, spécifique au métier de l'infrastructure, mais aussi indépendant de tout langage - mais si certains mécanismes rappellent, bien naturellement Ruby, puisqu'il est codé en Ruby. Maintenant, comment moi, j'ai rencontré Puppet ? Un peu par hasard en fait. Avant Red Hat, j'avais été recruté par une startup, à Berlin, pour faire du Scala - langage où je connaissais rien à l'époque au passage, et comme j'avais des bonnes connaissances en Linux, on m'a refilé la mise en place de l'IT, avec Puppet. On a donc tout automatisé à l'aide de ce dernier, et on a même était très loin. En effet, et c'est encore le cas à ce jour, l'IT au complet de la startup est littéralement reconstruit "from scratch" tout le matins. Tout les matins, on tue toutes les VMs dépoyées sur Amazon, on fait "un checkout" et on reconstruit l'intégralité du système - en à peu près une demi heure. Francois: Chef est présent sur le marché depuis 2009, influencé par Puppet et CFengine Chef est open source, license Apahce et tout comme Puppet, il est multi platform, il supporte notamment Ubuntu, Debian, RHEL/CentOS, Fedora, Mac OS X, Windows 7, and Windows Server. Tout comme Puppet, Chef a été concu pour s'integrer avec d'autres outils (rpm, msi, brew) chef n'est pas la representation canonique de votre infra, c'est un service qui qui expose des données sur l'état de votre infra structure. Tout dans Chef est décrit avec des scripts Ruby, il semblera sans doute plus familier que Puppet aux développeurs. Vous n'avez toutefois pas besoin d'être un expert Ruby pour commencer, Vous ne connaissez pas Ruby ? 20 minutes m'ont suffit et 10 devrait suffir à la plupart d'entre vous pour connaitre assez de Ruby pour commencer a utiliser ruby pour configurer votre infra avec Chef Mais vous serez grandement recompensé si vous investisser a minima dans Ruby Car vous pourrez integrer et reutiliser des gem/librairies Ruby et mettre en places des test unitaires, des test d'integrations https://speakerdeck.com/sethvargo/using-ruby-to-automate-your-life http://docs.opscode.com/chef_why.html --- layout: false .left-column[ ## Quoi? ### - Infrastructure ] .right-column[ **Infrastructure** [in-fruh-struhk-cher] nom féminin .red[[1]] une collection de * ressources: * réseaux, noeuds * systèmes de fichiers, fichiers, répertoires, liens symboliques, montages disques * utilisateurs, groupes * packages, logiciels, services * configuration * agissant de concert * pour fournir un service ] .footnote[.red[[1] [Introduction to Chef](http://www.slideshare.net/JulianDunn/chef-introduction-princeton-meetup)]] ??? --- layout: false .left-column[ ## Quoi? ### - Infrastructure ### - Infrastructure as code ] .right-column[ **Infrastructure as Code** ? Ne remplace pas juste tes scripts shell, te permet: * d'abstraire les élements de gestion de ton infra * de définir ton infra sous forme de code * de la (re)construire à partir de serveurs 'nus' * faire converger tes systèmes * de façon idempotente ``` Etat A --> Etat B (ex: install) Chef Client finished, 147/153 resources updated Etat B --> Etat B (ex: contrôle) Chef Client finished, 0/153 resources updated Etat C --> Etat B (ex: remise en état) Chef Client finished, 48/153 resources updated ``` ] ??? Concrètement que font Puppet et Chef ? Ben ce sont des outils d'infrastructure as code, comme dit le slide, ce qui signifie qu'ils permettent d'exprimer ou plutôt de décrire, chacun à sa manière, l'état souhaité de son infrastructure, et d'en automatiser non seulement la mise en place, mais aussi le maintien en état. Alors, bien évidement, vous avez peut être déjà vu ce genre d'automatisation réalisée à l'aide de shell scripts par exemple, mais ces outils permettent de faire bien mieux. En effet, ils fournissent non seulement un langage de description de haut niveau et approprié, mais surtout ils fournissent une couche d'abstraction, qui permet de décrire l'état d'un système, sans rentrer dans les détails de comment cet état sera concrètement implémenté sur le système cible. En outre, et c'est crucial pour assurer le maintien en état, ces outils agissent de manière idempotente (ça veut dire que après chaque exécution on doit rester dans le même état, c'est pas quand vous avez des problèmes au lit, avec votre partenaire). Donc, par exemple, on récupère un serveur fraichement installé, soit dans l'état A, et bien Puppet ou Chef va effectuer une série d'installations et de configuration pour l'amener à l'état B. Ensuite, à interval régulier, il va s'assurer que cet état B reste constant. Si cet état diverge de la cible (état C), parce que, par exemple: - un développeur à laisser un log en DEBUG après un passage sur le serveur pour analyser un indicent - ou parce qu'un admin système de mauvaise volonté à fermer un port dont il ne comprenait pas l'utilité. Et bien, dans tout les cas, ces outils vont redresser la situation, et s'assurer que la configuration du serveur reviennent à un état B. Francois: Ils font mieux que du bash, car ils apportent, reproducibilite, idem potence, clarté, c'est du ruby pas du bash Mais surtout ces framework apportent une couche d'abstractions aidant au managemtn de ton infra, pas jsute de ta machine @FLD, on peut être virer ce copier/coller en anglais, au pire, il est dans l'historique de Git @RP, laissons les pointeurs pour les mettre dans un slide final http://www.slideshare.net/jedi4ever/infrastructure-as-code-abug-session http://architects.dzone.com/articles/infrastructure-code https://www.youtube.com/watch?v=cuJZbRngWC0 --- layout: false .left-column[ ## Quoi? ### - Infrastructure ### - Infrastructure as code ### - Abstractions ] .right-column[ Complexe ? Non ! Abstrait. **persister et manager** tes abstractions sous forme de code. * ressources * rôles * représente le type de serveur * environnements * modèle ton cycle de release et tes processus (dev, test, stage, prod) * pannier de données (data bags) ] ??? Romain: Bref, Puppet & Chef vous permettent donc de décrire l'état souhaité de votre infrastructure et de non seulement persiter ce dernier, ainsi que ses révisions, mais aussi de "manager" votre infrastructure, en ajoutant des modifications à cette historique. Une infrastructure est quelque chose d'assez complexe. En plus des configurations et des installations, il y a des problématiques réseaux, tel que les firewall, et résolution de nom de FQDN - et j'en passe. Heureusement, pour simplifier ce fouilli, Puppet et Chef abstrait tout ces composants sous forme de "ressource". C'est abstraction est essentiel, car elle libère la description de l'état d'un système ("un webserveur pour tels vhosts") de l'implémentation physique sous jacente ("Apache 2.22 sur RHEL"). Resources: Les ressources définisssent les actions comme: * un paquet devrait étre installé, un service doit etre demarrer, un user, un group, un repertoire doit etre crée Ainsi, on peut simplement dire à Puppet, "je voudrais que ce système exécute Apache avec ce fichier configuration". Ce dernier va simplement utiliser "yum" si le système est sous RHEL ou "apt-get" sous Debian pour installer le logiciel. En fait, cette abstraction devrait vous paraitre assez naturelle, car c'est finalement assez proche de la notion d'interface en Java. Francois: Dans Chef les resources peuvent être notifiés, un service redemarre par exemple Les resource peuvent apparaitre plus d'une fois, Pour reussir a manager cette complexité, il est necessaire d'embrasser les abstraction offertes par Chef Roles: * rôles * représente votre type de serveur: lb, web, db * contient des attributs tels que , la liste de recettes a appliquer, de applicationa a installer, les ports * Environments * modèle votre cycle de release et vos process (dev, test, stage, prod) * contient des attributs tels que : ulr de ton paiement de service, l'url du repo yum, les versions des cookbooks * Data Bags, * données globale stockée en json sur le serveur * je l'utilise pour encrypter/proteger les secrets servant a la configuration de mon systeme * les autres best practices : * global pour toute votre infra : external service api key, license * ca doit etre ecrit/donné par un autre systeme: un pipeline d'integration continue, ton jenkins, des infos d'une autre equipe http://www.slideshare.net/opscode/week-1-overview-of-chef http://docs.opscode.com/chef_overview.html http://www.getchef.com/blog/2014/01/23/attributes-or-data-bags-what-should-i-use/ --- layout: false .left-column[ ## Quoi? ### - Infrastructure ### - Abstractions ### - Puppet & Chef ### - Clients - Serveur ] .right-column[ * Chef/Puppet Server * Noeud: une machine configurée pour être maintenue par un agent, un client Chef/Puppet * Noeud <--> object *Node* * attributs détectés et communiqués à l'agent * attributs configurés par les recettes * *run-list*: une liste des recettes executées * Client Chef/Puppet: met le noeud dans l'état attendu ] ??? * Chef server : Dans un utilisation classique les 2 solution fonctionne en mode client serveurs. D'autre mode existe,: chef-zero (in memeory chef serveur, chef-solo) le serveur fournit un repo de noeuds, recette, de cookbooks, d'env, de role, de data bags une api, un search * Noeud/*Node*: une machine configurée pour être maintenue par un agent, un client Chef/Puppet * machine: vm, physique, privée, ou sur le cloud * A chaque noeud correspond un object *Node* sur le serveur Chef/Puppet * attributs * détectés et communiqués à l'agent ( Ohai pour Chef): Platform, cpu, kernel, host names, fqdn et bien plus * configurés par les recettes * *run-list*: une liste ordonnées de roles et/ou de recettes executées dans un ordre défini * un client Chef/Puppet: un agent qui tourne sur chacun des noeuds inscrits auprès du serveur Chef/Puppet * met le noeud dans l'état attendu Contrairement a Puppet, il n'y pas de gestion de dependances dans Chef, (meme si les resource peuvent etre notifies), chef appliquera/actionera les resources dans un ordre definit par les recettes et les policy Henri Gomez: 'Puppet c'est maven, Chef c'est graddle' --- class: center, middle ![overview](img/chef-client-serveurs.png) --- class: center, middle, inverse # Comment? --- layout: false .left-column[ ## Comment ? ### - un simple jar ] .right-column[ M'$%^$& pas, je n'ai qu'un simple jar, un container osgi, cq5 oui mais il faut: * installer le jdk, * télécharger le jar, * l'installer en tant que service, * faire tourner ses log, * et les monitorer, * de la haute dispo ] ??? --- layout: false .left-column[ ## Comment ? ### - un simple jar #### - le récupérer ] .right-column[ * cq5-cookbook/recipes/default.rb ```ruby remote_file node['cq5']['quickstart_jar'] do source node['cq5']['repo_url'] owner node['cq5']['user'] group node['cq5']['group'] checksum '3043859473' action :create_if_missing notifies :restart, 'service[cq5]', :delayed end ``` ```ruby artifact_file node['cq5']['quickstart_jar'] do location 'com.day.cq:cq5:jar:5.5.0.20120220' nexus_configuration nexus_configuration_object owner node['cq5']['user'] group node['cq5']['group'] notifies :restart, 'service[cq5]', :delayed end ``` ```ruby service 'cq5' do action [:enable] supports [:status, :start, :stop, :restart] end ``` ] ??? https://github.com/RiotGames/artifact-cookbook#artifact_file Downloading files using artifact_file In its simplest state, the artifact_file resource is a wrapper for the remote_file resource for Nexus and URL locations. The key addition is retry logic and integrity checking for the downloaded files. Below is a brief description of the logic flow for the resource: Download the file using remote_file resource. Check the file's integrity Is it from the Nexus? Check the SHA1 of the downloaded file against Nexus Server's SHA1. Returns false if they are not equal. Not from Nexus - Is the checksum attribute defined for the resource? If defined - Check the SHA256 of the downloaded file against the checksum attribute. Returns false if they are not equal. If not defined - log a message and return true. When the logic returns true, the downloaded file is considered good and the resource will exit. When the logic above returns false, the downloaded file is considered corrupt and an attempt will be made to download the file again. The number of retries can be controlled with the download_retries attribute. --- layout: false .left-column[ ## Comment ? ### - un simple jar #### - le récupérer #### - gérer ses logs ] .right-column[ * cq5-cookbook/recipes/log.rb ```ruby include_recipe 'it-splunkforwarder::default' ``` * cq5-cookbook/attributes/log.rb ```ruby default.splunkforwarder.inputs = [ {"input_type" => "monitor://", "input_path" => "#{node['cq5']['log_dir']}/error.log", "input_vars" => {"source" => "cq_error.log", "sourcetype" => "log4j" } }] ``` ] --- layout: false .left-column[ ## Comment ? ### - un simple jar #### - le récupérer #### - gérer ses logs #### - haute dispo ] .right-column[ * mon-chef-repo\roles\cq5_server.rb ```ruby name "cq5_server" description "CQ5 Server Role" run_list "recipe[chef-client::delete_validation]", "recipe[chef-client]", "recipe[ntp]", "recipe[cq5]" ``` * mon-chef-repo\roles\load_balancer.rb ```ruby name 'load_balancer' description 'haproxy load balancer' run_list('recipe[haproxy::app_lb]') override_attributes( 'haproxy' => { 'app_server_role' => 'cq5_server' } ) ``` ] --- class: center, middle ![overview](img/simple-jar.png) --- class: center, middle ![overview](img/simple-jar2.png) --- layout: false .left-column[ ## Comment ? ### - un simple jar ### - un middleware ] .right-column[ * Mise en place de JBoss Data Grid (JDG) Il faut donc: * installer le jdk * déploiement de policy 'security-manager' * installer et configuer le jdg (v6) de manière complétement **automatisée** * intégration avec le système * script de démarrage (service) * journaux et liens symboliques * ouverture de port (firewall) * montage de systèmes de fichiers distants * mise à jour des règles SE Linux * mise à jour des binaires ] ??? presenter's notes: Alors de manière similaire au cas décrit par François, moi aussi, dans mon travail de tout les jours je dois assurer l'installation de "bouzin" en Java - et, étrangement, surtout ceux que Red Hat supporte (bizarrement, j'installe rarement du Spring...). Un de nos produits récent - et honnêtement, est JBoss Data Grid. Conçu pour remplacé JBoss Cache, ce produit permet de mettre en place une "grille de données". C'est donc, pour simplifier, une source de données de type NoSQL, qui distribue le stockage des données qu'on lui confie, sur plusieurs noeuds. Ainsi, Data Grid peut aisément monter à l'échelle, car, si on a besoin de plus d'espace, on rajoute simplement des noeuds. Par la magie d'un algorithme de hashage, quelques soit le nombre de noeuds formant la grille, le programme client sera toujours en mesure de déterminer quel noeud possède son information. Bref, c'est génial, c'est "cloud", c'est "scalable", etc... (dans la prochaine version, ça fera aussi le café et s'attaquera à la faim dans le monde) Plus sérieusement, c'est bien gentil de monter en charge, mais si il me faut un admin et deux heures pour agrandir (ou réduire) la taille de ma grille, c'est quand même pas très, très pratique, il faut le reconnaitre. Pour tirer parti de cet aspect du produit, il est donc nécessaire de pouvoir automatiser, autant que possible, son installation et sa configuration. En plus de permettre l'automatisation, il faut aussi pouvoir déployer aisément un correctif (un changement de binaire). JDG n'est pas, comme le backend de François, un simple jars. En effet, il s'execute sur un serveur JBoss AS et est donc fait de nombreux jars, mais aussi de fichier de configuration diverses. Une mise à jour, de securité ou non, peut affecter plusieurs de ces fichiers. Enfin, comme pour François, il ne faut pas oublier notre ami la JVM. Avant même d'installer JDG, il faut bien s'assurer que cet outil d'infrastructure soit en place. Alors, à la différence notable de son cas, nous chez Red Hat, on a peu cette habitude d'utiliser des RPMs ! D'ailleurs, c'est bien parce que Puppet, il est pas bête (oh la rime), et, par défaut, quand il faut installer quelque chose sur une RHEL ou une autre distribution à base de RPM, il utilise par défaut, RPM et yum. Alors, chouette, déjà c'est réglé, on package JDG sous forme de RPM - bidon, et on demande à Puppet de simpement l'installer. Bon il faut --- layout: false .left-column[ ## Comment ? ### - un simple jar ### - un middleware ] .right-column[ et aussi: * disposer de plusieurs instances par machine * pour créer une "grille" avec un seul noeud * instance plus "petite", limite impact en cas d'échec * mettre en place le monitoring * déploiement de l'agent [Jolokia](Jolokia) ] --- layout: false .left-column[ ## Comment ? ### - un simple jar ### - un middleware ] .right-column[ installer jdg et sa jvm ```ruby node *-jdg.mygrid.com { $openjdk = 'openjdk-1.6.0' package { $openjdk: ensure => installed, } $jdg = 'jdg' package { $jdg: ensure => installed, require => Package[$openjdk] } jdg_instances = [ 'jdg1', 'jdg2', 'jdg3' ] service { $jdg_instances: ensure => running, require => Package[$jdg], } } ``` le RPM [https://github.com/rpelisse/jdg-rpm-infra](https://github.com/rpelisse/jdg-rpm-infra) ] ??? TODO: décrire le contenu du script à l'oral Et voilà, le tour est joué, on vient déjà d'implémenter les deux premiers points de notre cahier des charges. On automatisé l'installation de JDG, et on s'est surtout assurer que notre logiciel dispose de la bonne "infrastructure" (ie la bonne jvm). En outre, permet d'assurer, lors de son exécution que non seulement le produit est installé, mais aussi que le service tourne ! Bon, avant d'attaquer la suite, je laisse François reprendre son cas d'étude à lui... --- ![overview](img/path-to-prod.png) --- ![overview](img/path-to-prod2.png) --- layout: false .left-column[ ## Comment ? ### - un simple jar ### - un middleware ### - environnements ] .right-column[ chef-repo/environments/dev-stable.rb ```ruby name "dev-stable" description "Environment for dev-stable nodes" cookbook_versions( {"adobehub"=>"= 0.0.16","cq5" =>"= 0.0.13"}) override_attributes({ "apache" => {"servername" => "app-dev-stable.corp.adobe.com"}, "cq5" => {"ldap" => {"vault_conf"=> "ldap_it_ad_test_conf" , "host"=> "ldap-dev.adobe.com"}, "disabled_osgi_bundles" => ['org.apache.sling.jcr.webdav', 'org.apache.sling.jcr.davex'], "heap_max" => "2048", "permgen" => "512", "debug" => "true", "debug_port" => "30305", "logrotate" => {"frequency"=> "daily"}, "logrotate" => {"rotate"=> "30"} } ``` ] --- class: center, middle, inverse # Romain ? --- layout: false .left-column[ ## Comment ? ### - un simple jar ### - un middleware ### - environnements ### - unique, central ] .right-column[ ```ruby file { '/etc/jdg/config.xml': content => template('jdg/config.xml') require => Package[$jdg] } ``` ```ruby ...
<% if management_ip != 'UNSET' %>
<% else %>
<% end %>
... ``` ] ??? --- ![overview](img/chef-vault.png) ??? --- layout: false .left-column[ ## Comment ? ### - un simple jar ### - un middleware ### - environnements ### - unique, central ### - sécurisé ] .right-column[ ``` chef_vault_item("secrets", "dbpassword") ``` ``` node['dev_mode'] ``` ```ruby include_recipe 'chef-vault-util::default' keystore_item = chef_vault_item('password','dev-stable-keystore') jvm_keystore_password = keystore_item['password'] execute "create the server keystore p12 key file to perform 2 way ssl call as client" do command "openssl pkcs12 -export -in #{node['ssl_cert_file_path']} -inkey #{node['ssl_key_file_path']} -out #{node['ssl_p12_file_path']} -passout pass:#{jvm_keystore_password}" not_if { File.exists?(node['ssl_p12_file_path']) } end ``` ] ??? https://github.com/Nordstrom/chef-vault Gem that allows you to encrypt a Chef Data Bag Item using the public keys of a list of chef nodes. This allows only those chef nodes to decrypt the encrypted values. https://github.com/opscode-cookbooks/chef-vault Si true, les donnés seront chargé If this is true, chef_vault_item will attempt to load the specified item as a regular Data Bag Item with Chef::DataBagItem.load. This is intended to be used only for testing, and not as a fall back to avoid issues loading encrypted items. --- class: center, middle, inverse # Pourquoi? --- layout: false .left-column[ ## Pourquoi? ![Redhat](img/redhat_logo.jpeg) ] .right-column[ Chef & Puppet: une porte d'entrée * pour passer de 10 à 100 serveurs * pour gérer un parc hétérogène * vers le cloud, * un acteur continuous delivery ] --- layout: false .left-column[ ## Pourquoi? ![Adobe](img/adobe_logo.png) ] .right-column[ - *'Accelerate, Simplify, Scale'* - décloisonner les équipes, dev, de qualité, de sécurité et d'exploitation - Comme notre infra devient code, elle devient * testable * versionable * jetable * repétable - [@bdelacretaz](http://www.slideshare.net/bdelacretaz/open-development-in-the-enterprise-apachecon-na-2013) * **If it's not in the source code control system, it doesn't exist.** ] --- layout: false .left-column[ ## pointeurs ] .right-column[ .super-small[ Le slideshow * created using http://github.com/gnab/remark * hosted at http://francoisledroff.github.io/chezlesbarbus Nous contacter: * https://twitter.com/rpelisse * https://twitter.com/francoisledroff Aller plus loin: * https://github.com/rpelisse/jdg-rpm-infra * https://github.com/RiotGames/artifact-cookbook * http://www.slideshare.net/opscode/week-1-overview-of-chef * http://docs.opscode.com/chef_overview.html * http://www.getchef.com/blog/2014/01/23/attributes-or-data-bags-what-should-i-use/ * http://www.slideshare.net/jedi4ever/infrastructure-as-code-abug-session * http://architects.dzone.com/articles/infrastructure-code * http://www.slideshare.net/opscode/week-1-overview-of-chef * https://github.com/Nordstrom/chef-vault * https://github.com/opscode-cookbooks/chef-vault * https://www.youtube.com/watch?v=cuJZbRngWC0 * http://www.slideshare.net/JulianDunn/chef-introduction-princeton-meetup * https://speakerdeck.com/sethvargo/using-ruby-to-automate-your-life * http://docs.opscode.com/chef_why.html * http://blip.tv/oreilly-velocity-conference/velocity-09-john-allspaw-10-deploys-per-day-dev-and-ops-cooperation-at-flickr-2297883 * http://blog.carlossanchez.eu/2012/03/13/infrastructure-as-code/ * http://www.jedi.be/blog/2012/05/12/codifying-devops-area-practices/ * http://www.slideshare.net/KrisBuytaert/7-tools-for-your-devops-stack * http://www.slideshare.net/carlossg/from-dev-to-devops-apachecon-na-2011 * http://dev2ops.org/blog/2010/2/22/what-is-devops.html * http://www.slideshare.net/jedi4ever/vagrant-devopsdays-mountain-view-2011 * http://www.puppetlabs.com/ * http://www.opscode.com/chef/ * http://www.slideshare.net/bdelacretaz/open-development-in-the-enterprise-apachecon-na-2013 ] ] --- class: center, middle, inverse # fin #### Questions ?