Install Ansible In Docker Container

/ Comments off

In this guide, we will use Ansible as a Deployment tool in a Continuous Integration/Continuous Deployment process using Jenkins Job.

In the world of CI/CD process, Jenkins is a popular tool for provisioning development/production environments as well as application deployment through pipeline flow. Still, sometimes, it gets overwhelming to maintain the application's status, and script reusability becomes harder as the project grows.

To overcome this limitation, Ansible plays an integral part as a shell script executor, which enables Jenkins to execute the workflow of a process.

To fix this error, the Docker SDK library for python must be installed on the target machine. But before installing you need to identify the python version in the target machine. The python version in that machine is Python 3.8.5. For Python 3.6 or later versions, the following command can used to install the Docker SDK library: For Python 2.6. The -t option is short for -tag.A tag provides a name for the image and optionally a tag in the name:tag format. They are also used as an alias for the ID of the image. Your image is tagged ansible-in-containers:latest which is made of two parts; image name and tag name. Here in this article I have created a Docker container on Managed Node using Ansible and deployed a web page from that container. Let’s see how it’s done First, we add the IP of the Managed Node to the Inventory on Control Node. There is nothing to prevent ansible from being installed in a container. It's just some python code after all. It appears that there are several options on dockerhub if you want. There are also ansible-galaxy collections and roles for creating ansible containers.

Let us begin the guide by installing Ansible on our Control node.

Install and Configure Ansible

Installing Ansible:
Here we are using CentOS 8 as our Ansible Control Node. To install Ansible, we are going to use python2-pip, and to do so, first, we have to install python2. Use the below-mentioned command to do so:

After Python is installed on the system, use pip2 command to install Ansible on the Control Node:

It might take a minute or two to complete the installation, so sit tight. Once the installation is complete, verify:

Through the above command, we notice that the config file path is missing, which we will create and configure later. For now, let’s move to the next section.

Configuring Ansible Control Node User:
The first thing we are going to do is create a user named ansadmin, as it is considered the best practice. So let’s create a user, by using the command adduser, which will create a new user to our system:

Now, use the passwd command to update the ansadmin user’s password. Make sure that you use a strong password.

Copy the password for user ansadmin and save it somewhere safe.

Once we have created the user, it's time to grant sudo access to it, so it doesn't ask for a password when we log in as root. To do so, follow the below-mentioned steps:

Go to the end of the file and paste the below-mentioned line as it is:

Before moving forward, we have one last thing to do. By default, SSH password authentication is disabled in our instance. To enable it, follow the below-mentioned steps:

Find PasswordAuthentication, uncomment it and replace no with yes, as shown below:

You will see why we are doing this in the next few steps. To reflect changes, reload the ssh service:

Now, log in as an ansadmin user on your Control Node and generate ssh key, which we will use to connect with our remote or managed host. To generate the private and public key, follow the below-mentioned commands:

Use ssh-keygen command to generate key:

Usually, keys are generated in the .ssh/ directory. In our case, you can find keys at /home/ansadmin/.ssh/. Now let us configure our Managed Host for Ansible.

Configuring Ansible Managed Host User:
First, we will create a user on our managed host, so log in to your host and create a user with the same name and password.

As our managed host is an Ubuntu machine, therefore here we have to use the adduser command. Please make sure that the password for the username ansadmin is the same for Control and Managed Host.

Other than this, it is also an excellent thing to cross-check if password authentication is enabled on the Managed Host as we need to copy the ssh public key from the control node to the Managed Host.

Switch to Control Node machine; to copy the public key to our Managed Host machine, we will use the command ssh-copy-id:

For the first time, it will ask for the password. Enter the password for ansadmin, and you are done. Now, if you wish, you can disable Password Authentication on both machines.

Setting Ansible Inventory:
Ansible allows us to manage multiple nodes or hosts at the same time. The default location for the inventory resides in /etc/ansible/hosts. In this file, we can define groups and sub-groups.

If you remember, earlier, the hosts' file was not created automatically for our Ansible. So let's create one:

Add the following lines in your hosts' file and save it:

Make sure that you replace your-managed-host-ip with your host IP address.

Let's break down the basic INI format:

  • docker_group - Heading in brackets is your designated group name.
  • docker_host & ansible_CN - The first hostname is docker_host, which points to our Managed Host. While the second hostname is ansible_CN, which is pointing towards our localhost, to be used in Ad-Hoc commands and Playbooks.
  • ansible_host - Here, you need to specify the IP address of our Managed Host.
  • ansible_user - We mentioned our Ansible user here.
  • ansible_ssh_private_key_file - Add the location of your private key.
  • ansible_python_interpreter - You can specify which Python version you want to use; by default, it will be Python2.
  • ansible_connection - This variable helps Ansible to understand that we are connecting the local machine. It also helps to avoid the SSH error.

It is time to test our Ansible Inventory, which can be done through the following command. Here we are going to use a simple Ansible module PING:

It looks like the Ansible system can now communicate with our Managed Host as well as with the localhost.

Install Docker:

We need a Docker ready system to manage our process; for this, we have to install Docker on both systems. So follow the below-mentioned steps:

For CentOS (Control Node):
Run the following command on your Control Node:

In case you encounter the below-mentioned error during installation:

Next, run the following command:

For Ubuntu OS (Managed Host):
Run the following command on your Managed Host, which is a Ubuntu-based machine:

That’s it for this section. Next, we are going to cover how to integrate Ansible with Jenkins.

Integrating Ansible with Jenkins:

In this section, we will integrate Ansible with Jenkins. Fire up your Jenkins, go to Dashboard > Manage Jenkins > Manage Plugins > Available and then search for Publish Over SSH as shown in the image below:

Now, go to Configure System and find Publish over SSH; under this section, go to SSH Servers and click on the Add button. Here we are going to add our Docker Server as well as Ansible Server, as shown in the image:

SSH server setting for Docker:

SSH server setting for Ansible:

In the Hostname field, add your IP address or domain name of Docker and Ansible server. Before saving the setting, make sure that you test the connection before saving the configuration, by clicking on the Test Configuration button as shown in the image below:

Create Jenkins Job

The next step is to create Jenkins jobs. The sole propose of this Job is to build, test, and upload the artifact to our Ansible Server. Here we are going to create Job as a Maven Project, as shown in the image below:

Next in Job setting page, go to the Source Code Management section and add your Maven project repo URL, as shown in the image below:

Find the Build section, and in Root POM field enter your pom.xml file name. Additionally in the Goals and options field enter clean install package:

After successful build completion, your goal is to send the war file to the specified directory to your Ansible server with the right permissions so that it doesn't give us the writing permission by assigning ansadmin to the directory.

Right now, we don't have such a directory, so let us create one. Follow the below-mentioned steps:

Directory /opt/docker will be used as our workspace, where Jenkins will upload the artifacts to Ansible Server.

Now, go to the Post-build Actions section and from the drop-down menu, select Send build artifacts over SSH, as shown in the image below:

Install

Make sure that in the Remote Directory field, you enter the pattern //opt//docker as it doesn’t support special characters. Apart from this, for now, we are going to leave the Exec Command field empty so that we can test whether our existing configuration works or not.

Now Build the project, and you will see the following output in your Jenkins’s console output:

Go to your Ansible Server terminal and see if the artifact was sent with right user privileges:

It looks like our webapp.war file was transferred successfully. In the following step, we will create an Ansible Playbook and Dockerfile.

Creating Dockerfile and Ansible Playbook:

Install Ansible In Docker Container

To create a Docker Image with the webapp.war file, first, we will create a DockerFile. Follow the below-mentioned steps:

First, log in to your Ansible Server and go to directory /opt/docker and create a file named as Dockerfile:

Now open the Dockerfile in your preferred editor, and copy the below-mentioned lines and save it:

Here instructions are to pull a Tomcat image with tag 8.5.50-jdk8-openjdk and copying the webapp.war file to Tomcat default webapp directory., which is /usr/local/tomcat/webapps

With the help of this Dockerfile, we will create a Docker container. So let us create the Ansible Playbook, which will enable us to automate the Docker image build process and later run the Docker container out of it.

We are creating a Ansible Playbook, which does two tasks for us:

  1. Pull Tomcat’s latest version and build an image using webapp.war file.
  2. Run the built image on the desired host.

For this, we are going to create a new YAML format file for your Ansible Playbook:

Now copy the below-mentioned line into your simple-ansible.yaml file:

You can get more help here: docker_image and docker_container. Now, as our Playbook is created, we can run a test to see if it works as planned:

Here we have used the --limit flag, which means it will only run on our Ansible Server (Control Node). You might see the following output, in your terminal window:

Look's like Playbook ran sccessfully and no error was detected during the Ansible Playbook check, so now we can move to Jenkins to complete our CI/CD process using Ansible.

Run Ansible Playbook using Jenkins

In this step, we would execute our Ansible Playbook (i.e., simple-ansible-playbook.yaml) file, and to do so let us go back to the Project Configuration page in Jenkins and find Post-build Actions there.

In this section, copy the below-mentioned command in the Exec command field:

Now, let us try to build the project and see the Jenkins Job's console output:

In the output, you can see that our Ansible playbook ran successfully. Let us verify if at Ansible Server the image is created and the container is running:

For Docker Image list:

For Docker Container list:

It looks like Jenkins was able to run the Ansible Playbook successfully. Next, we are going to push Docker Image to Docker Hub.

Pushing Docker Image to Docker Hub Using Ansible

We are going to use Docker Hub public repository for this guide; in case you want to work on a live project, then you should consider using the Docker Hub private registry.

For this step, you have to create a Docker Hub account if you haven’t had one yet.

Our end goal for this step is to publish the Docker Image to Docker Hub using Ansible Playbook. So go to your Ansible Control Node and follow the below-mentioned steps:

Make sure that you enter the right username and password.

Now it’s time to create a new Ansible Playbook which will build and push the Docker image to your Docker Hub account. Note that this image will be publicly available, so be cautious.

Container

Create a new Ansible Playbook, which will build a Docker image and push it to our Docker Hub account:

Let us run the playbook now and see what we get:

Go to your Docker Hub account and see if the image was pushed successfully, as shown in the image below:

Next, let us modify our simple-ansible-playbook.yaml playbook, which we created earlier, as from here on, we are going to pull the Docker image from Docker Hub Account and create a container out of it.

Note that we have used the import_playbook statement at the top of the existing playbook, which means that we want to run the build-push.yaml playbook first along with our main playbook, and this way, we don’t have to run multiple playbooks manually.

Let us break the whole process into steps:

  1. With the help of build-push.yaml playbook, we are asking Ansible to build an image with the artifacts sent by Jenkins to our Control Node, and later push the built image (i.e., simple-docker-image) to our Docker Hub’s account or any other private registry like AWS ECR or Google’s Container Registry.
  2. In the simple-ansible-playbook.yaml file, we have imported the build-push.yaml file, which is going to run prior to any statement present within the simple-ansible-playbook.yaml file.
  3. Once build-push.yaml playbook is executed, Ansible will launch a container into our Managed Docker Host by pulling our image from our defined registry.

Install Ansible In Docker Container List

Now, it's time to build our job. So in the next step, we will deploy the artifact to our Control Node, where Ansible Playbook will build an image, push to Docker Hub and run the container in Managed Host. Let us get started!

Jenkins Jobs to Deploy Docker Container Using Ansible

To begin, go to JenkinstoDockerUsingAnsible configure page and change the Exec command in the Post-build Actions section.

Copy the below-mentioned command and add it as shown in the image below:

Save the configuration and start the build; you will see the following output:

Now go to your Control Node and verify if our images were built:

It looks like Ansible Playbook was successfully executed on our Control Node. It’s time to verify if Ansible was able to launch containers on our Managed Host or not.

Go to your Managed Host and enter the following command:

Install Ansible Inside Docker Container

Now visit the following URL http://your-ip-addr:8888/webapp/ in your browser. Note that, Tomcat Server may take some time before you can see the output showing your project is successfully setup.

And you are done!

You successfully managed to deploy your application using Jenkins, Ansible, and Docker. Now, whenever someone from your team pushes code to the repository, Jenkins will build the artifact and send it to Ansible, from there Ansible will be responsible for publishing the application to the desired machine.