Erste Schritte mit Git für lokale und zentrale Repositories unter Eclipse – II

Im letzten Blog-Post

Erste Schritte mit Git für lokale und zentrale Repositories unter Eclipse – I

hatte ich ein einfaches Szenario beschrieben, das regelmäßige Wechsel zwischen mobiler und ortsgebundener Entwicklungsarbeit beinhaltet und gerade im Leben von Freiberuflern immer wieder auftritt. Versionskontrolle erfordert im Zuge solcher Wechsel das Arbeiten mit lokalen und zentralen Repositories sowie systematische Abgleichoperationen zwischen solchen Repositories. Git ist für derartige Szenarien gut geeignet. Um entsprechende Experimente durchführen zu können, haben wir im letzten Post unser einfaches Wunschszenario in durchzuführende logische Schritten untergliedert.

Unser Ziel ist nun eine Abbildung der identifizierten Schritte in eine Git-Versionsverwaltung unter der IDE Eclipse. Daraus ergaben sich konkrete Aufgabenstellungen für Tests. In diesem Post befassen wir uns mit den ersten drei der identifizierten Aufgaben:

  • Aufgabe 1: Erstellen eines lokalen Git-Repositories auf dem PC.
  • Aufgabe 2: Klärung: Wo liegt der “Working Tree”? Welchen Verzeichnisbaum zeigt Eclipse?
  • Aufgabe 3: Einbringen des Inhalts des Projektverzeichnisbaums in den Master-Branch des lokalen Repositories. Initiales Commit.

Ich setze für das Verständnis der nachfolgenden Ausführungen einige Begrifflichkeiten voraus, die ich im letzten Blog-Post dieser Serie erläutert habe. Da es sich hier um einen Linux-Blog handelt beschreibe ich alle Schritte zur Lösung der Aufgaben für eine Linux/Eclipse-Umgebung, Linux-Verzeichnisbäume und, soweit erforderlich, Linux-Shell-Kommandos. Vermutlich lässt sich das Meiste aber auch direkt auf eine MS-Umgebung übertragen.

Abgrenzung “Eclipse Workspace” versus “Git Workspace”

In deutschsprachigen Büchern zu Git ist oft die Rede von einem (Git-) “Workspace”. Andererseits gibt es aber auch unter Eclipse “Workspaces”. Diese sollten wir im Folgenden begrifflich auseinanderhalten:

  • Eclipse Workspace: Ein Eclipse Workspace verwaltet eine Ansammlung von mehreren Projekten und zugehörige Dateien in projektspezifischen Verzeichnissen. Für den gesamten Eclipse Workspace können verschiedene grundlegende Eclipse-Eigenschaften (Settings) projektübergeordnet eingestellt werden. Ich kürze einen Eclipse-Workspace nachfolgend mit EWS ab. Ein EWS ist regelmäßig mit einem zugehörigen Verzeichnis verbunden. Das schließt aber definierte Links in weitere zugeordnete Verzeichnisse nicht aus. Im Besonderen müssen die Projektdateien nicht zwingend in einem Verzeichnis unterhalb des Workspace-Verzeichnisses beheimatet sein. Die EWS-spezifischen Eclipse-Einstellungen werden jedoch in versteckten Dateien/Unterverzeichnissen des EWS-Verzeichnisses hinterlegt. Solche speziellen Dateien/Verzeichnisse eines EWS wird man später nicht unbedingt in einem GIT-Repository erfassen wollen, da sie typischerweise Anweisungen beinhalten, die für eine Eclipse-Version spezifisch sind; ein abgleichender Transfer auf ein anderes System mit einer älteren Eclipse-Version könnte dann zu Problenmen auf der Eclipse-Ebene führen.
  • Git-Workspace: Ein Git-Workspace bezieht sich auf Dateien einer Verzeichnisstruktur, deren Änderungshistorie in einem Git-Repository im Sinne einer Versionierung aufgezeichnet und verwaltet wird. Ich kürze nachfolgend einen Git-Workspace mit GWS ab. Ein GWS besteht typischerweise aus einem reinen Repository-Bereich unterhalb eines speziellen Verzeichnisses “.gitund einem sog. “Working
    Tree
    “, dessen Dateien eine definierte Code-Version auf einem Entwicklungs-“Branch” (-Zweig) beinhalten. Auf der Eclipse-Ebene entspricht der Working-Tree typischerweise der Verzeichnis-Struktur eines Projektes mit den dazu gehörigen aktuellen Code-Dateien.

Vorbereitende Schritte

Bevor wir uns an die Lösung unserer Aufgaben machen, müssen wir je nach Ausgangssituation ein paar vorbereitende Schritte treffen. Für diese und auch für nachfolgende Aktionen gilt:

Wir legen uns vorab immer eine Sicherheitskopie des gesamten EWS und ggf. auf Datei- oder Ordnerebene verlinkter anderer Eclipse Workspaces an. Ferner sichern wir vor Experimenten mit Dateien eines realen Projekts evtl. existierende SVN-Repositories, die mit diesem Projekt verbunden sein mögen.

Vorbereitender Schritt 0 – Git und das Eclipse EGit-Plugin installieren

Auf unserem Linux-PC installieren wir zunächst das für die jeweilige Distribution verfügbare Git-Paket. Wir erhalten damit u.a. auch Zugriff auf CLI-Kommandos, die im Zuge der Repository-Verwaltung eingesetzt werden können. Die Kenntnis solcher Kommandos ist übrigens nützlich, auch wenn man – wie ich – grafisch Bedien-Elemente einer IDE verwenden will. (Man kann unter Linux eine Git-basierte Versionsverwaltung von Projekten auch ausschließlich auf der Kommandozeile betreiben.) Wer Lust hat, kann neben Git selbst gleich auch noch die Pakete “gitg”, “Qgit”, “Giggle” und ggf. auch “git-cola” oder “cola-git” installieren. Jedes dieser Pakete bietet eine eigene unabhängig von Eclipse nutzbare GUI für Git mit mehr oder weniger Komfort und Funktionalität an.

Für Eclipse selbst gibt es ein Git-Plugin namens EGit (welches wiederum JGit benötigt). EGit sollte im Haupt- oder Update-Repository der jeweiligen Eclipse-Installation (hier Neon 3) in einer passenden Version verfügbar sein. Für den aktuellsten Stand greift man auf folgendes Eclipse-Repository zu:

http://download.eclipse.org/egit/updates.

Von dort können wir EGit genauso wie andere Eclipse Plugins auch installieren. Je nachdem, ob man vor hat, später auch externe GitHub-Dienste zu nutzen und/oder Mylyn einzusetzen, kann die Installation weiterer Plugins von Interesse sein. Das folgende Bild zeigt, welche Git-bezogenen Pakete ich selbst unter einem aktuellen Eclipse Neon 3 installiert habe:

Ich gehe auf die relativ trivialen Installationsschritte unter Linux/Eclipse nicht näher ein. Siehe bei Bedarf aber:
http://www.vogella.com/ tutorials/ EclipseGit /article.html #installation-of-git-support-into-eclipse
https://www.eclipse.org/ forums/ index.php/ t/273443/

Vorbereitender Schritt 1 – Lösen eines PHP-Projektes von seiner SVN-Anbindung

Das nachfolgende Bild zeigt die relativ simple Verzeichnis und Projektstruktur eines EWS namens “ecl_alienx”; das zugehörige Verzeichnis auf dem Linux-PC ist “/projekte/ecl_alienx”.

Das dortige Test-Projekt “alien1” und seine Verzeichnisse/Dateien sind unterhalb des Ordners “/projekte/ecl_alienx/alien1” beheimatet. Eclipse-Puristen würden diese Ortswahl für die Programmdateien mit einiger Berechtigung kritisieren. Das ist uns hier aber egal; es wird sich sowieso gleich ändern.

Den Bildinformationen entnehmen wir: Das Projekt ist offenbar noch mit einem Subversion-SVN-Repository verbunden. Wir lösen diese SVN-Verbindung nun über den Disconnect-Befehl, den wir unter dem Kontexmenüs des Projektes finden: => “Team => Disconnect”.

Dabei löschen wir auch die SVN-Metainformation in den “.svn”-Dateien jedes Projekt-Verzeichnisses. Das ist zwar nicht zwingend erforderlich; ich möchte bei den nachfolgenden Git-Experimenten aber keinen SVN-Ballast mit mir rumschleppen. (Das SVN-Repository selbst wird bei dieser Aktion übrigens nicht gelöscht).

Unser Projekt ist jetzt unbelastet von jeglicher Versionsverwaltung.

Für die weiteren Schritte lohnt es sich, den ViewGit Repositories” (z.B. im unteren Bereich des Eclipse Desktops) permanent geöffnet zu halten. Dieser View ist anfänglich natürlich noch leer; bei späteren Git-Aktionen ist ein kontrollierender Blick in diesen View immer informativ und hilfreich. Öffnen kann man den View über den Eclipse Menüpunkt “Window => Show View => Others => Git => Git Repositories”.

Lösung der Aufgabe 1 – Erstellen eines lokalen Repositories

Als erstes erstellen wir mittels einer Shell oder einem Dateimanager außerhalb des EWS ein Verzeichnis für unseren künftigen GWS inkl. eines lokalen GIT-Repositories. In meinem Testfall etwa unter “/projekte/GIT/alien1“. Dann öffnen wir das Kontext-Menü unseres Projektes erneut und wählen den Punkt “Team => Share Project“:

Im nächsten Dialogfenster klicken wir auf den “Create“-Button und geben im nachfolgenden Subdialog den vorgesehenen Zielort des Repositories an:

Achtung:
Das Bild deutet bereits an, dass EGit deutlich mehr vor hat, als nur ein Git-Repository anzulegen. Vielmehr sollen alle Unterverzeichnisse unseres Projektes in eine Verzeichnisstruktur im Targetverzeichnis “/projekte/GIT/alien1” umgezogen werden. Wir werden gleich sehen, dass dadurch der sog. “Working Tree” unter dem Directory “/projekte/GIT/alien1/alien1/” im Workspace angelegt wird; der Working Tree besteht initial also aus den ursprünglichen Projekt-Verzeichnissen und -Dateien des EWS.

Im Targetverzeichnis “/projekte/GIT/alien1” wird parallel auch das eigentliche Git-Repository als Teil des GWS angelegt. Die erforderlichen Repository-Strukturen (Unter-Verzeichnisse für verschiedene Informationen, Object-Datenbanken mit Blobs, Indices, …) findet man anschließend in einem Verzeichnis “/projekte/GIT/alien1/.git“.

Hinweis: Ich würde an dieser Struktur des GWS nichts ändern!

  • Git erlaubt zwar grundsätzlich eine Trennung des Dachverzeichnisses
    für das “.git”-Repository-Verzeichnis vom Dachverzeichnisses für den “Working Tree”. Man kann dies etwa über CLI-Kommandos erzwingen. Nach meiner Erfahrung bringt eine solche separate Lagerung des Repositories und des Working-Trees an unterschiedlichen Orten EGit aber bei weiteren Aktionen außer Tritt. Also den Umzug der Verzeichnisstruktur an die angezeigten Position bitte zulassen!
  • Bitte achtet auch darauf, dass der Pfad zum künftigen “.git”-Verzeichnisses in eurem Dialog wirklich so ähnlich aussieht wie dargestellt. Man gerät durch Unachtsamkeit relativ schnell in eine Situation, in der man “.git” nachher unterhalb des Hauptverzeichnisses des Working Trees wiederfindet. Auch das ist technisch zwar zulässig, hätte später aber mehrere unangenehme Seiteneffekte, auf die ich an dieser Stelle nicht eingehen will. Also: Bitte darauf achten, dass das “.git”-Verzeichnis auf derselben Ebene der Verzeichnisstruktur platziert wird wie der zu erzeugende Working Tree. !

Jetzt klicken wir endlich auf den Button “Finish”; je nach Größe des bereits vorhandenen Projektverzeichnisses dauert das Verlagern der Dateien ggf. ein wenig. Schließlich sind aber sowohl das Repository unter dem Directory “.git” wie auch der Working Tree am vorgesehenen Bestimmungsort vorhanden.

>Lösung der Aufgabe 2 – Working Tree und Verzeichnisstruktur

Das Ergebnis sollte sich im PHP-Explorer bzw. im View “Git Reposiories” wie folgt darstellen:

Im unteren Teil sehen wir einen Ausschnitt des “Git Repository”-Views. Bereits hier erkennen wir deutlich den Aufbau unseres neuen GWS. Der Working Tree ist dort als solcher bezeichnet und sein Pfad ist angegeben. Ein Dateimanager bestätigt die gewünschte Verzeichnishierarchie:

Glückwunsch! Wir haben unser erstes Git-Repository samt Working Tree erstellt. Durch die Parametrierung bei der Erstellung des Repositorys und durch die beiden obigen Abbildungen haben wir neben Aufgabe 1 auch schon Aufgabe 2 gelöst.

Das Repository ist in diesem Zustand aber erst vorbereitet. Noch sind dort keine Inhalte oder Verionsobjekte angelegt ….

Git-Smart-Icon-Leiste aktivieren

Um nachfolgend etwas einfacher mit dem Repository und dem Commit neuer Dateien arbeiten zu können, beschaffen wir uns eine Smart-Icon-Leiste für Git-Operationen im Kopfbereich von Eclipse. Das erreichen wir in zwei Schritten:

  • Klick auf den Eclipse-Menüpunkt “Window => Perspective => Customize Perspective … “. Dort unter dem Reiter “Action Set Availability” die Punkte “Git” und “Git Navigation Actions” aktivieren.
     
  • Danach aktivieren wir unter dem Tab “Menu Visibility” den Punkt “Git”:
     

Als Ergebnis erhalten wir folgende Leiste:

>Lösung der Aufgabe 3 – Master-Branch und initiales Commit

Der weiter oben dargestellte View “Git-Repositories” weist uns neben dem Repository-Symbol im Moment explizit darauf hin, dass noch keine HEAD-Version existiert. Wie auch? Im “Branches”-Bereich ist unter dem Punkt “Local” ja noch nicht mal ein (Master-) Branch zu finden (s. den vorhergehenden Blog-Post). Es gibt im Moment noch überhaupt keinen Branch!

Unter Git muss man Verzeichnisse und Dateien explizit für die Berücksichtigung in der Versionsverwaltung markieren. Die kleinen Fragezeichen in den Verzeichnis-Icons im PHP-Explorer deuten an, dass dies bislang noch für keines der vier Hauptverzeichnisse unseres Test-Projektes geschehen ist. Ein “gt;”-Symbol nach den Verzeichnis- bzw. auch nach einem Datei-Namen deutet ferner an, dass es eine Änderung gibt, die noch nicht per Commit im Repository erfasst wurde: Der aktuelle Inhalt jeder Datei stellt aus Sicht von Git offenbar eine Art erste (initiale) Änderung dar. Wir würden das Symbol bei jeder Datei unterhalb der Verzeichnisse sehen.

Später werden wir das “>”-Symbol natürlich genau an denjenigen Dateien/Verzeichnissen entdecken, die jemand seit dem letzten Commit modifiziert hat. Das ist beim Einsatz von Subversion ganz genauso. Einen kleinen Unterschied zu SVN gibt es allerdings doch, und der macht sich dadurch bemerkbar, dass das Verzeichnis “uploads” kein “>”-Symbol aufweist: Der Grund dafür ist, dass das Verzeichnis leer ist. Das ist ein Hinweis darauf, dass Git keine separate Versionsverwaltung für Verzeichnisse als Repository-Objekte vornimmt. Verzeichnisse sind lediglich ein Art Attribut der nach Versionen verwalteten Datei-Objekte!

Den aktuellen Repository-Zustand könnte man im Git-Sprachgebrauch also etwa so zusammenfassen: Es ist bislang weder ein “Commit” zu den vorhandenen Dateien erfolgt, noch wurden die in Verzeichnissen organisierten Dateien überhaupt für eine Indizierung und Verwaltung in einem Branch und damit auch der Git-Objektdatenbank vorgesehen. Wir ändern das nun in zwei separaten Schritten:

Schritt 1 – Einbeziehen der Verzeichnisse und ihrer Dateien in die Versionsverwaltung: Wir markieren unsere 4 Projektverzeichnisse des Beispiels “alien”, “includes”, “interpreters”, “uploads” im PHP- oder Projekt-Explorer. Dann klicken wir in der Git-Icon-Leiste auf das grüne Kreuz. Danach müssen warten, bis sich das Dialogfenster zu “Operation in Progress …” wieder schließt.

Die nächste Abbildung zeigt, dass sich die Mikro-Symbole an den Verzeichnissen nun geändert haben:

Der weiße Stern auf schwarzem Grund weist allerdings darauf hin, dass die Dateien in den Verzeichnissen immer noch keinen “Commit” erfahren haben.

Schritt 2 – Initialer Commit für alle erfassten Dateien:
Um für alle Dateien einen “Commit” einzuleiten, markieren wir unsere Verzeichnisse erneut und klicken dann auf das orange Repository-Symbol mit dem Pfeil von links nach rechts in der Git-Icon-Leiste; dieses Symbol befindet sich neben dem grünen Kreuz und symbolisiert einen Commit-Vorgang – unseren ersten im erstellten Repository.

Nach wenigen Augenblicken bietet sich uns dann folgendes Bild im sogenannten “Git Staging View“. Dieser View öffnet sich automatisch und listet Dateien/Verzeichnisse auf, die modifiziert wurden und für die endgültige Ausführung des Commits “vorgemerkt” sind. Man nennt das auch “Staging“.

Im linken Bereich sehen wir im Bereich “Unstaged Changes” Dateien (nur 2 von 5 sind sichtbar), die bislang nicht für Commits vorgemerkt wurden. Es handelt sich in unserem Fall um Eclipse-Konfigurationsdateien für das spezielle Projekt. Darunter sehen wir im Bereich “Staged Changes” allerdings die für das Commit vorgemerkten Dateien. In unserem Fall alle Projektdateien. (Es handelt sich offenbar um eine größeres Projekt, zu dem über 3000 einzelne Dateien beitragen.)

Im rechten Bereich des “Staging View” können (besser müssen) wir unseren Commit noch mit einem Kommentar verzieren. Unterhalb sollten auch Author und Committer angegeben werden; dabei sind bestimmte Formatanforderungen zu erfüllen, die wir nach einem Klick in das jeweilige Feld gefolgt von einem “Ctrl-Space” angezeigt bekommen. Die entsprechenden Werte lassen sich auch in den Eclipse-Preferences für Git hinterlegen. Man findet Git-Preferenzen wie üblich unter dem Menüpunkt “Window => Preferences => Team => Git”.

Wir klicken nun auf den Button “Commit“. Es wird jetzt eine erste Komplettversion im sog. “master”-Branch unseres Repositories erzeugt. Genauer: Zuerst wird der Master-Branch generiert; dann wird n einer ersten Projektversion auf diesem Branch der aktuelle Inhalt aller ausgewählten Projektdateien erfasst. Das Erzeugen der zugehörigen initialen Objekte des Repositories und deren Komprimierung dauert in meinem Fall wegen der großen Menge der Dateien ein paar Augenblicke.

Jeder Commit führt zu einem neuen Versionsstatus des gesamten Branches (sozusagen über alle modifizierten Dateien hinweg). Auf der Branch-Ebene entspricht ein Commit in seiner Gesamtheit somit einem eindeutigen Knoten (s. hierzu den letzten Post). Die Identität des Knotens wird durch einen eindeutigen Hash gekennzeichnet, dessen erste Buchstaben wir im Git-Repository-View auch angezeigt bekommen. Diesem Hash sind wiederum Hashes für die einzelnen erfassten Objekte (Dateien bzw. komprimierte Blobs zu deren Änderungen) zugeordnet. Auch die Änderungen selbst (bzw. zugehörige Objekte in einem Binärformat) werden also über Hashes identifiziert.

Im Git-Repository-View ergibt sich nach der Durchführung des Commits folgendes Bild :

Nun existiert offenbar der ersehnte lokale Master-Branch. Daneben erkennen wir die ersten alphanumerischen Zeichen seines Hashes (hier: 3659950) und die Anfänge unseres eben erstellten Kommentars.

Unsere Verzeichnis-Symbole im PHP-Explorer weisen nun zudem das kleine orangefarbene zylinderartige Repository-Symbol auf – damit wird angezeigt, dass die Dateien in den betroffenen Verzeichnissen ordnungsgemäß versioniert wurden. Das Fehlen von “>”-Symbolen an den Verzeichnissen, die Dateien enthalten, zeigt an, dass im Repository auch alles auf dem aktuellsten Stand ist.

Neben dem Verzeichnissymbol zum Haupt-Directory “alien1” unseres Projekts wird freundlicherweise dargestellt, welchem Branch der Inhalt des “Working Trees” gerade zugeordnet ist. (In realen Projekten wird es ja ggf. mehrere Branches geben). Der geneigte Leser wird nun sicher auch selbst beantworten können, warum das “>”-Symbol neben dem Hauptverzeichnis “alien1” nicht verschwunden ist.

Der interessierte Leser mag in einem eigenen Beispiel zudem mal einen Blick in das Verzeichnis “/…./.git/objects” werfen; man wird feststellen, dass auch dieses Verzeichnis nach dem initialen Commit mit vielen Dateien in einem Binärformat gefüllt wurde.
Nach unserem initialen Commit ist die komplette Information über den Inhalt der Projekt-Dateien also redundant vorhanden – einmal im “Working Tree” und auch in der Objektdatenbank des Repositories.

Nach weiteren Commits enthält das Repository aber deutlich mehr Informationen als der Working Tree: Der Working Tree spiegelt dann nur den Zustand wider, der zum geöffneten letzten Knoten des aktiven Branches gehört – plus ggf. zwischenzeitlich vorgenommene Änderungen, die noch nicht committed wurden. Das Repository hingegen enthält dann die gesamte bisherige Änderungshistorie. Dank Komprimierungstechnologie und der Speicherung inkrementeller Änderungen ist der Platzbedarf des Workings Trees über lange Zeit hinweg dennoch meist deutlich geringer als der Platzbedarf des Working Trees.

Zusammenfassung und Ausblick

Wir haben im Zuge dieses Artikels zu einem vorhandenen Projekt eine voll funktionsfähige lokale Versionsverwaltung unter Git eingerichtet, mit der wir nun weitere Experimente durchführen können. Wir haben dabei gesehen, dass ein Repository nach seiner Anlage auch gefüllt werden muss. Dazu sind Dateien für die Erfassung und Verfolgung in der Versionsverwaltung zu markieren. Ein Commit besteht im Grunde aus drei Phasen :

  • Phase 1: Auswahl und Staging der geänderten Dateien für die Durchführung des Commits.
  • Phase 2: Eingeben eines Kommentars zum Commit. Benennung des Autors und des Committers.
  • Phase 3: Technische Durchführung des Commits.

Ein Commit erzeugt einen eindeutig identifizierbaren Knoten in einem Branch. In einem initialen Commit werden der Master-Branch des Repositories und dessen erster Knoten erzeugt. Der Commit bzw. der korrespondierende Knoten im Branch sind durch einen eindeutigen Hash gekennzeichnet. Einem Commit sind ferner bestimmte (neu) angelegte Objekte im Verzeichnis “.git/objects” zugeordnet.

Im nächsten Blog-Post führen wir testweise einige Änderungen und zugehörige Commits durch. Wir betrachten dabei auch die Darstellung der Historie unter Eclipse. Zudem werfen wir einen ersten vergleichenden Blick auf die GUIs “GitG” bzw. “QGit”.

Erste Schritte mit Git für lokale und zentrale Repositories unter Eclipse – I

Seit Jahren arbeite ich unter Eclipse fast gewohnheitsmäßig mit SVN (Subversive Plugin und Polarion Connectoren) als Versionsverwaltungstool. Eine Frage, die mich dabei seit längerem verfolgt, ist:

Ist für Freiberufler wie mich, und damit in vielen Fällen für mobile Einzelkämpfer, trotz aller SVN-Affinität ein Wechsel auf Git sinnvoll? Woran kann man den Bedarf dingfest machen?

Steht ein Entwicklungsprojekt in einem überregional verteilten Team an, so setzen ja bereits viele andere Entwickler auch Git ein. Dann ist der Einsatz natürlich auch für mich unumgänglich. In der Situation befand ich mich aber noch nicht – deswegen habe ich eine ernsthafte Auseinandersetzung bislang auch immer wieder verschoben. Nun belasten mich ein paar Defizite von SVN aber zumindest für Entwicklungsaufgaben so, das ich das Thema wieder aufgreife.

Betrachten wir also mal eine sehr viel einfachere Situation als eine Entwicklung in einem verteilten Team. Nehmen wir an, das ich alleine etwas für einen Kunden entwickeln muss, aber den Kunden regelmäßig an einem anderen Ort (u.U. im Ausland) aufsuchen muss. Oder nehmen wir an, dass während der Entwicklungsarbeiten auch aus anderen gründen längere Abwesenheiten vom Arbeitsplatz-PC erforderlich sind, und in der Zwischenzeit am Laptop weitergearbeitet werden muss. Und gehen wir weiter von einer Situation aus, in der im Vor- und Nachfeld von Reisen der Status veränderter Projekt-Dateien regelmäßig versioniert und auf einfache Weise zwischen Arbeitsplatz-PC daheim und einem Laptop abgeglichen werden muss:

  1. Bewege ich mich zum Kunden, muss ich Dateien, die sich auf aktuell laufende Entwicklungsprojekte beziehen und an denen ich zuvor an meinem Arbeitsplatz gearbeitet habe, von meinem PC auf einfache automatisierte Weise auf einen Laptop transferieren. Dabei möchte ich aus entwicklungstechnischen Gründen (und in Beratungsprojekten z.B. zu Belegzwecken) immer die gesamte bisherige Versionshistorie der Dateien mit mir führen.
  2. Natürlich möchte ich answchließend zur Kontrolle weiterer Änderungen, die während der Reise anfallen, auf dem Laptop gerne ein lokales Versionsmanagement betreiben. Das gilt vor allem bei längerer Abwesenheit vom Heim/Firmenstandort. Und die während der Reise erreichten Zwischenstände möchte ich schon aus Backup-Gründen mit einem Repository im Internet abgleichen.
  3. Und natürlich sollen die auf dem Laptop erarbeiteten Ergebnisse nach dem Ende der Reise wieder in ein dortiges zentrales Repository des Haus-/Firmennetzes eingespielt werden. Von da dann wenn möglich auch weiter in ein lokales Repository auf meinem Arbeitsplatz-PC ..

Hier besteht also schon für einen Einzelkämpfer der Bedarf nach einer lokalen und einer zentraler Versionsverfolgung. Das bedingt zwangsläufig den Abgleich zwischen lokalen und zentralen Repositories zu sinnvoll gewählten Zeitpunkten. Will man solche Szenarien mit SVN abbilden steht man vor einem kleinen Dilemma, das erhebliche Klimmzüge erfordert.

SVN ist dafür gedacht, dass man sich mit einem (!) zentralen Server abgleicht. Der muss deshalb auch kontinuierlich erreichbar sein. Nun habe ich (gerade bei etwas längeren Auslandsaufenthalten) aber nicht immer eine Internetverbindung zur Verfügung. In einer solchen Situation bräuchte ich dann zwingend eine lokale Versionsverwaltung auf meinem Laptop, dessen Repository später mit Repositories mehrerer Server abgeglichen werden soll und muss. Das ist unter SVN wirklich ein Rezept für ein gediegenes Kuddelmuddel.

Unter Git ist das nach ersten Literaturstudien dagegen gut zu beherrschen. Git erlaubt das sichere Arbeiten mit einem lokalen und zentralen Repositories. In dieser Miniserie von Blog-Posts möchte ich deshalb für Interessierte
und Einsteiger, die Git unter Eclipse betreiben wollen, erste einfache Schritte beschreiben,

  • wie man lokale Repositorys mit Eclipse-Mitteln auf einem PC und auf einem Laptop aufsetzt,
  • wie man Repositories “cloned” und Clones zum Einrichten von Server-Repositories verwendet,
  • wie man ein lokales Repository dann mit einem ein zentralen Repository im Haus- oder Firmennetz verbindet
  • und gleichzeitig ein weiteres Repository im Internet als Backup- und Refernz-Repository benutzen kann.

Ich lasse dabei ein komplexes lokales und zentrales Feature- oder Release-Branching völlig außen vor. Um Release- und Feature-Branching kümmere ich mich evtl. in späteren Blog-Artikeln. Hier geht es nur um die Unterstützung eines quasi-sequentiellen Arbeitens an verschiedenen Geräten in folgendem Sinne:

Schritte eines Wunschszenarios für mobile Einzelkämpfer

  1. Entwicklung-/Dateiänderungen am Arbeitsplatz-PC. Versionierung mit Hilfe eines lokalen Repositorys auf dem PC
  2. => regelmäßiger Abgleich des Entwicklungsstandes auf dem PC mit einem zentralen Server-Repository im Hausnetz und einem zentralen Repository im Internet
  3. => Vorbereitung einer Reise: Abgleich des zentralen Server-Repositories mit dem lokalen Repositories eines Laptops
  4. => mobiles Arbeiten am Laptop und Versionsverwaltung mit einem dortigen lokalen Repository
  5. =>Abgleich neuer Versionsstände auf dem Laptop mit einem zentralen Repository im Internet
  6. => Rückkehr ins Firmennetz und Abgleich des Laptop-Repositories mit dem zentralen Git-Repository auf einem zuständigen Server des LANs
  7. => Abgleich zwischen Server-Repository und Arbeitsplatz-Repository
  8. => Arbeiten mit dem lokalen Repository am Arbeitsplatz und erneut Abgleich mit beiden Server-Repositories
  9. => Abgleich mit Laptop in Vorbereitung einer neuen Reise.
  10. Das ist ein denkbar einfaches Szenario, dass sich mit Hilfe einer IDE wie Eclipse nachbilden lassen sollte. Zur Vorbereitung benötigen wir jedoch einige generell Git-Begrifflichkeiten. Daher greife ich nachfolgend die Arbeitsschritte nochmal aus Eclipse-Perspektive auf und führe dabei gleichzeitig ein paar zentrale Begriffe aus der Git-Welt ein, an die man sich sowieso gewöhnen muss, wenn man ein Git-Plugin unter Eclipse einsetzen will.

    Wir leiten aus der Neubeschreibung der obigen Arbeitsschritte unseres Wunschszenarios nebenbei Aufgaben ab, deren Lösung später zu einer systematischen Abbildung der gewünschten Prozesse unter Eclipse führen wird.

    Das Wunschszenario in Git-Begriffen

    Zur Vertiefung betrachten wir folgende Skizze:

    Bin ich im firmeneigenen Netz arbeite ich normalerweise auf einer Linux-Workstation. Dort ist etwa “Eclipse Neon 3” mit dem Git-Plugin (Egit) installiert. Die Entwicklungsarbeit ist in Form von (Eclipse-) “Projekten” organisiert, zu denen jeweils ein Dateibaum gehört. In meinem Fall tummeln sich dort typischerweise PHP-, HTML,-, CSS-, Javascript- und auch mal Python-Dateien.

    Für unser Beispielszenario ziehen wir später die Dateien eines konkreten Eclipse-Projektes namens “alien1” heran. Die zugehörigen Dateien liegen dabei unter 4 Haupt-Verzeichnissen: includes, admin, interpreters,
    uploads. Das Projekt wurde in einem Eclipse-“Workspace” namens “ecl_alienx” platziert. Die genannten 4 Verzeichnisse sind im Beispiel deshalb unter einem Verzeichnis “/projekte/ecl_alienx/alien1” zu finden.

    Man könnte nun darüber streiten, ob die Aufbewahrung der Programm-Dateien innerhalb des Eclipse-Workspaces sinnvoll ist. Wir unterlassen diese Diskussion aber, da wir die Verzeichnislokation im Rahmen des Git-Einsatzes sowieso ändern werden.


    Was wollen wir nun im Detail erreichen?
    Zur Versionsverwaltung möchte ich in unserem Wunsch-Szenario zunächst ein lokales Git-Repository auf dem Arebitsplatz-PC benutzen, bis ich der Meinung bin, dass erreichte Zwischenergebnisse auch auf einem zentralen (Git-) Repository eines Servers im Haus-/Firmen-Netz zur Verfügung gestellt werden sollten. Ggf. für den Zugriff durch andere Nutzer/Tester, aber auch für zentrale Backups.

    Lokal checke ich eine erreichte neue (Zwischen-) Version zunächst als sogenannten “Commit” in das Git-Repository meiner Workstation ein. Manchmal muss man in der SW-Entwicklung von einer bestimmten Version aus unterschiedliche, und für eine Weile divergierende Wege zu neuen Versionen gehen. Man erhält dann “Verzweigungen” der Versionsstände; wie in SVN auch bezeichnet man diese Zweige in Git als “Branches“. Branches können zum Beispiel als Feature- oder Release-Branches angelegt werden zur experimentellen Entwicklung von Features in einem separaten Zweig bzw. zur Konsolidierung eingefrorener Versionsstände angelegt werden. Andee Branches mögen etwa auch einer Continuous Integration dienen. Zu und zwischen Branches – also definierten Abzweigungen in der Versionshistorie – möchte man ggf. wechseln. Unter Git spricht man hierbei (abweichend von anderen Versionsverwaltungssystemen) von sog. Checkouts. Warum wird später klarer werden. Würde man z.B. vom Master-Branch zu einem anderen Branch namens “Branch2″ wechseln, so würde Branch2” zum sog. “aktiven Branch” des Repositories werden.

    Jeder Commit entspricht grafisch gesehen einem “Knoten” eines Branches (s. die Skizze weiter unten); ein Knoten symbolisiert einen bestimmte Versionsstand des Branches (also eine eindeutigen Kombination aus definierten Versionsständen aller für die Versionsverwaltung erfassten Dateien). Ein Knoten in einem Branch entspricht also genau besehen nicht nur dem punktuellen Commit, der zu seiner Erzeugung führte, sondern im Kern der ganzen Historie aller vorangegangenen Commits auf den erfassten Dateien – ausgehend von einem initialen Commit. Die Rückkehr zu einem älteren Versionsstand (Knoten) in einem Branch nennt man unter Git einen sog. “Reset“.

    Für Aktionen wie Commits, eine Historienverfolgung, Branching, Checkouts, Resets etc. sollte im Grunde gar kein Server erforderlich sein; ich will mit meiner lokalen Versionsverwaltung und dem zugehörigen Repository wenn nötig auch einen ganze Weile völlig autonom arbeiten können ohne irgendwelche Kollegen zu belästigen.

    So weit so gut. Nun eine Einschränkung:

    In unserem Szenario konzentrieren wir uns weitgehend auf sukzessive voranschreitende Versionen – oder “Knoten” – in genau einem Branch jedes eingesetzten Repositories. Der ursprünglich erzeugte, erste und native Branch eines jeden Repositories ist dessen sog. Master-Branch. Wir beschäftigen uns in dieser Blog-Post-Serie also primär mit dem Abgleich zwischen den “Master”-Branches verschiedener Repositories. Wir lassen dabei für unser Wunschszenario die gewollte Erzeugung von Branches (Entwicklungszweigen) und das Wechseln zu einem anderen als dem “Master”-Branch weitgehend außen vor.

    Die Verzeichnisstruktur, in der die Dateien eines Eclipse-Projektes organisiert werden, muss sich in einem geeigneten Äquivalent im Rahmen der
    Repository-Verwaltung widerspiegeln. Ein solches Äquivalent ist der sog. “Working Tree” eines Repositories. Wir werden sehen, dass auch der Working Tree eine Verzeichnisstruktur darstellt; diese entspricht ferner einer Momentaufnahme eines definierten Knotens auf dem “aktuellen Branch”; in unserem Beispiel also auf dem Master-Branch. Achtung: Checkouts und Resets führen zu Veränderungen der Inhalte von Dateien im “Working Tree”.

    Typischerweise kann es sich ein Versionsverwaltungssystem aber nicht leisten, unterschiedliche und vollständige Varianten aller Dateiinhalte in normaler Dateiform aufzubewahren, um die Historie zu erfassen. Git arbeitet hier (wie andere System auch) inkrementell und verwahrt Differenzen zwischen Dateizuständen; zudem wird komprimiert: Im Ergebnis entstehen so Blobs einer Art Objekt-Datenbank. Die Objekte wiederum lassen sich eindeutig identifizieren und werden definierten Zustandsknoten von Branches (und damit auch Commits) zugeordnet. Eine eindeutige Identifizierung sowohl von Objekten als auch Commits (Knoten) wird in Git über Hashes ermöglicht, zwischen denen dann Relationen hergestellt werden. Weitere Details der Objektorganisation sind in unserem Kontext unwichtig.

    Der Working Tree stellt eine Momentaufnahme eines ausgewählten Knotens dar – in der Regel des letzten, also des jüngsten Knotens einer Branch-Historie. Dieser Knoten wird auch als HEAD des Branches bezeichnet.

    Die ersten Ziele, die wir unter Eclipse erreichen müssen, sind demnach folgende:

    • Aufgabe 1: Erstellen eines lokalen Repositories auf dem PC.
    • Aufgabe 2: Klärung: Wo liegt der “Working Tree”? Welchen Verzeichnisbaum zeigt Eclipse?
    • Aufgabe 3: Einbringen des Inhalts des Projektverzeichnisbaums in den Master-Branch des lokalen Repositories. Initiales Commit.
    • Aufgabe 4: Durchführung von Änderungen im Verzeichnisbaum des Projekts und Testen nachfolgender “Commits”. Blick auf die Git-Versionshistorie auf dem PC. Identifizierung des HEAD-Commmits bzw. -Knotens.

    Zu geeigneten Zeitpunkten möchte ich den aktuellen Stand meiner Dateien auch auf einem zentralen Git-Server (z.B. im Firmen-LAN) bereitstellen. Entsprechende Operation werden als “Push“-Operationen bezeichnet. Ziel (“Target”) eines Pushes ist also ein Branch aus einem anderen (Target-) Repository – hier also im Repository des Servers. Ein Pushvorgang erzeugt dort einen neuen Knoten.

    Andere bzw. auch ich selbst können später vom Server-Repository den dort festgehaltenen Entwicklungsstand auf andere Geräte (z.B. einen Laptop) und dortige lokale Repositories überführen. Dazu führen sie dann sog. Pull- oder Fetch-Operationen durch, mit denen der Versionsstand eines definierten Branches auf dem Server abgefragt und in das lokale Repository überführt und dort integriert wird. Auf den Unterschied zwischen Pull und Fetch gehe ich an passender Stelle in einem späteren Post dieser Serie kurz ein.

    In unserem Szenario “pullen” wir typischerweise den letzten Stand vom Master-Branch des Server-Repositories. Das Target eines Pulls ist also der aktuelle Branch in dem lokalen Repository, von dem aus ich auf ein anderes Repository als Quelle von Veränderungen zugreife. Der Pull erzeugt einen neuen Knoten in meinem lokalen Branch. In unserem Szenario finden Pulls normalerweise auf dem Laptop und später auch auf dem Arbeitsplatz-PC statt. Server-Repositories protokollieren in unserem Szenarion dagegen neue Versionsstände als Ergebnis von Push-Vorgängen zum einem dortigen Branch – bei uns dem Master-Branch des jeweiligen Server-Repositories.

    Sowohl bei einer Push- bzw. Pull-Operationen finden (automatisch) Merge-Prozesse mit dem Stand des betroffenen Branches auf dem Target-Repository statt. In unserem Szenario wird ein erster Push-Prozess also z.B. den Stand einer Datei (oder mehrerer Dateien) des Master-Branches auf einem lokalen PC-Repository mit dem Stand der entsprechenden Datei(en) (bzw. ihrer Objekte) im Master-Branch des Server-Repositorys zusammenführen. Das PC-Repository verändert sich dabei nicht; der neue Knoten entsteht auf dem Server. [Hat man Push/Pull-Vorgänge zwischen definierten Master-Branches unterschiedlicher Repositories verstanden, so sind spätere, komplexere Operationen zwischen anderen lokalen und zentralen Repository-Branches (als den Master-Branches) relativ einfach zu beherrschen.]

    Beim Zusammenführen unterschiedlicher Dateiänderungen in einem Merge können ggf. Konflikte auftreten; diese müssen dann ggf. manuell aufgelöst werden. Das erfordert ggf. detaillierte Vergleiche der in den unterschiedlichen Branches/Repositories vor dem Merge durchgeführten Änderungen. Wir werden aber sehen:

    Arbeitet man als Einzelperson phasenweise entweder ausschließlich auf dem Arbeitsplatz oder in einer anderen Phase ausschließlich auf dem Laptop und gleicht bei einem Übergang zwischen diesen Arbeitsphasen die jeweiligen lokalen Repositories mit einem zentralen Server-Repository in der oben angegebenen Schrittfolge ab, so treten Konflikte in der Regel nicht auf. In diesen Fällen kann Git die notwendigen Merges automatisch und auf einfache Weise erledigen. Man spricht dann auch von Fast-Forward-Merges (FF-Merges).

    Bei FF-Merges sind eigentlich nur neue Knoten in einem Branch zu erzeugen und Referenzen zu bereits bekannten Objekten aufzubauen. Letztere müssen möglicherweise zwischen Repositories kopiert werden; aber echte neue Objekte zu neuen Datenstrukturen sind nicht zu erzeugen. Es liegt dann kein Merge-Commit wie im Falle echter Zusammenführungen mehrer unterschiedlicher Änderungen in den Quell- und Target-Branches vor.

    Die Situation wird in folgender Skizze dargestellt. Wir sehen sukzessiv erstellte Knoten in den Master-Branches dreier Repositories. Echte Commits, bei denen Datenveränderungen vorgenommen wurden, sind als solche bezeichnet und durchnummeriert. Zu jedem Knoten findet man die ersten alphanumerischen Zeichen eines zugehörigen eindeutigen Hashes. In jedem Branch ist der führende Head-Knoten durch eine rote Füllung angedeutet.

    Push und Pull-Aktionen führen in der rein sequentiellen Aktionsabfolge unseres einfachen Szenarios zu unkomplizierten und konfliktfreien FF-Merges, in die wir nicht eingreifen müssen.

    Komplizierter wäre das Mergen allerdings dann, wenn die zentralen Versionsstände zu Dateien, an denen man selbst in seinem lokalen Repository arbeitet, während einer Phase auch durch andere von anderen Stellen aus manipuliert werden würden. Das schließen wir für diese Artikelserie aber mal aus. Etwas schwieriger ist auch ein zwischenzeitlicher lokaler “Reset” auf alte Versionen beim Abgleich zwischen den verschiedenen Arbeitsphasen an unterschiedlichen Geräten zu bewältigen. Auch auch das lassen wir hier zunächst außen vor. Ich komme darauf aber in einem späteren Post der Serie zurück.

    Der eine oder andere wird sich noch die Frage stellen, wie man denn überhaupt zu einem Repository kommt. Unter Git (und damit auch mit entsprechenden Tools unter Eclipse) ist das sowohl über das gezielte Erzeugen und Initialisieren eines Repositories in einem Projekt-Verzeichnis möglich als auch über das Klonen (also Kopieren) von Repositories. Clones mit bestimmten Eigenschaften
    können auch auf Server verschoben und anschließend mit lokalen Repositories verbunden werden. Wir werden uns den Aufbau und das Klonen von Repositories mit Eclipse Tools später genauer ansehen.

    Wir können an dieser Stelle jedoch schon mehrere neue Aufgaben festhalten, die wir unter Eclipse lösen müssen:

    • Aufgabe 5: Erstellen eines zentralen Repositories auf einem Server im LAN. Hierzu werden wir unser lokales PC-Repository aus Aufgabe 1 in einer bestimmten Weise “klonen”. Der Clone wird dann auf dem Server in zugänglicher Weise platziert.
    • Aufgabe 6: Anbinden des zentralen Repositories an das lokale PC-Repository. (Verkopplung der Master-Branches). Klärung der Frage, ob man ein lokales Commit auf dem PC mit einem gleichzeitigen Push zum Server verbinden kann.
    • Aufgabe 7: testweises Überführen von neuen Änderungen, die wir auf dem PC am Projekt vornehmen werden, in den Master-Branch des Git-Server-Repositories.

    Wenden wir uns nun unserem Laptop zu. Im Wunschszenario ist beim Wechsel von einer Arbeitsphase am PC auf eine mobile Phase unter alleinigem Einsatz des Laptops zunächst also eine Push-Operation vom PC auf den Server und danach eine Pull-Operation auf dem Laptop erforderlich. Es ergeben sich also folgende weitere Aufgaben:

    • Aufgabe 8: Erzeugen eines passenden Projektes in einem geeigneten Eclipse-Workspace des Laptops. Klonen des Server-Repositorys und Bereitstellen auf dem Laptop. Verbinden mit dem Projekt. Hier stellt sich u.a. die Frage: Kann man diese Schritte unter Eclipse nicht irgendwie miteinander verbinden?
    • Aufgabe 9: Transfer von neuen Commits, die wir auf dem PC vornehmen, über das zwischengeschaltete Server-Repository in das lokale Repository des Laptops. Also: Commit auf dem PC, Push zum Server und Pull-Operation auf dem Laptop.

    Danach arbeitet man ausschließlich auf dem Laptop weiter:

    • Aufgabe 10: Durchführung von Änderungen und entsprechenden Commits auf dem Laptop. Blick auf die Versionshistorie des Laptops.

    Hinweis: Unter Git wäre prinzipiell auch ein direkter Abgleich zwischen den lokalen Repositories des Laptops und des PCs möglich gewesen. Aus verschiedenen Gründen halten wir aber in einem LAN den Weg über ein zentrales Repository für eine deutlich bessere Idee (Stern-Architektur). Ein Grund besteht etwa in Sicherheitsargumenten und einer Zugriffskontrolle: Nicht jedes System soll auf Verzeichnisstrukturen jedes andere im Netz zugreifen können. Die Zugriffsberechtigung auf bestimmte Repository-Daten lässt sich an zentraler Stelle gleich für mehrere Mitarbeiter steuern. Ein weiterer Grund ist die zentrale Zugriffsprotokollierung. Zudem stehen die Arbeitsergebnisse an zentraler Stelle auch für Backups und andere Mitarbeiter zur Verfügung.


    Betrachten wir die Situation die sich bei der Rückkehr von einer Reise ergibt. Will man dann ausschließlich auf dem Arbeitsplatz-PC weiterarbeiten, so gilt: Erforderlich ist zuerst eine Push-Operation vom Laptop in Richtung Server-Repository des Firmen-LANs und anschließend eine Pull-Operation am PC, bei der man den aktuellen Stand vom Server-Repository in das lokale Repository des PCs überführt.

    Man kann die gesamte Kette “PC => Server => Laptop => Server => PC”, die im Laufe einer Reise abgearbeitet wird, auch an der oben dargestellten Skizze nachvollziehen. Der Weg vom Laptop zum PC ist daher die Umkehrung von Aufgabe 9:

    • Aufgabe 11: Transfer von Änderungen auf dem Laptop über den zentralen LAN-Server auf den Arbeitsplatz-PC.

    Repository im Internet
    Was soll nun in unserem 1-Mann-Szenario der in der Skizze angedeutete weitere Server im Internet ?

    Ein Repository kann man auch als spezielle Backup-Datenbank für erzielte Arbeitsergebnisse betrachten. Zentrale Repositories schützen in diesem Sinne gegen lokale Verluste. Tatsächlich ist es mir schon mal passiert, dass eine Laptop-Platte auf einer Reise ihren Geist aufgegeben hat. Manchmal kann man sich dann sogar eine neue Platte beschaffen – und Linux wie Eclipse sind auch schnell installiert. Aber woher bekommt man in einem solchen Fall ein halbwegs aktuelles Repository? Hier hilft ein Server im Internet.

    Umgekehrt gilt: Auch ein Totalverlust des Laptops (z.B. durch Diebstahl) ist in der Regel weniger schlimm als der Verlust der auf diesem Gerät erzielten Arbeitsergebnisse. D.h., wir werden das Internet-Repository auch während einer Reise relativ regelmäßig mit den auf dem Laptop erzielten Versionsständen per Push-Abgleich versorgen. Soweit wir eben Zugang zu einer halbwegs vernünftigen Internet-Anbindung haben. Da Git inkrementell und komprimiert sichert, ist die Menge der zu transferierenden Daten dann oft gar nicht so groß, wie man meinen möchte. Natürlich gilt, dass man ein zentrales Repository im Internet auch für andere Zwecke wie die Arbeit in einem verteilten Team nutzen könnte.

    Wir benutzen also ein zentrales Git-Repository im Internet (oder mehrere solcher Repositories) als Backup-Instanz. Damit das Repository des Internet-Servers bereits zu Beginn einer Reise ordentlich gefüllt ist, werden wir vom PC aus rechtzeitig entsprechende Push-Aktionen durchführen. Im Sinne einer Backup-Übung sogar relativ regelmäßig. Selbstverständlich müssen unsere Administratoren dafür Sorge tragen, dass der Server und der Kommunikationsweg zum Repository hinreichend gegen Zugriffe anderer geschützt ist. Hier gelten die gleichen Maßnahmen, die man bei jedem anderen Cloud-Service auch treffen würde.

    Es ergeben sich folgende abschließende Aufgaben:

    • Aufgabe 12: Klonen des LAN-Server-Repositories und Verschieben des Clones auf einen Server im Internet. Ankopplung an die Git-Versionsverwaltung unter Eclipse auf dem PC.
    • Aufgabe 13: Testen von gezielten Push-Vorgängen vom PC und vom Laptop zum Repository auf dem Internet-Server. Klärung der Frage, ob wir unter Eclipse mit einem Commit zwei parallel Pushvorgänge zu den verschiedenen Server-Repositories im LAN und im Internet anstoßen können.
    • Aufgabe 14: Testweiser Pull eines per Laptop erzeugten Versionsstandes vom Internet-Repository auf den PC. Anschließend Push vom Laptop zum Repository auf dem LAN-Server (!) und nachfolgender erneuter Pull desselben Versionsstandes durch den PC auch vom LAN-Server. Wird die Identität der Versionsstände erkannt?

    Damit genug der Theorie. Wir haben unser Wunschszenario in Git-Begriffen ausgedeutet und uns dabei ein ordentliches Paket an Aufgaben zusammengestellt, das wir soweit möglich und sinnvoll unter Eclipse abarbeiten wollen. Im nächsten Post dieser Serie
    Erste Schritte mit Git für lokale und zentrale Repositories unter Eclipse – II
    bewegen wir uns dann in die Git-Praxis unter Eclipse und legen dort erstmal ein lokales Repository für unser Beispielprojekt “alien1” an.

KVM, video QXL und video virtio Treiber – Video-Auflösung des Gnome-Desktops eines Debian 8-Gastystems einstellen

Das Gespann KVM/Qemu ist großartig und aus meinem Linux-Leben nicht mehr wegzudenken. Vorgestern habe ich ein “Debian 8”-Gast-System für Testzwecke auf einem KVM-Host aufgesetzt, der unter “Opensuse Leap 42.2” betrieben wird. Dabei fiel mir auf, dass bzgl. des Punktes “Video” (-System) während der Konfiguration der virtuellen Maschine mittels “virt-manager” nun neben dem guten und vertrauten qxl auch eine “virtio”-Komponente zur Auswahl bereitsteht. Beide Varianten verkörpern unterschiedliche “Treiber” mit denen das Gastsystem eine virtuelle Grafikkarte ansprechen kann. Als Kommunikationsprotokoll für den Transport der Grafikinformation zum Host setze ich typischerweise Spice ein.

Mir stellte sich dann die Frage, wie man eigentlich als User die Auflösung bestimmen kann, mit der das Spice-Fenster für den Gast-Desktop (hier: Gnome 3) unter dem X-Window-System des Hosts (hier: unter KDE-Plasma5) dargestellt wird. Das ist vor allem für den Fall des “virtio”-Treiber interessant. Da der Hypervisor hier wohl direkt über die Hostsystem-Treiber auf die Grafikkarte des Hostes (bzw. Speicheradressen der Graka) zugreift, war es für mich unklar, was ich an Einstellmöglichkeiten erwarten darf. Die Maximalauflösung des Hauptschirms am Host? Eine Liste von verschiedenen Auflösungen unterhalb einer Maximalauflösung?

Voraussetzung

Auf meinem Test-Host betreibe ich 3 Schirme im “xinerama”-Verbund an einer Nvidia-Grafikkarte (GTX 960; proprietärer Treiber der Version 375). Ich möchte natürlich das KVM-Fenster (genauer das Spice-Fenster) für den Gast nicht mit der Maximalauflösung des xinerama-Verbunds (7040×1440 Pixel) betreiben. Umso wichtiger ist für den User also eine angemessene, einfache Einstellmöglichkeiten im Gast-System selbst, die sich dann auf die Darstellung des Gast-Fensters auf dem Host niederschlagen soll.

Unterschiede in den Einstellmöglichkeiten beim Einsatz von QXL und virtio

Installiert man einen KVM-Gast unter “virt-manager” und kümmert sich nicht weiter um die Konsolen-Auflösung, so richtet geht libvirt von einer Standardauflösung von 800x600x16 für die Darstellung der GUI des Gast-Systems unter dem Spice-Protokoll aus. Diese Auflösung schlägt dann typischerweise auch auf einen Gnome- oder KDE-Desktop des Gastes durch. Entsprechend klein ist dann anfänglich auch das Spice-Display-Fenster auf dem Host.

Nun wird man als Standarduser versuchen, diese Auflösung im Gastsystem über die Einstellmöglichkeiten des jeweiligen Gast-Desktop-Systems (Gnome’s “gnome-control-center” bzw. KDE’s “systemsettings5”) zu verändern.

Hat man man als Video-Einheit, also die virtuelle Graka, des Gastsystems qxl gewählt, so kann man unter der Gnome- oder KDE-GUI des Gastes die Auflösung des Desktops tatsächlich dynamisch – d.h. im laufenden Betrieb – abändern.

Entscheidet man sich bei der Konfiguration des Gastes allerdings für “virtio” als Video-System, so erleidet man unter Debian 8 Schiffbruch: Die Einstellmöglichkeit beschränkt sich dann genau auf die bereits vorgegebene Größe von 800×600.

Ich bespreche die Standard-Einstellmöglichkeiten nachfolgend zunächst für QXL, den Gnome-Desktop und auch für TTYs; anschließend gehe ich auch kurz auf eine Einstellmöglichkeit für “virtio” ein. Weitergehende Einstellmöglichkeiten – wie etwa über “xrandr” werde ich auf Wunsch eines Lesers in einem späteren Artikel aufgreifen.

Gnome-Desktop-Auflösung des Gastes unter qxl setzen

Das nachfolgende Bild zeigt den Gnome 3 Desktop eines Debian-8-Gastes mit “qxl” in einer Auflösung von 1920x1080x32 auf einem KDE-Schirm des SuSE-KVM-Hostes mit einer 2560x1440x32-Auflösung.

Die Auflösung des Gnome-Desktops eines KVM-Gastsystems kann man (zumindest im Falle von QXL) sehr einfach über die “Gnome-Einstellungen=>Monitore” festlegen.

Das mögliche Auflösungsspektrum wird dabei offenbar nur durch die Auflösung der aktuellen Host-Schirme begrenzt. De facto bietet mir das System in meinem Fall Auflösungen bis zu 4K an. Diese Einstellungen beziehen sich aber nur auf den Desktop des Gastes – nicht jedoch dessen Konsolen-TTYs !

Hinweis: Hat man einen KVM-Gast mit KDE-Plasma5 so verwendet man “systemsettings5 &” und dort den Punkt “Anzeige und Monitor”, um die KDE-Auflösung festzulegen.

Das Tolle ist: Man kann unter QXL/Spice auch bei den gezeigten hohen Auflösungen wirklich flüssig arbeiten! Auch mit transparenten Fenstern! Da ist in den letzten Jahren ganze Arbeit geleistet worden. Vielen Dank an die Entwickler! (Vor allem wohl bei Red Hat.)

Auflösung der Debian8-Gast-TTYs setzen

Das “virt-manager”-Unterfenster zur Anzeige eines Gastes über Spice bietet einem dankenswerterweise einen Menüpunkt “Send Key” an, mit dessen Hilfe man Steuersequenzen wie Ctrl-Alt-F1 auch an den KVM-Gast schicken kann. So gelangt man dann u.a zu den Gast-Konsolen-TTYs “tty1” bis tty6. Um deren Auflösung von 800×600 auf vernünftige Werte abzuändern, muss der Framebuffer-Support des Hypervisors beeinflusst werden. Dies ist unter Debian 8 über Grub-Einstellungen möglich.

Hierzu editiert man mit Root-Rechten die Datei “/etc/default/grub” bzgl. zweier Zeilen (eine davon ist auszukommentieren):

GRUB_GFXMODE=1920x1080x32
GRUB_GFXPAYLOAD_LINUX=keep

Natürlich kann man auch eine andere definierte Standard-Auflösung als die für meinen Fall angegebene wählen.

Danach ist nach einem unten angegebenen Link nur noch das Absetzen eines “update-grub” (erfordert Root-Rechte) nötig. Und tatsächlich: Nach einem Reboot wiesen meine TTYs die gewünschte Konsolenauflösung auf.

Was kann man bei einem Wechsel von QXL zu “virtio” tun?

Wie gesagt, bietet die unter Opensuse Leap 42.2 verfügbare KVM-Implementierung die Möglichkeit an, für das Video-Device eines KVM-Gastes “virtio” statt QXL (oder weit weniger leistungsfähigen Treibern) zu wählen.

Welche Folgen hat ein Wechsel zu dieser Darstellungsart, bei der direkt auf die Host-HW zugegriffen wird?
Auf meinem System bislang keinerlei offenkundig negativen. Das Zeichnen der einzelnen Gnome-Fenster auf dem Gastdesktop geht bei sehr schnellen Bewegungen dieser Fenster über die Fläche des Gastdesktops gefühlt noch etwas flüssiger
als beim Einsatz von QXL. Das ganze grafische Verhalten des Gastes im “virt-manager”-Fenster ist danach so gut, dass man auch bei höchster Auflösung von der 2D-Grafik her praktisch keinen Unterschied zur Arbeit auf einem nativen System mehr merkt. Das ist wirklich beeindruckend gut!

Einen Wehrmutstropfen muss man als Standard-User unter Debian 8 (mit Kernel 3.16) aber dennoch hinnehmen:

Unter den “Gnome-Einstellungen=>Monitore” lässt sich die Auflösung nicht mehr dynamisch wie im Fall von QXL ändern. Für das Einblenden des grafischen Gast-Outputs in den Speicherbereich der realen Graka zählt unter Debian 8 offenbar allein die Auflösung, die man wie oben beschrieben für die Unterstützung des virtuellen Gast-Framebuffers durch den Hypervisor eingestellt hat.

Immerhin steht einem dadurch aber eine Einstellmöglichkeit zur Verfügung – wenn auch keine dynamische! Damit kann ich aber gut leben; wenn ich jemals eine dynamische Änderung des Gnome-Desktops eines KVM-Gastes brauchen sollte, verwende ich halt “qxl”.

Nachtrag, 29.06.2017:
Faktisch gilt die obige festgestellte Einschränkung für Debian 8 nur für Kernel 3.X. Mindestens ab Kernel 4.9 bietet der virtio-Treiber eine ganze Liste an Auflösungen an, aus denen man wählen kann. Siehe hierzu den Artikel

KVM, video virtio, Debian 8 guest, host with Intel HD 4000 – install a 4.9 kernel on the guest for optimal 2D graphics performance!

Nachtrag, 03.07.2017:
Ein User hat mich angeschrieben und zu Recht angemerkt, dass die im Gastsystem angebotenen Auflösungen unter “qxl” nicht immer an die Maximal-Auflösung der Schirme des Hosts heranreichen. Auf die Frage, was man dann tun kann, gehe ich gerne in einem weiteren Artikel ein. Sobald ich Zeit finde, den zu schreiben … Den entsprechenden Link werde ich dann hier nachtragen. Der Schlüssel liegt dabei vor allem in der Nutzung von “xrandr”. Bei der Gelegenheit gehe ich dann auch kurz auf das Thema von mehreren “virtuellen” Monitoren unter qxl ein.

Skalierung des Fensterinhaltes

Hingewiesen sei auch darauf, dass sich die Darstellung das gesamte Fenster zur Darstellung des KVM/Qemu-Gastes, das man vom virt-manager aus geöffnet hat, bei entsprechender Einstellung unter dem Menüpunkt “View” dynamisch skalieren lässt.

Auch das geht sehr flüssig und verzögerungsfrei!

Viel Freude weiterhin mit Linux und KVM/Qemu!

Links

https://superuser.com/questions/598374/how-to-change-the-resolution-of-the-bash-for-a-debian-vm

ufw auf Strato-vServern mit Debian 8 – fehlende iptables Log-Meldungen im systemd-Journal – rsyslogd

Gestern hatte ich das Vergnügen, ein Debian-Server-System auf einer aktuellen vServer-Plattform bei Strato einzurichten. Ich bereite entsprechende Arbeiten in der Regel vor, indem ich elementare Konfigurationsschritte – im Besonderen solche, die sicherheitsrelevant sind – vorab auf einem ähnlichen KVM-Gast-System in unserem Hausnetz simuliere und teste.

Diese Art von vorbereitenden Tests hat jedoch ihre Grenzen; nicht alles ist vergleichbar. Gestern bin ich mal wieder auf einen Unterschied im Zusammenhang mit iptables, ufw und den zugehörigen LOG-Meldungen unter systemd gestoßen. Letztere fehlten nämlich im systemd-Journal des Strato-vServers völlig.

Da fragt man sich schon, wie man denn unter solchen Voraussetzungen das gehostete System bzgl. von Angriffsmustern monitoren soll. Ich finde, diese Frage ist so relevant, dass sie sich auch andere Strato-Kunden besser vor dem Mieten eines vServers beantworten sollten. Deshalb dieser Post. Die gute Nachricht ist: Es gibt unabhängig von den Ursachen für das Fehlen der LOG-Meldungen einen Workaround.

Die schlechte Nachricht ist: Die Ursache der fehlenden Kernel-Meldungen im systemd-Journal ist unklar; zumindest mir. Auf einem KVM-Host funktioniert alles wie erwartet. Unterschiede zu gehosteten Servern sind meist auf einen anderen Ansatz in der Virtualisierung zurückzuführen (Stichwort: Container-Technologie vs. Hypervisor für Full/Para-Virtualisierung).

In diesem Falle erscheint mir das aber als Erklärungsansatz nicht plausibel und hinreichend. Ich gehe nachfolgend auf die Gründe etwas genauer ein. Zudem ist bei Debian 8 (leider) eben auch systemd in den Logging-Prozess involviert. Defizite von “systemd” in der Interaktion mit bestimmten Virtualisierungsumgebungen halte ich für durchaus möglich. Der Irrwitz, dass ein Programm beim Systemstart die Umgebung analysieren und für jeden Fall die richtige Antwort ziehen muss, hat halt seinen Preis …

ufw, netfilter/iptables und das Logging-Problem

Ich bin eigentlich ein Freund von Firewall-Builder (FWB). Für Debian-Systeme verwende ich aber auch “ufw“, um initial die wichtigsten Paketfilter-Regeln, also iptables-Anweisungen, bequem und zeitsparend aufzusetzen. Die drehen sich zunächst um den SSH-Zugang von außen und die Erlaubnis, dass der gehostete Server DNS-Server, NTP-Server und bestimmte Update-Server kontaktieren darf. Auch “pings” und “traceroute” vom Server nach außen erlaube ich. Alles andere wird von mir anfänglich rigoros geblockt. Später wird dann für die angestrebten Services des Servers gezielt nachgearbeitet. (Off topic: Viele Dienste, die mein Kunde benötigt, tunnele ich auf dem Server über eine SSH-Verbindung; ein direkter SSH-Zugang des Users root wird sowieso unterbunden und der SSH-Port verschoben.)

Anfänglich ist hinsichtlich eines minimalen Regelsatzes gar nicht viel zu tun. Im Anschluss an das Etablieren der ersten Paketfilter-Regeln möchte ich gerne die Arbeit von “netfilter” testen und das zugehörige Logging mitverfolgen. Typischerweise lasse ich dann “nmap” von außen auf das gehostete System los. Für einen Test des Serverzugriffs auf externe DNS-Dienste und Zugriffe auf Update-Server tut es dagegen “apt-get”. In beiden Fällen verfolge ich per SSH auf einem (Remote-) Terminal den Strom der Meldungen der (ufw-)”Firewall”.

Das erhoffte Verfolgen der iptables-Log-Meldungen schlug auf dem Strato-vServer mit installiertem Debian 8 aber fehl.

Debian 8.x nutzt wie gesagt systemd. Ufw schreibt die iptables-Log-Daten mit eigenen Zusätzen in das Log-System des Servers – bei einem systemd-basierten Systemen also in das dortige binäre Journal. Das systemd-Journal fängt im Normalfall neben System-Meldungen und Meldungen aus dem Userspace auch Kernel-Messages auf. Da systemd den gesamten Mix aus Messages in ein
binäres Datenformat in einer Datei überführt, muss man das Kommando “journalctl” mit geeigneten Filtern bzw. der Option “-f -nxxx” benutzen, um Log-Einträge auswerten bzw. direkt am Schirm mitverfolgen zu können.

Gesagt, getan. Leider tauchen auf einem Strato-vServer im Journal von “systemd” generell nur sehr wenig Informationen auf; hinsichtlich der Paketfilter-LOG-Meldungen findet man dort jedoch leider gar nichts.

Das iptables-Target “LOG” mündet auf einem mit “rsyslogd” ausgestatteten Log- und Warnsystem dagegen in Meldungen in der Datei “/var/log/kern.log” – schließlich handelt es sich ja um Kernel-Meldungen.

Die aus meiner Sicht schon immer kritikwürdige Idee, alle systemrelevanten Meldungen an einer Stelle in einem Binärformat zu sammeln, wird uns auf einem Strato vServer nun offenbar zum Verhängnis: Nur mit systemd können wir kleine und große externe Zugriffsversuche auf einen vServer offenbar nicht überwachen!

Ich bin übrigens nicht der Einzige, der dieses Problem hatte; siehe:
http://linux.debian.user.german.narkive.com/8AbyxJTP/keine-eintrage-von-dmesg-im-journal-systemd
Erstaunlich ist dennoch, dass man ansonsten im Internet fast nichts zu dieser Thematik findet.

Ob das Problem nun etwas mit systemd-Defiziten oder einer speziellen Konfiguration der systemd-Interaktion mit der Virtualisierungsumgebung bei Strato zu tun hat, muss man natürlich ein wenig austesten.

Firewall-Logging, Virtualisierung und Container

Tatsächlich erweist sich das Verhalten von Debian 8 mit “ufw” auf einem KVM-Gastsystem als gänzlich anders. Hier ein Auszug der ufw-Meldungen von einem KVM-Gast mit Debian 8, die mittels des Befehls

“journalctl -f -n20”

zur Anzeige gebracht wurden:

Apr 05 16:05:52 deb11 kernel: [UFW BLOCK] IN=eth0 OUT= MAC=52:54:00:d5:4a:9b:52:54:00:fc:27:c5:08:00 SRC=192.168.10.1 DST=192.168.10.11 LEN=44 TOS=0x00 PREC=0x00 TTL=54 ID=25556 PROTO=TCP SPT=64358 DPT=110 WINDOW=1024 RES=0x00 SYN URGP=0 
Apr 05 16:05:52 deb11 kernel: [UFW BLOCK] IN=eth0 OUT= MAC=52:54:00:d5:4a:9b:52:54:00:fc:27:c5:08:00 SRC=192.168.10.1 DST=192.168.10.11 LEN=44 TOS=0x00 PREC=0x00 TTL=59 ID=47868 PROTO=TCP SPT=64358 DPT=135 WINDOW=1024 RES=0x00 SYN URGP=0 
Apr 05 16:05:52 deb11 kernel: [UFW BLOCK] IN=eth0 OUT= MAC=52:54:00:d5:4a:9b:52:54:00:fc:27:c5:08:00 SRC=192.168.10.1 DST=192.168.10.11 LEN=44 TOS=0x00 PREC=0x00 TTL=45 ID=41401 PROTO=TCP SPT=64358 DPT=53 WINDOW=1024 RES=0x00 SYN URGP=0 
Apr 05 16:05:52 deb11 kernel: [UFW ALLOW] IN=eth0 OUT= MAC=52:54:00:d5:4a:9b:52:54:00:fc:27:c5:08:00 SRC=192.168.10.1 DST=192.168.10.11 LEN=44 TOS=0x00 PREC=0x00 TTL=42 ID=10106 PROTO=TCP SPT=64358 DPT=22 WINDOW=1024 RES=0x00 SYN URGP=0 
Apr 05 16:05:52 deb11 kernel: [UFW BLOCK] IN=eth0 OUT= MAC=52:54:00:d5:4a:9b:52:54:00:fc:27:c5:08:00 SRC=192.168.10.1 DST=192.168.10.11 LEN=44 TOS=0x00 PREC=0x00 TTL=54 ID=65381 PROTO=TCP SPT=64358 DPT=113 WINDOW=1024 RES=0x00 SYN URGP=0 
Apr 05 16:05:52 deb11 kernel: [UFW BLOCK] IN=eth0 OUT= MAC=52:54:00:d5:4a:9b:52:54:00:fc:27:c5:08:00 SRC=192.168.10.1 DST=192.168.10.11 LEN=44 TOS=0x00 PREC=0x00 TTL=47 ID=1758 PROTO=TCP SPT=64358 DPT=587 WINDOW=1024 RES=0x00 SYN URGP=0 
Apr 05 16:05:52 deb11 kernel: [UFW BLOCK] IN=eth0 OUT= MAC=52:54:00:d5:4a:9b:52:54:00:fc:27:c5:08:00 SRC=192.168.10.1 DST=192.168.10.11 LEN=44 TOS=0x00 PREC=0x00 TTL=47 ID=22236 PROTO=TCP SPT=64358 DPT=443 WINDOW=1024 RES=0x00 SYN URGP=0 
Apr 05 16:05:52 deb11 kernel: [UFW BLOCK] IN=eth0 OUT= MAC=52:54:00:d5:4a:9b:52:54:00:fc:27:c5:08:00 SRC=192.168.10.1 DST=192.168.10.11 LEN=44 TOS=0x00 PREC=0x00 TTL=55 ID=60478 PROTO=TCP SPT=64358 DPT=23 WINDOW=1024 RES=0x00 SYN URGP=0 
Apr 
05 16:05:52 deb11 kernel: [UFW BLOCK] IN=eth0 OUT= 

 
Offensichtlich führt im obigen Fall das System 192.168.10.1 einen Portscan auf dem betroffenen KVM-Host mit der IP 192.168.10.11 durch.

Ähnliche Meldungen erhält man bei einem Portscan auf einem vServer aber – wie gesagt – nicht.

Wie könnte man das erklären?
Ein naheliegender Erklärungsansatz wäre etwa folgender:
Das Logging von Kernel-Messages klappt auf einem KVM-Gast, also unter dem QEMU-Hypervisor (sog. Typ 2 Hypervisor), der über “virtio” auf dem Host nur partiell Paravirtualisierung und keine Container-Technologie einsetzt, natürlich problemfrei. Das Betriebssystem des KVM-Gastes und dessen Kernel arbeiten ja weitgehend autonom und greifen nur über Vermittlungsschichten auf den Kernel des Hosts und dessen HW-Unterstützung zu. Es besteht von Haus aus kein Problem bzgl. des Loggings von Kernel-Meldungen – sie beziehen sich immer auf den Kernel des Gastsystems.

Dagegen setzt Strato Container-Technologie ein – genauer VZ-Container unter Virtuozzo; selbiges basiert auf OpenVZ. Zu Grundeigenschaften siehe :
https://openvz.org/Main_Page und https://openvz.org/Features

Es handelt sich bei Strato wohl um Version 4.7 oder eine frühe 6er Version von “Virtuozzo Containers”. Dafür gibt es Indizien (u.a, dass sich Docker nicht installieren lässt); um einen genauen Nachweis habe ich mich aber (noch) nicht gekümmert. Ist auch egal.

In einer Container-Lösung wird jedenfalls die Kapazität und Funktionalität des Host-Kernels zwischen den Containern, die keinen eigenen Kernel besitzen, geteilt (schlanker “Single-Kernel-Approach”). Der Zugriff auf Netze erfolgt über eine entsprechende Netzwerk- und Schnittstellen-Virtualisierung. Typischerweise werden virtuelle venet- oder veth-NICs eingesetzt; je nachdem, auf welcher Ebene OSI-Stacks man arbeiten will. (veth-NICs setze ich selbst vielfach auch in komplexeren KVM/Qemu-Umgebungen bei der Netzwerkvirtualisierung ein.)

Die notwendige Separation der Container und ihrer Netzwerk-Kommunikation gegeneinander und gegenüber dem Host muss vom Host-Kernel bzw. dessen Modulen auf der Basis von Konfigurationsvorgaben für unpriviligierte Container (in ihren separaten Namespaces und bei modernen Ansätzen ggf. in cGroups) gewährleistet werden. Man wird den Container-Systemen jedenfalls nicht erlauben, alles einzusehen, was auf dem für alle zuständigen Host-Kernel abläuft. Dies bedeutet u.a., dass Containersysteme nicht beliebige Kernel-Module (z.B. für Packettracking unter Wireshark) laden dürfen.

Wer “iptables” im Zusammenhang mit Virtualisierungshosts aber ein wenig genauer kennt, kann sich vorstellen, dass man eine Host-Firewall natürlich immer so konfigurieren kann, dass die einzelnen virtuellen Netzwerkschnittstellen der (Container-) Gäste gegeneinander geblockt werden, aber dass generelle Forward-Regeln für physikalische Interfaces des Hosts nicht in Konflikt mit speziellen Filter-Regeln für ein spezifisches (virtuelles) Gast-Interface geraten müssen.

OpenVZ kann man deshalb sehr wohl so einrichten, dass der Admin eines Container-Systems seine eigenen iptables-Regeln für seine gastspezifischen NICs definieren kann. Siehe hierzu z.B.:
https://openvz.org/Setting_up_an_iptables_firewall.

Wesentliche Teile der verschiedenen netfilter-Module – im Besonderen für die Schicht 3 – stehen also auch Gästen zur Verfügung. Voraussetzung ist in einer Container-Architektur natürlich, dass grundlegende “netfilter”-Module auf dem OpenVZ-Host selbst geladen wurden.

Aber: Es wäre fahrlässig, wenn ein Container-Host alle netzwerkspezifischen Kernel-Meldungen (darunter iptables-Meldungen) auch für die Einsichtnahme durch die root-User der Container preisgeben würde. Das würde u.a ein
Ausspionieren der virtuellen Netzwerkumgebung und darauf aufbauend bestimmte Angriffsszenarien ermöglichen. Wenn wir überhaupt etwas im Container sehen, dann höchstens Meldungen zu selbst gesetzten Paketfilterregeln für die Container-spezifische NIC.

Zwischenfazit:

  • Wir dürfen uns in einer Container-Umgebung u.a. nicht darüber wundern, dass man bestimmte Kernel-Module vom Container aus erst gar nicht laden darf und z.B. lsmod eine vernünftige Antwort schuldig bleibt.
  • Wir dürfen uns nicht wundern, dass bestimmte sysctl-Befehle, die im Container abgesetzt werden, ggf. ignoriert werden.
  • Wir dürfen uns in einer Container-Umgebung nicht wundern, wenn man bestimmte Teile des systemd-Logs auf einem Container – und damit auf einem Strato-V-Server – nicht ggf. zu Gesicht bekommt. (Im Gegensatz zu einem KVM-Gast).

Der erste Punkt ist u.a. für den Betrieb der ufw relevant; s.u..

Bzgl. des zweiten Punktes ist zu beachten, dass OpenVZ, genauer der OpenVZ-Kernel, (network-) “Namespaces” nutzt. (“Namespaces” werden natürlich aber auch von aktuellen Linux-Kerneln unterstützt. Zu “Namespaces” siehe etwa
https://jvns.ca/blog/2016/10/10/what-even-is-a-container/
https://de.slideshare.net/jpetazzo/anatomy-of-a-container-namespaces-cgroups-some-filesystem-magic-linuxcon
https://openvz.org/WP/What_are_containers.

Deshalb lassen sich bestimmte Einstellung unterhalb von “/proc/sys” durchaus auch vom Container aus anpassen. Was in der jeweiligen OpenVZ-Umgebung erlaubt ist und was nicht, muss man ggf. durch Probieren herausfinden.

Den dritten Punkt werden wir in den nächsten Abschnitten für vServer kritisch hinterfragen.

Erste Konsequenzen für den Einsatz von “ufw”

Auch durch Probieren wird man herausfinden, dass “ufw” auch auf einem mit Debian 8 betriebenen vServer von Strato läuft – und man eigene iptables-Regeln problemfrei an den OpenVZ-Kernel weiterreichen kann.

Achtung:

Nach der Installation von ufw auf dem vServer NICHT unmittelbar “ufw enable” absetzen!! Zuerst den Port, auf dem man SSH betreibt, freischalten. Also etwa durch “ufw allow 22”, wenn man den SSH-Standardport benutzt. Ihr wollt euch ja nicht durch Anschalten der Firewall selbst aussperren!

Wie man schnell (hier durch einen Blick in das systemd-Journal feststellt), ist der Start von ufw auf einem vServer – auch im Rahmen eines Systemstarts – mit ein paar Fehlermeldungen verbunden.

Apr 05 14:21:03 xxx.stratoserver.net ufw[147]: Starting firewall: ufw...modprobe: ERROR: ../libkmod/libkmod.c:557 kmod_search_moddep() could not ope
Apr 05 14:21:03 xxx.stratoserver.net ufw[147]: modprobe: ERROR: ../libkmod/libkmod.c:557 kmod_search_moddep() could not open moddep file '/lib/modul
Apr 05 14:21:03 xxx.stratoserver.net ufw[147]: modprobe: ERROR: ../libkmod/libkmod.c:557 kmod_search_moddep() could not open moddep file '/lib/modul
Apr 05 14:21:03 xxx.stratoserver.net systemd-journal[114]: Permanent journal is using 24.0M (max allowed 4.0G, trying to leave 4.0G free of 499.5G a
Apr 05 14:21:03 xxx.stratoserver.net systemd-journal[114]: Time spent on flushing to /var is 1.770ms for 8 entries.
Apr 05 14:21:03 xxx.stratoserver.net ufw[147]: sysctl: permission denied on key 'net.ipv4.tcp_sack'
Apr 05 14:21:03 xxx.stratoserver.net ufw[147]: Setting kernel variables (/etc/ufw/sysctl.conf)...done.

r
 
Diese Meldungen rühren u.a. daher, dass ufw mit Hilfe von modprobe versucht, bestimmte “conntrack”-Sub-Module zu laden. Zudem versucht ufw per sysctl Kernel-Parameter abzuändern. Vorgegeben sind diese Schritte in den Dateien “/etc/default/ufw” und “/etc/ufw/sysctl.conf“.

Die genannten Fehler blockieren den Start aktueller ufw-Versionen aber nicht; wer sich dennoch an den Meldungen stört, kann die über Modifikationen der genannten Dateien, nämlich durch Auskommentieren der fehlerträchtigen Statements, verhindern. Siehe auch
https://www.hosteurope.de/faq/server/virtual-server/besonderheiten-firewall-virtual-server/; im Unterschied zu den dortigen Tipps aber beachten, dass auf dem vServer nur einer der sysctl-Befehle problematisch ist.)

Übrigens: Über das Starten von ufw bei einem Reboot des vServers muss man sich nach einem Absetzen von

systemctl enable ufw

keine Gedanken mehr machen. Debian 8 beinhaltet für ufw einen passenden LSB-Service, der beim Hochfahren ausgeführt wird.

Monitoring von ufw-iptables-Meldungen auf dem vServer mit Hilfe von dmesg

Nachdem man in systemd-Journal nichts findet: Gibt es andere Möglichkeiten, die LOG-Messages von ufw-/iptables zu verfolgen?

Da es sich um Kernel-Messages handelt, liegt ein versuchsweiser Blick auf den “dmesg”-Output nahe. Und tatsächlich – auf meinem vServer:

    
root@xxx:~ # dmesg
[1240949.664984] [UFW BLOCK] IN=venet0 OUT= MAC= SRC=45.55.2.201 DST=xxx LEN=40 TOS=0x00 PREC=0x00 TTL=244 ID=54321 PROTO=TCP SPT=40788 DPT=3306 WINDOW=65535 RES=0x00 SYN URGP=0 
[1240954.051018] [UFW BLOCK] IN=venet0 OUT= MAC= SRC=93.174.93.136 DST=xxx LEN=40 TOS=0x00 PREC=0x00 TTL=250 ID=4710 PROTO=TCP SPT=43745 DPT=3128 WINDOW=1024 RES=0x00 SYN URGP=0 
[1240986.448807] [UFW BLOCK] IN=venet0 OUT= MAC= SRC=45.55.1.72 DST=xxx LEN=40 TOS=0x00 PREC=0x00 TTL=244 ID=54321 PROTO=TCP SPT=46822 DPT=1900 WINDOW=65535 RES=0x00 SYN URGP=0 
[1241002.495868] [UFW BLOCK] IN=venet0 OUT= MAC= SRC=88.100.184.82 DST=xxx LEN=40 TOS=0x00 PREC=0x00 TTL=50 ID=13380 PROTO=TCP SPT=35180 DPT=23 WINDOW=44554 RES=0x00 SYN URGP=0 
[1241015.141452] [UFW BLOCK] IN=venet0 OUT= MAC= SRC=89.163.144.224 DST=xxx LEN=445 TOS=0x00 PREC=0x00 TTL=57 ID=32820 DF PROTO=UDP SPT=5180 DPT=5046 LEN=425 
[1241132.233004] [UFW BLOCK] IN=venet0 OUT= MAC= SRC=197.44.69.222 DST=xxx LEN=40 TOS=0x00 PREC=0x00 TTL=239 ID=44476 PROTO=TCP SPT=53226 DPT=1433 WINDOW=1024 RES=0x00 SYN URGP=0 
[1241145.520318] [UFW BLOCK] IN=venet0 OUT= MAC= SRC=208.100.26.228 DST=xxx LEN=40 TOS=0x08 PREC=0x00 TTL=242 ID=51210 PROTO=TCP SPT=47975 DPT=15672 WINDOW=1024 RES=0x00 SYN URGP=0 
[1241185.158299] [UFW BLOCK] IN=venet0 OUT= MAC= SRC=89.163.144.224 DST=xxx LEN=443 TOS=0x00 PREC=0x00 TTL=57 ID=56812 DF PROTO=UDP SPT=5400 DPT=4000 LEN=423 
[1241297.661764] [UFW BLOCK] IN=venet0 OUT= MAC= SRC=186.45.130.20 DST=xxx LEN=40 TOS=0x00 PREC=0x00 TTL=241 ID=12134 PROTO=TCP SPT=63715 DPT=23 WINDOW=14600 RES=0x00 SYN URGP=0 
[1241350.742715] [UFW BLOCK] IN=venet0 OUT= MAC= SRC=89.163.144.224 DST=xxx LEN=446 TOS=0x00 PREC=0x00 TTL=57 ID=14769 DF PROTO=UDP SPT=5320 DPT=5172 LEN=426 
[1241353.098569] [UFW BLOCK] IN=venet0 OUT= MAC= SRC=5.53.113.195 DST=xxx LEN=40 TOS=0x00 PREC=0x00 TTL=51 ID=48667 PROTO=TCP SPT=46919 DPT=23 WINDOW=39535 RES=0x00 SYN URGP=0 
[1241377.620483] [UFW BLOCK] IN=venet0 OUT= MAC= SRC=46.152.41.83 DST=xxx LEN=40 TOS=0x00 PREC=0x00 TTL=240 ID=40038 PROTO=TCP SPT=12600 DPT=23 WINDOW=14600 RES=0x00 SYN URGP=0 
[1241386.187457] [UFW BLOCK] IN=venet0 OUT= MAC= SRC=122.114.187.140 DST=xxx LEN=40 TOS=0x00 
PREC=0x00 TTL=238 ID=8477 PROTO=TCP SPT=46170 DPT=23 WINDOW=1024 RES=0x00 SYN URGP=0 
[1241437.193431] [UFW BLOCK] IN=venet0 OUT= MAC= SRC=218.91.210.142 DST=xxx LEN=40 TOS=0x00 PREC=0x00 TTL=48 ID=4557 PROTO=TCP SPT=45821 DPT=23 WINDOW=27541 RES=0x00 SYN URGP=0 
[1241512.054090] [UFW BLOCK] IN=venet0 OUT= MAC= SRC=89.163.144.224 DST=xxx LEN=443 TOS=0x00 PREC=0x00 TTL=57 ID=37720 DF PROTO=UDP SPT=5179 DPT=1028 LEN=423 
[1241553.246515] [UFW BLOCK] IN=venet0 OUT= MAC= SRC=49.4.143.59 DST=xxx LEN=40 TOS=0x00 PREC=0x00 TTL=104 ID=256 PROTO=TCP SPT=6000 DPT=135 WINDOW=16384 RES=0x00 SYN URGP=0 
[1241632.706391] [UFW BLOCK] IN=venet0 OUT= MAC= SRC=39.71.216.3 DST=xxx LEN=40 TOS=0x00 PREC=0x00 TTL=48 ID=4841 PROTO=TCP SPT=57398 DPT=22 WINDOW=55725 RES=0x00 SYN URGP=0 
[1241643.559480] [UFW BLOCK] IN=venet0 OUT= MAC= SRC=196.202.5.43 DST=xxx LEN=44 TOS=0x00 PREC=0x00 TTL=48 ID=53691 PROTO=TCP SPT=34866 DPT=23 WINDOW=33710 RES=0x00 SYN URGP=0 
[1241674.241572] [UFW BLOCK] IN=venet0 OUT= MAC= SRC=89.163.144.224 DST=xxx LEN=446 TOS=0x00 PREC=0x00 TTL=57 ID=60393 DF PROTO=UDP SPT=5288 DPT=1029 LEN=426 
[1241683.411659] [UFW BLOCK] IN=venet0 OUT= MAC= SRC=124.167.232.138 DST=xxx LEN=60 TOS=0x00 PREC=0x00 TTL=47 ID=40536 DF PROTO=TCP SPT=57844 DPT=22 WINDOW=14600 RES=0x00 SYN URGP=0 
[1241686.407572] [UFW BLOCK] IN=venet0 OUT= MAC= SRC=124.167.232.138 DST=xxx LEN=60 TOS=0x00 PREC=0x00 TTL=47 ID=40537 DF PROTO=TCP SPT=57844 DPT=22 WINDOW=14600 RES=0x00 SYN URGP=0   

 
Ja, die Welt ist schlecht – und wir tun offenbar gut daran, den Zugang zum Server zu blocken bzw. die Logs auch mal auszuwerten und später Blacklists einzusetzen. “fail2ban” zu konfigurieren schadet nebenbei auch nichts.

Wer periodische Updates des Outputs von dmesg ähnlich zu “tail -f” verfolgen will, probiere mal das Kommando

watch -n 0,2 “dmesg | tail -n $((LINES-6))”

in einem Terminal aus. (Ggf. das Terminalfenster etwas vergößern. Auf englischsprachigen Systemen “0.2” statt wie hier “0,2” ! Auf neueren Kerneln als dem der aktuellen vServer gibt es übrigens auch die dmesg-Option “-w”).

Aber das eigentlich Feststellenswerte ist ja, dass wir überhaupt was sehen!

Natürlich ist das, was man unter OpenVZ unter dmesg zu Gesicht bekommt, eingeschränkt (s. etwa https://bugs.openvz.org/browse/OVZ-5328).
Aber:
Der OpenVZ-Kernel liefert dem Container zulässige, relevante Informationen in den lokalen Message-Ringpuffer, die dort von root eingesehen werden können. Darunter auch die ersehnten iptables-Meldungen!

Nun stellt sich die große Frage, wie systemd mit diesen Kernelmeldungen interagiert und warum das, was unter dmesg erschient, nicht ins Journal der OpenVZ-Container-Umgebung eingestellt wird.

Das Problematische an systemd ist, wie immer, dass man das ohne seitenweises Lesen in systemd Blogs etc. und/oder gar Codestudium vermutlich nicht beantworten kann. Logisch erscheint mir das Ganze jedenfalls nicht. OpenVZ sorgt offenbar für eine Reduktion der Kernelinformationen auf das, was root im Container sehen sollte. iptables-Meldungen zur lokalen NIC des Containers werden dabei nicht ausgespart. Sie sollten daher eigentlich auch im systemd-Journal erscheinen!

Monitoring mittels rsyslogd ? !

Durch den dmesg-Test ermutigt, fragte ich mich, was wohl passieren würde, wenn rsyslog auf dem vServer-Debian-System installiert und aktiviert wäre. Das ist insofern interessant, als systemd ja externe Linux System-Logging-Services über Schnittstellen bedient und trotzdem sein eigenes Journal weiter versorgt. Man loggt dann im Normalfall sozusagen zweimal …

Eigentlich würde man nun erwarten, dass die Meldungen von dmesg auch in den verschiedenen Dateien, die der rsyslog-Dämon bedient, nicht auftauchen sollten. Weil systemd ja schon den
Transfer in die eigene Binärdatei verweigert. Also machen wir mal die Probe:

root@xxx:~# apt-get rsyslog
root@xxx:~# systemctl start rsyslog
root@xxx:~# systemctl enable rsyslog

Wenn nun doch etwas passieren sollte, so müssten iptables-Meldungen als Einträge unter “/var/log/kern.log” und/oder in der von ufw vorgesehenen Datei “/var/log/ufw.log” auftauchen.

Und tatsächlich finden wir (wider Erwarten) nach einer Weile in “kern.log” iptables-LOG-Meldungen:

  
Apr  6 13:19:57 xxx kernel: [1245761.082097] [UFW BLOCK] IN=venet0 OUT= MAC= SRC=118.163.90.134 DST=xxx LEN=40 TOS=0x00 PREC=0x00 TTL=48 ID=14764 PROTO=TCP SPT=33202 DPT=23 WINDOW=44186 RES=0x00 SYN URGP=0 
Apr  6 13:21:03 xxx kernel: [1245827.018789] [UFW BLOCK] IN=venet0 OUT= MAC= SRC=85.90.163.248 DST=xxx LEN=44 TOS=0x00 PREC=0x00 TTL=52 ID=358 PROTO=TCP SPT=21965 DPT=23 WINDOW=12453 RES=0x00 SYN URGP=0 
Apr  6 13:21:16 xxx kernel: [1245840.027789] [UFW BLOCK] IN=venet0 OUT= MAC= SRC=89.163.144.224 DST=xxx LEN=445 TOS=0x00 PREC=0x00 TTL=57 ID=61654 DF PROTO=UDP SPT=5201 DPT=4011 LEN=425 
Apr  6 13:22:26 xxx kernel: [1245910.326051] [UFW BLOCK] IN=venet0 OUT= MAC= SRC=91.98.36.115 DST=xxx LEN=40 TOS=0x00 PREC=0x00 TTL=46 ID=3739 PROTO=TCP SPT=31242 DPT=23 WINDOW=22306 RES=0x00 SYN URGP=0 
Apr  6 13:23:13 xxx kernel: [1245957.077099] [UFW BLOCK] IN=venet0 OUT= MAC= SRC=117.193.182.117 DST=xxx LEN=40 TOS=0x00 PREC=0x00 TTL=48 ID=29137 PROTO=TCP SPT=12209 DPT=22 WINDOW=52845 RES=0x00 SYN URGP=0 
Apr  6 13:23:54 xxx kernel: [1245997.536218] [UFW BLOCK] IN=venet0 OUT= MAC= SRC=45.55.1.114 DST=xxx LEN=40 TOS=0x00 PREC=0x00 TTL=244 ID=54321 PROTO=TCP SPT=43185 DPT=8123 WINDOW=65535 RES=0x00 SYN URGP=0 
Apr  6 13:23:56 xxx kernel: [1246000.108495] [UFW BLOCK] IN=venet0 OUT= MAC= SRC=192.151.169.29 DST=xxx LEN=40 TOS=0x00 PREC=0x00 TTL=51 ID=46742 PROTO=TCP SPT=54014 DPT=23 WINDOW=49390 RES=0x00 SYN URGP=0 
Apr  6 13:24:05 xxx kernel: [1246008.982092] [UFW BLOCK] IN=venet0 OUT= MAC= SRC=89.163.144.224 DST=xxx LEN=445 TOS=0x00 PREC=0x00 TTL=57 ID=19866 DF PROTO=UDP SPT=5391 DPT=4012 LEN=425 
Apr  6 13:24:08 xxx kernel: [1246011.450635] [UFW BLOCK] IN=venet0 OUT= MAC= SRC=163.172.204.214 DST=xxx LEN=447 TOS=0x00 PREC=0x00 TTL=58 ID=25411 DF PROTO=UDP SPT=5440 DPT=5060 LEN=427 
Apr  6 13:24:18 xxx kernel: [1246022.133966] [UFW BLOCK] IN=venet0 OUT= MAC= SRC=181.193.99.26 DST=xxx LEN=40 TOS=0x00 PREC=0x00 TTL=48 ID=47683 PROTO=TCP SPT=36520 DPT=23 WINDOW=41856 RES=0x00 SYN URGP=0 
Apr  6 13:24:29 xxx kernel: [1246032.599018] [UFW BLOCK] IN=venet0 OUT= MAC= SRC=89.248.166.146 DST=xxx LEN=48 TOS=0x00 PREC=0x00 TTL=123 ID=26103 PROTO=TCP SPT=11206 DPT=2083 WINDOW=65535 RES=0x00 SYN URGP=0 
Apr  6 13:24:50 xxx kernel: [1246053.507827] [UFW BLOCK] IN=venet0 OUT= MAC= SRC=71.165.26.106 DST=xxx LEN=40 TOS=0x00 PREC=0x00 TTL=50 ID=381 PROTO=TCP SPT=29725 DPT=23 WINDOW=3178 RES=0x00 SYN URGP=0 
Apr  6 13:25:44 xxx kernel: [1246108.065452] [UFW BLOCK] IN=venet0 OUT= MAC= SRC=139.162.118.251 DST=xxx LEN=40 TOS=0x00 PREC=0x00 TTL=246 ID=54321 PROTO=TCP SPT=56219 DPT=6379 WINDOW=65535 RES=0x00 SYN URGP=0 
Apr  6 13:26:16 xxx kernel: [1246139.839711] [UFW BLOCK] IN=venet0 OUT= MAC= SRC=174.16.249.159 DST=xxx LEN=40 TOS=0x00 PREC=0x00 TTL=240 ID=54734 PROTO=TCP SPT=43074 DPT=23 WINDOW=14600 RES=0x00 SYN URGP=0 
Apr  6 13:26:28 xxx kernel: [1246151.805797] [UFW BLOCK] IN=venet0 OUT= MAC= SRC=117.1.220.212 DST=xxx LEN=44 TOS=0x00 PREC=0x00 TTL=242 ID=2085 PROTO=TCP SPT=14216 DPT=5358 WINDOW=14600 RES=0x00 SYN URGP=0 
Apr  6 13:26:50 xxx kernel: [1246174.013725] [UFW BLOCK] IN=venet0 OUT= MAC= SRC=123.151.42.61 DST=xxx LEN=135 TOS=0x00 PREC=0x00 TTL=47 ID=32696 PROTO=UDP SPT=9019 DPT=1701 LEN=115 
Apr  6 13:27:01 xxx kernel: [1246184.993843] [UFW BLOCK] IN=venet0 OUT= MAC= SRC=89.163.144.224 DST=xxx LEN=445 TOS=0x00 
PREC=0x00 TTL=57 ID=44551 DF PROTO=UDP SPT=5365 DPT=4013 LEN=425 
Apr  6 13:27:27 xxx kernel: [1246211.300971] [UFW BLOCK] IN=venet0 OUT= MAC= SRC=89.120.177.89 DST=xxx LEN=44 TOS=0x00 PREC=0x00 TTL=55 ID=64605 PROTO=TCP SPT=59589 DPT=23 WINDOW=64213 RES=0x00 SYN URGP=0 

 
Die Welt ist inzwischen nicht besser geworden, aber nun können wir das Schlechte wenigstens mal verfolgen. (Dieselben Einträge erscheinen übrigens auch in ufw.log).

Tja, nicht alles im Leben mit systemd ist offenbar nachvollziehbar ….

Fazit

Das erwartete native Zusammenspiel zwischen einem Strato OpenVZ vServer und systemd unter Debian 8 funktioniert bzgl. der Protokollierung der LOG-Target-Meldungen von iptables nicht. Kernel-Meldungen zu iptables-Rules für die Container-NIC erschienen nicht im Journal von systemd.

Workarounds bestehen darin

  • den Output von dmesg kontinuierlich per Skript abzufragen und in eine Datei umzulenken.
  • rsyslog zu installieren und die Arbeit dem Zusammenspiel von systemd mit dem rsyslog-Dämon zu überlassen. Man protokolliert dann doppelt, aber man erhält wenigstens dauerhafte Log-Protokolle, die jeder sicherheitsbewußte Admin zur vorsorglichen Gefahrenabwehr benötigt.

Da die gewünschten Kernel-Meldungen bei gleicher Debian- und Systemd-Version in einem KVM-Gast erscheinen, ist das Problem mit dem systemd-Journal entweder

  • auf einen Fehler oder ein Sicherheitsfeature der OpenVZ-Umgebung,
  • oder auf ein seltsames (gewolltes oder fehlerhaftes) Zusammenspiel des OpenVZ-Kernels mit systemd in den Container-Umgebungen,
  • oder schlicht auf ein fehlerhaftes, bislang nicht erkanntes/bedachtes Verhalten von systemd in einem OpenVZ-Container

zurückzuführen.

Für letzteres spricht die Tatsache, dass der OpenVZ-Kernel iptables-Meldungen zur Container-NIC unter dmesg offenbart und dass systemd die Meldungen, die unter dmesg auftauchen wohl korrekt an weitere System-Logging-Services wie rsyslog weiterleitet.

Eine entsprechende Anfrage bei Strato, die hoffentlich Virtuozzo einschalten, läuft.

Das Fehlen von iptables-Log-Protokolle ist im Sinne der ISO 27000 (Strato hat da ein Zertifikat!) zudem als Sicherheitsproblem einzustufen, das Kunden kommentarlos zugemutet wird und von diesen Kunden selbst gelöst werden muss.

Weiterführende Links

Fehlende Einträge im systemd-Journal
http://linux.debian.user.german.narkive.com/8AbyxJTP/keine-eintrage-von-dmesg-im-journal-systemd

Container, Virtuozzo, OpenVZ und iptables, ufw
http://forum.openvirtuozzo.org/index.php?t=msg&goto=37264&&srch=container
https://openvz.org/Setting_up_an_iptables_firewall
http://askubuntu.com/questions/399624/ubuntu-server-12-04-and-ufw-failure-on-startup-and-several-module-not-found-err
https://www.hosteurope.de/faq/server/virtual-server/besonderheiten-firewall-virtual-server/
https://superuser.com/questions/659236/permission-denied-when-setting-values-in-sysctl-on-ubuntu-12-04
https://help.
ubuntu.com/community/UFW

https://help.virtuozzo.com/customer/en/portal/articles/2509437?_ga=1.206607316.635252319.1491384754
ab S. 317 in folgender Referenz
http://www.odin.com/fileadmin/parallels/documents/hosting-cloud-enablement/pvc/Production_Documents/VzLinuxUG_03132013.pdf
https://bugs.openvz.org/browse/OVZ-5328

Namespaces
http://www.netdevconf.org/1.1/proceedings/slides/rosen-namespaces-cgroups-lxc.pdf

LXC vs. OpenVZ
https://www.janoszen.com/2013/01/22/lxc-vs-openvz/
https://en.wikipedia.org/wiki/LXC
https://openvz.org/Comparison

OpenVZ integrates KVM/Qemu
http://openvz.livejournal.com/tag/criu
https://www.heise.de/ix/meldung/Virtualisierungsplattform-OpenVZ-wird-eigenstaendige-Distribution-3278115.html
https://openvz.org/Virtuozzo
https://openvz.org/QEMU
https://www.heise.de/ix/meldung/Virtualisierungsplattform-OpenVZ-wird-eigenstaendige-Distribution-3278115.html
https://openvz.org/FAQ
https://virtuozzo.com/virtual-machines-in-virtuozzo-7/
https://openvz.org/WP/What_are_containers#Networking

Virtualisierungsangebote in D – Vergleich
https://timreeves.de/trip-content/uploads/dokumente/Internet-Mietserver-Typen_im-Vergleich.pdf

Watch dmesg Output
http://unix.stackexchange.com/questions/95842/how-can-i-see-dmesg-output-as-it-changes

Webclipse JSjet, Eclipse Neon 2 and the Outline View – what I like and what I do not like – part III

JSjet is an Eclipse plugin intended for Javascript developers, who are dissatisfied with the sparse information the present JSDT version provides you with in the Outline View and the code completion boxes. See:
Webclipse JSjet, Eclipse Neon 2 and the Outline View – what I like and what not – part I.

But a professional user would check the quality of the information provided by JSjet, too. In my last post of this mini series about JSjet
Webclipse JSjet, Eclipse Neon 2 and the Outline View – what I like and what not – part II
I discussed some strong indications that – given certain circumstances – one unfortunately cannot always trust the information JSjet provides in the Outline View. Equally important: Uncritically picking information from JSjet’s code completion dialog in Eclipse Neon 2/3 may – again under certain circumstances – lead to unintended errors in your Javascript code. It depends very much on your programming style and the philosophy behind it. Adding new properties and methods to specific objects may have severe consequences. And JSjet (Vers. 1.72.201703081933 / 2017 CI 3b) is not handling a prototypal inheritance pattern well. You should test this out in case you want to use JSjet for professional work!

Still, one may hope that Genuitec overcomes these problems in future versions. I base this hope on the fact that a conservative simple inheritance pattern is analyzed correctly with respect to variables and functions the code completion dialog can offer as valid choices. So, the required code analysis capabilities are there in the background of the duo JSjet/Tern – but they are not used properly in all cases, yet.

Are there more aspects you should think about when planning to use JSjet? Yes, in my opinion, there are. They have to do with licensing and license conditions – and what you or your company tolerates regarding data gathering about a developer’s interaction with Eclipse.

License fees – a really fair prize for one seat installations

You should be aware of the fact that Webclipse JSjet is not for free if you plan to do serious development work with it. By serious I mean work that requires more than just 8 days per month. JSjet follows your interaction with JSjet – after having used it on more of 8 days you will be asked to get a license. If I remember correctly it was not important how much you used it on these 8 days. There are company licenses and personal licenses available. Note that you would license the Webclipse product which contains much more than just JSjet; e.g., you would also get an Angular IDE.

For me as a freelancer the personal license was the interesting one. I think a price around 30 $ per year for one workstation and 2 different Eclipse installations on this machine is a fair offer. After the comments on the quality in my last post you may think differently – but, hey, what has the present JSDT to offer you instead? And their are more things included in Webclipse than just JSjet and the Outline view …

License terms – and the question of surveillance …

Now, we come to a much more critical and frustrating point – at least for Europeans with an increasing awareness of and about data gathering by IT providers. And I make a clear distinction between services which I do not have to pay money for and licensed services, which I pay in Euros or Dollars. Personally, I do not want to pay for a license and have no option to stop information gathering about my interactions with the computer and/or used programs. I do not want to pay extra with data that potentially allow for a personal work or
interest profile that an IT provider can and wants to distribute/sell to third parties without my consent. So, I get pretty annoyed when a reference to personal data is directly included in frequent information transfers about my work, interest or habits.

Actually, the license statement shown during installation of Webclipse makes it very clear that you accept data gathering when licensing. We read:

8.0 Consent to Collect, Store, and Use Information. Licensor respects your privacy rights and recognizes the importance of protecting any information collected about you. Solely for the purpose of improving Licensor Services to you, you hereby authorize and consent to the collection, storage and use of aggregate information and data related to or derived from your use of the Software and any information or data (including personally identifiable information) that you elect to provide to Licensor in connection with your use of the Software. By installing, accessing or using the Software, you consent to these information collection and usage terms, including (where applicable) the transfer of data into a country outside of the European Union and/or the European Economic Area or the United States of America. Licensor assumes no obligation to protect confidential or proprietary information that you elect to provide to Licensor (other than personally identifiable information) from disclosure, and Licensor will be free to reproduce, use, and distribute the Information (other than personally identifiable information) to others without restriction.

(Marking parts of the text with strong or cursive letters was done by me.) Ja, ja – we should trust you … It is all in our own interest …. Really? Why does it all remind me of MS Win 10? And how bad that I do not trust in any data provision via the Internet to providers where I have no control about what they do with my personalized or possibly personalizable data. So, what does Genuitec gather – and when is this information sent from Eclipse to Genuitec? Let us start with the second question first:

Information is at least sent to Genuitec via https each and every time you start Eclipse with installed Webclipse components. This will probably happen at least daily. How can you test it? I recommend Linux users to find the IP address of Genuitec (same as the website), set up corresponding firewall and log statements on your machine or network segment for outgoing traffic and analyze the packets sent. Check also for additional (!) traffic and come to your own conclusions about the frequency of information transfer !

Equally interesting is the question what kind of data is “accumulated” and where is it stored in between 2 sending processes. Regarding this question I recommend to look thoroughly through the “.metadata/.plugins” folder inside your Eclipse workspace folders. One interesting folder you find there should be “com.genuitec.eclipse.monitor“. Have a look at the contents of the file located there. Or even better: Follow its changes via a “tail -f -nxxx” command during your working processes and your interaction with Eclipse. Then think a bit about the fact that the monitoring file includes hashes for your machine/workspace. And that your license information is directly included in this file. And remember that your original license order required the provision of quite a lot of personal data. Now think once again about the frequency of data transmission. Come to your own conclusions ….

If you did what I suggested above, you may get the idea that one gets a relatively fine granular image in time of what you as a developer personally do with Eclipse – at least over each day at your workstation. And then you may start questioning what Genuitec means by “data (including personally identifiable information) that you elect to
provide to Licensor”
.

Elect“??? Where, actually, is the possibility within Eclipse or Webclipse settings to choose? If you find any possibility to “elect”, please inform me, via e-mail …. I would like to see the options for restricting the data gathered, setting the accumulation period and controlling the relation to my personal license. I did not find such options ….. Or do we need more rigorous measures to “elect“?

Needless to point out for my German readers that alone the gathering of the various of time based information on a person’s interaction with Eclipse/Webclipse is not compliant with German labor legislation. Which forbids even the possibility of following personal work activities closely without anonymization. But the data gathered in the file

.../.plugins/com.genuitec.eclipse.monitor/myeclipse-usage.properties

provides no anonymization at all and neither you nor your boss have any control about how these data are treated by Genuitec.

And in addition: By following the changes of this file closely even some of your colleagues with sufficient access rights to your workspace folder could build up a profile of your daily work and your efforts – down to a millisecond. Nice, eh …? All of course in your interest … And in the interest of all your other colleagues having separate installations on their workplaces … The collected data of a company wide Webclipse installation would allow for a work load profile of the developer department, which could be broken down to individuals. By people with sufficient rights inside your company but, of course, by Genuitec in the US, too.

Now, it may be the right time to inform the officer for personal data protection in your company. And your IT network administrator, who probably is as a friend of Linux, may start with some deeper meditation on file access rights and firewall policies for the development department of your company. And both may agree upon taking their chances to “elect” and enforce company wide data protection policies.

But be aware – simply blocking the https data transfer to Genuitec servers would have an impact on any updates based on Eclipse repositories (due to automatic dependency checks). Such updates would hang … However, if you and your admins have come to this point – you/they would know what to do to solve this problem – if it is one for you or your company, at all.

My dear friends at Genuitec – I like the direction of your work, BUT you should profoundly rethink your data gathering policies – independent of the fact that your new government recently allowed for data gathering on US users without asking for the users’ consent. Checking a license can be done totally independent of data gathering. And it would be easy to offer (European) users options on the type of data to be collected and the frequency of collection. Be sure – European Linux users will take their chances to “elect” – or leave your product.

Final conclusion

JSjet as a part of Webclipse looked and looks very promising with respect to providing a better Eclipse Outline structure for Javascript coders. You definitely get more information about the code structure than provided by JSDT.

However, in its present status the combination of JSjet/Tern also showed some profound weaknesses – and provided (in my opinion) even misleading information on classes and prototypes. As a developer you would have to adapt your coding style to these deficits to avoid unintended code errors when picking up functions from JSjet’s code completion window. And beware of using prototypal inheritance patterns! However, there is a good chance that the present problems may disappear in future versions of JSjet.

Regarding license policies: JSjet is not for free, if you have a serious workload. The license conditions include your consent to a substantial information gathering – and
you cannot separate this from the transfer of information about your personal license and workplace. The gathering of information on my interaction with Eclipse is clearly far beyond what I personally accept as tolerable. German companies should evaluate the consequences closely and in relation to the German “Arbeitsrecht” as well as local company policies. There are options to enforce such policies on the network administration side.

From Genuitec I expect options to control the data gathering on various levels, the data transfer period and a clear separation between license checks and gathering of data on user interactions with parts of Eclipse/Webclipse for the future. And of course corrections to the information presented in the Outliner – but here they may depend on the Tern project.