《Go 简易速速上手小册》第10章:微服务与云原生应用(2024 最新版)
文章目录
- 10.1 构建微服务架构 - 探索 Go 语言的微观世界
- 10.1.1 基础知识讲解
- 10.1.2 重点案例:订单处理系统
- 订单服务
- 测试服务
- 10.1.3 拓展案例 1:用户认证服务
- 安装所需的包
- 实现用户模型和存储
- 实现 JWT 生成和验证
- 实现认证服务
- 测试服务
- 10.1.4 拓展案例 2:商品推荐服务
- 设计商品推荐服务
- 实现简化的推荐服务
- 集成推荐服务到订单系统
- 测试服务
- 10.2 容器化与 Go - 打包你的 Go 应用航向云端
- 10.2.1 基础知识讲解
- 10.2.2 重点案例:Go Web 服务的容器化
- 步骤一:编写Go Web服务
- 步骤二:编写 Dockerfile
- 步骤三:构建和运行容器
- 测试服务
- 10.2.3 拓展案例 1:多阶段构建优化
- 功能描述
- 步骤一:优化 Dockerfile
- 步骤二:构建和运行容器
- 步骤三:验证镜像大小的优化
- 测试服务
- 10.2.3 拓展案例 2:为 Go 微服务创建 Docker Compose 环境
- 功能描述
- 步骤一:准备用户服务和产品服务
- 步骤二:编写 Dockerfile
- 步骤三:编写 Docker Compose 文件
- 步骤四:启动服务
- 测试服务
- 10.3 云原生技术栈与 Go - Go 语言在云上的航行
- 10.3.1 基础知识讲解
- 10.3.2 重点案例:Go 微服务在 Kubernetes 上的部署
- 步骤一:准备 Go 微服务
- 步骤二:容器化 Go 微服务
- 步骤三:编写 Kubernetes 部署配置
- 步骤四:部署到 Kubernetes
- 步骤五:访问微服务
- 10.3.3 拓展案例 1:使用 Helm 管理 Go 应用的 Kubernetes 部署
- 步骤一:创建 Helm Chart
- 步骤二:定制化 Chart
- 步骤三:打包和部署 Chart
- 步骤四:验证部署
- 步骤五:更新和升级
- 10.3.4 拓展案例 2:实现 Go 微服务的自动扩展
- 步骤一:准备 Go 微服务
- 步骤二:为微服务启用资源请求和限制
- 步骤三:创建 HPA
- 步骤四:测试自动扩展
- 步骤五:调整 HPA 策略(可选)
10.1 构建微服务架构 - 探索 Go 语言的微观世界
10.1.1 基础知识讲解
微服务架构是一种将单一应用程序划分成一组小服务的方法,每个服务运行在其独立的进程中,服务之间通过轻量级的通信机制(通常是HTTP资源API)相互协作、相互独立部署。这种架构允许快速、可靠和频繁地部署大型、复杂的应用程序。
微服务架构的核心特点包括:
- 服务分离:每个微服务负责应用程序的一小部分功能,并可以独立更新和扩展。
- 自治性:每个服务都是独立部署的,有自己的数据库和数据管理模型,减少了服务间的依赖。
- 技术多样性:不同的服务可以使用不同的编程语言和数据存储技术开发,使得技术栈更加灵活。
- 可扩展性:可以根据需要对特定功能进行扩展,而不必重新部署整个应用。
Go 在微服务中的应用
Go语言以其并发支持、高性能和简洁语法成为构建微服务的热门选择。Go的标准库提供了强大的网络和HTTP支持,使得开发RESTful API变得简单快捷。
10.1.2 重点案例:订单处理系统
在这个扩展案例中,我们将构建一个简单的订单处理系统,演示如何使用Go语言和gin
框架开发微服务。这个系统将包含订单服务的基础实现,包括创建订单和查询订单详情的功能。
订单服务
安装gin
框架
首先,确保安装了gin
框架:
go get -u github.com/gin-gonic/gin
定义订单模型
在订单服务中,我们定义一个Order
结构体来表示订单信息:
// models.gopackage maintype Order struct {ID string `json:"id"`Items []Item `json:"items"`Total float64 `json:"total"`
}type Item struct {ProductID string `json:"product_id"`Quantity int `json:"quantity"`Price float64 `json:"price"`
}
实现订单服务
我们使用gin
来创建RESTful API,处理创建和查询订单的请求:
// order_service.gopackage mainimport ("github.com/gin-gonic/gin""net/http"
)var orders = []Order{{ID: "1", Items: []Item{{ProductID: "101", Quantity: 2, Price: 15.0}}, Total: 30.0},
}func main() {router := gin.Default()router.POST("/orders", createOrder)router.GET("/orders/:id", getOrder)router.Run(":8080")
}func createOrder(c *gin.Context) {var newOrder Orderif err := c.ShouldBindJSON(&newOrder); err != nil {c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})return}// 这里简化处理,直接添加到数组。在实际应用中,应保存到数据库。newOrder.ID = "2" // 假设生成的订单IDorders = append(orders, newOrder)c.JSON(http.StatusCreated, newOrder)
}func getOrder(c *gin.Context) {orderID := c.Param("id")for _, order := range orders {if order.ID == orderID {c.JSON(http.StatusOK, order)return}}c.JSON(http.StatusNotFound, gin.H{"error": "Order not found"})
}
在这个简单的示例中,我们实现了两个API端点:/orders
用于创建新订单,/orders/:id
用于查询指定ID的订单详情。为了简化,我们将创建的订单存储在内存中的一个切片中,并未使用数据库。
测试服务
- 创建订单:使用
curl
或Postman发送POST请求到http://localhost:8080/orders
,请求体包含订单数据。 - 查询订单:发送GET请求到
http://localhost:8080/orders/1
,获取ID为1的订单详情。
通过这个案例,你已经学会了如何使用Go语言和gin
框架开发简单的微服务。虽然这个订单处理系统非常基础,但它为你提供了微服务架构下开发复杂系统的起点。随着你进一步深入学习,你将能够添加更多服务,如支付服务和库存服务,使用消息队列处理服务间通信,甚至使用容器化和云原生技术来部署你的微服务。
10.1.3 拓展案例 1:用户认证服务
在这个扩展案例中,我们将为订单处理系统添加一个用户认证服务,使用JSON Web Tokens (JWT)进行安全认证。这个服务将负责用户的注册、登录,并在成功登录后发放JWT,以便用户在访问受保护的订单服务时进行身份验证。
安装所需的包
首先,安装gin
框架和JWT相关的Go包:
go get -u github.com/gin-gonic/gin
go get -u github.com/golang-jwt/jwt/v4
实现用户模型和存储
为简化,我们使用内存存储来保存用户信息和模拟数据库操作:
// models.gopackage maintype User struct {Username stringPassword string // 注意:实际应用中应存储密码的哈希值
}var userStore = map[string]string{"user1": "password1", // 用户名:密码,实际应用中应存储密码的哈希值
}
实现 JWT 生成和验证
定义一个简单的JWT管理器,用于生成和验证JWT:
// jwt_manager.gopackage mainimport ("fmt""time""github.com/golang-jwt/jwt/v4"
)var jwtKey = []byte("my_secret_key") // 保持安全type Claims struct {Username string `json:"username"`jwt.RegisteredClaims
}func GenerateJWT(username string) (string, error) {expirationTime := time.Now().Add(1 * time.Hour)claims := &Claims{Username: username,RegisteredClaims: jwt.RegisteredClaims{ExpiresAt: jwt.NewNumericDate(expirationTime),},}token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)tokenString, err := token.SignedString(jwtKey)return tokenString, err
}func ValidateToken(tokenString string) (*Claims, bool) {claims := &Claims{}token, err := jwt.ParseWithClaims(tokenString, claims, func(token *jwt.Token) (interface{}, error) {return jwtKey, nil})if err != nil {return nil, false}return claims, token.Valid
}
实现认证服务
使用gin
框架实现用户注册、登录以及JWT验证的中间件:
// auth_service.gopackage mainimport ("github.com/gin-gonic/gin""net/http"
)func main() {router := gin.Default()router.POST("/login", login)router.GET("/orders", authenticateJWT(), getOrder) // 使用JWT中间件保护订单服务router.Run(":8080")
}func login(c *gin.Context) {var user Userif err := c.ShouldBindJSON(&user); err != nil {c.JSON(http.StatusBadRequest, gin.H{"error": "Bad request"})return}// 模拟用户认证expectedPassword, ok := userStore[user.Username]if !ok || expectedPassword != user.Password {c.JSON(http.StatusUnauthorized, gin.H{"error": "Authentication failed"})return}// 生成JWTtoken, err := GenerateJWT(user.Username)if err != nil {c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to generate token"})return}c.JSON(http.StatusOK, gin.H{"token": token})
}func authenticateJWT() gin.HandlerFunc {return func(c *gin.Context) {const Bearer_schema = "Bearer "header := c.GetHeader("Authorization")if header == "" {c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "Authorization header missing"})return}tokenString := header[len(Bearer_schema):]claims, valid := ValidateToken(tokenString)if !valid {c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "Invalid token"})return}// Token is valid, add username to the contextc.Set("username", claims.Username)c.Next()}
}func getOrder(c *gin.Context) {// 获取订单逻辑c.JSON(http.StatusOK, gin.H{"message": "Order details"})
}
在这个示例中,login
函数处理用户登录请求,成功认证后生成JWT。authenticateJWT
是一个中间件,用于保护需要认证的路由,它验证请求中的JWT并提取用户名。
测试服务
- 登录:发送POST请求到
http://localhost:8080/login
,包含用户名和密码,以获取JWT。 - 访问受保护的路由:使用获取的JWT作为
Authorization
头发送GET请求到http://localhost:8080/orders
。
通过这个拓展案例,你已经学会了如何在Go语言中添加用户认证服务,并使用JWT进行安全认证。这是构建现代Web应用和微服务的关键组成部分,确保了数据的安全访问和服务的安全调用。随着你对Go和微服务架构的深入理解,你将能够构建更加安全、可靠的应用。
10.1.4 拓展案例 2:商品推荐服务
在这个拓展案例中,我们将为订单处理系统添加一个商品推荐服务,根据用户的购买历史和浏览行为来推荐商品。此服务将独立于订单处理系统,通过事件驱动方式接收用户行为数据,并使用简单的算法来生成推荐。
设计商品推荐服务
核心概念
- 用户行为数据:包括用户的购买记录和浏览历史,用于分析用户偏好。
- 推荐算法:基于用户行为数据,推算出可能感兴趣的商品。
- 事件驱动:该服务通过监听用户行为事件(如购买或浏览商品)来触发推荐算法。
实现简化的推荐服务
为了保持示例的简洁性,我们将使用一个静态的商品列表来模拟商品数据库,并实现一个基于用户最近购买商品的简单推荐算法。
模拟商品数据库
// products.gopackage mainvar products = []string{"Go Programming Book","Rubber Duck","Pirate Hat","Gin Framework Guide","Kubernetes Deployment Handbook",
}
实现推荐逻辑
// recommendation_service.gopackage mainimport ("fmt""math/rand""time"
)func recommendProduct(boughtProduct string) string {rand.Seed(time.Now().UnixNano())recommendedIndex := rand.Intn(len(products))// 简单地从产品列表中随机选择一个产品作为推荐,确保推荐的产品不是刚买的产品for products[recommendedIndex] == boughtProduct {recommendedIndex = rand.Intn(len(products))}return products[recommendedIndex]
}
集成推荐服务到订单系统
我们将模拟用户购买商品后接收推荐的过程。在订单服务中,每当用户购买商品,我们将调用推荐服务来推荐另一个商品。
// order_service.gopackage mainimport ("github.com/gin-gonic/gin""net/http"
)func main() {router := gin.Default()router.POST("/purchase", purchaseProduct)router.Run(":8080")
}func purchaseProduct(c *gin.Context) {type Purchase struct {ProductName string `json:"product_name"`}var purchase Purchaseif err := c.ShouldBindJSON(&purchase); err != nil {c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request"})return}recommendedProduct := recommendProduct(purchase.ProductName)c.JSON(http.StatusOK, gin.H{"message": "Purchase successful", "recommended_product": recommendedProduct})
}
在这个简单的示例中,当用户通过POST请求到/purchase
端点购买一个商品时,系统将返回一个推荐的商品。这个推荐是基于一个简单的随机选择算法,实际应用中,推荐算法会更加复杂,可能会考虑用户的购买历史、商品相似度、用户评分等因素。
测试服务
- 购买商品:发送 POST 请求到
http://localhost:8080/purchase
,包含要购买的商品名称,查看返回的推荐商品。
通过这个拓展案例,你了解了如何为现有的订单处理系统添加一个简单的商品推荐服务。虽然这里使用的推荐算法非常基础,但它展示了如何基于用户行为数据来增加额外的服务和功能,为用户提供个性化体验。随着技术的深入,你可以探索更高级的算法和技术,如机器学习,来进一步提升推荐系统的准确性和效率。
10.2 容器化与 Go - 打包你的 Go 应用航向云端
10.2.1 基础知识讲解
容器化是一种轻量级、可移植的软件打包技术,它允许开发者将应用及其全部依赖一起打包成一个容器镜像。这种方法确保了应用在不同环境中的一致性和可靠性。Docker是目前最流行的容器化平台,提供了一个标准化的方法来打包、分发和运行容器化应用。
为什么 Go 适合容器化?
- 高效的二进制文件:Go编译后的应用是单个二进制文件,包含了所有依赖,非常适合放入轻量级的容器中。
- 跨平台编译:Go支持交叉编译,可以轻松为不同平台生成二进制文件,进一步增强了容器的可移植性。
- 快速启动时间:Go应用启动速度快,非常适合在容器环境中快速扩展和部署。
容器化 Go 应用的基本步骤:
- 编写Dockerfile:定义如何在容器中构建和运行Go应用。
- 构建容器镜像:使用Dockerfile和源代码构建可部署的容器镜像。
- 运行容器:从镜像启动容器,运行你的Go应用。
10.2.2 重点案例:Go Web 服务的容器化
让我们通过一个实际的示例来演示如何将一个简单的Go编写的Web服务容器化,从而可以在任何支持Docker的环境中运行。
步骤一:编写Go Web服务
首先,我们需要创建一个简单的HTTP服务。以下是服务的代码,它会在根路径/
上响应带有欢迎信息的HTTP请求。
main.go:
package mainimport ("fmt""net/http"
)func main() {http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {fmt.Fprintf(w, "Hello, Dockerized World!")})fmt.Println("Server is running on port 8080...")http.ListenAndServe(":8080", nil)
}
步骤二:编写 Dockerfile
接下来,我们需要为我们的Go应用编写一个Dockerfile
。这个Dockerfile
使用了多阶段构建,第一阶段用于构建应用,第二阶段运行应用。
Dockerfile:
# 第一阶段:构建环境
FROM golang:1.16-alpine AS buildWORKDIR /app# 复制模块文件并下载依赖
COPY go.mod go.sum ./
RUN go mod download# 复制源代码
COPY *.go ./# 编译应用
RUN CGO_ENABLED=0 GOOS=linux go build -o /go-web-app# 第二阶段:运行环境
FROM scratch# 从构建阶段复制编译好的二进制文件
COPY --from=build /go-web-app /go-web-app# 暴露端口
EXPOSE 8080# 定义入口点
ENTRYPOINT ["/go-web-app"]
步骤三:构建和运行容器
使用以下命令构建Docker镜像,并运行容器:
docker build -t go-web-app .
docker run -d -p 8080:8080 go-web-app
-t go-web-app
:给镜像命名为go-web-app
。-d
:后台运行容器。-p 8080:8080
:将容器的8080端口映射到宿主机的8080端口。
测试服务
在浏览器或使用命令行工具(如curl
)访问http://localhost:8080
,你应该会看到“Hello, Dockerized World!”的欢迎信息。
例如,使用curl
测试:
curl http://localhost:8080
输出应为:
Hello, Dockerized World!
通过这个案例,你已经学会了如何将一个简单的Go Web服务容器化。这个过程涉及到编写应用代码、创建Dockerfile以及使用Docker命令构建和运行容器。容器化不仅使得部署变得简单快捷,而且提高了应用的可移植性和一致性,为在云环境中运行提供了便利。随着你对Docker和容器化技术的进一步探索,你将能够更有效地开发、部署和管理Go应用。
10.2.3 拓展案例 1:多阶段构建优化
在Docker容器化的上下文中,多阶段构建是一种优化技术,它允许在一个Dockerfile中使用多个构建阶段,但最终只将必要的文件复制到最终镜像中。这样做的好处是可以显著减小最终镜像的大小,同时保持构建过程的清晰和高效。
功能描述
为了展示多阶段构建优化,我们将使用前面创建的Go Web服务案例,并优化其Dockerfile,以减小最终产生的Docker镜像的大小。
步骤一:优化 Dockerfile
以下是针对Go Web服务的多阶段构建优化后的Dockerfile:
# 第一阶段:构建环境
FROM golang:1.16-alpine AS builderWORKDIR /app# 复制Go模块和依赖文件
COPY go.mod go.sum ./
RUN go mod download# 复制源代码
COPY . .# 编译Go应用为静态链接的二进制文件
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o go-web-app .# 第二阶段:运行环境
FROM alpine:latest RUN apk --no-cache add ca-certificatesWORKDIR /root/# 从构建阶段复制编译好的二进制文件
COPY --from=builder /app/go-web-app .# 暴露端口
EXPOSE 8080# 定义入口点
CMD ["./go-web-app"]
在这个优化后的Dockerfile中,我们在第二阶段使用了alpine:latest
作为基础镜像,而不是scratch
。这是因为alpine
镜像虽然相对较小,但包含了运行大多数应用所需的最小系统和库,包括ca-certificates
,这对于执行HTTPS请求非常重要。同时,通过使用CGO_ENABLED=0
编译Go应用,我们确保生成的二进制文件是静态链接的,没有依赖于C库,这让它可以在几乎任何Linux环境下运行。
步骤二:构建和运行容器
使用优化后的Dockerfile,按照之前的步骤构建并运行容器:
docker build -t go-web-app-optimized .
docker run -d -p 8080:8080 go-web-app-optimized
步骤三:验证镜像大小的优化
你可以使用以下命令来比较优化前后镜像的大小,看到多阶段构建优化带来的效果:
docker images | grep go-web-app
你应该会注意到,使用多阶段构建优化后的镜像大小要比原始镜像小得多。
测试服务
确保服务正常运行,通过访问http://localhost:8080
或使用curl
命令测试:
curl http://localhost:8080
应返回“Hello, Dockerized World!”的欢迎信息。
通过这个拓展案例,你学会了如何通过多阶段构建来优化Go应用的Docker镜像大小,使其更适合生产环境部署。这种优化不仅减少了资源消耗,还加快了镜像的传输和部署速度,是容器化应用部署中的一个重要实践。随着你深入探索Docker和容器技术,你将能够构建更高效、更安全的容器化应用。
10.2.3 拓展案例 2:为 Go 微服务创建 Docker Compose 环境
在微服务架构中,通常需要同时管理多个服务。Docker Compose是一个用于定义和运行多容器Docker应用程序的工具。通过使用Docker Compose,你可以使用YAML文件来配置应用的服务,并且通过一个简单的命令来启动和停止所有服务。
功能描述
假设我们有两个Go微服务:一个是用户服务,用于处理用户的注册和登录请求;另一个是产品服务,用于管理产品信息。我们将使用Docker Compose来定义这两个服务,并确保它们可以在同一网络中相互通信。
步骤一:准备用户服务和产品服务
为了简化,我们将为用户服务和产品服务各自创建一个简单的HTTP服务器。每个服务都监听不同的端口,并提供基本的RESTful API。
用户服务(UserService):
// userService/main.go
package mainimport ("fmt""net/http"
)func main() {http.HandleFunc("/users", func(w http.ResponseWriter, r *http.Request) {fmt.Fprintf(w, "User service is up!")})fmt.Println("User service listening on port 8081...")http.ListenAndServe(":8081", nil)
}
产品服务(ProductService):
// productService/main.go
package mainimport ("fmt""net/http"
)func main() {http.HandleFunc("/products", func(w http.ResponseWriter, r *http.Request) {fmt.Fprintf(w, "Product service is up!")})fmt.Println("Product service listening on port 8082...")http.ListenAndServe(":8082", nil)
}
步骤二:编写 Dockerfile
为每个服务编写一个Dockerfile。由于这两个服务结构类似,Dockerfile也会非常相似。
# Dockerfile
FROM golang:1.16-alpineWORKDIR /appCOPY go.mod ./
COPY go.sum ./
RUN go mod downloadCOPY *.go ./RUN go build -o serviceEXPOSE 8081 # 对于用户服务
# EXPOSE 8082 # 对于产品服务CMD ["./service"]
请根据实际服务调整EXPOSE
行。
步骤三:编写 Docker Compose 文件
创建docker-compose.yml
文件来定义用户服务和产品服务。
version: '3.8'
services:user-service:build:context: ./userServicedockerfile: Dockerfileports:- "8081:8081"product-service:build:context: ./productServicedockerfile: Dockerfileports:- "8082:8082"
这个docker-compose.yml
文件定义了两个服务:user-service
和product-service
。它们分别映射了对应的端口到宿主机,以便你可以从宿主机访问这些服务。
步骤四:启动服务
在包含docker-compose.yml
文件的目录中运行以下命令来构建和启动服务:
docker-compose up --build
这将根据每个服务的Dockerfile构建镜像,然后启动容器。--build
选项确保在启动服务之前构建或重新构建镜像。
测试服务
一旦服务启动,你可以通过访问http://localhost:8081/users
和http://localhost:8082/products
来测试用户服务和产品服务是否正常运行。
通过这个拓展案例,你已经学会了如何使用Docker Compose来定义和管理多个Go微服务。Docker Compose不仅简化了多容器应用的开发和测试流程,还提供了一种在生产环境中部署和扩展服务的有效方法。随着你对Docker Compose的进一步探索,你将能够更加灵活和高效地部署复杂的微服务架构。
10.3 云原生技术栈与 Go - Go 语言在云上的航行
10.3.1 基础知识讲解
云原生技术是指那些为开发者提供构建和运行可扩展应用程序在现代动态环境中(如公有云、私有云和混合云)的技术集合。这些技术使得应用更加灵活、可维护,并易于扩展。
云原生技术栈的关键组件包括:
- 容器化:容器提供了一种轻量级的、一致的软件打包方式,使应用在不同的计算环境中运行得更加可靠。
- 微服务架构:通过将应用拆分为一组小服务,微服务架构使得应用更容易开发和扩展。
- 声明式自动化:使用Kubernetes等工具自动管理容器化应用,实现自我修复、自动扩展和滚动更新等。
- DevOps和持续交付:云原生鼓励更快的迭代速度和更高的部署频率,通过自动化的构建、测试和部署来实现。
Go 在云原生中的角色
Go语言因其简单、高效和强大的并发支持,在云原生生态系统中占据了重要地位。许多关键的云原生项目,如Kubernetes、Docker和Istio,都是用Go编写的。Go的这些特性使其成为开发高性能、可扩展的云原生应用的理想选择。
10.3.2 重点案例:Go 微服务在 Kubernetes 上的部署
让我们通过一个具体的示例来演示如何将Go编写的微服务容器化并部署到Kubernetes集群上。这个过程涵盖了应用的容器化、创建Docker镜像、推送到镜像仓库,以及编写和应用Kubernetes部署配置。
步骤一:准备 Go 微服务
首先,我们复用之前创建的简单HTTP服务器代码,该服务监听8080端口并返回欢迎消息。
main.go:
package mainimport ("fmt""net/http"
)func handler(w http.ResponseWriter, r *http.Request) {fmt.Fprintf(w, "Hello, Kubernetes World!")
}func main() {http.HandleFunc("/", handler)fmt.Println("Starting server on port 8080...")http.ListenAndServe(":8080", nil)
}
步骤二:容器化 Go 微服务
为微服务创建一个Dockerfile:
# 使用Go官方镜像作为构建环境
FROM golang:1.16-alpine AS build# 设置工作目录
WORKDIR /app# 复制并下载依赖
COPY go.mod ./
COPY go.sum ./
RUN go mod download# 复制源代码并编译
COPY *.go ./
RUN CGO_ENABLED=0 GOOS=linux go build -o webapp .# 使用scratch作为运行环境
FROM scratch
COPY --from=build /app/webapp /webapp
EXPOSE 8080
ENTRYPOINT ["/webapp"]
构建并推送镜像到Docker Hub或其他容器镜像仓库:
docker build -t yourusername/go-webapp-k8s .
docker push yourusername/go-webapp-k8s
请确保替换yourusername
为你的Docker Hub用户名。
步骤三:编写 Kubernetes 部署配置
创建webapp-deployment.yaml
文件,定义微服务的部署和服务对象:
apiVersion: apps/v1
kind: Deployment
metadata:name: go-webapp
spec:replicas: 2selector:matchLabels:app: go-webapptemplate:metadata:labels:app: go-webappspec:containers:- name: go-webappimage: yourusername/go-webapp-k8sports:- containerPort: 8080---
apiVersion: v1
kind: Service
metadata:name: go-webapp-service
spec:type: LoadBalancerports:- port: 8080targetPort: 8080selector:app: go-webapp
替换image
字段中的yourusername/go-webapp-k8s
为你的镜像名称。
步骤四:部署到 Kubernetes
使用kubectl应用部署配置,将应用部署到Kubernetes集群:
kubectl apply -f webapp-deployment.yaml
查看部署状态和服务:
kubectl get deployments
kubectl get services
步骤五:访问微服务
如果你在本地使用Minikube,使用以下命令找到服务的URL:
minikube service go-webapp-service --url
在浏览器中访问该URL,或使用curl命令,你应该能够看到“Hello, Kubernetes World!”的消息。
通过这个案例,你已经学会了如何将Go微服务容器化并在Kubernetes上部署。这不仅展示了从代码到部署的完整流程,还体现了云原生应用开发中的关键实践,包括容器化、微服务架构和声明式自动化部署。随着你深入探索Kubernetes和云原生技术栈,你将能够构建和管理更加复杂和强大的应用。
10.3.3 拓展案例 1:使用 Helm 管理 Go 应用的 Kubernetes 部署
Helm是Kubernetes的包管理器,它使得定义、安装和升级Kubernetes应用变得简单。通过Helm,我们可以将应用及其依赖打包到一个chart中,然后通过简单的命令来部署和管理这个chart。这个案例将展示如何使用Helm来管理之前创建的Go微服务的部署。
步骤一:创建 Helm Chart
首先,确保你已经安装了Helm。然后在命令行中执行以下命令来创建一个新的Helm chart:
helm create go-webapp-chart
这将在当前目录下创建一个名为go-webapp-chart
的文件夹,里面包含了chart的初始文件和文件夹结构。
步骤二:定制化 Chart
定制化你的Helm chart来适配Go微服务。修改go-webapp-chart/values.yaml
文件来定义一些默认配置,比如镜像的仓库和标签:
# values.yamlreplicaCount: 2image:repository: yourusername/go-webapp-k8spullPolicy: IfNotPresent# tag: "If you have a specific version"service:type: LoadBalancerport: 8080
确保将image.repository
的值替换为你的容器镜像地址。
接下来,修改go-webapp-chart/templates/deployment.yaml
文件,确保它使用values.yaml
中定义的值:
# deployment.yaml 中的部分内容
spec:replicas: {{ .Values.replicaCount }}template:spec:containers:- name: go-webappimage: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"ports:- containerPort: {{ .Values.service.port }}
步骤三:打包和部署 Chart
在chart目录(go-webapp-chart
)中,打包你的chart:
helm package .
然后,使用Helm安装你的chart到Kubernetes集群:
helm install go-webapp-release ./go-webapp-chart-0.1.0.tgz
这里go-webapp-release
是release的名字,你可以根据需要自定义。
步骤四:验证部署
使用以下命令来检查release的状态:
helm list
kubectl get services
找到你的服务的外部IP或端口(如果你在本地如Minikube上测试,使用minikube service go-webapp-service --url
获取URL),然后在浏览器中访问或使用curl命令来验证服务是否正常运行。
步骤五:更新和升级
如果需要更新应用配置,你可以修改values.yaml
文件,然后使用以下命令更新部署:
helm upgrade go-webapp-release ./go-webapp-chart
通过这个案例,你学会了如何使用Helm来管理Go应用的Kubernetes部署。Helm不仅简化了Kubernetes应用的部署流程,还提供了版本控制、回滚等功能,极大地提高了云原生应用管理的效率和可靠性。随着你对Helm的深入学习,你将能够更加高效地管理复杂的Kubernetes应用。
10.3.4 拓展案例 2:实现 Go 微服务的自动扩展
Kubernetes的水平自动扩展(HPA,Horizontal Pod Autoscaler)允许根据监测到的CPU使用率或其他选定的度量自动增加或减少Pod的数量。这个案例将演示如何为Go编写的微服务实现自动扩展功能,以确保应用能够根据负载自动调整其运行实例的数量。
步骤一:准备 Go 微服务
假设我们已经有一个Go微服务,它已经被容器化并部署到Kubernetes上,如之前的“Go微服务在Kubernetes上的部署”案例所示。
步骤二:为微服务启用资源请求和限制
为了使HPA能够根据CPU使用情况自动扩展Pod,首先需要在微服务的Deployment配置中指定每个容器的资源请求和限制。编辑你的deployment.yaml
文件,为containers
部分添加resources
字段:
apiVersion: apps/v1
kind: Deployment
metadata:name: go-webapp
spec:...template:...spec:containers:- name: go-webappimage: yourusername/go-webapp-k8sresources:requests:cpu: "100m"memory: "100Mi"limits:cpu: "200m"memory: "200Mi"ports:- containerPort: 8080
这里的requests
字段指定了每个Pod启动时的最小资源需求,而limits
字段则指定了Pod可以消耗的最大资源量。
步骤三:创建 HPA
接下来,使用kubectl
命令创建HPA,以自动扩展你的Go微服务。以下命令创建一个HPA,它将根据目标Pod的平均CPU使用率自动调整Pod的数量。当CPU使用率超过50%时,Kubernetes会尝试增加Pod的数量,直到最多10个Pod。
kubectl autoscale deployment go-webapp --cpu-percent=50 --min=1 --max=10
步骤四:测试自动扩展
为了测试HPA,你可以通过增加向微服务发送的请求来人为增加负载。这可以通过编写简单的脚本不断请求你的服务来实现。
监控HPA和Pod的状态,以查看是否根据CPU负载自动调整了Pod的数量:
kubectl get hpa
kubectl get pods
步骤五:调整 HPA 策略(可选)
根据应用的具体需求,你可能需要调整HPA的行为。这可以通过编辑HPA的配置来实现:
kubectl edit hpa go-webapp
在编辑器中,你可以修改例如--cpu-percent
和--min/--max
参数等HPA的配置项。
通过这个案例,你学会了如何为Go编写的微服务实现Kubernetes的自动扩展功能。利用HPA,你的应用可以根据实时负载自动调整资源使用,从而保证应用的性能和响应速度。这是构建高可用云原生应用的关键技术之一,随着你对Kubernetes和云原生技术栈的深入学习,你将能够构建更加灵活和强大的应用系统。
相关文章:

《Go 简易速速上手小册》第10章:微服务与云原生应用(2024 最新版)
文章目录 10.1 构建微服务架构 - 探索 Go 语言的微观世界10.1.1 基础知识讲解10.1.2 重点案例:订单处理系统订单服务测试服务 10.1.3 拓展案例 1:用户认证服务安装所需的包实现用户模型和存储实现 JWT 生成和验证实现认证服务测试服务 10.1.4 拓展案例 2…...

代码随想录算法训练营第34天| Leetcode 860.柠檬水找零、406.根据身高重建队列、452. 用最少数量的箭引爆气球
文章目录 Leetcode 860.柠檬水找零Leetcode 406.根据身高重建队列Leetcode 452. 用最少数量的箭引爆气球 Leetcode 860.柠檬水找零 题目链接:Leetcode 860.柠檬水找零 题目描述: 在柠檬水摊上,每一杯柠檬水的售价为 5 美元。顾客排队购买你的…...

数据结构~二叉树(基础知识)
上一篇博客我们对树有了初步了解与学习,这篇我将初步学习二叉树!!(新年快乐!) 目录 二叉树 1、定义: 2、特点: 3、基本形态: 4、二叉树的种类: &…...

AI大模型学习笔记之四:生成式人工智能(AIGC)是如何工作的?
OpenAI 发布 ChatGPT 已经1年多了,生成式人工智能(AIGC)也已经广为人知,我们常常津津乐道于 ChatGPT 和 Claude 这样的人工智能系统能够神奇地生成文本与我们对话,并且能够记忆上下文情境。 Midjunery和DALLE 这样的AI…...

bat脚本 创建计划任务 一分钟设置ntp同步周期为60s
要在Windows中使用批处理脚本(.bat)创建一个计划任务来每分钟同步一次NTP时间,你可以使用schtasks命令来创建计划任务。下面是一个示例脚本,展示了如何创建这样一个计划任务: echo off set "taskNameSyncNTP"…...

python数据分析numpy基础之mean用法和示例
1 python数据分析numpy基础之mean用法和示例 python的numpy库的mean()函数,用于计算沿指定轴(一个轴或多个轴)的算术平均值。 用法 numpy.mean(a, axisNone, dtypeNone, outNone, keepdims<no value>, *, where<no value>)描述 返回数组元素的平均值…...

微服务学习 | Springboot整合Dubbo+Nacos实现RPC调用
🏷️个人主页:鼠鼠我捏,要死了捏的主页 🏷️系列专栏:Golang全栈-专栏 🏷️个人学习笔记,若有缺误,欢迎评论区指正 前些天发现了一个巨牛的人工智能学习网站,通俗易懂&…...

只允许访问固定网址,如何让电脑只能上指定的网站
在企业管理中,确保员工在工作时能够专注于指定的任务和资源至关重要。为了实现这一目标,许多企业选择限制员工电脑的访问权限,只允许他们访问固定的网址或网站。 这种策略不仅有助于提高工作效率,还能减少因不当上网行为带来的安全…...

作业帮 x TiDB丨多元化海量数据业务的支撑
导读 作业帮是一家成立于 2015 年的在线教育品牌,致力于用科技手段助力教育普惠。经过近十年的积累,作业帮运用人工智能、大数据等技术,为学生、老师、家长提供学习、教育解决方案,智能硬件产品等。随着公司产品和业务场景越来越…...

文生图提示词:天气条件
天气和气候 --天气条件 Weather Conditions 涵盖了从基本的天气类型到复杂的气象现象,为描述不同的天气和气候条件提供了丰富的词汇。 Sunny 晴朗 Cloudy 多云 Overcast 阴天 Partly Cloudy 局部多云 Clear 清晰 Foggy 雾 Misty 薄雾 Hazy 朦胧 Rainy 下雨 Showers …...

【nginx实践连载-3】发布VSTO应用
要使用 Nginx 发布 VSTO 应用程序,需要将 ClickOnce 发布文件夹部署到 Nginx 服务器上。以下是一些步骤: 将 ClickOnce 发布文件夹复制到 Nginx 服务器上。确认 Nginx 配置文件中有一个指向 ClickOnce 发布文件夹的位置块。确保Nginx 配置文件中启用了 …...

【前端工程化面试题】使用 webpack 来优化前端性能/ webpack的功能
这个题目实际上就是来回答 webpack 是干啥的,你对webpack的理解,都是一个问题。 (1)对 webpack 的理解 webpack 为啥提出 webpack 是啥 webpack 的主要功能 前端开发通常是基于模块化的,为了提高开发效率࿰…...

思迈特再获国家权威认证:代码自主率98.78%
日前,思迈特软件自主研发的商业智能与数据分析软件(Smartbi Insight)通过中国赛宝实验室(工业和信息化部电子第五研究所)代码扫描测试,Smartbi Insight V11版本扫描测得代码自主率为98.78%的好成绩…...

JavaScript排序
直接看代码 <table border"1" cellspacing"0"><thead class"tou"><tr><td>选择按钮</td><td>汽车编号</td><td>汽车图片</td><td>汽车系列名称</td><td>汽车能源</…...
【读书笔记】ICS设备及应用攻击(一)
工控系统通常是由互联设备所构成的大型复杂系统,这些设备包括类似于人机界面(HMI)、PLC、传感器、执行器以及其他使用协商好的协议进行相互通信的设备。所有交互背后的驱动力都是软件,软件为工控系统中几乎所有部分的运行提供支撑…...

网络原理(HTTP篇)
网络原理HTTP 前言HTTPHTTP的工作流程抓包工具抓取HTTP报文HTTP报文格式 请求报文具体细节首行URLURL的基本格式URL encode 方法 报头(header)HostContent-Length 和 Content-TypeUser-Agent(UA)RefererCookie(重要) 前言 如图&a…...

关于油封密封件你了解多少?
油封也称为轴封或旋转轴封,旨在防止设备中的润滑剂泄漏,并防止外部污染物进入机械。它们通常用于泵和电机等旋转设备,在固定部件和移动部件之间提供密封界面。 油封的有效性很大程度上取决于其材料。不同的材料具有不同程度的耐热性、耐压性…...

Leetcode 72 编辑距离
题意理解: 给你两个单词 word1 和 word2, 请返回将 word1 转换成 word2 所使用的最少操作数 。 你可以对一个单词进行如下三种操作: 插入一个字符 删除一个字符 替换一个字符 将word1转换为word2,可以进行三种操作:增、删、改&am…...

羊大师揭秘,如何挑选出好牧场的奶羊,该怎么看
羊大师揭秘,如何挑选出好牧场的奶羊,该怎么看 了解牧场的管理和环境:好的牧场应该有规范的管理制度,环境整洁,草场茂盛,为奶羊提供了充足的食物和良好的生活环境。在这样的牧场中,奶羊能够得到…...

MySQL数据库基础(八):DML数据操作语言
文章目录 DML数据操作语言 一、DML包括哪些SQL语句 二、数据的增删改(重点) 1、数据的增加操作 2、数据的修改操作 3、数据的删除操作 DML数据操作语言 一、DML包括哪些SQL语句 insert插入、update更新、delete删除 二、数据的增删改(…...

(09)Hive——CTE 公共表达式
目录 1.语法 2. 使用场景 select语句 chaining CTEs 链式 union语句 insert into 语句 create table as 语句 前言 Common Table Expressions(CTE):公共表达式是一个临时的结果集,该结果集是从with子句中指定的查询派生而来…...

Spring 用法学习总结(四)之 JdbcTemplate 连接数据库
🐉目录 9 JdbcTemplate 9 JdbcTemplate Spring 框架对 JDBC 进行了封装,使用 JdbcTemplate 方便实现对数据库操作 相关包: 百度网盘链接https://pan.baidu.com/s/1Gw1l6VKc-p4gdqDyD626cg?pwd6666 创建properties配置文件 💥注意…...

第 385 场 LeetCode 周赛题解
A 统计前后缀下标对 I 模拟 class Solution { public:int countPrefixSuffixPairs(vector<string> &words) {int n words.size();int res 0;for (int i 0; i < n; i)for (int j i 1; j < n; j)if (words[i].size() < words[j].size()) {int li words[…...

什么是RabbitMQ?
一、引言 RabbitMQ是一个开源的消息代理软件,用于在分布式系统中传递消息。它实现了高级消息队列协议(AMQP),提供了一种可靠的、强大的、灵活的消息传递机制,使得不同应用程序或组件之间可以轻松地进行通信。 二、概念…...

JWT登录验证前后端设计与实现笔记
设计内容 前端 配置全局前置路由守卫axios拦截器登录页面和主页 后端 JWT的封装登录接口中间件放行mysql数据库的连接 详细设计 路由设计 配置全局前置守卫,如果访问的是登录页面则放行,不是则进入判断是否有token,没有则拦截回到登录…...

自定义类型详解 ----结构体,位段,枚举,联合
目录 结构体 1.不完全声明 2.结构体的自引用 3.定义与初始化 4.结构体内存对齐与结构体类型的大小 结构体嵌套问题 位段 1.什么是位段? 2.位段的内存分配 枚举 1.枚举类型的定义 2.枚举的优点 联合(共同体) 1.联合体类型的声明以…...

VueCLI核心知识综合案例TodoList
目录 1 拿到一个功能模块首先需要拆分组件: 2 使用组件实现静态页面的效果 3 分析数据保存在哪个组件 4 实现添加数据 5 实现复选框勾选 6 实现数据的删除 7 实现底部组件中数据的统计 8 实现勾选全部的小复选框来实现大复选框的勾选 9 实现勾选大复选框来…...

关于cuda路径问题
问题:Could not load dynamic library ‘libcudart.so.11.0’ 原因:调用系统环境下的cuda但系统环境没有装cuda 解决: 1.在系统环境装cuda,但如果每权限就不好操作; 2.用虚拟环境装好的cuda路径丢给环境变量 暂时性&am…...

六、Spring/Spring Boot整合ActiveMQ
Spring/Spring Boot整合ActiveMQ 一、Spring整合ActiveMQ1.pom.xml2.Queue - 队列2.1 applicationContext.xml2.2 生产者2.3 消费者 3.Topic - 主题3.1 applicationContext.xml3.2 生产者3.3 消费者 4.消费者 - 监听器4.1 编写监听器类4.2 配置监听器4.3 生产者消费者一体 二、…...

树莓派4B(Raspberry Pi 4B)使用docker搭建springBoot/springCloud服务
树莓派4B(Raspberry Pi 4B)使用docker搭建springBoot/springCloud服务 前提:本文基于Ubuntu,Java8,SpringBoot 2.6.13讲解 准备工作 准备SpringBoot/SpringCloud项目jar包 用 maven 打包springBoot/springCloud项目&…...