At the moment there is a great hype about "docker", even if the technique isn't new. So what's so great about it?
I think it got popular, because it's very easy to build system-containers with it. There is also a repository where you find ready to use environments for many use cases. With a few commands, you can have an isolated system with all the configs you need. That's very nice. Compared to virtual machines, those containers need a minimum of resources because they share the resources with their host-machine and don't run their own kernel. And they don't need to boot, they just run when they are started. Docker implemented some kind of scripts called "Dockerfiles". Those are recipies of how images should be configured, customized and build.
When I first heard about docker I was just thinking on developers. Now I realized how useful this tool could be for administrators too. You can use one server and serve every customer his own "linux+apache2+mysql"-system, instead of virtual hosting or chroot-ing.
In this article i want to describe how to create a "Debian Wheezy"-Image using "debootstrap". This debianwheezy-image will be the base for our "dockerfile". The dockerfile itself will create another image called "hoti/drupal-dev". In this dockerfile we will pre-install a ssh-server,mysql-server, apache2-server, php5, drush and drupal.
Download a Debian Wheezy Bootstrap:
debootstrap wheezy wheezy
Our output looks like this:
I: Configuring ifupdown... I: Configuring kmod... I: Configuring libapt-pkg4.12:amd64... I: Configuring libept1.4.12... I: Configuring libapt-inst1.5:amd64... I: Configuring libreadline6:amd64... I: Configuring logrotate... I: Configuring libboost-iostreams1.49.0... I: Configuring groff-base... I: Configuring gnupg... I: Configuring libsigc++-2.0-0c2a:amd64... I: Configuring libgnutls26:amd64... I: Configuring apt-utils... I: Configuring udev... I: Configuring iptables... I: Configuring man-db... I: Configuring apt... I: Configuring wget... I: Configuring libcwidget3... I: Configuring aptitude... I: Configuring tasksel... I: Configuring tasksel-data... I: Base system installed successfully.
Now create a docker-image:
tar -C wheezy/ -c . | docker import - debianwheezy
And check out that it was created successfully:
docker images -a REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE debianwheezy latest f5c9b4660eee 18 seconds ago 218.4 MB
Lets delete the bootstrap-files:
rm -r debianwheezy
Now we create a container out of our image and install the worlds best editor into it:
docker run -it debianwheezy /bin/bash root@5c0a2b5468c1:/# apt-get update Hit http://ftp.us.debian.org wheezy Release.gpg Hit http://ftp.us.debian.org wheezy Release Hit http://ftp.us.debian.org wheezy/main amd64 Packages Get:1 http://ftp.us.debian.org wheezy/main Translation-en [3846 kB] Fetched 3846 kB in 5s (668 kB/s) Reading package lists... Done root@5c0a2b5468c1:/# apt-get install vim Reading package lists... Done Building dependency tree... Done The following extra packages will be installed: libgpm2 vim-runtime Suggested packages: gpm ctags vim-doc vim-scripts The following NEW packages will be installed: libgpm2 vim vim-runtime 0 upgraded, 3 newly installed, 0 to remove and 0 not upgraded. Need to get 5484 kB of archives. After this operation, 24.9 MB of additional disk space will be used. Do you want to continue [Y/n]? y Get:1 http://ftp.us.debian.org/debian/ wheezy/main libgpm2 amd64 1.20.4-6 [35.8 kB] Get:2 http://ftp.us.debian.org/debian/ wheezy/main vim-runtime all 2:7.3.547-7 [4607 kB] Get:3 http://ftp.us.debian.org/debian/ wheezy/main vim amd64 2:7.3.547-7 [841 kB] Fetched 5484 kB in 7s (711 kB/s) Selecting previously unselected package libgpm2:amd64. (Reading database ... 9308 files and directories currently installed.) Unpacking libgpm2:amd64 (from .../libgpm2_1.20.4-6_amd64.deb) ... Selecting previously unselected package vim-runtime. Unpacking vim-runtime (from .../vim-runtime_2%3a7.3.547-7_all.deb) ... Adding 'diversion of /usr/share/vim/vim73/doc/help.txt to /usr/share/vim/vim73/doc/help.txt.vim-tiny by vim-runtime' Adding 'diversion of /usr/share/vim/vim73/doc/tags to /usr/share/vim/vim73/doc/tags.vim-tiny by vim-runtime' Selecting previously unselected package vim. Unpacking vim (from .../vim_2%3a7.3.547-7_amd64.deb) ... Processing triggers for man-db ... Setting up libgpm2:amd64 (1.20.4-6) ... Setting up vim-runtime (2:7.3.547-7) ... Processing /usr/share/vim/addons/doc Setting up vim (2:7.3.547-7) ... update-alternatives: using /usr/bin/vim.basic to provide /usr/bin/vim (vim) in auto mode update-alternatives: using /usr/bin/vim.basic to provide /usr/bin/vimdiff (vimdiff) in auto mode update-alternatives: using /usr/bin/vim.basic to provide /usr/bin/rvim (rvim) in auto mode update-alternatives: using /usr/bin/vim.basic to provide /usr/bin/rview (rview) in auto mode update-alternatives: using /usr/bin/vim.basic to provide /usr/bin/vi (vi) in auto mode update-alternatives: using /usr/bin/vim.basic to provide /usr/bin/view (view) in auto mode update-alternatives: using /usr/bin/vim.basic to provide /usr/bin/ex (ex) in auto mode root@5c0a2b5468c1:/# exit
With "exit" we stopped the container and returned back to our system. Now let's check the state of our container:
docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 5c0a2b5468c1 debianwheezy:latest "/bin/bash" 3 minutes ago Exited (0) 45 seconds ago clever_almeida
Now let's commit our changes into our debianwheezy image so that we have a debianwheezy image with vim pre-installed:
docker commit -m "vim installed" 5c0a2b5468c1 debianwheezy:latest 4b4f8b6f115b042f1d4ed5dcbb3d607e63316f33d6004a43ac994a8c4c99bfc1
We can remove our container and create a new one to check if vim is installed:
docker rm 5c0a2b5468c1 5c0a2b5468c1
docker run -it debianwheezy:latest /bin/bash root@54bfa48a9ac0:/# apt-get install vim Reading package lists... Done Building dependency tree Reading state information... Done vim is already the newest version. 0 upgraded, 0 newly installed, 0 to remove and 0 not upgraded. root@54bfa48a9ac0:/#
Since this worked well, we can now stop and remove this container:
docker stop 54bfa48a9ac0 docker rm 54bfa48a9ac0
Finally it's time for our dockerfile(i borrowed the file from https://www.debian-administration.org/article/698/Automating_the_creation_of_docker_images):
# # Simple dockerfile for an ssh + server. # # Source: https://www.debian-administration.org/article/698/Automating_the_creation_of_docker_images # # Hoti # -- # # # From this base-image / starting-point # FROM debianwheezy # # Authorship # MAINTAINER hoti # # Update apt # RUN DEBIAN_FRONTEND=noninteractive apt-get update -q -q RUN DEBIAN_FRONTEND=noninteractive apt-get upgrade --yes --force-yes # # Install utitiles # RUN DEBIAN_FRONTEND=noninteractive apt-get install curl git less sudo screen --yes --force-yes # # Install runit # RUN DEBIAN_FRONTEND=noninteractive apt-get install runit --yes --force-yes # # Install SSH # RUN DEBIAN_FRONTEND=noninteractive apt-get install openssh-server openssh-client --yes --force-yes # # Install MySQL # RUN DEBIAN_FRONTEND=noninteractive apt-get install mysql-server --yes --force-yes # # Install Apache2 + php5 # RUN DEBIAN_FRONTEND=noninteractive apt-get install apache2 php5 php5-cli php5-mysql php5-gd --yes --force-yes # # Setup a root password; simple enough to remember, but hard enough that # it won't be cracked immediately. (ha!) # RUN echo "root:toor" | chpasswd # # Expose the SSH port # EXPOSE 22 # # Expose the Apache2 port # EXPOSE 80 # # Now make sure that runit will launch SSHD, via runit. # # NOTE: Remember runit will launch /etc/service/sshd/run # RUN mkdir /etc/service/sshd RUN /bin/echo -e '#!/bin/sh' > /etc/service/sshd/run RUN /bin/echo -e 'exec /usr/sbin/sshd -D' >> /etc/service/sshd/run RUN mkdir /etc/service/mysqld RUN /bin/echo -e '#!/bin/sh' > /etc/service/mysqld/run RUN /bin/echo -e 'exec mysqld_safe &' >> /etc/service/mysqld/run RUN mkdir /etc/service/apache2 RUN /bin/echo -e '#!/bin/sh' > /etc/service/apache2/run RUN /bin/echo -e 'exec apachectl start' >> /etc/service/apache2/run # # Make sure our run-script is executable. # RUN chown root.root /etc/service/sshd/run RUN chmod 755 /etc/service/sshd/run RUN chown root.root /etc/service/mysqld/run RUN chmod 755 /etc/service/mysqld/run RUN chown root.root /etc/service/apache2/run RUN chmod 755 /etc/service/apache2/run # # Install composer + drush # RUN curl -sS https://getcomposer.org/installer | php RUN mv composer.phar /usr/local/bin/composer RUN chown root.root /usr/local/bin/composer RUN chmod 755 /usr/local/bin/composer RUN composer global require drush/drush:dev-master RUN ln -s /root/.composer/vendor/drush/drush/drush /usr/local/bin/drush RUN ln -s /root/.composer/vendor/drush/drush/drush.complete.sh /etc/bash_completion.d/ RUN mkdir /etc/drush RUN mkdir /var/www/drupal RUN echo '> /etc/drush/drushrc.php RUN echo '$options['r'] = '/var/www/drupal';' >> /etc/drush/drushrc.php RUN cd /var/www && git clone --branch 7.x http://git.drupal.org/project/drupal.git RUN cd /var/www/drupal/sites/default && mkdir /var/www/drupal/sites/default/files && cp default.settings.php settings.php # RUN mysqladmin -uroot create drupal RUN chown www-data /var/www/drupal/sites/default/files RUN chown www-data /var/www/drupal/sites/default/settings.php RUN a2enmod rewrite # # Finally launch runit. # ENTRYPOINT ["/usr/sbin/runsvdir-start"]
Build the image using the Dockerfile:
docker build -t=hoti/drupal-dev - < Dockerfile.runit
.. And create an container-instance:
docker run -d -p 1122:22 -p 1180:80 hoti/drupal-dev
Now we can connect via ssh:
ssh root@localhost -p 1122
..Or using a browser: