After having played a little bit with Docker, it's time to try something more serious: I'll try to set up a Drupal web server, relying on following containers:
In order to have data-only containers with minimal disk space overhead, I'll build them on a Busybox image. But this will require additional containers, used for initialization (there could be some other solutions but, being a Docker beginner, I didn't find a good one).
The working directory I'll use, on my Linux development machine, is /root/dockerTests/. [I upgraded my Mac to Yosemite, and it seems that this had a bad side effect of docker2boot, so I switched back to Linux, before spending some time on cleaning Docker configuration on the Mac.]
So, let's go!
#DOCKER-VERSION 1.3.0 # We'll rely on Ubuntu 14.04 LTS. FROM ubuntu:14.04 # Install required software. RUN DEBIAN_FRONTEND=noninteractive apt-get update && apt-get install -y \ apache2 \ libapache2-mod-auth-mysql \ libapache2-mod-php5 \ nano \ php5 \
php5-gd \ php5-mcrypt \ php5-mysql # Activate Drupal web site. ADD drupal.conf /etc/apache2/sites-available/ RUN a2dissite 000-default RUN a2ensite drupal # Expose port 80 to the host machine EXPOSE 80 ENTRYPOINT ["/usr/sbin/apache2ctl"] CMD ["-D", "FOREGROUND"]
<VirtualHost *:80> DocumentRoot /var/www/drupal/ LogLevel warn ErrorLog /dev/stdout CustomLog /dev/stdout combined </VirtualHost>
docker build -t pascalbod/apache2:v1 .
#DOCKER-VERSION 1.3.0 # Minimal image. FROM busybox:ubuntu-14.04 # Declare volume for web site directory. VOLUME /var/www/drupal CMD ["true"]
docker build -t pascalbod/drupalweb:v1 .
docker run -d --name drupalweb pascalbod/drupalweb:v1
#DOCKER-VERSION 1.3.0 # We'll rely on Ubuntu 14.04 LTS. FROM ubuntu:14.04 # Install required software. RUN DEBIAN_FRONTEND=noninteractive apt-get update && apt-get install -y \ wget
# Script used at run time to initialize Drupal web site container.
ADD run.sh /run.sh
RUN chmod u+x /run.sh
CMD ["/run.sh"]
#!/bin/bash
# Download Drupal
echo "=> Downloading Drupal."
wget http://ftp.drupal.org/files/projects/drupal-7.33.tar.gz
tar -xvzf drupal-7.33.tar.gz
rm drupal-7.33.tar.gz
# Move files to intended location
echo "=> Moving files."
cd drupal-7.33/ mv * .htaccess .gitignore /var/www/drupal/.
cd ..
rmdir drupal-7.33/
# Prepare settings.php and file permissions
echo "=> Preparing settings.php and file permissions."
cd /var/www/drupal/ cp sites/default/default.settings.php sites/default/settings.php chmod a+w sites/default/settings.php chmod a+w sites/default
echo "=> Done."
docker build -t pascalbod/drupalwebinit:v1 .
docker run -d --volumes-from drupalweb pascalbod/drupalwebinit:v1
#DOCKER-VERSION 1.3.0 # Minimal image. FROM busybox:ubuntu-14.04 # Declare volume for database directory. VOLUME /var/lib/mysql CMD ["true"]
docker build -t pascalbod/drupaldb:v1 .
#DOCKER-VERSION 1.3.0 # We'll rely on Ubuntu 14.04 LTS. FROM ubuntu:14.04 # Install required software. RUN DEBIAN_FRONTEND=noninteractive apt-get update && apt-get install -y \ mysql-client \ mysql-server # Set up MySQL configuration so that we can access it from outside. ADD my.cnf /etc/mysql/conf.d/my.cnf # Add script that initializes MySQL data directory. ADD run.sh /run.sh RUN chmod a+x /run.sh # Expose MySQL port to the host machine. EXPOSE 3306
[mysqld] bind-address=0.0.0.0
#!/bin/bash
if [ ! -d /var/lib/mysql/mysql ]; then # Setup MySQL data directory. echo "=> Creating MySQL data directory." mysql_install_db --datadir=/var/lib/mysql fi echo "=> Running MySQL Server." exec mysqld_safe --datadir=/var/lib/mysql
docker build -t pascalbod/mysqlinit:v1 .
docker run -d --name drupaldb pascalbod/drupaldb:v1
#DOCKER-VERSION 1.3.0 # We'll rely on Ubuntu 14.04 LTS. FROM ubuntu:14.04 # Install required software. RUN DEBIAN_FRONTEND=noninteractive apt-get update && apt-get install -y \ mysql-client \ mysql-server
# Script used at run time to initialize Drupal database container. ADD run.sh /run.sh RUN chmod u+x /run.sh CMD ["/run.sh"]
#!/bin/bash echo "=> Initializing MySQL data." mysql_install_db echo "=> Starting MySQL server." /usr/bin/mysqld_safe & echo "=> Waiting for MySQL server." while (true); do echo " waiting for 3 s..." sleep 3s mysql -uroot -e "status" > /dev/null 2>&1 && break done echo "=> Setting MySQL root password." PASS='pw0drupal0' mysql -uroot -e "update mysql.user set Password=password('$PASS') where user = 'root';" echo "=> Creating drupal database and user." mysql -uroot -e "CREATE DATABASE drupal CHARACTER SET utf8 COLLATE utf8_general_ci;" PASS='pw1drupal1' mysql -uroot -e "CREATE USER 'drupal'@'%' IDENTIFIED BY '$PASS';" mysql -uroot -e "GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, INDEX, ALTER, \ CREATE TEMPORARY TABLES ON drupal.* TO 'drupal'@'%';" echo "=> Done."
docker build -t pascalbod/drupaldbinit:v1 .
docker run -d --volumes-from drupaldb pascalbod/drupaldbinit:v1
#DOCKER-VERSION 1.3.0 # We'll rely on Ubuntu 14.04 LTS. FROM ubuntu:14.04 # Install required software. RUN DEBIAN_FRONTEND=noninteractive apt-get update && apt-get install -y \ mysql-client \ mysql-server # Set up MySQL configuration so that we can access it from outside. ADD my.cnf /etc/mysql/conf.d/my.cnf # Expose MySQL port to the host machine. EXPOSE 3306 ENTRYPOINT ["mysqld_safe"]
[mysqld] bind-address=0.0.0.0
docker build -t pascalbod/mysql:v1 .
docker run -d --volumes-from drupaldb --name db pascalbod/mysql:v1
At this stage, we have a running Drupal web site container, a running Drupal database container and a running MySQL container. Now let's start Apache container:
docker run -d -p 23001:80 --volumes-from drupalweb --link db:db pascalbod/apache2:v1
Now, Drupal configuration web page is available at <myHost>:23001 (I chose a random port, for configuration duration).
When asked for database information, click on ADVANCED OPTIONS, and set database host to db, the link alias we provided to above command.
A few additional adjustements should be performed: some file ownership settings, addition of some Drupal modules, etc. One way to do this is to use the exec command on target container:
docker exec -i -t <containerId> bash
This creates a new bash session in the container, which I use to end Drupal configuration.
I'm quite sure the way I used Docker to set up my Drupal configuration is not an optimal one. I tried to use one container per service, and one container per type of persistant data. This design choice seems to comply with some Docker container patterns. But the way I implemented it is quite complex. It wasn't so easy to set up. What's more, I wonder whether that's the best answer to my needs. I'll spend some more time using Docker over the next few months, and I'll discover a lot more than I know today . This should allow me to optimize this complex set up... As Chinese people say: 熟能生巧 (skill comes from practice).
05-Jan-2015 - Update: see this article for the Drupal configuration I finally chose, for a live Drupal site.