将您的 Kubernetes 基础架构编写为 Go 代码 - “cdk8s-plus”在行动!
使用“cdk8s-plus”库减少样板代码
我之前的一篇博客文章介绍了如何开始使用 cdk8s(Kubernetes 的云开发工具包),它是一个开源框架(CNCF 的一部分),您可以使用它使用常规编程语言(而不是 yaml)定义您的 Kubernetes 应用程序 .
您可以设置一个简单的 nginx 部署并通过服务访问它 - 所有这些都是使用 Go 完成的,然后将其转换为 yaml(使用 cdk8s 合成器)并使用 kubectl 提交到集群。 这是一个好的开始。 然而,由于核心 cdk8s 库是相当低级的(这是有充分理由的!),代码涉及大量样板。
cdk8s-plus 利用 cdk8s 核心库中的构建块,从而通过为所有 Kubernetes 对象(例如部署、服务等)提供更高级别的抽象/API 来帮助减少冗长和复杂性。在本博客中,我们将看到 cdk8s-plus 的实际应用,甚至 用它在 Kubernetes 上部署 Wordpress!
让我们从改进 Nginx 部署开始。
要见证 cdk8s-plus 是如何工作的,最好看一下代码。
在我们进行过程中,我将引导您完成代码。
func NewNginxChart(scope constructs.Construct, id string, props *NginxChartProps) cdk8s.Chart {
var cprops cdk8s.ChartProps
if props != nil {
cprops = props.ChartProps
}
chart := cdk8s.NewChart(scope, jsii.String(id), &cprops) dep := cdk8splus22.NewDeployment(chart, jsii.String("deployment"), &cdk8splus22.DeploymentProps{Metadata: &cdk8s.ApiObjectMetadata{Name: jsii.String("nginx-deployment-cdk8s-plus")}}) dep.AddContainer(&cdk8splus22.ContainerProps{
Name: jsii.String("nginx-container"),
Image: jsii.String("nginx"),
Port: jsii.Number(80)}) dep.ExposeViaService(&cdk8splus22.DeploymentExposeViaServiceOptions{
Name: jsii.String("nginx-container-service"),
ServiceType: cdk8splus22.ServiceType_LOAD_BALANCER,
Ports: &[]*cdk8splus22.ServicePort{{Port: jsii.Number(9090), TargetPort: jsii.Number(80)}}}) return chart
}
我们首先创建一个部署,然后添加一个容器,最后使用服务公开它。 这是非常直观和用户友好的。
容器详细信息可以通过 DeploymentProps 提供,但使用 AddContainer 似乎更自然(至少对我而言)。
要生成 Kubernetes 清单,只需运行 cdk8s synth。 这将在 dist 文件夹中生成一个 yaml。 这是一个示例(某些名称、标签等在您的情况下会有所不同):
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment-cdk8s-plus
spec:
minReadySeconds: 0
progressDeadlineSeconds: 600
replicas: 1
selector:
matchLabels:
cdk8s.io/metadata.addr: nginx-cdk8s-plus-deployment-c84b388e
strategy:
rollingUpdate:
maxSurge: 25%
maxUnavailable: 25%
type: RollingUpdate
template:
metadata:
labels:
cdk8s.io/metadata.addr: nginx-cdk8s-plus-deployment-c84b388e
spec:
automountServiceAccountToken: true
containers:
- image: nginx
imagePullPolicy: Always
name: nginx-container
ports:
- containerPort: 80
securityContext:
privileged: false
readOnlyRootFilesystem: false
runAsNonRoot: false
dnsPolicy: ClusterFirst
securityContext:
fsGroupChangePolicy: Always
runAsNonRoot: false
setHostnameAsFQDN: false
---
apiVersion: v1
kind: Service
metadata:
name: nginx-container-service
spec:
externalIPs: []
ports:
- port: 9090
targetPort: 80
selector:
cdk8s.io/metadata.addr: nginx-cdk8s-plus-deployment-c84b388e
type: LoadBalancer
部署和服务都存在于同一个清单中,因为它们是在同一个图表中声明的。
值得注意的是,不需要指定任何 Pod 标签选择器、模板标签(在部署代码中)或服务选择器。 cdk8s-plus 通过自动生成 cdk8s.io/metadata.addr 来处理它: nginx-cdk8s-plus-deployment-c84b388e,它在 spec.selector.matchLabels 和 spec.template.metadata.labels 中使用,以及 nginx-container-service 中的服务选择器
关于依赖的说明
go.mod 列出所有模块:
require (
github.com/aws/constructs-go/constructs/v10 v10.1.42
github.com/aws/jsii-runtime-go v1.61.0
github.com/cdk8s-team/cdk8s-core-go/cdk8s/v2 v2.3.31
github.com/cdk8s-team/cdk8s-plus-go/cdk8splus22/v2 v2.0.0-rc.23
)
请注意,我们使用的是 cdk8splus22。 这种命名约定的原因是因为每个 cdk8s-plus 库都单独出售以针对特定的 Kubernetes 版本 - 末尾的 22 表示此依赖项将适用于 Kubernetes 1.22
我建议阅读常见问题解答以获得进一步的清晰度
要在本地进行测试……
…你可以使用 minikube、kind 等。
git clone https://github.com/abhirockzz/cdk8s-for-go-developers
cd part2-cdk8s-plus-in-action/nginx-example# make sure cluster is running
minikube start# create the resources
kubectl apply -f dist/
kubectl get pods -w
Pod 运行后,检查服务:
kubectl get svc
In a terminal, run this command (it runs as a separate process):
minikube tunnel
要访问 nginx 服务器,请导航到外部 IP(根据服务)。 对于 minikube,您可以简单地使用 localhost:9090 或 127.0.0.0:9090
在 Kubernetes 上安装 Wordpress 怎么样?
我喜欢这个例子——它并不过分复杂但足够现实,因为它有多个移动部分,包括无状态、有状态组件、不同类型的服务等的组合。
这篇文章不是对 Wordpress 的深入探讨,而是受到 Kubernetes 文档中的这篇文章的粗略启发,我认为人们可能对这篇文章很熟悉。
main 函数将让您了解前方的情况:
func main() {
app := cdk8s.NewApp(nil) mySQLChart := NewMySQLChart(app, "mysql", nil)
wordpressChart := NewWordpressChart(app, "wordpress", nil) wordpressChart.AddDependency(mySQLChart) app.Synth()
}
到目前为止,我们已经处理了一个图表。 我们的 Wordpress cdk8s 应用程序有两个单独的图表 - 一个用于 MySQL 数据库,另一个用于 Wordpress。 这将导致由于 cdk8s 合成过程而创建了两个不同的清单。
我们先看MySQL图表
为简洁起见,省略了一些代码
我们首先定义一个 Kubernetes Secret 来存储 MySQL 密码(使用 NewSecret):
func NewMySQLChart(scope constructs.Construct, id string, props *MyChartProps) cdk8s.Chart {
//....
secretName := "mysql-pass"
password := "Password123" mysqlSecret := cdk8splus22.NewSecret(chart, jsii.String("mysql-secret"),
&cdk8splus22.SecretProps{
Metadata: &cdk8s.ApiObjectMetadata{Name: jsii.String(secretName)}}) secretKey := "password"
mysqlSecret.AddStringData(jsii.String(secretKey), jsii.String(password))
MySQL 密码已在代码中声明 — 无论如何都不是最佳实践,仅用于演示。 不要在生产中这样做!
然后我们创建部署并提供容器详细信息。 请注意如何将 Secret 作为环境变量添加到容器中:
dep := cdk8splus22.NewDeployment(chart, jsii.String("mysql-deployment-cdk8splus"), &cdk8splus22.DeploymentProps{}) containerImage := "mysql" mysqlContainer := dep.AddContainer(&cdk8splus22.ContainerProps{
Name: jsii.String("mysql-container"),
Image: jsii.String(containerImage),
Port: jsii.Number(3306),
}) envValFromSecret := cdk8splus22.EnvValue_FromSecretValue(&cdk8splus22.SecretValue{Key: jsii.String(secretKey), Secret: mysqlSecret}, &cdk8splus22.EnvValueFromSecretOptions{Optional: jsii.Bool(false)}) mySQLPasswordEnvName := "MYSQL_ROOT_PASSWORD" mysqlContainer.Env().AddVariable(jsii.String(mySQLPasswordEnvName), envValFromSecret)
对于持久存储,我们创建了一个 PersistentVolumeClaim,使用它来定义一个 Volume 并挂载到路径 /var/lib/mysql 的容器上。
mysqlPVC := cdk8splus22.NewPersistentVolumeClaim(chart, jsii.String("mysql-pvc"), &cdk8splus22.PersistentVolumeClaimProps{
AccessModes: &[]cdk8splus22.PersistentVolumeAccessMode{cdk8splus22.PersistentVolumeAccessMode_READ_WRITE_ONCE},
Storage: cdk8s.Size_Gibibytes(jsii.Number(2))}) mysqlVolumeName := "mysql-persistent-storage"
mysqlVolume := cdk8splus22.Volume_FromPersistentVolumeClaim(chart, jsii.String("mysql-vol-pvc"), mysqlPVC, &cdk8splus22.PersistentVolumeClaimVolumeOptions{Name: jsii.String(mysqlVolumeName)}) mySQLVolumeMountPath := "/var/lib/mysql"
mysqlContainer.Mount(jsii.String(mySQLVolumeMountPath), mysqlVolume, &cdk8splus22.MountOptions{})
最后,我们创建一个服务:
mySQLServiceName := "mysql-service"
clusterIPNone := "None" cdk8splus22.NewService(chart, jsii.String("mysql-service"), &cdk8splus22.ServiceProps{
Metadata: &cdk8s.ApiObjectMetadata{Name: jsii.String(mySQLServiceName)},
Selector: dep,
ClusterIP: jsii.String(clusterIPNone),
Ports: &[]*cdk8splus22.ServicePort{{Port: jsii.Number(3306)}},
})
与前面的示例不同,我们显式创建一个服务,然后在服务选择器中引用部署对象。
是时候在 Kubernetes 上启动 Wordpress 了!
冲洗并重复 — cdk8s synth 创建清单并使用 kubectl 应用它:
cd part2-cdk8s-plus-in-action/wordpress#create manifests
cdk8s synth#apply them
kubectl apply -f dist/#output - you will see something similar to:secret/mysql-pass created
deployment.apps/mysql-mysql-deployment-cdk8splus-c83762d9 created
persistentvolumeclaim/mysql-mysql-pvc-c8799bba created
service/mysql-service created
deployment.apps/wordpress-wordpress-deployment-cdk8splus-c8252da7 created
service/wordpress-service created
persistentvolumeclaim/wordpress-wordpress-pvc-c8334a29 created
在不同的终端运行(如果尚未运行):
minikube tunnel
使用浏览器导航到 http://localhost:80。 您应该会看到熟悉的 Wordpress 安装屏幕。
继续,完成安装并登录到您的 Wordpress 实例。 随意尝试。 也许尝试删除 MySQL 部署并重新创建它。 多亏了 PersistentVolume,MySQL 数据应该可以恢复并且 wordpress 将继续工作。
结论
惊人的! 在这篇博客中,您看到了 cdk8s-plus 的表现力。 我们从一个紧凑且不那么冗长的 Nginx 部署版本开始,最终得到了一个成熟的 WordPress 实例——全部使用 Go。
快乐编码!
关注七爪网,获取更多APP/小程序/网站源码资源!
留言与评论(共有 0 条评论) “” |