Wo speichert ein Datenbank Docker Container seine Daten?

Frage

Die Frage, die aufgetaucht ist, ist folgende: Ich möchte einen Datenbank Docker Container zum Beispiel in OpenShift erstellen. Dies ist eine sehr einfache Sache, da OpenShift bereits Templates für diverse Datenbanklösungen wie PostgreSQL anbietet.

Die Frage ist nun: Wenn ich diese PostgreSQL Instanz verwende und fleissig Daten inserte und update – Sind diese Daten dann im Container gespeichert oder brauche ich extra einen externen Speicher?

Antwort

Docker Container sind von kurzlebiger/flüchtiger Natur – Das korrekte Englische Wort dafür ist ephemeral. Heisst, alle Daten, die ich in meinem Docker Container speichere, sind verloren, wenn ich den Container neustarte oder wenn sonst etwas mit ihm passiert.

Um Daten persistieren zu können wie etwa in einer Datenbank muss man diesen Container an einen externen Speicher anschliessen (etwa NFS, Block Storage wie SAN oder Container Native/Ready storage wie gluster/ceph). Werden die Daten dort persistiert, überdauern sie auch das brutale Töten des Docker Containers.

Wenn man dann Daten in die PostgreSQL Tabellen einfügt, schreibt es die Daten dann effektiv auf den angegebenen Speicher, den man an den Container beziehungsweise an den Pod angehängt hat.

So macht mans also richtig: Immer zuerst ein persistentes Volume anlegen und dann mit einem sogenannten Persistent Volume Claim auf diesen Speicher zugreifen.

Werbeanzeigen

Du kannst in deinem Java 8 Projekt keine JAR Datei verwenden die in einer höheren Version kompiliert wurde

Was wie das elfte Gebot klingt ist mir tatsächlich passiert: Ich habe an meinem Java 8 Projekt gearbeitet und musste dann eine Model-Klasse von einem anderen Projekt verwenden. Doof nur: Das andere Projekt ist bereits in Java 11 programmiert (noch ohne Module zu verwenden).

Ich habe mir nichts dabei gedacht, sondern wie gewohnt die Maven Abhängigkeit im Pom.xml eingetragen und kurz darauf habe ich die Jar-Datei in meinem Projekt in IntelliJ gefunden.

Als ich die Klasse versucht habe, zu verwenden, war IntelliJ sogar noch höflich zu mir und hat mir gesagt „Ja gut, ich kenne diese Klasse, die liegt doch in diesem Jar-Dings, du kannst sie also einfach importieren„.

Als ich die Klasse aber tatsächlich importiert habe kam nur die Meldung „Cannot resolve symbol„.

Ich habe alles mögliche versucht: Den Cache in IntelliJ invalidiert+restartet, den Target Ordner gelöscht und nochmals Maven:clean-install gemacht, und so weiter, aber nichts hat geholfen. IntelliJ konnte die Klasse einfach nicht finden. Selbst im Classpath war die Klasse beziehungsweise das Jar vorhanden.

Ganz zufällig habe ich etwas entdeckt, als ich die Klasse dekompiliert betrachtet habe: IntelliJ hat mich darauf hingewiesen, dass die Klasse in Java 11 kompiliert wurde. Das habe ich zu Beginn nicht gewusst, obwohl ich in diesem Blogpost natürlich explizit über genau diese Situation schreibe.

Was auch mühsam war: Bei meiner Internetrecherche bin ich auf niemanden getroffen, der die gleiche Situation beschrieben hat. Sobald man irgendwas wie „Use class from java 11 in java 8 project“ bei Google sucht kommen alles nur Anleitungen, wie man von Java 8 auf Java 11 migriert.

Weder die Internetrecherche noch meine Arbeitskollegen konnten mir weiterhelfen. Was also tun? Natürlich! Frage auf Stackoverflow gepostet und prompt hatte ich 8 Minuten später ganze 3 Antworten, die es mir erklärten:

You cannot use a jar file compiled in higher version of java in a project developed in lower version of java

Da momentan viele Firmen noch Java 8 verwenden und gegebenfalls zum Teil bereits auf Java 11 gewechselt haben ist es sicherlich praktisch, wenn jeder Java-Entwickler diesen Satz zumindest mal gehört hat.

Wie funktioniert ein Observable in Angular?

Ehrlich gesagt glaube ich, dass jeder, der einen Artikel mit solch einer Überschrift liest, bereits weiss, was ein Observer ist. Und das Thema Observer ist im Grunde eine absolut einfache Sache. In diesem Artikel erkläre ich kurz, was Observer sind und zeige es dann an einem Codebeispiel.

Was sind Obersables?

Stimmt, die heissen ja Observables, gar nicht Observer, verdammt. Ja ne, einen dooferen Namen hätten sie denen wohl nicht geben können. Sogar im Titel dieses Abschnitts habe ich es unabsichtlich falsch geschrieben.

Das Prinzip ist ganz einfach und auch unter Publish Subscribe und anderen Namen bekannt – Oder vorallem von Instagram und anderen Medienplattformen. Wir haben zum Beispiel eine ganz coole Band wie Sum 41, richtige Rockstars, die übrigens gerade jetzt ein neues Album herausbringen. Und dann haben wir Fans dieser Rockstars. Und die Fans wollen natürlich wissen, was die Rockstars so treiben, was sie zum Frühstück essen, wo das nächste Konzert ist etc. Und die Rockstars schicken natürlich gerne alle Informationen an die Fans, sobald diese bekannt sind.

PS: Ich wollte eigentlich die Band Falconer nehmen, die ein echter Geheimtipp von mir ist und die ich momentan im Repeat-Forever Modus rauf und runter höre, aber die sind so unbekannt, dass ich lieber Sum 41 genommen habe. Die kennen viele wohl noch aus ihrer Jugendzeit 🙂

Ja und die Rockstars ist also unser Observable und die Fans sind die Observer (auf Deutsch: Beobachter). Und jeder Fan klickt natürlich auf Instagram oder Youtube auf „Follow“, um immer über alles informiert zu sein – das wäre der Subscribe-Mechanismus.

But why?

Ja das frage ich mich auch jeden Abend vor dem Einschlafen: Warum braucht es eigentlich Observables? Also bei mir war es einfach so, dass in meinem aktuellen Projekt Observables verwendet werden und ich darum gezwungenermassen lernen muss, was dahinter steckt.

Na gut, schauen wir mal, was auf der offiziellen Seite steht… blabla… blabla… ah ja, hier steht es: Es geht darum, dass Komponenten miteinander kommunizieren wollen, und dass es asynchron passiert, also nicht blockierend.

Gut, irgendwie finde ich das auch komisch, zu erklären, warum es Observables braucht. Frag mal einen Sum 41 Fan, warum er die neuesten News von der Band haben will… Na logisch, er will halt immer auf dem aktuellen Stand sein. Und dass es nicht blockiert, wie wir Informatiker zu sagen pflegen, ist auch logisch: Kein Fan möchte permanent auf der Sum 41-Homepage sein und aktualisieren drücken, sondern die Nachrichten bequem erhalten, sobald es Neuigkeiten gibt.

Aber wem erkläre ich das eigentlich? Wir alle werden ja mittlerweile todgespamt von allen möglichen Apps, die uns Push-Notifications zusenden.

Aber gut, genug geschwatzt, bevor mir auch noch die letzte Handvoll Leser weglaufen, bringe ich lieber mein Code-Beispiel.

Lass uns ein Observable in Angular bauen

Das Beispiel ist todlangweilig (Super Einstieg, um Spannung aufzubauen, Anm. des Reviewers):

  • Wir haben eine Liste von Studenten in der Rockband (Observable)
  • und die Fans (Observer) erhalten entweder die Informatikstudenten oder die Chemiestudenten als Liste serviert.

Zuerst brauchen wir ein Beispielprojekt. Sie wissen schon, wie man ein Projekt erstellt, oder? In Java fängt auch nicht jedes Tutorial damit an, wie man ein Projekt in Eclipse erstellt. Aber vielleicht ist das ein Ritual bei Angular-Tutorials, also falls Sie es nicht wissen würden: Sie müssen mittels npm angular installieren und dann folgenden Befehl ausführen:

ng new echt-cooles-projekt

Okay haben wir diese Hürde genommen. Als nächstes erstellen wir eine einfache Model-Klasse von einem Studenten. Im Ordner „src -> app“ können Sie die folgende Datei student.model.ts erstellen:

export class Student {
   id: number;
   name: string;
   fach: string;
 }

Nun kommt der eigentliche Observer. Diesen packen wir gleich neben das Student-Model in eine Datei student.service.ts und die sieht folgendermassen aus:

import { Injectable } from '@angular/core';
import { Student } from './student.model';
import { Observable, Observer } from 'rxjs';

@Injectable({
  providedIn: 'root'
})
export class StudentService {

  outsideObserver;

  informatikStudenten: Student[] = [{
    id: 1,
    name: 'Fritz',
    fach: 'Informatik'
  },
  {
    id: 2,
    name: 'Hans',
    fach: 'Informatik'
  }];

  chemieStudenten: Student[] = [{
    id: 3,
    name: 'Peter',
    fach: 'Chemie'
  }];

  constructor() {

    // 5000 steht für 5000 Millisekunden bzw. Sekunden
    setTimeout(() => {
      console.log('wechsle jetzt zu Chemiestudenten mit next');
      this.outsideObserver.next(this.chemieStudenten);
    }, 7000);

    // Das reine Löschen der Daten von aussen aktualisiert die Daten im Client nicht
    // Erst nach einem erneuten next() Aufruf
    setTimeout(() => {
      console.log('lösche jetzt die Informatikstudenten ohne next aufzurufen');
      this.informatikStudenten = [];
      console.log(this.informatikStudenten);
    }, 10000);
  }

  public getStudents(): any {
    const studentsObservable = new Observable(observer => {
      this.outsideObserver = observer;

      observer.next(this.informatikStudenten);

      setTimeout(() => {
        console.log('Jetzt schicke ich nochmals die Informatikstudenten mit next');
        observer.next(this.informatikStudenten);
      }, 12000);

      setTimeout(() => {
        console.log('sende nochmals Chemiestudenten mit next');
        observer.next(this.chemieStudenten);
      }, 16000);

      setTimeout(() => {
        console.log('Verarbeitung complete');
        // Nach einem Complete funktioniert kein error() und kein next() mehr
        observer.complete();
      }, 18000);

      // Nach einem Error funktioniert kein next() mehr
      setTimeout(() => {
        observer.error('Verdammt dieser Fehler bringt nach dem Complete gar nichts!!!');
      }, 20000);

    });

    return studentsObservable;
  }
}

Häh? Ich versteh nichts! Ich werde lieber Kebabverkäufer!

Pah, das kann gar nicht sein, ich habe das Beispiel extra einfach und verständlich gewählt!

Also gut, ich erkläre, was ich gemacht habe:

a) Die Klasse beinhaltet zwei Listen von Studenten: Informatikstudenten und Chemiestudenten. Diese wollen wir später auf der Homepage sehen.

b) Die Rockband selber findet sich in der Methode getStudents();. Dort sieht es auch komplizierter aus, als es tatsächlich ist. Ich habe einige setTimeout()’s eingebaut, welche nach und nach ausgeführt werden, damit wir das Verhalten des Observables untersuchen können. Die könnte man auch weglassen.

Das Wichtigste ist aber einfach das erstellen des Observables mit new.

Die ganze Geschichte mit dem outsideObserver können Sie eigentlich ignorieren. Das habe ich nur eingebaut, um zu zeigen, dass man das Observables auch speichern und später an einer anderen Stelle wiederverwenden kann – Was ich nämlich in keinem anderen Tutorial im Internet gefunden habe.

Die drei Methoden des Observables

Und was man dann noch wissen muss: Ein Observables – so mühsam ich dieses Wort auch finde – hat drei Methoden, die es verwenden kann:

  1. Mit next() werden alle Fans, die ein Abo haben, mit den neuesten Infos versorgt – Welche Infos das auch immer sein mögen, das kann man ja selber definieren.
  2. Mit error() kann man das Passwort des Fans auslesen. Neeeiiiinnn natürlich kann man damit eine Fehlermeldung schmeissen.
  3. Mit complete() kann man die Rockstars quasi in Rente schicken. Nach einem complete() geht next() oder error() nicht mehr, das Observable ist dann abgeschlossen. Ist übrigens optional, der Informationsfluss kann durchaus einfach offenbleiben.

Ja gut, jetzt haben wir sogar noch ein wenig Theorie gelernt.

Was ganz wichtig bei der ganzen Sache ist: Observer abonnieren zwar Informationen von den Observables, wenn ein Observable die Daten intern ändert, kriegt der Observer das aber noch nicht mit! Erst wenn der Observable die Methode next() aufruft, werden die Daten an alle Observer mit einem Abonnement verschickt.

Einen neuen Fan erstellen – Vielleicht sogar einen Groupie!

In unserem neuen Projekt können wir gleich die Datei app.component.ts für den Fan beziehungsweise den Observer verwenden. Dieser muss der Rockband mitteilen, dass sie jetzt alle News haben möchte. Das sieht dann so aus:

import { Component, OnInit } from '@angular/core';
import { Student } from './student.model';
import { StudentService } from './student.service';
import { Observable } from 'rxjs';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {

  students: Student[] = [];
  studentsObserver;

  constructor(private studentService: StudentService) {}

  ngOnInit() {
    this.studentsObserver = this.studentService.getStudents();
  }

  getStudentData() {
    this.studentsObserver.subscribe((studentsData: Student[]) => {
      this.students = studentsData;
    });
  }

}

Hier sehen wir, wie das StudentService-Observable in den Konstruktor depency-injected wird (erklären Sie diesen Satz mal Ihrer Mutter…).

In der Methode getStudentData() wird dann effektiv das Abonnement abgeschlossen und auch gleich mitgegeben, wohinein die geschickten Daten gespeichert werden sollen.

Ich habe das ganze bewusst ein wenig auseinandergenommen um zu zeigen, dass der Code an verschiedenen Stellen in der Datei liegen kann.

Die Methode getStudentData() wird dabei von einem Button in der Datei app.component.html aufgerufen. Das sieht so aus:

(PS: Falls im Code unten „>“ steht, das sollte einfach ein „>“ sein. Ich weiss nicht, warum das Anzeigen von HTML in WordPress so schwer ist…)

<p&gt;Öffne die Entwicklerkonsole mit F12 um die Meldungen zu sehen</p&gt;
<p&gt;Bitte rasch einmalig auf den Button drücken, um die Informatikstudenten zu sehen</p&gt;

<button (click)="getStudentData()"&gt;Zeig die Studenten an</button&gt;

<div class="col-md-3 col-xs-6" *ngFor="let student of students"&gt;
  <p&gt;{{ student.id }}</p&gt;
  <p&gt;{{ student.name }}</p&gt;
  <p&gt;{{ student.fach }}</p&gt;
  <hr&gt;
</div&gt;

Ja, als Konsequenz ist es halt so, dass Sie beim Start der Applikation den Knopf drücken müssen, damit das Abonnement abgeschlossen wird. Aber das Leben ist nun mal eine seriöse Angelegenheit. Da fällt mir gleich ein Zitat von einem „Falconer-Lied ein, das lautet:

There are too many stones and life ist just made of glass

Hmm im Lied klingt das irgendwie eindrucksvoller als einfach so geschrieben. Das Lied heisst übrigens „Busted to the floor„. Witziger Fact: Beim Erfinder dieses Titels handelt es sich um dieselbe Person, die auch den Observables den Namen gegeben hat!

Okay, wo waren wir?

Ah ja, also alles reinkopiert und dann Server gestartet mit

ng serve

dann http://localhost:4200/ aufgerufen und gleich den angezeigten Button geklickt.

Dann noch mit F12 die Entwicklerkonsole aufgemacht und schon können Sie schön nachvollziehen, wie die Studenten nacheinander vom Observable an den Observer geschickt werden.

Gut, ich gebe zu, ich habe heute Morgen wohl eine Clownsmannschaft gefrühstückt, aber es ist auch sauheiss hier und ausserdem Freitag, da muss man sich eine grosse Portion schlechten Humor bewahren. Wenn Ihnen das nicht passt schreiben Sie mir doch bitte einen Kommentar unten hin, das würde mich freuen!

In dem Sinne viel Glück mit der weiteren Angular-Programmierung!