Containerization and Deployment of Application on Atomic Host using Ansible Playbook

This article describes how to build Docker image and deploy containerized application on Atomic host (any Remote host) using Ansible Playbook.

Building Docker image for an application and run container/cluster of containers is nothing new. But the idea is to automate the whole process and this is where Ansible playbooks come in to play.

Note that you can use Cloud/Workstation based Image to execute the following task. Here I am issuing the commands on Fedora Workstation.

Let’s see How to automate the containerization and deployment process for a simple Flask application:

We are going to deploy container on Fedora Atomic host.

First, Let’s Create a simple Flask Hello-World Application.

This is the Directory structure of the entire Application:

├── ansible
│   ├── ansible.cfg
│   ├── inventory
│   └── main.yml
├── Dockerfile
├── flask-helloworld
│   ├──
│   ├── static
│   │   └── style.css
│   └── templates
│       ├── index.html
│       └── master.html
└── requirements.txt



from flask import Flask, render_template

APP = Flask(__name__)

def index():
    return render_template('index.html')

if __name__ == '__main__':, host='')


body {
  background: #F8A434;
  font-family: 'Lato', sans-serif;
  color: #FDFCFB;
  text-align: center;
  position: relative;
  bottom: 35px;
  top: 65px;
.description {
  position: relative;
  top: 55px;
  font-size: 50px;
  letter-spacing: 1.5px;
  line-height: 1.3em;
  margin: -2px 0 45px;


<!doctype html>
    {% block head %}
    <title>{% block title %}{% endblock %}</title>
    {% endblock %}
    										<link rel="stylesheet" href="" integrity="sha384-1q8mTJOASx8j1Au+a5WDVnPi2lkFfwwEAa8hDDdjZlpLegxhjVME1fgjWPGmkzs7" crossorigin="anonymous">
    										<link href="" rel="stylesheet" integrity="sha384-T8Gy5hrqNKT+hzMclPo118YTQO6cYprQmhrYwIiQ/3axmI1hQomh7Ud2hPOy8SP1" crossorigin="anonymous">
    										<link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
    										<link href=',700' rel='stylesheet' type='text/css'>

<div id="container">
    {% block content %}
    {% endblock %}</div>


{% extends "master.html" %}

{% block title %}Welcome to Flask App{% endblock %}

{% block content %}
<div class="description">

Hello World</div>
{% endblock %}

Let’s write the Dockerfile.

FROM fedora
MAINTAINER Trishna Guha<>

RUN dnf -y update && dnf -y install python-virtualenv && dnf clean all

RUN virtualenv venv
RUN source venv/bin/activate

RUN mkdir -p /app

COPY requirements.txt /app

RUN pip install -r requirements.txt

COPY files/ /app/

ENTRYPOINT ["python"]
CMD [""]

Now we will work on Ansible playbook for our application that deals with the automation part:

Create inventory file:

IP_ADDRESS_OF_HOST ansible_ssh_private_key_file=<'PRIVATE_KEY_FILE'>

Replace IP_ADDRESS_OF_HOST with the IP address of the atomic/remote host and ‘PRIVATE_KEY_FILE’ with your private key file.

Create ansible.cfg file:



Replace USER with the user of your remote host.

Create main.yml file:

- name: Deploy Flask App
  hosts: atomic
  become: yes

    src_dir: [Source Directory]
    dest_dir: [Destination Directory]

    - name: Create Destination Directory
       path: "{{ dest_dir }}/files"
       state: directory
       recurse: yes

    - name: Copy Dockerfile to host
       src: "{{ src_dir }}/Dockerfile"
       dest: "{{ dest_dir }}"

    - name: Copy requirements.txt to host
       src: "{{ src_dir }}/requirements.txt"
       dest: "{{ dest_dir }}"

    - name: Copy Application to host
       src: "{{ src_dir }}/flask-helloworld/"
       dest: "{{ dest_dir }}/files/"

    - name: Make sure that the current directory is {{ dest_dir }}
      command: cd {{ dest_dir }}

    - name: Build Docker Image
      command: docker build --rm -t fedora/flask-app:test -f "{{ dest_dir }}/Dockerfile" "{{ dest_dir }}"

    - name: Run Docker Container
      command: docker run -d --name helloworld -p 5000:5000 fedora/flask-app:test

Replace [Source Directory] in src_dir field in main.yml with your /path/to/src_dir of your current host.

Replace [Destination Directory] in dest_dir field in main.yml with your /path/to/dest_dir of your remote atomic host.

Now simply run $ ansible-playbook main.yml :).  To verify if the application is running issue this command $ curl http://localhost:5000 on your atomic/remote host.

You can also manage your containers running on remote host using Cockpit. Check this article to know how to use Cockpit to manage your containers:



Here is the repository of the above example:

My future post will be related to ansible-container where I will describe how we can build Docker image and orchestrate container without writing any Dockerfile🙂.


What is if __name__ == ‘__main__’ ?


Module is simply Python file that has .py extension. Module can contain variables, functions, classes that can be reused.

In order to use module we need to import the module using import command. Check the full list of built-in modules in Python here

The first time a module is loaded in to running Python script, it is initialized by executing the code in the module once. To know various ways of importing modules visit here:

if __name__ == ‘__main__’:

We see if __name__ == ‘__main__’: quite often. Let’s see what this actually is.

__name__ is global variable in Python that exists in all namespaces. It is attribute of module. It is basically the name of the module as str (string) type.

Show Me Code:

Create a file named ‘’ and type the following code and save it. We have defined a simple mathematical square method here.


Now create another file named ‘’ in the same directory and type the following code and save it.


Now on terminal run the program with ‘python3’

Here we have defined a method in a module and using it in another file.

Now let’s look into if __name__ == ‘__main__’:

Open the ‘’ file and edit it as given in following:


Leave ‘’ unchanged.

Now on your terminal run ‘’. 


Here we have imported the module mymath. The variable __name__ is set to the name of the module that is imported.

Now on terminal run ‘’


We have run the file as program itself. And you can see here the variable __name__ is set to the string “__main__”.
And we have checked if __name__ == “__main__” is True execute the following instructions which means if the file is run as standalone program itself execute the following instructions.

If you do  print(type(__name__)) in the program, you will see it returns ‘str’ (string) type.

Happy Coding!

Run commands on Fedora Atomic host from Remote host using Ansible

This post will show how to run commands on your atomic host from remote.

I am using Fedora Atomic host. Boot up your atomic instance. Make your you have Ansible installed on your control host.

The user of fedora instance is “fedora” by default and there is no password authentication. So first we will need to create password on the atomic for user “fedora”.

For that type the following command. It will ask for new password.

$ passwd

Now we will need to change PasswordAuthentication to YES . Open /etc/ssh/sshd_config on atomic host and change PasswordAuthentication to YES. Now The atomic host is all set🙂.

Go to your Remote host/Control host. I am using Fedora Workstation.

Now we need to generate ssh key on our control host.

Type the following command. This will create ssh key(private and public) on your host. The default location is of public key is ~/.ssh/

$ ssh-keygen

It is time to add the ssh key to the Atomic host.
Type the following command. This will add your ssh public key to .ssh/authorized_keys on atomic host.

$ ssh-copy-id username@IPofAtomicHost

Now we will create inventory and config file for Ansible.

$ mkdir test && cd test
$ touch inventory
$ touch ansible.cfg

Inside the inventory file add the following:


Inside the ansible.cfg file add the following:


Now let’s ping the atomic host🙂.

$ ansible atomic -i inventory -m ping

If the above returns Success we will try to run command on atomic host from our remote host🙂.
Type the following to run command on your atomic host.

$ ansible atomic -i inventory -m command -a "sudo atomic host upgrade"


NOTE: If you have you atomic instance running on Openstack make sure to add icmp to the security groups of the instance.



Run Apache on Fedora Atomic Host

This post describes how to run Apache on Atomic host. I am using Fedora atomic host.

Boot up an atomic instance (Fedora preferred).

To test the Apache container, just run

atomic run

Make sure you are using


After the container has started successfully, Now do

curl http://localhost:80

This will display


Now If you want to build your own image copy the source down to your host. 

Then Edit the Dockerfile and make your changes.

Now Build the image:

# docker build --rm -t /httpd .

After the build is successful, Run the container:

# docker run -d -p 80:80 /httpd #To assign port 80 of your host that maps to port 80 on the container
# docker run -d -p 80 /httpd #To assign random port that maps to port 80 on the container

If you do curl http://localhost you will see the required output.

Screenshot from 2016-09-06 10-55-07

Screenshot from 2016-09-06 10-58-21

PythonPune August Meetup: Back to Basics


PythonPune August Meetup was held at Red Hat Pune on 28th August, 2016. So Thanks for supporting us always! Many people came down for the meetup. Some of them were students and some were professionals.

This time the topic was Back to Basics[Python3 Workshop]. We all know that the support for Python2 is going to over by 2020. Here is the Python2 Countdown Clock So it is the time to brush up the basic skills for Python3.  That was the motive for the meetup.

The meetup started with introduction. Chandan Kumar introduced me to the crowd and all of them gave their introduction as well.

We started with basic “Hello World” program and we covered up to “Modules” of Python3🙂.

Lots of questions came up when we started discussing about Data structure, Slicing, File handling and Modules.

At the end of the workshop people were given a problem to solve. The response was pretty good🙂. Later we told about the next meetup  of PyladiesPune and the meetup ended with discussing about contributing to Open Source Projects. Chandan helped me to keep the session pretty interactive, so thanks to him🙂.

Here is the slide for Back to Basics[Python3]:

Me giving the talk:


IRC Client: Irssi On Atomic Host

If you are a terminal geek you will always want to do things using terminal😉. And when it comes to Atomic host, YES you will have to do stuffs using terminal.

If you don’t know about Atomic, you must visit🙂

This post will describe how to setup and use IRC client on Atomic host. This will be applicable for any Cloud host also.

Irssi is a terminal based IRC client for Unix/Linux systems. And the best part is we will not need to setup things manually because we have containers🙂.

Let’s Get Stared:

I am using Fedora Atomic host here. Get Fedora atomic host from here

Make Sure you have Docker installed.

Copy the Dockerfile from here:

Now run docker build -t username/irssi .This will build image.

There after you just need to run the container🙂  docker run -it username/irssi.

Later on sometime you will be able to do the whole set up only docker run -it fedora/irssi once Fedora adds Irssi to its Docker hub :).

After you start the container you will see something like this:

Screenshot from 2016-08-19 14-12-05

Let’s join a channel

Screenshot from 2016-08-19 14-14-16

You will find the Irssi Commands here: Irssi Commands.

Cockpit Container on Atomic Host

Screenshot from 2016-08-16 17-42-05

Cockpit is a remote manager for GNU/Linux servers.

  • Cockpit is a server manager that makes it easy to administer your GNU/Linux servers via a web browser.
  • Cockpit makes it easy for any sysadmin to perform simple tasks, such as administering storage, inspecting journals and starting and stopping services.
  • Jumping between the terminal and the web tool is no problem. A service started via Cockpit can be stopped via the terminal. Likewise, if an error occurs in the terminal, it can be seen in the Cockpit journal interface.
  • You can monitor and administer several servers at the same time. Just add them with a single click and your machines will look after its buddies.

The Cockpit team is currently uploading the cockpit container to the Fedora repo on the Docker Hub, but Fedora Release Engineering is working on publishing layered images. We now have a super-privileged container (SPC) for the web service (cockpit-ws) with the bridge, shell, and docker components installed by default on the Atomic host.

This means you can simply run atomic run fedora/cockpitws as root or with sudo and cockpit will be running on port 9090. Try it🙂.

Getting Started

Boot up Fedora Atomic instance.

Install the Container

Install cockpitws container using atomic.

# atomic install fedora/cockpitws
/usr/bin/docker run -ti --rm --privileged -v /:/host fedora/cockpitws /container/atomic-install
+ sed -e /pam_selinux/d -e /pam_sepermit/d /etc/pam.d/cockpit
+ mkdir -p /host/etc/cockpit/ws-certs.d
+ chmod 755 /host/etc/cockpit/ws-certs.d
+ chown root:root /host/etc/cockpit/ws-certs.d
+ mkdir -p /host/var/lib/cockpit
+ chmod 775 /host/var/lib/cockpit
+ chown root:wheel /host/var/lib/cockpit
+ /bin/mount --bind /host/etc/cockpit /etc/cockpit
+ /usr/sbin/remotectl certificate --ensure

There’s a few things going on here in the install method.

Note that we’re exposing the Atomic host root directory to the container at /host. As a SPC (Super Privileged Container), this allows the container to access the host filesystem and make changes. The install method creates a set of directories in /etc and /var to persist configs. This means that we don’t need any particular cockpitws container to stick around, any cockpitws container will be able to read the appropriate state from the host. We can upgrade the cockpit image and not worry about losing data. Since/etc and /var are writable on an Atomic host, and /etc content will be appropriately merged on a tree change, cockpit data will also survive an atomic host upgrade as well.

Set up the systemd unit

# vi /etc/systemd/system/cockpitws.service

Description=Cockpit Web Interface

ExecStart=/usr/bin/docker run --rm --privileged --pid host -v /:/host --name %p fedora/cockpitws /container/atomic-run --local-ssh
ExecStop=-/usr/bin/docker stop -t 2 %p


With the container available to docker, we’ll build the systemd unit file next. For local systemd unit files, we want them to reside in /etc/systemd/system.

The ExecStart line in the unit file looks nearly identical to the RUN label, with one change. When running containers from systemd, we don’t want to use docker -d, instead we want either docker -a or docker --rm. We’re using docker --rm here since we don’t need this particular container instance to survice a restart. We are going to name container using the %p tag to pick up the systemd service name, just to make it easier to find in docker ps.

Start the Service

Now we can reload systemd to read the new unit file, enable the service to start on reboot, and then start the new cockpitws service.

  # systemctl daemon-reload
  # systemctl enable cockpitws.service
  Created symlink from /etc/systemd/system/ to /etc/systemd/system/cockpitws.service.
  # systemctl start cockpitws.service
  # systemctl status cockpitws.service

  ● cockpitws.service - Cockpit Web Interface
  Loaded: loaded (/etc/systemd/system/cockpitws.service; enabled; vendor preset: disabled)
  Active: active (running) since Tue 2016-08-16 12:42:23 UTC; 10s ago
Main PID: 2047 (docker)
   Tasks: 6 (limit: 512)
  Memory: 0B
     CPU: 1ms
  CGroup: /system.slice/cockpitws.service
          └─2047 /usr/bin/docker run --rm --privileged --pid host -v /:/host --name cockpitws fedora/cockpitws /container/atomic-run --local-ssh

  Aug 16 12:42:25 atomic.novalocal docker[2047]: + sed -e /pam_selinux/d -e /pam_sepermit/d /etc/pam.d/cockpit
  Aug 16 12:42:25 atomic.novalocal docker[2047]: + mkdir -p /host/etc/cockpit/ws-certs.d
  Aug 16 12:42:25 atomic.novalocal docker[2047]: + chmod 755 /host/etc/cockpit/ws-certs.d
  Aug 16 12:42:25 atomic.novalocal docker[2047]: + chown root:root /host/etc/cockpit/ws-certs.d
  Aug 16 12:42:25 atomic.novalocal docker[2047]: + mkdir -p /host/var/lib/cockpit
  Aug 16 12:42:25 atomic.novalocal docker[2047]: + chmod 775 /host/var/lib/cockpit
  Aug 16 12:42:25 atomic.novalocal docker[2047]: + chown root:wheel /host/var/lib/cockpit
  Aug 16 12:42:25 atomic.novalocal docker[2047]: + /bin/mount --bind /host/etc/cockpit /etc/cockpit
  Aug 16 12:42:25 atomic.novalocal docker[2047]: + /usr/sbin/remotectl certificate --ensure
  Aug 16 12:42:25 atomic.novalocal docker[2047]: INFO: cockpit-ws: Using certificate: /etc/cockpit/ws-certs.d/0-self-signed.cert

Now that the service is up and running, point your web browser at port 9090 on the Atomic host and you should see the Cockpit login page. You’ll need to log in with a user in the wheel group in order to administrate the system, but you can log in as any user to view the local host. For the published Fedora Atomic cloud image, log in with the fedora credentials and you should be ready to go. You can login as root user. For that You need to setup password for root user in your atomic instance. After that you need to change PasswordAuthentication to yes in /etc/ssh/sshd_config and you are ready to go.

You can add other hosts to this Cockpit instance, with the knowledge that reboots and upgrades to the host or the container won’t affect the configuration.

Note that if you are using Openstack you need to add Port 9090 in your security group.

I just started Cockpit container on atomic host yesterday.

Here is the screenshot of the containers running.

Screenshot from 2016-08-17 11-30-22