大家好, 我是老麦, 一个小运维。今天我们继续手写这个 kustz
文章内容并不是所有代码块都有详细描述。部分内容, 我觉得不太重要的就一笔带过了。每个代码片段都提供了文件路径, 可以自己到 Github 上查看。
https://github.com/tangx/kustz/tree/chapter/01-sample-deployment
我觉得今天的内容特基础, 但有相对比较重要, 因为我们之后所有的工作都是为了简化(或者说抽象) 这些 API 的配置。
2.1. [kustz] 定义字符串创建 Deployment
先做个假设
为了简单, 我们假定所管理的 Deployment 都是 单容器 的。
首先参考 kubectl create
命令
$ kubectl create deployment my-dep --image=busybox --replicas 1 --dry-run=client -o yaml
安装 client-go API
访问 client-go
https://github.com/kubernetes/client-go
$ go get k8s.io/client-go@v0.25.4
这里直接选用最新版本 v0.25.4
。对于其他版本的兼容, 留在以后再做。
定义 Kustz Config
参考 kubectl create
命令, 创建配置文件 kustz.yml
结构如下
# kustz.yml namespace: demo-demo name: srv-webapp-demo service: name: nginx image: docker.io/library/nginx:alpine replicas: 2
在 service 中添加了 name 字段, 这是在 kubectl create
命令中没有的。后者直接使用了镜像名称作为 name 的值。
由于我们的设计只有一个容器, 这里也可以 省略或使用默认值。这里增加字段 完全是为了展示凑 API。
在 /pkg/kustz/kustz.go
中创建 Config
, 对应所有字段。
type Config struct { Name string `json:"name"` Namespace string `json:"namespace"` Service Service `json:"service"` } type Service struct { Name string `json:"name"` Image string `json:"image"` Replicas int32 `json:"replicas"` }
拼凑 Deployment API
从这个标题就可以看出来, 这里就就没什么难度了, 就是把 kustz.Config
中的所有字段全部放在 Deployment API
中。
为 kustz.Config
添加 KubeDeployment
方法, 在 /pkg/kustz/k_deployment.go
中。
func (kz *Config) KubeDeployment() *appv1.Deployment { return &appv1.Deployment{ TypeMeta: metav1.TypeMeta{ Kind: "Deployment", APIVersion: "apps/v1", }, ObjectMeta: metav1.ObjectMeta{ Name: kz.Name, Namespace: kz.Namespace, Labels: CommonLabels(*kz), }, Spec: appv1.DeploymentSpec{ Replicas: &kz.Service.Replicas, Template: kz.KubePod(), Selector: &metav1.LabelSelector{ MatchLabels: CommonLabels(*kz), }, }, } }
可以看到, 拼凑主要由 3 部分, 都是很熟悉的字段。
TypeMeta
: Deployment 的信息申明ObjectMeta
: 应用服务 的信息申明Spec
: 就是具体信息了。
如果你看的够仔细,可以在 Spec
中发现 Template
字段就开始 套娃 了。
KubeDeployment
中调用了 /pkg/kustz/k_pod.go
中的 KubePod
方法。
func (kz *Config) KubeDeployment() *appv1.Deployment { return &appv1.Deployment{ Spec: appv1.DeploymentSpec{ // ... 省略 Template: kz.KubePod(), }, } }
KubePod
中调用了 /pkg/kustz/k_container.go
中的 KubeContainer
方法。
func (kz *Config) KubePod() corev1.PodTemplateSpec { return corev1.PodTemplateSpec{ // ... 省略 Spec: corev1.PodSpec{ Containers: kz.KubeContainer(), }, } }
最后, 在 KubeContainer
方法中, 创建了最里面的 container 信息。
func (kz *Config) KubeContainer() []corev1.Container { if kz.Service.Name == "" { kz.Service.Name = kz.Name } // ...省略 return []corev1.Container{c} }
前面我们说到过 kz.Service.Name
为了展示 API 的拼凑。为了以后使用方便, 这里我们设置其默认值为应用服务名 kz.Name
。
公共标签
在 Kubernetes 中, 不同 API 之间的关系都是通过 标签选择 关联的。为了方便, 在 /pkg/kustz/common.go
中使用函数 CommonLabels()
创建公共标签, 方便关联。
文件解析
细心的你可以已经发现了, 明明配置文件用的是 yaml
格式, 但是在 Config
中的标签却是 json:"name"
。
这里只是为了 单纯 为了保障 yaml 库一致, 在 /pkg/kubeutils/yaml.go
中使用了 sigs.k8s.io/yaml
库而已, 这个库可以兼容 json, yaml
标签。
测试
进入 kustz
, 执行命令
$ go test -v . $ kubectl create deployment srv-webapp-demo --image=nginx -n demo-demo --dry-run=client -o yaml
对比二者内容, 基本上完全一样了。
2.2. [kustz] 定义字符串创建 Service
大家好, 我是老麦, 一个小运维。 今天我们为 kustz 增加 Service 功能。
代码还是在 Github, 文章中有不清楚的可以上去看看
https://github.com/tangx/kustz/tree/chapter/02-define-strings-to-service
Kube Service
通过 kubectl create service
命令可以看到, service 的模式还是挺多的。
$ kubectl create service -h Create a service using a specified subcommand. Aliases: service, svc Available Commands: clusterip Create a ClusterIP service externalname Create an ExternalName service loadbalancer Create a LoadBalancer service nodeport Create a NodePort service
除了以上列出来的四种之外, 还用一种 Headless Service
(https://kubernetes.io/docs/concepts/services-networking/service/#headless-services)。
Headless Service
是当 类型 为 ClusterIP,且 IP 值为 None
。 所以是 Cluster IP
的一种特殊情况。
# 创建一个新的 ClusterIP service $ kubectl create service clusterip my-cs --tcp=5678:8080 # 创建一个新的 ClusterIP service (headless 模式) $ kubectl create service clusterip my-cs --clusterip="None"
Service API 中的 Port
如果你之前留意过 Service API, 你就应该会发现 API 中带有 port 的字段就有 3 个。 弄清楚他们分别对应什么这点很重要
先来看看一个 NodePort
的 API。
# $ kubectl create service nodeport my-cs --tcp=80:8080 --dry-run=client -o yaml apiVersion: v1 kind: Service # ... 省略 spec: ports: - name: 80-8080 nodePort: 18080 port: 80 protocol: TCP targetPort: 8080 selector: app: my-cs type: NodePort
对于 nodePort, port, targetPort
这三个名词如果还不能直接回答的话, 认真记住下面这张图。
- 集群外部用户通过
nodePort -> port -> targetPort
。 - 集群内部用户通过
port -> targetPort
。