Dockerized Apache

  • Dockeriser Apache

    • Dockeriser Apache simple version

    • Network Consideration for the Apache Container

    • Setting up the website

      • Setting up the website via Git or Subversion

      • Setting up the website with a volume

      • Preservation of site data (container volume and naming)

        • Defining a volume for data

        • Naming the container to keep site data
    • Configuration

      • Apache configuration

      • Application Configuration

    • Viewing Apache logs

    • Emergency corrective
    • Corrective emergency

Dockeriser Apache

We have seen the apache configuration, back and forth, we will now see how to dockeriser apache. As always the docker part is optional, but I find it very interesting to standardize your deployment. I will take the time to present a simple way of setting up and addressing some problem that you might encounter.

Dockeriser Apache simple version

We will continue to use the Ubuntu system to make the deployment free to you to change the distribution of course you will have file path problems if you opt for CentOS and RedHat.

We have already seen the creation of an image customize docker, as it is a little time we will go quietly offering the opportunity for everyone to refresh this memory.

We will set up the basics by installing apache and as well as the structure of the files. Let’s set up a work structure:

 

$ mkdir ~/git/mein_apache $ cd ~/git/mein_apache $ git init . $ touch Licence $ git add Licence $ git commit -a -m "Initialisation du dépot Git " $ vim Dockerfile

I urge you to use git to keep track of changes to your Docker.

$ cat Dockerfile # Définition de l'image de Base ( distribution ) FROM i686/ubuntu MAINTAINER Paul Perret 'paul.perret@patapouf.com' # Activation du mode non interactif pour apt ENV DEBIAN_FRONTEND noninteractive # Installation des applications de Base RUN apt-get update && apt-get install -y apache2 apache2-utils && apt-get clean # Fix timezone RUN ln -s -f /usr/share/zoneinfo/Canada/Eastern /etc/localtime # Port exposer EXPOSE 80 CMD ["/usr/sbin/apache2","-DFOREGROUND"]

Let’s build the image by giving it a meaningful name in my case: apache-train

$ docker build -t apache-train . [... OUTPUT COUPÉ ...] Step 5 : EXPOSE 80 ---> Running in cb3cec30ef9c ---> 7648874030d3 Removing intermediate container cb3cec30ef9c Step 6 : CMD /usr/sbin/apache2 -DFOREGROUND ---> Running in c37de7aa4829 ---> 6c9f625812c5 Removing intermediate container c37de7aa4829 Successfully built 6c9f625812c5

Are we doing a test ?? I tell you all right now it will not work: P, it’s part

$ docker run apache-train [Tue Jul 12 17:25:05.374632 2016] [core:warn] [pid 1] AH00111: Config variable ${APACHE_LOCK_DIR} is not defined [Tue Jul 12 17:25:05.377490 2016] [core:warn] [pid 1] AH00111: Config variable ${APACHE_PID_FILE} is not defined [Tue Jul 12 17:25:05.377522 2016] [core:warn] [pid 1] AH00111: Config variable ${APACHE_RUN_USER} is not defined [Tue Jul 12 17:25:05.377529 2016] [core:warn] [pid 1] AH00111: Config variable ${APACHE_RUN_GROUP} is not defined [Tue Jul 12 17:25:05.377556 2016] [core:warn] [pid 1] AH00111: Config variable ${APACHE_LOG_DIR} is not defined [Tue Jul 12 17:25:05.396087 2016] [core:warn] [pid 1:tid 3075414656] AH00111: Config variable ${APACHE_LOG_DIR} is not defined [Tue Jul 12 17:25:05.397428 2016] [core:warn] [pid 1:tid 3075414656] AH00111: Config variable ${APACHE_LOG_DIR} is not defined [Tue Jul 12 17:25:05.397458 2016] [core:warn] [pid 1:tid 3075414656] AH00111: Config variable ${APACHE_LOG_DIR} is not defined AH00526: Syntax error on line 74 of /etc/apache2/apache2.conf: Invalid Mutex directory in argument file:${APACHE_LOCK_DIR}

We will take this opportunity to see how we will analyze this problem, my first SLR and start the container either in automatic mode with execution of the EXEC statement contained at the end of the Dockerfile

[ ... OUTPUT COUPÉ ... ] # Port exposer EXPOSE 80 CMD ["/usr/sbin/apache2","-DFOREGROUND"]

So let’s run the container with bash in interactive mode:

$ docker run -it apache-train bash root@46e37e65f98b:/# ip addr show [... OUTPUT COUPÉ ...] 15: eth0@if16: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default link/ether 02:42:ac:11:00:06 brd ff:ff:ff:ff:ff:ff inet 172.17.0.6/16 scope global eth0

We will start the apache service in the “classic” way:

root@46e37e65f98b:/# /etc/init.d/apache2 start * Starting web server apache2 /usr/sbin/apache2ctl: 87: ulimit: error setting limit (Operation not permitted) Setting ulimit failed. See README.Debian for more information. AH00558: apache2: Could not reliably determine the server's fully qualified domain name, using 172.17.0.6. Set the 'ServerName' directive globally to suppress this message * root@46e37e65f98b:/# ps aux | grep apac root 37 0.0 0.2 5500 4124 ? Ss 17:32 0:00 /usr/sbin/apache2 -k start www-data 40 0.0 0.1 228132 3744 ? Sl 17:32 0:00 /usr/sbin/apache2 -k start www-data 41 0.0 0.1 228132 3832 ? Sl 17:32 0:00 /usr/sbin/apache2 -k start

If we go to the URL: http://172.17.0.6/ it works:

 

But in the Dockerfile statement it’s NOT /etc/init.d/apache2 start that is used, let’s try with the command in the Dockerfile:

root@46e37e65f98b:/# /usr/sbin/apache2 -DFOREGROUND [Tue Jul 12 17:37:40.874436 2016] [core:warn] [pid 146] AH00111: Config variable ${APACHE_LOCK_DIR} is not defined [Tue Jul 12 17:37:40.874582 2016] [core:warn] [pid 146] AH00111: Config variable ${APACHE_PID_FILE} is not defined [Tue Jul 12 17:37:40.874623 2016] [core:warn] [pid 146] AH00111: Config variable ${APACHE_RUN_USER} is not defined [Tue Jul 12 17:37:40.874642 2016] [core:warn] [pid 146] AH00111: Config variable ${APACHE_RUN_GROUP} is not defined [Tue Jul 12 17:37:40.876067 2016] [core:warn] [pid 146] AH00111: Config variable ${APACHE_LOG_DIR} is not defined [Tue Jul 12 17:37:40.882795 2016] [core:warn] [pid 146:tid 3075172992] AH00111: Config variable ${APACHE_LOG_DIR} is not defined [Tue Jul 12 17:37:40.883647 2016] [core:warn] [pid 146:tid 3075172992] AH00111: Config variable ${APACHE_LOG_DIR} is not defined [Tue Jul 12 17:37:40.883699 2016] [core:warn] [pid 146:tid 3075172992] AH00111: Config variable ${APACHE_LOG_DIR} is not defined AH00526: Syntax error on line 74 of /etc/apache2/apache2.conf: Invalid Mutex directory in argument file:${APACHE_LOCK_DIR}

SUPER, we do not have the solution but we can reproduce it, but why we will not use the command that works in the Dockerfile. The problem with the apache start service instruction is that the process will be put in the background, so the docker container will start, it will start apache successfully but as it will be in the background the container will stop. Demonstration:

root@46e37e65f98b:/# exit $ tail Dockerfile [... OUTPUT COUPÉ ...] # Port exposer EXPOSE 80 CMD ["/etc/init.d/apache2","start"] $ docker build -t apache-train . [... OUTPUT COUPÉ ...] Step 5 : EXPOSE 80 ---> Using cache ---> 7648874030d3 Step 6 : CMD /etc/init.d/apache2 start ---> Running in 5921092110f2 ---> 8bd040c92c51 Removing intermediate container 5921092110f2 Successfully built 8bd040c92c51 $ docker run apache-train * Starting web server apache2 /usr/sbin/apache2ctl: 87: ulimit: error setting limit (Operation not permitted) Setting ulimit failed. See README.Debian for more information. AH00558: apache2: Could not reliably determine the server's fully qualified domain name, using 172.17.0.7. Set the 'ServerName' directive globally to suppress this message * $ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES

So the process of creating the image was a success but when running, apache is started but as the process is in the background the docker has stopped successfully. We see it when using the ps docker command.

Let’s go back to the first attempt with foregrounding (FOREGROUND) apache process if we look at the errors we had overall is due to undefined environment variables. When using the Service command, the latter loads the file, if you run the apache_train container you will be able to view this file:

# cat /etc/apache2/envvars | grep -v "^#" | grep -v "^$" unset HOME if [ "${APACHE_CONFDIR##/etc/apache2-}" != "${APACHE_CONFDIR}" ] ; then SUFFIX="-${APACHE_CONFDIR##/etc/apache2-}" else SUFFIX= fi export APACHE_RUN_USER=www-data export APACHE_RUN_GROUP=www-data export APACHE_PID_FILE=/var/run/apache2/apache2$SUFFIX.pid export APACHE_RUN_DIR=/var/run/apache2$SUFFIX export APACHE_LOCK_DIR=/var/lock/apache2$SUFFIX export APACHE_LOG_DIR=/var/log/apache2$SUFFIX export LANG=C export LANG

If you revitalize the errors, we will be able to note this lack:

[Tue Jul 12 17:25:05.374632 2016] [core:warn] [pid 1] AH00111: Config variable ${APACHE_LOCK_DIR} is not defined [Tue Jul 12 17:25:05.377490 2016] [core:warn] [pid 1] AH00111: Config variable ${APACHE_PID_FILE} is not defined [Tue Jul 12 17:25:05.377522 2016] [core:warn] [pid 1] AH00111: Config variable ${APACHE_RUN_USER} is not defined [Tue Jul 12 17:25:05.377529 2016] [core:warn] [pid 1] AH00111: Config variable ${APACHE_RUN_GROUP} is not defined [Tue Jul 12 17:25:05.377556 2016] [core:warn] [pid 1] AH00111: Config variable ${APACHE_LOG_DIR} is not defined

In order to correct this problem when creating the image so the Dockerfile I will pre defined these variables. This gives:

$ cat Dockerfile [... OUTPUT COUPÉ ...] # Fix timezone RUN ln -s -f /usr/share/zoneinfo/Canada/Eastern /etc/localtime ENV APACHE_RUN_USER www-data ENV APACHE_RUN_GROUP www-data ENV APACHE_PID_FILE /var/run/apache2.pid ENV APACHE_RUN_DIR /var/run/apache2 ENV APACHE_LOCK_DIR /var/lock/apache2 ENV APACHE_LOG_DIR /var/log/apache2 # Port exposer EXPOSE 80 CMD ["/usr/sbin/apache2","-DFOREGROUND"]

Let’s take again the creation of the image:

$ docker build -t apache-train . [... OUTPUT COUPÉ ...] Removing intermediate container 2be1c89d4526 Step 10 : ENV APACHE_LOG_DIR /var/log/apache2 ---> Running in 5eca720fb524 ---> 7746103ca4f7 Removing intermediate container 5eca720fb524 Step 11 : EXPOSE 80 ---> Running in 64727159ffb2 ---> 3fc14f0e80ac Removing intermediate container 64727159ffb2 Step 12 : CMD /usr/sbin/apache2 -DFOREGROUND ---> Running in 525ec50bd3aa ---> 52d35906d969 Removing intermediate container 525ec50bd3aa Successfully built 52d35906d969

Let’s run the image to create the container:

$ docker run apache-train AH00558: apache2: Could not reliably determine the server's fully qualified domain name, using 172.17.0.2. Set the 'ServerName' directive globally to suppress this message

As you can see the system does not give you back the hand, you have the apache process in the foreground, if you take another terminal you will see that the container is running.

$ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES e03dc52435a9 apache-train "/usr/sbin/apache2 - About a minute ago Up About a minute 80/tcp angry_tesla

In order to complete the validation, we retrieve the IP address of the container to confirm that we see the default apache page. As you can see the last column includes the “generic” name that was given to the container in this case angry_tesla, so we will use the docker inspect instruction to extract the IP address that was allocated by DHCP by the deamon docker.

$ docker inspect angry_tesla | grep IPAddress "IPAddress": "172.17.0.2", "SecondaryIPAddresses": null,

So if you go to the URL: http://172.17.0.2, you will have the default apache web page. Woot, it works, but because it often has but try another machine on your network to access the page with IP 172.17.0.2, you will find that it does NOT work :-(.

Network Consideration for the Apache Container

We have a container that runs the apache default page appears, but this is only accessible from the machine where the container rolls. Let’s take a few minutes to talk about sub-docker networking, let’s start with a graphical representation of IP addresses and network:

 
So here we have a docker host that has 2 containers, apache-train and apache-test (lack of imagination: P).

The docker host to the IP 192.168.42.25 on the network, if we need to establish an ssh connection, we use this IP address. The docker machine manages an “internal” network for the containers the selected network segment is 172.17.0.0/16 This network segment is known only to the docker host. When initializing a new container:

 

 

  1. docker initializes the instance of the container

  2. creates a virtual interface that will be the docker host example: vethcdff57c that will be associated with the container

  3. Docker creates an eth0 interface in the container and associate it with the created interface either vethcdff57c

  4. Subsequently the docker host frees in its IP address pool and assigns it to the container 172.17.0.4

So the 172.17.0.0/16 network segment is known only from the docker host it is not possible to communicate directly with the containers using their internal IP.

Yes, but I can connect from my container on the software depots to do the installations, so the network works even outside. Effectively outgoing communications works WITHOUT problem, is it magic?

I would like to say yes, but no … The magic is realized by a system of nat (Network Address Translation). What does it mean in French?

If you make the following order if your docker host you will have something similar:

$ sudo iptables -L -n -v -t nat [... OUTPUT COUPÉ ...] Chain POSTROUTING (policy ACCEPT 876 packets, 59176 bytes) pkts bytes target prot opt in out source destination 0 0 MASQUERADE all -- * !docker0 172.17.0.0/16 0.0.0.0/0 [... OUTPUT COUPÉ ...]

We use iptables which is the internal firewall to GNU / Linux, it is able to nat also.

Basically the following statement means, If the source IP address is in the 172.17.0.0/16 network segment then:

$ ipcalc 172.17.0.0/16 [... OUTPUT COUPÉ ...] HostMin: 172.17.0.1 10101100.00010001. 00000000.00000001 HostMax: 172.17.255.254 10101100.00010001. 11111111.11111110
So if the originating address is between IP 172.17.0.1 and 172.17.255.254 and the destination interface is NOT docker0 so that is not an internal communication between the containers then changes the IP address source in order to put the IP address: 192.168.42.45 (the it is implicit: P)

So let’s see the path of the network packets to clarify the situation a small picture often helps in the explanation:

 

If you are wondering how the system is able to transmit information when the remote server responds to it, when there is a change in iptables addressing maintain a lookup table in order to handle when the packets come back. It will redo the address change but instead of changing the Source of the packet it will change the destination, it will replace 192.168.42.45 by the IP of the container is 172.17.0.6 in our example.

Now that the explanation on outward communications is realized how do we do for externally initiated communications that wants to see the web page in the container. To do this we will associate a port with the “public” IP address on the network that will be associated with the container. In English / French we will do a port-forward.

 

Realize the operation to confirm that I do not lie to you: P, no joke to see the operation.

$ docker run -p 80:80 apache-train AH00558: apache2: Could not reliably determine the server's fully qualified domain name, using 172.17.0.2. Set the 'ServerName' directive globally to suppress this message

We use the -p option to set the port on the local machine -> to -> container port. If we carry out the netstat command we will see the available port

$ sudo netstat -lntp | grep 80 tcp6 0 0 :::80 :::* LISTEN 4608/docker-proxy $ ps aux | grep 4608 root 4608 0.0 0.7 837704 15600 ? Sl 17:02 0:00 docker-proxy -proto tcp -host-ip 0.0.0.0 -host-port 80 -container-ip 172.17.0.6 -container-port 80

Now we can access Apache’s default page from the entire network using the IP of the host machine. That’s http://192.168.42.45.

Super so we have a container with apache that works, available on the entire network, it’s time to put content on it.

Setting up the website

We arrive quietly in the hard, setting up the website so that it is available to all. Several methods are available for this operation, you will have to choose the most suitable for you. What will probably be a decision-making factor is the maturity of your site, if it is more static or enormously modified.

As a reminder, the docker system was originally set up to provide an application or service with a complete package (OS + application + all dependencies …) so we are talking about final version or at least that will be repackaged during modification so let’s see the first method using this mode.

Setting up the website via Git or Subversion

One method is to burn in the basic image the website, personally I find this solution the best, use the revision controller (Git or subversion or other) as source. Remember training git you could use a specific branch in order to have an exact version of your website in your apache container.

Let’s see an example with the git repository: https://github.com/shibarecords/siteweb_formation.

We have a website in git composed of 3 branches: master, 2.0 and 2.1.

We will see to set up the different version and management of the images. This is part modify our image in order to have an appropriate page with the branch master

# Définition de l'image de Base ( distribution ) FROM i686/ubuntu MAINTAINER Perret Paul 'paul.perret@patapouf.com' # Activation du mode non interactif pour apt ENV DEBIAN_FRONTEND noninteractive # Installation des applications de Base RUN apt-get update && apt-get install -y apache2 apache2-utils git && apt-get clean # Fix timezone RUN ln -s -f /usr/share/zoneinfo/Canada/Eastern /etc/localtime ENV APACHE_RUN_USER www-data ENV APACHE_RUN_GROUP www-data ENV APACHE_PID_FILE /var/run/apache2.pid ENV APACHE_RUN_DIR /var/run/apache2 ENV APACHE_LOCK_DIR /var/lock/apache2 ENV APACHE_LOG_DIR /var/log/apache2 ENV SITE_DOCROOT /var/www/html/ ENV SITE_REPO https://github.com/shibarecords/siteweb_formation ENV SITE_VERSION master # Mise en place du site RUN rm -rf $SITE_DOCROOT && git clone $SITE_REPO -b $SITE_VERSION $SITE_DOCROOT # Port exposer EXPOSE 80 CMD ["/usr/sbin/apache2","-DFOREGROUND"]

Small adjustment in the configuration first in addition to installing apache, we install the application git to allow us to recover the version of the website on the deposit. In addition I defined 3 variables:

  • SITE_DOCROOT : directory where we install the website

  • SITE_REPO : URL to checkout / retrieve the website

  • SITE_VERSION : the branch I want to extract

If we build and start the container we will have access to the website.

$ docker build -t apache-train . $ docker run apache-train AH00558: apache2: Could not reliably determine the server's fully qualified domain name, using 172.17.0.8. Set the 'ServerName' directive globally to suppress this message

If we want to create the container for version 2.0 of the site I only have to modify the variable SITE_VERSION. Of course we could use the same build command, but take the opportunity to see the use of tags available for the image.

$ cat Dockerfile [... OUTPUT COUPÉ ...] ENV SITE_DOCROOT /var/www/html/ ENV SITE_REPO https://github.com/shibarecords/siteweb_formation ENV SITE_VERSION 2.0 # Mise en place du site RUN rm -rf $SITE_DOCROOT && git clone $SITE_REPO -b $SITE_VERSION $SITE_DOCROOT [... OUTPUT COUPÉ ...] $ docker build -t apache-train:2.0 . [... OUTPUT COUPÉ ...] Step 11 : ENV SITE_DOCROOT /var/www/html/ ---> Using cache ---> ffb88a8f9010 Step 12 : ENV SITE_REPO https://github.com/shibarecords/siteweb_formation ---> Using cache ---> 96a00982c41c Step 13 : ENV SITE_VERSION 2.0 ---> Running in bb0f9948e540 ---> bb0edcfebf23 Removing intermediate container bb0f9948e540 Step 14 : RUN rm -rf $SITE_DOCROOT && git clone $SITE_REPO -b $SITE_VERSION $SITE_DOCROOT ---> Running in 620ecdce4428 Cloning into '/var/www/html'... ---> 19218c816f5b Removing intermediate container 620ecdce4428 Step 15 : EXPOSE 80 ---> Running in 0f3595f15808 ---> c74a55cf7036 Removing intermediate container 0f3595f15808 Step 16 : CMD /usr/sbin/apache2 -DFOREGROUND ---> Running in f56d32de0082 ---> 8e8ba8bd17ac Removing intermediate container f56d32de0082 Successfully built 8e8ba8bd17ac

As you can see the entire creation of the container was not redone, as we had similar creation layers between the master version and version 2.0 it reuses the layers of creation until the first difference.

Result if we display the images available on the system we have the master version == latest and version 2.0 which is named with the same number.

$ docker images | grep apache apache-train 2.0 8e8ba8bd17ac 3 minutes ago 339.1 MB apache-train latest 865ad6322b1b 18 minutes ago 339.1 MB

Now you can start the version of your website:

$ docker run apache-train AH00558: apache2: Could not reliably determine the server's fully qualified domain name, using 172.17.0.10. Set the 'ServerName' directive globally to suppress this message $ docker run apache-train:2.0 AH00558: apache2: Could not reliably determine the server's fully qualified domain name, using 172.17.0.11. Set the 'ServerName' directive globally to suppress this message

Setting up the website with a volume

For people with a “mature” website that does not move much or is evolving with a well-defined release system this is fine though if you have a small personal site that moves quietly in time it is likely that this solution is binding. So we will see another solution, we will externalize the website of the container. This solution is less beautiful, because not having the website included in the container is not complete, but everyone that reality with the constraints.

Let’s see the volume system This mechanism allows to define a directory of the docker host in the container. I’ll start by removing the git command from the DockerFile to no longer include the website in the container.

Here is the result of the DockerFile:

 

# Définition de l'image de Base ( distribution ) FROM i686/ubuntu MAINTAINER Paul Perret 'paul.perret@patapouf.com' # Activation du mode non interactif pour apt ENV DEBIAN_FRONTEND noninteractive # Installation des applications de Base RUN apt-get update && apt-get install -y apache2 apache2-utils git && apt-get clean # Fix timezone RUN ln -s -f /usr/share/zoneinfo/Canada/Eastern /etc/localtime ENV APACHE_RUN_USER www-data ENV APACHE_RUN_GROUP www-data ENV APACHE_PID_FILE /var/run/apache2.pid ENV APACHE_RUN_DIR /var/run/apache2 ENV APACHE_LOCK_DIR /var/lock/apache2 ENV APACHE_LOG_DIR /var/log/apache2 # Port exposer EXPOSE 80 CMD ["/usr/sbin/apache2","-DFOREGROUND"]

I build the image with the tag: flat:

$ docker build -t apache-train:flat . Sending build context to Docker daemon 44.54 kB Sending build context to Docker daemon Step 0 : FROM i686/ubuntu ---> 6a6004b92956 [ ... OUTPUT COUPÉ ...] Removing intermediate container 71625a7802d8 Successfully built 0e166a670d17 $ docker images | grep flat apache-train flat 0e166a670d17 About a minute ago 338.6 MB

If we start the container we will have the apache default page:

$ docker run apache-train:flat AH00558: apache2: Could not reliably determine the server's fully qualified domain name, using 172.17.0.1. Set the 'ServerName' directive globally to suppress this message

Stop the container and make the mount point / volume. First I create the website in the directory / data / apache / html and restart the apache container with the volume.

$ sudo mkdir -p /data/apache/html $ sudo vim /data/apache/html/index.html $ sudo cat /data/apache/html/index.html Super site web directement dans le docker host

Starting the container

$ docker run -v /data/apache/html/:/var/www/html apache-train:flat AH00558: apache2: Could not reliably determine the server's fully qualified domain name, using 172.17.0.2. Set the 'ServerName' directive globally to suppress this message

If we go to the URL: http://172.17.0.2, we will have the page previously created, we can modify the file index.html without having to redo / recreate a container.

But I repeat this solution to a major drawback the fact that the container is not complete however this allows you to easily isolate your apache application from the rest of the system. As I like less this solution I will return to the method with the extraction system of the site with git, it is my formation I am free: P, by cons we will see an interesting use of the volume, all of continuation: D.

Preservation of site data (container volume and naming)

Reprenons donc notre conteneur avec l’extraction du site avec le système de git , je vais aussi réaliser une petite modification afin d’avoir php de présent afin de faire une démonstration. De plus j’ai créer la branche 2.2 du site web , car nous avons une nouvelle version celle ci utilisant php.

Voici le résultat du DockerFile :

# Définition de l'image de Base ( distribution ) FROM i686/ubuntu MAINTAINER Perret paul 'paul.perret@patapouf.com' # Activation du mode non interactif pour apt ENV DEBIAN_FRONTEND noninteractive # Installation des applications de Base RUN apt-get update && apt-get install -y apache2 apache2-utils git libapache2-mod-php5 && apt-get clean # Fix timezone RUN ln -s -f /usr/share/zoneinfo/Canada/Eastern /etc/localtime ENV APACHE_RUN_USER www-data ENV APACHE_RUN_GROUP www-data ENV APACHE_PID_FILE /var/run/apache2.pid ENV APACHE_RUN_DIR /var/run/apache2 ENV APACHE_LOCK_DIR /var/lock/apache2 ENV APACHE_LOG_DIR /var/log/apache2 ENV SITE_DOCROOT /var/www/html/ ENV SITE_REPO https://github.com/shibarecords/siteweb_formation ENV SITE_VERSION 2.2 # Mise en place du site RUN rm -rf $SITE_DOCROOT && git clone $SITE_REPO -b $SITE_VERSION $SITE_DOCROOT && chown $APACHE_RUN_USER:$APACHE_RUN_GROUP $SITE_DOCROOT/data # Port exposer EXPOSE 80 CMD ["/usr/sbin/apache2","-DFOREGROUND"]

I realize the apache-train image: 2.2 with this new configuration

$ docker build -t apache-train:2.2 .

We run it

$ docker run apache-train:2.2 AH00558: apache2: Could not reliably determine the server's fully qualified domain name, using 172.17.0.7. Set the 'ServerName' directive globally to suppress this message

If you go to the web page http://172.17.0.7 you will have the page with the sheep, I added a small php file named cfile.php it makes the creation of 10 files in the directory / var / www / html / data on the server.

Let’s look at the mechanism together, before generating the files we will see the contents of the directory, to do this we will go in interactive mode in the container. I use the ps docker command to list the running containers.

$ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES e05bf8a9adae apache-train:2.2 "/usr/sbin/apache2 - 4 seconds ago Up 3 seconds 80/tcp admiring_feynman

We see our container based on the apache-train image: 2.2, which is running for 4 seconds, the container name is admiring_feynman. I will use this name to connect to it.

$ docker exec -it admiring_feynman bash root@e05bf8a9adae:/# ls bin boot dev etc home lib media mnt opt proc root run sbin srv sys tmp usr var root@e05bf8a9adae:/# ls /var/www/html/ LICENSE cfile.php data data.dtd dessin_mouton.jpg index.html root@e05bf8a9adae:/# ls /var/www/html/data README

The website is present as well as the directory containing the data, if we access the URL http://172.17.0.7/cfile.php you should have the following information in your browser:

58 58 58 58 58 58 58 58 58 58

In addition, we will have 10 files in the directory / var / www / html / data:

root@e05bf8a9adae:/# ls /var/www/html/data 0.txt 1.txt 2.txt 3.txt 4.txt 5.txt 6.txt 7.txt 8.txt 9.txt README

If I stop the container, and restart it, all cleanly:

root@e05bf8a9adae:/# exit $ docker stop admiring_feynman $ docker run apache-train:2.2 AH00558: apache2: Could not reliably determine the server's fully qualified domain name, using 172.17.0.8. Set the 'ServerName' directive globally to suppress this message $ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 4dcddcf83a7b apache-train:2.2 "/usr/sbin/apache2 - 48 seconds ago Up 46 seconds 80/tcp lonely_pare $ docker exec -it lonely_pare bash root@4dcddcf83a7b:/# ls /var/www/html/ LICENSE cfile.php data data.dtd dessin_mouton.jpg index.html root@4dcddcf83a7b:/# ls /var/www/html/data README

If you remember during the presentation of docker we made mention that the system works with layers the upper layer is by default ephemeral, it is present only when running the container.

Defining a volume for data

So all the data was written in this layer that disappeared when the container was shut down. This can be very problematic, so to correct this problem we can set up the volume system not on the entire website but on the data written when using the container.

$ sudo mkdir -p /data/data-site/ $ docker run -v /data/data-site/:/var/www/html/data apache-train:2.2 AH00558: apache2: Could not reliably determine the server's fully qualified domain name, using 172.17.0.1. Set the 'ServerName' directive globally to suppress this message $ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES cd07dc0a105c apache-train:2.2 "/usr/sbin/apache2 - 5 seconds ago Up 3 seconds 80/tcp jolly_pare $ docker exec -it jolly_pare bash root@cd07dc0a105c:/# ls /var/www/html/data root@cd07dc0a105c:/#

If we go to the website http://172.17.0.1, we can see the web page with the sheep: D. If we access the URL http://172.17.0.1/cfile.php we do not see the digit list as before: – /. Let’s analyze the problem together This is a “classic” problem when using volumes. Let’s start with the apache server logs which will probably give us some information:

root@cd07dc0a105c:/# tail /var/log/apache2/error.log [Wed Aug 03 08:25:07.437086 2016] [:error] [pid 7] [client 172.17.42.1:41958] PHP Warning: fclose() expects parameter 1 to be resource, boolean given in /var/www/html/cfile.php on line 9 [Wed Aug 03 08:25:07.437132 2016] [:error] [pid 7] [client 172.17.42.1:41958] PHP Warning: fopen(./data/7.txt): failed to open stream: Permission denied in /var/www/html/cfile.php on line 7

The message is clear the apache system is not able to open / write in the data directory, let’s validate the permissions of this directory.

root@cd07dc0a105c:/# ls -ld /var/www/html/data drwxr-xr-x 2 root root 4096 Aug 3 08:22 /var/www/html/data

Oupss yet it worked before, we had it defined in the file DockerFile during the creation of the container. Here’s what’s in the DockerFile for creating the directory:

# Mise en place du site RUN rm -rf $SITE_DOCROOT && git clone $SITE_REPO -b $SITE_VERSION $SITE_DOCROOT && chown $APACHE_RUN_USER:$APACHE_RUN_GROUP $SITE_DOCROOT/data

When using the volume, the latter at the top of the system layer of the container is a bit like when we do a mount bind we end up with the new mount point over the original file system. The solution sets the correct permissions on the file system of the docker host. We must therefore allow the www-data user to be written to the docker host’s directory / data / data-site.

$ sudo chown www-data:www-data /data/data-site chown: invalid user: ‘www-data:www-data’

Oupss the user www-data does not exist on my system 🙁 it is present ONLY in my container, how can I solve this problem? In fact the GNU / Linux system file he does not care about the name : P, it’s really only to make it simpler for humans, but the system only stores the UID and GID of the user, so if I know this information I can associate them with the directory and they will be well represented in the container … Demonstration, firstly I get the UID and GID of the user in the container

root@cd07dc0a105c:/# id www-data uid=33(www-data) gid=33(www-data) groups=33(www-data) $ sudo chown 33:33 /data/data-site/ root@cd07dc0a105c:/# ls -ld /var/www/html/data drwxr-xr-x 2 www-data www-data 4096 Aug 3 08:22 /var/www/html/data

WOOT magic: D, let’s validate that this works now, so I go back to the URL http://172.17.0.1/cfile.php, now I have the number list. If we look in the container and on the docker host we will have the data.

root@cd07dc0a105c:/# ls -l /var/www/html/data total 40 -rw-r--r-- 1 www-data www-data 58 Aug 3 08:42 0.txt -rw-r--r-- 1 www-data www-data 58 Aug 3 08:42 1.txt -rw-r--r-- 1 www-data www-data 58 Aug 3 08:42 2.txt -rw-r--r-- 1 www-data www-data 58 Aug 3 08:42 3.txt -rw-r--r-- 1 www-data www-data 58 Aug 3 08:42 4.txt -rw-r--r-- 1 www-data www-data 58 Aug 3 08:42 5.txt -rw-r--r-- 1 www-data www-data 58 Aug 3 08:42 6.txt -rw-r--r-- 1 www-data www-data 58 Aug 3 08:42 7.txt -rw-r--r-- 1 www-data www-data 58 Aug 3 08:42 8.txt -rw-r--r-- 1 www-data www-data 58 Aug 3 08:42 9.txt $ ls -l /data/data-site/ total 40 -rw-r--r-- 1 http http 58 Aug 3 08:42 0.txt -rw-r--r-- 1 http http 58 Aug 3 08:42 1.txt -rw-r--r-- 1 http http 58 Aug 3 08:42 2.txt -rw-r--r-- 1 http http 58 Aug 3 08:42 3.txt -rw-r--r-- 1 http http 58 Aug 3 08:42 4.txt -rw-r--r-- 1 http http 58 Aug 3 08:42 5.txt -rw-r--r-- 1 http http 58 Aug 3 08:42 6.txt -rw-r--r-- 1 http http 58 Aug 3 08:42 7.txt -rw-r--r-- 1 http http 58 Aug 3 08:42 8.txt -rw-r--r-- 1 http http 58 Aug 3 08:42 9.txt

If we stop the container and restart it we will still have the data as they are contained on the docker host.

$ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES cd07dc0a105c apache-train:2.2 "/usr/sbin/apache2 - 5 seconds ago Up 3 seconds 80/tcp jolly_pare $ docker stop jolly_pare jolly_pare $ docker run -v /data/data-site/:/var/www/html/data apache-train:2.2 AH00558: apache2: Could not reliably determine the server's fully qualified domain name, using 172.17.0.2. Set the 'ServerName' directive globally to suppress this message $ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES bdb7aab8b32d apache-train:2.2 "/usr/sbin/apache2 - 25 seconds ago Up 24 seconds 80/tcp kickass_newton $ docker exec -it kickass_newton bash root@bdb7aab8b32d:/# ls -l /var/www/html/data total 40 -rw-r--r-- 1 www-data www-data 58 Aug 3 08:42 0.txt -rw-r--r-- 1 www-data www-data 58 Aug 3 08:42 1.txt -rw-r--r-- 1 www-data www-data 58 Aug 3 08:42 2.txt -rw-r--r-- 1 www-data www-data 58 Aug 3 08:42 3.txt -rw-r--r-- 1 www-data www-data 58 Aug 3 08:42 4.txt -rw-r--r-- 1 www-data www-data 58 Aug 3 08:42 5.txt -rw-r--r-- 1 www-data www-data 58 Aug 3 08:42 6.txt -rw-r--r-- 1 www-data www-data 58 Aug 3 08:42 7.txt -rw-r--r-- 1 www-data www-data 58 Aug 3 08:42 8.txt -rw-r--r-- 1 www-data www-data 58 Aug 3 08:42 9.txt

Naming the container to keep site data

The other way is to make sure that the top layer is kept and recalled when starting the container:

To do this we will name the container, this will give us a fixed name unlike those dynamically generated as we have used so far. Demonstration of the operation without the volume but with the naming of the container.

$ docker run --name shibarecords apache-train:2.2 AH00558: apache2: Could not reliably determine the server's fully qualified domain name, using 172.17.0.3. Set the 'ServerName' directive globally to suppress this message

So I started the apache-train image: 2.2 by explicitly naming the shibarecords container.

CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 14979a4cf52c apache-train:2.2 "/usr/sbin/apache2 - 49 seconds ago Up 48 seconds 80/tcp shibarecords

If we look at the contents of the data directory of the site:

$ docker exec -it shibarecords bash root@14979a4cf52c:/# ls -l /var/www/html/data total 4 -rw-r--r-- 1 root root 40 Aug 2 08:32 README

I access the URL for creating files: http://172.17.0.3/cfile.php, I have the list of numbers and if we look at the contents of the directory the whole is present:

root@14979a4cf52c:/# ls -l /var/www/html/data total 44 -rw-r--r-- 1 www-data www-data 58 Aug 3 09:00 0.txt -rw-r--r-- 1 www-data www-data 58 Aug 3 09:00 1.txt -rw-r--r-- 1 www-data www-data 58 Aug 3 09:00 2.txt -rw-r--r-- 1 www-data www-data 58 Aug 3 09:00 3.txt -rw-r--r-- 1 www-data www-data 58 Aug 3 09:00 4.txt -rw-r--r-- 1 www-data www-data 58 Aug 3 09:00 5.txt -rw-r--r-- 1 www-data www-data 58 Aug 3 09:00 6.txt -rw-r--r-- 1 www-data www-data 58 Aug 3 09:00 7.txt -rw-r--r-- 1 www-data www-data 58 Aug 3 09:00 8.txt -rw-r--r-- 1 www-data www-data 58 Aug 3 09:00 9.txt -rw-r--r-- 1 root root 40 Aug 2 08:32 README

I close the container and restart it

$ docker stop shibarecords shibarecords $ docker start shibarecords shibarecords $ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 14979a4cf52c apache-train:2.2 "/usr/sbin/apache2 - 8 hours ago Up 10 seconds 80/tcp shibarecords $ docker exec -it shibarecords bash root@14979a4cf52c:/# ls -l /var/www/html/data total 44 -rw-r--r-- 1 www-data www-data 58 Aug 3 09:00 0.txt -rw-r--r-- 1 www-data www-data 58 Aug 3 09:00 1.txt -rw-r--r-- 1 www-data www-data 58 Aug 3 09:00 2.txt -rw-r--r-- 1 www-data www-data 58 Aug 3 09:00 3.txt -rw-r--r-- 1 www-data www-data 58 Aug 3 09:00 4.txt -rw-r--r-- 1 www-data www-data 58 Aug 3 09:00 5.txt -rw-r--r-- 1 www-data www-data 58 Aug 3 09:00 6.txt -rw-r--r-- 1 www-data www-data 58 Aug 3 09:00 7.txt -rw-r--r-- 1 www-data www-data 58 Aug 3 09:00 8.txt -rw-r--r-- 1 www-data www-data 58 Aug 3 09:00 9.txt -rw-r--r-- 1 root root 40 Aug 2 08:32 README

As we can see the container still contains all the data generated by the system, the layer (spreading) of data was retained despite the restart. However, this layer is only kept on the docker host and not on the original image, at this point you had to plan your data management: D.

Nothing prevents you from using both the volume and the naming of the container !!

Configuration

Configuration Apache

We covered the issue of setting up the website, as well as the question of storing information, but nothing about the configuration of the apache server. I think the time has come to cover this point no less critical especially if you have a complete website see complex.

The solutions are still multiple, of course it is still possible to make a mount point with the volume, however you may quickly have a management problem or standardization if you have a large number of server.

The Apache configuration is linked to your application, if you have instructions such as mod_rewrite or authentication sections this applies all the time. We will therefore set up a standard generic configuration in the base image and then customize it when running the container.

First, let’s modify the git repository web site to include the configuration.

$ cd siteweb_formation/ $ ls cfile.php data data.dtd dessin_mouton.jpg index.html LICENSE $ git branch 2.0 2.1 * 2.2 master

We will create branch 3.0 to include the new configuration, it will be cleaner.

$ git checkout -b 3.0 Switched to a new branch '3.0'

I’m going to put the whole site under a docroot directory and set apache configuration under apacheConf, I’m also creating a privates directory for offsite data.

$ mkdir docroot $ mv * docroot mv: cannot move ‘docroot’ to a subdirectory of itself, ‘docroot/docroot’ $ mkdir apacheConf privates

Here is the apache configuration:

$ cat apacheConf/siteA.conf ServerAdmin ${SERVER_ADMIN} DocumentRoot /var/www/html/docroot Options Indexes AllowOverride None # Section d'authentification AuthType Basic AuthName "Authentication Required" AuthUserFile "/var/www/html/privates/htpasswd" Require ${VALIDE_USER} ErrorLog ${APACHE_LOG_DIR}/error.log CustomLog ${APACHE_LOG_DIR}/access.log combined

As you can see I have set environment variables for the ServerAdmin and Require statement. This will allow us to have a docker image usable for all deployments. We will see how to set the values when starting the container. We can plan that the value in place for the email is distinct from the development or production environment, this is the same for the access authorization to the data directory.

As you can see I have set a password file in the privates directory so I will also define a htpasswd file.

$ htpasswd -c privates/htpasswd admin $ htpasswd privates/htpasswd tom $ htpasswd privates/htpasswd bob $ cat privates/htpasswd tom:$apr1$nh2m2SRP$Vr7T.s8jH3n2F6tQECUc9/ bob:$apr1$UTUQuKYU$Ot1G/ICuCWvtdF48C4Lkg1 robert:$apr1$.2jP2rT4$c7Ddv9YMdzYj.UYpUReFi. admin:$apr1$bYi5/UtQ$17RBM3ieAzaQRRIYJcOHO.

We add it all in git and push to the server git: D.

$ git add * $ git commit -a -m "Version 3.0 avec configuration apache plus fichier de mot de passe" $ git push origin master

The DockerFile is now modified to reflect this new configuration.

$ cat DockerFile FROM i686/ubuntu MAINTAINER Paul Perret 'paul.perret@patapouf.com' # Activation du mode non interactif pour apt ENV DEBIAN_FRONTEND noninteractive # Installation des applications de Base RUN apt-get update && apt-get install -y apache2 apache2-utils git libapache2-mod-php5 && apt-get clean # Fix timezone RUN ln -s -f /usr/share/zoneinfo/Canada/Eastern /etc/localtime ENV APACHE_RUN_USER www-data ENV APACHE_RUN_GROUP www-data ENV APACHE_PID_FILE /var/run/apache2.pid ENV APACHE_RUN_DIR /var/run/apache2 ENV APACHE_LOCK_DIR /var/lock/apache2 ENV APACHE_LOG_DIR /var/log/apache2 ENV SITE_DOCROOT /var/www/html/ ENV SITE_REPO https://github.com/shibarecords/siteweb_formation ENV SITE_VERSION 3.0 # Mise en place du site RUN rm -rf $SITE_DOCROOT && git clone $SITE_REPO -b $SITE_VERSION $SITE_DOCROOT && chown $APACHE_RUN_USER:$APACHE_RUN_GROUP $SITE_DOCROOT/docroot/data RUN cp $SITE_DOCROOT/apacheConf/* /etc/apache2/sites-available/ && a2dissite 000-default && a2ensite siteA # Port exposer EXPOSE 80 CMD ["/usr/sbin/apache2","-DFOREGROUND"]

We build everything:

$ docker build -t apache-train:3.0 .

We execute:

$ docker run apache-train:3.0 [Wed Aug 03 17:43:36.836978 2016] [core:warn] [pid 1] AH00111: Config variable ${SERVER_ADMIN} is not defined [Wed Aug 03 17:43:36.839862 2016] [core:warn] [pid 1] AH00111: Config variable ${VALIDE_USER} is not defined AH00526: Syntax error on line 14 of /etc/apache2/sites-enabled/siteA.conf: Unknown Authz provider: ${VALIDE_USER}

Oupss actually I defined particular configurations via the environment variables in the apache configuration but I did not provide them at startup … Let’s fix the problem immediately. In the example below I start with a phony email for the administrator or I allow any valid user to establish a connection in the data directory

$ docker run --env SERVER_ADMIN=toto@shibarecords.com --env VALIDE_2USER=valid-user apache-train:3.0 AH00558: apache2: Could not reliably determine the server's fully qualified domain name, using 172.17.0.10. Set the 'ServerName' directive globally to suppress this message

Here is another example of use for production for example:

$ docker run --env SERVER_ADMIN=prod@shibarecords.com --env VALIDE_2USER="user admin" apache-train:3.0 AH00558: apache2: Could not reliably determine the server's fully qualified domain name, using 172.17.0.6. Set the 'ServerName' directive globally to suppress this message

In this last example only the admin account can see the contents of the directory.

Application Configuration

Super so apache configuration management is done, you have to put more meat according to your needs but the concept is presented. Now let’s go to the application configuration, in fact it is very likely that if your application uses a Database to work it is not the same for production or development.

I will create another branch, yes yes again: P

$ git checkout -b 3.1 Switched to a new branch '3.1' $ vim docroot/config.conf $ cat docroot/config.conf database_host = ${DB_HOST} database_user = ${DB_USER} database_pass = ${DB_PASS} database_db = ${DB_DB}

I still use the same definition of variable … We commit and validate, this is exactly the moment when we should not skip the presentation, because it will not work I tell you all right now: P.

$ git commit -a -m "Ajout de la configuration DB" [3.1 2e804ed] Ajout de la configuration DB 1 file changed, 4 insertions(+) create mode 100644 docroot/config.conf $ git push origin 3.1

I modify the DockerFile to use the new branch during the build

ENV SITE_VERSION 3.1

Then we build:

$ docker build -t apache-train:3.1 .

We use the argument passage to start the container

$ docker run --env SERVER_ADMIN=toto@shibarecords.com --env VALIDE_USER="user admin" --env DB_HOST=db.shibarecords.com --env DB_USER=toto --env DB_PASS=password --env DB_DB=mydb apache-train:3.1 AH00558: apache2: Could not reliably determine the server's fully qualified domain name, using 172.17.0.10. Set the 'ServerName' directive globally to suppress this message

We go to the URL: http://172.17.0.10/config.conf and there … uh … it has not changed! The apache daemon is smart enough to support environment variables unfortunately it is not native to all applications. We will have to put an additional mechanism. When starting the container I will extract the environment variables and make a small sed (search and replace) to define the right values.

Let’s start with writing the script:

$ mkdir scripts $ vim scripts/sed_var.sh $ cat scripts/sed_var.sh #!/bin/bash LST_VAR=$(env | grep ^DB) for env_2_change in $LST_VAR ; do ENV_NAME=$(echo $env_2_change | cut -d "=" -f 1) ENV_VAL=$(echo $env_2_change | cut -d "=" -f 2-) sed -i "s/${$ENV_NAME}/$ENV_VAL/g" docroot/config.conf done

Quickly, I put all the variables starting with the letters DB and I put it in a list. I loop through this list and separate the name of the variable (ENV_NAME) with the value (ENV_VAL). I make a sed that will modify the file thanks to the -i option. I present the concept, to you to adapt it for your needs the complexity of this scripts can increase it will be possible also to use ansible or puppet to you to see: D.

So this script must be executed when starting the container, in addition to the execution of the apache process of course. Variable change should be done preferably with startup. We will modify the DockerFile to allow this operation.

So I’m going to write another start.sh startup script that will do both of these things.

$ vim scripts/start.sh $ cat scripts/start.sh #!/bin/bash # Changement des variables /usr/local/sbin/sed_var.sh # Démarrage du processus apache /usr/sbin/apache2 -DFOREGROUND

We modify the DockerFile:

$ cat DockerFile [ ... OUTPUT COUPÉ ...] # Mise en place du site RUN rm -rf $SITE_DOCROOT && git clone $SITE_REPO -b $SITE_VERSION $SITE_DOCROOT && chown $APACHE_RUN_USER:$APACHE_RUN_GROUP $SITE_DOCROOT/docroot/data RUN cp $SITE_DOCROOT/apacheConf/* /etc/apache2/sites-available/ && a2dissite 000-default && a2ensite siteA # Copy SCRIPTS COPY scripts/*.sh /usr/local/sbin/ RUN chmod a+x /usr/local/sbin/*.sh # Port exposer EXPOSE 80 CMD ["/usr/local/sbin/start.sh"]

So I added the COPY of the new scripts, modified the RUN permissions and changed the run command of the container to use the start.sh script.

We start the build (we will eventually get a little coffee :)), and we will run the container:

$ docker build -t apache-train:3.1 . $ docker run --env SERVER_ADMIN=toto@shibarecords.com --env VALIDE_USER="user admin" --env DB_HOST=db.shibarecords.com --env DB_USER=toto --env DB_PASS=password --env DB_DB=mydb apache-train:3.1 AH00558: apache2: Could not reliably determine the server's fully qualified domain name, using 172.17.0.4. Set the 'ServerName' directive globally to suppress this message

If we go to the URL http://172.17.0.4/config.conf all values were changed !!! WOOT.

Thanks to this solution you have ONE reference images and when using it the context is passed to distinguish the specificity, such as the environment of DEV or other.

Viewing Apache logs

Let’s continue the process of improvement of the solution ;-), in fact even at the end of this presentation there will be still possible improvements but must know sometimes stop.

So we have an image containing our site and a basic configuration that is set up when the container starts. Of course, like all systems in operation, there is a problem of operation, so we will be obliged to consult the application logs. The best solution is to have a centralized syslog server allowing the recovery of all the logs of the networks which allows to carry out an analysis, with generation of graph, etc …

Well this being said if you have some container you do not want to add this layer of complexity, we will see to view the apache logs with the docker logs statement.

Currently, if we do the docker logs instruction we have what the / usr / sbin / apache2 -DFOREGROUND command provides on the screen. It is likely that you prefer to see the error messages and / or possibly the access logs to the site.

It should be known that the docker logs instruction can be executed remotely or certain application allows to display this information via a web page … For example docker UI if I am not mistaken: D.

Realize the modification of the Docker in order to have this functionality to do this we will modify the startup script.

$ vim scripts/start.sh $ cat scripts/start.sh #!/bin/bash # Changement des variables /usr/local/sbin/sed_var.sh # Démarrage du processus apache /usr/sbin/apache2 # Affichage des logs tail -f /var/log/apache2/error.log /var/log/apache2/access.log

We build the container and run it:

$ docker build -t apache-train:3.1 . $ docker run --env SERVER_ADMIN=toto@shibarecords.com --env VALIDE_USER="user admin" --env DB_HOST=db.shibarecords.com --env DB_USER=toto --env DB_PASS=password --env DB_DB=mydb apache-train:3.1 AH00558: apache2: Could not reliably determine the server's fully qualified domain name, using 172.17.0.3. Set the 'ServerName' directive globally to suppress this message ==> /var/log/apache2/error.log <== [Mon Aug 01 21:39:05.645683 2016] [mpm_event:notice] [pid 2581:tid 3074931328] AH00489: Apache/2.4.7 (Ubuntu) configured -- resuming normal operations [Mon Aug 01 21:39:05.645902 2016] [core:notice] [pid 2581:tid 3074931328] AH00094: Command line: '/usr/sbin/apache2' [Mon Aug 01 21:39:11.891689 2016] [mpm_event:notice] [pid 2581:tid 3074931328] AH00491: caught SIGTERM, shutting down [Mon Aug 01 21:39:12.080570 2016] [mpm_prefork:notice] [pid 3709] AH00163: Apache/2.4.7 (Ubuntu) configured -- resuming normal operations [Mon Aug 01 21:39:12.083256 2016] [core:notice] [pid 3709] AH00094: Command line: '/usr/sbin/apache2' [Mon Aug 01 21:39:13.577065 2016] [mpm_prefork:notice] [pid 3709] AH00169: caught SIGTERM, shutting down [Mon Aug 01 21:39:14.838949 2016] [mpm_prefork:notice] [pid 3785] AH00163: Apache/2.4.7 (Ubuntu) PHP/5.5.9-1ubuntu4.17 configured -- resuming normal operations [Mon Aug 01 21:39:14.839074 2016] [core:notice] [pid 3785] AH00094: Command line: '/usr/sbin/apache2' ==> /var/log/apache2/access.log <== ==> /var/log/apache2/error.log <== [Fri Aug 05 17:07:36.342459 2016] [mpm_prefork:notice] [pid 40] AH00163: Apache/2.4.7 (Ubuntu) PHP/5.5.9-1ubuntu4.17 configured -- resuming normal operations [Fri Aug 05 17:07:36.342649 2016] [core:notice] [pid 40] AH00094: Command line: '/usr/sbin/apache2'

If you go to the container web page, you will see the contents of the access file.

Emergency corrective

Good for environments in use it is fine, but what to do if there is an emergency modification to made, indeed you must make an emergency modification on a configuration see an application file. The answer is normally to redo a version contained in git and redo the image to redeploy it.

If you suggest this solution to change the email address for example it is possible that people in charge is very cautious to perform this operation. So we are going to cover a possibility that does not follow good practice, but the operational reality makes it sometimes difficult to always follow good practice.

It is possible to make a modification on a running container without having to redo the build, I will make an example I will add an option in the configuration file which will contain the type of encryption to use.

Fichier : $DOC_ROOT/docroot/config.conf database_crypt = TLS

If I look at the running container if I simply add and stop and restart the container I will lose the change.

$ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 2ced572f0476 apache-train:3.1 "/usr/local/sbin/sta 12 minutes ago Up 12 minutes 80/tcp jolly_blackwell5 $ docker exec -it jolly_blackwell5 bash root@2ced572f0476:/# echo "database_crypt = TLS" >> /var/www/html/docroot/config.conf root@2ced572f0476:/# cat /var/www/html/docroot/config.conf database_host = db.shibarecords.com database_user = toto database_pass = password database_db = mydb database_crypt = TLS

I stop and restart

$ docker stop jolly_blackwell5 $ docker run --env SERVER_ADMIN=toto@shibarecords.com --env VALIDE_USER="user admin" --env DB_HOST=db.shibarecords.com --env DB_USER=toto --env DB_PASS=password --env DB_DB=mydb apache-train:3.1 $ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 62f90667a188 apache-train:3.1 "/usr/local/sbin/sta 16 seconds ago Up 15 seconds 80/tcp silly_hodgkin $ docker exec -it silly_hodgkin bash root@62f90667a188:/# cat /var/www/html/docroot/config.conf database_host = db.shibarecords.com database_user = toto database_pass = password database_db = mydb

Now the “Fix”, I redo the modification but in addition I COMMIT the change.

root@62f90667a188:/# echo "database_crypt = TLS" >> /var/www/html/docroot/config.conf root@62f90667a188:/# exit exit $ docker commit -m " Ajout option database_crypt = TLS " silly_hodgkin apache-train:3.1 b118bcb68f95723e4e004ea6ba6a36ac8f4078eaf2bcd35a591e1e6f1a1851ba

With the docker commit statement I burn the new configuration in the container, the -m option allows me to define a message in order to know the modification made. Validate the result by stopping the container and restarting it.

$ docker stop silly_hodgkin silly_hodgkin $ docker run --env SERVER_ADMIN=toto@shibarecords.com --env VALIDE_USER="user admin" --env DB_HOST=db.shibarecords.com --env DB_USER=toto --env DB_PASS=password --env DB_DB=mydb apache-train:3.1 $ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 713d27ebc826 apache-train:3.1 "/usr/local/sbin/sta 12 seconds ago Up 10 seconds 80/tcp lonely_wozniak $ docker exec -it lonely_wozniak bash root@713d27ebc826:/# cat /var/www/html/docroot/config.conf database_host = db.shibarecords.com database_user = toto database_pass = password database_db = mydb database_crypt = TLS

YEAHH it really works ;-), with the docker history command you can review the change that was made.

$ docker history apache-train:3.1 IMAGE CREATED CREATED BY SIZE COMMENT b118bcb68f95 3 minutes ago /usr/local/sbin/start.sh 1.48 kB Ajout option database_crypt = TLS 5127cb299161 21 minutes ago /bin/sh -c #(nop) CMD ["/usr/local/sbin/start 0 B 12d36e660e8f 21 minutes ago /bin/sh -c #(nop) EXPOSE 80/tcp 0 B 1c669168c35f 21 minutes ago /bin/sh -c chmod a+x /usr/local/sbin/*.sh 679 B [ ... OUTPUT COUPÉ ... ]

I should have put the -a option to specify the author … When the docker commit but you see the result.

WARNING: you must modify the GIT repository to keep the new configuration for the next build of the image !!!

Docker-Compose to simplify