frosch03.de/posts/2016-10-27-Ansible-and-Docker

Docker Container

The following describes how to setup the environment for the docker image that later serves the frosch03.de blog files through an apache2 server.

load .tar docker file

First of all one needs to get the correct docker image. This might be done by loading the docker images tarball.

{% highlight bash %} docker load -i container1.tar {% endhighlight %}

create data folder for the webserver

Next a folder is needed, that contains the data for the webserver to serve. Also a location for storing .log files is needed. A folder to hold both location is created somewhere.

{% highlight bash %} mkdir home/frosch03/data4webserver {% endhighlight %}

Also a location for the log files is needed:

{% highlight bash %} mkdir home/frosch03/data4webserver/log {% endhighlight %}

If needed, you could create a sub structure within the log folder. The content of the log-folder will be accessible from within the docker container from the folder /var/log/apache2.

Finally a folder that contains the data to be served by the webserver is needed:

{% highlight bash %} mkdir home/frosch03/data4webserver/data {% endhighlight %}

This folder will be mapped onto the containers /var/www/ folder. If you like, you could now copy the data into the data folder. Use the file structure as you will reference it from the apache's site configuration.

Set rights for apache2

In the next step, the user rights of the files must be changed, such that the apache is able to access the documents. This is typically done by setting the group ownership of the files to www-data, or if you like the decimal representation: 33.

{% highlight bash %} sudo chgrp -R 33 /home/frosch03/data4webserver {% endhighlight %}

Run docker container

Now everything is at it's place such that we now could run the docker container.

{% highlight bash %} docker run -ti –name frosch03\_de\_testing -p 8023:80
-v /home/frosch03/data4webserver/data:/var/www
-v /home/frosch03/data4webserver/log:/var/log/apache2
container1 {% endhighlight %}

Here we give the instance the name frosch03<sub>de</sub><sub>testing</sub>. Also the local port 80 is mapped to the external one 8023. Then the two volumes are mapped, the data volume to /var/www and the log one to /var/log/apache2.

Now one has to start the apache server. This is done by spawning a shell within the docker container by:

{% highlight bash %} docker exec -ti frosch03\_de\_testing bash {% endhighlight %}

Inside the container, apache could simply be started via the command:

{% highlight bash %} service apache2 start {% endhighlight %}

Ansible

There are two kinds of things to be explained within the following: 1) There is the definition of computers, that docker containers are deployed to and 2) there are the ansible playbooks that will be used to create new containers.

The machines that will be used as install targets are defined within the file /etc/ansible/hosts.

Hosts

This is a simple file within the ini file format, that just lists machines under a naming section. Here I have a computers DNS name under the section web and the localhost under the section local:

{% highlight ini %} [web] some.server

[local] localhost {% endhighlight %}

So with that I now am able to deploy my docker stuff to web or to local, whatever that means. It does not matter, if there are 20 machines listed beneath web.

Files & Folder Structure

This section gives a rough overview on the file structure I created, in order to do things the ansible way. (Or at least, what I think the ansible way is).

Basically I have a frosch03.de playbook which references two roles, docker and frosch03. The playbook defined within YAML and is stored on the top level.

Both roles come with their own folders, that hold a files and a tasks directory. The files folder contains files, that are used within the role definition e.g. Dockerfile which contains the information on how to create the docker container.

The tasks folder contains YAML definitions that tell ansible what to do. This is the simple folder structure for the frosch03.de docker container:

  • frosch03.de.yml
  • roles/
    • docker/

      • files/
      • tasks/
        • docker.arch.yml
        • main.yml
        • docker.ubuntu.yml

      frosch03/

      • files/
        • Dockerfile
        • frosch03blogdata.tar.bz2
        • frosch03.de.conf
      • tasks/
        • main.yml

With that said, lets have a look at the different roles.

Docker

The docker role contains of just YAML definitions within the tasks folder. There is the main definition within main.yml.

The first three definitions include more definitions, depending upon the operation system that the ansible will connect to. So this depends not on the machine from where ansible is used to do something remotely, but on the os of the machine under installation.

{% highlight yaml %} - include: docker.ubuntu.yml when: "ansible\_os\_family == 'Ubuntu'"

  • include: docker.ubuntu.yml when: "ansible\_os\_family == 'Debian'"
  • include: docker.arch.yml when: "ansible\_os\_family == 'Archlinux'" {% endhighlight %}

There are three operation system that are discriminated, Ubuntu, Debian and Archlinux. As Ubuntu and Debian are pretty similar, they share the same docker definitions. For the Arch side, a different definition file is used. Both define their way on how to install docker with it's dependencies on the remote machine.

The remote system is equipped with docker and python-setuputils right after the os specific tasks are completed. After that, pip is installed in both cases with easyinstall and is then used to install docker-py.

{% highlight yaml %} - name: Install pip easy\_install: name=pip state=latest executable=easy\_install-2.7

  • name: Install docker-py pip: name: docker-py {% endhighlight %}

Last but not least, the main.yml defines that docker is started on boot and with the last task docker is finally started.

{% highlight yaml %} - name: Start docker on boot service: name=docker state=started enabled=yes

  • name: Make sure docker is running service: name: docker state: started {% endhighlight %}

Frosch03

1. Files

The frosch03 role contains the data needed in order to set up the frosch03.de blog. The files folder contains the Dockerfile which set's up a ubuntu based server, equipped with an apache2 webserver. It also contains the configuration file for the apache2 server called frosch03.de.conf.

Last but not least, a tarball is included, that holds the data of the webserver. In this case the tarball contains a folder that holds a data and a log folder. The data folder itself holds the files that should be served by the apache. The log folder contains the locations, where apache will put it's log files into.

2. Tasks

There is only the main task defined within main.yml. This task describes the sets up of the servers docker container, together the data/log storage locations.

{% highlight yaml %} - name: Create necessary directories file: path: "{{ item }}" mode: 0755 state: directory with\_items: - "/tmp/frosch03.de-ghost/frosch03\_ghost" - "/tmp/frosch03.de-ghost/data" {% endhighlight %}

With the next step, the files Dockerfile and frosch03.de.conf are copied to the storage location of where the docker image is build. (Here this is done inside the temporary folder)

{% highlight yaml %} - name: Copy frosch03\_ghost files to /tmp/frosch03.de-ghost/frosch03\_ghost copy: src: "{{ item }}" dest: "/tmp/frosch03.de-ghost/frosch03\_ghost/{{ item }}" with\_items: - "Dockerfile" - "frosch03.de.conf" {% endhighlight %}

The docker image itself is build right after that. Its done from exactly the location, the files have been copied to.

{% highlight yaml %} - name: Build frosch03.de-ghost container shell: docker build -t frosch03\_ghost . args: chdir: /tmp/frosch03.de-ghost/frosch03\_ghost {% endhighlight %}

The newly created docker image is called frosch03<sub>ghost</sub>.

After that's done, the data for apache to serve will be copied into the folders, that are given the docker container as volumes. So the first tasks copies the tarball into that location.

Then the tarball is extracted into that folders sub folder data. Note: The group of the extracted files is set to 33 as this corresponds to www-data (or sometimes http). Apache runs typically with this group and therefore the rights are needed in order to allow apache to access the extracted data later on.

{% highlight yaml %} - name: Copy the data to the server copy: src: "frosch03\_blog\_data.tar.bz2" dest: "/tmp/frosch03.de-ghost/frosch03\_blog\_data.tar.bz2"

  • name: Extract frosch03.de-ghost data unarchive: src=/tmp/frosch03.de-ghost/frosch03\_blog\_data.tar.bz2 dest=/tmp/frosch03.de-ghost/data group=33 {% endhighlight %}

In the last two tasks, the docker container is run. The first one tries to restart the docker container if it exists; the second one starts the docker container if it wasn't existing.

{% highlight yaml %} - name: Restart frosch03.de-Ghost docker: image: frosch03\_ghost name: frosch03\_de ports: 8023:80 state: restarted volumes: /tmp/frosch03.de-ghost/data/data:/var/www,/tmp/frosch03.de-ghost/data/log:/var/log/apache2 {% endhighlight %}

{% highlight yaml %} - name: Make sure that frosch03.de-Ghost is running in the end docker: image: frosch03\_ghost name: frosch03\_de ports: 8023:80 state: running detach: True volumes: /tmp/frosch03.de-ghost/data/data:/var/www,/tmp/frosch03.de-ghost/data/log:/var/log/apache2 {% endhighlight %}