Erster Container für Entwicklung
Für die erste Nutzung als Entwickler, werden wir ein vorhandenes Beispielprojekt aus dem
GitHub Repository nehmen. Es liegt im Unterordner blazor-postgres.
Wie der Name schon andeutet, handelt es sich um eine Web-Anwendung mit Blazor. Die Anwendung nutzt zur Datenspeicherung die Datenbank Postgres. Die Datenbank wollen wir als Container ausführen. Das bietet folgende Vorteile:
- Keine großen Administrator Vorkenntnisse zu Postgres Datenbank notwendig
- Wir können jederzeit entscheiden, welche Version der Datenbank wir nutzen wollen (z.B. kann eine ältere Version der Applikation eine ältere DB Version erfordern - für Fehlerkorrekturen)
- Wir können sehr schnell einen “sauberen” Zustand der Datenbank erzeugen.
Starten der Applikation
Falls noch nicht geschehen, müssen Sie die .Net SDK 10 für Ihr Betriebssystem installieren.
Öffnen Sie den Projektordner in dem Editor Ihrer Wahl. Ich nutze dafür VS Code mit der installierten Erweiterung “C# DevKit”.
Versuchen Sie die App nur zu starten, ohne dass wir aktuell eine passende Datenbank dazu haben.
dotnet run
Da die Anwendung bereits beim Start eine Verbindung zur Datenbank erfordert, scheitert der Start mit einer Fehlermeldung.
dotnet run
Die Starteinstellungen von /Users/eugen/src/container-kurs/blazor-postgres/Properties/launchSettings.json werden verwendet…
Buildvorgang wird ausgeführt...
fail: Microsoft.EntityFrameworkCore.Database.Connection[20004]
An error occurred using the connection to database 'devdb' on server 'tcp://localhost:5432'.
Unhandled exception. Npgsql.NpgsqlException (0x80004005): Failed to connect to 127.0.0.1:5432
---> System.Net.Sockets.SocketException (61): Connection refused
at Npgsql.Internal.NpgsqlConnector.Connect(NpgsqlTimeout timeout)
at Npgsql.Internal.NpgsqlConnector.Connect(NpgsqlTimeout timeout)
at Npgsql.Internal.NpgsqlConnector.RawOpen(NpgsqlTimeout timeout, Boolean async, CancellationToken cancellationToken)
at Npgsql.Internal.NpgsqlConnector.<Open>g__OpenCore|209_0(NpgsqlConnector conn, String username, SslMode sslMode, GssEncryptionMode gssEncMode, NpgsqlTimeout timeout, Boolean async, CancellationToken cancellationToken)
at Npgsql.Internal.NpgsqlConnector.Open(NpgsqlTimeout timeout, Boolean async, CancellationToken cancellationToken)
at Npgsql.PoolingDataSource.OpenNewConnector(NpgsqlConnection conn, NpgsqlTimeout timeout, Boolean async, CancellationToken cancellationToken)
at Npgsql.PoolingDataSource.<Get>g__RentAsync|33_0(NpgsqlConnection conn, NpgsqlTimeout timeout, Boolean async, CancellationToken cancellationToken)
at Npgsql.NpgsqlConnection.<Open>g__OpenAsync|42_0(Boolean async, CancellationToken cancellationToken)
at Npgsql.NpgsqlConnection.Open()
at Microsoft.EntityFrameworkCore.Storage.RelationalConnection.OpenDbConnection(Boolean errorsExpected)
at Microsoft.EntityFrameworkCore.Storage.RelationalConnection.OpenInternal(Boolean errorsExpected)
at Microsoft.EntityFrameworkCore.Storage.RelationalConnection.Open(Boolean errorsExpected)
at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReader(RelationalCommandParameterObject parameterObject)
at Microsoft.EntityFrameworkCore.Migrations.HistoryRepository.GetAppliedMigrations()
at Npgsql.EntityFrameworkCore.PostgreSQL.Migrations.Internal.NpgsqlHistoryRepository.GetAppliedMigrations()
at Microsoft.EntityFrameworkCore.RelationalDatabaseFacadeExtensions.GetAppliedMigrations(DatabaseFacade databaseFacade)
at Microsoft.EntityFrameworkCore.RelationalDatabaseFacadeExtensions.GetPendingMigrations(DatabaseFacade databaseFacade)
at BlazorWebAppMovies.Data.SeedData.Initialize(IServiceProvider serviceProvider) in /Users/eugen/src/container-kurs/blazor-postgres/Data/SeedData.cs:line 20
at Program.<Main>$(String[] args) in /Users/eugen/src/container-kurs/blazor-postgres/Program.cs:line 23
Start der Postgres Datenbank
Damit die Anwendung starten können, müssen wir die Postgres Datenbank starten. Dazu suchen wir auf dem größten Repository für Container Images, dem hub.docker.com von Docker Inc., nach Postgres.
Kategorisierung in Docker Hub
Die Suche gibt uns sehr viele Ergebnisse zu Postgres, da jeder auf diesem Hub Images veröffentlichen kann. Docker Hub hilft uns ein wenig dabei, das richtige Image herauszufinden, in dem es die Image-Repositories kategorisiert.
Es gibt sogenannte “offizielle” Image, die direkt von den Entwicklern der jeweiligen Software zur Verfügung gestellt werden. Nach der Verifizierung, bekommen diese ein Siegel “Docker Official Image”. Damit sind solche Images am vertrauenswürdigsten. Man erkenn solche Images relativ einfach, an den Namen.
Die Namen von den offiziellen Images, haben keinen Präfix. Das haben wir bereits bei nginx gesehen. Auch da bestand der Image-Name nur aus dem Namen der Software. Bei Postgres heißt das Image auch einfach postgres.
Eine weitere Kategorie sind die “Verified Publisher”. Dabei handelt es sich zwar nicht um die “Ersteller” der jeweiligen Software, aber um Firmen, die von Docker Inc. validiert und für vertrauenswürdig befunden worden. Es sind of Firmen, die selbst Ihr Geld mit Containern verdienen und optimierte Images für bestimmte Bereiche liefern. Zu den “Verified Publisher” gehören zum Beispiel
- CircleCI: Ein CI/CD as a Service Anbieter
- Microsoft
- Ubuntu
- Bitnami: Anbieter von VM Images / Container Images
Aussuchen der notwendigen Parameter
Wir nutzen für unseren Zweck das offizielle Image von Postgres. Wenn wir in der Suche diesen auswählen, erscheint die Detail-Seite des Repositories. Hier finden wir die Beschreibung, wie das vorhandene Container-Image beim Starten mit Parametern angepasst werden kann. Oft stehen auch Informationen, welche Version, Basis-Images und Architekturen unterstützt werden.
Das Postgres Repository hat zum Beispiel Images für:
- Postgres-Versions: 18, 17, 16, 15, 14, 13, 12
- Architekturen: amd64, arm32v5, arm32v6, arm32v7, arm64v8, i386, mips64le, ppc64le, riscv64, s390x
- Basis-Images
- alpine: Basiert auf Alpine-Linux
- bullseye: Basiert auf Debian Trixie (13)
- bookworm: Basiert auf Debian Bookworm (12)
Um auf die Datenbank in unserer Anwendung zugreifen zu können, müssen wir folgende Einstellungen für die Datenbank wissen / setzen:
- Benutzername
- Kann im offiziellen Image über Umgebungsvariable
POSTGRES_USERgesetzt werden (Standardwert istpostgres)
- Kann im offiziellen Image über Umgebungsvariable
- Passwort
- Muss im offiziellen Image über Umgebungsvariable
POSTGRES_PASSWORDgesetzt werden
- Muss im offiziellen Image über Umgebungsvariable
- Datenbankname
- Kann im offiziellen Image über Umgebungsvariable
POSTGRES_DBgesetzt werden (Standardwert entspricht dem Benutzernamen)
- Kann im offiziellen Image über Umgebungsvariable
Die Umgebungsvariablen werden an Docker Runtime mit dem Parameter -e übergeben (kann auch mehrmals verwendet werden).
Aus den gesammelten Informationen, können wir nun den geforderten (kürzesten) Aufruf ableiten:
docker run -e POSTGRES_USER=devuser \
-e POSTGRES_PASSWORD=devpassword \
-e POSTGRES_DB=devdb \
-p 5432:5432 -d postgres:18-alpine
-e POSTGRES_USER=devuser: setzt den Benutzernamen aufdevuser-e POSTGRES_PASSWORD=devpassword: setzt das Passwort aufdevpassword-e POSTGRES_DB=devdb: setzt die Datenbankname aufdevdb-p 5432:5432: ordnet den Standard Port von Postgres zu demselben Port auf unserem Host zupostgres:18-alpine: startet den Postgres Container mit der Version 18 und dem Alpine-Basis-Image

Postgres Container in Docker Desktop
Starten der Applikation mit laufender Datenbank
Nun läuft die Postgres Datenbank im Hintergrund (in der Version 18), so dass die App auf diese Zugreifen kann. Da wir einige Einstellungen nicht angegeben haben, werden dabei Standardwerte genutzt.
--name: Wir haben dem Container keinen expliziten Namen gegeben. Aus diesem Fall wird dieser durch die Runtime “gewürfelt”. Bei meinem ersten Start war der Namefunny_austin.
Wenn wir jetzt die Applikation starten. In der Ausgabe wird auch die URL Angezeigt, unter der die Applikation erreichbar ist.
dotnet run
Using launch settings from /Users/eugen/src/container-kurs/blazor-postgres/Properties/launchSettings.json...
Building...
fail: Microsoft.EntityFrameworkCore.Database.Command[20102]
Failed executing DbCommand (10ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
SELECT "MigrationId", "ProductVersion"
FROM "__EFMigrationsHistory"
ORDER BY "MigrationId";
fail: Microsoft.EntityFrameworkCore.Database.Command[20102]
Failed executing DbCommand (1ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
SELECT "MigrationId", "ProductVersion"
FROM "__EFMigrationsHistory"
ORDER BY "MigrationId";
info: Microsoft.EntityFrameworkCore.Migrations[20411]
Acquiring an exclusive lock for migration application. See https://aka.ms/efcore-docs-migrations-lock for more information if this takes too long.
info: Microsoft.EntityFrameworkCore.Migrations[20402]
Applying migration '20241206073458_Init'.
info: Microsoft.Hosting.Lifetime[14]
Now listening on: http://localhost:5216
info: Microsoft.Hosting.Lifetime[0]
Application started. Press Ctrl+C to shut down.
Öffnen Sie die Applikation nun unter der ausgegebenen Adresse http://localhost:5216.
