Docker 是一個容器化平台,可以簡化應用程式的打包、分發和部署。您可以利用 Go 和 Docker 的優勢來提高應用程式的效率、可移植性和安全性。
本教學致力於教您如何使用 Docker 建置和部署 Go 應用程式。您將透過使用 Gorilla Mux 和 GORM 套件建立 RESTful API 來學習,並將其容器化和部署。
您需要在電腦上安裝 Go 和 Docker,才能使用 Docker 建置和容器化您的 Go 應用程式。
確保您的系統上安裝了 Go 和 Docker。您可以從 Go 官方下載網站下載 Go,從 Docker Hub 下載 Docker。如果尚未造訪該網頁,請造訪該網頁,然後按照您的特定作業系統的安裝說明進行操作。
本文介紹如何使用 Docker 部署 Go 應用程序,並介紹有關安裝和設定 Docker 和 Postgres 資料庫的更多信息,包括容器化 Go 應用程式。
安裝完成後,根據需要設定環境變數和路徑來設定您的Go開發環境。確保您有一個具有所需目錄結構的工作 Go 工作區。
此外,您還可以熟悉 Docker 的命令列介面 (CLI) 和基本 Docker 概念。
為此專案建立一個新目錄,並執行 go mod init 指令將該目錄初始化為 Go 專案。
go mod init
初始化 Go 專案後,執行此命令將 GORM 和 Gorilla Mux 套件作為依賴項新增至您的專案。
go get github.com/gorilla/mux go get gorm.io/gorm go get gorm.io/driver/postgres
您將使用 Gorilla Mux 套件進行路由。 GORM 套件提供了一個接口,供您使用 Go 類型進行 SQL 資料庫操作以及您安裝的驅動程式套件(在本例中為 Postgres)。
在本教程中,您將使用流行的 Go 分層架構風格並使用介面與我們應用程式的各個元件進行互動。
這是應用程式的目錄結構。
go mod init
這個專案結構看起來組織良好,清楚地分離了不同組件之間的關注點。隨著 Go API 的發展,這個組織可以讓您更輕鬆地維護和擴展它。
這不是 Go 標準。然而,許多 Go 開發人員和開源專案在您的應用程式中使用這種結構。
您將為您的應用程式設定資料庫功能。您必須使用結構定義模型,連接到資料庫,並為資料庫上的插入操作設定遷移。
這是資料庫實作所需的導入清單。
go get github.com/gorilla/mux go get gorm.io/gorm go get gorm.io/driver/postgres
第一個任務是定義一個與您的應用程式的資料庫架構相符的支柱。 GORM 提供了用於指定欄位的附加選項和約束的標籤。
. ├── 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
User 結構體表示處理資料庫中使用者資料的模型。
在您的database.go 檔案中,宣告一個結構體來封裝資料庫連線實例。您將使用該結構從資料庫實現套件的其他部分連接到資料庫。
go mod init
接下來,建立一個資料庫連接函數,將資料庫實作與資料庫程式連接到資料庫:
go get github.com/gorilla/mux go get gorm.io/gorm go get gorm.io/driver/postgres
NewDatabase 函數建立一個新的資料庫實例並建立與資料庫的連線。它會傳回一個指向資料庫實例的指針,並且在此過程中發生錯誤(如果有)。
成功連接資料庫後,您可以使用以下函數為資料庫實作設定遷移功能:
. ├── 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
MgrateDB 函數使用資料庫用戶端 AutoMigrate 函數為 User 結構設定自動遷移,如果在此過程中遇到任何問題,則傳回錯誤。
在為資料庫架構定義結構的 users.go 檔案中,您可以繼續定義資料庫實作的函數。
這裡是負責資料庫CRUD操作的CreateUser、GetUserByID、UpdateUser和DeleteUser函數。
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" )
您的使用者實作將呼叫這些函數來存取資料庫功能。
您的使用者實作在將資料從資料庫中繼到 HTTP 實作方面發揮著重要作用。
您將定義一個與資料庫實作中的結構相符的結構,並將 JSON 標籤新增至欄位以供使用;然後,您將定義使用 HTTP 實作中的資料呼叫資料庫函數的函數。
以下是使用者實作所需的導入:
// 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"` }
這是一個有 JSON 標籤的結構。 gorm.Model 欄位中的 json:"-" 指定您要從 JSON 操作中排除該欄位。
// internal/models/database.go type Database struct { Client *gorm.DB }
接下來,您將聲明一個接口,其中包含用戶實現函數的方法、用戶實現的服務結構以及初始化服務實現的函數。
// 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 }
介面和服務將協助管理使用者實作以外的與使用者相關的操作。
接下來,您可以定義呼叫資料庫實作的 UserService 結構實作的方法。
// 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 }
CreateUser、GetUserByID、UpdateUser 和 DeleteUser 函數負責呼叫資料庫實作上的 CRUD 操作。 HTTP 實作將會呼叫這些函數來存取資料庫。
HTTP 實作是應用程式的一部分,用於接收傳入請求並與之互動。
這是您在 HTTP 實作中所需的匯入清單:
go mod init
首先,宣告一個結構體並包含一個 Router 實例、一個 HTTP 實例和一個使用者服務實例。
go get github.com/gorilla/mux go get gorm.io/gorm go get gorm.io/driver/postgres
然後建立一個傳回指向 Handler 結構的指標的函數,您可以在其中設定伺服器和處理程序。
. ├── 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
NewHandler 函數設定並設定 HTTP 請求處理程序,使其準備好處理特定服務的傳入 HTTP 請求,同時定義伺服器設定和路由。
您在 NewHandler 函數中呼叫的 mapRoutes 函數透過將路由對應到各自的處理函數來設定路由。
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" )
接下來,定義處理函數及其功能。 這裡有CreateUser、GetUserByID、UpdateUser和DeleteUser函數,它們負責攔截HTTP請求並根據操作回應。
// 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"` }
現在,您可以編寫啟動伺服器的功能了。
// internal/models/database.go type Database struct { Client *gorm.DB }
Serve 函數在指定連接埠上啟動伺服器,如果過程中發生錯誤,則傳回錯誤。
匯入 main.go 檔案中的實作以耦合實作並執行您的應用程式。
// 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 }
您可以在 main.go 檔案中宣告一個 Run 函數來實例化應用程式的啟動,然後在 main 函數中呼叫該函數。
// 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 }
Run 函數建立一個資料庫實例,初始化遷移功能,初始化 HTTP 和 User 實作並啟動伺服器。
您可以在主函數中呼叫 Run 函數來啟動您的應用程式。
// 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 }
在考慮使用 Docker 對其進行容器化之前,應用程式應該運作良好。
現在您已經成功建置並運行了程序,您可以繼續使用 Docker 將其容器化。
您的 Dockerfile 將有兩個階段:建置階段和最終階段。這種方法可以減少影像大小,透過減少攻擊面來最大限度地降低安全風險,確保高效的運行時效能,並促進不同開發和部署階段的可重複性。
您還將使用 Alpine Linux 作為 Docker 映像的基礎映像,因為它們更有效率、更安全,並且採用極簡設計,可實現更小的映像大小、更快的建置速度和更少的攻擊面。
使用 Dockerfile 中的建置和最終階段可以有效地建立 Docker 映像。建置階段從包含建置工具和相依性的基礎映像開始,編譯應用程式工件,並產生可能較大的中間映像。
這是建置階段的 Dockerfile 的內容:
go mod init
最後階段採用較小的基礎映像,僅複製必要的執行時間元件,並產生針對生產最佳化的緊湊映像。
以下是最後階段的 Dockerfile 內容:
go mod init
編寫 Dockerfile 後,您可以繼續建置並執行該檔案。
執行此命令以使用 build 命令從檔案建立 Docker 映像。
go get github.com/gorilla/mux go get gorm.io/gorm go get gorm.io/driver/postgres
-t 標誌指定 Docker 映像的標籤為 betterapp,後面的點 (.) 指定您要在目前目錄中建置 Dockerfile。
您可以使用 run 指令執行映像,並使用 -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
隨後的 -e 標誌用於為您的應用程式指定環境變數。
Docker Compose 是一個容器編排工具,可以簡化多個 Docker 容器的使用。您可以使用 Docker compose 來編排您的 Go 應用程式及其元件。
您將使用 YAML 檔案來指定指令,Docker compose 將設定您的應用程式以節省您的時間和複雜性。
首先,使用以下命令建立一個 Docker Compose YAML 文件,然後在編輯器中開啟該文件:
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" )
建立 Dockerfile 後,您可以開始編寫用於部署應用程式的命令和指令:
// 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"` }
YAML 檔案定義了兩個服務:my-postgres(資料庫容器實例)和 Web 服務(在設定環境變數、連接埠和相依性之前您的 Go 應用程式)。
現在,您可以繼續使用 docker-compose build 指令來建置映像。
// internal/models/database.go type Database struct { Client *gorm.DB }
您的輸出應與此類似:
最後,您可以使用 docker-compose up 指令來執行容器。
go mod init
-d 標誌以分離模式運行容器,這使得它與終端會話無關。
這是運行指令的結果:
您可以關閉終端,容器應該繼續運作。
容器啟動後,您可以執行 CURL 請求來測試您的 API:
go get github.com/gorilla/mux go get gorm.io/gorm go get gorm.io/driver/postgres
恭喜,您已經使用 Docker 和 Docker Compose 成功部署並運行了一個工作 Go 應用程式。
您已經學習如何使用 Docker 和 Docker Compose 建置和簡化 Go 應用程式的部署。當您繼續您的開發之旅時,您在這裡獲得的技能和理解將被證明是確保順利部署和卓越營運的重要資產。
考慮探索進階 Docker 功能,例如最佳化 Dockerfile 建置或為大型應用程式實作 Docker Swarm。
以上是如何使用 Docker 部署 Go 應用程式的詳細內容。更多資訊請關注PHP中文網其他相關文章!