Docker est une plate-forme de conteneurisation qui simplifie le packaging, la distribution et le déploiement des applications. Vous pouvez exploiter les avantages de Go et Docker pour améliorer l’efficacité, la portabilité et la sécurité de vos applications.
Ce didacticiel vise à vous apprendre comment créer et déployer vos applications Go avec Docker. Vous apprendrez en créant une API RESTful avec les packages Gorilla Mux et GORM que vous conteneuriserez et déploierez.
Vous devez avoir Go et Docker installés sur votre ordinateur pour créer et conteneuriser vos applications Go avec Docker.
Assurez-vous que Go et Docker sont installés sur votre système. Vous pouvez télécharger Go depuis le site Web officiel de téléchargement Go et Docker depuis Docker Hub. Visitez la page Web si ce n’est pas le cas et suivez les instructions d’installation correspondant à votre système d’exploitation spécifique.
Cet article explique comment déployer des applications Go avec Docker et vous en apprend davantage sur l'installation et la configuration de Docker et d'une base de données Postgres, y compris la conteneurisation de vos applications Go.
Après l'installation, configurez votre environnement de développement Go en définissant les variables d'environnement et les chemins selon vos besoins. Assurez-vous que vous disposez d’un espace de travail Go fonctionnel avec la structure de répertoires requise.
De plus, vous pouvez vous familiariser avec l'interface de ligne de commande (CLI) de Docker et les concepts de base de Docker.
Créez un nouveau répertoire pour ce projet et exécutez la commande go mod init pour initialiser le répertoire en tant que projet Go.
go mod init
Après avoir initialisé le projet Go, exécutez cette commande pour ajouter les packages GORM et Gorilla Mux en tant que dépendances à votre projet.
go get github.com/gorilla/mux go get gorm.io/gorm go get gorm.io/driver/postgres
Vous utiliserez le package Gorilla Mux pour le routage. Le package GORM fournit une interface vous permettant d'utiliser les types Go pour les opérations de base de données SQL avec le package de pilotes que vous avez installé (dans ce cas, Postgres).
Dans ce didacticiel, vous utiliserez un style d'architecture en couches Go populaire et utiliserez des interfaces pour interagir avec les différents composants de notre application.
Voici la structure des répertoires de l'application.
go mod init
Cette structure de projet apparaît bien organisée, séparant clairement les préoccupations entre les différentes composantes. Cette organisation facilite la maintenance et la mise à l'échelle de votre API Go à mesure qu'elle se développe.
Ce n'est pas un standard Go. Cependant, de nombreux développeurs Go et projets open source utilisent cette structure pour vos applications.
Vous configurerez la fonctionnalité de base de données pour votre application. Vous devrez définir les modèles à l'aide de structures, vous connecter à la base de données et mettre en place des migrations pour vos opérations d'insertion sur votre base de données.
Voici la liste des importations dont vous aurez besoin pour la mise en œuvre de la base de données.
go get github.com/gorilla/mux go get gorm.io/gorm go get gorm.io/driver/postgres
La première tâche consiste à définir une structure qui correspond au schéma de votre base de données pour votre application. GORM fournit des balises pour spécifier des options et des contraintes supplémentaires sur les champs.
. ├── 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
La structure User représente le modèle permettant de travailler avec les données utilisateur dans une base de données.
Dans votre fichier database.go, déclarez une structure pour encapsuler l'instance de connexion à la base de données. Vous utiliserez la structure pour vous connecter à votre base de données à partir d’autres parties du package d’implémentation de base de données.
go mod init
Ensuite, créez une fonction de connexion à la base de données qui connecte l'implémentation de la base de données au programme de base de données à la base de données :
go get github.com/gorilla/mux go get gorm.io/gorm go get gorm.io/driver/postgres
La fonction NewDatabase crée une nouvelle instance de base de données et établit une connexion à la base de données. Il renvoie un pointeur vers l'instance de base de données et une erreur, le cas échéant, se produit pendant le processus.
Après une connexion réussie à la base de données, vous pouvez configurer la fonctionnalité de migration pour l'implémentation de votre base de données avec la fonction suivante :
. ├── 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
La fonction MgrateDB configure des migrations automatiques pour la structure User avec la fonction AutoMigrate du client de base de données et renvoie une erreur si elle est rencontrée au cours du processus.
Dans le fichier users.go où vous avez défini la structure de votre schéma de base de données, vous pouvez procéder à la définition des fonctions pour l'implémentation de la base de données.
Voici les fonctions CreateUser, GetUserByID, UpdateUser et DeleteUser responsables des opérations CRUD sur la base de données.
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" )
Votre implémentation utilisateur appellera ces fonctions pour accéder à la fonctionnalité de la base de données.
Votre implémentation utilisateur joue un rôle important dans le relais des données de la base de données vers l'implémentation HTTP.
Vous définirez une structure qui correspond à la structure dans l'implémentation de la base de données et ajouterez des balises JSON aux champs pour utilisation ; Ensuite, vous définirez des fonctions qui appellent les fonctions de base de données avec les données de l'implémentation HTTP.
Voici les importations dont vous aurez besoin pour l'implémentation de votre utilisateur :
// 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"` }
Voici la structure avec les balises JSON. Le json:"-" dans le champ gorm.Model précise que vous souhaitez exclure le champ des opérations JSON.
// internal/models/database.go type Database struct { Client *gorm.DB }
Ensuite, vous déclarerez une interface avec des méthodes pour les fonctions d'implémentation utilisateur, une structure de service pour l'implémentation utilisateur et une fonction qui initialise l'implémentation du service.
// 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 }
L'interface et le service aideront à gérer les opérations liées aux utilisateurs en dehors de la mise en œuvre de l'utilisateur.
Ensuite, vous pouvez définir les méthodes de l'implémentation de la structure UserService qui appellent l'implémentation de la base de données.
// 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 }
Les fonctions CreateUser, GetUserByID, UpdateUser et DeleteUser sont chargées d'appeler les opérations CRUD sur l'implémentation de la base de données. L'implémentation HTTP appellera ces fonctions pour accéder à la base de données.
L'implémentation HTTP fait partie de votre application qui reçoit et interagit avec les requêtes entrantes.
Voici la liste des importations dont vous aurez besoin pour votre implémentation HTTP :
go mod init
Tout d'abord, déclarez une structure et incluez une instance de routeur, une instance HTTP et une instance du service utilisateur.
go get github.com/gorilla/mux go get gorm.io/gorm go get gorm.io/driver/postgres
Créez ensuite une fonction qui renvoie un pointeur vers la structure Handler, où vous pouvez configurer le serveur et les gestionnaires.
. ├── 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
La fonction NewHandler installe et configure un gestionnaire de requêtes HTTP, le rendant prêt à gérer les requêtes HTTP entrantes pour un service spécifique tout en définissant également les paramètres et les itinéraires du serveur.
La fonction mapRoutes que vous avez appelée dans la fonction NewHandler configure les itinéraires en les mappant à leurs fonctions de gestionnaire respectives.
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" )
Ensuite, définissez les fonctions du gestionnaire et leurs fonctionnalités. Voici les fonctions CreateUser, GetUserByID, UpdateUser et DeleteUser qui sont chargées d'intercepter les requêtes HTTP et de répondre en fonction de l'opération.
// 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"` }
Maintenant, vous pouvez écrire la fonctionnalité de démarrage du serveur.
// internal/models/database.go type Database struct { Client *gorm.DB }
La fonction Serve démarre le serveur sur le port spécifié et renvoie une erreur s'il y en a pendant le processus.
Importez les implémentations dans votre fichier main.go pour coupler les implémentations et exécuter votre application.
// 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 }
Vous pouvez déclarer une fonction Run qui instancie le démarrage de votre application dans le fichier main.go puis appeler la fonction dans la fonction principale.
// 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 }
La fonction Run crée une instance de base de données, initialise la fonctionnalité de migration, initialise les implémentations HTTP et utilisateur et démarre le serveur.
Vous pouvez appeler la fonction Run dans la fonction principale pour lancer votre application.
// 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 }
L'application devrait fonctionner correctement avant d'envisager de la conteneuriser avec Docker.
Maintenant que vous avez créé et exécuté le programme avec succès, vous pouvez procéder à sa conteneurisation avec Docker.
Votre Dockerfile comportera deux étapes, la construction et l'étape finale. Cette approche réduit la taille de l'image, minimise les risques de sécurité en réduisant la surface d'attaque, garantit des performances d'exécution efficaces et facilite la reproductibilité entre les différentes étapes de développement et de déploiement.
Vous utiliserez également Alpine Linux comme image de base de vos images Docker, car elles sont plus efficaces et sécurisées avec une conception minimaliste qui se traduit par des tailles d'image plus petites, des constructions plus rapides et des surfaces d'attaque réduites.
L'utilisation des étapes de construction et finales dans un Dockerfile permet la création efficace d'images Docker. La phase de construction commence par une image de base contenant les outils de construction et les dépendances, compile les artefacts d'application et génère une image intermédiaire potentiellement volumineuse.
Voici le contenu du Dockerfile pour la phase de construction :
go mod init
L'étape finale utilise une image de base plus petite, copie uniquement les composants d'exécution nécessaires et aboutit à une image compacte optimisée pour la production.
Voici le contenu de votre Dockerfile pour l'étape finale :
go mod init
Après avoir écrit le Dockerfile, vous pouvez procéder à la création et à l'exécution du fichier.
Exécutez cette commande pour créer l'image Docker à partir du fichier avec la commande build.
go get github.com/gorilla/mux go get gorm.io/gorm go get gorm.io/driver/postgres
L'indicateur -t spécifie la balise de l'image Docker comme betterapp et le point suivant (.) spécifie que vous souhaitez créer le fichier Docker dans le répertoire actuel.
Vous pouvez exécuter l'image avec la commande run et spécifier un mappage de port du conteneur vers votre machine hôte avec l'indicateur -p.
. ├── 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
Les indicateurs -e suivants servent à spécifier les variables d'environnement pour votre application.
Docker Compose est un outil d'orchestration de conteneurs qui simplifie le travail avec plusieurs conteneurs Docker. Vous pouvez utiliser Docker Compose pour orchestrer vos applications Go et leurs composants.
Vous utiliserez un fichier YAML pour spécifier l'instruction et Docker compose configurera vos applications pour vous faire gagner du temps et de la complexité.
Tout d'abord, créez un fichier Docker Compose YAML avec la commande ci-dessous et ouvrez le fichier dans votre éditeur :
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" )
Après avoir créé le Dockerfile, vous pouvez commencer à écrire les commandes et directives pour déployer votre application :
// 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"` }
Le fichier YAML définit deux services : my-postgres qui est l'instance du conteneur de base de données et le service Web, qui est votre application Go avant de configurer leurs variables d'environnement, leurs ports et leurs dépendances.
Maintenant, vous pouvez procéder à la création des images avec la commande docker-compose build.
// internal/models/database.go type Database struct { Client *gorm.DB }
Votre résultat devrait être similaire à ceci :
Enfin, vous pouvez exécuter vos conteneurs avec la commande docker-compose up.
go mod init
L'indicateur -d exécute les conteneurs en mode détaché, ce qui le rend indépendant de la session du terminal.
Voici le résultat de l’exécution de la commande :
Vous pouvez fermer votre terminal et le conteneur devrait continuer à fonctionner.
Vous pouvez exécuter les requêtes CURL pour tester votre API une fois les conteneurs opérationnels :
go get github.com/gorilla/mux go get gorm.io/gorm go get gorm.io/driver/postgres
Félicitations, vous avez déployé et exécuté avec succès une application Go fonctionnelle avec Docker et Docker Compose.
Vous avez appris à créer et simplifier le déploiement de votre application Go avec Docker et Docker Compose. Au fur et à mesure que vous poursuivez votre parcours de développement, les compétences et la compréhension que vous avez acquises ici se révéleront des atouts essentiels pour garantir des déploiements fluides et l'excellence opérationnelle.
Envisagez d'explorer les fonctionnalités avancées de Docker, telles que l'optimisation des builds Dockerfile ou la mise en œuvre de Docker Swarm pour des applications plus volumineuses.
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!