<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
<channel>
        <title>Infrastruktur mit Qualität</title>
        <description>Infrastruktur mit Qualität - Peter Roßbach, Andreas Schmidt</description>
        <link>rss.xml</link>
        <link></link>
        <lastBuildDate>2015-04-16T17:35:35+02:00</lastBuildDate>
        <pubDate>2015-04-16T17:35:35+02:00</pubDate>
        <ttl>1800</ttl>


        <item>
                <title>Docker Container mit serverspec testen - Teil 2</title>
                <description>&lt;p&gt;Vor einiger Zeit hatten wir in einem Post gezeigt, welche Möglichkeiten existieren, um &lt;a href=&quot;http://www.infrabricks.de/blog/2014/09/10/docker-container-mit-serverspec-testen&quot;&gt;Container mit Serverspec zu testen&lt;/a&gt;.
Zu diesem Zeitpunkt waren die Möglichkeiten im Großen und Ganzen in Ordnung, aber sicherlich nicht
einfach zu handhaben. Nur durch eigene Erweiterungen von serverspec mit einem experimentellem nsenter-Backend war das Testen von Docker-Container sinnvoll möglich.&lt;/p&gt;

&lt;p&gt;Seitdem hat sich im Projekt Serverspec einiges getan. Zum einen gibt es nun &lt;em&gt;Resource Types&lt;/em&gt; für Docker-Container und -Images. Damit lassen sich auf einem Docker-Host die Eigenschaften von lokal liegenden Images und laufenden Containern prüfen. Zum anderen wurde das Docker-Backend so erweitert, dass auch über den API-Call von &lt;code&gt;docker exec&lt;/code&gt;
Prüfkommandos in einem laufenden Container mit ausgeführt werden können. Zeit, sich das Ganze im Detail anzuschauen.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/docker_serverspec_docker-exec.png&quot; alt=&quot;Serverspec-Kommandos über docker-exec ausführen&quot;&gt;&lt;/p&gt;

&lt;h1 id=&quot;resource-types&quot;&gt;Resource Types&lt;/h1&gt;

&lt;p&gt;Bei &lt;em&gt;Resource Types&lt;/em&gt; handelt es sich um die Zielobjekte, die man in einem &lt;code&gt;describe&lt;/code&gt;-Block beschreibt. So sind z.B. die
bekannten &lt;code&gt;file&lt;/code&gt;, &lt;code&gt;process&lt;/code&gt;, &lt;code&gt;port&lt;/code&gt; usw. Resource Types. Es gibt zwei Typen, die Docker-Objekte beschreiben, beide
beziehen ihre Daten aus dem API-Call zu &lt;code&gt;docker inspect&lt;/code&gt;. D.h. alles was ein &lt;code&gt;inspect&lt;/code&gt;-Aufruf an Metadaten liefert, kann
auch mit serverspec abgefragt werden.&lt;/p&gt;

&lt;h2 id=&quot;docker_image&quot;&gt;docker_image&lt;/h2&gt;

&lt;p&gt;Bei Images ist natürlich erstmal interessant, dass es lokal vorliegt, um gestartet werden zu können. Meistens kommt
ein Image aus einer Registry, ggf. hat man aber auch andere Lieferwege - z.B. aus der eigenen Buildchain per Tarball auf
die Zielmaschine - implementiert. Das kann man testen:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Gemfile&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;source&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;https://rubygems.org&amp;#39;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;ruby&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;2.1.5&amp;#39;&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;gem&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;serverspec&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;~&amp;gt; 2&amp;#39;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;gem&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;docker-api&amp;#39;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;.rspec&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;--color
--format documentation
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;spec/localhost/fedora_21_spec.rb&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;serverspec&amp;#39;&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;set&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:backend&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:exec&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;describe&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;docker_image&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;fedora:21&amp;#39;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;it&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;should&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;exist&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;bundle install --path vendor
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;bundle &lt;span class=&quot;nb&quot;&gt;exec &lt;/span&gt;rspec --pattern spec/localhost/&lt;span class=&quot;se&quot;&gt;\*&lt;/span&gt;_spec.rb

Docker image &lt;span class=&quot;s2&quot;&gt;&amp;quot;fedora:21&amp;quot;&lt;/span&gt;
 should exist

Finished in 0.13116 seconds &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;files took 0.34526 seconds to load&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;m&quot;&gt;1&lt;/span&gt; example, &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt; failures
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Wenn gerade kein Ruby auf dem eigenen Rechner installiert ist, kann dies
natürlich auch im Container erledigt werden. Damit die Docker &lt;em&gt;Resource Types&lt;/em&gt; funktionieren, muss eine Docker-CLI und funktionierender Docker Host installiere sein.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;docker run -v &lt;span class=&quot;k&quot;&gt;$(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;pwd&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;)&lt;/span&gt;:&lt;span class=&quot;k&quot;&gt;$(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;pwd&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
 -v /var/run/docker.sock:/var/run/docker.sock &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
 -v /usr/local/bin/docker:/usr/local/bin/docker &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
 --workdir&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;$(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;pwd&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;)&lt;/span&gt; -ti --rm ruby:2.1.5 &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  /bin/bash -c &lt;span class=&quot;s2&quot;&gt;&amp;quot;bundle install --path vendor ; bundle exec rspec --pattern spec/localhost/fedora_21_spec.rb&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Um an die &lt;code&gt;inspect&lt;/code&gt;-Daten heranzukommen, gibt es zwei Alternativen, hier am Beispiel der Systemarchitektur. Entweder
verwendet man den &lt;code&gt;inspection&lt;/code&gt;-Matcher, der eine komplette Map zurückliefert, aus der Teile testet. Oder man gibt
den zu testenden Schlüssel als Parameter mit und prüft das Ergebnis. Beide Alternativen sind sinnvoll, so kann man
z.B. bei der zweiten Variante auch mit regulären Ausdrücken testen.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;describe&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;docker_image&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;fedora:21&amp;#39;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;its&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:inspection&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;should_not&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;Architecture&amp;#39;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;i386&amp;#39;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;its&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;Architecture&amp;#39;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;should&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;eq&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;amd64&amp;#39;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;bundle &lt;span class=&quot;nb&quot;&gt;exec &lt;/span&gt;rspec
&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;...&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
Docker image &lt;span class=&quot;s2&quot;&gt;&amp;quot;fedora:21&amp;quot;&lt;/span&gt;
  inspection
    should not include &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;Architecture&amp;quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&amp;gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;i386&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;Architecture&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
    should eq &lt;span class=&quot;s2&quot;&gt;&amp;quot;amd64&amp;quot;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;...&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Welche Eigenschaften sind an einem Docker-Image interessant, was kann sinnvoll getestet werden?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Ein Maintainer sollte gesetzt sein, z.B. kann man dort einen Schlüssel einbauen, der anzeigt, dass dieses Image aus der eigenen Build-Chain stammt, und nicht von extern kommt.&lt;/li&gt;
&lt;li&gt;Good Practise für ist es, einen ENTRYPOINT zu verwenden, um Nutzung und einzuschränken und Falsch-Nutzung zu vermeiden.&lt;/li&gt;
&lt;li&gt;Für Service-Container sollten bestimmte Ports exposed werden.&lt;/li&gt;
&lt;li&gt;Bestimmte Environment-Parameter müssen vorhanden sein, sonst funktionieren Skripte oder Konfigurationen nicht.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Zum Beispiel hier ein Demo-Dockerfile:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;FROM fedora:21
MAINTAINER My Private Build Chain

ENV MYAPP_VERSION 47.11

EXPOSE 80

ENTRYPOINT &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;/bin/entrypoint&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Gebaut:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;docker build -t testimage .
&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;...&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
Successfully built aeb232471f6f

&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;docker images
REPOSITORY          TAG                 IMAGE ID            CREATED              VIRTUAL SIZE
testimage           latest              aeb232471f6f        &lt;span class=&quot;m&quot;&gt;54&lt;/span&gt; seconds ago       241.3 MB
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Mit einer passenden Spec ist die Überprüfung schnell implementiert:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;describe&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;docker_image&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;testimage&amp;#39;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;it&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;should&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;exist&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;its&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;Author&amp;#39;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;should&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;eq&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;My Private Build Chain&amp;#39;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;its&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;Entrypoint&amp;#39;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;should_not&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;eq&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;&amp;#39;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;its&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;Entrypoint&amp;#39;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;should_not&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;eq&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;/bin/entrypoint&amp;#39;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;its&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;Config.Env&amp;#39;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;should&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;sr&quot;&gt;/MYAPP_VERSION=47\.11/&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;its&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;Config.ExposedPorts&amp;#39;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;should&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;sr&quot;&gt;/80\/tcp/&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;its&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;Config.ExposedPorts&amp;#39;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;should_not&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;sr&quot;&gt;/22\/tcp/&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Ergibt:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;bundle &lt;span class=&quot;nb&quot;&gt;exec &lt;/span&gt;rspec --pattern spec/localhost/&lt;span class=&quot;se&quot;&gt;\*&lt;/span&gt;_spec.rb

Docker image &lt;span class=&quot;s2&quot;&gt;&amp;quot;testimage&amp;quot;&lt;/span&gt;
  should exist
  &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;Author&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
    should eq &lt;span class=&quot;s2&quot;&gt;&amp;quot;My Private Build Chain&amp;quot;&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;Entrypoint&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
    should not eq &lt;span class=&quot;s2&quot;&gt;&amp;quot;&amp;quot;&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;Entrypoint&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
    should not eq &lt;span class=&quot;s2&quot;&gt;&amp;quot;/bin/entrypoint&amp;quot;&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;Config.Env&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
    should include /MYAPP_VERSION&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;47&lt;span class=&quot;se&quot;&gt;\.&lt;/span&gt;11/
  &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;Config.ExposedPorts&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
    should include /80&lt;span class=&quot;se&quot;&gt;\/&lt;/span&gt;tcp/
  &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;Config.ExposedPorts&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
    should not include /22&lt;span class=&quot;se&quot;&gt;\/&lt;/span&gt;tcp/

Finished in 0.12227 seconds &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;files took 0.35186 seconds to load&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;m&quot;&gt;7&lt;/span&gt; examples, &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt; failures
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Es ist also sehr einfach bestimmte Qualitätsnormen der Docker-Images zu überprüfen. Manche Dinge sollen unbedingt enthalten sein, und andere Einstellungen, z.B. einen offenen SSH-Port, sind ehr unerwünscht.&lt;/p&gt;

&lt;h2 id=&quot;docker_container&quot;&gt;docker_container&lt;/h2&gt;

&lt;p&gt;Dasselbe gibt es natürlich auch für Container. Hier wird es interessanter, weil wir in der Lage sind, Laufzeitaspekte
zu berücksichtigen. Das fängt mit einem laufenden Container an:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;describe&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;docker_container&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;testcontainer&amp;#39;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;it&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;should&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;exist&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;it&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;should&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;be_running&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Ohne einen Container mit dem Namen gestartet zu haben, läuft die Spec in zwei Fehler. Also kann die Spec mit dem folgenden Befehl erfüllt werden:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;docker run -tdi --name testcontainer fedora:21 /bin/bash
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;bundle &lt;span class=&quot;nb&quot;&gt;exec &lt;/span&gt;rspec --pattern spec/localhost/&lt;span class=&quot;se&quot;&gt;\*&lt;/span&gt;_spec.rb

Docker container &lt;span class=&quot;s2&quot;&gt;&amp;quot;testcontainer&amp;quot;&lt;/span&gt;
 should exist
 should be running

Finished in 0.13791 seconds &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;files took 0.39023 seconds to load&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;m&quot;&gt;2&lt;/span&gt; examples, &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt; failures
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Mit den gleichen Inspection-Ausdrücken können nun Container Checks implementiert werden. Serverspec unterstützt noch einen weiteren Ausdruck &lt;code&gt;have_volume&lt;/code&gt; für die Prüfung von Volumes:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;describe&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;docker_container&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;testcontainer&amp;#39;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;it&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;should&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;have_volume&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;/mnt&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;/tmp&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Ausgeführt:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;docker run -tdi --name testcontainer -v /tmp:/mnt fedora:21 /bin/bash
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;bundle &lt;span class=&quot;nb&quot;&gt;exec &lt;/span&gt;rspec --pattern spec/localhost/&lt;span class=&quot;se&quot;&gt;\*&lt;/span&gt;_spec.rb

Docker container &lt;span class=&quot;s2&quot;&gt;&amp;quot;testcontainer&amp;quot;&lt;/span&gt;
  should have volume &lt;span class=&quot;s2&quot;&gt;&amp;quot;/mnt&amp;quot;&lt;/span&gt;, &lt;span class=&quot;s2&quot;&gt;&amp;quot;/tmp&amp;quot;&lt;/span&gt;

Finished in 0.10888 seconds &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;files took 0.35251 seconds to load&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;m&quot;&gt;1&lt;/span&gt; example, &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt; failures
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&quot;einer-nach-dem-anderen...&quot;&gt;Einer nach dem anderen...&lt;/h2&gt;

&lt;p&gt;Ein Nachteil dieser Resource Types liegt darin, das nur ein Image oder Container auf einmal geprüft werden kann. In einer Teststufe der &lt;em&gt;Build chain&lt;/em&gt; ist das in Ordnung, weil in der Regel nur ein Image oder Container gebaut wird. In Produktions- oder Staging-Systemen besteht ggf. der Wunsch, alle Container eines bestimmten Typs auf einmal
zu prüfen: z.B. &amp;quot;Alle Container, die &lt;code&gt;web*&lt;/code&gt; heissen, sollen nur Port 443 exposen und nicht privilegiert ablaufen.&amp;quot;&lt;/p&gt;

&lt;p&gt;Das ist in der Form nicht mit den aktuellen &lt;em&gt;Resource Types&lt;/em&gt; von Serverspec möglich. Eine alternative Variante ist in
&lt;a href=&quot;https://github.com/de-wiring/containerspec&quot;&gt;Containerspec&lt;/a&gt; implementiert. Dort wird cucumber an Stelle von
rspec verwendet, um in der Gherkin-Syntax Prüffälle zu formulieren.&lt;/p&gt;

&lt;p&gt;Damit lassen sich mehrere Images bzw. Container auf einmal prüfen:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;Scenario: NGINX Container
  When there is a running container named like &amp;#39;nginx.*&amp;#39;
  Then it should run on image &amp;#39;nginx:1.7.8&amp;#39;
  And containers should not expose port &amp;#39;80&amp;#39;
  And containers should expose port &amp;#39;443&amp;#39; on host port &amp;#39;8443&amp;#39;
  And container volume &amp;#39;/etc/nginx/sites-enabled&amp;#39; should be mounted
  And container volume &amp;#39;/var/log/nginx&amp;#39; should not be mounted
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Der Ausdruck &amp;quot;When there is a running container...&amp;quot; selektiert alle laufenden Container mit bestimmten Eigenschaften, hier z.B. einen Container-Namen der auf &amp;quot;nginx.*&amp;quot; matcht.
Ein &lt;a href=&quot;https://github.com/de-wiring/containerspec/wiki/Specifying-and-testing-a-docker-setup&quot;&gt;ausführlicheres Beispiel&lt;/a&gt; ist im Github-Wiki hinterlegt.&lt;/p&gt;

&lt;h1 id=&quot;docker-backend&quot;&gt;Docker-Backend&lt;/h1&gt;

&lt;p&gt;Mit den obigen Resource Types ist das Docker-Setup auf dem Host spezifizierbar. Im nächsten Schritte möchten wir
aber auch gerne innerhalb von laufenden Containern Specs ausführen. Dabei hilft eine Erweiterung des Docker-Backends.
Es kennt zwei Modi:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Wenn &lt;code&gt;docker_image&lt;/code&gt; gesetzt ist, wird ein Image geprüft. Das hatten wir im &lt;a href=&quot;http://www.infrabricks.de/blog/2014/09/10/docker-container-mit-serverspec-testen/&quot;&gt;Blog-Post&lt;/a&gt; schon beschrieben.&lt;/li&gt;
&lt;li&gt;Wenn &lt;code&gt;docker_container&lt;/code&gt; gesetzt ist, wird ein laufender Container geprüft. Dazu werden die Befehle mit &lt;code&gt;docker exec&lt;/code&gt; in den Container gebeamt und ausgeführt.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Hier ein Beispiel, um Container zu testen. Wir möchten den Namen des Containers als Environmentvariable mitgeben, also
brauchen wir einen angepassten &lt;code&gt;spec_helper.rb&lt;/code&gt;. Damit das Docker-Backend läuft, müssen vorher noch abhängige Pakete installiert werden (s. Gemfile).&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;bundle &lt;span class=&quot;nb&quot;&gt;exec &lt;/span&gt;serverspec-init
Select number: 1
Select number: 2

 + spec/
 + spec/localhost/
 + spec/localhost/sample_spec.rb
 + spec/spec_helper.rb
 + Rakefile
 + .rspec
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Der Spec-Helper sieht dann so aus:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;root&lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@localhost&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;~]&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;# cat spec/spec_helper.rb&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;serverspec&amp;#39;&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;set&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:backend&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:docker&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;set&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:docker_container&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ENV&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;TARGET&amp;#39;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Damit können wir beim &lt;code&gt;rake spec&lt;/code&gt;-Aufruf ein &lt;code&gt;TARGET=xyz&lt;/code&gt; vorstellen und so den Containernamen (oder ID) mitgeben, der wir testen möchten.&lt;/p&gt;

&lt;p&gt;Als Beispiel nehmen wir den laufenden Fedora21-Testcontainer von oben, mit einer Demo-Spec:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;c1&quot;&gt;# cat spec/localhost/sample_spec.rb&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;spec_helper&amp;#39;&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;describe&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;package&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;httpd&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;it&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;should&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;be_installed&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ TARGET&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;testcontainer rake spec
&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;...&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
Package &lt;span class=&quot;s2&quot;&gt;&amp;quot;httpd&amp;quot;&lt;/span&gt;
  should be installed &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;FAILED - 1&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;

Failures:

  1&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; Package &lt;span class=&quot;s2&quot;&gt;&amp;quot;httpd&amp;quot;&lt;/span&gt; should be installed
     On host &lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;localhost&lt;span class=&quot;s1&quot;&gt;&amp;#39;&lt;/span&gt;
&lt;span class=&quot;s1&quot;&gt;     Failure/Error: it { should be_installed }&lt;/span&gt;
&lt;span class=&quot;s1&quot;&gt;       expected Package &amp;quot;httpd&amp;quot; to be installed&lt;/span&gt;

&lt;span class=&quot;s1&quot;&gt;     # ./spec/localhost/sample_spec.rb:4:in block (2 levels) in &amp;lt;top (required)&amp;gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;

Finished in 0.34612 seconds &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;files took 0.29735 seconds to load&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;m&quot;&gt;1&lt;/span&gt; example, &lt;span class=&quot;m&quot;&gt;1&lt;/span&gt; failure
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Klar, das Paket httpd ist noch nicht installiert. Wir holen es nach:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;docker attach testcontainer
bash-4.3# yum install -y httpd
&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;...&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
Complete!
bash-4.3# &amp;lt;CTRL-P&amp;gt; + &amp;lt;CTRL-Q&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Damit läuft die Spec durch:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ TARGET&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;testcontainer bundle &lt;span class=&quot;nb&quot;&gt;exec &lt;/span&gt;rspec --pattern spec/localhost/&lt;span class=&quot;se&quot;&gt;\*&lt;/span&gt;_spec.rb

Package &lt;span class=&quot;s2&quot;&gt;&amp;quot;httpd&amp;quot;&lt;/span&gt;
  should be installed

Finished in 0.50143 seconds &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;files took 0.5923 seconds to load&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;m&quot;&gt;1&lt;/span&gt; example, &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt; failures
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Nachteilig ist und bleibt, dass die für die Tests notwendigen Binaries im Container vorhanden sein müssen. Das trifft
mittlerweile selbst bei Distributionen nur noch teilweise zu. Ein &lt;em&gt;fedora:21&lt;/em&gt; hat erstmal kein &lt;code&gt;netstat&lt;/code&gt;, so kann &lt;code&gt;port&lt;/code&gt; nicht geprüft werden. Ein &lt;em&gt;debian:wheezy&lt;/em&gt; kennt kein &lt;code&gt;ps&lt;/code&gt;, usw. Für die White-Box-Testbarkeit sollten also diese Tools nachinstalliert werden.&lt;/p&gt;

&lt;p&gt;Schwierig wird es, wenn das Image statisch gelinkte Binaries als Applikationen beinhaltet (z.B. aus der Go-Welt), und
auf ein &amp;quot;klassisches&amp;quot; Linux-Userland verzichtet. Dann müssen die Tools ggf. als Volume mit eingemountet werden, um den Container testbar zu machen.&lt;/p&gt;

&lt;h1 id=&quot;fazit&quot;&gt;Fazit&lt;/h1&gt;

&lt;p&gt;Das Thema Testing und Docker wird langsam rund :) Wir haben ausreichend Möglichkeiten, einen Docker-Host durchzutesten, und mit dem erweiterten Docker-Backend von Serverspec nun auch die laufenden Container. D.h. einer Test-Driven Infrastructure mit Docker steht nun nichts mehr im Weg.&lt;/p&gt;

&lt;p&gt;Buildchains führen seit einger Zeit automatisierte Tests mit dem Applikationcode aus. Viele Unternehmen, die Konfigurationsmanagement-Tools einsetzen lassen in Buildchains diesen Code ebenfalls Unit-testen.&lt;/p&gt;

&lt;p&gt;Beim Einsatz von Docker kommt Buildchains eine neue Aufgabe zu: Sie &lt;em&gt;produzieren&lt;/em&gt; nicht mehr nur Anwendungscode, sie produzieren Infrastrukturen. Und diese Infrastruktur-Artefakte lassen sich genau so gut testen, wie die Anwendung selbst.&lt;/p&gt;

&lt;p&gt;Viel Spaß beim Ausprobieren wünschen:&lt;/p&gt;

&lt;p&gt;Andreas und Peter&lt;/p&gt;
</description>
                <link>/blog/2015/04/16/docker-container-mit-serverspetesten-teil-2</link>
                <guid>/blog/2015/04/16/docker-container-mit-serverspetesten-teil-2</guid>
                <pubDate>2015-04-16T00:00:00+02:00</pubDate>
        </item>

        <item>
                <title>Docker Microservice Basis mit Apache Tomcat implementieren</title>
                <description>&lt;p&gt;Das Docker-Ökosystem ist die ideale Umgebung, um Microservices zu implementieren. Die Ideen ist, verschiedene Services auf einem Rechner isoliert von einander bereitzustellen. Ähnlichkeiten zu der heute verbreiteten Virtualisierung existieren, aber ohne die Abhängigkeiten zu einem bestimmten Hersteller oder dem Overhead der Ablaufplattform. In diesem Post werden verschiedene Weg zur Verwendung eines eigenen Java- und Tomcat-Image beschrieben.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/docker-java-tomcat-base-image.png&quot; alt=&quot;Docker Java Tomcat Base Image&quot;&gt;&lt;/p&gt;

&lt;p&gt;Die Docker-Container nutzen einfach den Linux-Kernel und können in verschiedenen Umgebungen anpassbar betrieben werden. Die Leichtigkeit beruht auf den schon lange vorhandenen Linux API&amp;#39;s, wie Namespaces, CGroups, Capabilities oder SELinux. Docker fügt neben einem Rest-Service noch die Definition eines austauschbaren Image-Formats hinzu. Das Teilen von vorgefertigter Software ist nun also mit Docker wirklich Realität. Damit das Teilen auch platzsparend ist, kommt ein Layered Filesystem zum Einsatz. Docker liefert Schnittstellen und besitzt Plugins, die Raum für eigene Erweiterungen bieten. Alles ist OpenSource und wird von einer aktiven Community entwickelt. Das bringt jeden Entwickler und Administrator schnell zum Schwärmen. Es befeuert die Idee, eine kontrollierte Umgebung von der Entwicklung bis in die Produktion zu nutzen. Microservices lassen sich so einfacher realisieren und orchestrieren. Der Begriff &lt;em&gt;Microservice&lt;/em&gt; ist schwer zu fassen, die &lt;a href=&quot;http://12factor.net/&quot;&gt;12 Factor Rules&lt;/a&gt; bieten eine erste Orientierung für die Entwicklung. Wichtiger Punkt ist, dass die Software in möglichst unabhängigen und autarken Einheiten bereitgestellt wird.&lt;/p&gt;

&lt;p&gt;Die Begriffe &lt;a href=&quot;http://martinfowler.com/articles/microservices.html&quot;&gt;Microservice&lt;/a&gt;, Continuous Delivery-Pipeline und Docker berauscht also gerade die IT. Alles in kleine Funktionseinheiten spalten, wird als Heilmittel für die Ablösung der kostenträchtigen aktuellen IT gepriesen. Wir wollen schneller, zuverlässiger und  preiswerter liefern und damit den Wunsch nach unkomplizierten Änderungen endlich befriedigen. Schöne neue Welt, aber Hand auf Herz. Die IT-Welt ist komplex und die bestehenden Systeme beherrschen unsere tägliches Handeln mehr als uns lieb ist. Wer das Glück hat, in seinem Projekt schon jetzt einen Blick in die IT-Zukunft wagen zu können, der kann allerdings nun aus dem Vollen schöpfen. Das Docker-Ökosystem bietet jede Menge neuer exotischer Verführungen.&lt;/p&gt;

&lt;p&gt;Eine Übersicht über den aktuellen Stand könnt Ihr im &lt;a href=&quot;https://entwickler.de/special-issue/entwickler-magazin-spezial-vol-2-docker-117484.html&quot;&gt;Entwickler Magazin Spezial Vol.2: Docker&lt;/a&gt; nachlesen. Hier haben viele unserer Kollegen und wir verschiedene Aspekte von Docker erklärt und berichten vom wirklichen Einsatz.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Also ran ans Werk!&lt;/strong&gt;&lt;/p&gt;

&lt;h2 id=&quot;bereitstellen-von-java--und-apache-tomcat-docker-images&quot;&gt;Bereitstellen von Java- und Apache Tomcat Docker-Images&lt;/h2&gt;

&lt;p&gt;Eine Entwicklungsumgebung für Java mit Apache Tomcat aufzusetzen, kann von vielen Tücken begleitet sein. Schnell kommt das Setup einer DB und weitere Backends hinzu. Das Aufsetzen einer einheitlichen Umgebung im Team und die Integration neuer Mitglieder ist leider oft eine zeitaufwendige Geschichte. Schnelle Auslieferung bedeutet auch schnelles handeln im Team, im Code, in der Entwicklungsumgebung und in der Produktion. Hier hilft nur die Automatisierung und Standardisierung voranzutreiben. Docker kann hier helfen, die Infrastruktur mehr als Code zu begreifen. Viele vorgefertigte Images stehen auf dem Docker-Hub schon bereit. Ein Test-Setup einer fremden Komponente kann also schnell erfolgen. Eine Herausforderung bleibt es allerdings, den eigenen individuellen Code schnell mit den bereitgestellten Services zu verheiraten oder ein eigenes Services-Images zu realisieren.&lt;/p&gt;

&lt;h3 id=&quot;das-experiment:-ein-java-image-für-dev-und-ops-bereitstellen&quot;&gt;Das Experiment: Ein Java-Image für Dev und Ops bereitstellen&lt;/h3&gt;

&lt;p&gt;Auf dem Docker-Hub existieren natürlich viele Java-Images. Allerdings basieren sie oft auf dem &lt;em&gt;falschem&lt;/em&gt; Betriebssystem, enthalten nicht die richtige Java Version oder sie sind schlicht zu groß.&lt;/p&gt;

&lt;p&gt;Im folgenden entsteht eine Basis, die ein eigenes Java-Images erzeugt.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Mit minimaler Größe, damit ein schneller Download möglich ist.&lt;/li&gt;
&lt;li&gt;Für den Apache Tomcat 8 reicht ein Java-Runtime.&lt;/li&gt;
&lt;li&gt;Java Anwendungen und Werkzeuge sollen nutzbar sein.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/docker-java-tomcat-download.png&quot; alt=&quot;Docker Java Tomcat Download&quot;&gt;&lt;/p&gt;

&lt;p&gt;Als &lt;em&gt;minimales&lt;/em&gt; Betriebssystem ohne alles reicht für Java die Distribution &lt;a href=&quot;https://github.com/progrium/busybox&quot;&gt;Busybox&lt;/a&gt; völlig aus. Mit Hilfe von &lt;code&gt;curl&lt;/code&gt; ist so schnell ein Oracle JRE-Tarball extrahiert und bereitgestellt.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;jre8/Dockerfile&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;# Busybox with a Java installation
FROM progrium/busybox
MAINTAINER Peter Rossbach &amp;lt;peter.rossbach@bee42.com&amp;gt;

# Install cURL
RUN opkg-install curl

# Java Version
ENV JAVA_VERSION_MAJOR 8
ENV JAVA_VERSION_MINOR 25
ENV JAVA_VERSION_BUILD 17
ENV JAVA_PACKAGE       server-jre
ENV JAVA_CHECKSUM      c3ec171fac394c584a0a5cecb1731efd

# Download, verify and extract Java
RUN curl -kLOH &amp;quot;Cookie: gpw_e24=http%3A%2F%2Fwww.oracle.com%2F; oraclelicense=accept-securebackup-cookie&amp;quot; \
http://download.oracle.com/otn-pub/java/jdk/${JAVA_VERSION_MAJOR}u${JAVA_VERSION_MINOR}-b${JAVA_VERSION_BUILD}/${JAVA_PACKAGE}-${JAVA_VERSION_MAJOR}u${JAVA_VERSION_MINOR}-linux-x64.tar.gz \
  &amp;amp;&amp;amp; echo &amp;quot;${JAVA_CHECKSUM}  ${JAVA_PACKAGE}-${JAVA_VERSION_MAJOR}u${JAVA_VERSION_MINOR}-linux-x64.tar.gz&amp;quot; &amp;gt; ${JAVA_PACKAGE}-${JAVA_VERSION_MAJOR}u${JAVA_VERSION_MINOR}-linux-x64.tar.gz.md5.txt \
  &amp;amp;&amp;amp; md5sum -c ${JAVA_PACKAGE}-${JAVA_VERSION_MAJOR}u${JAVA_VERSION_MINOR}-linux-x64.tar.gz.md5.txt \
  &amp;amp;&amp;amp; gunzip ${JAVA_PACKAGE}-${JAVA_VERSION_MAJOR}u${JAVA_VERSION_MINOR}-linux-x64.tar.gz \
  &amp;amp;&amp;amp; tar -xf ${JAVA_PACKAGE}-${JAVA_VERSION_MAJOR}u${JAVA_VERSION_MINOR}-linux-x64.tar -C /opt \
  &amp;amp;&amp;amp; rm ${JAVA_PACKAGE}-${JAVA_VERSION_MAJOR}u${JAVA_VERSION_MINOR}-linux-x64.tar* \
  &amp;amp;&amp;amp; ln -s /opt/jdk1.${JAVA_VERSION_MAJOR}.0_${JAVA_VERSION_MINOR} /opt/jdk

# Set environment
ENV JAVA_HOME /opt/jdk
ENV PATH ${PATH}:${JAVA_HOME}/bin

VOLUME [ &amp;quot;/opt/jdk&amp;quot;]

ENTRYPOINT [&amp;quot;java&amp;quot;]
CMD [&amp;quot;-version&amp;quot;]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Nicht vergessen beim Download von fremden Quellen, die Prüfsumme zu überprüfen. Mit diesem &lt;code&gt;jre8/Dockerfile&lt;/code&gt; lässt sich nun der Java-Container schnell erzeugen und testen:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;mkdir -p jre8
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;vi jre8/Dockerfile
...
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;docker build -t infrabricks/ex-java:jre-8 jre8
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;docker run --rm infrabricks/ex-java:jre-8
java version &lt;span class=&quot;s2&quot;&gt;&amp;quot;1.8.0_25&amp;quot;&lt;/span&gt;
Java&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;TM&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; SE Runtime Environment &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;build 1.8.0_25-b17&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
Java HotSpot&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;TM&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; 64-Bit Server VM &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;build 25.25-b02, mixed mode&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;docker images &lt;span class=&quot;p&quot;&gt;|&lt;/span&gt;grep &lt;span class=&quot;s2&quot;&gt;&amp;quot;infrabricks/java&amp;quot;&lt;/span&gt;
infrabricks/java                                          jre-8                    96860db18ac9        &lt;span class=&quot;m&quot;&gt;8&lt;/span&gt; seconds ago       160.3 MB
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Voila!&lt;/strong&gt;&lt;/p&gt;

&lt;h4 id=&quot;jdk-gefällig&quot;&gt;JDK gefällig&lt;/h4&gt;

&lt;p&gt;Wenn ein Java Development-Kit gewünscht wird, kann dies analog erstellt werden.&lt;/p&gt;

&lt;p&gt;Dazu müssen im Dockerfile folgenden Veränderung erfolgen:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;jdk8/Dockerfile&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;...
ENV JAVA_PACKAGE       jdk
ENV JAVA_CHECKSUM      e145c03a7edc845215092786bcfba77e
...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Das Erzeugen des Images und der Tests geschieht analog.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;mkdir -p jdk8
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;vi jkd8/Dockerfile
...
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;docker build -t infrabricks/ex-java:jdk-8 jdk8
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;docker run --rm infrabricks/ex-java:jdk-8
java version &lt;span class=&quot;s2&quot;&gt;&amp;quot;1.8.0_25&amp;quot;&lt;/span&gt;
Java&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;TM&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; SE Runtime Environment &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;build 1.8.0_25-b17&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
Java HotSpot&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;TM&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; 64-Bit Server VM &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;build 25.25-b02, mixed mode&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;docker run --rm --entrypoint&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;/bin/sh -ti -v &lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;pwd&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;:/data infrabricks/java:jdk-8
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;ls /opt/jdk/bin
ControlPanel    jarsigner       javafxpackager  jcmd            jhat            jmc.ini         jstat           orbd            rmiregistry     unpack200
appletviewer    java            javah           jconsole        jinfo           jps             jstatd          pack200         schemagen       wsgen
extcheck        java-rmi.cgi    javap           jcontrol        jjs             jrunscript      jvisualvm       policytool      serialver       wsimport
idlj            javac           javapackager    jdb             jmap            jsadebugd       keytool         rmic            servertool      xjc
jar             javadoc         javaws          jdeps           jmc             jstack          native2ascii    rmid            tnameserv
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;du -s /opt/jdk1.8.0_25
&lt;span class=&quot;m&quot;&gt;322308&lt;/span&gt;  /opt/jdk1.8.0_25
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;exit&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;docker images &lt;span class=&quot;p&quot;&gt;|&lt;/span&gt;grep &lt;span class=&quot;s2&quot;&gt;&amp;quot;infrabricks/java&amp;quot;&lt;/span&gt;
infrabricks/java                                          jre-8                    96860db18ac9        &lt;span class=&quot;m&quot;&gt;22&lt;/span&gt; minutes ago      160.3 MB
infrabricks/java                                           jdk-8                    fbf0c4b72d14        &lt;span class=&quot;m&quot;&gt;8&lt;/span&gt; seconds ago      331.3 MB
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;In der Auflistung wird deutlich, welch große Mengen Plattenplatz die visuellen Tools, libs, Quellen und Dokumentationen eines JDK&amp;#39;s benötigen! In der Produktion sollte dieser Overhead nur selten notwendig sein, oder?&lt;/p&gt;

&lt;h4 id=&quot;apache-tomcat-image---ontop&quot;&gt;Apache Tomcat Image - Ontop&lt;/h4&gt;

&lt;p&gt;Auf der Basis des Java-Images kann nun die Bereitstellung des Tomcats erfolgen:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;tomcat8/Dockerfile&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;FROM infrabricks/ex-java:jre-8
MAINTAINER Peter Rossbach &amp;lt;peter.rossbach@bee42.com&amp;gt;

ENV TOMCAT_MINOR_VERSION 8.0.15
ENV CATALINA_HOME /opt/tomcat

RUN curl -O http://archive.apache.org/dist/tomcat/tomcat-8/v${TOMCAT_MINOR_VERSION}/bin/apache-tomcat-${TOMCAT_MINOR_VERSION}.tar.gz &amp;amp;&amp;amp; \
 curl http://archive.apache.org/dist/tomcat/tomcat-8/v${TOMCAT_MINOR_VERSION}/bin/apache-tomcat-${TOMCAT_MINOR_VERSION}.tar.gz.md5 | md5sum -c - &amp;amp;&amp;amp; \
 gunzip apache-tomcat-*.tar.gz &amp;amp;&amp;amp; \
 tar xf apache-tomcat-*.tar &amp;amp;&amp;amp; \
 rm apache-tomcat-*.tar &amp;amp;&amp;amp; mv apache-tomcat* ${CATALINA_HOME} &amp;amp;&amp;amp; \
 rm -rf ${CATALINA_HOME}/webapps/examples \
  ${CATALINA_HOME}/webapps/docs ${CATALINA_HOME}/webapps/ROOT \
  ${CATALINA_HOME}/webapps/host-manager \
  ${CATALINA_HOME}/RELEASE-NOTES ${CATALINA_HOME}/RUNNING.txt \
  ${CATALINA_HOME}/bin/*.bat ${CATALINA_HOME}/bin/*.tar.gz

WORKDIR /opt/tomcat
EXPOSE 8080
EXPOSE 8009
VOLUME [ &amp;quot;/opt/tomcat&amp;quot; ]

ENTRYPOINT [ &amp;quot;/opt/tomcat/bin/catalina.sh&amp;quot; ]
CMD [ &amp;quot;run&amp;quot;]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Die Standard-Distribution des Tomcats wird gesäubert. Dann werden die entsprechenden Ports preisgegeben und der Startbefehl für den Tomcat gesetzt.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;mkdir -p tomcat8
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;vi tomcat8/Dockerfile
...
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;docker build -t infrabricks/ex-tomcat:8 tomcat8
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;docker run --rm --entrypoint&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;/opt/tomcat/bin/version.sh infrabricks/ex-tomcat:8
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h4 id=&quot;die-erste-anwendung---hello-status&quot;&gt;Die erste Anwendung - Hello Status&lt;/h4&gt;

&lt;p&gt;Die folgende Status-Anwendung kann nun implementiert und eingebunden werden.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;index.jsp&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-jsp&quot; data-lang=&quot;jsp&quot;&gt;&lt;span class=&quot;k&quot;&gt;&amp;lt;%@&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;page&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;session&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;false&amp;quot;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;%&amp;gt;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;&amp;lt;%&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;java&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;DateFormat&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dateFormat&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;java&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;SimpleDateFormat&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;yyyy/MM/dd HH:mm:ss&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;%&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;html&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;Docker Tomcat Status page&lt;span class=&quot;nt&quot;&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;

&lt;span class=&quot;nt&quot;&gt;&amp;lt;ul&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;li&amp;gt;&lt;/span&gt;Hostname : &lt;span class=&quot;k&quot;&gt;&amp;lt;%=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;java&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;net&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;InetAddress&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getLocalHost&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getHostName&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;%&amp;gt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;li&amp;gt;&lt;/span&gt;Tomcat Version : &lt;span class=&quot;k&quot;&gt;&amp;lt;%=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;application&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getServerInfo&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;%&amp;gt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;li&amp;gt;&lt;/span&gt;Servlet Specification Version : &lt;span class=&quot;k&quot;&gt;&amp;lt;%=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;application&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getMajorVersion&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;%&amp;gt;&lt;/span&gt;.&lt;span class=&quot;k&quot;&gt;&amp;lt;%=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;application&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getMinorVersion&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;%&amp;gt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;li&amp;gt;&lt;/span&gt;JSP version : &lt;span class=&quot;k&quot;&gt;&amp;lt;%=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;JspFactory&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getDefaultFactory&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getEngineInfo&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getSpecificationVersion&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;%&amp;gt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;li&amp;gt;&lt;/span&gt;Now : &lt;span class=&quot;k&quot;&gt;&amp;lt;%=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dateFormat&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;format&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;java&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;util&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;Date&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;())&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;%&amp;gt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/ul&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Die einfach Anwendung kann nun mittels &lt;code&gt;zip&lt;/code&gt; zu einem WAR-File verpackt werden und gegebenenfalls als Volume eingebunden werden.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;mkdir -p status/webapp
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;status/webapps
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;vi index.jsp
...
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;zip -r ../status.war .
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; ../..
&lt;span class=&quot;nv&quot;&gt;$ CID&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;$(&lt;/span&gt;docker run -d -v &lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;pwd&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;/status/webapp:/opt/tomcat/webapps/status&lt;span class=&quot;k&quot;&gt;)&lt;/span&gt; infrabricks/ex-tomcat:8
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;docker logs &lt;span class=&quot;nv&quot;&gt;$CID&lt;/span&gt;
18-Dec-2014 17:45:18.678 INFO &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;main&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; org.apache.catalina.startup.VersionLoggerListener.log Server version:        Apache Tomcat/8.0.15
18-Dec-2014 17:45:18.681 INFO &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;main&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; org.apache.catalina.startup.VersionLoggerListener.log Server built:          Nov &lt;span class=&quot;m&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;2014&lt;/span&gt; 19:25:20 UTC
18-Dec-2014 17:45:18.682 INFO &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;main&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; org.apache.catalina.startup.VersionLoggerListener.log Server number:         8.0.15.0
18-Dec-2014 17:45:18.683 INFO &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;main&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; org.apache.catalina.startup.VersionLoggerListener.log OS Name:               Linux
18-Dec-2014 17:45:18.683 INFO &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;main&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; org.apache.catalina.startup.VersionLoggerListener.log OS Version:            3.16.7-tinycore64
18-Dec-2014 17:45:18.687 INFO &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;main&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; org.apache.catalina.startup.VersionLoggerListener.log Architecture:          amd64
...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Ausführen kann man die Anwendung mittels &lt;code&gt;curl&lt;/code&gt;. Wenn ein Browser-Zugriff gewünscht ist, muss der Tomcat-Port mit der Option &lt;code&gt;-p 8080:8080&lt;/code&gt; von außen erreichbar gemacht werden.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ IP&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;$(&lt;/span&gt;docker inspect --format &lt;span class=&quot;s1&quot;&gt;&amp;#39;&amp;#39;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;CID&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;})&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;curl -s http://&lt;span class=&quot;nv&quot;&gt;$IP&lt;/span&gt;:8080/status/index.jsp


&amp;lt;html&amp;gt;
&amp;lt;body&amp;gt;
&amp;lt;h1&amp;gt;Docker Tomcat Status page&amp;lt;/h1&amp;gt;

&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;Hostname : a222c4e3f231&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;Tomcat Version : Apache Tomcat/8.0.15&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;Servlet Specification Version : 3.1&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;JSP version : 2.3&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;Now : 2014/12/17 16:06:32&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h4 id=&quot;nutzung-der-tomcat-manager-webapp&quot;&gt;Nutzung der Tomcat Manager Webapp&lt;/h4&gt;

&lt;p&gt;Der Zugriff auf die Manager Anwendung des Tomcats kann nur mit entsprechender
Autorisierung erfolgen. Die Konfiguration erfolgt hier durch die folgenden Dateien:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;tomcat8/conf/tomcat-users.xml&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-xml&quot; data-lang=&quot;xml&quot;&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;?xml version=&amp;#39;1.0&amp;#39; encoding=&amp;#39;utf-8&amp;#39;?&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;tomcat-users&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;xmlns=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;http://tomcat.apache.org/xml&amp;quot;&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;xmlns:xsi=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;http://www.w3.org/2001/XMLSchema-instance&amp;quot;&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;xsi:schemaLocation=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;http://tomcat.apache.org/xml tomcat-users.xsd&amp;quot;&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;version=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;1.0&amp;quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;

  &lt;span class=&quot;nt&quot;&gt;&amp;lt;role&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;rolename=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;manager-script&amp;quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;user&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;username=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;manager&amp;quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;password=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;tomcat&amp;quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;roles=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;manager-script&amp;quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/tomcat-users&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Die Anbindung ist etwas aufwendiger, da nur Verzeichnisse in einen Container eingebunden werden können. Es wird also ein Startskript benötigt, das vor dem Start des Containers die Datei verlinkt oder kopiert.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;tomcat8/bin/tomcat.sh&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;c&quot;&gt;#!/bin/sh&lt;/span&gt;
ln -s /opt/bootstrap/conf/tomcat-users.xml /opt/tomcat8/conf/tomcat-users.xml
&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;CATALINA_HOME&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;/bin/catalina.sh run
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Die Integration in den Tomcat geschieht durch die Anbindung eines Volumes.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;mkdir -p tomcat8/bin
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;vi tomcat8/bin/tomcat.sh
...
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;chmod -x tomcat8/bin/tomcat.sh
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;docker run -d &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
 -v &lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;pwd&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;/status/webapp:/opt/tomcat/webapps/status &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
 -v &lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;pwd&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;/tomcat8:/opt/bootstrap &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
 --entrypoint&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;/opt/bootstrap/tomcat.sh &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
 infrabricks/ex-tomcat:8
&lt;span class=&quot;nv&quot;&gt;$ CID&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;$(&lt;/span&gt;docker ps -lq&lt;span class=&quot;k&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$ IP&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;$(&lt;/span&gt;docker inspect --format &lt;span class=&quot;s1&quot;&gt;&amp;#39;&amp;#39;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;CID&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;})&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;curl -u manager:tomcat http://&lt;span class=&quot;nv&quot;&gt;$IP&lt;/span&gt;:8080/manager/text/list
OK - Listed applications &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; virtual host localhost
/status:running:0:status
/manager:running:0:manager
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Natürlichen lassen sich ähnliche Tomcat-Erweiterungen ins Verzeichnis &lt;code&gt;/opt/bootstrap/lib&lt;/code&gt; einbinden oder andere Konfigurationen austauschen. Im Git Projekt &lt;a href=&quot;https://github.com/infrabricks/docker-simple-tomcat8&quot;&gt;infrabricks docker-simple-tomcat8&lt;/a&gt;  ist ein erweitertes Skript zu finden. Ein weiteres Projekt einer echten Infrabricks Tomcat-Line ist in der Realisierung. Dort entsteht eine ganzen Tomcat-Familie, die auf verschiedenen Java- und Tomcat-Versionen besteht.&lt;/p&gt;

&lt;h3 id=&quot;tricks&quot;&gt;Tricks&lt;/h3&gt;

&lt;h4 id=&quot;docker-container-overlay&quot;&gt;Docker Container Overlay&lt;/h4&gt;

&lt;p&gt;Wenn die JDK-Tools in einem Tomcat benötigt werden, lassen sich
diese einfach von JDK-Image übernehmen. Das geht problemlos, auch ohne dass der Tomcat von diesem Images abgeleitet werden muss.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/docker-java-tomcat-jdk-overlay.png&quot; alt=&quot;Docker Java Tomcat JDK Overlay&quot;&gt;&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;docker run --name jdk8 infrabricks/ex-java:jdk-8
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;docker run -d &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
 --volumes-from jdk8 &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
 -v &lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;pwd&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;/status/webapp:/opt/tomcat/webapps/status &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
 infrabricks/ex-tomcat:8
&lt;span class=&quot;nv&quot;&gt;$ CID&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;$(&lt;/span&gt;docker ps -lq&lt;span class=&quot;k&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;docker &lt;span class=&quot;nb&quot;&gt;exec&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$CID&lt;/span&gt; jstat -gc &lt;span class=&quot;m&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;5000&lt;/span&gt;  
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;docker &lt;span class=&quot;nb&quot;&gt;exec&lt;/span&gt; -ti &lt;span class=&quot;nv&quot;&gt;$CID&lt;/span&gt; /bin/sh
...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Das JDK-Image exportiert mit der Angabe &lt;code&gt;VOLUME [ &amp;quot;/opt/jdk&amp;quot; ]&lt;/code&gt; die Java-Installation. Mit der Angabe von &lt;code&gt;--volumes-from&lt;/code&gt; lässt sich einfach die vorhandene JRE-Installation überblenden. Layered Filesysteme sind schon ein Segen für die Entwicklung von Infrastruktur.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Happy debugging!!&lt;/strong&gt;&lt;/p&gt;

&lt;h4 id=&quot;docker-composition:-tomcat-als-data-container-nutzen&quot;&gt;Docker Composition: Tomcat als Data-Container nutzen&lt;/h4&gt;

&lt;p&gt;Wenn man die vollständige Freiheit über die Wahl der Java-Distribution haben möchte, kann man als Alternative den Tomcat als Data-Container liefern. Auf der Basis von &lt;code&gt;progrium/busybox&lt;/code&gt; lässt sich das schnell erzeugen und die Installation als Volume freigeben.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/docker-java-tomcat-composition.png&quot; alt=&quot;Docker Java Tomcat Composition&quot;&gt;&lt;/p&gt;

&lt;p&gt;Mit folgenden Änderungen auf dem bestehenden &lt;code&gt;tomcat8/Dockerfile&lt;/code&gt; entsteht ein
Tomcat Data-Container.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;tomcat8-volume/Dockerfile&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;FROM progrium/busybox
MAINTAINER Peter Rossbach &amp;lt;peter.rossbach@bee42.com&amp;gt;

# Install wget
RUN opkg-install curl

ENV TOMCAT_MINOR_VERSION 8.0.15
ENV CATALINA_HOME /opt/tomcat

RUN curl -O http://archive.apache.org/dist/tomcat/tomcat-8/v${TOMCAT_MINOR_VERSION}/bin/apache-tomcat-${TOMCAT_MINOR_VERSION}.tar.gz &amp;amp;&amp;amp; \
curl http://archive.apache.org/dist/tomcat/tomcat-8/v${TOMCAT_MINOR_VERSION}/bin/apache-tomcat-${TOMCAT_MINOR_VERSION}.tar.gz.md5 | md5sum -c - &amp;amp;&amp;amp; \
gunzip apache-tomcat-*.tar.gz &amp;amp;&amp;amp; \
tar xf apache-tomcat-*.tar &amp;amp;&amp;amp; \
rm apache-tomcat-*.tar &amp;amp;&amp;amp; mv apache-tomcat* ${CATALINA_HOME} &amp;amp;&amp;amp; \
rm -rf ${CATALINA_HOME}/webapps/examples \
${CATALINA_HOME}/webapps/docs ${CATALINA_HOME}/webapps/ROOT \
${CATALINA_HOME}/webapps/host-manager \
${CATALINA_HOME}/RELEASE-NOTES ${CATALINA_HOME}/RUNNING.txt \
${CATALINA_HOME}/bin/*.bat ${CATALINA_HOME}/bin/*.tar.gz

VOLUME [ &amp;quot;/opt/tomcat&amp;quot; ]

CMD [ &amp;quot;/bin/true&amp;quot; ]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Start des Data Containers Tomcats auf der Basis des JDK&amp;#39;s:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;docker build -t infrabricks/ex-tomcat:8-volume tomcat8-volume
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;docker run --name tomcat8 infrabricks/ex-tomcat:8-volume
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;docker run -d -p 8080:8080 &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
 --volumes-from tomcat8 &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
 -v &lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;pwd&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;/status/webapp:/opt/tomcat/webapps/status &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
 --entrypoint /opt/tomcat/bin/catalina.sh &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
 infrabricks/ex-java:jdk-8 run
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Mit diesem Muster lassen sich nun sehr effizient und schnell verschiedene Java-Versionen mit einer Anwendung testen. Natürlich spricht auch nichts dagegen, einfach einen Apache Tomcat lokal auszupacken und diesen direkt als Volume zu nutzen.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Quick and Dirty&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ T_V&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;8.0.15
&lt;span class=&quot;nv&quot;&gt;$ T_URL&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;http://archive.apache.org/dist/tomcat/tomcat-8
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;curl -O &lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;T_URL&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;/v&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;T_V&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;/bin/apache-tomcat-&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;T_V&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;.tar.gz
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;tar xzf apache-tomcat-&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;T_V&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;.tar.gz
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;docker run -d -p &lt;span class=&quot;m&quot;&gt;8080&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
 -v &lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;pwd&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;/apache-tomcat-&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;T_V&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;:/opt/tomcat &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
 -v &lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;pwd&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;/status/webapp:/opt/tomcat/webapps/status &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  --entrypoint /opt/tomcat/bin/catalina.sh &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
 infrabricks/ex-java:jdk-8 run
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Ein flexibleres &lt;code&gt;tscratch.sh&lt;/code&gt;-Script für diese Anwendung, findet ihr im &lt;a href=&quot;https://github.com/infrabricks/docker-simple-tomcat8&quot;&gt;Beispiel Projekt&lt;/a&gt; zu diesem Post.&lt;/p&gt;

&lt;h2 id=&quot;fazit&quot;&gt;Fazit&lt;/h2&gt;

&lt;p&gt;Mit dieser Docker Tomcat Basis kann nun der Start für die eigenen Webapps oder REST-Microservices gewagt werden. In einer der nächsten Post wird ein entsprechendes REST-Beispiel vorgestellt und im folgenden schrittweise zu einer eigenen Microservice-Plattform weiterentwickelt.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Java-Installationen für die Produktion sollten auf einem minimalen Base-Image beruhen.&lt;/li&gt;
&lt;li&gt;Alle Downloads sollten mit Checksum validiert werden.&lt;/li&gt;
&lt;li&gt;Das vorgestellte Tomcat Basis-Image lässt sich sehr einfach mit eigenen Konfigurationen, Anwendungen und Libs erweitern.&lt;/li&gt;
&lt;li&gt;Die Komposition von verschiedenen Containern macht den Test und die Entwicklung einfacher.&lt;/li&gt;
&lt;li&gt;Jede der gezeigten Varianten hat seinen Nutzen. Die reine Docker-Images-Lehre immer alles in ein auslieferbares Image zu packen ist richtig, aber während der Entwicklung und Test nicht immer die flexibelste und schnellste Lösung.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;WARNUNG&lt;/strong&gt;: Um die visuellen Java-Tools zu nutzen, kann es sein, dass ein Ubuntu Host mit X11 und ein Debian Base Image mit entsprechenden X-Libs benötigt wird &lt;a href=&quot;http://fabiorehm.com/blog/2014/09/11/running-gui-apps-with-docker/&quot;&gt;Running Docker  gui apps&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In diesem Sinne, viel Spaß beim Probieren oder selber Gestalten.&lt;/p&gt;

&lt;hr&gt;

&lt;p&gt;Peter&lt;/p&gt;
</description>
                <link>/blog/2014/12/19/docker-microservice-basis-mit-apache-tomcat-implementieren</link>
                <guid>/blog/2014/12/19/docker-microservice-basis-mit-apache-tomcat-implementieren</guid>
                <pubDate>2014-12-19T00:00:00+01:00</pubDate>
        </item>

        <item>
                <title>Docker-Container mit Serverspec testen</title>
                <description>&lt;p&gt;Nachdem wir in &lt;a href=&quot;http://www.infrabricks.de/tags.html&quot;&gt;diversen Posts&lt;/a&gt; vor einiger Zeit &lt;a href=&quot;serverspec.org&quot;&gt;Serverspec&lt;/a&gt;
für Server und VMs vorgestellt haben, brauchen wir jetzt natürlich auch noch eine sinnvolle Verbindung
zu Docker. Die Frage ist also, wie kann man innerhalb von Containern eine
Spezifikation prüfen?&lt;/p&gt;

&lt;p&gt;Dazu gibt es natürlich mehrere Möglichkeiten.&lt;/p&gt;

&lt;h2 id=&quot;ssh&quot;&gt;SSH&lt;/h2&gt;

&lt;p&gt;Die aus Serverspec-Sicht einfachste Art besteht darin, den Container als
Zielhost anzugeben, mit dem sich Serverspec dann regulär per SSH verbinden kann.
Für serverspec macht es keinen Unterschied, ob es sich um echte Hardware, eine
VM oder einen Container handelt.&lt;/p&gt;

&lt;p&gt;Das wiederum führt aber zu größeren Umbauarbeiten im Container, da man nun neben
dem eigentlichen Service, den man laufen lassen möchte, noch einen SSH-Daemon
benötigt. Beispielsweise lässt sich die Integration mehrere Services innerhalb eines Containers mit &lt;a href=&quot;http://supervisord.org/&quot;&gt;Supervisor.d&lt;/a&gt; umsetzen.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/docker_serverspec_ssh.png&quot; alt=&quot;Serverspec über ssh ausführen&quot;&gt;&lt;/p&gt;

&lt;p&gt;Letzen Endes muss man an der Stelle aber eigentlich die Grundlagen-Entscheidung
treffen, wie der eigene Container ausgestaltet sein soll: Als Microservice,
ausschließlich mit dem Zielprozess, oder als VM-Ersatz mit mehreren Services inklusive sshd.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fazit&lt;/strong&gt;: Falls die Antwort &amp;quot;VM-Ersatz&amp;quot; lautet, stellt der SSH-Zugang für Serverspec die
einfachste Möglichkeit dar. Falls der Microservice-Ansatz geplant ist, müssen
wir uns andere Zugangsmöglichkeiten anschauen.&lt;/p&gt;

&lt;h2 id=&quot;zur-build-zeit&quot;&gt;Zur Build-Zeit&lt;/h2&gt;

&lt;p&gt;Man kann den Serverspec-Aufruf natürlich auch zur Build-Zeit in das Dockerfile
platzieren. Dabei lassen sich die Spezifikationsfiles per &amp;quot;ADD&amp;quot;-Befehl einsetzen,
über &amp;quot;RUN&amp;quot; wird serverspec dann ausgeführt und schreibt das Ergebnis in eine
Datei, zur späteren Einsicht. Die Spezifikationsdateien und die Ergebnisdatei
dürfen auch auf einem Docker Volume liegen, um das ganze z.B. von außen steuern zu können.&lt;/p&gt;

&lt;p&gt;Am Beispiel:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;mkdir serverspec-docker-test
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;serverspec-docker-test
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;mkdir spec.d
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;spec.d
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;serverspec --init

&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;serverspec-init
Select OS &lt;span class=&quot;nb&quot;&gt;type&lt;/span&gt;:

  1&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; UN*X
  2&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; Windows

Select number: 1

Select a backend &lt;span class=&quot;nb&quot;&gt;type&lt;/span&gt;:

  1&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; SSH
  2&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; Exec &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;local&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;

Select number: 2

 + spec/
 + spec/localhost/
 + spec/localhost/httpd_spec.rb
 + spec/spec_helper.rb
 + Rakefile

&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;vim Dockerfile
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Hier setzen wir in den &lt;code&gt;Dockerfile&lt;/code&gt; folgendes ein:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;FROM ubuntu:14.04

RUN sudo apt-get -yqq update

RUN sudo apt-get -yqq install ruby1.9.3

RUN sudo gem install rake -v &amp;#39;10.3.2&amp;#39; --no-ri --no-rdoc
RUN sudo gem install rspec -v &amp;#39;2.99.0&amp;#39; --no-ri --no-rdoc
RUN sudo gem install specinfra -v &amp;#39;1.21.0&amp;#39; --no-ri --no-rdoc
RUN sudo gem install serverspec -v &amp;#39;1.10.0&amp;#39; --no-ri --no-rdoc

ADD ./spec.d /opt/spec.d

RUN ( cd /opt/spec.d; rake spec )

CMD /bin/bash
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Jetzt den Container bauen (gekürzter Auszug):&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;docker build .
Sending build context to Docker daemon 7.168 kB
Sending build context to Docker daemon
Step &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt; : FROM ubuntu:14.04
 ---&amp;gt; c4ff7513909d
Step &lt;span class=&quot;m&quot;&gt;1&lt;/span&gt; : RUN sudo apt-get -yqq update
 ---&amp;gt; Running in bc2eb91c00ff
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;...&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
Removing intermediate container bc2eb91c00ff
Step &lt;span class=&quot;m&quot;&gt;2&lt;/span&gt; : RUN sudo apt-get -yqq install ruby1.9.3
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;...&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
Step &lt;span class=&quot;m&quot;&gt;3&lt;/span&gt; : RUN sudo gem install rake -v &lt;span class=&quot;s1&quot;&gt;&amp;#39;10.3.2&amp;#39;&lt;/span&gt; --no-ri --no-rdoc
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;...&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
Step &lt;span class=&quot;m&quot;&gt;4&lt;/span&gt; : RUN sudo gem install rspec -v &lt;span class=&quot;s1&quot;&gt;&amp;#39;2.99.0&amp;#39;&lt;/span&gt; --no-ri --no-rdoc
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;...&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
Step &lt;span class=&quot;m&quot;&gt;5&lt;/span&gt; : RUN sudo gem install specinfra -v &lt;span class=&quot;s1&quot;&gt;&amp;#39;1.21.0&amp;#39;&lt;/span&gt; --no-ri --no-rdoc
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;...&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
Step &lt;span class=&quot;m&quot;&gt;6&lt;/span&gt; : RUN sudo gem install serverspec -v &lt;span class=&quot;s1&quot;&gt;&amp;#39;1.10.0&amp;#39;&lt;/span&gt; --no-ri --no-rdoc
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;...&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
Step &lt;span class=&quot;m&quot;&gt;7&lt;/span&gt; : ADD ./spec.d /opt/spec.d
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;...&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
Step &lt;span class=&quot;m&quot;&gt;8&lt;/span&gt; : RUN &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; /opt/spec.d&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; rake spec &lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
 ---&amp;gt; Running in 1f880efa0c71
/usr/bin/ruby1.9.1 -S rspec spec/localhost/httpd_spec.rb
dpkg-query: no packages found matching httpd
FFhttpd: unrecognized service
FFFF

Failures:

  1&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; Package &lt;span class=&quot;s2&quot;&gt;&amp;quot;httpd&amp;quot;&lt;/span&gt; should be installed
     On host &lt;span class=&quot;sb&quot;&gt;``&lt;/span&gt;
     Failure/Error: it &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt; should be_installed &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
       dpkg-query -f &lt;span class=&quot;s1&quot;&gt;&amp;#39;${Status ..&amp;#39;&lt;/span&gt;

&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;...&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;

Finished in 0.32489 seconds
&lt;span class=&quot;m&quot;&gt;6&lt;/span&gt; examples, &lt;span class=&quot;m&quot;&gt;6&lt;/span&gt; failures

&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;...&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;

/usr/bin/ruby1.9.1 -S rspec spec/localhost/httpd_spec.rb failed
2014/09/06 18:35:10 The &lt;span class=&quot;nb&quot;&gt;command&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;/bin/sh -c &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; /opt/spec.d&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; rake spec &lt;span class=&quot;o&quot;&gt;)]&lt;/span&gt; returned a non-zero code: 1
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Natürlich schlägt das Beispiel des Serverspec Generators fehl, da der Container kein httpd enthält. Es ist
halt die Demo-Spezifikation des Befehls &lt;code&gt;serverspec-init&lt;/code&gt;, aber man sieht den Aufruf.
In der Übersicht sieht das ganze so aus:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/docker_serverspec_buildtime.png&quot; alt=&quot;Serverspec zur Build-Zeit ausführen&quot;&gt;&lt;/p&gt;

&lt;p&gt;Vorteile:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Man muss nichts an &lt;code&gt;serverspec&lt;/code&gt; ändern, außer es im Container zu installieren.&lt;/li&gt;
&lt;li&gt;Es passt zum Ablauf in Build-Chains: Beim Bau des Containers wird eine Spezifikation
geprüft. Das Ergebnis kann von außen nachgeschaut werden, bei Failures stoppt die
Build-Chain.&lt;/li&gt;
&lt;li&gt;Bei aufeinander aufbauenden Images (z.B. FROM rossbachp/tomcat8:latest) kann
man den darunterliegenden Containerinhalt auf Korrektheit prüfen, wenn man sich nicht darauf
verlassen möchte.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Nachteile:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Man muss serverspec (und Abhängigkeiten, inkl. ruby) im Container installieren, obwohl
man es zur Laufzeit nicht mehr braucht. D.h. eigentlich sollten die Pakete nach
erfolgreichem Spec-Lauf wieder deinstalliert werden, inkl. eine &lt;a href=&quot;http://jasonwilder.com/blog/2014/08/19/squashing-docker-images/&quot;&gt;squashen des Docker Images&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Man kann nur statische Aspekte der Betriebssystem-Installation prüfen, z.B.
Dateien, Verzeichnisstrukturen, Pakete, Kernel-Einstellungen.&lt;/li&gt;
&lt;li&gt;Dynamische Aspekte des Service, z.B. läuft der Service, horcht der Port, usw.
können nicht getestet werden, da der Zielprozess ja noch gar nicht läuft.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Fazit&lt;/strong&gt;: Wem es reicht, innerhalb der Buildchain statische Aspekte seines
Docker Containers zu prüfen, ist hiermit gut bedient.&lt;/p&gt;

&lt;h2 id=&quot;mit-serverspec-und-dem-docker-backend&quot;&gt;Mit serverspec und dem Docker-Backend&lt;/h2&gt;

&lt;p&gt;Serverspec (bzw. SpecInfra) besitzt in seiner Architektur einen Backend-Teil.
In diesem Backend wird unterschieden, wie die Spec-Kommandos auf dem Ziel
ausgeführt werden soll (Beispiel: SSH). Seit SpecInfra v0.4.0 gibt es ein
Docker-Backend, das wiederum auf dem &lt;code&gt;docker-api&lt;/code&gt; gem aufbaut.&lt;/p&gt;

&lt;p&gt;Es nimmt ein existierendes Image und ändert darin den &amp;quot;CMD&amp;quot;-Aufruf so ab, dass
nicht der im Image definierte Zielprozess gestartet wird, sondern der Prüfbefehl,
den serverspec gerade ausführen möchte. Der Container wird gestartet, der
Befehl ausgeführt, das Ergebnis zurückgeliefert und von Serverspec bearbeitet.&lt;/p&gt;

&lt;p&gt;Wir probieren es aus. Als erstes installieren wir das docker-api gem, dabei
wird &lt;code&gt;mkmf&lt;/code&gt; aus ruby-dev vorausgesetzt:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;serverspec-docker-test

&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;sudo apt-get install ruby-dev
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;...&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;

&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;sudo gem install docker-api
Building native extensions.  This could take a &lt;span class=&quot;k&quot;&gt;while&lt;/span&gt;...
Fetching: archive-tar-minitar-0.5.2.gem &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;100%&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
Fetching: docker-api-1.13.2.gem &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;100%&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
Successfully installed json-1.8.1
Successfully installed archive-tar-minitar-0.5.2
Successfully installed docker-api-1.13.2
&lt;span class=&quot;m&quot;&gt;3&lt;/span&gt; gems installed
Installing ri documentation &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; json-1.8.1...
Installing ri documentation &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; archive-tar-minitar-0.5.2...
Installing ri documentation &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; docker-api-1.13.2...
Installing RDoc documentation &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; json-1.8.1...
Installing RDoc documentation &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; archive-tar-minitar-0.5.2...
Installing RDoc documentation &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; docker-api-1.13.2...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Dann muss Serverspec mitgeteilt werden, dass statt SSH ein Docker-Container
geprüft wird, und auch, welcher Container es sein soll. Das ganze spielt sich
in der Datei &lt;code&gt;spec_helper.rb&lt;/code&gt; ab:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;serverspec&amp;#39;&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# - - - - - Docker einbauen (statt Exec-Helper)- - - - -&lt;/span&gt;
&lt;span class=&quot;kp&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;SpecInfra&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Helper&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Docker&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# - - - - - Docker einbauen (statt Exec-Helper)- - - - -&lt;/span&gt;
&lt;span class=&quot;kp&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;SpecInfra&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Helper&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;DetectOS&lt;/span&gt;

&lt;span class=&quot;no&quot;&gt;RSpec&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;configure&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# - - - - - Image setzen - - - - -&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;docker_image&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;9590610349ba&amp;#39;&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# - - - - - Image setzen - - - - -&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ENV&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;ASK_SUDO_PASSWORD&amp;#39;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;highline/import&amp;#39;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sudo_password&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ask&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;Enter sudo password: &amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;q&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;q&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;false&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sudo_password&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ENV&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;SUDO_PASSWORD&amp;#39;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Und ausführen:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;rake spec
/usr/bin/ruby1.9.1 -S rspec spec/localhost/httpd_spec.rb
FFFFFF

Failures:

  1&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; Package &lt;span class=&quot;s2&quot;&gt;&amp;quot;httpd&amp;quot;&lt;/span&gt; should be installed
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;...&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;  

Finished in &lt;span class=&quot;m&quot;&gt;1&lt;/span&gt; minute 13.09 seconds
&lt;span class=&quot;m&quot;&gt;6&lt;/span&gt; examples, &lt;span class=&quot;m&quot;&gt;6&lt;/span&gt; failures
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;...&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;  
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Den ersten Unterschied den man bemerkt, ist der deutlich höhere Zeitaufwand
zum prüfen. Schließlich wird für jeden Prüfbefehl (das können mehrere je
describe-Block der Spec sein) ein neuer Container instanziiert.&lt;/p&gt;

&lt;p&gt;Ein Nachweis gelingt indirekt über &lt;code&gt;docker ps -a&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;sudo docker ps -a
CONTAINER ID        IMAGE               COMMAND                CREATED             STATUS                        PORTS               NAMES
16643fab8e17        9590610349ba        &lt;span class=&quot;err&quot;&gt;&amp;quot;&lt;/span&gt;/bin/sh -c &lt;span class=&quot;err&quot;&gt;&amp;#39;&lt;/span&gt;netstat   &lt;span class=&quot;m&quot;&gt;13&lt;/span&gt; seconds ago      Exited &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;1&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;12&lt;/span&gt; seconds ago                         mad_goldstine
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;...&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;In der COMMAND-Spalte &lt;em&gt;sieht&lt;/em&gt; man z.B. die Ausführen des netstat-Kommandos aus der
Spec (&lt;code&gt;port(80), it { should be_listening }&lt;/code&gt;). Es handelt sich um eine bereits
abgelaufenen Container, da er nach Beendigung des Serverspec-Prüfkommandos natürlich gestoppt ist.&lt;/p&gt;

&lt;p&gt;Vorteile:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Man muss serverspec im Container nicht installieren, es reicht die Installation auf dem Host.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Nachteile:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Das Setzen der Container-ID im &lt;code&gt;spec_helper&lt;/code&gt; ist in dieser Form unschön, d.h. man
benötigt weiteren Code um z.B. Ziel-Images abzufragen oder als Parameter entgegen
zu nehmen.&lt;/li&gt;
&lt;li&gt;Es lassen sich wieder nur statische Aspekte prüfen, da der eigentliche Zielprozess
nicht ausgeführt, sondern durch serverspec ersetzt wird.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Fazit&lt;/strong&gt;: Schon besser, da der Container so ohne Serverspec-Overhead auskommt.
Aber es lässt sich immer noch kein laufender Service prüfen.&lt;/p&gt;

&lt;h2 id=&quot;nsenter&quot;&gt;nsenter&lt;/h2&gt;

&lt;p&gt;Die nächste Stufe besteht darin, in einen laufenden Container hineinzuschauen und
dabei die Spec auszuführen.&lt;/p&gt;

&lt;p&gt;Hierbei hilft &lt;a href=&quot;http://man7.org/linux/man-pages/man1/nsenter.1.html&quot;&gt;nsenter&lt;/a&gt;.
Die Installation ist im &lt;a href=&quot;https://blog.codecentric.de/2014/07/vier-wege-in-den-docker-container/&quot;&gt;Blogeintrag von Alexander Berresch&lt;/a&gt;
sehr schön beschrieben. nsenter liegt auch als &lt;a href=&quot;https://github.com/jpetazzo/nsenter&quot;&gt;Docker-Container&lt;/a&gt; von
@jpetazzo vor. Wir wählen die manuelle Installationsvariante:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;curl --silent https://www.kernel.org/pub/linux/utils/util-linux/v2.24/util-linux-2.24.tar.gz &lt;span class=&quot;p&quot;&gt;|&lt;/span&gt; tar -zxf-
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;util-linux-2.24
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;./configure --without-ncurses
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;make nsenter
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;sudo cp nsenter /usr/local/bin
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Eine genaue Beschreibung von nsenter führt an der Stelle zu weit, dafür sei
auf die Blogeinträge verwiesen. &lt;strong&gt;&lt;em&gt;In a nutshell&lt;/em&gt;&lt;/strong&gt;: nsenter startet einen neuen Prozess
und setzt ihn in die Namespaces eines existierenden Containers.&lt;/p&gt;

&lt;p&gt;Wir starten einen Container und ermitteln seine Prozess-ID.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Vorsicht&lt;/strong&gt;: Die
Spaces zwischen den geschwungenen Klammern bei &lt;code&gt;.State.Pid&lt;/code&gt; gehören da nicht hin,
aber ohne Space werden sie vom Markup verschluckt.:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;docker run -tdi ubuntu:14.04
2c67dc16c6f0c1d90e53f5836b7c1de461578b63f903fd4454fafb32b02706f8

&lt;span class=&quot;nv&quot;&gt;$ PID&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;$(&lt;/span&gt;docker inspect --format &lt;span class=&quot;s1&quot;&gt;&amp;#39;{ { .State.Pid }}&amp;#39;&lt;/span&gt;  2c67dc16c6f0c1d90e53f5836b7c1de461578b63f903fd4454fafb32b02706f8&lt;span class=&quot;k&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$PID&lt;/span&gt;
9452
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Dann wird nsenter ausgeführt. Die Parameter stehen für die Namespaces, die
der neue Prozess &lt;em&gt;erben&lt;/em&gt; soll:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;sudo nsenter --target &lt;span class=&quot;nv&quot;&gt;$PID&lt;/span&gt; --mount --uts --ipc --net --pid &lt;span class=&quot;s1&quot;&gt;&amp;#39;/bin/sh&amp;#39;&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# ps -ef&lt;/span&gt;
UID        PID  PPID  C STIME TTY          TIME CMD
root         &lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;     &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;  &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt; 19:16 ?        00:00:00 /bin/bash
root        &lt;span class=&quot;m&quot;&gt;29&lt;/span&gt;     &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;  &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt; 19:23 ?        00:00:00 /bin/sh
root        &lt;span class=&quot;m&quot;&gt;30&lt;/span&gt;    &lt;span class=&quot;m&quot;&gt;29&lt;/span&gt;  &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt; 19:23 ?        00:00:00 ps -ef
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;D.h. man erhält eine Shell, die in der Prozessliste auch sichtbar ist (PID 1=Containerprozess,
PID 29=über nsenter gestartetes /bin/sh).&lt;/p&gt;

&lt;p&gt;Nun könnte man serverspec ausführen, wenn es vorhanden wäre. Leider hat die neue Shell
den Mount-Namespace des Containers geerbt, und damit nur Zugriff auf das Dateisystem
innerhalb Containers und serverspec liegt außerhalb.&lt;/p&gt;

&lt;p&gt;Um dennoch etwas testen zu können, verwenden wir das gebaute Image aus dem ersten Beispiel,
in dem ruby und serverspec installiert wurde, also das Images mit der ID &lt;code&gt;9590610349ba&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;docker run -tdi 9590610349ba
c84aaa2adeadda9f1ea1fe080110e25b5d68b151aadbe4706ad0538208d82cc9
&lt;span class=&quot;nv&quot;&gt;$ PID&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;$(&lt;/span&gt;docker inspect --format &lt;span class=&quot;s1&quot;&gt;&amp;#39; { {.State.Pid }} &amp;#39;&lt;/span&gt; c84aaa&lt;span class=&quot;k&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$PID&lt;/span&gt;
9680
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Dann kann man über nsenter einen neuen Prozess im Container starten und
serverspec ausführen:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;sudo nsenter --target &lt;span class=&quot;nv&quot;&gt;$PID&lt;/span&gt; --mount --uts --ipc --net --pid &lt;span class=&quot;s1&quot;&gt;&amp;#39;/bin/bash&amp;#39;&lt;/span&gt;

root@c84aaa2adead:/# &lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; /opt/spec.d/

root@c84aaa2adead:/opt/spec.d# rake spec
/usr/bin/ruby1.9.1 -S rspec spec/localhost/httpd_spec.rb
dpkg-query: no packages found matching httpd
FFhttpd: unrecognized service
FFFF
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;...&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;

Finished in 0.21691 seconds
&lt;span class=&quot;m&quot;&gt;6&lt;/span&gt; examples, &lt;span class=&quot;m&quot;&gt;6&lt;/span&gt; failures
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Das liefert ebenfalls Fehler, da der HTTP-Server nicht installiert ist. Da wir
die Spezifikation aber in einem laufenden Container &lt;em&gt;hineingebeamt&lt;/em&gt; und
gestartet haben, können auch dynamische Aspekte des Zielservice mit abgeprüft werden.&lt;/p&gt;

&lt;p&gt;Das ganze kann man natürlich auch abkürzen und in den nsenter Aufruf packen:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;sudo nsenter --target &lt;span class=&quot;nv&quot;&gt;$PID&lt;/span&gt; --mount --uts --ipc --net --pid -- /bin/bash -c &lt;span class=&quot;s1&quot;&gt;&amp;#39;cd /opt/spec.d &amp;amp;&amp;amp; rake&amp;#39;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Vorteile:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Dynamische Aspekte sind in der Spec nun auch prüfbar, da man sich zur Laufzeit auf
einen Container aufschalten kann.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Nachteile:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Die Installation von nsenter auf dem Docker Host ist notwendig.&lt;/li&gt;
&lt;li&gt;Serverspec muss im Container installiert sein.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Fazit&lt;/strong&gt;: Hier ergeben sich noch nicht soviele Vorteile gegenüber der Variante mit
dem Docker-Backend in Serverspec.&lt;/p&gt;

&lt;h2 id=&quot;nsenter-+-serverspec&quot;&gt;nsenter + serverspec&lt;/h2&gt;

&lt;p&gt;Jetzt bleibt noch die Möglichkeit, nsenter in serverspec, genaugenommen im Projekt specinfra,
als Backend zu integrieren. Serverspec unterstützt das aktuell noch nicht, wir
probieren es als Prototyp.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/docker_serverspec_nsenter.png&quot; alt=&quot;Serverspec-Kommandos über nsenter ausführen&quot;&gt;&lt;/p&gt;

&lt;p&gt;Dabei wird eine neue Backend-Klasse &lt;code&gt;Nsenter&lt;/code&gt; implementiert
und registriert. Sie erhält einen Parameter, die &lt;code&gt;nsenter_pid&lt;/code&gt;, damit das Backend
weiss, wo der Container liegt.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;mkdir nsenter-proto
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;nsenter-proto
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;git clone https://github.com/serverspec/specinfra
Cloning into &lt;span class=&quot;s1&quot;&gt;&amp;#39;specinfra&amp;#39;&lt;/span&gt;...
remote: Counting objects: 5305, &lt;span class=&quot;k&quot;&gt;done&lt;/span&gt;.
Receiving objects: 100% &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;5305/5305&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;, 628.18 KiB &lt;span class=&quot;p&quot;&gt;|&lt;/span&gt; 473.00 KiB/s, &lt;span class=&quot;k&quot;&gt;done&lt;/span&gt;.
remote: Total &lt;span class=&quot;m&quot;&gt;5305&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;delta 0&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;, reused &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;delta 0&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
Resolving deltas: 100% &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;2810/2810&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;, &lt;span class=&quot;k&quot;&gt;done&lt;/span&gt;.
Checking connectivity... &lt;span class=&quot;k&quot;&gt;done&lt;/span&gt;.
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;specinfra/lib/specinfra
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;vi backend.rb

.. anfügen ..
require &lt;span class=&quot;s1&quot;&gt;&amp;#39;specinfra/backend/nsenter&amp;#39;&lt;/span&gt;

&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;vim helper/backend.rb

... den Typ &lt;span class=&quot;s1&quot;&gt;&amp;#39;Nsenter&amp;#39;&lt;/span&gt; einfügen ...

module SpecInfra
  module Helper
    &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;Exec&amp;#39;&lt;/span&gt;, &lt;span class=&quot;s1&quot;&gt;&amp;#39;Nsenter&amp;#39;&lt;/span&gt;, &lt;span class=&quot;s1&quot;&gt;&amp;#39;Ssh&amp;#39;&lt;/span&gt;, &lt;span class=&quot;s1&quot;&gt;&amp;#39;Cmd&amp;#39;&lt;/span&gt;, &lt;span class=&quot;s1&quot;&gt;&amp;#39;Docker&amp;#39;&lt;/span&gt;, &lt;span class=&quot;s1&quot;&gt;&amp;#39;WinRM&amp;#39;&lt;/span&gt;, &lt;span class=&quot;s1&quot;&gt;&amp;#39;ShellScript&amp;#39;&lt;/span&gt;, &lt;span class=&quot;s1&quot;&gt;&amp;#39;Dockerfile&amp;#39;&lt;/span&gt;, &lt;span class=&quot;s1&quot;&gt;&amp;#39;Lxc&amp;#39;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;.each &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;|&lt;/span&gt;

&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;vim configuration.rb

... den Konfigurationsparameter &lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;nsenter_pid&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt; ans &lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;Array VALID_OPTIONS_KEYS&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt; anfügen ...

module SpecInfra
  module Configuration
    class &lt;span class=&quot;s&quot;&gt;&amp;lt;&amp;lt; self&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;      VALID_OPTIONS_KEYS = [&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;        :path,&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;[...]&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;        :request_pty,&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;        :nse&lt;/span&gt;nter_pid,

&lt;span class=&quot;c&quot;&gt;# Eine Prototyp-Version von nsenter für specinfra liegt als gist vor&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# https://gist.github.com/aschmidt75/bb38d971e4f47172e2de&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;curl https://gist.githubusercontent.com/aschmidt75/bb38d971e4f47172e2de/raw/350f9419159ffba282496f90232110e06b77cf69/specinfra_nsenter_prototype &amp;gt;backend/nsenter.rb

&lt;span class=&quot;c&quot;&gt;# das neue gem muss gebaut werden, der falsche wercker.yml link stört.&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; ../..
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;rm wercker.yml
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;touch wercker.yml

&lt;span class=&quot;c&quot;&gt;# Das Gem-Build kommando verlässt sich auf git ls-files, also added wir es&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# im lokalen Repository&lt;/span&gt;

&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;git add .
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;git commit -m &lt;span class=&quot;s2&quot;&gt;&amp;quot;added nsenter backend&amp;quot;&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# das wird gebaut und installiert.&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;gem build specinfra.gemspec --force
  Successfully built RubyGem
  Name: specinfra
  Version: 1.27.0
  File: specinfra-1.27.0.gem

&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;sudo gem install specinfra-1.27.0.gem
Successfully installed specinfra-1.27.0
&lt;span class=&quot;m&quot;&gt;1&lt;/span&gt; gem installed
Installing ri documentation &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; specinfra-1.27.0...
Installing RDoc documentation &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; specinfra-1.27.0...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Dazu erstellen wir eine kleine Spezifikation und starten ein Docker-Image:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;nsenter-proto
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;serverspec-init
Select OS &lt;span class=&quot;nb&quot;&gt;type&lt;/span&gt;:

  1&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; UN*X
  2&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; Windows

Select number: 1

Select a backend &lt;span class=&quot;nb&quot;&gt;type&lt;/span&gt;:

  1&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; SSH
  2&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; Exec &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;local&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;

Select number: 2

 + spec/
 + spec/localhost/
 + spec/localhost/httpd_spec.rb
 + spec/spec_helper.rb
 + Rakefile
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Zu Testzwecken wird die Spezifikation verkleinert:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;  &lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;vim spec/localhost/httpd_spec.rb

require &lt;span class=&quot;s1&quot;&gt;&amp;#39;spec_helper&amp;#39;&lt;/span&gt;

describe package&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;apache2&amp;#39;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  it &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt; should be_installed &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
end
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Ein Image wird gestartet, wir brauchen die PID:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;docker run -tdi ubuntu:14.04
9367d023570d4670ca1d12aa431bb826a131a1dcc0b02797a90372489d7927a6
vagrant@docker-workshop:~/nsenter-proto&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;docker inspect -f &lt;span class=&quot;s1&quot;&gt;&amp;#39;{ { .State.Pid }}&amp;#39;&lt;/span&gt; 9367d0
15344
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Der &lt;code&gt;spec_helper&lt;/code&gt; wird auf nsenter umgestellt, und die PID &lt;code&gt;15344&lt;/code&gt; wird mitgegeben:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;vim spec/spec_helper.rb

require &lt;span class=&quot;s1&quot;&gt;&amp;#39;serverspec&amp;#39;&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# - - - - - NSENTER verwenden - - - - -&lt;/span&gt;
include SpecInfra::Helper::Nsenter
&lt;span class=&quot;c&quot;&gt;# - - - - - nach problemen mit DetecOs&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# wird hier Debian explizit gesetzt - - -&lt;/span&gt;
include Serverspec::Helper::Debian

RSpec.configure &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;|&lt;/span&gt;c&lt;span class=&quot;p&quot;&gt;|&lt;/span&gt;

  &lt;span class=&quot;c&quot;&gt;# - - - - - PID für NSENTER aus Environment - - - - -&lt;/span&gt;
  c.nsenter_pid &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; ENV&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;NSENTER_PID&amp;#39;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; ENV&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;ASK_SUDO_PASSWORD&amp;#39;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Der spannende Moment beginnt:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ NSENTER_PID&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;15344&lt;/span&gt; rake spec
/usr/bin/ruby1.9.1 -S rspec spec/localhost/httpd_spec.rb
nsenter_exec! sudo dpkg-query -f &lt;span class=&quot;s1&quot;&gt;&amp;#39;${Status}&amp;#39;&lt;/span&gt; -W apache2 &lt;span class=&quot;p&quot;&gt;|&lt;/span&gt; grep -E &lt;span class=&quot;s1&quot;&gt;&amp;#39;^(install|hold) ok installed$&amp;#39;&lt;/span&gt;
F

Failures:

  1&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; Package &lt;span class=&quot;s2&quot;&gt;&amp;quot;apache2&amp;quot;&lt;/span&gt; should be installed
     On host &lt;span class=&quot;sb&quot;&gt;``&lt;/span&gt;
     Failure/Error: it &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt; should be_installed &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
       sudo dpkg-query -f &lt;span class=&quot;s1&quot;&gt;&amp;#39;${Status}&amp;#39;&lt;/span&gt; -W apache2 &lt;span class=&quot;p&quot;&gt;|&lt;/span&gt; grep -E &lt;span class=&quot;s1&quot;&gt;&amp;#39;^(install|hold) ok installed$&amp;#39;&lt;/span&gt;
       expected Package &lt;span class=&quot;s2&quot;&gt;&amp;quot;apache2&amp;quot;&lt;/span&gt; to be installed
     &lt;span class=&quot;c&quot;&gt;# ./spec/localhost/httpd_spec.rb:4:in `block (2 levels) in &amp;lt;top (required)&amp;gt;&amp;#39;&lt;/span&gt;

Finished in 0.02865 seconds
&lt;span class=&quot;m&quot;&gt;1&lt;/span&gt; example, &lt;span class=&quot;m&quot;&gt;1&lt;/span&gt; failure
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Die Debug-Ausgabe &lt;em&gt;nsenter_exec!&lt;/em&gt; zeigt, dass das neue nsenter-Backend aufgerufen
wird. Die spec liefert natürlich Fehler, weil der Apache nicht installiert ist.&lt;/p&gt;

&lt;p&gt;Wir einem Docker &lt;code&gt;attach&lt;/code&gt; kommen wir in den laufenden Container und installieren das &lt;code&gt;httpd&lt;/code&gt; Package nach:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;docker attach 9367


root@9367d023570d:/# apt-get update -yqq
root@9367d023570d:/# apt-get -yqq install apache2
Preconfiguring packages ...
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;...&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;

&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;CRTL-P&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;, &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;CTRL-Q&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; drücken, um zu detachen
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Und die Spec erneut ausführen:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ NSENTER_PID&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;15344&lt;/span&gt; rake spec
/usr/bin/ruby1.9.1 -S rspec spec/localhost/httpd_spec.rb
nsenter_exec! sudo dpkg-query -f &lt;span class=&quot;s1&quot;&gt;&amp;#39;${Status}&amp;#39;&lt;/span&gt; -W apache2 &lt;span class=&quot;p&quot;&gt;|&lt;/span&gt; grep -E &lt;span class=&quot;s1&quot;&gt;&amp;#39;^(install|hold) ok installed$&amp;#39;&lt;/span&gt;
.

Finished in 0.05324 seconds
&lt;span class=&quot;m&quot;&gt;1&lt;/span&gt; example, &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt; failures
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Das hat funktioniert.&lt;/p&gt;

&lt;p&gt;Vorteile:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Wenn nsenter als Backend in serverspec integriert wäre, könnte man so sehr einfach
laufende Container testen, d.h. mit allen statischen und dynamischen Aspekten.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;serverspec&lt;/code&gt; muss nicht im Container installiert sein, es reicht wenn die Prüfkommandos
im Container funktionieren.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Nachteile:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Der Aufruf von &lt;code&gt;serverspec&lt;/code&gt; klappt nur noch als Root bzw. mit sudo-Rechte auf &lt;code&gt;nsenter&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Es wird &lt;code&gt;nsenter&lt;/code&gt; als zusätzliches Paket auf dem Host benötigt.&lt;/li&gt;
&lt;li&gt;Die Integration der Prozess-PID in &lt;code&gt;spec_helper&lt;/code&gt; erfordert noch geeignete Wrapper.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Fazit&lt;/strong&gt;: &lt;em&gt;Whew, what a ride. In a nutshell: Don&amp;#39;t try this at home!&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Der Prototyp
hat zwar in Bezug auf Ubuntu und den Apache2-Package-Test funktioniert, er besitzt
aber noch keine Testabdeckung und deckt sicherlich nicht alle Eventualitäten ab.
Wenn nsenter als regulär installierbares Paket in die Package-Repositories der
Distributionen aufgenommen wird und Serverspec ggf. ab Version 2.X ein nsenter-backend
mitbringt, kann das ein sinnvoller Weg sein, um Container zu testen.&lt;/p&gt;

&lt;h2 id=&quot;testbarkeit:-gegeben!&quot;&gt;Testbarkeit: Gegeben!&lt;/h2&gt;

&lt;p&gt;Insgesamt sieht die Testbarkeit von Container-Images über serverspec gar nicht schlecht aus.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Zumindest die statischen Aspekte lassen sich über den Ansatz im &lt;code&gt;Dockerfile&lt;/code&gt; und mit dem
Docker-Backend von serverspec gut abtesten.&lt;/li&gt;
&lt;li&gt;Wer Container als VM-Ersatz betreibt, hat in der Regel volle Testbarkeit über den SSH-Zugang.&lt;/li&gt;
&lt;li&gt;Sobald die Entwicklung um nsenter fortgeschritten ist lässt sich die volle Testbarkeit
sicherlich auch für den Microservice-Container-Ansatz erreichen.&lt;/li&gt;
&lt;li&gt;Um auf einer Maschine unterschiedliche Projekte und Versionen der Testinfrastruktur ablaufen zu lassen empfehlen wir eine &lt;a href=&quot;https://github.com/docker/docker/wiki/Docker-in-Docker&quot;&gt;DockerInDocker&lt;/a&gt; Installation zu überlegen.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Viel Spaß beim Ausprobieren!&lt;/p&gt;

&lt;h2 id=&quot;&quot;&gt;&lt;/h2&gt;

&lt;p&gt;Andreas &amp;amp; Peter&lt;/p&gt;
</description>
                <link>/blog/2014/09/10/docker-container-mit-serverspec-testen</link>
                <guid>/blog/2014/09/10/docker-container-mit-serverspec-testen</guid>
                <pubDate>2014-09-10T00:00:00+02:00</pubDate>
        </item>

        <item>
                <title>Docker-Hosts mit Puppet provisionieren und testen</title>
                <description>&lt;p&gt;Die ersten Schritte mit Docker gestalten sich durch &lt;a href=&quot;2014-06-30-docker-mit-boot2docker-starten.md&quot;&gt;boot2docker&lt;/a&gt;
recht einfach, so hat man schnell eine Spielwiese erstellt, um die Funktionalität
ausprobieren zu können. Aber spätestens wenn Docker-Container im Test- oder Produktionssystem live gestellt werden sollen,
stellt sich die Frage nach dem reproduzierbaren Aufsetzen eines Docker-Hosts.&lt;/p&gt;

&lt;p&gt;Da wir für dieses Beispiel gar nicht so viele Dinge zu installieren, bzw. konfigurieren haben, ist ein leichtgewichtiges Tool wie z.B. &lt;a href=&quot;http://www.ansible.com&quot;&gt;Ansible&lt;/a&gt; oder &lt;a href=&quot;http://www.saltstack.com/&quot;&gt;SaltStack&lt;/a&gt; naheliegend. Viele Unternehmen
setzen allerdings seit geraumer Zeit auf &lt;a href=&quot;https://www.puppetlabs.com/&quot;&gt;Puppet&lt;/a&gt;, das allgemein bekannt sein dürfte.&lt;/p&gt;

&lt;p&gt;Um die Hürde nicht zu hoch zu legen und zuviel Veränderung auf einmal anzubringen, bauen wir dieses Beispiel
mit Puppet auf. Um die Installation testbar zu bekommen, empfiehlt
sich der Einsatz von &lt;a href=&quot;http://www.serverspec.org&quot;&gt;serverspec&lt;/a&gt;. Wer noch nicht so vertraut mit ServerSpec ist, sollte unseren &lt;a href=&quot;http://www.infrabricks.de/blog/2014/04/25/serverspec-server-spezifizieren-und-testen/&quot;&gt;Einführungs- Post&lt;/a&gt; dazu kurz lesen.&lt;/p&gt;

&lt;h2 id=&quot;vagrant/docker-provisioner&quot;&gt;Vagrant/Docker-Provisioner&lt;/h2&gt;

&lt;p&gt;Vagrant bietet selber einen &lt;a href=&quot;http://docs.vagrantup.com/v2/provisioning/docker.html&quot;&gt;Docker-Provisioner&lt;/a&gt; an.
Dieser ist nicht zu verwechseln mit dem Docker-Provider, der Docker als Backend verwendet, damit Vagrant
Container anstelle von VMs startet. Der Provisioner hingegen ist in der Lage, Docker
auf der gestartetem VM zu installieren, mit Images zu bestücken und
daraus Container zu starten. Die Konfiguration des Docker-Servers ist davon noch ausgenommen.&lt;/p&gt;

&lt;p&gt;Das ist schon eine gute Abkürzung auf dem Weg in Richtung Reproduzierbarkeit, sie hängt
allerdings auch davon ab, wie weit Vagrant in der Continuous Delivery Kette zum Einsatz kommt. Wenn z.B.
das Livesystem auf einer Virtualisierung beruht, die nicht durch ein Vagrant-Backend
unterstützt wird, kommt man mit dem Docker-Provisioner an der Stelle nicht weiter.
Dann werden Entwicklungs- und vielleicht auch Testsystem nachvollziehbar bestückt, beim Sprung
auf das Livesystem ergibt sich ein Bruch.&lt;/p&gt;

&lt;h2 id=&quot;puppet-modul-für-docker&quot;&gt;Puppet-Modul für Docker&lt;/h2&gt;

&lt;p&gt;Eine mögliche Lösung ist, Puppet für die Installation und Konfiguration des Docker-Servers
zu verwenden. Ein Puppet-Modul kann getestet werden, lässt sich in Vagrant über den
Puppet-Provisioner integrieren und auf allen Stages der Delivery-Chain nutzen.&lt;/p&gt;

&lt;p&gt;Wenn man in der PuppetForge nach Docker sucht, wird man schnell bei dem &lt;a href=&quot;https://forge.puppetlabs.com/garethr/docker&quot;&gt;Modul von Gareth Rushgrove&lt;/a&gt; fündig.
Damit lässt sich Docker installieren, in Teilen konfigurieren,
Images lassen sich herunterladen und Container können gestartet werden.&lt;/p&gt;

&lt;p&gt;Und wir möchten die Installation natürlich mit Serverspec&amp;#39;s testen, um nachhaltig zu beweisen das wir korrekt provisioniert haben.&lt;/p&gt;

&lt;p&gt;Alle Schritte können mit dem Github-Repository &lt;a href=&quot;https://github.com/aschmidt75/docker-testing-playground&quot;&gt;aschmidt75/docker-testing-playground&lt;/a&gt;
nachvollzogen werden. Im Text finden sich in den Abschnitten (Git-Tag)-Einträge, die
auf Tags im Repository verweisen. So lassen sich einzelne Stände nachvollziehen.&lt;/p&gt;

&lt;p&gt;Los geht&amp;#39;s!&lt;/p&gt;

&lt;h3 id=&quot;mit-der-leere-vm-beginnen-...&quot;&gt;Mit der leere VM beginnen ...&lt;/h3&gt;

&lt;p&gt;Wir starten mit einem einfach Vagrant-Konfiguration, das eine einzelne VM auf Basis
Ubuntu 14.04 aufbaut. Da wir auf einen fest benannten Paketstand aufsetzen
möchten, führen wir kein Update durch. Sinnvoll ist es, hier genau das Image
mit Werkzeugen wir z.B. &lt;a href=&quot;http://www.packer.io/&quot;&gt;Packer&lt;/a&gt; selber zu bauen und vorzuhalten, das man für den Betrieb
der eigenen Plattform haben möchte.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;c1&quot;&gt;# -*- mode: ruby -*-&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# vi: set ft=ruby :&lt;/span&gt;

&lt;span class=&quot;no&quot;&gt;Vagrant&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;configure&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;2&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vm&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;box&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;trusty64&amp;quot;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vm&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;box_url&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;http://cloud-images.ubuntu.com/vagrant/trusty/20140723/trusty-server-cloudimg-amd64-vagrant-disk1.box&amp;quot;&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vm&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;docker-test1&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;primary&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;(Git-Tag v1)&lt;/p&gt;

&lt;p&gt;Wer das ganze schnell ausprobieren möchte, kann sich den Code von github auschecken:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;$ git clone https://github.com/aschmidt75/docker-testing-playground
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Die einzelnen Stationen sind getagged, d.h. den obigen Stand v1 erhält man mit:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;$ git checkout tags/v1
Note: checking out &amp;#39;tags/v1&amp;#39;.
....
HEAD is now at 456090f... moved to test cmd
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3 id=&quot;...-serverspec-basis-dazugeben-...&quot;&gt;... Serverspec-Basis dazugeben ...&lt;/h3&gt;

&lt;p&gt;Die VM können wir mit &lt;code&gt;vagrant up&lt;/code&gt; starten, wir sind aber noch nicht so richtig weit gekommen. Um unsere
Installation testbar zu machen, benötigen wir serverspec. Es gibt ein Vagrant-Plugin für
Serverspec, allerdings ist das Zusammenspiel mit verschiedenen Versionen von serverspec,
Vagrant und dem Plugin noch nicht ideal. Außerdem möchten wir Serverspec-Spezifikation
auch später ohne Vagrant weiterverwenden können. Von daher installieren wir mit einem
Shell Provisioner Serverspec plus Abhängigkeiten und gehen davon aus, dass wir unsere Specs
über eine Synced-Folder in die VM reinreichen. Bei den gems geben wir zumindest
für serverspec, specinfra, rspec und rake feste Versionen an. Die beiden Projekte serverspec und specinfra sind aktuell sehr in der Entwicklung, also aufgepasst mit der Repoduzierbarkeit!&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;mkdir spec.d
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;vi Vagrantfile
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;    &lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vm&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;synced_folder&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;spec.d/&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;/mnt/spec.d&amp;quot;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# install &amp;amp; run serverspec&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vm&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;provision&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;shell&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;inline&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;EOS&lt;/span&gt;
&lt;span class=&quot;sh&quot;&gt;( sudo gem list --local | grep -q serverspec ) || {&lt;/span&gt;
&lt;span class=&quot;sh&quot;&gt;    sudo gem install rake -v &amp;#39;10.3.2&amp;#39;&lt;/span&gt;
&lt;span class=&quot;sh&quot;&gt;    sudo gem install rspec -v &amp;#39;2.99.0&amp;#39;&lt;/span&gt;
&lt;span class=&quot;sh&quot;&gt;    sudo gem install specinfra -v &amp;#39;1.21.0&amp;#39;&lt;/span&gt;
&lt;span class=&quot;sh&quot;&gt;    sudo gem install serverspec -v &amp;#39;1.10.0&amp;#39;&lt;/span&gt;
&lt;span class=&quot;sh&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;sh&quot;&gt;cd /mnt/spec.d&lt;/span&gt;
&lt;span class=&quot;sh&quot;&gt;rake spec&lt;/span&gt;

&lt;span class=&quot;no&quot;&gt;EOS&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;(Git-Tag v2)&lt;/p&gt;

&lt;p&gt;Die Vagrant VM muss wg. des Mounts neu gestartet und provisioniert werden:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;$ vagrant reload
$ vagrant provision
(...)
==&amp;gt; docker-test1: Running provisioner: shell...
    docker-test1: Running: inline script
==&amp;gt; docker-test1: stdin: is not a tty
==&amp;gt; docker-test1: Successfully installed specinfra-1.21.0
==&amp;gt; docker-test1: Successfully installed net-ssh-2.9.1
(...)
==&amp;gt; docker-test1: rake aborted!
==&amp;gt; docker-test1: No Rakefile found (looking for: rakefile, Rakefile, rakefile.rb, Rakefile.rb)
==&amp;gt; docker-test1: (See full trace by running task with --trace)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3 id=&quot;...-spezifikation-formulieren-...&quot;&gt;... Spezifikation formulieren ...&lt;/h3&gt;

&lt;p&gt;D.h. serverspec wurde installiert, aber da keine Specs vorhanden sind, kann der &lt;code&gt;rake spec&lt;/code&gt;-Aufruf
natürlich noch nichts tun. Wir legen uns auf dem Host über &lt;code&gt;serverspec-init&lt;/code&gt; eine leere Spezifikations-Hülle hin,
das HTTP-Beispiel wird durch das ersetzt, was wir testen wollen:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;$ cd spec.d
$ serverspec-init
Select OS type:

  1) UN*X
  2) Windows

Select number: 1

Select a backend type:

  1) SSH
  2) Exec (local)

Select number: 2

 + spec/
 + spec/localhost/
 + spec/localhost/httpd_spec.rb
 + spec/spec_helper.rb
 + Rakefile
$ rm spec/localhost/httpd_spec.rb
$ vim spec/localhost/docker_spec.rb

require &amp;#39;spec_helper&amp;#39;

describe &amp;#39;It should have docker installed&amp;#39; do
end
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;(Git-Tag v3)&lt;/p&gt;

&lt;p&gt;Ein &lt;code&gt;vagrant provision&lt;/code&gt; zeigt nun:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt; vagrant &lt;span class=&quot;nv&quot;&gt;provision&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;==&lt;/span&gt;&amp;gt; docker-test1: Running provisioner: shell...
    docker-test1: Running: inline &lt;span class=&quot;nv&quot;&gt;script&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;==&lt;/span&gt;&amp;gt; docker-test1: stdin: is not a &lt;span class=&quot;nv&quot;&gt;tty&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;==&lt;/span&gt;&amp;gt; docker-test1: Running provisioner: shell...
    docker-test1: Running: inline &lt;span class=&quot;nv&quot;&gt;script&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;==&lt;/span&gt;&amp;gt; docker-test1: stdin: is not a &lt;span class=&quot;nv&quot;&gt;tty&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;==&lt;/span&gt;&amp;gt; docker-test1: /usr/bin/ruby1.9.1 -S rspec spec/localhost/docker_spec.rb
&lt;span class=&quot;o&quot;&gt;==&lt;/span&gt;&amp;gt; docker-test1: No examples found.
&lt;span class=&quot;o&quot;&gt;==&lt;/span&gt;&amp;gt; docker-test1:
&lt;span class=&quot;o&quot;&gt;==&lt;/span&gt;&amp;gt; docker-test1: Finished in 0.00006 &lt;span class=&quot;nv&quot;&gt;seconds&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;==&lt;/span&gt;&amp;gt; docker-test1: &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt; examples, &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt; failures
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Im Spec-File können wir jetzt ausdrücken, wie Docker installiert sein sollte, z.B. so:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;vim spec.d/spec/localhost/docker_spec.rb
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;und den leeren describe-Block ersetzen durch:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;describe&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;It should have docker installed&amp;#39;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;describe&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;lxc-docker-1.1.1&amp;#39;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;it&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;should&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;be_installed&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;describe&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;group&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;docker&amp;#39;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;it&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;should&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;exist&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;describe&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;file&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;/var/run/docker.sock&amp;#39;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;it&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;should&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;be_socket&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;it&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;should&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;be_owned_by&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;root&amp;#39;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;it&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;should&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;be_grouped_into&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;docker&amp;#39;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;describe&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;command&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;docker -v&amp;#39;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;its&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:stdout&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;should&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;match&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;^Docker version 1\.1\.1.*&amp;#39;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Das entspricht der Standardinstallation über das Repository von Docker, zumindest für die
Version 1.1.1, die wir haben möchten. Ein &lt;code&gt;vagrant provision&lt;/code&gt; zeigt nun
eine Menge Fehler, da ja noch nichts installiert ist.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;vagrant provision
&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;...&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
Finished in 0.10243 seconds
&lt;span class=&quot;m&quot;&gt;5&lt;/span&gt; examples, &lt;span class=&quot;m&quot;&gt;5&lt;/span&gt; failures

Failed examples:

rspec ./spec/localhost/docker_spec.rb:5 &lt;span class=&quot;c&quot;&gt;# It should have docker installed Package &amp;quot;lxc-docker-1.1.1&amp;quot; should be installed&lt;/span&gt;
rspec ./spec/localhost/docker_spec.rb:9 &lt;span class=&quot;c&quot;&gt;# It should have docker installed Group &amp;quot;docker&amp;quot; should exist []&lt;/span&gt;
rspec ./spec/localhost/docker_spec.rb:13 &lt;span class=&quot;c&quot;&gt;# It should have docker installed File &amp;quot;/var/run/docker.sock&amp;quot; should be socket&lt;/span&gt;
rspec ./spec/localhost/docker_spec.rb:14 &lt;span class=&quot;c&quot;&gt;# It should have docker installed File &amp;quot;/var/run/docker.sock&amp;quot; should be owned by &amp;quot;root&amp;quot;&lt;/span&gt;
rspec ./spec/localhost/docker_spec.rb:15 &lt;span class=&quot;c&quot;&gt;# It should have docker installed File &amp;quot;/var/run/docker.sock&amp;quot; should be grouped into &amp;quot;docker&amp;quot;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;...&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;(Git-Tag v4)&lt;/p&gt;

&lt;h3 id=&quot;...-das-puppet-modul-hinzufügen-...&quot;&gt;... Das Puppet-Modul hinzufügen ...&lt;/h3&gt;

&lt;p&gt;Wir möchte Docker über Puppet und das Puppetmodul aus der Forge installieren, d.h. es lohnt sich
auch, das als Serverspec auszudrücken, um es dann umzusetzen. Die aktuelle Version ist 1.1.3:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;$ vim spec.d/spec/localhost/puppet_spec.rb
(..einfügen..)
require &amp;#39;spec_helper&amp;#39;

describe package &amp;#39;puppet&amp;#39; do
    it { should be_installed }
end

describe &amp;#39;It should have the garethr-docker module&amp;#39; do
    describe file &amp;#39;/etc/puppet/modules/docker&amp;#39; do
        it { should be_directory }
        it { should be_mode &amp;#39;755&amp;#39; }
    end

    describe command &amp;#39;puppet module list&amp;#39; do
        its(:stdout) { should match &amp;#39;garethr-docker.*1\.1\.3&amp;#39; }
    end
end
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Ein &lt;code&gt;vagrant provision&lt;/code&gt; zeigt nun natürlich noch mehr Fehler an. Wir beheben das ganze,
indem das Vagrantfile um einen Shell-Provisioner-Abschnitt ergänzt wird, der über puppet
das Modul nachinstalliert, solange es noch nicht vorhanden ist. Wir wählen auch
hier gezielt eine feste Version aus:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;err&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;vi&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Vagrantfile&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# install puppet module for docker&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vm&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;provision&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;shell&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;inline&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;s1&quot;&gt;&amp;#39;sudo su - -c &amp;quot;( puppet module list | grep -q garethr-docker ) || puppet module install -v 1.1.3 garethr-docker&amp;quot;&amp;#39;&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;# install &amp;amp; run serverspec&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;vagrant provision
&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;...&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;==&lt;/span&gt;&amp;gt; docker-test1: Running provisioner: shell...
    docker-test1: Running: inline &lt;span class=&quot;nv&quot;&gt;script&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;==&lt;/span&gt;&amp;gt; docker-test1: stdin: is not a &lt;span class=&quot;nv&quot;&gt;tty&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;==&lt;/span&gt;&amp;gt; docker-test1: stdin: is not a &lt;span class=&quot;nv&quot;&gt;tty&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;==&lt;/span&gt;&amp;gt; docker-test1: Notice: Preparing to install into /etc/puppet/modules ...
&lt;span class=&quot;o&quot;&gt;==&lt;/span&gt;&amp;gt; docker-test1: Notice: Downloading from https://forge.puppetlabs.com ...
&lt;span class=&quot;o&quot;&gt;==&lt;/span&gt;&amp;gt; docker-test1: Notice: Installing -- &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; not interrupt ...
&lt;span class=&quot;o&quot;&gt;==&lt;/span&gt;&amp;gt; docker-test1: /etc/puppet/modules
&lt;span class=&quot;o&quot;&gt;==&lt;/span&gt;&amp;gt; docker-test1: └─┬ garethr-docker &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;v1.1.3&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;==&lt;/span&gt;&amp;gt; docker-test1:   ├── puppetlabs-apt &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;v1.5.1&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;==&lt;/span&gt;&amp;gt; docker-test1:   ├── puppetlabs-stdlib &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;v4.3.0&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;==&lt;/span&gt;&amp;gt; docker-test1:   └── stahnma-epel &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;v0.1.0&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;...&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
Finished in 1.11 seconds
&lt;span class=&quot;m&quot;&gt;9&lt;/span&gt; examples, &lt;span class=&quot;m&quot;&gt;5&lt;/span&gt; failures

Failed examples:
&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;...&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;(Git-Tag v5)&lt;/p&gt;

&lt;h3 id=&quot;...-und-docker-über-puppet-installieren-lassen&quot;&gt;... und Docker über Puppet installieren lassen&lt;/h3&gt;

&lt;p&gt;Im Serverspec-Teil sind allerdings die vier &lt;code&gt;Examples&lt;/code&gt; für Puppet grün, nur die Docker-Examples
sind rot. Also müssen wir jetzt Docker installieren. Dazu bauen wir ein Puppet-Modul,
welches über den Puppet-Provisioner in Vagrant ausgerollt wird. Erst einmal eine leere Hülle:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;mkdir puppet.d
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;mkdir puppet.d/manifests
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;mkdir puppet.d/modules
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;vim puppet.d/manifests/default.pp
&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;..einfügen..&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;

notify &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;Running puppet apply on $hostname&amp;quot;&lt;/span&gt;: &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;vi Vagrantfile
&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;..einfügen..&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;c&quot;&gt;# provision the node&lt;/span&gt;
    s.vm.provision :puppet, :options &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&amp;gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;--verbose&amp;quot;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;|&lt;/span&gt;puppet&lt;span class=&quot;p&quot;&gt;|&lt;/span&gt;
        puppet.manifests_path &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;puppet.d/manifests&amp;quot;&lt;/span&gt;
        puppet.module_path &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;puppet.d/modules&amp;quot;&lt;/span&gt;
        puppet.manifest_file &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;default.pp&amp;quot;&lt;/span&gt;
    end

    &lt;span class=&quot;c&quot;&gt;# install &amp;amp; run serverspec&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;...&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Da der Puppet-Provisioner intern über Vagrant einen Synced-Folder erzeugt, müssen wir die
VM reloaden, danach kann provisioniert werden:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;vagrant reload
&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;...&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;vagrant provision
&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;...&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;==&lt;/span&gt;&amp;gt; docker-test1: Running provisioner: puppet...
&lt;span class=&quot;o&quot;&gt;==&lt;/span&gt;&amp;gt; docker-test1: Running Puppet with default.pp...
&lt;span class=&quot;o&quot;&gt;==&lt;/span&gt;&amp;gt; docker-test1: stdin: is not a tty
&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;...&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;==&lt;/span&gt;&amp;gt; docker-test1: Notice: Compiled catalog &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; vagrant-ubuntu-trusty-64 in environment production in 0.03 seconds
&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;...&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;==&lt;/span&gt;&amp;gt; docker-test1: Info: Applying configuration version &lt;span class=&quot;s1&quot;&gt;&amp;#39;1405518114&amp;#39;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;==&lt;/span&gt;&amp;gt; docker-test1: Notice: Running puppet apply on vagrant-ubuntu-trusty-64
&lt;span class=&quot;o&quot;&gt;==&lt;/span&gt;&amp;gt; docker-test1: Notice: /Stage&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;main&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;/Main/Notify&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;Running puppet apply on vagrant-ubuntu-trusty-64&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;/message: defined &lt;span class=&quot;s1&quot;&gt;&amp;#39;message&amp;#39;&lt;/span&gt; as &lt;span class=&quot;s1&quot;&gt;&amp;#39;Running puppet apply on vagrant-ubuntu-trusty-64&amp;#39;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;==&lt;/span&gt;&amp;gt; docker-test1: Info: Creating state file /var/lib/puppet/state/state.yaml
&lt;span class=&quot;o&quot;&gt;==&lt;/span&gt;&amp;gt; docker-test1: Notice: Finished catalog run in 0.03 seconds

&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;...&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;...Fehler von serverspec, weil Docker noch nicht installiert ist...&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;(Git-Tag v6)&lt;/p&gt;

&lt;p&gt;Damit fehlt jetzt &amp;quot;nur&amp;quot; noch das was eigentlich wollten, nämlich Docker auch zu installieren :-)
Das geht mit dem Modul aus der Puppetforge sehr einfach. Wir implementieren ein Modul,
bestehend aus Subklassen install, run in eigenen .pp-Dateien
und der Abhängigkeit. Im install-Bereich kommt die Docker-Klasse ins Spiel, wo
die Konfiguration des Servers gesetzt werden kann.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;mkdir -p puppet.d/modules/docker_host/&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;manifests,templates&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;vi puppet.d/modules/docker_host/manifests/init.pp
class docker_host &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
  notify &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;in docker_host&amp;#39;&lt;/span&gt;: &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

  class &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;docker_host::install&amp;#39;&lt;/span&gt;: &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

  class &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;docker_host::run&amp;#39;&lt;/span&gt;: &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

  Class&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;docker_host::install&amp;#39;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; -&amp;gt; Class&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;docker_host::run&amp;#39;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;vi puppet.d/modules/docker_host/manifests/install.pp
include &lt;span class=&quot;s1&quot;&gt;&amp;#39;docker&amp;#39;&lt;/span&gt;

class docker_host::install &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
  class &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;docker&amp;#39;&lt;/span&gt;:
    &lt;span class=&quot;nv&quot;&gt;version&lt;/span&gt;       &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&amp;gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;1.1.1&amp;#39;&lt;/span&gt;,
    &lt;span class=&quot;nv&quot;&gt;manage_kernel&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&amp;gt; &lt;span class=&quot;nb&quot;&gt;false&lt;/span&gt;,
    &lt;span class=&quot;nv&quot;&gt;tcp_bind&lt;/span&gt;      &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&amp;gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;tcp://127.0.0.1:2375&amp;#39;&lt;/span&gt;,
    &lt;span class=&quot;nv&quot;&gt;socket_bind&lt;/span&gt;   &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&amp;gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;unix:///var/run/docker.sock&amp;#39;&lt;/span&gt;,
  &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;vi puppet.d/modules/docker_host/manifests/run.pp
class docker_host::run &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;vi puppet.d/manifests/default.pp
&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;...einfügen..&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
class &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;docker_host&amp;#39;&lt;/span&gt;: &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;(Git-Tag v7)&lt;/p&gt;

&lt;p&gt;Ein &lt;code&gt;vagrant provision&lt;/code&gt; dauert nun schon etwas länger, da Docker nun auch
installiert wird:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;o&quot;&gt;==&lt;/span&gt;&amp;gt; docker-test1: Notice: Running puppet apply on vagrant-ubuntu-trusty-64
&lt;span class=&quot;o&quot;&gt;==&lt;/span&gt;&amp;gt; docker-test1: Notice: /Stage&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;main&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;/Main/Notify&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;Running puppet apply on vagrant-ubuntu-trusty-64&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;/message: defined &lt;span class=&quot;s1&quot;&gt;&amp;#39;message&amp;#39;&lt;/span&gt; as &lt;span class=&quot;s1&quot;&gt;&amp;#39;Running puppet apply on vagrant-ubuntu-trusty-64&amp;#39;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;==&lt;/span&gt;&amp;gt; docker-test1: Notice: /Stage&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;main&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;/Docker::Install/Package&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;cgroup-lite&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;/ensure: ensure changed &lt;span class=&quot;s1&quot;&gt;&amp;#39;purged&amp;#39;&lt;/span&gt; to &lt;span class=&quot;s1&quot;&gt;&amp;#39;present&amp;#39;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;==&lt;/span&gt;&amp;gt; docker-test1: Notice: /Stage&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;main&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;/Docker::Install/Apt::Source&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;docker&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;/Apt::Key&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;Add key: A88D21E9 from Apt::Source docker&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;/Apt_key&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;Add key: A88D21E9 from Apt::Source docker&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;/ensure: &lt;span class=&quot;nv&quot;&gt;created&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;==&lt;/span&gt;&amp;gt; docker-test1: Notice: in &lt;span class=&quot;nv&quot;&gt;docker_host&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;==&lt;/span&gt;&amp;gt; docker-test1: Notice: /Stage&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;main&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;/Docker_host/Notify&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;in docker_host&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;/message: defined &lt;span class=&quot;s1&quot;&gt;&amp;#39;message&amp;#39;&lt;/span&gt; as &lt;span class=&quot;s1&quot;&gt;&amp;#39;in docker_host&amp;#39;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;==&lt;/span&gt;&amp;gt; docker-test1: Notice: /Stage&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;main&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;/Docker::Install/Apt::Source&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;docker&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;/Apt::Pin&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;docker&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;/File&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;docker.pref&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;/ensure: &lt;span class=&quot;nv&quot;&gt;created&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;==&lt;/span&gt;&amp;gt; docker-test1: Notice: /Stage&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;main&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;/Docker::Install/Apt::Source&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;docker&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;/File&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;docker.list&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;/ensure: &lt;span class=&quot;nv&quot;&gt;created&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;==&lt;/span&gt;&amp;gt; docker-test1: Info: /Stage&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;main&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;/Docker::Install/Apt::Source&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;docker&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;/File&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;docker.list&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;: Scheduling refresh of Exec&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;apt_update&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;==&lt;/span&gt;&amp;gt; docker-test1: Info: /Stage&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;main&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;/Docker::Install/Apt::Source&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;docker&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;/File&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;docker.list&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;: Scheduling refresh of Exec&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;Required packages: &lt;span class=&quot;s1&quot;&gt;&amp;#39;debian-keyring debian-archive-keyring&amp;#39;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; docker&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;==&lt;/span&gt;&amp;gt; docker-test1: Notice: /Stage&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;main&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;/Docker::Install/Apt::Source&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;docker&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;/Exec&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;Required packages: &lt;span class=&quot;s1&quot;&gt;&amp;#39;debian-keyring debian-archive-keyring&amp;#39;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; docker&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;: Triggered &lt;span class=&quot;s1&quot;&gt;&amp;#39;refresh&amp;#39;&lt;/span&gt; from &lt;span class=&quot;m&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;events&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;==&lt;/span&gt;&amp;gt; docker-test1: Notice: /Stage&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;main&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;/Apt::Update/Exec&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;apt_update&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;: Triggered &lt;span class=&quot;s1&quot;&gt;&amp;#39;refresh&amp;#39;&lt;/span&gt; from &lt;span class=&quot;m&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;events&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;==&lt;/span&gt;&amp;gt; docker-test1: Notice: /Stage&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;main&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;/Docker::Install/Package&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;docker&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;/ensure: ensure changed &lt;span class=&quot;s1&quot;&gt;&amp;#39;purged&amp;#39;&lt;/span&gt; to &lt;span class=&quot;s1&quot;&gt;&amp;#39;present&amp;#39;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;==&lt;/span&gt;&amp;gt; docker-test1: Info: /Stage&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;main&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;/Docker::Service/File&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;/etc/default/docker&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;: Filebucketed /etc/default/docker to puppet with sum &lt;span class=&quot;nv&quot;&gt;ce88dab1dcba6f92903120b9beba2521&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;==&lt;/span&gt;&amp;gt; docker-test1: Notice: /Stage&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;main&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;/Docker::Service/File&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;/etc/default/docker&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;/content: content changed &lt;span class=&quot;s1&quot;&gt;&amp;#39;{md5}ce88dab1dcba6f92903120b9beba2521&amp;#39;&lt;/span&gt; to &lt;span class=&quot;s1&quot;&gt;&amp;#39;{md5}c44278611ed762b2de4b5b78cda333e6&amp;#39;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;==&lt;/span&gt;&amp;gt; docker-test1: Info: /Stage&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;main&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;/Docker::Service/File&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;/etc/default/docker&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;: Scheduling refresh of Service&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;docker&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;==&lt;/span&gt;&amp;gt; docker-test1: Info: /Stage&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;main&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;/Docker::Service/File&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;/etc/init.d/docker&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;: Filebucketed /etc/init.d/docker to puppet with sum &lt;span class=&quot;nv&quot;&gt;d9d2305259b22bfbc1086939a23df23a&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;==&lt;/span&gt;&amp;gt; docker-test1: Notice: /Stage&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;main&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;/Docker::Service/File&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;/etc/init.d/docker&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;/ensure: &lt;span class=&quot;nv&quot;&gt;removed&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;==&lt;/span&gt;&amp;gt; docker-test1: Info: /Stage&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;main&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;/Docker::Service/File&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;/etc/init.d/docker&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;: Scheduling refresh of Service&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;docker&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;==&lt;/span&gt;&amp;gt; docker-test1: Notice: /Stage&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;main&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;/Docker::Service/Service&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;docker&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;: Triggered &lt;span class=&quot;s1&quot;&gt;&amp;#39;refresh&amp;#39;&lt;/span&gt; from &lt;span class=&quot;m&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;events&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;==&lt;/span&gt;&amp;gt; docker-test1: Notice: Finished catalog run in 148.66 seconds
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;... und die Specs ...&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;==&amp;gt; docker-test1: /usr/bin/ruby1.9.1 -S rspec spec/localhost/docker_spec.rb spec/localhost/puppet_spec.rb
(...)
==&amp;gt; docker-test1: Finished in 0.9264 seconds
==&amp;gt; docker-test1: 9 examples, 0 failures
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3 id=&quot;fertig!&quot;&gt;Fertig!&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;9 Examples, 0 Failures&lt;/code&gt;: geschafft. Wir haben jetzt eine virtuelle Maschine, die&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Puppet und das Docker-Modul beinhaltet,&lt;/li&gt;
&lt;li&gt;ein lauffähigen Docker-Server über Puppet installiert hat und&lt;/li&gt;
&lt;li&gt;das ganze mit Hilfe von Serverspec testbar macht.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Wenn man die Serverspec-Ausgabe detailliert mitverfolgen möchte, hilft ein &lt;code&gt;--format&lt;/code&gt;-Eintrag im
&lt;code&gt;Rakefile&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;vi spec.d/Rakefile
RSpec::Core::RakeTask.new&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;:spec&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;|&lt;/span&gt;t&lt;span class=&quot;p&quot;&gt;|&lt;/span&gt;
  t.pattern &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;spec/*/*_spec.rb&amp;#39;&lt;/span&gt;
  t.rspec_opts &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;--format documentation&amp;#39;&lt;/span&gt;
end
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Damit kann man serverspec bei der Arbeit zusehen, allerdings kann die Ausgabe mit steigendem Umfang
der Spec auch recht lang werden. Zu Debugging-Zwecken lohnt es sich allerdings sehr.&lt;/p&gt;

&lt;p&gt;Wir können jetzt damit fortfahren, die Spezifikation wasserdicht zu machen, und alle
Einstellungen, die wir über das Puppet-Modul in die Docker-Konfiguration einbringen können, auch abzutesten. Das werden wir nicht im Detail erläutern, wer mag, checkt sich den Master-Branch aus und schaut sich die Specs an.&lt;/p&gt;

&lt;p&gt;Am Ende haben wir die Basis für eine vollautomatische und nachvollziehbare Installation eines Docker-Hosts.  &lt;/p&gt;

&lt;h2 id=&quot;&quot;&gt;&lt;/h2&gt;

&lt;p&gt;Andreas &amp;amp; Peter&lt;/p&gt;
</description>
                <link>/blog/2014/07/24/hosts-mit-docker-und-puppet-provisionieren</link>
                <guid>/blog/2014/07/24/hosts-mit-docker-und-puppet-provisionieren</guid>
                <pubDate>2014-07-24T00:00:00+02:00</pubDate>
        </item>

        <item>
                <title>Docker entschlüsselt: Netzwerk-Teil 2</title>
                <description>&lt;p&gt;Im &lt;a href=&quot;http://www.infrabricks.de/blog/2014/07/06/docker-entschlusselt-netzwerk/&quot;&gt;ersten Teil&lt;/a&gt;
von &amp;quot;Docker entschlüsselt: Netzwerk&amp;quot; haben wir gesehen,
wie der Docker-Daemon Netzwerkinterfaces, die &lt;code&gt;docker0&lt;/code&gt;-Bridge und die
Kommunikation der Container nach außen und untereinander managed.&lt;/p&gt;

&lt;p&gt;Im zweiten Teil sollen nun die Grundlagen geschaffen werden, damit Docker-Container
auch über Host-Grenzen hinweg kommunizieren können. Dafür gibt es mehrere
Möglichkeiten (z.B. die Default-Bridge &lt;code&gt;docker0&lt;/code&gt; an ein externes Interface anzuschließen oder
  das iptables-Regelwerk zu erweitern), wir wählen diejenige, welche mit der Standardkonfiguration
des Docker-Daemon funktioniert.&lt;/p&gt;

&lt;h2 id=&quot;der-plan:-eine-neue-bridge-anlegen&quot;&gt;Der Plan: Eine neue Bridge anlegen&lt;/h2&gt;

&lt;p&gt;Ziel ist es, auf zwei virtuellen Maschinen je einen Docker Container zu instanziieren.
Dieser Container wird mit einem neuen &lt;code&gt;eth1&lt;/code&gt; Netzwerkinterface versorgt, das über
eine eigene &lt;code&gt;br1&lt;/code&gt; Netzwerk-Bridge mit einem &lt;code&gt;eth1&lt;/code&gt; Netzwerkinterface des Hosts verbunden ist:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/docker_network_2vms.png&quot; alt=&quot;docker_network_2vms.png&quot;&gt;&lt;/p&gt;

&lt;h2 id=&quot;voraussetzungen&quot;&gt;Voraussetzungen&lt;/h2&gt;

&lt;p&gt;Um ein solches Setup schnell aufzusetzen, empfiehlt sich die Kombination aus
Vagrant und Virtualbox. Als Basis kann dafür unser &lt;a href=&quot;https://github.com/rossbachp/dockerbox&quot;&gt;DockerBox&lt;/a&gt; - Projekt auf github dienen. Dazu das passende Vagrantfile für zwei VMs auf Basis Ubuntu:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;no&quot;&gt;Vagrant&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;configure&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;2&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# https://vagrantcloud.com/stamm/trusty64-dockeattr_reader :attr_names&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vm&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;box&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;trusty64&amp;quot;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vm&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;box_url&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;http://cloud-images.ubuntu.com/vagrant/trusty/current/trusty-server-cloudimg-amd64-vagrant-disk1.box&amp;quot;&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vm&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;docker-test1&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;primary&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vm&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;network&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;private_network&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;ip&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;192.168.77.5&amp;quot;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vm&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;provider&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;virtualbox&amp;quot;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vb&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;vb&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;customize&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;modifyvm&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;--nicpromisc2&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;allow-all&amp;#39;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;vb&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;gui&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;false&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;vb&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;customize&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;modifyvm&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;--memory&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;512&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;vb&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;customize&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;modifyvm&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;--cpus&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;1&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vm&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;docker-test2&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;primary&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vm&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;network&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;private_network&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;ip&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;192.168.77.6&amp;quot;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vm&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;provider&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;virtualbox&amp;quot;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vb&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;vb&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;customize&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;modifyvm&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;--nicpromisc2&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;allow-all&amp;#39;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;vb&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;gui&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;false&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;vb&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;customize&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;modifyvm&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;--memory&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;512&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;vb&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;customize&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;modifyvm&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;--cpus&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;1&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Das besondere liegt in der Definition eines zusätzlichen Netzwerkinterfaces
&lt;code&gt;eth1&lt;/code&gt;, dass im weiteren in den &lt;a href=&quot;http://de.wikipedia.org/wiki/Promiscuous_Mode&quot;&gt;Promisc-Mode&lt;/a&gt; geschaltet wird:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt; &lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vm&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;network&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;private_network&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;ip&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;192.168.77.5&amp;quot;&lt;/span&gt;
 &lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vm&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;provider&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;virtualbox&amp;quot;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vb&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
       &lt;span class=&quot;n&quot;&gt;vb&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;customize&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;modifyvm&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;--nicpromisc2&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;allow-all&amp;#39;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Auf der Seite des Hosts wird dazu eine Host-Only Bridge erzeugt (z.B. &lt;code&gt;vnet1&lt;/code&gt;),
an dem diese virtuellen Netzwerkinterfaces angeklemmt sind.&lt;/p&gt;

&lt;p&gt;Nach Starten der VMs kann man sich das Ergebnis anschauen:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;vagrant up
....
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;vagrant ssh docker-test1
....
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;ip addr show
...
3: eth1: &amp;lt;BROADCAST,MULTICAST,UP,LOWER_UP&amp;gt; mtu &lt;span class=&quot;m&quot;&gt;1500&lt;/span&gt; qdisc pfifo_fast master ovs-system state UP group default qlen 1000
    link/ether 08:00:27:a5:83:64 brd ff:ff:ff:ff:ff:ff
    inet 192.168.77.5/24 brd 192.168.77.255 scope global eth1
       valid_lft forever preferred_lft forever
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;In den beiden VMs werden nun noch Pakete, u.a. docker, nach installiert:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;sudo apt-get -y update
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;sudo apt-get -y install curl git openssl ca-certificates make bridge-utils arping
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;sudo apt-get install -y docker.io
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;sudo ln -sf /usr/bin/docker.io /usr/local/bin/docker
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Alternativ kann die &lt;a href=&quot;https://github.com/rossbachp/dockerbox&quot;&gt;DockerBox&lt;/a&gt; eingesetzt werden,
dort muss nur das Paket bridge-utils nachinstalliert werden.&lt;/p&gt;

&lt;p&gt;Um mit dem Docker-Containern zu experimentieren, ziehen wir das Ubuntu-Image:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;sudo -i
~# docker pull ubuntu:latest
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Und instanziieren einen neuen Docker-Container, lassen ihn im Vordergrund geöffnet.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;~# docker run -t -i ubuntu:latest /bin/bash
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Um das Ziel zu erreichen, benötigt jeder Container ein neues Netzwerkinterface.
Außerdem soll auf den VMs eine neue Bridge existieren, die an das VM-Interface
mit dem privaten Netzwerk angeschlossen ist.&lt;/p&gt;

&lt;p&gt;Den größten Teil dieser Arbeit kann dabei &lt;a href=&quot;https://github.com/jpetazzo/pipework&quot;&gt;Pipework&lt;/a&gt; übernehmen.&lt;/p&gt;

&lt;h2 id=&quot;pipework&quot;&gt;Pipework&lt;/h2&gt;

&lt;p&gt;Bei pipework handelt es sich um ein Shell-Skript, das sich um genau diese Aufgaben kümmert:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Anlegen einer Bridge auf dem Host&lt;/li&gt;
&lt;li&gt;Anlegen eines Netzwerkinterfaces im Container, zugeordnet zu dessen Namenspace&lt;/li&gt;
&lt;li&gt;Anlegen eines (Peer-)Netzwerkinterfaces auf dem Host, verknüpft zum Interface im Container&lt;/li&gt;
&lt;li&gt;Anklemmen des Host-Interfaces an die Bridge&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Dabei versteht es sich mit der Linux Bridge und &lt;a href=&quot;http://openvswitch.org/&quot;&gt;Open vSwitch&lt;/a&gt; und bietet weitreichende Möglichkeiten.&lt;/p&gt;

&lt;p&gt;Auf den VMs kann pipework folgendermassen installiert werden:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;sudo -i
~# git clone https://github.com/jpetazzo/pipework
~# &lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;pipework
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Um einen Container mit einem neuen Netzwerkinterface zu versorgen, brauchen wir jeweils seine Container ID.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;~# docker ps
....
~# &lt;span class=&quot;nv&quot;&gt;CID&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&amp;lt;Container-ID einsetzen&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Jetzt geben wir dem Container ein neues Interface, mit einer IP-Adresse&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;~# ./pipework br0 $CID 192.168.77.10/24
# bzw. auf der zweiten VM:
~# ./pipework br0 $CID 192.168.77.20/24
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;In der (noch offenen, s.o.) Container-Shell lässt sich das nachprüfen:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;ip addr show eth1
20: eth1: &amp;lt;BROADCAST,MULTICAST,UP,LOWER_UP&amp;gt; mtu &lt;span class=&quot;m&quot;&gt;1500&lt;/span&gt; qdisc pfifo_fast state UP group default qlen 1000
    link/ether be:fc:f1:47:02:2a brd ff:ff:ff:ff:ff:ff
    inet 192.168.77.10/24 scope global eth1
       valid_lft forever preferred_lft forever
    inet6 fe80::bcfc:f1ff:fe47:22a/64 scope link
       valid_lft forever preferred_lft forever
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;D.h. pipework hat uns ein passendes Interfaces erzeugt und mit einer IP versorgt.
Auf dem Host lässt sich der Zustand der Bridge anzeigen:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;~# brctl show
bridge name bridge id       STP enabled interfaces
br0     8000.0800273bcbbb   no    pl5330eth1
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Es ist zu sehen, dass auf der &lt;code&gt;docker0&lt;/code&gt;-Bridge ein veth-Interface angebunden ist
(im Container: eth0), und auf der neuen &lt;code&gt;br0&lt;/code&gt;-Bridge ein anderes virtuellees-Interface,
das im Container dem neuen eth1 entspricht. Pipework vergibt dabei Interface-Namen, die
mit &amp;quot;pl&amp;quot; prefixed sind.&lt;/p&gt;

&lt;h2 id=&quot;anzeige-der-bridge-/interface-struktur&quot;&gt;Anzeige der Bridge-/Interface-Struktur&lt;/h2&gt;

&lt;p&gt;Mit einem Ruby-Skript lässt sich der Zusammenhang zwischen Bridges, Interfaces
auf dem Host und in den Container anzeigen:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;~# git clone https://github.com/aschmidt75/docker-network-inspect
~# &lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;docker-network-inspect/lib/
~# ./docker-network-inspect.rb &lt;span class=&quot;nv&quot;&gt;$CID&lt;/span&gt;
CONTAINER 6437709a4ea2
+ PID 5330
+ INTERFACES
 + lo &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;1&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
 + eth0 &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;5&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
  + HOST PEER veth6166 &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;6&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
   + BRIDGE
 + eth1 &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;8&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
  + HOST PEER pl5330eth1 &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;9&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
   + BRIDGE br0
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&quot;container-über-vm-grenzen-verbinden&quot;&gt;Container über VM-Grenzen verbinden&lt;/h2&gt;

&lt;p&gt;Um die Container auf den beiden VMs miteinander sprechen zu lassen, wird eine
Verbindung der beiden neuen Bridges notwendig. Dazu liegen auf den VMs die
Host-Interfaces (&lt;code&gt;eth1&lt;/code&gt;) bereit. Wichtig ist, dass diese Interfaces und die
Interfaces der Container im selben Subnetz liegen (hier: 192.168.77.0/24)&lt;/p&gt;

&lt;p&gt;In den VMs verbinden wir das jeweilige &lt;code&gt;eth1&lt;/code&gt; mit der Bridge &lt;code&gt;br0&lt;/code&gt;&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;~# brctl addif br0 eth1
~# brctl show br0
bridge name bridge id       STP enabled interfaces
br0     8000.0800273bcbbb   no      eth1
                            pl5330eth1
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Im Container selber lässt sich nun die IP des jeweils anderen Docker-Containers auf der anderen VM anpingen:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Tipp&lt;/strong&gt;: Auf die richtige IP in der jeweiligen VM achten!&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Im Docker-Container auf der &lt;code&gt;docker-test1&lt;/code&gt;-VM hilft folgender Test:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;~# ping 192.168.77.20
PING 192.168.77.20 &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;192.168.77.20&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; 56&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;84&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; bytes of data.
&lt;span class=&quot;m&quot;&gt;64&lt;/span&gt; bytes from 192.168.77.20: &lt;span class=&quot;nv&quot;&gt;icmp_seq&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;ttl&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;64&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0.364 ms
&lt;span class=&quot;m&quot;&gt;64&lt;/span&gt; bytes from 192.168.77.20: &lt;span class=&quot;nv&quot;&gt;icmp_seq&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;ttl&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;64&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0.524 ms
^C
--- 192.168.77.20 ping statistics ---
&lt;span class=&quot;m&quot;&gt;2&lt;/span&gt; packets transmitted, &lt;span class=&quot;m&quot;&gt;2&lt;/span&gt; received, 0% packet loss, &lt;span class=&quot;nb&quot;&gt;time &lt;/span&gt;1000ms
rtt min/avg/max/mdev &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; 0.364/0.444/0.524/0.080 ms
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Im Docker-Container auf der &lt;code&gt;docker-test2&lt;/code&gt;-VM hilft folgender Test:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;~# ping 192.168.77.10
PING 192.168.77.10 &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;192.168.77.10&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; 56&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;84&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; bytes of data.
&lt;span class=&quot;m&quot;&gt;64&lt;/span&gt; bytes from 192.168.77.10: &lt;span class=&quot;nv&quot;&gt;icmp_seq&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;ttl&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;64&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0.401 ms
&lt;span class=&quot;m&quot;&gt;64&lt;/span&gt; bytes from 192.168.77.10: &lt;span class=&quot;nv&quot;&gt;icmp_seq&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;ttl&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;64&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0.675 ms
^C
--- 192.168.77.10 ping statistics ---
&lt;span class=&quot;m&quot;&gt;2&lt;/span&gt; packets transmitted, &lt;span class=&quot;m&quot;&gt;2&lt;/span&gt; received, 0% packet loss, &lt;span class=&quot;nb&quot;&gt;time &lt;/span&gt;999ms
rtt min/avg/max/mdev &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; 0.401/0.538/0.675/0.137 ms
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&quot;fazit&quot;&gt;Fazit&lt;/h2&gt;

&lt;p&gt;Das automatische Verlinken von Docker-Containern ist im Docker-Daemon
aktuell nur auf demselben Host möglich. Das Verbinden von Containern über Hostgrenzen
hinweg ist zur Zeit noch etwas manueller Aufwand. Wir dürfen gespannt sein, wann das Docker-Team bzw. 
die Community auch hier eine Lösung anbieten werden.&lt;/p&gt;

&lt;p&gt;Wer das obige Setup automatisiert aufsetzen möchte, findet in meinem
&lt;a href=&quot;http://github.com/aschmidt75/docker-network-playground/wiki&quot;&gt;Network Playground&lt;/a&gt; mit dem
&lt;strong&gt;Simple-Setup&lt;/strong&gt; eine vorbereitete Lösung zum Ausprobieren.&lt;/p&gt;

&lt;p&gt;Im Prinzip ist man mit Pipework in der Lage, komplexere Netzwerkarchitekturen
aufzubauen. Einen weiteren Schritt in Richtung Netzwerkvirtualisierung und
&lt;a href=&quot;http://www.sflow.org/&quot;&gt;Software-Defined Network&lt;/a&gt; stellt Open vSwitch dar. Das werden wir im nächsten Post weiter beleuchten.&lt;/p&gt;

&lt;h2 id=&quot;&quot;&gt;&lt;/h2&gt;

&lt;p&gt;Andreas&lt;/p&gt;
</description>
                <link>/blog/2014/07/11/docker-entschlusselt-netzwerk-teil-2</link>
                <guid>/blog/2014/07/11/docker-entschlusselt-netzwerk-teil-2</guid>
                <pubDate>2014-07-11T00:00:00+02:00</pubDate>
        </item>

        <item>
                <title>Docker entschlüsselt: Netzwerk</title>
                <description>&lt;p&gt;Wenn man mit Docker experimentiert, kann man außerordentlich schnelle Erfolge erzielen.
Der Docker-Daemon sorgt im Hintergrund dafür, dass viele notwendige Dinge wie Dateisysteme
und Netzwerk einfach geregelt sind. So wundert man sich auch nicht, dass ein neu gebauter
Container Netzwerkzugriff ins Internet hat, um z.B. Pakete zu installieren.&lt;/p&gt;

&lt;p&gt;Aber wie funktioniert das eigentlich genau? In diesem Post möchten wir das Thema Netzwerk mit Docker ein wenig beleuchten.&lt;/p&gt;

&lt;p&gt;Die Beispiele gehen von einem Ubuntu 14.04 LTS mit installiertem und lauffähigem Docker aus. Der
&lt;a href=&quot;/blog/2014/06/30/docker-mit-boot2docker-starten&quot;&gt;boot2docker Post&lt;/a&gt; erklärt, wie man mit Hilfe von boot2docker
schnell eine Docker-Spielwiese aufbauen kann. Da im &lt;a href=&quot;http://distro.ibiblio.org/tinycorelinux/&quot;&gt;Tiny Linux&lt;/a&gt; zur Zeit das
Tooling für das Netzwerk fehlt, haben wir uns entschlossen lieber direkt eine eigene Linux Installation mit Vagrant und
Virtualbox aufzusetzen. Unser Projekt &lt;a href=&quot;https://github.com/rossbachp/dockerbox&quot;&gt;dockerbox&lt;/a&gt; erfüllt diesen Zweck.&lt;/p&gt;

&lt;h2 id=&quot;das-netzwerk-im-docker-container&quot;&gt;Das Netzwerk im Docker-Container&lt;/h2&gt;

&lt;p&gt;Wenn man einen einfachen Container mit einer Shell als Prozess startet, kann man im Container
und auf dem Host nachschauen, was sich netzwerktechnisch dort abspielt:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;~# docker run -t -i ubuntu /bin/bash
root@4de56414033f:/# ip addr show
1: lo: &amp;lt;LOOPBACK,UP,LOWER_UP&amp;gt; mtu &lt;span class=&quot;m&quot;&gt;1500&lt;/span&gt; qdisc noqueue state UNKNOWN group default
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
37: eth0: &amp;lt;BROADCAST,UP,LOWER_UP&amp;gt; mtu &lt;span class=&quot;m&quot;&gt;1500&lt;/span&gt; qdisc pfifo_fast state UP group default qlen 1000
    link/ether e2:47:24:55:de:d4 brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.2/16 scope global eth0
       valid_lft forever preferred_lft forever
    inet6 fe80::e047:24ff:fe55:ded4/64 scope link
       valid_lft forever preferred_lft forever
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;D.h. es gibt ein &lt;code&gt;Loopback&lt;/code&gt;-Interface und ein &lt;code&gt;eth0&lt;/code&gt;-Netzwerkinterface im Docker Container.
Das &lt;code&gt;eth0&lt;/code&gt;-Interface hat auch bereits eine IP-Adresse aus der Default-Range &lt;code&gt;172.17.0.0/16&lt;/code&gt;,
nämlich die &lt;code&gt;.2&lt;/code&gt;. Damit der Container &amp;quot;nach draußen&amp;quot; sprechen kann, benötigt er eine
Route aus seiner Umgebung heraus über den Host ins Internet. Mit dem Befehl &lt;code&gt;ip&lt;/code&gt; kann man
sich Routen auch im Container anzeigen lassen. Man sieht, dass es eine entsprechende
Default-Route mit der IP &lt;code&gt;172.17.42.1&lt;/code&gt; angelegt ist:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;root@4de56414033f:/# ip ro show
default via 172.17.42.1 dev eth0
172.17.0.0/16 dev eth0  proto kernel  scope link  src 172.17.0.2

root@4de56414033f:/# ping www.infrabricks.de
PING github.map.fastly.net &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;185.31.17.133&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; 56&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;84&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; bytes of data.
&lt;span class=&quot;m&quot;&gt;64&lt;/span&gt; bytes from github.map.fastly.net &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;185.31.17.133&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;: &lt;span class=&quot;nv&quot;&gt;icmp_seq&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;ttl&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;61&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;46.2 ms
&lt;span class=&quot;m&quot;&gt;64&lt;/span&gt; bytes from github.map.fastly.net &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;185.31.17.133&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;: &lt;span class=&quot;nv&quot;&gt;icmp_seq&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;ttl&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;61&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;46.8 ms
&lt;span class=&quot;m&quot;&gt;64&lt;/span&gt; bytes from github.map.fastly.net &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;185.31.17.133&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;: &lt;span class=&quot;nv&quot;&gt;icmp_seq&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;3&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;ttl&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;61&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;44.5 ms
^C
--- github.map.fastly.net ping statistics ---
&lt;span class=&quot;m&quot;&gt;3&lt;/span&gt; packets transmitted, &lt;span class=&quot;m&quot;&gt;3&lt;/span&gt; received, 0% packet loss, &lt;span class=&quot;nb&quot;&gt;time &lt;/span&gt;2003ms
rtt min/avg/max/mdev &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; 44.555/45.891/46.823/0.968 ms
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&quot;was-ist-eigentlich-die-bridge-docker0?-...&quot;&gt;Was ist eigentlich die Bridge &lt;code&gt;docker0&lt;/code&gt;? ...&lt;/h2&gt;

&lt;p&gt;Auf dem Host kümmert sich der Docker-Daemon um die Netzwerk-Magic. Bei Installation wird eine Linux Network Bridge &lt;code&gt;docker0&lt;/code&gt; angelegt.
Eine Bridge erscheint erstmal wie ein eigenes Netzwerkinterfaces, im Fall von
&lt;code&gt;docker0&lt;/code&gt; besitzt diese Bridge sogar eine eigene IP-Adresse. Man kann sich
eine Bridge vorstellen wie das virtuelle Äquivalent eines Hardware-Switches, aber
ohne eigene Logik (die ein Switch hätte). Andere Netzwerkinterfaces können an
eine Bridge angeschlossen werden, und der Kernel (das Modul bridge) leitet
Pakete, die auf beliebigen Interfaces ankommen an alle angeschlossenen Interfaces weiter.&lt;/p&gt;

&lt;p&gt;Mit dem &lt;code&gt;ip&lt;/code&gt;-Kommando kann man die Bridge als Interface (mit ihrer IP) sehen:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;~# sudo ip addr show docker0
4: docker0: &amp;lt;BROADCAST,MULTICAST,UP,LOWER_UP&amp;gt; mtu &lt;span class=&quot;m&quot;&gt;1500&lt;/span&gt; qdisc noqueue state UP group default
    link/ether 16:69:e4:75:45:86 brd ff:ff:ff:ff:ff:ff
    inet 172.17.42.1/16 scope global docker0
       valid_lft forever preferred_lft forever
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Das Tool &lt;code&gt;brctl&lt;/code&gt; zeigt die Interfaces an, die an die Bridge angeschlossen sind.
Es stammt aus dem Paket &lt;code&gt;bridge-utils&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;~# sudo brctl show
bridge name bridge id       STP enabled interfaces
docker0     8000.1669e4754586   no      vethc3cd
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;In der letzten, rechten Spalte werden die an die Bridge angeschlossenen Interfaces angezeigt.
Das sieht zugegebermaßen etwas seltsam aus, ein &lt;code&gt;veth&lt;/code&gt;-Interface. Man kann sich die Details anzeigen lassen:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;~# sudo ip addr show vethc3cd
38: vethc3cd: &amp;lt;BROADCAST,UP,LOWER_UP&amp;gt; mtu &lt;span class=&quot;m&quot;&gt;1500&lt;/span&gt; qdisc pfifo_fast master docker0 state UP group default qlen 1000
    link/ether 76:c0:d8:ea:50:4d brd ff:ff:ff:ff:ff:ff
    inet6 fe80::74c0:d8ff:feea:504d/64 scope link
       valid_lft forever preferred_lft forever
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Es handelt sich quasi um ein virtuelles Kabel, das an der Bridge hängt (in der
ersten Ausgabezeile zu sehen, &lt;code&gt;master docker0&lt;/code&gt;). Dieses Interface ist damit 
die Gegenstelle des &lt;code&gt;eth0&lt;/code&gt;-Interface im Containers.
Das lässt sich auch mit Linux-Bordmitteln herausfinden, wir bemühen die Statistik-Funktion
von &lt;code&gt;ethtool&lt;/code&gt; und finden heraus:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;~# sudo ethtool -S vethc3cd
NIC statistics:
     peer_ifindex: 37
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;ethtool&lt;/code&gt; zeigt an, dass der Index des Peers zu &lt;code&gt;vethc3cd&lt;/code&gt; den Identifier &lt;code&gt;37&lt;/code&gt; trägt. Und das
ist genau die ID, die im Container selber beim &lt;code&gt;eth0&lt;/code&gt; angezeigt wird (s.o.). D.h. es ergibt sich folgendes Bild:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/docker_network_basics1.png&quot; alt=&quot;docker_network_basics1&quot;&gt;&lt;/p&gt;

&lt;p&gt;Das veth-Interface auf dem Host und das eth-Interface im Container sind wie die beiden
Seiten derselben (Netzwerk-)Medaille. Alles was der eine transportiert, sieht der andere
auch, nur in verschiedenen Container- bzw. Namespace-Ebenen. So trennt Docker
das äußere Host-Interface vom inneren Container-Interface.&lt;/p&gt;

&lt;h2 id=&quot;anschluss-in-die-welt-da-draußen&quot;&gt;Anschluss in die Welt da draußen&lt;/h2&gt;

&lt;p&gt;Mit dem Kommando &lt;code&gt;brctl&lt;/code&gt; kann man sehen, dass nur ein Interface auf der Bridge angeschlossen ist,
nämlich das &lt;code&gt;veth...&lt;/code&gt;-Interface. Allerdings ist das Netzwerk-Interface des Hosts (im Diagramm das obere &lt;code&gt;eth0&lt;/code&gt;)
nicht an der Bridge angeklemmt. Das wäre auch möglich, braucht aber einige weitere Voraussetzungen
und Umbauarbeiten, die z.B. &lt;a href=&quot;http://jpetazzo.github.io/2013/10/16/configure-docker-bridge-network/&quot;&gt;im Blog von @jpetazzo&lt;/a&gt;
beschrieben sind.&lt;/p&gt;

&lt;p&gt;Wie also kann der Container Pakete ins Internet schicken und die Antworten erhalten? Der Docker-Daemon
baut dafür auf dem Host einen Automatismus mit Hilfe von &lt;code&gt;iptables&lt;/code&gt; auf. In der Prerouting- und
Routing-Chain wird klar, dass ein Paket nach außen geroutet werden soll.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;~# sudo /sbin/iptables -L -n -t nat
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;....&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;

Chain POSTROUTING &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;policy ACCEPT&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
target     prot opt &lt;span class=&quot;nb&quot;&gt;source               &lt;/span&gt;destination
MASQUERADE  all  --  172.17.0.0/16       !172.17.0.0/16
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;In der Postrouting-Chain gibt es einen Masquerade-Eintrag. Dabei setzt der Host Paketen, die für die Außenwelt bestimmt sind, die eigene IP des ausgehenden Interfaces ein, sodass die Antworten später auch zurückgeroutet werden können.&lt;/p&gt;

&lt;p&gt;Mit dem Aufruf eines traceroute-Tools (hier &lt;code&gt;mtr-tiny&lt;/code&gt;, kann auch ein anderes Tool sein) im Docker-Container sieht man,
dass alle Netzpakete automatisch über die IP des
Hosts geroutet werden, die an der &lt;code&gt;docker0&lt;/code&gt;-Bridge hängt (172.17.42.1). Da die Bridge nicht am &lt;code&gt;eth0&lt;/code&gt; des Host hängt,
gibt es keine direkten Weg nach draußen. Aber das IP-Masquerade und das Routing auf dem Host sorgen dafür, dass der
nächste (2.) Hop die &lt;code&gt;eth0&lt;/code&gt; auf dem Host ist (10.0.2.2). Danach geht es weiter über die Netzinfrastruktur, an der
der Host hängt.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;root@4de56414033f:/# apt-get install mtr-tiny
root@4de56414033f:/# mtr www.infrabricks.de
                                     My traceroute  &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;v0.85&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
2ad667affd45 &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;0.0.0.0&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;                                                 Thu Jul  &lt;span class=&quot;m&quot;&gt;3&lt;/span&gt; 16:37:37 2014
Keys:  Help   Display mode   Restart statistics   Order of fields   quit
                                                       Packets               Pings
 Host                                                Loss%   Snt   Last   Avg  Best  Wrst StDev
 1. 172.17.42.1                                       0.0%     &lt;span class=&quot;m&quot;&gt;6&lt;/span&gt;    0.1   0.1   0.1   0.3   0.0
 2. 10.0.2.2                                          0.0%     &lt;span class=&quot;m&quot;&gt;6&lt;/span&gt;    0.4   0.5   0.4   0.9   0.0
 3. ???
 ...
11. ???
12. github.map.fastly.net                             0.0%     &lt;span class=&quot;m&quot;&gt;5&lt;/span&gt;   44.1  44.1  43.9  44.4   0.0
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&quot;kommunikation-zwischen-den-docker-containern-auf-dem-selben-host&quot;&gt;Kommunikation zwischen den Docker-Containern auf dem selben Host&lt;/h2&gt;

&lt;p&gt;Da alle Docker-Container auf derselben Bridge &lt;code&gt;docker0&lt;/code&gt; lokalisiert sind, können sie darauf uneingeschränkt untereinander kommunizieren.
Das Prinzip wurde in der LINK-Funktionalität vom Docker-Daemon weiter ausgebaut.&lt;/p&gt;

&lt;p&gt;Ein zweiter Container erhält eine neue IP und ist der in der Lage, den ersten zu erreichen:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;~# docker run -t -i ubuntu /bin/bash
root@2e2d98cf5c43:/# ip addr show eth0
39: eth0: &amp;lt;BROADCAST,UP,LOWER_UP&amp;gt; mtu &lt;span class=&quot;m&quot;&gt;1500&lt;/span&gt; qdisc pfifo_fast state UP group default qlen 1000
    link/ether 16:47:b2:34:b1:87 brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.5/16 scope global eth0
       valid_lft forever preferred_lft forever
    inet6 fe80::1447:b2ff:fe34:b187/64 scope link
       valid_lft forever preferred_lft forever
       root@2e2d98cf5c43:/# ping 172.17.0.2
PING 172.17.0.2 &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;172.17.0.2&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; 56&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;84&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; bytes of data.
&lt;span class=&quot;m&quot;&gt;64&lt;/span&gt; bytes from 172.17.0.2: &lt;span class=&quot;nv&quot;&gt;icmp_seq&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;ttl&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;64&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0.099 ms
&lt;span class=&quot;m&quot;&gt;64&lt;/span&gt; bytes from 172.17.0.2: &lt;span class=&quot;nv&quot;&gt;icmp_seq&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;ttl&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;64&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0.091 ms
&lt;span class=&quot;m&quot;&gt;64&lt;/span&gt; bytes from 172.17.0.2: &lt;span class=&quot;nv&quot;&gt;icmp_seq&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;3&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;ttl&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;64&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0.080 ms
^C
--- 172.17.0.2 ping statistics ---
&lt;span class=&quot;m&quot;&gt;3&lt;/span&gt; packets transmitted, &lt;span class=&quot;m&quot;&gt;3&lt;/span&gt; received, 0% packet loss, &lt;span class=&quot;nb&quot;&gt;time &lt;/span&gt;2001ms
rtt min/avg/max/mdev &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; 0.080/0.090/0.099/0.007 ms
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Das funktioniert, weil der Docker-Daemon in Default-Verhalten keine iptables-Sperren auf der Bridge
einrichtet, d.h. alle Container können untereinander und mit dem Host auf allen offenen Ports kommunizieren.&lt;/p&gt;

&lt;p&gt;Falls man das aus Sicherheitsgründen nicht möchte, kann man dieses &lt;a href=&quot;https://docs.docker.com/articles/networking/#between-containers&quot;&gt;Verhalten ändern&lt;/a&gt;. Dabei sorgt eine andere Default-Policy im iptables dafür, das Pakete verworfen werden, außer es wird explizit erlaubt.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/docker_network_basics_host.png&quot; alt=&quot;docker_network_basics_host&quot;&gt;&lt;/p&gt;

&lt;h2 id=&quot;docker-container-für-die-aussenwelt-erreichbar-machen&quot;&gt;Docker-Container für die Aussenwelt erreichbar machen&lt;/h2&gt;

&lt;p&gt;Die &lt;a href=&quot;https://docs.docker.com/userguide/dockerlinks/&quot;&gt;Link-Funktionalität&lt;/a&gt; von Docker macht das einfach
sehr einfach zugänglich, da man Container anhand ihres Namens und einer Port-Nummer untereinander verknüpfen kann:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/docker_network_basics2_link.png&quot; alt=&quot;docker_network_basics2_link&quot;&gt;&lt;/p&gt;

&lt;p&gt;Im Dockerfile hat man mit EXPOSE die Möglichkeit, einen lokalen Port des Containers auf dem Host weiterzuleiten, sodass er auch von außen erreichbar ist. Da die &lt;code&gt;docker0&lt;/code&gt;-Bridge aber nicht mit dem Host-Interface verbunden ist gibt es auch hierbei einen iptables-Mechanismus.&lt;/p&gt;

&lt;p&gt;Alternativ kann man im &lt;code&gt;docker run&lt;/code&gt;-Befehl direkt eine Weiterleitung einrichten. Das Beispiel zeigt, wie ein Container mit einer Weiterleitung gestartet wird, ein Netcat-Listen Prozess hört auf dem &lt;em&gt;inneren&lt;/em&gt; Container-Port 80.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;~# docker run -t -i -p 80:8000 ubuntu /bin/bash
root@e5d717bdfc32:/# nc -l 0.0.0.0 80
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Falls &lt;code&gt;nc&lt;/code&gt; nicht installiert ist, hilft ein &lt;code&gt;apt-get install netcat&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Auf dem Host kann man sich die Weiterleitung von Docker anzeigen lassen (&lt;code&gt;docker port&lt;/code&gt;).
Über &lt;code&gt;netstat&lt;/code&gt; sieht man, dass der Docker-Daemon auf dem weitergeleiteten Port hört:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;~# docker port 28096eac487b 80
0.0.0.0:8000
~# netstat -nltp
Active Internet connections &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;only servers&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;...&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
tcp6       &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;      &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt; :::8000                 :::*                    LISTEN      6062/docker.io
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Und auf dem Host wurde eine iptables Forward-Regel eingerichtet, damit der Traffic, der vom Host-Interface ankommt,
über die Bridge an den Container gerichtet werden kann:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;~# sudo /sbin/iptables -L -n
Chain INPUT &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;policy ACCEPT&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
target     prot opt &lt;span class=&quot;nb&quot;&gt;source               &lt;/span&gt;destination

Chain FORWARD &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;policy ACCEPT&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
target     prot opt &lt;span class=&quot;nb&quot;&gt;source               &lt;/span&gt;destination
ACCEPT     tcp  --  0.0.0.0/0            172.17.0.2           tcp dpt:80
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&quot;im-detail-...&quot;&gt;Im Detail ...&lt;/h2&gt;

&lt;p&gt;Der Docker-Daemon sorgt hinter den Kulissen dafür, dass alle &lt;em&gt;drehenden&lt;/em&gt; Teile auch
richtig zusammenarbeiten. Bei der normalen Arbeit mit Docker muss man sich darum selten
kümmern. Mit Docker ist man aber auch in der Lage, komplexere Netzwerk-Setups zu simulieren
und damit eine Docker-Umgebung produktionsreif aufzubauen.&lt;/p&gt;

&lt;p&gt;Wer das ganze im Detail nachlesen möchte, ist auf der Docker.io Dokumentation-Seite
zu &lt;a href=&quot;https://docs.docker.com/articles/networking/&quot;&gt;Advanced Networking&lt;/a&gt; gut aufgehoben.&lt;/p&gt;

&lt;p&gt;Im nächsten Schritt werden wir Container über Hostgrenzen hinweg verbinden und damit die Grundlage
für ein skalierfähige und ausfallsichere Umgebungen zu schaffen. Jede Menge Posts erscheinen nun
zum Thema Docker bzw. Linux Networking. Lukas Pustina zeigte in seinem
&lt;a href=&quot;https://blog.codecentric.de/2014/01/leichtgewichtige-virtuelle-maschinen-mit-docker-oder-wie-man-100-vms-laufen/&quot;&gt;Post&lt;/a&gt; wie
einfach es ist, hundert Docker Container auf einem Host zu starten. Jason Edelman schreibt
regelmässig über das Thema Networking und sein Artikel über Docker
mit &lt;a href=&quot;http://www.jedelman.com/home/open-vswitch-201-301&quot;&gt;Open vSwitch&lt;/a&gt; zu verbinden, gibt viele Anregungen.&lt;/p&gt;

&lt;p&gt;Das Thema &lt;em&gt;Software Defined Networks&lt;/em&gt; ist komplex, aber nun gibt es endlich eine interessante
praktische Verwendung für jeden von uns Docker-Interessierten.&lt;/p&gt;

&lt;h2 id=&quot;&quot;&gt;&lt;/h2&gt;

&lt;p&gt;Andreas &amp;amp; Peter&lt;/p&gt;
</description>
                <link>/blog/2014/07/06/docker-entschlusselt-netzwerk</link>
                <guid>/blog/2014/07/06/docker-entschlusselt-netzwerk</guid>
                <pubDate>2014-07-06T00:00:00+02:00</pubDate>
        </item>

        <item>
                <title>Docker mit boot2docker starten</title>
                <description>&lt;p&gt;Das Projekt Docker schlägt seit den ersten Lebenszeichen Mitte letzten Jahres zunehmend höhere Begeisterungswellen. Docker verspricht einen schnellen Start in die Welt der DevOps, flexiblen Konfiguration und stabilen Images. All dies sind für uns sehr wichtige Voraussetzungen, um Infrastruktur testbar zu machen. Grund genug für uns, das ganze unter die Lupe zu nehmen und Euch einfache Anleitungen zum Ausprobieren an die Hand zu geben. Wie kann man am einfachsten mit Docker  auf dem eigene Rechner durchstarten?&lt;/p&gt;

&lt;h2 id=&quot;erste-schritte-mit-docker&quot;&gt;Erste Schritte mit Docker&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;http://docker.io&quot;&gt;Docker&lt;/a&gt; ermöglicht es, die eigenen Prozesse in leichtgewichtige &lt;a href=&quot;https://linuxcontainers.org/&quot;&gt;Linux Container&lt;/a&gt; einzupacken. Am besten kann man die Wirkung als eine fettreduzierte Virtualisierung beschreiben. Wer Docker direkt probieren möchte, kann das &lt;a href=&quot;http://www.docker.com/tryit/&quot;&gt;Online Tutorial&lt;/a&gt; nutzen. Eine eigene Installation ist für einen echten Docker-Einsatz allerdings unerlässlich. Damit dies auf dem eigenen Rechner zuverlässig gelingt, empfiehlt sich die lokale Installation mit dem Projekt &lt;a href=&quot;http://boot2docker.io&quot;&gt;boot2docker&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/boot2docker.png&quot; alt=&quot;boot2docker&quot;&gt;&lt;/p&gt;

&lt;p&gt;Mit der Hilfe von Boot2Docker wird auf dem eigene Windows oder Mac eine virtuelle Maschine mit einer Basis-Docker &lt;a href=&quot;http://tinycorelinux.net/&quot;&gt;Tiny Linux Installation&lt;/a&gt; installiert. Eine Voraussetzung ist die Installation einer aktuellen Version von VirtualBox. Weiterhin wird die Docker Client CLI und eine boot2docker Management CLI installiert. So läßt sich anschliessend sehr bequem sämtliche Administration ohne lästiges einloggen via ssh vom eigenen Rechner erledigen. Docker selbst benötigt Zugang zu dem &lt;a href=&quot;https://registry.hub.docker.com/&quot;&gt;Cloud Images Registry von Docker Inc&lt;/a&gt;. Von dort werden die Betriebsysteme und Container geladen. Aktuell befinden sich dort schon mehr als 15.000 vorgefertigte Container für die unterschiedlichsten Einsatzzwecke. Die Qualität ist unterschiedlich und vor dem Einsatz lohnt sich ein Blick in die Sourcen des Containers. Die Konfiguration eines Container befindet sich in der Datei &lt;code&gt;Dockerfile&lt;/code&gt;. Als Basis Images lohnt ein Blick auf die &lt;a href=&quot;https://registry.hub.docker.com/u/phusion/baseimage/&quot;&gt;Phusion Baseimage&lt;/a&gt; zu werfen.&lt;/p&gt;

&lt;p&gt;Die grössten Unterschiede zwischen Vagrant und Docker sind:&lt;/p&gt;

&lt;table&gt;&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Vagrant&lt;/th&gt;
&lt;th&gt; Docker&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;em&gt;Nutzung&lt;/em&gt;&lt;/td&gt;
&lt;td&gt;Entwicklung&lt;/td&gt;
&lt;td&gt; Entwicklung und Betrieb&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;em&gt;Speicherung&lt;/em&gt;&lt;/td&gt;
&lt;td&gt;Dauerhaft&lt;/td&gt;
&lt;td&gt; Flüchtig und braucht externe Volumes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;em&gt;Anzahl der Services&lt;/em&gt;&lt;/td&gt;
&lt;td&gt;viele&lt;/td&gt;
&lt;td&gt; meist einer&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;em&gt;Tools&lt;/em&gt;&lt;/td&gt;
&lt;td&gt;cli&lt;/td&gt;
&lt;td&gt; cli und REST Service&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;em&gt;Programmierung&lt;/em&gt;&lt;/td&gt;
&lt;td&gt; Ruby&lt;/td&gt;
&lt;td&gt; Bash &amp;amp; Go, Java, Ruby, JavaScript, Scala, ...&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;em&gt;Technik&lt;/em&gt;&lt;/td&gt;
&lt;td&gt; Virtualisierung&lt;/td&gt;
&lt;td&gt; LXC&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;

&lt;h2 id=&quot;installation-von-boot2docker&quot;&gt;Installation von boot2docker&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;http://boot2docker.io/&quot;&gt;Boot2docker&lt;/a&gt; hilft dabei, ein für Docker passendes Linux mit Virtualbox auf Windows oder OS X zu installieren. Mit der Version 1.0 liegt die Installation nun als fertiges Package vor. Als Voraussetzung muss &lt;a href=&quot;https://www.virtualbox.org/&quot;&gt;VirtualBox&lt;/a&gt; in der Version &lt;code&gt;&amp;gt;4.3.12&lt;/code&gt; installiert sein. Eine leistungsfähige Internet-Verbindung, die schnell den Transfer von mehr als 1GB Daten erlaubt, ist hier wirklich hilfreich. Eine Live-Demo mit unbekannten langsamen WiFi-Netzen oder Mobiles hat der Demo-Gott hier nicht vorgesehen. Denn zum Start müssen neben den Images für die Virtualisierung noch die Basis-Images für Docker geladen werden. Also ist genügend Zeit für ein bisschen Lesen im Netz oder eine Unterhaltung mit den Kollegen.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.docker.com/userguide/&quot;&gt;Docker User Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.docker.com/articles/basics/&quot;&gt;Docker Basics&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/boot2docker-install.png&quot; alt=&quot;boot2docker&quot;&gt;&lt;/p&gt;

&lt;p&gt;Neben der VM wird auf dem Host ein lokaler Docker-Client installiert, damit ohne  Login auf dem Linux alle Docker-Befehle genutzt werden können. Nach der Installation von boot2Docker kann geprüft werden, ob der Docker-Client auf dem Host verfügbar ist.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;docker version
Docker version 1.0.1, build 990021a
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Die eigene Docker-Testumgebung wird mit dem Befehl &lt;code&gt;boot2docker init&lt;/code&gt; erzeugt. Dabei wird eine neue virtuelle Maschine in der VirtualBox erstellt. Der Start der Umgebung erfolgt mit &lt;code&gt;boot2docker up&lt;/code&gt;. Wichtig ist, dass man nun den Docker-Client auf der eigenen Maschine auf der gestarteten VM mit einer Export-Anweisung konfiguriert. Die Anweisung befindet sich am Ende der Ausgabe des Kommandos. Nun kann die Fernsteuerung von Docker in der VM beginnen. Dies ist möglich, da Docker ein HTTP REST API besitzt und alle Steuerungen darüber erfolgen. Neben der Shell Client gibt es diverse Docker Integrationen für Ruby, Go, Php, Java, Scala oder Groovy.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;boot2docker up
2014/06/22 19:12:29 Waiting &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; VM to be started...
..^&lt;span class=&quot;o&quot;&gt;[[&lt;/span&gt;C.....
2014/06/22 19:12:50 Started.
2014/06/22 19:12:50 To connect the Docker client to the Docker daemon, please &lt;span class=&quot;nb&quot;&gt;set&lt;/span&gt;:
2014/06/22 19:12:50     &lt;span class=&quot;nb&quot;&gt;export &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;DOCKER_HOST&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;tcp://192.168.59.103:2375

&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;export &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;DOCKER_HOST&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;tcp://192.168.59.103:2375
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Nun stehen alle Docker Kommandos auf dem eigenen Mac- oder Windows-Rechner zur Verfügung. Ohne Problem lässt sich nun über das Docker REST API die gesamte Docker-Installation fernsteuern.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;docker images
REPOSITORY           TAG                   IMAGE ID            CREATED             VIRTUAL SIZE
busybox              buildroot-2013.08.1   d200959a3e91        &lt;span class=&quot;m&quot;&gt;2&lt;/span&gt; weeks ago         2.489 MB
busybox              ubuntu-14.04          37fca75d01ff        &lt;span class=&quot;m&quot;&gt;2&lt;/span&gt; weeks ago         5.609 MB
busybox              ubuntu-12.04          fd5373b3d938        &lt;span class=&quot;m&quot;&gt;2&lt;/span&gt; weeks ago         5.455 MB
busybox              buildroot-2014.02     a9eb17255234        &lt;span class=&quot;m&quot;&gt;2&lt;/span&gt; weeks ago         2.433 MB
busybox              latest                a9eb17255234        &lt;span class=&quot;m&quot;&gt;2&lt;/span&gt; weeks ago         2.433 MB
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Folgende &lt;code&gt;docker&lt;/code&gt;-Kommandos können nun ausgeführen werden:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;docker
Usage: docker &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;OPTIONS&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; COMMAND &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;arg...&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
 -H&lt;span class=&quot;o&quot;&gt;=[&lt;/span&gt;unix:///var/run/docker.sock&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;: tcp://host:port to &lt;span class=&quot;nb&quot;&gt;bind&lt;/span&gt;/connect to or unix://path/to/socket to use

A self-sufficient runtime &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; linux containers.

Commands:
    attach    Attach to a running container
    build     Build an image from a Dockerfile
    commit    Create a new image from a container&lt;span class=&quot;s1&quot;&gt;&amp;#39;s changes&lt;/span&gt;
&lt;span class=&quot;s1&quot;&gt;    cp        Copy files/folders from the containers filesystem to the host path&lt;/span&gt;
&lt;span class=&quot;s1&quot;&gt;    diff      Inspect changes on a container&amp;#39;&lt;/span&gt;s filesystem
    events    Get real &lt;span class=&quot;nb&quot;&gt;time &lt;/span&gt;events from the server
    &lt;span class=&quot;nb&quot;&gt;export    &lt;/span&gt;Stream the contents of a container as a tar archive
    &lt;span class=&quot;nb&quot;&gt;history   &lt;/span&gt;Show the &lt;span class=&quot;nb&quot;&gt;history &lt;/span&gt;of an image
    images    List images
    import    Create a new filesystem image from the contents of a tarball
    info      Display system-wide information
    inspect   Return low-level information on a container
    &lt;span class=&quot;nb&quot;&gt;kill      &lt;/span&gt;Kill a running container
    load      Load an image from a tar archive
    login     Register or Login to the docker registry server
    logs      Fetch the logs of a container
    port      Lookup the public-facing port which is NAT-ed to PRIVATE_PORT
    pause     Pause all processes within a container
    ps        List containers
    pull      Pull an image or a repository from the docker registry server
    push      Push an image or a repository to the docker registry server
    restart   Restart a running container
    rm        Remove one or more containers
    rmi       Remove one or more images
    run       Run a &lt;span class=&quot;nb&quot;&gt;command &lt;/span&gt;in a new container
    save      Save an image to a tar archive
    search    Search &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; an image in the docker index
    start     Start a stopped container
    stop      Stop a running container
    tag       Tag an image into a repository
    top       Lookup the running processes of a container
    unpause   Unpause a paused container
    version   Show the docker version information
    &lt;span class=&quot;nb&quot;&gt;wait      &lt;/span&gt;Block &lt;span class=&quot;k&quot;&gt;until&lt;/span&gt; a container stops, &lt;span class=&quot;k&quot;&gt;then&lt;/span&gt; print its &lt;span class=&quot;nb&quot;&gt;exit &lt;/span&gt;code
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Mit dem Befehl &lt;code&gt;boot2docker ssh&lt;/code&gt; ist die Einwahl auf die VM möglich.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;boot2docker ssh
Warning: Permanently added &lt;span class=&quot;s1&quot;&gt;&amp;#39;[localhost]:2022&amp;#39;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;RSA&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; to the list of known hosts.
                        &lt;span class=&quot;c&quot;&gt;##        .&lt;/span&gt;
                  &lt;span class=&quot;c&quot;&gt;## ## ##       ==&lt;/span&gt;
               &lt;span class=&quot;c&quot;&gt;## ## ## ##      ===&lt;/span&gt;
           /&lt;span class=&quot;s2&quot;&gt;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\_&lt;/span&gt;__/ &lt;span class=&quot;o&quot;&gt;===&lt;/span&gt;
      ~~~ &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;~~ ~~~~ ~~~ ~~~~ ~~ ~ /  &lt;span class=&quot;o&quot;&gt;===&lt;/span&gt;- ~~~
           &lt;span class=&quot;se&quot;&gt;\_&lt;/span&gt;_____ o          __/
             &lt;span class=&quot;se&quot;&gt;\ &lt;/span&gt;   &lt;span class=&quot;se&quot;&gt;\ &lt;/span&gt;       __/
              &lt;span class=&quot;se&quot;&gt;\_&lt;/span&gt;___&lt;span class=&quot;se&quot;&gt;\_&lt;/span&gt;_____/
 _                 _   ____     _            _
&lt;span class=&quot;p&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;|&lt;/span&gt;__   ___   ___ &lt;span class=&quot;p&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;|&lt;/span&gt;_&lt;span class=&quot;p&quot;&gt;|&lt;/span&gt;___ &lt;span class=&quot;se&quot;&gt;\ &lt;/span&gt;__&lt;span class=&quot;p&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;|&lt;/span&gt; ___   ___&lt;span class=&quot;p&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;|&lt;/span&gt; _____ _ __
&lt;span class=&quot;p&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;_ \ / _ \ / _ \| __| __) / _` |/ _ \ / __| |/ / _ \ &amp;#39;&lt;/span&gt;__&lt;span class=&quot;p&quot;&gt;|&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;|&lt;/span&gt;_&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;_&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;_&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;|&lt;/span&gt;_ / __/ &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;_&lt;span class=&quot;p&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;_&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;__&lt;span class=&quot;p&quot;&gt;|&lt;/span&gt;   &amp;lt;  __/ &lt;span class=&quot;p&quot;&gt;|&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;|&lt;/span&gt;_.__/ &lt;span class=&quot;se&quot;&gt;\_&lt;/span&gt;__/ &lt;span class=&quot;se&quot;&gt;\_&lt;/span&gt;__/ &lt;span class=&quot;se&quot;&gt;\_&lt;/span&gt;_&lt;span class=&quot;p&quot;&gt;|&lt;/span&gt;_____&lt;span class=&quot;se&quot;&gt;\_&lt;/span&gt;_,_&lt;span class=&quot;p&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\_&lt;/span&gt;__/ &lt;span class=&quot;se&quot;&gt;\_&lt;/span&gt;__&lt;span class=&quot;p&quot;&gt;|&lt;/span&gt;_&lt;span class=&quot;p&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\_\_&lt;/span&gt;__&lt;span class=&quot;p&quot;&gt;|&lt;/span&gt;_&lt;span class=&quot;p&quot;&gt;|&lt;/span&gt;
boot2docker: 1.0.0
             master : 16013ee - Mon Jun  &lt;span class=&quot;m&quot;&gt;9&lt;/span&gt; 16:33:25 UTC 2014
docker@boot2docker:~&lt;span class=&quot;err&quot;&gt;$&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Nun ist eine direkte Interaktion mit allen Containern und Prozessen auf der Linux VM möglich. Weitere Linux Packages für Monitoring, Logging und andere Services können genutzt werden. Natürlich kann nun das Netzwerk für die Kooperation mit anderen Maschinen und Services erweitert werden. Eine Freigabe von Docker Container Ports auf dem Mac lässt sich mit dem Script &lt;a href=&quot;https://gist.github.com/deinspanjer/9215467&quot;&gt;boot2docker-fwd&lt;/a&gt; erledigen.&lt;/p&gt;

&lt;p&gt;In der Liste der boot2docker Befehle finden sich die üblichen Verdächtigen zum Management der VM:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;boot2docker --help
Usage: boot2docker &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&amp;lt;options&amp;gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &amp;lt;&lt;span class=&quot;nb&quot;&gt;command&lt;/span&gt;&amp;gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&amp;lt;args&amp;gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;

boot2docker management utility.

Commands:
    init                    Create a new boot2docker VM.
    up&lt;span class=&quot;p&quot;&gt;|&lt;/span&gt;start&lt;span class=&quot;p&quot;&gt;|&lt;/span&gt;boot           Start VM from any states.
    ssh &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;ssh-command&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;       Login to VM via SSH.
    save&lt;span class=&quot;p&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;suspend            &lt;/span&gt;Suspend VM and save state to disk.
    down&lt;span class=&quot;p&quot;&gt;|&lt;/span&gt;stop&lt;span class=&quot;p&quot;&gt;|&lt;/span&gt;halt          Gracefully shutdown the VM.
    restart                 Gracefully reboot the VM.
    poweroff                Forcefully power off the VM &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;might corrupt disk image&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;.
    reset                   Forcefully power cycle the VM &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;might corrupt disk image&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;.
    delete                  Delete boot2docker VM and its disk image.
    config&lt;span class=&quot;p&quot;&gt;|&lt;/span&gt;cfg              Show selected profile file settings.
    info                    Display detailed information of VM.
    ip                      Display the IP address of the VM&lt;span class=&quot;err&quot;&gt;&amp;#39;&lt;/span&gt;s Host-only network.
    status                  Display current state of VM.
    download                Download boot2docker ISO image.
    version                 Display version information.
...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Die Basis von &lt;em&gt;boot2docker&lt;/em&gt; ist aktuell der Linux Kernel &lt;em&gt;3.14.1&lt;/em&gt; mit AUFS und Docker &lt;em&gt;1.0.1&lt;/em&gt;. Es besteht die Möglichkeit, ein eigenes Image für die VirtualBox zu erstellen.&lt;/p&gt;

&lt;h2 id=&quot;start-des-ersten-docker-containers&quot;&gt;Start des ersten Docker-Containers&lt;/h2&gt;

&lt;p&gt;In der VM oder auf der eigenen Maschine können nun Docker Container administriert, erzeugt, gestartet, gestoppt oder wieder gelöscht werden.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;docker run ubuntu uname -a
Unable to find image &lt;span class=&quot;s1&quot;&gt;&amp;#39;ubuntu&amp;#39;&lt;/span&gt; locally
Pulling repository ubuntu
e54ca5efa2e9: Download &lt;span class=&quot;nb&quot;&gt;complete&lt;/span&gt;
511136ea3c5a: Download &lt;span class=&quot;nb&quot;&gt;complete&lt;/span&gt;
d7ac5e4f1812: Download &lt;span class=&quot;nb&quot;&gt;complete&lt;/span&gt;
2f4b4d6a4a06: Download &lt;span class=&quot;nb&quot;&gt;complete&lt;/span&gt;
83ff768040a0: Download &lt;span class=&quot;nb&quot;&gt;complete&lt;/span&gt;
6c37f792ddac: Download &lt;span class=&quot;nb&quot;&gt;complete&lt;/span&gt;
Linux 321d285612ef 3.14.1-tinycore64 &lt;span class=&quot;c&quot;&gt;#1 SMP Mon Jun 9 16:21:23 UTC 2014 x86_64 x86_64 x86_64 GNU/Linux&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Das Erzeugen eines eigenen Images kann mit einem Dockerfile definiert werden.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;mkdir -p hello
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;hello
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;vi Dockerfile
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Dockerfile&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;FROM ubuntu

CMD [&amp;quot;echo&amp;quot;, &amp;quot;Hello&amp;quot;, &amp;quot; Docker&amp;quot;]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Mit dem Befehl &lt;code&gt;docker build&lt;/code&gt; wird nun in der VM ein Image produziert und kann mit &lt;code&gt;docker run&lt;/code&gt; gestartet werden.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;docker build -t boot/hello .
Sending build context to Docker daemon  2.56 kB
Sending build context to Docker daemon
Step &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt; : FROM ubuntu
 ---&amp;gt; e54ca5efa2e9
Step &lt;span class=&quot;m&quot;&gt;1&lt;/span&gt; : CMD &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;echo&amp;quot;&lt;/span&gt;, &lt;span class=&quot;s2&quot;&gt;&amp;quot;Hello&amp;quot;&lt;/span&gt;, &lt;span class=&quot;s2&quot;&gt;&amp;quot;Docker&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
 ---&amp;gt; Running in 8dedcb96f9c0
 ---&amp;gt; 891601c49719
Removing intermediate container 8dedcb96f9c0
Successfully built 891601c49719
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;docker run boot/hello
Hello Docker
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Nun ist die Basis für eigene Docker-Experimente gelegt. Die Integration in die eigenen Projekte, erweiterten Möglichkeiten für Tests oder ein vereinfachter Zugriff auf diverse Backends sind erste Kandidaten. Es gibt enorme Möglichkeiten und eine Suche im öffentlichen &lt;a href=&quot;https://registry.hub.docker.com/&quot;&gt;Image-Register&lt;/a&gt; lohnt sich.&lt;/p&gt;

&lt;p&gt;Wir starten nun eine kleine Serie, zur Entschlüsselung von Docker für DevOps. Damit wollen wir die Chancen und Risiken dieser wunderbaren neuen Technologie aufzeigen und diskutieren.&lt;/p&gt;

&lt;h2 id=&quot;&quot;&gt;&lt;/h2&gt;

&lt;p&gt;Peter&lt;/p&gt;
</description>
                <link>/blog/2014/06/30/docker-mit-boot2docker-starten</link>
                <guid>/blog/2014/06/30/docker-mit-boot2docker-starten</guid>
                <pubDate>2014-06-30T00:00:00+02:00</pubDate>
        </item>

        <item>
                <title>Security-Tests mit serverspec</title>
                <description>&lt;p&gt;Sichere Systeme zu bauen und zu betreiben ist eine kontinuierliche Herausforderung. Ein erster Ansatz ist,
Sicherheitsaspekte zu spezifizieren und testbar zu machen. Serverspec besitzt eine Reihe von nützlichen Eigenschaften, um dem Ziel näher zu kommen.&lt;/p&gt;

&lt;p&gt;Durch die deklarative rspec-Syntax ist es möglich, Infrastrukturspezifikationen zu verfassen, die sicherheitsrelevante
Aspekte, wie etwa Berechtigungen, beschreiben. Und das ganze wird natürlich auf Knopfdruck testbar.&lt;/p&gt;

&lt;h2 id=&quot;you-should_not-...&quot;&gt;You should_not ...&lt;/h2&gt;

&lt;p&gt;Eine praktische Eigenschaft ist dabei, Eigenschaften ausdrücken, die eben nicht vorliegen sollten. Dazu
bietet rspec das Schlüsselwort &lt;code&gt;should_not&lt;/code&gt; an, wie z.B. in&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;describe&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;file&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;/etc/ssh/sshd_config&amp;#39;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;its&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:content&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;should_not&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;contain&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;/PermitRootLogin Yes/&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Security-Tests beziehen sich natürlich nicht nur auf Eigenschaften von Dateien, sondern auf
viel mehr, beispielsweise:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Pakete: Manche Pakete sollten besser nicht installiert sein (Beispiel: &lt;code&gt;sendmail&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Dienste: Service sollten nicht laufen, und auch nicht enabled sein. Andere sollten auf jeden Fall laufen (z.B. iptables)&lt;/li&gt;
&lt;li&gt;Die Dateiberechtigungen betreffen vor allem World-Rechte und Ausführbarkeit. Die sollten stark eingeschränkt sein.&lt;/li&gt;
&lt;li&gt;Dateien sollten nur den Nutzer gehören, die sie zur Ausführung benötigen.&lt;/li&gt;
&lt;li&gt;Manche User sollten keine Shell haben.&lt;/li&gt;
&lt;li&gt;(NFS-)Mounts, die nur als Dateiablage dienen, sollten auch nicht ausführbar sein.&lt;/li&gt;
&lt;li&gt;Services die Ports öffnen, sollten dies nur auf bestimmten IPs tun.&lt;/li&gt;
&lt;li&gt;Konfigurationsdateien für Services wie bspw. Apache sollten sichere Einstellungen beinhalten, z.B. aktuelle SSL Cipher Suites&lt;/li&gt;
&lt;li&gt;Die Zertifikate und Schlüssel müssen die richtigen sein, z.B. auch mit hoher Schlüsselstärke&lt;/li&gt;
&lt;li&gt;... und vieles mehr.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Das lässt sich ganz gut mit &lt;a href=&quot;http://www.serverspec.org/&quot;&gt;serverspec&lt;/a&gt; beschreiben.&lt;/p&gt;

&lt;h2 id=&quot;pakete&quot;&gt;Pakete&lt;/h2&gt;

&lt;p&gt;Um auszudrücken, dass eine Menge an Paketen nicht installiert sein sollte, kann man z.B.
mit einem Iterator über eine Liste wandern und einen describe-Block aufbauen (Beispiel mit
Paketnamen für RedHat bzw. CentOS):&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;sx&quot;&gt;%W( bluetooth cups isdn tftp autofs )&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;each&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pkgname&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;describe&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pkgname&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;it&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;should_not&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;be_installed&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Ähnliches mit Services (sowohl Negativ- als auch Positiv-Beispiele):&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;sx&quot;&gt;%W( sendmail )&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;each&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;describe&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;service&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;s&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;it&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;should_not&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;be_enabled&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;it&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;should_not&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;be_running&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;sx&quot;&gt;%W( iptables )&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;each&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;describe&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;service&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;s&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;it&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;should&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;be_enabled&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;it&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;should&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;be_running&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&quot;nutzer-ohne-shell&quot;&gt;Nutzer ohne Shell&lt;/h2&gt;

&lt;p&gt;Hier lässt Linux mehrere Varianten zu, eine ist &lt;code&gt;/bin/nologin&lt;/code&gt;. Puppet erhält
beispielsweise einen eigenen Laufzeitnutzer, der sollte aber ebenfalls keine Shell
besitzen und wird besser mit &lt;code&gt;/bin/false&lt;/code&gt; eingerichtet.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;describe&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;user&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;apache&amp;#39;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;it&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;should&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;have_login_shell&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;/bin/nologin&amp;#39;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;describe&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;user&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;puppet&amp;#39;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;it&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;should&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;have_login_shell&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;/bin/false&amp;#39;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&quot;nfs-mounts&quot;&gt;NFS-Mounts&lt;/h2&gt;

&lt;p&gt;NFS-Mounts, die nur zur Ablage von Dateien verwendet werden, sollten 
mit dem &lt;code&gt;no-executable&lt;/code&gt;-Flag gemountet werden:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;describe&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;/&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;it&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;should&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;be_mounted&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;with&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;ss&quot;&gt;:options&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:noexec&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&quot;konfigurationsdateien-am-beispiel-apache&quot;&gt;Konfigurationsdateien am Beispiel Apache&lt;/h2&gt;

&lt;p&gt;Zur Absicherung einer Webserver-Konfiguration wie bspw. dem Apache gehören
mehrere Dinge. Wir möchten z.B. sicherstellen, dass SSL-relevante Parameter
vorhanden sind, dass die Zertifikats- und Schlüsseldateien existieren und die
richtigen sind (z.B. anhand des &lt;code&gt;CommonNames&lt;/code&gt;).
Letzteres können wir durch ein Serverspec &lt;code&gt;command&lt;/code&gt; erreichen, was openssl
ausführt um das Zertifikat auszulesen und anzuzeigen. Im Block selber verwenden
wir Matcher, um den Inhalt zu prüfen.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;  &lt;span class=&quot;n&quot;&gt;describe&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;file&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;/etc/ssl/mykey.crt&amp;quot;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;it&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;should&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;be_file&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;it&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;should&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;be_mode&lt;/span&gt;         &lt;span class=&quot;s1&quot;&gt;&amp;#39;644&amp;#39;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;it&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;should&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;be_owned_by&lt;/span&gt;     &lt;span class=&quot;s1&quot;&gt;&amp;#39;root&amp;#39;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;it&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;should&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;be_grouped_into&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;root&amp;#39;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;describe&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;command&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;openssl x509 -in /etc/ssl/mykey.cert -text&amp;#39;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;it&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;should&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;return_exit_status&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;its&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:stdout&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;should&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;match&lt;/span&gt; &lt;span class=&quot;sr&quot;&gt;/Subject:.*example.com/&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Und wir möchten gerne die Schlüsselstärke der SSL-Schlüssel verifizieren und
schauen, ob der Schlüssel selber valide ist:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;describe&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;command&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;openssl rsa -in /etc/ssl/mykey.key -check&amp;quot;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;its&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:stdout&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;should&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;match&lt;/span&gt; &lt;span class=&quot;sr&quot;&gt;/^RSA key ok$/&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;it&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;should&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;return_exit_status&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&quot;ssl-zertifikate-als-ressourcen-beschreiben&quot;&gt;SSL-Zertifikate als Ressourcen beschreiben&lt;/h2&gt;

&lt;p&gt;Nun ist der Aufruf von openssl und das &lt;strong&gt;heraus-greppen&lt;/strong&gt; der gewünschten Informationen
zwar möglich, aber leider etwas umständlich. Hier wünsche ich mir eher so etwas wie:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;describe&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sslcertificate&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;xyz.crt&amp;#39;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;its&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:subject&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;should&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;match&lt;/span&gt; &lt;span class=&quot;sr&quot;&gt;/.../&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;its&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:key_strength&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;should&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;be_at_least&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2048&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;its&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:validity&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;should&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;describe&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rsakey&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;xyz.key&amp;#39;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;it&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;should&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;be_valid&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;it&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;should&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;be_restricted_to&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;root&amp;#39;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Das funktioniert in serverspec nur mit einem eigenen Resource Type. In einem
der folgenden Posts machen wir uns an die Implementierung einer solchen Erweiterung von serverspec.&lt;/p&gt;

&lt;h2 id=&quot;&quot;&gt;&lt;/h2&gt;

&lt;p&gt;Andreas&lt;/p&gt;
</description>
                <link>/blog/2014/06/12/security-tests-mit-serverspec</link>
                <guid>/blog/2014/06/12/security-tests-mit-serverspec</guid>
                <pubDate>2014-06-12T00:00:00+02:00</pubDate>
        </item>

        <item>
                <title>Docker 1.0 steht bereit</title>
                <description>&lt;p&gt;Die freudige Neuigkeit für alle Entwickler und Administrator ist, dass nun &lt;a href=&quot;http://blog.docker.com/2014/06/its-here-docker-1-0/&quot;&gt;Docker 1.0&lt;/a&gt; bereitsteht. In nur 15 Monaten hat sich Docker von einer Idee zu einer gewaltigen neuen IT-Technologie Bewegung entwickelt. Im Rahmen der ersten DockerCon 2014 in San Fransisco können sich die sicherlich überglücklichen Teilnehmer und wir darauf freuen, nun ohne Beta-Einschränkungen in die Produktion zu gehen.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/docker-white.png&quot; alt=&quot;Docker logo&quot;&gt; &lt;/p&gt;

&lt;p&gt;Die großen Internet Firmen wie eBay, Yelp, Spotify und Baidu nutzen Docker schon eine Weile sehr erfolgreich. Alle Projekte berichten über außerordentliche Erfolge ihrer Komponenten mit Docker, die zuverlässiger, schneller und effektiver zu installieren sind. Der Graben zwischen Entwicklung, Administration und der wirklichen Produktion scheint nun durch das Docker Container Managmenent überwindbar. Eine Anwendung in einem Docker Container, kann sehr einfach zwischen verschiedenen Umgebungen, lokal auf echtem Eisen, auf einer Virtualisierungsplattform oder in der Cloud gestartet werden und das ohne Veränderung. Das Leben für uns DevOps hat eine neue Baustelle. Bin sehr gespannt, wie sich die riesigen bestehenden Tanker mit diesem Betriebsmodell schneller und leistungsfähiger umgestalten lassen. Es wird eine große Herausforderung, sich für die Zukunft wettbewerbsfähig aufzustellen. &lt;/p&gt;

&lt;p&gt;Docker Inc., die Firma und Treiber dieser Entwicklung, sind aus dem Unternehmen DotCloud hervorgegangen. Die neue Firma hat aktuell einen strengen Fokus die Docker Technologie weiterzuentwicklen und zu vermarkten. Die Ankündigung, dass Docker nun fester Bestandteil des Red Hat 7 Release sein wird hilf da sicherlich. Die Integration mit bestehenden Virtualisierungslösungen ist auf einem gutem Weg, aber vielleicht gibt es ja bald neue Wege mit Docker.&lt;/p&gt;

&lt;p&gt;Die Eigenschaften des aktuellen Docker 1.0 Ökosystems sind:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Alle aktuellen Linux Distributionen werden unterstützt:

&lt;ul&gt;
&lt;li&gt;Red Hat&lt;/li&gt;
&lt;li&gt;Debian&lt;/li&gt;
&lt;li&gt;Ubuntu&lt;/li&gt;
&lt;li&gt;Fedora&lt;/li&gt;
&lt;li&gt;CentOS&lt;/li&gt;
&lt;li&gt;Gentoo&lt;/li&gt;
&lt;li&gt;Suse&lt;/li&gt;
&lt;li&gt;Arch&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;Plug-in Schnittstellen zur Kontrolle der Ausführung und zu den Dateisystemtreibern.&lt;/li&gt;
&lt;li&gt;Mit boot2docker macht es möglich Docker direkt mit Mac OS X und Windows zu betreiben.&lt;/li&gt;
&lt;li&gt;Die Dokumentation ist aktualisiert.&lt;/li&gt;
&lt;li&gt;Docker Inc liefert ein nun kompletes Trainingmaterialen und kommerziellen Support&lt;/li&gt;
&lt;li&gt;Integration mit Docker Hub, der andere wichtige Dienst für den Betreib mit Docker.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Von Docker sind mittlerweile mehr als drei Million Downloads erfolgt. Immer mehr Startups und DevOps bringen neue Ideen für Erweiterungen des noch jungen Ökosystems hervor.  Vermutlich laufen jetzt schon 100.000 Docker Container weltweit und es werde noch sehr viele folgen. Aktuell stehen mehr als 14.000 fertige Container im offiziellen Docker Hub Registry bereit. Das Docker Release 1.0 ist ein konsequenter nächster Schritt, eine Continous Delivery Pipeline bis in die Produktion sicher, nachvollziehbar und zuverlässig zu realisieren. Docker wird mit seinen Containern schon sehr bald Enterprise und Startup Projekte sehr erfolgreich machen.&lt;/p&gt;

&lt;p&gt;Wir werden in diesem Blog bald ausführlich mit dem Thema Docker mit Qualität entwickeln, auseinandersetzen.&lt;/p&gt;

&lt;h2 id=&quot;der-blaue-wal-legt-nun-richtig-los....&quot;&gt;Der blaue Wal legt nun richtig los....&lt;/h2&gt;

&lt;p&gt;Peter&lt;/p&gt;
</description>
                <link>/blog/2014/06/09/Docker-1.0-steht-bereit</link>
                <guid>/blog/2014/06/09/Docker-1.0-steht-bereit</guid>
                <pubDate>2014-06-09T00:00:00+02:00</pubDate>
        </item>

        <item>
                <title>infrataster und serverspec: Blackbox- und Whitebox-Testing</title>
                <description>&lt;p&gt;Für Infrastrukturtest bieten sich verschiedene Verfahren an. Aus der Softwareentwicklung
sind &lt;a href=&quot;http://de.wikipedia.org/wiki/Black-Box-Test&quot;&gt;&lt;strong&gt;Blackbox&lt;/strong&gt;&lt;/a&gt; - und
&lt;a href=&quot;http://de.wikipedia.org/wiki/White-Box-Test&quot;&gt;&lt;strong&gt;Whitebox&lt;/strong&gt;&lt;/a&gt;-Tests bekannt.
Bei der ersten Variante wird das, was man testen möchte ausschließlich von
außen (als Black Box) betrachtet, und das Verhalten der Komponenten wird über
seine Schnittstellen gegenüber einer Spezifikation bewertet.&lt;/p&gt;

&lt;h2 id=&quot;whitebox-...&quot;&gt;Whitebox ...&lt;/h2&gt;

&lt;p&gt;Bei Whitebox-Tests fließen Detailinformationen der zu testenden
Komponente ein, d.h. man muss also in die Komponente hereinschauen können, um
den Test durchzuführen.&lt;/p&gt;

&lt;p&gt;In den letzten Posts über &lt;a href=&quot;http://www.serverspec.org/&quot;&gt;serverspec&lt;/a&gt; haben wir uns
mit Whitebox-Testing beschäftigt. Hier beschreiben wir in einer Spezifikation
den Detailaufbau eines Servers, und serverspec prüft für uns diese Dinge ab.
Dazu muss serverspec natürlich in/auf den Server schauen.&lt;/p&gt;

&lt;p&gt;Wenn der Server beispielsweise einen Webservice bereitstellt, können wir mit serverspec prüfen,&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ob die Pakete für Middleware und Applikation installiert sind,&lt;/li&gt;
&lt;li&gt;ob die Applikation ihre Konfigurationsdateien besitzt,&lt;/li&gt;
&lt;li&gt;und diese korrekt sind,&lt;/li&gt;
&lt;li&gt;ob der Service startet und einen Netzwerkport belegt,&lt;/li&gt;
&lt;li&gt;und vieles mehr.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Damit ist nur leider nicht gesagt, dass der Webservice auch wie gewünscht
funktioniert. Mit dem Whitebox-Test haben wir nur die Grundlagen abgeprüft, die
überhaupt erst einmal notwendig sind.&lt;/p&gt;

&lt;p&gt;Man könnte im nächsten Schritt mit einem Tool wie curl oder wget innerhalb
des Servers einen HTTP-Call absetzen und das Ergebnis prüfen. Die Funktionsfähigkeit
kann von außen betrachtet aber immer noch scheitern, etwa weil die Netzwerkkonfiguration nicht stimmt
oder iptables den Zugriff verhindert.&lt;/p&gt;

&lt;h2 id=&quot;...-und-blackbox&quot;&gt;... und Blackbox&lt;/h2&gt;

&lt;p&gt;Das wiederum lässt sich mit einem Test von außen abprüfen. Wenn ein anderer
Server den Service abfragt und ein korrektes Ergebnis erhält, kann man schon eher
sicher sein, dass alles korrekt ist.&lt;/p&gt;

&lt;p&gt;Da serverspec erweiterbar ist, lassen sich prinzipiell auch Blackbox-Tests
durchführen. Ein einfaches - allerdings unschönes - Beispiel nutzt das Kommandozeilentool
&lt;code&gt;curl&lt;/code&gt; um einen HTTP-Call zu platzieren und Daten aus der Ausgabe zu prüfen:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;describe&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;command&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;curl http://appserver:8080/test&amp;#39;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;it&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;should&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;return_exit_status&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;its&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:stdout&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;should&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;match&lt;/span&gt; &lt;span class=&quot;sr&quot;&gt;/^success$/&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Das sollte funktionieren, wandelt aber den deklarativen Ansatz von serverspec in einen
imperativen um: Wir beschreiben nicht eine Webresource, sondern konstruieren ein
&lt;code&gt;command&lt;/code&gt;, um sie abzufragen. Vor allem wenn beim curl-Aufruf Parameter übergeben werden, vielleicht
noch über HTTP POST, wird der Einzeiler länger und unschöner.&lt;/p&gt;

&lt;h2 id=&quot;geschmacksprobe:-infrataster&quot;&gt;Geschmacksprobe: Infrataster&lt;/h2&gt;

&lt;p&gt;Glücklicherweise gibt es ein Projekt, das den Blackbox-Ansatz in rspec-Art und
Weise umsetzt, &lt;a href=&quot;https://github.com/ryotarai/infrataster&quot;&gt;Infrataster&lt;/a&gt;. Dies ist
eine Erweiterung auf rspec, die verschiedene Typen einführt um Calls abzusetzen
und das Ergebnis abzuprüfen. Dabei werden Webcrawler-Frameworks aus der Ruby-Welt
eingesetzt um dennoch bei einer lesbaren Testspezifikation bleiben zu können.&lt;/p&gt;

&lt;p&gt;Das sieht dann beispielsweise so aus:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;describe&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;server&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:app&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;describe&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;http://appserver:8080/test&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;it&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;responds content including &amp;#39;success&amp;#39;&amp;quot;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;response&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;to&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;include&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;success&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Hier wird im äußeren describe-Block der zu testenden Server angegeben (&lt;code&gt;:app&lt;/code&gt;, s.u.),
im inneren Block die Ressource (&lt;code&gt;appserver:8080/test&lt;/code&gt;), und die Expectations, z.B.
bezüglich der Rückgabe.&lt;/p&gt;

&lt;p&gt;Infrataster kann dabei die Rückgabe auch detaillierter prüfen, etwa ob
bestimmte Response-Header gesetzt sind, hier, ob der Content-Type &lt;code&gt;text/html&lt;/code&gt; entspricht:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;        &lt;span class=&quot;n&quot;&gt;it&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;responds as &amp;#39;text/html&amp;#39;&amp;quot;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;response&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;headers&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;content-type&amp;#39;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;to&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;match&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;%r{^text/html}&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Außerdem kann man bei Konstruktion des Calls auch Parameter mitgeben, z.B.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;    &lt;span class=&quot;n&quot;&gt;describe&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
            &lt;span class=&quot;s1&quot;&gt;&amp;#39;http://appserver:8080/foo/app&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;nb&quot;&gt;method&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;   &lt;span class=&quot;ss&quot;&gt;:get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;ss&quot;&gt;params&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;   &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;foo&amp;#39;&lt;/span&gt;   &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;bar&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
            &lt;span class=&quot;ss&quot;&gt;headers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;  &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;USER&amp;#39;&lt;/span&gt;  &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;VALUE&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Damit lassen sich Webservices auch von außen gut testen. Weitere Post zeigen
die Verdrahtung zu den Zielservern (&amp;quot;:app&amp;quot;), die Nutzung von Proxies,
wie Infrataster aufgebaut ist, und wie man damit ein reales Testszenario aufsetzt.&lt;/p&gt;

&lt;h2 id=&quot;beides-zusammen,-ftw!&quot;&gt;Beides zusammen, FTW!&lt;/h2&gt;

&lt;p&gt;Weder Blackbox- noch Whitebox-Tests sind für sich genommen ausreichend. Wenn
innerhalb der Komponente alles in Ordnung ist (Whitebox) heisst das nicht
automatisch, dass ihr Verhalten nach außen wie gewünscht funktioniert.&lt;/p&gt;

&lt;p&gt;Umgekehrt kann man aus einem fehlschlagenden Blackbox-Test noch nicht ermitteln,
woran es eigentlich scheitert, d.h. der Fehler ist erkennbar, aber nicht
lokalisierbar.&lt;/p&gt;

&lt;p&gt;Um Infrastrukturkomponenten qualitativ testen zu können, sind sowohl White-
als auch Blackbox-Tests sehr sinnvoll. Hier ist die Kombination von
serverspec und Infrataster wirksam und empfehlenswert!&lt;/p&gt;

&lt;h2 id=&quot;&quot;&gt;&lt;/h2&gt;

&lt;p&gt;Andreas&lt;/p&gt;
</description>
                <link>/blog/2014/05/22/blackbox-und-whitebox-testing</link>
                <guid>/blog/2014/05/22/blackbox-und-whitebox-testing</guid>
                <pubDate>2014-05-22T00:00:00+02:00</pubDate>
        </item>

        <item>
                <title>serverspec mit Vagrant verbinden</title>
                <description>&lt;p&gt;Eine späte Integration der eigenen Software in die Produktionsumgebung rächt sich meistens. Der Kundennutzen muss immer früher sicher hergestellet werden. Jede Änderung soll geschwindt in die Produktion, um dort zu beweisen, ob diese Eigenschaft den gewünschten Nutzen wirklich bietet. Natürlich soll kein Fehler in die Produktion gelangen. Die Änderungen müssen überprüft werden und durch verschiedene aufeinander aufbauende Umgebungen die Qualität sicher gestellt werden. Um so eher dies gelingt, um so schneller kann eine gezielte Korrektur erfolgen.&lt;/p&gt;

&lt;p&gt;Das Ziel sollte es sein eine Deployment Pipeline zu installieren [Jez Humble, David Farley: &amp;quot;Continuous Delivery&amp;quot;, 2011 Pearson Education]. Damit das Feedback schnellst möglich gelingt, ist es ratsam schon früh die Integration in die Produktionumgebung zu realisieren und die Teilinstallation am eigenen Arbeitsplatz zu überprüfen. Dieser Artikel beschreibt die Erstellung einer Apache Httpd -Installation mit &lt;a href=&quot;http://vagrantup.com&quot;&gt;Vagrant&lt;/a&gt; und [Virtualbox](&lt;a href=&quot;http://www.virtualbox.org&quot;&gt;http://www.virtualbox.org&lt;/a&gt;. Die Besonderheit ist der Einsatz von &lt;a href=&quot;http://serverspec.org&quot;&gt;serverspec&lt;/a&gt; zur Valdierung der Provisionierung.&lt;/p&gt;

&lt;p&gt;Der Plan ist, einen Apache httpd Service in einer CentOS 6.5 Box aufzusetzen und sicherzustellen, dass der Webserver wirklich läuft. Als ersten Schritt wird ein entsprechendes Basis CentOS 6.5 Image mithilfe von Vagrant auf die lokale Virtualbox installieren. Damit also die folgenden Schritte praktisch nachvollzogen werden können, bedarf es einer entsprechende Installation von Vagrant und Virtualbox auf dem System. Entsprechende Anleitungen dazu befinden sich auf den Websites der beiden OpenSource Projekte.&lt;/p&gt;

&lt;p&gt;Ein gesichertes Betriebssystem für die eigene Vagrant Box zu bekommen ist nicht einfach. Zum guten Gelingen und notwendigen Beitrag der Sicherheit, sollten man diese Installation lieber selbst in die Hand nehmen. Mit den Projekten &lt;a href=&quot;http://www.packer.io/&quot;&gt;Packer&lt;/a&gt; oder &lt;a href=&quot;https://github.com/jedi4ever/veewee&quot;&gt;Veewee&lt;/a&gt; kann dies komfortabel für verschiedene Betriebssysteme, virtuelle Plattformen und Clouds umgesetzt werden. Eine gute Kenntnis der Installation von Betriebssystemen und viel Geduld, führt dann langsam zum Ziel. Natürlich gibt es auch fertige Boxen. Für Vagrant gibt es neben dem Cloud Angebot &lt;a href=&quot;https://vagrantcloud.com/&quot;&gt;Vagrant Cloud&lt;/a&gt; natürlich auch eine freie Sammlung &lt;a href=&quot;http://www.vagrantbox.es/&quot;&gt;Vagrantbox&lt;/a&gt;. Eine sehr einfache und leicht nachzuvollziehende CentOS 6.5 Installation wird von &lt;a href=&quot;https://github.com/2creatives/vagrant-centos/&quot;&gt;2Creatives&lt;/a&gt; bereitgestellt. Die Box wird regelmässig aktualisiert und steuert sehr direkt die Management Schnittstelle von Virtualbox an. Die Box kann nun mit folgendem Vagrant-Befehl auf der eigenen Maschine bereitgestellt werden:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;mkdir apache-specbox
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;apache-specbox
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;vi Vagrantfile
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Mit dem folgenden Vagrant Konfiguration wird die CentOS-Box von 2creatives geladen, ein privates Netzwerk zusätzlich geschaffen, der Ressourcenbedarf festgelegt und der Name &lt;code&gt;apacheSpecbox&lt;/code&gt; der neuen Virtualbox-Node vergeben.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;c1&quot;&gt;# -*- mode: ruby -*-&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# vi: set ft=ruby :&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;## Vagrantfile&lt;/span&gt;

&lt;span class=&quot;no&quot;&gt;VAGRANTFILE_API_VERSION&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;2&amp;quot;&lt;/span&gt;

&lt;span class=&quot;no&quot;&gt;Vagrant&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;configure&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;VAGRANTFILE_API_VERSION&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vm&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;box&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;2creatives/centos65-x86_64-20140116&amp;quot;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vm&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;box_url&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;https://github.com/2creatives/vagrant-centos/releases/download/v6.5.3/centos65-x86_64-20140116.box&amp;quot;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vm&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;box_download_checksum_type&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;sha256&amp;quot;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vm&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;box_download_checksum&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;84eda9c4f00c86b62509d1007d4f1cf16b86bccb3795659cb56d1ea0007c3adc&amp;quot;&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vm&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:apacheSpecbox&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vm&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;network&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;private_network&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;ip&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;192.168.33.10&amp;quot;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vm&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;host_name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;apacheSpecbox.example.com&amp;quot;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vm&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;provider&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;virtualbox&amp;quot;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vb&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
         &lt;span class=&quot;n&quot;&gt;vb&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;gui&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;false&lt;/span&gt;
         &lt;span class=&quot;n&quot;&gt;vb&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;customize&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;modifyvm&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;--memory&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;512&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
         &lt;span class=&quot;n&quot;&gt;vb&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;customize&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;modifyvm&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;--cpus&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;1&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
         &lt;span class=&quot;n&quot;&gt;vb&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;apacheSpecbox&amp;quot;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Dann ein:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;vagrant up
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Die Voraussetzungen für eine Apache httpd Installation sind also nun gegeben. Als nächsten Schritt könnte man mit dem Befehl &lt;code&gt;vagrant ssh&lt;/code&gt; sich auf die neue &lt;code&gt;apacheSpecbox&lt;/code&gt; anmelden und den Apache mit dem Package Manager manuell installieren. Allerdings wären das gleich mehrere Verstöße der guten Sitten. Alles und damit ist wirklich ALLES gemeint, muss durch entsprechende Programmierung automatisch nachvollzogen und prüfbar sein. Hmm, welche Anforderungen muss soll die Installation eines Apaches den wirklich erfüllen? Wie kann man durch ein Werkzeug die Überprüfung formulieren und ausführbar machen? Genau an dieser Stelle beginnt dann die Suche im Netz, nach Ideen und Lösungen. Seit nunmehr zwei Jahren gibt es das kleine Projekt &lt;a href=&quot;http://www.serverspec.org&quot;&gt;serverspec&lt;/a&gt; von Gosuke Miyashita, das sich als Antwort auf diese Fragen entpuppt.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/vagrant-serverspec.png&quot; alt=&quot;Mit Serverspec eine Provisionierung von Vagrant valideren&quot;&gt;&lt;/p&gt;

&lt;p&gt;Damit die Installation wiederholbar ist und dokumentiert wird, wird ein Gemfile erzeugt und mit dem &lt;code&gt;ruby bundler&lt;/code&gt;
die Installation gestartet.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;vi Gemfile
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;c1&quot;&gt;## Gemfile&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;ruby&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;2.1.1&amp;#39;&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;source&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;https://rubygems.org&amp;#39;&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;gem&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;serverspec&amp;#39;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;bundle install
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;serverspec-init
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;rake
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Mit dem Kommando &lt;code&gt;serverspec-init&lt;/code&gt; wird die Testumgebung zur Prüfung der Installation erzeugt. Das Werkzeug serverspec kann für verschiedene Unix Plattformen und Windows genutzt werden. Es kann remote via ssh oder lokal mit der jeweiligen Shell ausgeführt werden. Schön ist, dass der Generator gleich eine Variante für den ssh-Zugang einer Vagrant Box generieren kann. Wie für die Aufgabe gemacht, wird gleich eine Apache httpd-Testspezifikation mitgeneriert.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;serverspec-init
Select OS &lt;span class=&quot;nb&quot;&gt;type&lt;/span&gt;:

  1&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; UN*X
  2&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; Windows

Select number: 1

Select a backend &lt;span class=&quot;nb&quot;&gt;type&lt;/span&gt;:

  1&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; SSH
  2&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; Exec &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;local&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;

Select number: 1

Vagrant instance y/n: y
Auto-configure Vagrant from Vagrantfile? y/n: y
 + spec/
 + spec/apacheSpecbox/
 + spec/apacheSpecbox/httpd_spec.rb
 + spec/spec_helper.rb
 + Rakefile
&lt;span class=&quot;c&quot;&gt;###&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Eine Überprüfung der Node zeigt, dass der Apache noch nicht installiert ist. Stimmt!&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;rake spec
/usr/bin/ruby -S rspec spec/apacheSpecbox/httpd_spec.rb
FFFFFF
...viele Fehlermeldungen...

Finished in 0.99715 seconds
&lt;span class=&quot;m&quot;&gt;6&lt;/span&gt; examples, &lt;span class=&quot;m&quot;&gt;6&lt;/span&gt; failures
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Ein Blick auf die Spezifikation &lt;code&gt;spec/apacheSpecbox/httpd_spec.rb&lt;/code&gt; zeigt die Anforderungen. Das httpd-Package soll installiert sein. Der httpd soll als OS-Service konfiguiert werden. Wie gewohnt soll der Apache unter dem Port 80 erreichbar sein.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;c1&quot;&gt;## spec/apacheSpecbox/httpd-spec.rb&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;spec_helper&amp;#39;&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;describe&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;package&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;httpd&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;it&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;should&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;be_installed&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;describe&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;service&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;httpd&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;it&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;should&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;be_enabled&lt;/span&gt;   &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;it&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;should&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;be_running&lt;/span&gt;   &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;describe&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;port&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;80&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;it&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;should&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;be_listening&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;describe&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;/etc/httpd/conf/httpd.conf&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;it&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;should&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;be_file&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Zum Erreichen dieses Ziels, muss die Node nun provisioniert werden. Vagrant bringt eine Vielzahl von entsprechenden Plugins für Ansible, Chef, Puppet, Saltstack oder Shell gleich mit. Zur Umsetzung der Anforderungen reicht der Shell-Provisioner erstmal völlig aus. Durch folgende Änderungen in der Datei Vagrantfile kann dies schnell implementiert werden.&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;c1&quot;&gt;# -*- mode: ruby -*-&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# vi: set ft=ruby :&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;## Vagrantfile&lt;/span&gt;

&lt;span class=&quot;no&quot;&gt;VAGRANTFILE_API_VERSION&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;2&amp;quot;&lt;/span&gt;

&lt;span class=&quot;no&quot;&gt;Vagrant&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;configure&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;VAGRANTFILE_API_VERSION&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vm&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;box&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;2creatives/centos65-x86_64-20140116&amp;quot;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vm&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;box_url&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;https://github.com/2creatives/vagrant-centos/releases/download/v6.5.3/centos65-x86_64-20140116.box&amp;quot;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vm&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;box_download_checksum_type&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;sha256&amp;quot;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vm&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;box_download_checksum&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;84eda9c4f00c86b62509d1007d4f1cf16b86bccb3795659cb56d1ea0007c3adc&amp;quot;&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vm&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:apacheSpecbox&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vm&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;network&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;private_network&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;ip&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;192.168.33.10&amp;quot;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vm&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;host_name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;apacheSpecbox.example.com&amp;quot;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vm&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;provider&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;virtualbox&amp;quot;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vb&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
         &lt;span class=&quot;n&quot;&gt;vb&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;gui&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;false&lt;/span&gt;
         &lt;span class=&quot;n&quot;&gt;vb&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;customize&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;modifyvm&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;--memory&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;512&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
         &lt;span class=&quot;n&quot;&gt;vb&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;customize&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;modifyvm&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;--cpus&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;1&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
         &lt;span class=&quot;n&quot;&gt;vb&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;apacheSpecbox&amp;quot;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vm&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;provision&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;shell&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
         &lt;span class=&quot;ss&quot;&gt;inline&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;SCRIPT&lt;/span&gt;
&lt;span class=&quot;sh&quot;&gt;echo I am provisioning...&lt;/span&gt;
&lt;span class=&quot;sh&quot;&gt;yum -y install httpd&lt;/span&gt;
&lt;span class=&quot;sh&quot;&gt;date &amp;gt; /etc/vagrant_provisioned_at&lt;/span&gt;
&lt;span class=&quot;no&quot;&gt;SCRIPT&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Mit dem Befehl &lt;code&gt;vagrant provision&lt;/code&gt; wird nun die Provisionierung ausgeführt. Ein erneuter Test zeigt, dass nun der Apache durch die Packages zwar installiert ist, aber er weder gestartet, noch als Service angemeldet ist. Weiterhin fehlt das Package &lt;code&gt;nc&lt;/code&gt;, damit serverspec die Tests auf dem Port durchführen kann. Weiterhin wäre es auch schön, wenn der httpd Server auch den richtigen ServerName bekommt. Durch eine Modifikation unseres kleinen Inline Provisinierungsskripts lässt sich das schnell erledigen.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;   &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vm&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;provision&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;shell&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
         &lt;span class=&quot;ss&quot;&gt;inline&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;SCRIPT&lt;/span&gt;
&lt;span class=&quot;sh&quot;&gt;echo I am provisioning...&lt;/span&gt;
&lt;span class=&quot;sh&quot;&gt;yum -y install httpd nc&lt;/span&gt;
&lt;span class=&quot;sh&quot;&gt;sed -i &amp;#39;s/#ServerName www.example.com:80/ServerName apacheSpecbox.example.com:80/g&amp;#39; /etc/httpd/conf/httpd.conf&lt;/span&gt;
&lt;span class=&quot;sh&quot;&gt;chkconfig httpd on --level 2345&lt;/span&gt;
&lt;span class=&quot;sh&quot;&gt;service httpd restart&lt;/span&gt;
&lt;span class=&quot;sh&quot;&gt;date &amp;gt; /etc/vagrant_provisioned_at&lt;/span&gt;
&lt;span class=&quot;no&quot;&gt;SCRIPT&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Mit der nächsten Provisionierung gelingt nun die Verifikation. Unser Ergebnis ist das erstmal &lt;strong&gt;Grün&lt;/strong&gt;!&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;vagrant provision
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;rake spec
/usr/bin/ruby -S rspec spec/apacheSpecbox/httpd_spec.rb
.......

Finished in 0.99715 seconds
&lt;span class=&quot;m&quot;&gt;6&lt;/span&gt; examples, &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt; failures
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Die Validierung bringt zu Tage, dass die Basisanforderungen erfüllt und überprüft werden können. Weiterhin sind alle Schritte der Installation und der Testausführung beschrieben. Eine wiederholbare Testprozedur für die Apache httpd Installation ist implementiert. Als Verfahren sind die Test vor der Implementierung umgesetzt worden. Eine noch bessere Integration von Serverspec und Vagrant existiert im Projekt &lt;a href=&quot;https://github.com/jvoorhis/vagrant-serverspec&quot;&gt;vagrant-serverspec plugin&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Die Installation des Plugin erfolgt mit folgendem Befehl:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;vagrant plugin install vagrant-serverspec
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Die Integration als Vagrant Provisioner erfolgt im Konfigurations-Block des Nodes &lt;code&gt;apacheSpecbox&lt;/code&gt;&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;c1&quot;&gt;## Vagrantfile&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vm&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;provision&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:serverspec&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;spec&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
       &lt;span class=&quot;n&quot;&gt;spec&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pattern&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;specs/apacheSpecbox/*_spec.rb&amp;#39;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Für die Ausführung dieser Variante bietet sich an, die gesamte Provisionierung einfach zu wiederholen.
Dazu zerstören man den aktuellen Node und setzen diesen komplette neu auf. Mithilfe des Plugins werden nun unsere Test sofort ausgeführt. Volia!&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;vagrant destroy apacheSpecbox
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;vagrant up apacheSpecbox
&lt;span class=&quot;c&quot;&gt;# look at results&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Leider ist die Version von Serverspec im Plugin veraltet. Deshalb raten ist zur Zeit die direkten Installation der bessere Weg. Die Gestaltung von flexiblen Testspecs ist damit zukunfsträchtiger. Ein wichtiger erster Schritt für die Bereitstellung von testgetriebener Infrastruktur ist vollbracht. Ein Testfirst-Ansatz für die Infrastruktur ist also ohne wesentlichen Aufwand möglich. Eine inkrementellere Arbeitsweise für die Erstellung von Systemen leicht umsetzbar.&lt;/p&gt;

&lt;p&gt;Nun geht es an die Verbesserung des Erreichten. In diesem Blog wird es dazu noch viel zu lesen geben.&lt;/p&gt;

&lt;h2 id=&quot;&quot;&gt;&lt;/h2&gt;

&lt;p&gt;Peter&lt;/p&gt;
</description>
                <link>/blog/2014/05/09/serverspec-mit-vagrant-verbinden</link>
                <guid>/blog/2014/05/09/serverspec-mit-vagrant-verbinden</guid>
                <pubDate>2014-05-09T00:00:00+02:00</pubDate>
        </item>

        <item>
                <title>serverspec standalone betreiben</title>
                <description>&lt;p&gt;Nachdem wir im letzten Post allgemein vorgestellt haben, was man mit &lt;a href=&quot;http://serverspec.org/&quot;&gt;serverspec&lt;/a&gt;
machen kann, wollen wir die ersten Beispiele in eine ausführbare Form bringen,
sodass man damit weiter experimentieren kann.&lt;/p&gt;

&lt;h2 id=&quot;voraussetzungen&quot;&gt;Voraussetzungen&lt;/h2&gt;

&lt;p&gt;Um den Post nicht zu groß aufzubauen und nicht zu viele Abhängigkeiten einzuführen,
benötigen wir nur eine Serverinstanz, auf der wir lokal testen. Das kann eine
VM oder auch das eigene Notebook sein. Auch wenn serverspec mit vielen Betriebssystemen
umgehen kann, sind Debian- oder Redhat-Distros zum Spielen am einfachsten.
Die Beispiele gehen von CentOS-6.5 mit englischem Locale aus.&lt;/p&gt;

&lt;p&gt;Es läuft einfacher, wenn die Instanz auf Repos im Internet zugreifen kann, es
geht aber auch offline bzw. mit lokalen Mirrors. Das ist durchaus hilfreich in
Umgebungen, in denen nicht jeder Server Zugriff nach außen hat und auch (noch)
keine lokalen Mirros aufgesetzt sind.&lt;/p&gt;

&lt;p&gt;Eine weitere Voraussetzung ist eine lauffähige Ruby- und rubygems-Installation ab Version 1.8.7.
Diese wird in der Regel von den Linux-Distributionen in den eigenen Paketrepositories
mitgeliefert. Also:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;sudo yum install -y ruby rubygems
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;oder bei Debian&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;sudo apt-get install ruby1.9.3 rubygems
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&quot;installation-von-serverspec&quot;&gt;Installation von serverspec&lt;/h2&gt;

&lt;h3 id=&quot;online&quot;&gt;Online&lt;/h3&gt;

&lt;p&gt;Natürlich ist die online-Installation am einfachsten. serverspec liegt als gem-Paket
bei rubygems.org vor, und darüber werden abhängige Pakete erkannt und mit installiert.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;sudo gem install serverspec rake --no-ri --no-rdoc
Successfully installed net-ssh-2.9.0
Successfully installed rspec-core-2.14.8
Successfully installed diff-lcs-1.2.5
Successfully installed rspec-expectations-2.14.5
Successfully installed rspec-mocks-2.14.6
Successfully installed rspec-2.14.1
Successfully installed highline-1.6.21
Successfully installed specinfra-1.11.0
Successfully installed serverspec-1.6.0
Successfully installed rake-10.3.1
&lt;span class=&quot;m&quot;&gt;10&lt;/span&gt; gems installed
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Was machen die Pakete:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;diff-lcs&lt;/code&gt; findet Unterschiede bspw. in Arrays&lt;/li&gt;
&lt;li&gt;&lt;code&gt;net-ssh&lt;/code&gt; ist eine Ruby-Library zum SSH-Connect zu anderen Hosts&lt;/li&gt;
&lt;li&gt;&lt;code&gt;rspec-*&lt;/code&gt; sind alle Pakete für RSpec (&lt;a href=&quot;http://www.rspec.info&quot;&gt;www.rspec.info&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;highline&lt;/code&gt; für etwas Farbe im Kommandozeilenleben&lt;/li&gt;
&lt;li&gt;&lt;code&gt;specinfra&lt;/code&gt; ist das Serverspec-Backend mit einer Abstraktion für verschiedene Betriebssysteme mit deren Kommandos.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;serverspec&lt;/code&gt; das eigentliche Serverspec-Frontend, das wir benutzen wollen.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;offline&quot;&gt;Offline&lt;/h3&gt;

&lt;p&gt;Die Offlineinstallation ist auch kein Problem, dazu ziehen wir uns die notwendigen
Pakete von rubygems und kopieren sie auf die Serverinstanz. Wer mag, setzt sich
eine eigenen rubygems-Mirrorserver auf.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; i in diff-lcs-1.2.5 net-ssh-2.9.0 highline-1.6.21 bundler-1.6.2 rake-10.3.1 rspec-core-2.14.8 rspec-expectations-2.14.5 rspec-mocks-2.14.6 rspec-2.14.1 specinfra-1.11.0 serverspec-1.6.0&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  wget http://rubygems.org/downloads/&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;.gem
&lt;span class=&quot;k&quot;&gt;done&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Dann lokal installieren:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;sudo gem install --local --no-ri --no-rdoc rake-10.3.1.gem bundler-1.6.2.gem diff-lcs-1.2.5.gem rspec-core-2.14.8.gem rspec-expectations-2.14.5.gem rspec-mocks-2.14.6.gem rspec-2.14.1.gem net-ssh-2.9.0.gem highline-1.6.21.gem specinfra-1.11.0.gem serverspec-1.6.0.gem
Successfully installed rake-10.3.1
Successfully installed bundler-1.6.2
Successfully installed diff-lcs-1.2.5
Successfully installed rspec-core-2.14.8
Successfully installed rspec-expectations-2.14.5
Successfully installed rspec-mocks-2.14.6
Successfully installed rspec-2.14.1
Successfully installed net-ssh-2.9.0
Successfully installed highline-1.6.21
Successfully installed specinfra-1.11.0
Successfully installed serverspec-1.6.0
&lt;span class=&quot;m&quot;&gt;11&lt;/span&gt; gems installed
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&quot;init!&quot;&gt;Init!&lt;/h2&gt;

&lt;p&gt;Um mit den eigenen Specs loszulegen, bringt serverspec ein Skript &lt;code&gt;serverspec-init&lt;/code&gt;
mit, um eine Art Vorlage zu generieren, die erstmal lauffähig ist. Das rufen wir
in einem leeren Verzeichnis auf, und beantworten einige Fragen:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;mkdir myspecs
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;myspecs
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;serverspec-init
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Hier müssen wir entscheiden, wo die zu testende Instanz liegt. Entweder greift
serverspec per &lt;code&gt;ssh&lt;/code&gt; darauf zu, oder man testet die eigene Instanz (&lt;code&gt;local&lt;/code&gt;).
Das wollen wir in unserem Fall auch tun, für Unix:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;serverspec-init
Select OS &lt;span class=&quot;nb&quot;&gt;type&lt;/span&gt;:

  1&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; UN*X
  2&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; Windows

Select number: 1

Select a backend &lt;span class=&quot;nb&quot;&gt;type&lt;/span&gt;:

  1&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; SSH
  2&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; Exec &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;local&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;

Select number: 2
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&quot;die-leere-vorlage&quot;&gt;Die leere Vorlage&lt;/h2&gt;

&lt;p&gt;Serverspec hat das folgende für uns erzeugt:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt; + spec/
 + spec/localhost/
 + spec/localhost/httpd_spec.rb
 + spec/spec_helper.rb
 + Rakefile
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Wofür braucht man was?&lt;/p&gt;

&lt;h3 id=&quot;*_spec.rb&quot;&gt;*_spec.rb&lt;/h3&gt;

&lt;p&gt;Das sind die eigentlichen Spezifikationsfiles, wo die Tests lagern. Bei der
Zusammenstellung ist man frei: Ein _spec.rb für hunderte Tests (nicht sinnvoll)
oder für jeden Tests ein eigenes _spec.rb (auch nicht sinnvoll). In den nächsten
Posts werden wir hierfür eine sinnvolle Struktur aufzubauen.&lt;/p&gt;

&lt;h3 id=&quot;rakefile&quot;&gt;Rakefile&lt;/h3&gt;

&lt;p&gt;Rake ist quasi das &amp;quot;make&amp;quot; für ruby. Es automatisiert Vorgänge und dient uns
hier als &amp;quot;Glue&amp;quot;, um die rspec-basierten Tests anzustarten. Man könnte auch
rspec direkt ausführen, allerdings biegt das für uns generierte Rakefile
einige Dinge für die Ausführung richtig.
In der Standardversion werden einfach alle Dateien im spec/ Unterverzeichnis
(und den darunter liegenden Verzeichnissen) aufgegriffen, die auf _spec.rb
enden.&lt;/p&gt;

&lt;h3 id=&quot;spec_helper.rb&quot;&gt;spec_helper.rb&lt;/h3&gt;

&lt;p&gt;Der Spec-Helper wird von den Testcases verwendet (&amp;quot;require&amp;quot;) und schafft einige
Voraussetzungen. Interessant sind z.B. das Erkennen von Betriebssystemen
(&lt;code&gt;include .... DetectOS&lt;/code&gt;) sowie (falls noch notwendig) das abfragen eines
Passworts für sudo.&lt;/p&gt;

&lt;h3 id=&quot;http_spec.rb&quot;&gt;http_spec.rb&lt;/h3&gt;

&lt;p&gt;Die leere Vorlage ist gar nicht so leer, sie enthält nämlich ein Beispiel
für einen funktionierenden Webserver, die wir einfach verwenden werden.
Geprüft wird:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;dass ein OS-Paket installiert wurde (hier: httpd, passt auf RHEL),&lt;/li&gt;
&lt;li&gt;dass der Service automatisch gestartet wird und aktuell läuft,&lt;/li&gt;
&lt;li&gt;dass ein Port geöffnet ist und&lt;/li&gt;
&lt;li&gt; dass eine Konfigurationsdatei mit bestimmten Inhalte vorliegt.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Das sieht dann so aus:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;spec_helper&amp;#39;&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;describe&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;package&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;httpd&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;it&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;should&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;be_installed&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;describe&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;service&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;httpd&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;it&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;should&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;be_enabled&lt;/span&gt;  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;it&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;should&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;be_running&lt;/span&gt;  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;describe&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;port&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;80&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;it&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;should&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;be_listening&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;describe&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;/etc/httpd/conf/httpd.conf&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;it&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;should&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;be_file&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;it&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;should&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;contain&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;ServerName localhost&amp;quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Die Syntax ist sehr einfach und fast natürlichsprachlich. Es besteht aus mehreren
Blöcken, die bestimmte Aspekte (package, service, port, file) beschreiben. In
den Blöcken liegen dann Match-Ausdrücke, die bestimmte Konditionen abprüfen&lt;/p&gt;

&lt;h2 id=&quot;erster-testrun&quot;&gt;Erster Testrun&lt;/h2&gt;

&lt;p&gt;Wir lassen &amp;quot;die spec&amp;quot; einfach mal laufen und schauen, was passiert:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;sudo rake spec
Failures:

  1&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; Package &lt;span class=&quot;s2&quot;&gt;&amp;quot;httpd&amp;quot;&lt;/span&gt; should be installed
     Failure/Error: it &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt; should be_installed &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
       rpm -q httpd
       package httpd is not installed
       expected Package &lt;span class=&quot;s2&quot;&gt;&amp;quot;httpd&amp;quot;&lt;/span&gt; to be installed
     &lt;span class=&quot;c&quot;&gt;# ./spec/localhost/httpd_spec.rb:4&lt;/span&gt;

  2&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; Service &lt;span class=&quot;s2&quot;&gt;&amp;quot;httpd&amp;quot;&lt;/span&gt; should be enabled
  ....

  ....

Finished in 0.05863 seconds
&lt;span class=&quot;m&quot;&gt;6&lt;/span&gt; examples, &lt;span class=&quot;m&quot;&gt;6&lt;/span&gt; failures

Failed examples:

rspec ./spec/localhost/httpd_spec.rb:4 &lt;span class=&quot;c&quot;&gt;# Package &amp;quot;httpd&amp;quot; should be installed&lt;/span&gt;
rspec ./spec/localhost/httpd_spec.rb:8 &lt;span class=&quot;c&quot;&gt;# Service &amp;quot;httpd&amp;quot; should be enabled&lt;/span&gt;
rspec ./spec/localhost/httpd_spec.rb:9 &lt;span class=&quot;c&quot;&gt;# Service &amp;quot;httpd&amp;quot; should be running&lt;/span&gt;
rspec ./spec/localhost/httpd_spec.rb:13 &lt;span class=&quot;c&quot;&gt;# Port &amp;quot;80&amp;quot; should be listening&lt;/span&gt;
rspec ./spec/localhost/httpd_spec.rb:17 &lt;span class=&quot;c&quot;&gt;# File &amp;quot;/etc/httpd/conf/httpd.conf&amp;quot; should be file&lt;/span&gt;
rspec ./spec/localhost/httpd_spec.rb:18 &lt;span class=&quot;c&quot;&gt;# File &amp;quot;/etc/httpd/conf/httpd.conf&amp;quot; content should match /ServerName localhost/&lt;/span&gt;
/usr/bin/ruby -S rspec spec/localhost/httpd_spec.rb failed
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Wir sehen, dass eigentlich alles fehlschlägt. Klar, denn noch haben wir nichts
installiert bzw. provisioniert.&lt;/p&gt;

&lt;h2 id=&quot;red,-green,-refactor&quot;&gt;Red, Green, Refactor&lt;/h2&gt;

&lt;p&gt;Gemäß dem Testdriven-Zyklus sind wir jetzt im &amp;quot;Red&amp;quot; angelangt. Wir haben einen
Testcase, der einen Zielzustand beschreibt. Unsere Infrastruktur-
Tests schlagen fehl, also machen wir uns daran, diese grün zu bekommen.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Disclaimer&lt;/strong&gt;: Natürlich wählt man hierzu am besten ein Provisionierungswerkzeug,
also Salt, Chef, Puppet, ... Um den Post einfach zu halten werden wir hier manuell
installieren, das Umformen (z.B. ein Provisioner für Vagrant) bleibt
dann für den &amp;quot;Refactor&amp;quot;-Schritt :-)&lt;/p&gt;

&lt;p&gt;Das erste ist die Installation des Pakets.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;sudo yum install -y httpd
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Wir lassen die spec noch einmal laufen und sehen:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;sudo rake spec
...
...
Finished in 0.0678 seconds
&lt;span class=&quot;m&quot;&gt;6&lt;/span&gt; examples, &lt;span class=&quot;m&quot;&gt;4&lt;/span&gt; failures

Failed examples:

rspec ./spec/localhost/httpd_spec.rb:8 &lt;span class=&quot;c&quot;&gt;# Service &amp;quot;httpd&amp;quot; should be enabled&lt;/span&gt;
rspec ./spec/localhost/httpd_spec.rb:9 &lt;span class=&quot;c&quot;&gt;# Service &amp;quot;httpd&amp;quot; should be running&lt;/span&gt;
rspec ./spec/localhost/httpd_spec.rb:13 &lt;span class=&quot;c&quot;&gt;# Port &amp;quot;80&amp;quot; should be listening&lt;/span&gt;
rspec ./spec/localhost/httpd_spec.rb:18 &lt;span class=&quot;c&quot;&gt;# File &amp;quot;/etc/httpd/conf/httpd.conf&amp;quot; content should match /ServerName localhost/&lt;/span&gt;
/usr/bin/ruby -S rspec spec/localhost/httpd_spec.rb failed
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Oben hatten wir noch 6 Failures, jetzt nur noch 4. Es wird. Als nächstes sollte
httpd.conf konfiguriert werden. Wir fügen dort &lt;code&gt;localhost&lt;/code&gt; ein:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;$ sudo vi /etc/httpd/conf/httpd.conf
....
ServerName localhost:80
...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Ein erneuter Test:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;$ sudo rake spec
6 examples, 3 failures

Failed examples:

rspec ./spec/localhost/httpd_spec.rb:8 # Service &amp;quot;httpd&amp;quot; should be enabled
rspec ./spec/localhost/httpd_spec.rb:9 # Service &amp;quot;httpd&amp;quot; should be running
rspec ./spec/localhost/httpd_spec.rb:13 # Port &amp;quot;80&amp;quot; should be listening
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Nur noch 3 Failures. Als nächstes sollte der Service laufen und automatisch gestartet sein:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;$ sudo chkconfig --add httpd
$ sudo chkconfig --level 345 httpd on
$ sudo service httpd start
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Und so ist das Endresultat:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;sudo rake spec
/usr/bin/ruby -S rspec spec/localhost/httpd_spec.rb
......

Finished in 0.05298 seconds
&lt;span class=&quot;m&quot;&gt;6&lt;/span&gt; examples, &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt; failures
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Damit sind wir &amp;quot;green&amp;quot;.&lt;/p&gt;

&lt;h2 id=&quot;what&amp;#39;s-next?&quot;&gt;What&amp;#39;s next?&lt;/h2&gt;

&lt;p&gt;Jetzt können wir unsere Tests spezifizieren und auf einem konkreten Server ausführen.
Mit dieser Basis können wir spielen und neue Tests einbauen. Eine gute Übersicht dessen
was möglich ist, gibt die Seite &lt;a href=&quot;http://serverspec.org/resource_types.html&quot;&gt;Resource Types&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In einer etwas realistischeren Arbeitsumgebung
wird es aber viele Server geben, die sich in Gruppen einteilen lassen (Webserver,
  Applikationsserver, ...).
Und vermutlich haben wir mehrere Umgebungen (Test, Live, ...), die sich in
Teilen unterscheiden.&lt;/p&gt;

&lt;p&gt;All das lässt sich auch mit serverspec abdecken, die nächsten Posts zeigen, wie :-)&lt;/p&gt;

&lt;h2 id=&quot;&quot;&gt;&lt;/h2&gt;

&lt;p&gt;Andreas&lt;/p&gt;
</description>
                <link>/blog/2014/05/07/serverspec-standalone-betreiben</link>
                <guid>/blog/2014/05/07/serverspec-standalone-betreiben</guid>
                <pubDate>2014-05-07T00:00:00+02:00</pubDate>
        </item>

        <item>
                <title>serverspec: Server spezifizieren und testen</title>
                <description>&lt;p&gt;In der Softwareentwicklung sind Spezifikation und Testen fester Bestandteil des Arbeitsweise. Unit-Testing und
Test Driven Development haben in der modernen Entwicklung ihren festen Platz, ob agil oder nicht. Bei der
Bereitstellung von IT Infrastruktur, also Netzwerk, Storage und Compute sieht es dagegen noch eher klassisch
aus: Appliances und Server werden aufgebaut und übergeben, und wenn technische Einzelheiten nicht funktionieren,
wird nachgearbeitet.&lt;/p&gt;

&lt;p&gt;Bei der Bereitstellung von virtuellen Maschinen sieht es schon etwas besser aus. Hier haben Elemente aus der
Test Driven Infrastruktur Einzug gehalten. VMs entstammen entweder einem Image oder einer strukturierten Installation (z.B. Kickstart),
 und sie erhalten ihre Konfiguration über entsprechende Werkzeuge wie Salt, Ansible oder Puppet.&lt;/p&gt;

&lt;p&gt;Aber auch diese Werkzeuge benötigen ihre Konfigurationen, die - je nach Werkzeug - eher gecoded als &amp;quot;spezfiziert&amp;quot; aussehen.
Puppet als Beispiel bietet eine deklarative DSL, aber eine größere Puppetinstallation inkl. PuppetDB und/oder Hiera, Module und
deren Abhängigkeiten besitzt eine eigene Komplexität. Und die muss durch erfahrene Infra-Coder gemanaged werden.&lt;/p&gt;

&lt;h2 id=&quot;wie-soll-das-endergebnis-aussehen?&quot;&gt;Wie soll das Endergebnis aussehen?&lt;/h2&gt;

&lt;p&gt;An welcher Stelle in der Bereitstellungskette wird eigentlich genau beschrieben, &amp;quot;wie&amp;quot; das Endergebnis aussehen soll? Und mit
welcher Sprache?&lt;/p&gt;

&lt;p&gt;Ruby-Entwickler kennen mit rspec, cucumber und gherkin Möglichkeiten, (Code-)Funktionalität zu spezifizieren. Die sieht dann - je
nach verwendetem Framework - auch natürlich-sprachlich aus. Dasselbe gibt es nun auch für IT-Infrastruktur, im speziellen: Servern.&lt;/p&gt;

&lt;h2 id=&quot;serverspec&quot;&gt;serverspec&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;http://www.serverspec.org/&quot;&gt;Serverspec&lt;/a&gt; ist ein Werkzeug, um RSpec-Testfälle für Server formulieren und ausführen zu können. Dabei wird
das Endergebnis spezifiziert und getestet. D.h. es ist egal, mit welchem Konfigurationsmanagementtool ein Server aufgesetzt wurde oder
ob er sogar manuell installiert wurde, serverspec testet allein den aktuellen Zustand.&lt;/p&gt;

&lt;p&gt;Wie sieht so etwas aus? Ein paar Beispiele:&lt;/p&gt;

&lt;h4 id=&quot;es-sollten-user-da-sein.&quot;&gt;Es sollten User da sein.&lt;/h4&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;describe user &amp;#39;vagrant&amp;#39; do
  it { should exist }
  it { should belong_to_group &amp;#39;sudo&amp;#39; }
  it { should have_home_directory &amp;#39;/home/vagrant&amp;#39; }
end
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h4 id=&quot;dateien-sollten-vorhanden-sein,-mit-bestimmten-inhalten&quot;&gt;Dateien sollten vorhanden sein, mit bestimmten Inhalten&lt;/h4&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;describe file &amp;#39;/home/vagrant/.ssh/authorized_keys&amp;#39; do
  it { should be_file }
  it { should be_mode 600 }
  it { should contain(&amp;#39;vagrant@precise64&amp;#39;) }
  it { should be_owned_by &amp;#39;vagrant&amp;#39; }
  it { should be_grouped_into &amp;#39;vagrant&amp;#39; }
end
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h4 id=&quot;prozesse-sollten-laufen,-ports-sollten-offen-sein&quot;&gt;Prozesse sollten laufen, Ports sollten offen sein&lt;/h4&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;describe process &amp;#39;sshd&amp;#39; do
  it { should be_running }
end

describe port(22) do
  it { should be_listening.with &amp;#39;tcp&amp;#39; }
end
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;An den einfachen Beispielen lässt sich die Funktionsweise von serverspec gut zeigen. Eine Spezifikation besteht aus mehrere Blöcken, worin ein
bestimmter Aspekt (User, File, Process, Port, ...) beschrieben ist. Die Ausdrücke im Block selber findet sich sog. RSpec Expectations und
Matchers, d.h. Ausdrücke die für den jeweiligen Aspekt erfüllt sein sollen. Wie funktioniert nun das Testen selber?&lt;/p&gt;

&lt;h2 id=&quot;wie-arbeitet-serverspec?&quot;&gt;Wie arbeitet serverspec?&lt;/h2&gt;

&lt;p&gt;Serverspec kann je nach Modus unterschiedlich arbeiten: Lokal, per SSH auf einen entfernten Host oder z.B. mit Vagrant Plugins in eine virtuelle Maschine.
Dabei werden Kommandos zusammengebaut, um die &amp;quot;Rohdaten&amp;quot; einer Expectation abzufragen und gegen den Matcher zu prüfen. Das klingt eher abstrakt, von
daher ein konkretes Beispiel:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;describe file &amp;#39;/home/vagrant/.ssh/authorized_keys&amp;#39; do
  it { should be_mode 600 }
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Es soll also geprüft werden, ob die &lt;code&gt;authorized_keys&lt;/code&gt; den Mode 600 besitzt. Serverspec wird daraus diese Schritte bauen:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Eine Verbindung zum Ziel vorbereiten (z.b. per SSH)&lt;/li&gt;
&lt;li&gt;ein Kommando konstruieren, das für das Betriebssystem des Servers passt, also:

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;sudo stat -c %a /home/vagrant/.ssh/authorized_keys | grep -- \^600\$&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;das Kommando ausführen, das Ergebnis abholen und vergleich.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In diesem Fall wird vom &lt;code&gt;grep&lt;/code&gt; der Exitcode verwendet, die einfachste Möglichkeit. Bei anderen Abfragen können auch reguläre Ausdrücke eingesetzt werden.&lt;/p&gt;

&lt;p&gt;Und so sieht es aus, wenn man es ausführt:
&lt;code&gt;
/usr/bin/ruby -S rspec spec/node/simple_spec.rb
....
Finished in 0.95 seconds
4 examples, 0 failures
&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Das war jetzt ein kleines Beispiel, wie man mit serverspec Aspekte einer Serverinstallation spezifizieren und testen kann. Serverspec bietet aktuell
ca. 30 dieser Aspekte - genannt Resource Types - an, um vielfältige Dinge zu testen. Die Bandbreite reicht von Repositories, Prozessen, Netzwerk, Dateien,
User und Gruppen bis zu Mounts und Filesystemen.&lt;/p&gt;

&lt;h2 id=&quot;wofür-ist-das-gut?&quot;&gt;Wofür ist das gut?&lt;/h2&gt;

&lt;p&gt;Die Frage ist gar nicht so leicht zu beantworten, es hängt nämlich davon ab, was für ein Unternehmen man ist, und welcher Art von Einschränkungen man ggf. unterliegt.
Aber es gibt Mehrwert für fast alle Vorhaben. Die drei wichtigsten Gründe für die Verwendung von Tests in der Infrastruktur-Entwicklung sind:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Qualität&lt;/strong&gt;: Die Deployment Pipeline kann um eine zusätzliche Qualitätsstufe erweitert werden, die nicht nur die Artefakte auf dem Weg durch die Pipeline testet, sondern auch das Endergebnis.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Auditierbarkeit&lt;/strong&gt;: Zur Unterstützung eines IT-Audits lässt sich eine natürlichsprachliche Spezifikation der Serverlandschaft verfassen und automatisiert testen.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Regressionstest&lt;/strong&gt;: Auch Server lassen sich nun nach Veränderungen (z.B. Deployments oder anderen Changes) regressionstesten.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;wie-geht&amp;#39;s-weiter?&quot;&gt;Wie geht&amp;#39;s weiter?&lt;/h2&gt;

&lt;p&gt;Jetzt haben wir nur an der Oberfläche gekratzt, aber hoffentlich Interesse geweckt. Weitere Blogposts werden sich detailliert mit Serverspec befassen.&lt;/p&gt;

&lt;h2 id=&quot;&quot;&gt;&lt;/h2&gt;

&lt;p&gt;Andreas&lt;/p&gt;
</description>
                <link>/blog/2014/04/25/serverspec-server-spezifizieren-und-testen</link>
                <guid>/blog/2014/04/25/serverspec-server-spezifizieren-und-testen</guid>
                <pubDate>2014-04-25T00:00:00+02:00</pubDate>
        </item>

        <item>
                <title>Herzlich Willkommen zum Blog</title>
                <description>&lt;p&gt;Dies ist ein Blog über IT-Infrastruktur und den aufkommenden Trend &amp;quot;Infrastruktur
als Code&amp;quot;.&lt;/p&gt;

&lt;p&gt;Im Zuge der Virtualisierung und der Open Source Entwicklung werden viele Aspekte
von IT-Infrastruktur kontinuierlich erweitert und neu definiert. Komplexität und
Vielfält hinsichtlich Werkzeuge und auch der darunterliegenden Technologien
nehmen täglich zu.&lt;/p&gt;

&lt;p&gt;IT-Infrastrukturen werden auch nicht mehr manuell betrieben. Es entstehen
ablauffähige Prozeduren, die installieren, migrieren und prüfen. Diese
Pipelines sind in der Softwareentwicklung schon seit längerem bekannt, und dort
versuchen Entwickler schon seit mehr als 20 Jahren durch frühzeitiges Testen ein umfassenderes Feedback ihrer Änderungen
zu bekommen. Weitreichende Maßnahmen zur Qualitätssicherung gehören dort zum Standard.&lt;/p&gt;

&lt;p&gt;Wir müssen nun das Thema der Qualität auch in der Infrastrukturentwicklung neu definieren.&lt;/p&gt;

&lt;p&gt;Gerade die OpenSource Projekt sind hierbei ein wichtiger Motor für die
Verbreitung und Quelle der Inspiration mehr Qualität zu realisieren. Notwendigerweise
müssen sie deshalb grosse Teile ihrer Implementierungen konsequent testen. Ständige
Veränderungen, neue Teamkonstellation und
kurze Produktionszyklen bestimmt den Alttag. Qualitätsmängel werden von Kunden und
Produktverantwortlichen schnell entdeckt und wenig geschätzt.
Im Bereich der Infrastruktur betreten wir mit diesem Thema meist noch Neuland.&lt;/p&gt;

&lt;p&gt;In diesem Blog beginnen wir nun die testgetriebene Vorgehensweise für die Entwicklung
der Infrastruktur zu adaptieren. Hierbei werden wir bestehende Techniken, Werkzeuge und
Vorgehensweisen vorstellen und empfehlen.&lt;/p&gt;

&lt;p&gt;Viele Grüße und viel Spaß wünschen:&lt;/p&gt;

&lt;p&gt;Peter Roßbach&lt;/p&gt;

&lt;p&gt;Andreas Schmidt&lt;/p&gt;
</description>
                <link>/blog/2014/04/23/welcome</link>
                <guid>/blog/2014/04/23/welcome</guid>
                <pubDate>2014-04-23T00:00:00+02:00</pubDate>
        </item>


</channel>
</rss>
