 Hey everybody, welcome to the Galaxy Admin Training session on using Ansible. This session assumes that you've already went through the slides on the training material page and we're going to follow with the hands-on. The start of this session reiterates what most of you should already know from going through the slides and we'll only run very quickly through it. If you need to read more on it, feel free to pause the video obviously at any point and read the documents and materials that are linked from here. So Ansible is a tool that you can use to run commands on remote computers. The very interesting part of it is that you don't have to install Ansible on the remote computers in order to run the Ansible against those which allows you for transparent administration of those machines. It allows you for moving files around, configuring things, starting processes, scaling processes, basically whatever you're capable of doing with command line utilities. You can also do that with through an Ansible path. There are some other softwares that do similar things to Ansible, like Ansible, like Puppet or Shift, but in Galaxy world most of the things are written for configuration management is using Ansible, so that's a very good reason for also using Ansible for your own Galaxy. Since you're going to be able to reuse a whole bunch of materials and code already written by the members of the community. Let's quickly run through these basic terms of what we encountered when working with Ansible. The basis of everything is something called inventory file which contains either URLs or IPs or other identifiers of the actual machines you want to affect with the Ansible script. The other part that you might be interested in is called Ansible module which you can think of as a piece of a Python code which is reusable and configurable for a certain usually very atomic purpose. So something like a command or a move file or copy file, those would be modules in this context. Then there is a bigger unit of work called task which usually consists of a specific module or more and contains variables and configuration of how to invoke like in the example of copying like where is this, where is the source of this file that we're going to copy and where it should be copied to sort of like a destination. Even bigger unit in this hierarchy is something called a role which contains not just the tasks with the configured modules inside but also the actual files that should be copied like the contents of them. These could also be templated and all this together is called a role and this is a very useful unit to share. So Ansible has its own website where you can share these roles and we have many of these roles ready to roll for the Galaxy administration purposes. So anybody can grab these roles and use them in their own configuration for their own Galaxy deployment. When you actually want to execute the roles against a specified set of servers or just one, you make something called a playbook which is a file written in the NAML format and it lists all the high level information for the Ansible to be able to execute all the tasks you specified. So it lists where the host file is, what roles it should be using, what configuration, what variables are available and things like that. A special part of Ansible is something called WALT which you can use for storing and sharing encrypted information which in the end will allow you to, if you imagine having the Ansible code and all these tasks roles and playbooks in your Git repository version. If you include a WALT this will allow you to share production level configured playbook publicly because only the pretty chosen people will have the passwords to access the WALT which for everybody else will be encrypted and unreadable. We've talked about the inventory file. This is roughly how it looks. It specifies groups of servers and here we can see two of them. One is called web servers, one is called databases but they can also be called my great servers and the green servers or any other number of these groups and they're usually specified either by IP or by URL and you can specify some other things. For example, what is the name of the user that Ansible should be connecting as when it's executing the tasks it's given. The roles can sometimes look a little bit scary because there can be many folders. What you're looking at here is a folder structure. So the leftmost folder is the root folder and there are folders in there called defaults, files, handlers, meta tasks, templates and vars and each of these folders contain some sort of configuration for Ansible pieces that we're going to execute. I think this is taken from an actual real role from the Galaxy project that's used to configure and manage the CMFS and as with I would say all of the Galaxy project Ansible roles, this one is also public and shared and everybody's encouraged to use it, contribute and just benefit from. So this is an actual real role hierarchy and structure would look like and here's some description of what the folders are meant for. The most important folder of every role you're ever going to see is called the tasks and that's the one that contains the glues everything together. So in the other folders there are default variables, the files to copy or to use the templates to fill with various runtime data or even like configuration data. But the tasks is where it all comes together and where you can see where things are coming from when they're connected. So if you're exploring a role for the first time start with the tasks folder. Here's an example of a task file. So this one is in a folder called tasks and it's called main.yaml probably because it's either the only one or the most important one. And here you can see two tasks or it's two module calls. Here is a task for downloading CMFS preload it's a machine and the module is called get underscore URL and all these variables are fairly straightforward. It receives a URL where the things are stored. It gives us about the destination where this should be downloaded to and who should own the file both owners and group and what should be the read mode or the execute mode on the once downloaded. And then there's an extra step that checks that this task is only executed only when this variable is true. So when it's required. And this here in the bottom is another another task it's going to call the service module and what it's supposed to do is that it makes sure that the autofile system is enabled which is here and also that it's running not just enabled but it's actually running at that point so if it's not running it will store it if it is running it will just let me be. And that's another feature or sort of architectural design of Ansible that it's trying to be do some extent idempotent of number of executions. So no for example these two tasks no matter how many times you execute the playbook that is executing these tasks the system should end up in the very same state. So this task it's not going to turn off and on the autofile when it's running it will leave it on when it's not running it will start it when the service is not enabled it will enable it but when it's enabled it will leave it enabled. So and that's something that you can often take advantage of when working with Ansible because this can be very very powerful. It can also be sometimes a bit scary because you can break this functionality so if you rely on it too heavily and then your playbook is for example doing something that just cannot be redone at the same state like if it's a committing code into repository then every commit will end up with different hash so Ansible cannot really do it the exact same way. So you can take advantage of it but you should be aware of its limitations. There are some stylistic choices that needs to be made when working with Ansible. Namely there are two main styles how to write the YAML files for Ansible. One is that you use these indented variable names and module names or you can define all these in line. This is a matter of preference. Most of Galaxy project Ansible roles I've seen are using the first style which is what we're going to follow but sometimes you can see these so don't get scared. These are the same they're just written in slightly different syntax. Now we get to the playbooks which again is the sort of topmost file that you interact with when working with Ansible and in this you define what's going to happen from the from sort of like executive standpoint like these servers set variables for all the roles and tasks we're going to run to these values and then execute these roles and this sort of defines how this is going to operate once you once you run it. There are some notes on philosophies on how to design your playbooks whether they should take care of an atomic operation on the remote server or whether they should take care of one set of things that's related to for example one service. These are up to you Ansible does not dictate what should the approach be but generally try to choose one and stick to it. As far as I know Galaxy is usually trying to stick to a single playbook that does everything for a given service. So as we touched a couple of times already Ansible playbooks and send roles can use variables and these variables can be defined in many places in fact there are probably like 30 of these places where these variables can be and there is an order of precedence. So sometimes when you when you run into trouble with you know some tasks not behaving as it should scoping to a wrong file scoping to a wrong destination or something like that make sure to make sure you understand what variables are actually going to are actually being used for the playbook execution. Now this is for the first section I think the walls will leave for the for the very end so get ready for your first playbook and your first role. Your first playbook and your first Ansible role. So I changed the setup a little bit now you should see the training material on the left on the screen and on the right you'll see my terminal. So I'm going to get one of the galaxiabin training machines each of you should have your own machine to connect to and nobody should be sharing the machine since we're going to work in the same directories you don't want to clash with someone else I'm modifying the same files. So I assume all of you have that if you don't please post this video go obtain your URL and username and password and connect to your machines once you're ready let's go. One thing to be aware of is that Ansible is a tool and a very powerful one and if you use it in the wrong way you can break things so Ansible can delete things Ansible can move things override things generally it can destroy stuff so until you're fairly confident that you know what you're doing I recommend to work in sort of a sandbox settings just like for the galaxiabin training you have a virtual machine that if you just completely burn it down it's fine you can just get a new one by the way just if you need a new one let me know in the chat or on the slide I know I'll get you one nevertheless just be aware of these tools powered and stay safe there are some options that you can you can use when running Ansible the dash dash diff and dash dash check and these are going to sort of test what's going to happen when you actually run so it's sort of a fake run of the playbook it has limited insights of what's actually going to happen because you cannot predict completely what's going to happen on the specific machine when you run these commands so but Ansible is trying to give you its best guess at what is going to change so you can inspect for example diffs like differences between files that you are trying to modify so let's hop into it let's create the basic role so I'm currently logged in as a Ubuntu user and I'm in my home directory I believe so I'm going to run through these tasks of creating a role the first step we already have because we're all in the virtual machines the second step install Ansible is already solved for us too because all these machines have Ansible installed so let's start with the bullet point number three create directory named intro and changed into it so to create the directory let's mkdir and we'll call an intro and I will enter it there we go now we want to create the inventory file the generally the general name for it is hosts and for creating and manipulating and changing files feel free to use any editor you would like I'm going to use nano so let's create file code hosts and then we will create a group and code my hosts which is specified like this and now we specify where the Ansible like a destination for the Ansible to execute and because we want to execute locally we want to run Ansible from the same machine that we are affecting we're going to specify the host as local host the Ansible connection parameter we will set to local and the Ansible user parameter will set to Ubuntu I believe since that's our user on this on this machine that's what everybody should be logged in at and then we save the file and here if you want you can you can check whether the decisions you made in choosing these variables is correct also if you fall behind with any point or if you just feel lazy typing there is a convenient copy button in most of these just that are throughout the training so if you just copy that you'll get the whole contents of such and you can just paste it in your editor in a terminal further we're going to create the directory for the tasks that we're going to write in Ansible and so again we're creating directories this time it's multiple directories at once so we're going to use the dash p so we want to create roles directory we want to create my role sub directory of that and want to create the tasks so all these directories should be not created and now we're supposed to create the actual file with tasks written in YAML so I'm going to enter the path to this file and name it main.yaml since it's probably going to be the only one that we're going to use so let's go with main. Now we're writing YAML and we want to do just one task we want to copy a file to a remote host so the remote host here is defined by the host names so what we're actually going to do is we're going to copy a file locally since we are the remote host in this context but nevertheless it should do something on our behalf and it doesn't matter what the destination is at least it doesn't matter to the YAML so I'll name the task this is completely arbitrary you can name it whatever now we select what module we're going to use we want to use the module called copy and we'll give it some parameters so we'll give the parameter called sorts and we say you should copy file called test.txt and we'll give it the parameter destination or test which says and this file that you found called test.txt copied to a temporary folder under slash that slash dmp now now we say this save this that's our first task so we're using a module called copy this of course has its own documentation and it has a listing of things that you can use listing of modes that you can use when copying things and generally whatever you're trying to do in Ansible you usually want to use an already made module or task or role or playbook of somebody else unless like until you feel confident enough to to write your own and better ones and now we need to create the file itself so we selected it we wrote a task that tells Ansible hey take this file and copy it there but we don't have the test.txt file yet so let's create that and for this purpose we'll create another folder where we can drop these files and we'll put it under the same role because it's uh it's connected to the role we're running so I create this folder roles models files and I'm going to create the file next and we'll call it test.txt because that's how we named it in the task and inside we can write whatever we want um write our galaxy and save that file so we have the task we have the actual file that should be copied and now we need a playbook to glue this together until galaxy um what it should do with what files and what hosts so we're going to create a file called playbook in the root folder playbook.demo and now we write demo again and we'll write um so this playbook will run on these hosts this is the name that I've chosen in my host file this is the name of the group my hosts and I'll select which roles it will run on and I want to run it on only one role that's called my role which corresponds to the to the folder structure that I've created and I'll save this playbook and so we created a bunch of files and some folder structure and we can run the playbook but before that let's make sure that we put things in the in the correct places since this is the first time we're putting it there so we can use the tree command which everybody should have available their path um to see how the folder structure underneath the current intro folder looks like so we have a file called hosts a file called playbook demo and then a directory called roles and in the roles directory there's a role called my roles and this should be my role right yeah made a typo so this is the set of roles and these my roles should be the ones uh should be the one that I've created so let's just move this whole folder oh it's in roles right so this role should be my role and we can play that by checking the playbook and this is the roles name that we're invoking so now we can run it so for running playbook we use ansible dash playbook command which is part of the ansible installation so if you have the ansible command you also have the ansible playbook command um we give it dash i hosts parameter which says inventory and then the name of the file that has the inventory in it for us that's the hosts file it's also the default and then we'll give it the path to the playbook itself which for us is just in the root folder so we're running ansible playbook command on hosts inventory and the playbook we want to execute is called playbook.ian so and this is the output of ansible lots of afterisks but all sorts of information about every step that's happening so the most important step for us at the moment is this my role task execution which is supposed to copy the file to the remote host and here in the output we can see that ansible says changed on local host changed means that ansible did something on the remote server with regard to this task and generally if there is no errors it should be successfully making whatever you asked it to so let's check so what we thought ansible to do is to take the file and copy it to the temporary directory so let's see if there is some file in temporary directory that is called test.txt there is and it contains the hello galaxy so this is not where we've created the file this is where we copied the file using ansible so ansible did that on our behalf there are some ideas in the tutorial that you can use for getting a sort of more experience with running basic playbooks but i'll leave that to your discussion there's another interesting part of this playbook execution that we just ran through that we did not define so this that we did this is the my role that we created but this task called gathering facts is not our making but it succeeded which i guess is good but it's also would be good to know what it's happened what happened there so this is a default ansible task that ansible will always run on your behalf in the beginning of of every playbook and what it does is it runs the setup module and the setup module loads all the informations and facts and variables of the host and then the playbook itself and all the tasks tasks and roles that are called from within it are able to use all these facts so things like the ip of the machine they're running on or its configuration its environment variables its operation system its runtime values and things like that and you can explore what is being returned to ansible from the remote hosts if you run the setup module by itself on the host so we're going to invoke the ansible command on the same inventory so we're executing it on our own machine that's listed in the host file and we're running the module called setup on the group of my hosts which again is what we did and we're piping into the to the less page browser and what we got is a whole bunch of probably JSON of sorts that specify that lists all the information that ansible was able to get from our system and therefore all this information are available to whatever tasks and roles you want to execute in the playbook which could be very useful for for many purposes one of the purposes it could be used for is that different operating systems could have a different responses to certain commands so you want to use the command that's specific to the operating system that you're calling this should not be the case in general like if you're copying you should always just use the copy module and ansible will properly use it on all the destinations on all the hosts but there can be cases where where where these operating system differences will play um will play a role so there's a question for us to solve what variables stores the os name so for that we can we can explore the output of this ansible call and we can grab for distribution seems ansible distribution is subuntu which we knew since our username is subuntu but at least now we know the version the version should be 2004 another question here is where all the places you can find your machine's ip ipv4 let's check for ipv4 yep that sounds like it so ansible default ipv4 ansible all ipv4 addresses looks like the the variables that we would use if we want to use the the ip of our hosts in our tasks or roles the next interesting application is our the the templated files the templated files or templates you would use when you want to distribute a file across systems but that file is slightly different depending on where you're copying it um so let's run through an example so to to clarify what exactly this does so we're going to create a bunch of directories again uh first we're creating the directory for templates we're also going to create directory for defaults since templates you're going to follow with variables and it's useful to have um to have defaults for those values and now we're going to create um a variable file for my role which lives under roles my role defaults and we call it main.yaml and i'm writing yaml again and we're going to specify one variable called server name and the value of such will be sharks so now we have a server name defined here in the main.yaml as a default value and then we're going to create the template itself so for templating for for templating ansible uses a template engine called ginger um which is not entirely unreasonable um and generally you can find that where the template is being used where the template where the templating is being used that's where the double curly braces occur so in the examples below you can see that this all these curly braces mean that the templating is going to insert the value of the of this of this variable before the playbooks or the roles execution so back to our example we created the variable file and now we're going to create a template file so we're going to create this uh this file called test dot i and i does the j2 j2 is the ginger oh i see you cannot see that let me clear the console that's why i move up and now i will create the test of i and i the j2 file and we can now insert the contents so i'm going to create an example template which sets the server name to whatever server name is defined at the time of execution and it also sets the listen variable or environment variable to whatever whatever is available as the default ipv4 address which will be provided by the by the ansible setup module that we explored a couple minutes ago so now i'm saving this test i and i which is templated and now we're going to add a task to our role because we want to use this template to fill it with variables and then write it somewhere so i'm going to open my role which has tasks defined in this main.yaml file so roles my role tasks main.yaml this is the step number six here and here's my first task that's already here that was the copying of file to remote host where we were copying to the test.txt file and we'll create another task here which we will name um template configuration file maybe and we're going to use the module called template and it behaves fairly similarly to the module copy it's going to have a source which for us is the test.ini.j2 that's the file we created as the source of the template and it's going to have a destination because templating is used for for writing files to remote destination filled with the variables that are important to us so we'll write this file in the temporary directory again under test.ini file so we're dropping the j2 suffix since after this modules run after this templates run it will no longer be a template because it will be filled with the variables that are available to to the playbook execution so i saved that and now we should run the playbook again so we run the ansible playbook we're running we're operating on the same inventory called host and we're running playbook.yml so we can see that there is one extra task for my role so the first task was to copy the file to remote host and that has not changed because the file is present at the destination and ansible checked that for us so it's not going to redo that but there is a new task that we created to template the configuration file and that one reports to be changed so ansible is claiming that it did what we asked for so let's check if there is test.ini in the temporary directory and there is and it has been templated since we can see that the server name is sharks that's not the value in the template it's the value in the variable file and then it also templated the ipfr machine which it got from the setup module of ansible so this has worked so we templated a file with the defaults that we defined for a given role now when you're actually using roles that were written by someone else you're instead of changing the defaults of that role which is not for you to modify you usually create your own variable folder or variable files that take precedence of whatever was supplied with the role so we're going to create create a folder called group wars which is where generally these user or user supplied variables are going to be stored and we're going to create a variable file there called myhosts.yml we're calling it like that because that's the group you know inventory file that we're operating on and this signifies that these variables are specific to those machines defined within that group they're not applicable for others and now we're writing yaml again and we will overwrite the default for the server name so instead of cats, sharks, dogs, we'll have dragon zombies and now we're actually overriding the defaults so maybe this could be a nice time to check what ansible thinks is going to happen so instead of running playbook like this the ansible playbook dash i hosts playbook yaml i'm going to add the check flag and the diff flag so this is not doing a test run so the first tasks aren't interesting anymore because we're not changing those but this is the one we changed we changed the templating of the configuration file and now instead of just writing hey this has changed and ansible done that it's actually showing us a diff of what ansible thinks is going to happen so it's saying that there is uh to be there's going to be a change in the server name and from sharks it will be changed to dragon zombies sounds good i think this is what we wanted when we were changing the variables so i'm going to delete the drarun options and just execute the playbook and now ansible is just saying yes that's what i did um go see for yourself which i'm going to do so let me check what the what the values are within the s.ini so the server name has been changed to dragon zombies so it's now ignoring the default and it's consuming the variable that we specified in the in the group vars folder so that's what we did we used a whole bunch of variable templating and you can use these almost anywhere in ansible they can be used in tasks they can be used in roles they can often be used in playbooks there are also ways how to how to get variables at the execution time of the playbook so not before the run or at the beginning of the run but you can actually sort of uh trickle variables from early tasks of the playbook into the late tasks of of the same playbook well good job everybody now we've created our own small role that uses multiple modules and even uses templating and runs against our defined inventory and if we wanted to share this role or if we wanted to download and use roles of others and there's something called ansible galaxy which is a service provided by ansible so it has no relations to galaxy project it's provided by ansible and it's sort of app store for ansible roles so whenever you create something that you think could be useful to share you can upload it there it's sort of just a service like any other with a web interface where you can search for roles that others shared what I'm going to search for here is the example role that we're going to install in our and run within our own playbook and it's called memcached its author is the Jeff Geerling which is this sort of ansible galaxy powerhouse that has created dozens maybe hundreds of high value high quality ansible roles that people all around the world are happy to use so what we're going to do in the first step is that we're going to use the ansible galaxy command which is part of the ansible installation to install the role from Jeff Geerling called memcached and we'll install it into the folder called roles so I'll just copy the command from the tutorial and execute and the ansible galaxy we're going to download all the files and put them into the roles folder by checking to my roles folder I can see that the memcached is now stored here so the next step we need to do is to actually put into our playbook the link link to this role that we wanted being installed and managed by ansible so we're modifying our playbook.yaml and we'll add a geerlingguide.memcached role under my roles under my role in the roles section of this playbook then we save and now when we execute the playbook the memcached framework for caching should be installed together with the execution of the rest of our playbook so again we'll operate on our host file and we'll give the ansible playbook command the playbook.yaml path however we received an error which in this case is expected so what this is going to tell is that the repermission is denied in the step install.memcached so the problem here is that our playbook and our ansible playbook command operates as the user ubuntu and the user ubuntu on this machine does not have permissions to install stuff so what we need to do is we need to use sudo or sort of become super user for this particular task within the ansible execution so ansible has means how to do that and what we need to do is we need to change our playbook so in the playbook.yaml under these hosts entries my hosts we need to add become true which tells ansible to become a super user when executing this playbook so I'll save that and we will rerun the playbook again so I'm rerunning the same command with the same playbook which I only enhanced with the become true entry so I did not immediately fail which is a good sign so hopefully we'll get installed soon and there are some other ways how you can how you can specify whether something should be run as a super user whether some command should be run with sudo whether ansible should ask for passwords when it's when it's needed and such generally what you should do when you're operating on the remote system you should reduce the lowest permissions that are needed for a for a given task but this will often depend on what the policy of the machine you're working on is so our role installed correctly or the role installed the role executed correctly so we have a memcache now installed on the machine including the default configuration since we didn't change anything in the default config so we're running memcached on whatever configuration was provided by default by the jeff geerling the author of the of the role in the end of this session there is a write-up about how to choose a role from from from galaxy ansible from or from ansible galaxy and there are no easy ways how to how to answer that you need to look into whether other people are using it whether it has a good documentation whether from whatever you're able to parse it looks reasonable and then maybe test it before you actually deploy it on on on something that you care about however there are some there are some namespaces that you can use for filtering so for example things that are written by jeff geerling are most of the time of very high quality in the same manner we recommend using the galaxy project and use galaxy dot underscore eu ansible roles which are oftentimes the the best roles to use for maintaining a galaxy instance another feature that's very useful in ansible is something called ansible fault which allows you to encrypt secrets related to usually the hosts that you're using the inventory you're deploying to and then ship it together with the with the code for configuration management with the roles and tasks and playbooks so this allows you to keep everything together but also to keep it safe since the world is is encrypted and it allows for nice sharing of production level playbooks so for example use galaxy dot eu and use galaxy dot org are sharing all of their playbooks that maintain the infrastructure and the galaxy instances and then surrounding services together with the secrets but all the secrets are obviously encrypted using the ansible fault so in order to use ansible fault we're going to run through a couple of hands-on items to just get a little bit of experience about how to approach this so we're going to create a folder called secret group wars and then we're going to generate a random password using the open ssl command that's 24 characters long and we'll store the password in some file called vault password txt we'll check that something happened there there's a password 24 characters long and we're going to use to encrypt the vault now we're going to create the vault itself using the password file as the password for its creation so the ansible vault command is part of the ansible installation and this is going to create a vault under secret group wars all dot yaml file so now we are inside the all dot yaml and once we save this it's going to be encrypted with the password that we supplied to the ansible vault command so we're going to specify an api key variable here and we'll call it a super secret super key to everything and we'll save that then now we close the editor and what happened now is that the ansible vault command created this file on our behalf and it encrypted it using this password so if we check the file we've just created without any attempts of decrypting it we'll just see rubbish um so this we can take and comment wherever we want even in public repositories as long as we keep the vault password safe so that should obviously never go into the git repository and it should be shared only with the people that need to know so in order to use this new encrypted variable that we defined we're going to modify our template that we've created in previous step so it was the test dot i and i dot j2 and we're going to make it sure what happened here i see so we're going to modify the template file there we go and we're going to set the api key or maybe we can just yeah we'll set the api key to the variable that we specified in the vault that's encrypted there and we save the template and now we need to modify the playbook to specify that this playbook is going to use the vault encrypted variable file which is under secret group wars we created that path and the file name is all of the ammo we should be it i'll save the playbook and now ansible still doesn't know how to decrypt this so we can decrypt it using command but but when we run it as a playbook we need to specify in the playbook how to decrypt stuff and for that ansible uses a configuration file in the root it's called ansible.cfg and it's it's an ini file to which we're going to paste contents of this which says that for the default if you want to decrypt stuff use the waltzpassword.txt write it out and now we're going to run the playbook as before so we're supplying the inventory of hosts and our playbook name stays the same. Epickey is undefined i think i've made a mistake with one of the names there so it's probably somewhere in the template so i called this api underscore key i don't think we changed anything here it's fine and we should also check all right let's try again. Epickey is still undefined well let's try to edit the waltz since maybe i made a typo there so i'm changing the command from create to edit since this file already exists yep and the api key here is without the underscore so that was the cause of the name issues so now if we rerun the playbook this should this should pass so all the roles from before are green unchanged the only thing that changed was the template over the templating of the configuration file and so now we can we can check whether the templating looks like we think it less and so what happened here is that Ansible on our behalf using the password we provided in the ansible.cfg filled this template with our super secret super key to everything so as long as you keep the password safe you can the master password of sorts you can share encrypted stuff together with your roles and playbooks and tasks and make this sort of a unified tool to manage your machines and your deployments