Marcelo Emmerich's Picture

Marcelo Emmerich

11 posts

X11 App aus nativem Docker Container auf dem Mac ausführen

Seit geraumer Zeit steht eine Beta Version eines nativen Docker Clients für Mac zur Verfügung, der den Umweg über boot2docker oder sonstige Linux VMs überflüssig macht. Wir nutzen Docker auch, um grafische Anwendungen zu entwickeln. Nun stellt sich die Frage, wie wir eine Anwendung, die einen X11 Server benötigt, von einem nativen Docker Container auf dem Mac darstellen können. In der Vergangenheit haben wir diverse Variationen dieser Aufgabenstellung umgesetzt:

  • Lokale X11 Linux VM, Display auf MacOS oder lokal in der VM
  • Lokale Headless Linux VM, Display auf MacOS
  • Remote Headless Linux VM, Display auf MacOS
  • Remote Headless Linux VM, Display auf Windows 10
  • ...

Nun kommt eine neue Variante dazu:

  • Lokaler native Docker Container, Display auf MacOS

Aus den Erfahrungen der anderen Varianten haben wir gemutmaßt, daß es reichen könnte XQuartz auszuführen und die DISPLAY Umgebungsvariable zu übergeben. Leider wird das mit einem Fehler quittiert, da der Docker Client nicht auf den XQuartz Socket zugreifen kann:

$ docker run --rm -it --net=host -e DISPLAY test/xterm
xterm: Xt error: Can't open display: /private/tmp/com.apple.launchd.TFUw2s0Mer/org.macosforge.xquartz:0  

Auch andere Versuche, den XQuartz Socket als Unix X-Socket über ein Volume Mount einzubinden sind fehlgeschlagen. Also haben wir und für einen Umweg entschieden, bis wir eine bessere Lösung finden oder seitens Docker oder XQuartz entsprechende Änderungen implementiert werden: wir nutzen das Tool socat, um den XQuartz Socket über den X11 Default-Port umzuleiten. Dem Docker Container reicht dann die DISPLAY Umgebungsvariable, um X11 Anwendungen anzeigen zu können. Die Lösung sieht wie folgt aus (Annahme: XQuartz läuft schon):

$ brew install socat
...
$ socat TCP-LISTEN:6000,reuseaddr,fork UNIX-CLIENT:\"$DISPLAY\" &
$ docker run --rm -it --net=host -e DISPLAY=192.168.178.20:0 test/xterm

Wobei 192.168.178.20 meine aktuelle IP im internen Netz ist.

Node.js Module mit JSDoc dokumentieren

Das Revealing Module Pattern ist eine bewährte Methode, um JavaScript-Code zu kapseln und eine private Implementierung hinter einer definierten öffentlichen Schnittstelle zu verbergen. In diesem Artikel werde ich zeigen, wie man das Revealing Module Pattern in Node.js verwendet und wie man so ein Modul mit http://usejsdoc.org/.

Als ersten Schritt implementieren wir ein generisches Modul nach den Richtlinien des Revealing Module Pattern:

var katzenModul = (function () {  
    var privaterName = 'kitty';

    function publicGetName(){
        return privaterName;
    }

    return {
        getName : publicGetName
    };
})();

katzenModul.getName();  

Dieses Modul definiert eine Funktion publicGetName(), die nach aussen als getName deklariert wird. Der Name der Katze ist privat und kann nicht von aussen zugegriffen werden, wie die entsprechenden Tests beweisen:

describe('katzenModul', function() {

  it('should return the name of the cat', function() {
      var name = katzenModul.getName();
      assert.equal(name, 'kitty');
  });

  it('should not allow access to private variables', function() {
      assert.equal( undefined, katzenModul.privaterName );
  });

  it('should not allow access to private functions', function() {
      assert.equal( undefined, katzenModul.publicGetName );
  });
});

Als nächstes machen wir aus unserem generischen Modul ein Node-Modul:

var katzenModul = (function () {  
    var privaterName = 'kitty';

    function publicGetName(){
        return privaterName;
    }

    return {
        getName : publicGetName
    };
})();
module.exports = katzenModul;  

Durch die letzte Zeile module.exports = katzenModul; haben wir unser Modul Node.js bekannt gemacht. Nun können wir das Modul z.B. wie folgt verwenden:

var katzenModul = require('./katzenModul');

console.log( katzenModul.getName() );  

Ein weiterer Vorteil des Revealing Module Pattern ist, dass es sich sehr gut eignet, um Dokumentation zu schreiben, ohne die Lesbarkeit des Codes zu beeinträchtigen. Der Grund dafür ist, dass die Dokumentation der "öffentlichen" Schnittstelle eines solchen Moduls am Ende der Datei steht und nicht den eigentlichen Code "verunreinigt". So sieht z.B. eine dokumentierte Version von katzenModul aus:

/**
 * @description Dieses Module liefert Katzennamen
 * @module katzenModul
 * @author Marcelo Emmerich
 */
var katzenModul = (function () {  
    var privaterName = 'kitty';

    function publicGetName(){
        return privaterName;
    }

    return {
        /**
         * @function
         * @description Liefert den Namen der Katze
         * @memberof module:katzenModul
         * @returns {String} Den Namen der Katze als String
         */
        getName : publicGetName
    };
})();
module.exports = katzenModul;  

Zuerst habe ich das Modul als solches mit dem JSDoc Tag @module definiert, um es später referenzieren zu können. @author und @description sind vermutlich selbst erklärend, also schauen wir uns die interessanteren Tags an. Die Funktion getName ist mit @function markiert. Das ist deswegen notwendig, weil der JSDoc Parser sonst nicht mit der Syntax des Revealing Module Pattern klar kommt und die Funktion nicht als solche erkennt. Weiter müssen wir JSDoc auch damit auf die Sprünge helfen, die Funktion getName als zum Modul katzenModul zugehörig anzuerkennen. Das erreichen wir mit dem @memberof module:<Modulname> Tag. Wenn wir nun mit JSDoc die Dokumentation erzeugen, wird unser Modul als solches aufgeführt und die Funktion getName korrekt referenziert.

Agil, Extrem oder doch Anarchisch?

In einen Interview von 2015 16: Kent Beck - Tiny Decisions and Emergent Design bin ich auf eine sehr interessante Aussage von Kent Beck (Extreme Programming Erfinder, Mitunterzeichner des Agilen Manifests und Autor von JUnit) gestossen. Er erklärte, dass er damals, als die Agile Bewegung begann, mit dem Begriff "agil" nicht glücklich gewesen sei, denn dieser sei zu gefällig. Wer kann denn schon (im generischen Sinne des Wortes) nicht agil sein wollen? Das Wort sei schliesslich nur positiv belegt.

Das ist sicher einer der Faktoren, die dazu geführt haben, dass so viele Organisationen auf den agilen Zug aufgesprungen sind, ohne wirklich hinter der Idee zu stehen. Deswegen sehen wir in der täglichen Praxis so viele Projekte, die nach "WaterScrumFall" durchgeführt werden. Hauptsache man ist agil.

Kent Beck wählte den Begriff "Extreme Programming" für seinen agilen Ansatz. Er argumentiert, dass nicht jeder automatisch "extrem" sein möchte. Das führt dazu, dass die Wahrscheinlichkeit höher ist, dass man entweder ganz oder gar nicht hinter der Sache steht.

In letzter Zeit beschäftigen wir uns bei der Pulsar mit post-agilen Ansätzen. Einer dieser Ansätze, der maßgeblich von Fred George geprägt wurde, ist Programmer Anarchy. Hier findet sich schon im Namen das, was Kent Beck damals angemerkt hatte. Nicht jeder assoziiert "anarchisch" mit etwas positivem. Das erhöht die Wahrscheinlichkeit, dass man wirklich dahinter steht, sollte man sich für diesen Weg entscheiden.

Wir werden uns weiter mit Programmer Anarchy und anderen post-agilen Ansätzen beschäftigen und unsere Erkenntnisse hier posten.

Scrum ist nicht agil

Zugegeben, der Titel ist ein wenig provokant. Das soll es aber auch, denn ich möchte damit ein Gefühl zum Ausdruck bringen, das mich schon lange beschleicht. Der Ausschlag gebende Anstoß für diesen Artikel kam, als ich mich selbst in folgender Situation befand: Wir waren mitten im Sprint und der Kunde wünschte dringend die Umsetzung einer bestimmten Funktionalität. Meine fast schon automatische Antwort darauf war:

wir sind mitten im Sprint. Während des Sprints ändert sich der Scope nicht. Gerne nehmen wir die Anforderung auf und priorisieren diese im kommenden Sprint entsprechend.

Ich fühlte mich schlecht dabei, wusste aber in diesem Moment nicht genau warum. Erst später kam ich darauf: ich hatte den Prozess höher gewertet als den Kunden und unsere Interaktion. Ich hatte eine wichtige Anforderung künstlich um 2 Wochen verzögert, nur weil der Prozess es so will. Immerhin sind wir in der Lage, Änderungen innerhalb von 10 Minuten auf Produktion zu deployen. Mir wurde schlagartig klar, dass das nur die Spitze des Eisbergs war. Immer mehr Episoden dieser Art aus vergangenen Projekten schossen mir auf einmal durch den Kopf, so dass mir letzendlich klar wurde, Scrum ist nicht agil.

Selbstverständlich kann ich eine solche Aussage nicht lediglich auf der Basis eines Gefühls oder eines einzelnen Beispieles postulieren. Glücklicherweise können wir bei Pulsar Solutions auf eine recht umfangreiche Projekt-Historie zurückgreifen. Hier finden sich hauptsächlich Projekte, die nach Scrum entwickelt worden sind. Mit anderen Worten, die hier vorgestellten Erkenntnissen basieren auf empirische Daten, gesammelt aus den Erfahrungen von ca. 10 Jahren Projektgeschäft.

Bevor ich erkläre, warum Scrum nicht agil ist, sollten wir definieren, was agil ist. Aus unserer Sicht ist ein Team (oder eine Organisation) dann agil, wenn es sich an die Werteverteilung hält, die im Agilen Manifest beschrieben worden ist. Hier die Werte des Agilen Manifests:

Wir erschließen bessere Wege, Software zu entwickeln, indem wir es selbst tun und anderen dabei helfen. Durch diese Tätigkeit haben wir diese Werte zu schätzen gelernt:

  • Individuen und Interaktionen mehr als Prozesse und Werkzeuge
  • Funktionierende Software mehr als umfassende Dokumentation
  • Zusammenarbeit mit dem Kunden mehr als Vertragsverhandlung
  • Reagieren auf Veränderung mehr als das Befolgen eines Plans

Das heißt, obwohl wir die Werte auf der rechten Seite wichtig finden, schätzen wir die Werte auf der linken Seite höher ein.

Gehen wir die einzelnen Werte der Reihe nach durch und schauen wir, ob diese in der Praxis so gelebt werden oder nicht:

Individuen und Interaktionen mehr als Prozesse und Werkzeuge

Leider ist unsere Erfahrung, dass in der Praxis das Gegenteil der Fall ist. Insbesondere das Thema Prozesse hat einen extrem hohen Wert gegenüber Individuen und Interaktionen. Ohne Rücksicht auf Verluste muss der Prozess eingehalten werden. Dafür ist der Scrum Master schliesslich da, um den Prozess einzuhalten... Aber woher kommt diese Verschiebung der Werte? Aus unserer Erfahrung gibt es dafür zwei Gründe. Zum Einen geht es bei Scrum um viel Geld. Es werden Zertifizierungen verkauft. Es werden zertifizierte Mitarbeiter - entschuldigung: Consultants - verkauft. Es werden Tools, Schulungen, usw. verkauft. Dass diese Zertifizierungen meistens das Papier nicht Wert sind, auf das Sie gedruckt sind, weil sie nach einem 2-Tages-Workshop vergeben werden, interessiert offenbar niemand.
Der andere Grund, warum der Prozess meistens so vehement umgesetzt wird, hat mit Conway's Gesetzt zu tun. Dieses besagt:

Organisationen, die Systeme entwerfen, […] sind auf Entwürfe festgelegt, welche die Kommunikationsstrukturen dieser Organisationen abbilden.

Nun sehen sich solche Unternehmen aber in einem Konflikt, weil es zwei Kräfte gibt, die an diesen Strukturen rütteln. Zum Einen wollen die meisten Mitarbeiter von IT Abteilungen nach modernen Methoden arbeiten. Es gibt also Druck von unten. Zum Anderen wird solchen Unternehmen verkauft, dass man mit agilen Methoden viel Geld sparen kann. Wie können diese Unternehmen also die Vorteile nutzen, ohne das Unternehmen selbst in eine agile Organisationsform umzugestalten? Das würde ja den Verlust von Kontrolle und Hierarchien bedeuten. Zum Glück gibt es Scrum! In der Organisation kann alles beim Alten bleiben, an der Grenze zur "agilen" IT steht ja ein Product Owner der als Schnittstelle zwischen Entwicklung und Stakeholder steht und übersetzen muss. Und zum Glück gibt es ein Backlog mit 500 User Stories, die schon vor Projektbeginn in einer Initialbefüllung für eine Aufwandsabschätzung herangezogen wurden. Man möchte ja wissen was der Spaß kosten wird, agil hin oder her.
Ich könnte die ironischen Spitzen immer weiter treiben, aber ich glaube die Idee ist klar geworden. Scrum ist mittlerweile nur noch ein Vehikel, um nicht agilen Unternehmen einen Prozess zu verkaufen, der zwar auch nicht wirklich agil ist, aber so klingt und mit dem man Ausgaben rechtfertigen kann.

Funktionierende Software mehr als umfassende Dokumentation

Ursprünglich bezog sich dieser Satz darauf, dass Entwickler zu viel Zeit mit der Erstellung von Dokumentation verbracht haben, anstatt zu entwickeln. Dieser Umstand hat sich heute etwas verändert, aber auch hier hat Scrum dazu geführt, dass sich die Werteverteilung umgekehrt hat. In Scrum-Projekten ist es mittlerweile Usus, dass die ersten Sprints nichts brauchbares Produzieren und dazu dienen, die "Werte" einzupendeln. Mit Werte sind hier Metriken gemeint, die gerne in KPI Dashboards Management-gerecht auf Knopfdruck generiert werden können. Velocity, Burn Down Chart, Defect Fix Rate und etliche mehr. Weiter wird meistens ein Wiki aufgesetzt, wo sich Definition of Done befinden, Richtlinien für die Nutzung der Sourcecode-Verwaltung, Leitfaden für effektive Stand-up Meetings, Ablaufplan des Sprint Reviews, der Grooming Session, der Retrospektive, des Sprint-Pre-Plannings usw. Weiter werden die Ergebnisse, Protokolle und Notizen dieser Meetings fest gehalten. Das ist alles Dokumentation. Und in all der Zeit, die damit verbracht wird, wird keine eizige Zeile Code geschrieben und an den Kunden ausgeliefert.

Zusammenarbeit mit dem Kunden mehr als Vertragsverhandlung

Sprints bzw. die für einen Sprint zugesicherten Story Points, die Velocity, das (hoffentlich) als Business-Value formulierte Sprint-Ziel sowie die Capacity der Teammitglieder während eines Sprints. Das sind alles Verträge. Nicht im klassischem Sinne, aber dennoch Verträge. Je größer die Organisation um so mehr wird auf diese Indikatoren geachtet, mit dem Resultat, dass wir an Agilität verlieren. Die folgende Situation dürfte jedem bekannt vorkommen, der schon mal in einem Scrum Team gearbeitet hat. Mittem im Sprint taucht ein Problem auf, der eigentlich erfordern würde, dass die Arbeit sofort gestoppt wird und erstmal mit dem Kunden Rücksprache gehalten wird. Selbst wenn der Impuls da ist, sitzen einem dann automatisch die Scrum-Teufelchen auf der Schulter, die sagen: "wenn du jetzt nicht weitermachst wird die Velocity sinken" oder "mach einfach weiter, sonst schaffst du nicht die von dir zugesicherten Story Points". Das Problem wird also erstmal ignoriert, kommt aber erfahrungsgemäss trotzdem raus. Dann gibt es Diskussionen mit dem Kunden darüber, ob die Story angenommen werden kann oder nicht, wie viel zusätzlicher Aufwand das beim nächsten Sprint generiert, usw. Also Vertragsverhandlungen anstelle von Zusammenarbeit mit dem Kunden.

Reagieren auf Veränderung mehr als das Befolgen eines Plans

In Scrum muss der Plan befolgt werden. Wenn die Arbeit für die nächsten 2, 3 oder 4 Wochen fest steht, werden Veränderungen entweder ausgeblendet oder auf den nächsten Sprint geschoben. Auch hier gilt, nur die Definition dessen was ein Plan ist, hat sich verändert seitdem das Manifest geschrieben wurde. Die Werte aber sind geblieben. Ein Sprint ist ein Plan. Zwar nicht für 3 Jahre, sonder nur für 3 Wochen, aber trotzdem ein Plan. Stellen wir diesen Plan über die Fähigkeit, auf Änderungen zu reagieren, sind wir nicht agil.

Und was nun?

Die Frage ist an dieser Stelle natürlich mehr als berechtigt. Was sollen wir statt dessen tun? Die Antwort darauf ist ein klares "kommt darauf an". Jede Organisation und jedes Team ist anders. Für manche Organisationen ist Scrum mit all den Problemen, auf die ich hier aufmerksam gemacht habe, trotzdem besser als das was davor praktiziert wurde. Andere wiederum würden extrem davon profitieren, sich von Scrum zu lösen. Auf verschiedene Fälle, die wir beobachtet haben, werden wir in kommenden Artikel detaillierter eingehen. Grundsätzlich ist es aber sicher nicht verkehrt, bei der täglichen Arbeit im Rahmen von Scrum (oder anderen agilen Methoden) sich einfach die Werte des Agilen Manifests bewusst zu sein und ggf. Dinge zu hinterfragen, wenn die Vermutung nahe liegt, dass eine Werteumkehrung statt findet.

libVLC Entwicklungsumgebung als Docker Container ohne Qt4

Entwickler komplexer Projekte müssen oft Open-Source Bibliotheken einbinden. Insbesondere in der nativen Entwicklung können diese Bibliotheken eine hohe Anzahl an Abhängigkeiten haben. Diese Abhängigkeiten können sowohl in Form von weiteren Bibliotheken, Tools oder sogar ganze Programmiersprachen auftreten. Ein gutes Beispiel hierfür ist libVLC. libVLC ist die Bibliothek, auf die der populäre VLC Player aufgebaut ist. Als Entwickler kann man libVLC nutzen, um Audio und Video in eigenen Anwendungen abzuspielen.

Wichtig! Die folgenden Ausführungen setzen ein voll funktionsfähiges Linux mit X-Server und aktueller Docker (v1.9.1) Installation voraus.

In einem aktuellen Projekt hatten wir die Aufgabe, eine reproduzierbare Entwicklungsumgebung zu schaffen, auf deren Basis wir eine komplexe Qt5 Anwendung unter Linux implementieren wollten, die unter anderem Videos abspielen sollte. Das stellte uns vor zwei Herausforderungen:

  • wie können wir eine reproduzierbare Entwicklungsumgebung mit einer definierten Version von libVLC schaffen, und trotzdem den Entwicklern die Freiheit lassen, mit ihren bevorzugten Tools und Editoren zu arbeiten?
  • libVLC bindet Qt4 ein. Wir nutzen Qt5. Es ist bekannt, dass sich Qt4 und Qt5 im selben Projekt nicht nebeneinander ausführen lassen, ohne dass es Probleme zur Laufzeit gibt. Wie können wir also eine libVLC Version ohne Qt4 bauen?

Für die erste Herausforderung war eine Lösung relativ schnell gefunden. Wir haben ein Docker Image erstellt, das eine Basis Ubuntu Distribution mit der zu diesem Zeitpunkt aktuellen Version 2.2.1 von libVLC und allen nötigen Tools und Abhängigkeiten enthält. Die Idee ist, dass man als Entwickler den entsprechenden Container lokal ausführt und über einen Volume Mount sein Sourcecode mit dem Container teilt und baut. Somit kann das Editieren des Codes und das Arbeiten mit git und anderen Tools wie gewohnt auf dem lokalen Rechner statt finden. Nur zum Bauen muss der Container bemüht werden.

Das Qt4 Problem haben wir gelöst, indem wir einen Patch in libVLC während der Erstellung des Docker Images eingebaut haben, der zu einer Version von libVLC ohne Qt4 führt. Entgegen anfänglicher Bedenken ist das unproblematisch, weil Qt4 hauptsächlich für Benutzeroberflächen von Plugin-Einstellungen und ähnliches verwendet wird. Da wir libVLC lediglich einbinden und unsere eigene UI entwickelt haben, ist es für uns kein Problem, auf diese Funktionen zu verzichten.

Im Folgenden werde ich zeigen, wie man ein minimales C Programm, das eine Mediendatei mit libVLC wiedergibt, mit dem Image kompilieren und linken kann.

Das Image befindet sich auf unserem öffentlichen Repository, von dort können wir es erst einmal mittels pull auf unserem lokalen Rechner ziehen:

docker pull pulsarsolutions/libvlc_no_qt:2.2.1  

Und dann interaktiv ausführen:

docker run --rm -it pulsarsolutions/libvlc_no_qt:2.2.1 bash  

Nach dem o.g. Befehl sollte man sich in einer bash Shell im Container befinden. Damit kann man allerdings noch nicht viel anfangen, da es gar keinen Sourcecode zum kompilieren gibt. Das ändern wir jetzt. Wir gehen wieder aus dem laufendem Container indem wir

exit  

eingeben. Als nächstes legen wir ein neues Verzeichnis an

mkdir /home/marcelo/projects/vlc_minimal_sample  

und erzeugen dort eine neue C-Quelldatei test.c mit folgendem Inhalt:

#include <stdio.h>
#include <stdlib.h>

#include <vlc/vlc.h>

int main(int argc, char **argv)  
{
    libvlc_instance_t *inst;
    libvlc_media_player_t *mp;
    libvlc_media_t *m;

    // load the vlc engine
    inst = libvlc_new(0, NULL);

    // create a new item
    m = libvlc_media_new_location(inst, "http://www.sample-videos.com/video/mp4/360/big_buck_bunny_360p_5mb.mp4");

    // create a media play playing environment
    mp = libvlc_media_player_new_from_media(m);

    // no need to keep the media now
    libvlc_media_release(m);

    // play the media_player
    libvlc_media_player_play(mp);

    getchar();

    // stop playing
    libvlc_media_player_stop(mp);

    // free the media_player
    libvlc_media_player_release(mp);

    libvlc_release(inst);


    return 0;
}

Das Programm ist eine minimalistische Implementierung einer Videowiedergabe mit libVLC. Das Video wird direkt aus dem Internet abgespielt, daher sollte der Host, also die Maschine auf der der Container gestartet wird, auch mit dem Internet verbunden sein.

Unser Ziel ist es, diese Datei nun im laufenden Container zu kompilieren und zu linken, denn nur im Container sind die dafür nötigen Tools, Bibliotheken und Abhängigkeiten installiert. Um die Datei dem Container bereitzustellen verwenden wir einen sog. Volume Mount. Das bedeutet, dass ein lokales Verzeichnis (Volume) in ein Verzeichnis im Container gemounted wird. Damit sieht unser docker Aufruf jetzt so aus:

docker run --rm -it -v /home/marcelo/projects/vlc_minimal_sample/:/home/developer/src pulsarsolutions/libvlc_no_qt:2.2.1  

Damit wird das lokale Verzeichnis /home/marcelo/projects/vlcminimalsample auf das Verzeichnis /home/developer/src im Container gemounted. An dieser Stelle sei darauf hingewiesen, dass der Container einen Default-Benutzer namens developer anlegt. Dieser Benutzer hat die id 1000 und gehört einer Gruppe die ebenfalls die id 1000 hat. Wenn der lokale Benutzer auf dem Host eine andere Kombination von uid:gid hat, kann es zu einem Rechteproblem kommen. In einem zukünftigen Artikel werde ich beschreiben, wie man damit umgehen kann.

Nachdem wir den o.g. Befehl ausgeführt haben, können wir cd src im Container in das Verzeichnis wechseln, in das unsere Quelldatei liegt. Nun können wir diese wie folgt übersetzen:

gcc $(pkg-config --cflags libvlc) -c test.c -o test.o  
gcc test.o -o test $(pkg-config --libs libvlc)  

Im Anschluss daran sollte eine ausführbare Datei test im aktuellen Verzeichnis liegen. Mit

./test

kann die Datei ausgeführt werden. Da wir uns in der Kommandozeile befinden werden wir aber nicht viel zu sehen bekommen, die Shell wird höchstens versuchen, das Video im Text-Modus zu rendern. Als letzten Schritt in diesem Artikel werden wir nun die Ausgabe des Containers auf den lokalen X-Server im Host umleiten, so dass wir das Video-Fenster auch sehen können.

Das geschieht mit einem weiteren Volume Mount und der Übergabe der DISPLAY Umgebungsvariable und sieht dann so aus:

docker run --rm \  
  -v --net=host \
  -e DISPLAY -v \ /home/marcelo/projects/vlc_minimal_sample/:/home/developer/src \
  -it pulsarsolutions/libvlc_no_qt:2.2.1 bash

Indem wir die DISPLAY Umgebungsvariable sowie die Option --net=host verwenden, kann der Docker Container auf den X Server und somit auf das Display zugreifen.

Die Option --net=host stellt auf Produktivsystemen ein Sicherheitsrisiko dar, da es im Grunde das Netzwerk des Containers nicht kapselt. Daher sollte diese Option nur für lokale Umgebungen verwendet werden, die man selber kontrolliert.

Wenn wir nun

./test

ausführen, sollte das Video in einem neuen Fenster im Host abgespielt werden.

Das war nur ein kurzer Einblick in die Möglichkeiten die Docker bietet, um reproduzierbare Entwicklungsumgebungen bereit zu stellen. Aus Platzgründen sind hier viele Themen nicht erwähnt worden, wie z.B. Audio oder IDEs. Das wird dann Gegenstand zukünftiger Artikel sein.