9:59:59.000,9:59:59.000 Thank you everyone for coming. 9:59:59.000,9:59:59.000 If you were expecting the Postgres talk,[br]that was the one before, so 9:59:59.000,9:59:59.000 you might need to watch the video stream. 9:59:59.000,9:59:59.000 So, Ansible best practices, 9:59:59.000,9:59:59.000 I thought about calling it "Ansible,[br]my best practices", 9:59:59.000,9:59:59.000 so, just warning ahead, this is things[br]I stumbled on using Ansible 9:59:59.000,9:59:59.000 for the last 2-3 years and 9:59:59.000,9:59:59.000 those are very specific things I found[br]that worked very well for me. 9:59:59.000,9:59:59.000 About me, I do also freelance work,[br]do a lot of Ansible in there, 9:59:59.000,9:59:59.000 I'm also the Debian maintainer for[br]Ansible with Harlan Lieberman-Berg 9:59:59.000,9:59:59.000 If there are any bugs in the package,[br]just report them. 9:59:59.000,9:59:59.000 The talk will be roughly divided into[br]4 parts. 9:59:59.000,9:59:59.000 The first part will be about why you[br]actually want to use config management 9:59:59.000,9:59:59.000 and why you specifically want to use[br]Ansible. 9:59:59.000,9:59:59.000 So, if you're still SSHing into machines[br]and editing config files, 9:59:59.000,9:59:59.000 you're probably a good candidate[br]for using Ansible. 9:59:59.000,9:59:59.000 Then, the second part will be about good[br]role and playbook patterns 9:59:59.000,9:59:59.000 that I have found that work really well[br]for me. 9:59:59.000,9:59:59.000 The third chapter will be about typical[br]antipatterns I've stumbled upon, 9:59:59.000,9:59:59.000 either in my work with other people[br]using Ansible, 9:59:59.000,9:59:59.000 or the IRC support channel, for example. 9:59:59.000,9:59:59.000 The fourth part will be like advanced[br]tips and tricks you can use 9:59:59.000,9:59:59.000 like fun things you can do with Ansible. 9:59:59.000,9:59:59.000 Quick elevator pitch, what makes config[br]management good? 9:59:59.000,9:59:59.000 It actually also serves as a documentation[br]of changes on your servers over time 9:59:59.000,9:59:59.000 so if you just put the whole config[br]management in a git repo 9:59:59.000,9:59:59.000 and just regularly commit, 9:59:59.000,9:59:59.000 you will actually be able to say 9:59:59.000,9:59:59.000 "Why doesn't this work? It used to work[br]a year ago" 9:59:59.000,9:59:59.000 You can actually check why. 9:59:59.000,9:59:59.000 Also, most config management tools have[br]a lot better error reporting than 9:59:59.000,9:59:59.000 your self-written bash scripts that do[br]whatever. 9:59:59.000,9:59:59.000 And usually, you have a very good[br]reproducibility with config management 9:59:59.000,9:59:59.000 and also idempotency, meaning that if you[br]run, for example, a playbook several times 9:59:59.000,9:59:59.000 you will always get the same result. 9:59:59.000,9:59:59.000 Also, it's great if you work in small team[br]or you admin ??? in the company 9:59:59.000,9:59:59.000 and you have some people working[br]on a few things too. 9:59:59.000,9:59:59.000 It makes team work a lot easier and[br]you will save a lot of time actually 9:59:59.000,9:59:59.000 debugging things when things break. 9:59:59.000,9:59:59.000 What makes Ansible good? 9:59:59.000,9:59:59.000 Comparing it to Chef or Puppet for example[br]it's really easy to set up, 9:59:59.000,9:59:59.000 you start with two config files, you have[br]it installed and you're ready to go. 9:59:59.000,9:59:59.000 It's also agentless, so whatever machines[br]you actually want to control, 9:59:59.000,9:59:59.000 the only thing you they really need to have[br]is an SSH daemon and Python 2.6+ 9:59:59.000,9:59:59.000 so that's virtually any Debian machine[br]you have installed and 9:59:59.000,9:59:59.000 that ??? 9:59:59.000,9:59:59.000 Ansible also supports configuration[br]of many things like 9:59:59.000,9:59:59.000 networking equipment or even Windows[br]machines, 9:59:59.000,9:59:59.000 they don't need SSH but they use the[br]WinRM 9:59:59.000,9:59:59.000 but Ansible came a bit late to the game[br]so Ansible's still not as good 9:59:59.000,9:59:59.000 in coverage like for example Puppet, 9:59:59.000,9:59:59.000 which literally, you can configure any[br]machine on the planet with that, 9:59:59.000,9:59:59.000 as long as it has a CPU. 9:59:59.000,9:59:59.000 Next step, I will talk about good[br]role patterns. 9:59:59.000,9:59:59.000 If you've never worked with Ansible[br]before, 9:59:59.000,9:59:59.000 this is the point when you watch[br]the video stream, 9:59:59.000,9:59:59.000 that you pause it and start working[br]a few weeks with it 9:59:59.000,9:59:59.000 and then unpause the actual video. 9:59:59.000,9:59:59.000 A good role should ideally have[br]the following layout. 9:59:59.000,9:59:59.000 So, in the "roles" directory, you have[br]the name of the role and task/main.yml 9:59:59.000,9:59:59.000 You have the following rough layout. 9:59:59.000,9:59:59.000 At the beginning of the role, you check[br]for various conditions, 9:59:59.000,9:59:59.000 for example using the "assert" task to[br]for example check that 9:59:59.000,9:59:59.000 certain variables are defined, things[br]are set, 9:59:59.000,9:59:59.000 that it's maybe part of a group, things[br]like that you actually want to check. 9:59:59.000,9:59:59.000 Then, usually, you install packages, you[br]can use apt on CentOS machines, 9:59:59.000,9:59:59.000 yum, or you can do a git checkout or[br]whatever, 9:59:59.000,9:59:59.000 then usually you do some templating of[br]files where you have certain abstraction 9:59:59.000,9:59:59.000 and the variables are actually put into[br]the template and 9:59:59.000,9:59:59.000 make the actual config file. 9:59:59.000,9:59:59.000 There's also good to point out that[br]the template module actually has 9:59:59.000,9:59:59.000 a "validate" parameter, 9:59:59.000,9:59:59.000 that means you can actually use a command[br]to check your config files for syntax errors 9:59:59.000,9:59:59.000 and if that fails, your playbook will fail[br]before actually deploying that config file 9:59:59.000,9:59:59.000 so you can for example use Apache with[br]the right parameters to actually do 9:59:59.000,9:59:59.000 a check on the syntax of the file. 9:59:59.000,9:59:59.000 That way, you never end up with a state[br]where there's a broken config. 9:59:59.000,9:59:59.000 In the end, you usually… 9:59:59.000,9:59:59.000 When you change things, you trigger[br]handlers to restart any ??? 9:59:59.000,9:59:59.000 If you use variables, I recommend putting[br]sensible defaults in 9:59:59.000,9:59:59.000 defaults/main.yml 9:59:59.000,9:59:59.000 and then you only have to override[br]those variables on specific cases. 9:59:59.000,9:59:59.000 Ideally, you should have sensible defaults[br]you want to have to get whatever things 9:59:59.000,9:59:59.000 you want to have running. 9:59:59.000,9:59:59.000 When you start working with it and do that[br]a bit more, 9:59:59.000,9:59:59.000 you notice a few things and that is 9:59:59.000,9:59:59.000 your role should ideally run in "check mode". 9:59:59.000,9:59:59.000 "ansible-playbook" has --check that[br]basically is just a dry run of 9:59:59.000,9:59:59.000 your complete playbook 9:59:59.000,9:59:59.000 and with --diff, it will actually show you[br]for example file changes, 9:59:59.000,9:59:59.000 or file mode changes, stuff like that 9:59:59.000,9:59:59.000 and won't actually change anything. 9:59:59.000,9:59:59.000 So if you end up editing a lot of stuff,[br]you can use that as a check. 9:59:59.000,9:59:59.000 I'll later get to some antipatterns that[br]actually break that thing. 9:59:59.000,9:59:59.000 And, ideally, the way you change files[br]and configs and states, 9:59:59.000,9:59:59.000 you should make sure that when the actual[br]changes are deployed, 9:59:59.000,9:59:59.000 and you run it a second time, 9:59:59.000,9:59:59.000 that Ansible doesn't report any changes 9:59:59.000,9:59:59.000 because if you end up writing your roles[br]fairly sloppy, you end up having 9:59:59.000,9:59:59.000 a lot of changes and then, 9:59:59.000,9:59:59.000 in the end of the report, you have like[br]20 changes reported and 9:59:59.000,9:59:59.000 you kind of then know those 18,[br]they're always there 9:59:59.000,9:59:59.000 and you kind of miss the 2 that are[br]important, that actually broke your system 9:59:59.000,9:59:59.000 If you want to do it really well, you make[br]sure that it doesn't report any changes 9:59:59.000,9:59:59.000 when you run it twice in a row. 9:59:59.000,9:59:59.000 Also, a thing to consider is you can define[br]variables in the "defaults" folder 9:59:59.000,9:59:59.000 and also in the "vars" folder, 9:59:59.000,9:59:59.000 but if you look up how variables get[br]inherited, you'll notice that 9:59:59.000,9:59:59.000 the "vars" folder is really hard to[br]actually override, 9:59:59.000,9:59:59.000 so you want to avoid that as much as[br]possible. 9:59:59.000,9:59:59.000 That much larger section will be about[br]typical anti-patterns I've noticed 9:59:59.000,9:59:59.000 and I'll come to the first one now. 9:59:59.000,9:59:59.000 It's the shell or command module. 9:59:59.000,9:59:59.000 When people start using Ansible, that's[br]the first thing they go 9:59:59.000,9:59:59.000 "Oh well, I know how to use wget or I know[br]'apt-get install' " 9:59:59.000,9:59:59.000 and then they end up using the shell module[br]to do just that. 9:59:59.000,9:59:59.000 If you use the shell module or the command[br]module, you usually don't want to use that 9:59:59.000,9:59:59.000 and that's for several reasons. 9:59:59.000,9:59:59.000 There's currently, I think, 1300 different[br]modules in Ansible 9:59:59.000,9:59:59.000 so there's likely a big chance that[br]whatever you want to do, 9:59:59.000,9:59:59.000 there's already a module for that, that[br]just does that thing. 9:59:59.000,9:59:59.000 But those two modules also have several[br]problems and that is 9:59:59.000,9:59:59.000 the shell module, of course, gets[br]interpreted by your actual shell, 9:59:59.000,9:59:59.000 so if you have any special variables[br]in there, 9:59:59.000,9:59:59.000 you'd actually also have to take care of[br]any variables you interpret in the shell string. 9:59:59.000,9:59:59.000 Then, one of the biggest problems is if[br]you run your playbook in check mode, 9:59:59.000,9:59:59.000 the shell and the command modules[br]won't get run. 9:59:59.000,9:59:59.000 So if you're actually doing anything[br]with that, they just get skipped 9:59:59.000,9:59:59.000 and that would cause that your actual[br]check mode and the real mode, 9:59:59.000,9:59:59.000 they will start diverging if you use[br]a lot of shell module. 9:59:59.000,9:59:59.000 The worst, also, bad part about this[br]is that these two modules, 9:59:59.000,9:59:59.000 they'll always ??? changed 9:59:59.000,9:59:59.000 like, you run a command and it exits 0 9:59:59.000,9:59:59.000 it's like "Oh, it changed" 9:59:59.000,9:59:59.000 To get the reporting right on that module,[br]you'd actually have to define for yourself 9:59:59.000,9:59:59.000 when this is actually a change or not. 9:59:59.000,9:59:59.000 So you'd have to probably get the output[br]and then check, for example, 9:59:59.000,9:59:59.000 if there's something on stderr or something[br]to report an actual error or change. 9:59:59.000,9:59:59.000 Then I'll get to the actual examples. 9:59:59.000,9:59:59.000 The left is a bad example for using[br]the shell module, 9:59:59.000,9:59:59.000 I've seen that a lot, it's basically 9:59:59.000,9:59:59.000 "Yeah, I actually want this file, so just[br]use 'cat /path/file' and I'll use 9:59:59.000,9:59:59.000 the register parameter to get the output". 9:59:59.000,9:59:59.000 The actual output goes into the "shell_cmd"[br]and then 9:59:59.000,9:59:59.000 we want to copy it to some other file[br]somewhere else and 9:59:59.000,9:59:59.000 so we use the Jinja "{{ }}" to define[br]the actual content of the file 9:59:59.000,9:59:59.000 and then put it into that destination file 9:59:59.000,9:59:59.000 That is problematic because, first of all[br]if you run it in check mode, 9:59:59.000,9:59:59.000 this gets skipped and then this variable[br]is undefined and 9:59:59.000,9:59:59.000 Ansible will fail with an error, so you[br]won't be able to actually 9:59:59.000,9:59:59.000 run that in check mode. 9:59:59.000,9:59:59.000 The other problem is this will always[br]??? 9:59:59.000,9:59:59.000 so you'd probably have to… 9:59:59.000,9:59:59.000 the most sensible thing would probably[br]be to say just "changed when false" 9:59:59.000,9:59:59.000 and just acknowledge that that shell[br]command won't change anything on this system 9:59:59.000,9:59:59.000 The good example would be to use the[br]actual "slurp" module that will 9:59:59.000,9:59:59.000 just slurp the whole file and base64encode it 9:59:59.000,9:59:59.000 and you can access the actual content with[br]"path_file.contents" and you then just 9:59:59.000,9:59:59.000 base64decode it and write in there. 9:59:59.000,9:59:59.000 The nice thing is slurp will never return[br]any change, so it won't say it changed 9:59:59.000,9:59:59.000 and it also works great in check mode. 9:59:59.000,9:59:59.000 Here's an other quick example. 9:59:59.000,9:59:59.000 The example on the left, oh yeah wget. 9:59:59.000,9:59:59.000 Here's the problem, every time your playbook[br]runs, this file will get downloaded 9:59:59.000,9:59:59.000 and of course if the file can't be[br]retrieved from that URL 9:59:59.000,9:59:59.000 it will throw an error and that will[br]happen all the time. 9:59:59.000,9:59:59.000 The right example is a more clean example[br]using the uri module. 9:59:59.000,9:59:59.000 You define a URL to retrieve a file from,[br]you define where you want to write it to 9:59:59.000,9:59:59.000 and you use the "creates" parameter to say 9:59:59.000,9:59:59.000 "Just skip the whole thing if the file is[br]already there".