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 %}