Docker ist eine Containerisierungsplattform, die das Packen, Verteilen und Bereitstellen von Anwendungen vereinfacht. Sie können die Vorteile von Go und Docker nutzen, um die Effizienz, Portabilität und Sicherheit Ihrer Anwendungen zu verbessern.
In diesem Tutorial lernen Sie, wie Sie Ihre Go-Anwendungen mit Docker erstellen und bereitstellen können. Sie lernen, indem Sie eine RESTful-API mit den Gorilla Mux- und GORM-Paketen erstellen, die Sie in Containern speichern und bereitstellen.
Sie müssen Go und Docker auf Ihrem Computer installiert haben, um Ihre Go-Apps mit Docker zu erstellen und zu containerisieren.
Stellen Sie sicher, dass Go und Docker auf Ihrem System installiert sind. Sie können Go von der offiziellen Go-Download-Website und Docker vom Docker Hub herunterladen. Besuchen Sie die Webseite, falls Sie dies noch nicht getan haben, und befolgen Sie die Installationsanweisungen für Ihr spezifisches Betriebssystem.
In diesem Artikel erfahren Sie, wie Sie Go-Apps mit Docker bereitstellen und erfahren mehr über die Installation und Einrichtung von Docker und einer Postgres-Datenbank, einschließlich der Containerisierung Ihrer Go-Anwendungen.
Konfigurieren Sie nach der Installation Ihre Go-Entwicklungsumgebung, indem Sie Umgebungsvariablen und Pfade nach Bedarf festlegen. Stellen Sie sicher, dass Sie über einen funktionierenden Go-Arbeitsbereich mit der erforderlichen Verzeichnisstruktur verfügen.
Darüber hinaus können Sie sich mit der Befehlszeilenschnittstelle (CLI) von Docker und den grundlegenden Docker-Konzepten vertraut machen.
Erstellen Sie ein neues Verzeichnis für dieses Projekt und führen Sie den Befehl go mod init aus, um das Verzeichnis als Go-Projekt zu initialisieren.
go mod init
Führen Sie nach der Initialisierung des Go-Projekts diesen Befehl aus, um die Pakete GORM und Gorilla Mux als Abhängigkeiten zu Ihrem Projekt hinzuzufügen.
go get github.com/gorilla/mux go get gorm.io/gorm go get gorm.io/driver/postgres
Für das Routing verwenden Sie das Gorilla Mux-Paket. Das GORM-Paket bietet eine Schnittstelle, über die Sie Go-Typen für SQL-Datenbankoperationen zusammen mit dem von Ihnen installierten Treiberpaket (in diesem Fall Postgres) verwenden können.
In diesem Tutorial verwenden Sie einen beliebten Go-Schichtarchitekturstil und verwenden Schnittstellen, um mit den verschiedenen Komponenten unserer App zu interagieren.
Hier ist die Verzeichnisstruktur der Anwendung.
go mod init
Diese Projektstruktur erscheint gut organisiert und trennt die Anliegen klar zwischen verschiedenen Komponenten. Diese Organisation erleichtert die Wartung und Skalierung Ihrer Go-API, wenn sie wächst.
Dies ist kein Go-Standard. Allerdings verwenden viele Go-Entwickler und Open-Source-Projekte diese Struktur für Ihre Anwendungen.
Sie richten die Datenbankfunktionalität für Ihre Anwendung ein. Sie müssen die Modelle mithilfe von Strukturen definieren, eine Verbindung zur Datenbank herstellen und Migrationen für Ihre Einfügevorgänge in Ihrer Datenbank einrichten.
Hier ist die Liste der Importe, die Sie für die Datenbankimplementierung benötigen.
go get github.com/gorilla/mux go get gorm.io/gorm go get gorm.io/driver/postgres
Die erste Aufgabe besteht darin, einen Strut zu definieren, der Ihrem Datenbankschema für Ihre App entspricht. GORM bietet Tags zum Angeben zusätzlicher Optionen und Einschränkungen für Felder.
. ├── Dockerfile ├── cmd │ └── server │ └── main.go └── internal ├── http │ ├── handlers.go │ └── users.go ├── models │ ├── database.go │ ├── migrations.go │ └── users.go └── users └── user.go 6 directories, 11 files
Die Benutzerstruktur stellt das Modell für die Arbeit mit Benutzerdaten in einer Datenbank dar.
Deklarieren Sie in Ihrer Datenbank.go-Datei eine Struktur, um die Datenbankverbindungsinstanz zu kapseln. Sie verwenden die Struktur, um von anderen Teilen des Datenbankimplementierungspakets aus eine Verbindung zu Ihrer Datenbank herzustellen.
go mod init
Als nächstes erstellen Sie eine Datenbankverbindungsfunktion, die die Datenbankimplementierung mit dem Datenbankprogramm mit der Datenbank verbindet:
go get github.com/gorilla/mux go get gorm.io/gorm go get gorm.io/driver/postgres
Die NewDatabase-Funktion erstellt eine neue Datenbankinstanz und stellt eine Verbindung zur Datenbank her. Es gibt einen Zeiger auf die Datenbankinstanz zurück und während des Prozesses tritt gegebenenfalls ein Fehler auf.
Nach einer erfolgreichen Datenbankverbindung können Sie die Migrationsfunktionalität für Ihre Datenbankimplementierung mit der Funktion wie folgt einrichten:
. ├── Dockerfile ├── cmd │ └── server │ └── main.go └── internal ├── http │ ├── handlers.go │ └── users.go ├── models │ ├── database.go │ ├── migrations.go │ └── users.go └── users └── user.go 6 directories, 11 files
Die MgrateDB-Funktion richtet mit der AutoMigrate-Funktion des Datenbank-Clients automatische Migrationen für die Benutzerstruktur ein und gibt einen Fehler zurück, wenn während des Prozesses ein Fehler auftritt.
In der Datei „users.go“, in der Sie die Struktur für Ihr Datenbankschema definiert haben, können Sie mit der Definition der Funktionen für die Datenbankimplementierung fortfahren.
Hier sind die Funktionen „CreateUser“, „GetUserByID“, „UpdateUser“ und „DeleteUser“, die für CRUD-Vorgänge in der Datenbank verantwortlich sind.
package models import ( // imports from the user implementation "BetterApp/internal/users" "context" "gorm.io/gorm" "fmt" "gorm.io/driver/postgres" "gorm.io/gorm/schema" "os" )
Ihre Benutzerimplementierung ruft diese Funktionen auf, um auf die Datenbankfunktionalität zuzugreifen.
Ihre Benutzerimplementierung spielt eine wichtige Rolle bei der Weiterleitung von Daten aus der Datenbank an die HTTP-Implementierung.
Sie definieren eine Struktur, die mit der Struktur in der Datenbankimplementierung übereinstimmt, und fügen den Feldern JSON-Tags zur Verwendung hinzu. Anschließend definieren Sie Funktionen, die die Datenbankfunktionen mit den Daten aus der HTTP-Implementierung aufrufen.
Hier sind die Importe, die Sie für Ihre Benutzerimplementierung benötigen:
// internal/models/users.go type User struct { gorm.Model Username string `gorm:"unique;not null"` Email string `gorm:"unique;not null"` IsActive bool `gorm:"not null"` }
Hier ist die Struktur mit JSON-Tags. Der json:"-" im Feld gorm.Model gibt an, dass Sie das Feld von den JSON-Vorgängen ausschließen möchten.
// internal/models/database.go type Database struct { Client *gorm.DB }
Als nächstes deklarieren Sie eine Schnittstelle mit Methoden für die Benutzerimplementierungsfunktionen, eine Dienststruktur für die Benutzerimplementierung und eine Funktion, die die Dienstimplementierung initialisiert.
// internal/models/database.go func NewDatabase() (*Database, error) { // Construct a connection string using environment variables for database configuration. configurations := fmt.Sprintf("host=%v port=%v user=%v password=%v dbname=%v sslmode=%v", os.Getenv("DB_HOST"), os.Getenv("DB_PORT"), os.Getenv("DB_USERNAME"), os.Getenv("DB_PASSWORD"), os.Getenv("DB_NAME"), os.Getenv("SSL_MODE")) // Open a connection to the database using GORM and PostgreSQL driver. db, err := gorm.Open(postgres.New(postgres.Config{ DSN: configurations, PreferSimpleProtocol: true, }), &gorm.Config{NamingStrategy: schema.NamingStrategy{ SingularTable: true, }}) if err != nil { return nil, err } // Enable connection pooling by configuring maximum idle and open connections. sqlDB, err := db.DB() if err != nil { return nil, err } sqlDB.SetMaxIdleConns(10) sqlDB.SetMaxOpenConns(100) // Return the Database instance with the established database connection. return &Database{ Client: db, }, nil }
Die Schnittstelle und der Dienst helfen bei der Verwaltung benutzerbezogener Vorgänge außerhalb der Benutzerimplementierung.
Als nächstes können Sie Methoden der UserService-Strukturimplementierung definieren, die die Datenbankimplementierung aufrufen.
// internal/models/migrations.go func (d *Database) MigrateDB() error { log.Println("Database Migration in Process...") // Use GORM AutoMigrate to migrate all the database schemas. err := d.Client.AutoMigrate(&User{}) if err != nil { return err } log.Println("Database Migration Complete!") return nil }
Die Funktionen „CreateUser“, „GetUserByID“, „UpdateUser“ und „DeleteUser“ sind für den Aufruf der CRUD-Vorgänge in der Datenbankimplementierung verantwortlich. Die HTTP-Implementierung ruft diese Funktionen auf, um auf die Datenbank zuzugreifen.
Die HTTP-Implementierung ist Teil Ihrer Anwendung, die eingehende Anfragen empfängt und mit ihnen interagiert.
Hier ist die Liste der Importe, die Sie für Ihre HTTP-Implementierung benötigen:
go mod init
Deklarieren Sie zunächst eine Struktur und schließen Sie eine Router-Instanz, eine HTTP-Instanz und eine Instanz des Benutzerdienstes ein.
go get github.com/gorilla/mux go get gorm.io/gorm go get gorm.io/driver/postgres
Erstellen Sie dann eine Funktion, die einen Zeiger auf die Handler-Struktur zurückgibt, in der Sie den Server und die Handler konfigurieren können.
. ├── Dockerfile ├── cmd │ └── server │ └── main.go └── internal ├── http │ ├── handlers.go │ └── users.go ├── models │ ├── database.go │ ├── migrations.go │ └── users.go └── users └── user.go 6 directories, 11 files
Die NewHandler-Funktion richtet einen HTTP-Anforderungshandler ein und konfiguriert ihn, um ihn für die Verarbeitung eingehender HTTP-Anfragen für einen bestimmten Dienst bereit zu machen und gleichzeitig Servereinstellungen und Routen zu definieren.
Die Funktion „mapRoutes“, die Sie in der Funktion „NewHandler“ aufgerufen haben, richtet Routen ein, indem sie sie ihren jeweiligen Handlerfunktionen zuordnet.
package models import ( // imports from the user implementation "BetterApp/internal/users" "context" "gorm.io/gorm" "fmt" "gorm.io/driver/postgres" "gorm.io/gorm/schema" "os" )
Als nächstes definieren Sie die Handlerfunktionen und ihre Funktionalitäten. Hier sind die Funktionen „CreateUser“, „GetUserByID“, „UpdateUser“ und „DeleteUser“, die für das Abfangen von HTTP-Anfragen und die Antwort basierend auf dem Vorgang verantwortlich sind.
// internal/models/users.go type User struct { gorm.Model Username string `gorm:"unique;not null"` Email string `gorm:"unique;not null"` IsActive bool `gorm:"not null"` }
Jetzt können Sie die Funktionalität zum Starten des Servers schreiben.
// internal/models/database.go type Database struct { Client *gorm.DB }
Die Serve-Funktion startet den Server am angegebenen Port und gibt einen Fehler zurück, falls während des Vorgangs ein Fehler auftritt.
Importieren Sie die Implementierungen in Ihre main.go-Datei, um die Implementierungen zu koppeln und Ihre App auszuführen.
// internal/models/database.go func NewDatabase() (*Database, error) { // Construct a connection string using environment variables for database configuration. configurations := fmt.Sprintf("host=%v port=%v user=%v password=%v dbname=%v sslmode=%v", os.Getenv("DB_HOST"), os.Getenv("DB_PORT"), os.Getenv("DB_USERNAME"), os.Getenv("DB_PASSWORD"), os.Getenv("DB_NAME"), os.Getenv("SSL_MODE")) // Open a connection to the database using GORM and PostgreSQL driver. db, err := gorm.Open(postgres.New(postgres.Config{ DSN: configurations, PreferSimpleProtocol: true, }), &gorm.Config{NamingStrategy: schema.NamingStrategy{ SingularTable: true, }}) if err != nil { return nil, err } // Enable connection pooling by configuring maximum idle and open connections. sqlDB, err := db.DB() if err != nil { return nil, err } sqlDB.SetMaxIdleConns(10) sqlDB.SetMaxOpenConns(100) // Return the Database instance with the established database connection. return &Database{ Client: db, }, nil }
Sie können eine Run-Funktion deklarieren, die den Start Ihrer App in der main.go-Datei instanziiert, und dann die Funktion in der Hauptfunktion aufrufen.
// internal/models/migrations.go func (d *Database) MigrateDB() error { log.Println("Database Migration in Process...") // Use GORM AutoMigrate to migrate all the database schemas. err := d.Client.AutoMigrate(&User{}) if err != nil { return err } log.Println("Database Migration Complete!") return nil }
Die Run-Funktion erstellt eine Datenbankinstanz, initialisiert die Migrationsfunktionalität, initialisiert die HTTP- und Benutzerimplementierungen und startet den Server.
Sie können die Funktion „Ausführen“ in der Hauptfunktion aufrufen, um Ihre Anwendung zu starten.
// internal/models/users.go func (d *Database) CreateUser(ctx context.Context, user *users.User) error { newUser := &User{ Username: user.Username, Email: user.Email, IsActive: false, } if err := d.Client.WithContext(ctx).Create(newUser).Error; err != nil { return err } return nil } // GetUserByID returns the user with a specified id func (d *Database) GetUserByID(ctx context.Context, id int64) (users.User, error) { user := users.User{} if err := d.Client.WithContext(ctx).Where("id = ?", id).First(&user).Error; err != nil { return users.User(User{}), err } return users.User(User{ Username: user.Username, Email: user.Email, IsActive: user.IsActive, }), nil } // UpdateUser updates an existing user in the database func (d *Database) UpdateUser(ctx context.Context, updatedUser users.User, id uint) error { // Check if the user with the specified ID exists var existingUser User if err := d.Client.WithContext(ctx).Where("id = ?", id).First(&existingUser).Error; err != nil { return err } // Update the fields of the existing user with the new values existingUser.Username = updatedUser.Username existingUser.Email = updatedUser.Email existingUser.IsActive = updatedUser.IsActive // Save the updated user back to the database if err := d.Client.WithContext(ctx).Save(&existingUser).Error; err != nil { return err } return nil } // DeleteUser deletes a user from the database by their ID func (d *Database) DeleteUser(ctx context.Context, id uint) error { // Check if the user with the specified ID exists var existingUser User if err := d.Client.WithContext(ctx).Where("id = ?", id).First(&existingUser).Error; err != nil { return err } // Delete the user from the database if err := d.Client.WithContext(ctx).Delete(&existingUser).Error; err != nil { return err } return nil }
Die Anwendung sollte einwandfrei laufen, bevor Sie über die Containerisierung mit Docker nachdenken.
Nachdem Sie das Programm erfolgreich erstellt und ausgeführt haben, können Sie mit der Containerisierung mit Docker fortfahren.
Ihre Docker-Datei besteht aus zwei Phasen: der Build- und der Endphase. Dieser Ansatz reduziert die Bildgröße, minimiert Sicherheitsrisiken durch Reduzierung der Angriffsfläche, gewährleistet eine effiziente Laufzeitleistung und erleichtert die Reproduzierbarkeit über verschiedene Entwicklungs- und Bereitstellungsphasen hinweg.
Sie verwenden Alpine Linux auch als Basis-Image Ihrer Docker-Images, da diese effizienter und sicherer sind und ein minimalistisches Design zu kleineren Image-Größen, schnelleren Builds und geringeren Angriffsflächen führt.
Die Verwendung der Build- und Endphasen in einer Docker-Datei ermöglicht die effiziente Erstellung von Docker-Images. Die Build-Phase beginnt mit einem Basis-Image, das Build-Tools und Abhängigkeiten enthält, kompiliert Anwendungsartefakte und generiert ein potenziell großes Zwischen-Image.
Hier ist der Inhalt der Docker-Datei für die Build-Phase:
go mod init
In der letzten Phase wird ein kleineres Basis-Image verwendet, nur die notwendigen Laufzeitkomponenten kopiert und ein kompaktes, für die Produktion optimiertes Image erstellt.
Hier ist der Inhalt Ihrer Docker-Datei für die letzte Phase:
go mod init
Nachdem Sie die Docker-Datei geschrieben haben, können Sie mit dem Erstellen und Ausführen der Datei fortfahren.
Führen Sie diesen Befehl aus, um das Docker-Image aus der Datei mit dem Build-Befehl zu erstellen.
go get github.com/gorilla/mux go get gorm.io/gorm go get gorm.io/driver/postgres
Das Flag -t gibt den Tag für das Docker-Image als betterapp an und der folgende Punkt (.) gibt an, dass Sie die Docker-Datei im aktuellen Verzeichnis erstellen möchten.
Sie können das Image mit dem Befehl „run“ ausführen und mit dem Flag -p eine Portzuordnung vom Container zu Ihrem Host-Computer angeben.
. ├── Dockerfile ├── cmd │ └── server │ └── main.go └── internal ├── http │ ├── handlers.go │ └── users.go ├── models │ ├── database.go │ ├── migrations.go │ └── users.go └── users └── user.go 6 directories, 11 files
Die nachfolgenden -e-Flags dienen der Angabe von Umgebungsvariablen für Ihre Anwendung.
Docker Compose ist ein Container-Orchestrierungstool, das die Arbeit mit mehreren Docker-Containern vereinfacht. Sie können Docker Compose verwenden, um Ihre Go-Apps und ihre Komponenten zu orchestrieren.
Sie verwenden eine YAML-Datei, um die Anweisung anzugeben, und Docker Compose richtet Ihre Anwendungen ein, um Ihnen Zeit und Komplexität zu sparen.
Erstellen Sie zunächst eine Docker Compose YAML-Datei mit dem folgenden Befehl und öffnen Sie die Datei in Ihrem Editor:
package models import ( // imports from the user implementation "BetterApp/internal/users" "context" "gorm.io/gorm" "fmt" "gorm.io/driver/postgres" "gorm.io/gorm/schema" "os" )
Nachdem Sie die Docker-Datei erstellt haben, können Sie mit dem Schreiben der Befehle und Anweisungen für die Bereitstellung Ihrer App beginnen:
// internal/models/users.go type User struct { gorm.Model Username string `gorm:"unique;not null"` Email string `gorm:"unique;not null"` IsActive bool `gorm:"not null"` }
Die YAML-Datei definiert zwei Dienste: my-postgres, die Datenbank-Container-Instanz, und den Webdienst, der Ihre Go-Anwendung ist, bevor deren Umgebungsvariablen, Ports und Abhängigkeiten konfiguriert werden.
Jetzt können Sie mit dem Build-Befehl docker-compose mit dem Erstellen der Images fortfahren.
// internal/models/database.go type Database struct { Client *gorm.DB }
Ihre Ausgabe sollte etwa so aussehen:
Schließlich können Sie Ihre Container mit dem Befehl docker-compose up ausführen.
go mod init
Das Flag -d führt die Container im getrennten Modus aus, wodurch sie unabhängig von der Terminalsitzung sind.
Hier ist das Ergebnis der Ausführung des Befehls:
Sie können Ihr Terminal schließen und der Container sollte weiterlaufen.
Sie können die CURL-Anfragen ausführen, um Ihre API zu testen, sobald die Container aktiv sind:
go get github.com/gorilla/mux go get gorm.io/gorm go get gorm.io/driver/postgres
Herzlichen Glückwunsch, Sie haben erfolgreich eine funktionierende Go-App mit Docker und Docker Compose bereitgestellt und ausgeführt.
Sie haben gelernt, wie Sie die Bereitstellung Ihrer Go-App mit Docker und Docker Compose erstellen und vereinfachen. Während Sie Ihre Entwicklungsreise fortsetzen, werden sich die Fähigkeiten und das Verständnis, die Sie hier erworben haben, als wesentliche Vorteile für die Gewährleistung reibungsloser Bereitstellungen und operativer Exzellenz erweisen.
Erwägen Sie die Erkundung erweiterter Docker-Funktionen wie die Optimierung von Dockerfile-Builds oder die Implementierung von Docker Swarm für größere Anwendungen.
Das obige ist der detaillierte Inhalt vonSo stellen Sie Go-Anwendungen mit Docker bereit. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!