K8S 二次开发
我们在对一个东西进行二次开发的时候,我们需要有以下两点需要注意:
- 知道各个组件的使用,这里我就不在介绍 K8S 和 docker 的一些使用
- 熟悉对应的 api
在 K8S 中 api 也是对应的 http reset api ,这里使用的是 go-client
这里主要介绍的是开发 deployment+service
1 docker API 的 go 客户端
https://pkg.go.dev/github.com/docker/docker/client#section-readme
通过下面这个例子其实我们在二次开发一个东西的时候,需要对该服务本身的功能做了解,下面这个范例只是为了演示 go 的第三方包如何学习的一个过程
1.1 列出当前所有容器信息
可以通过 docker 的 sdk 实现对容器的列出
package main
import (
"context"
"fmt"
"github.com/docker/docker/api/types"
"github.com/docker/docker/client"
)
func main() {
// 定义 docker 的 client
cli, err := client.NewClientWithOpts(client.FromEnv)
if err != nil {
panic(err)
}
// 列出容器信息,返回一个切片
containers, err := cli.ContainerList(context.Background(), types.ContainerListOptions{})
if err != nil {
panic(err)
}
// 遍历切片输出容器id 和使用的镜像
for _, container := range containers {
fmt.Printf("%s %s\n", container.ID[:10], container.Image)
}
}
执行
[16:21:13 root@k8s-master ~]#./testdocker
container.ID=f14c5124c0,image=sha256:2297da0160d57032124efb335e38c52e20d252c5c494dbd8c88a9a2d02b41654
container.ID=aa0d42b638,image=sha256:181172b235b225c5644edae46296bd7c2305c05113e89a9b4274a952546743f4
container.ID=9202f8d8f9,image=sha256:296a6d5035e2d6919249e02709a488d680ddca91357602bd65e605eac967b899
container.ID=6d10a00ad5,image=registry.cn-hangzhou.aliyuncs.com/google_containers/pause:3.4.1
container.ID=63fee7086d,image=registry.cn-hangzhou.aliyuncs.com/google_containers/pause:3.4.1
container.ID=e6eadfccb8,image=sha256:296a6d5035e2d6919249e02709a488d680ddca91357602bd65e605eac967b899
container.ID=949870c1c0,image=sha256:ef4bce0a7569b4fa83a559717c608c076a2c9d30361eb059ea4e1b7a55424d68
1.2 创建容器
package main
import (
"context"
"fmt"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/client"
"github.com/docker/go-connections/nat"
)
func main() {
cli, err := client.NewClientWithOpts(client.FromEnv)
if err != nil {
panic(err)
}
// 创建容器
// context.TODO() 在我们不知道传递什么上下文的时候可以使用context.TODO()
body, err := cli.ContainerCreate(context.TODO(), &container.Config{
Tty: true,
OpenStdin: true,
Image: "nginx:1.16.1", // 该容器使用的镜像
}, &container.HostConfig{
// 容器端口 80 tcp 协议,暴露至宿主机的 8082,容器名为 testnginx
PortBindings: nat.PortMap{nat.Port("80/tcp"): []nat.PortBinding{{"0.0.0.0", "8082"}}},
}, nil, nil, "testnginx2")
if err != nil {
panic(err)
}
fmt.Println(boyd, err)
// 通过 body 获取到容器 id
containerID := body.ID
// 启动容器
err = cli.ContainerStart(context.TODO(), containerID, types.ContainerStartOptions{})
fmt.Println(err)
}
执行程序
[10:09:34 root@k8s-master ~]#./testdocker
{5aa50b5633a8c5fb510c687a94de29cced803f292cb5cb1495c4a806107e5edf []} <nil>
# 通过过滤查看该容器已经创建并启动
[10:09:39 root@k8s-master ~]#docker ps | grep testnginx
5aa50b5633a8 nginx:1.16.1 "nginx -g 'daemon of…" 13 seconds ago Up 11 seconds 127.0.0.1:8082->80/tcp testnginx2
1.2.1 验证
浏览器验证该容器已经被创建
2 K8S client-go
这里使用的 client-go 是一个 K8S 的 SDK 工具
这里我使用的是 client-go 的 0.20.4 版本
https://pkg.go.dev/k8s.io/client-go@v0.20.4
进入到这个连接中找到我们需要使用的工具
client-go sdk 查看对应代码方法
1.kubectl api-resources 查看对应的 api 如 deployment 对应的 api 就是 apps.v1
2.然后 sdk 源码中找到对应的方法再点击到对应的方法或者接口
3.使用对应接口里面的方法实现创建
4.然后再我们的程序中编写代码
client-go 开发流程:
1.获取 K8S 配置文件
2.初始化配置文件
3.拿到 K8S 客户端
4.通过对于的资源类型进行编写代码
1.通过 kubectl api-resource
查看对应的 api
# 如果 apiversion 只有 v1 就是对应的 core.v1
[10:30:30 root@k8s-master ~]#kubectl api-resources
NAME SHORTNAMES APIVERSION NAMESPACED KIND
bindings v1 true Binding
componentstatuses cs v1 false ComponentStatus
configmaps cm v1 true ConfigMap
endpoints ep v1 true Endpoints
events ev v1 true Event
limitranges limits v1 true LimitRange
namespaces ns v1 false Namespace
nodes no v1 false Node
persistentvolumeclaims pvc v1 true PersistentVolumeClaim
persistentvolumes pv v1 false PersistentVolume
pods po v1 true Pod
podtemplates v1 true PodTemplate
replicationcontrollers rc v1 true ReplicationController
resourcequotas quota v1 true ResourceQuota
secrets v1 true Secret
serviceaccounts sa v1 true ServiceAccount
services svc v1 true Service
mutatingwebhookconfigurations admissionregistration.k8s.io/v1 false MutatingWebhookConfiguration
validatingwebhookconfigurations admissionregistration.k8s.io/v1 false ValidatingWebhookConfiguration
customresourcedefinitions crd,crds apiextensions.k8s.io/v1 false CustomResourceDefinition
apiservices apiregistration.k8s.io/v1 false APIService
controllerrevisions apps/v1 true ControllerRevision
daemonsets ds apps/v1 true DaemonSet
deployments deploy apps/v1 true Deployment
replicasets rs apps/v1 true ReplicaSet
statefulsets sts apps/v1 true StatefulSet
tokenreviews authentication.k8s.io/v1 false TokenReview
localsubjectaccessreviews authorization.k8s.io/v1 true LocalSubjectAccessReview
selfsubjectaccessreviews authorization.k8s.io/v1 false SelfSubjectAccessReview
selfsubjectrulesreviews authorization.k8s.io/v1 false SelfSubjectRulesReview
subjectaccessreviews authorization.k8s.io/v1 false SubjectAccessReview
horizontalpodautoscalers hpa autoscaling/v1 true HorizontalPodAutoscaler
cronjobs cj batch/v1 true CronJob
jobs batch/v1 true Job
certificatesigningrequests csr certificates.k8s.io/v1 false CertificateSigningRequest
leases coordination.k8s.io/v1 true Lease
endpointslices discovery.k8s.io/v1 true EndpointSlice
events ev events.k8s.io/v1 true Event
ingresses ing extensions/v1beta1 true Ingress
flowschemas flowcontrol.apiserver.k8s.io/v1beta1 false FlowSchema
prioritylevelconfigurations flowcontrol.apiserver.k8s.io/v1beta1 false PriorityLevelConfiguration
nodes metrics.k8s.io/v1beta1 false NodeMetrics
pods metrics.k8s.io/v1beta1 true PodMetrics
ingressclasses networking.k8s.io/v1 false IngressClass
ingresses ing networking.k8s.io/v1 true Ingress
networkpolicies netpol networking.k8s.io/v1 true NetworkPolicy
runtimeclasses node.k8s.io/v1 false RuntimeClass
poddisruptionbudgets pdb policy/v1 true PodDisruptionBudget
podsecuritypolicies psp policy/v1beta1 false PodSecurityPolicy
clusterrolebindings rbac.authorization.k8s.io/v1 false ClusterRoleBinding
clusterroles rbac.authorization.k8s.io/v1 false ClusterRole
rolebindings rbac.authorization.k8s.io/v1 true RoleBinding
roles rbac.authorization.k8s.io/v1 true Role
priorityclasses pc scheduling.k8s.io/v1 false PriorityClass
csidrivers storage.k8s.io/v1 false CSIDriver
csinodes storage.k8s.io/v1 false CSINode
csistoragecapacities storage.k8s.io/v1beta1 true CSIStorageCapacity
storageclasses sc storage.k8s.io/v1 false StorageClass
volumeattachments storage.k8s.io/v1 false VolumeAttachment
我们都知道要创建这些资源的时候需要先创建 client,创建 client 需要使用一个 config 文件
2.1 获取到配置文件
因为我们都知道要创建这些资源的时候都需要看获取到 config 配置文件,因为这个请求需要去访问到我们的 api server
1.拷贝 config
# 这里我先将 K8S 集群中的配置文件拷贝至编写代码的服务器上
[10:32:15 root@k8s-master ~]#cd /root/.kube/
# 将配置文件拷贝至写代码的 K8S 项目中的 etc 文件中
[18:42:57 root@k8s-master .kube]#scp config 10.0.0.3:/root/project/testK8S/etc
2.在代码服务器上 get client-go@v0.20.4
包
[19:14:17 root@go testK8S]#go mod init testK8S
[19:11:18 root@go testK8S]#go get k8s.io/client-go@v0.20.4
# 这样指定我的程序依赖这个包
[19:15:49 root@go testK8S]#go mod tidy
2.2 namespace
2.2.1 namespace 获取
通过代码实现获取 namespace 的列表,因为后续我们需要获取不同的 namespace 下的资源
// 初始化配置文件
func clientcmd.BuildConfigFromFlags(masterUrl string, kubeconfigPath string) (*rest.Config, error)
package main
import (
"context"
"fmt"
"log"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/clientcmd"
)
func main() {
// 配置文件路径
kubeconfig := "etc/config"
// 初始化配置文件拿到 config 结构体,因为我这里使用的 kubeconfig 所以不用写入 url
config, err := clientcmd.BuildConfigFromFlags("", kubeconfig)
if err != nil {
panic(err)
}
// 通过 config 生成 client
clientset, err := kubernetes.NewForConfig(config)
if err != nil {
log.Fatal(err)
}
// 争对不同的资源可以通过不同的 clientset api 获取
// namespace 的 api 在 corev1 ,直接获取 namespace 接口
namespaceClient := clientset.CoreV1().Namespaces()
// 获取 namespace 列表
namespaceList, err := namespaceClient.List(context.TODO(), v1.ListOptions{})
if err != nil {
log.Fatal(err)
}
// Items 是一个切片,Items是列表中命名空间对象的列表。
for _, namespace := range namespaceList.Items {
fmt.Println(namespace.Name)
}
}
获取到对应的 namespace
[19:16:34 root@go testK8S]#go run main.go
default
kube-node-lease
kube-public
kube-system
limits
mysql
role
web
2.2.2 namespace 删除
package main
import (
"context"
"log"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/clientcmd"
)
func main() {
kubeconfig := "etc/config"
// 初始化配置文件
config, err := clientcmd.BuildConfigFromFlags("", kubeconfig)
if err != nil {
log.Fatal(err)
}
// 创建 K8S 客户端
clientSet, err := kubernetes.NewForConfig(config)
if err != nil {
log.Fatal(err)
}
// 定义 namespaceclient
namespaceClitn := clientSet.CoreV1().Namespaces()
// 删除 web namespace
err = namespaceClitn.Delete(context.TODO(), "web", v1.DeleteOptions{})
if err != nil {
log.Fatal(err)
}
}
运行程序
[19:19:19 root@go testK8S]#go run main.go
2.3 deployment
deployment 列表获取、创建、修改、删除
2.3.1 获取所有 namespace 下 deployment
package main
import (
"context"
"fmt"
"log"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/clientcmd"
)
// K8S 配置初始化
func k8sConfig() *kubernetes.Clientset {
kubeconfig := "etc/config"
config, err := clientcmd.BuildConfigFromFlags("", kubeconfig)
if err != nil {
log.Fatal(err)
}
clientSet, err := kubernetes.NewForConfig(config)
if err != nil {
log.Fatal(err)
}
return clientSet
}
// namespace 获取
func Namespace() []string {
namespaceClient := k8sConfig().CoreV1().Namespaces()
namespaceList, err := namespaceClient.List(context.TODO(), v1.ListOptions{})
if err != nil {
log.Fatal(err)
}
namesapces := []string{}
for _, namespace := range namespaceList.Items {
namesapces = append(namesapces, namespace.Name)
}
return namesapces
}
// deployment 获取
func Deployment() {
for _, namespaces := range Namespace() {
deploymentClient := k8sConfig().AppsV1().Deployments(namespaces)
deploymentList, err := deploymentClient.List(context.TODO(), v1.ListOptions{})
if err != nil {
log.Fatal(err)
} else {
for _, deployment := range deploymentList.Items {
fmt.Printf("namespace:%s name:%s\n", deployment.Namespace, deployment.Name)
}
}
}
}
func main() {
// 调用函数
Deployment()
}
# 获取到所有的 namespace 下的 deployment
[21:50:40 root@go testK8S]#go run main.go
namespace:kube-system name:calico-kube-controllers
namespace:kube-system name:coredns
namespace:kube-system name:metrics-server
namespace:web name:web-tomcat-app1-deployment
2.3.2 删除指定的 deployment
package main
import (
"context"
"fmt"
"log"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/clientcmd"
)
// K8S 配置初始化
func k8sConfig() *kubernetes.Clientset {
kubeconfig := "etc/config"
config, err := clientcmd.BuildConfigFromFlags("", kubeconfig)
if err != nil {
log.Fatal(err)
}
clientSet, err := kubernetes.NewForConfig(config)
if err != nil {
log.Fatal(err)
}
return clientSet
}
// namespace 获取
func GetNamespace() []string {
namespaceClient := k8sConfig().CoreV1().Namespaces()
namespaceList, err := namespaceClient.List(context.TODO(), v1.ListOptions{})
if err != nil {
log.Fatal(err)
}
namesapces := []string{}
for _, namespace := range namespaceList.Items {
namesapces = append(namesapces, namespace.Name)
}
return namesapces
}
// deployment 获取
func GetDeployment() {
for _, namespaces := range GetNamespace() {
deploymentClient := k8sConfig().AppsV1().Deployments(namespaces)
deploymentList, err := deploymentClient.List(context.TODO(), v1.ListOptions{})
if err != nil {
log.Fatal(err)
} else {
for _, deployment := range deploymentList.Items {
fmt.Printf("namespace:%s name:%s\n", deployment.Namespace, deployment.Name)
}
}
}
}
// deployment 删除 web namespace 下的 web-tomcat-app1-deployment
func DelDeployment() {
deploymentClient := k8sConfig().AppsV1().Deployments("web")
err := deploymentClient.Delete(context.TODO(), "web-tomcat-app1-deployment", v1.DeleteOptions{})
if err != nil {
log.Fatal(err)
} else {
fmt.Println("web deployment delete success!")
}
}
func main() {
DelDeployment()
}
# 删除成功
[21:59:34 root@go testK8S]#go run main.go
web deployment delete success!
2.3.3 创建 deployment
在创建 deployment 的时候就需要指定创建到那个 namespace 下,这里我将创建到默认的 namespace 下
package main
import (
"context"
"fmt"
"log"
appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/clientcmd"
)
// K8S 配置初始化
func k8sConfig() *kubernetes.Clientset {
kubeconfig := "etc/config"
config, err := clientcmd.BuildConfigFromFlags("", kubeconfig)
if err != nil {
log.Fatal(err)
}
clientSet, err := kubernetes.NewForConfig(config)
if err != nil {
log.Fatal(err)
}
return clientSet
}
// 由于在创建 deployment 的时候需要指定副本集,而且是一个 int32 的指针类型
func Int32ptr(i int32) *int32 {
return &i
}
// 创建 deployment
func CreateDeployment() {
// 通过 config 生成 K8S Deployments.client
deploymentClient := k8sConfig().AppsV1().Deployments("web")
// 对 deployment 的操作是 create
deployment, err := deploymentClient.Create(context.TODO(), &appsv1.Deployment{
// meta 字段,定义这个 deployment 的 name 和所在的 namespace 以及标签
ObjectMeta: metav1.ObjectMeta{
Name: "test-golang",
Namespace: "web",
Labels: map[string]string{"app": "test-golang"},
},
// spec 字段,定义副本数等
Spec: appsv1.DeploymentSpec{
Replicas: Int32ptr(2),
Selector: &metav1.LabelSelector{
MatchLabels: map[string]string{"app": "test-golang"},
},
// template 字段
Template: corev1.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{
Labels: map[string]string{"app": "test-golang"},
},
// template.spec 字段
Spec: corev1.PodSpec{
Containers: []corev1.Container{
{
Name: "test",
Image: "nginx:1.16.1",
ImagePullPolicy: corev1.PullIfNotPresent,
Ports: []corev1.ContainerPort{
{
Name: "http",
ContainerPort: 80,
Protocol: corev1.ProtocolTCP,
},
},
},
},
},
},
},
}, metav1.CreateOptions{})
if err != nil {
log.Fatal(err)
} else {
fmt.Printf("deployment Create success!\n%v\n", &deployment.Status)
}
}
func main() {
CreateDeployment()
}
执行:
[14:34:56 root@go testK8S]#go run main.go
deployment Create success!
&DeploymentStatus{ObservedGeneration:0,Replicas:0,UpdatedReplicas:0,AvailableReplicas:0,UnavailableReplicas:0,Conditions:[]DeploymentCondition{},ReadyReplicas:0,CollisionCount:nil,}
在 K8S 上查看
# pod 已经创建成功,副本数为 2
[16:03:04 root@k8s-master k8syaml]#kubectl get pod -n web
NAME READY STATUS RESTARTS AGE
test-golang-7f5b4bb549-57f58 1/1 Running 0 39m
test-golang-7f5b4bb549-rl4b6 1/1 Running 0 39m
# deployment 创建成功
[16:02:56 root@k8s-master k8syaml]#kubectl get deployments.apps -n web
NAME READY UP-TO-DATE AVAILABLE AGE
test-golang 2/2 2 2 37m
# 查看详细信息和程序中的一样
[16:04:38 root@k8s-master k8syaml]#kubectl describe deployments.apps -n web test-golang
Name: test-golang
Namespace: web
CreationTimestamp: Tue, 09 Nov 2021 15:25:18 +0800
Labels: app=test-golang
Annotations: deployment.kubernetes.io/revision: 1
Selector: app=test-golang
Replicas: 2 desired | 2 updated | 2 total | 2 available | 0 unavailable
StrategyType: RollingUpdate
MinReadySeconds: 0
RollingUpdateStrategy: 25% max unavailable, 25% max surge
Pod Template:
Labels: app=test-golang
Containers:
test:
Image: nginx:1.16.1
Port: 80/TCP
Host Port: 0/TCP
Environment: <none>
Mounts: <none>
Volumes: <none>
Conditions:
Type Status Reason
---- ------ ------
Available True MinimumReplicasAvailable
Progressing True NewReplicaSetAvailable
OldReplicaSets: <none>
NewReplicaSet: test-golang-7f5b4bb549 (2/2 replicas created)
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal ScalingReplicaSet 39m deployment-controller Scaled up replica set test-golang-7f5b4bb549 to 2
2.3.4 修改 deployment
这里我就修改刚才上面创建的 web namespace 下的 deployment ,将副本集改为对应的,如果说想修改其他熟悉也是一样的
2.3.4.1 修改 deployment 副本集
package main
import (
"context"
"fmt"
"log"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/clientcmd"
)
// K8S 配置初始化
func k8sConfig() *kubernetes.Clientset {
kubeconfig := "etc/config"
config, err := clientcmd.BuildConfigFromFlags("", kubeconfig)
if err != nil {
log.Fatal(err)
}
clientSet, err := kubernetes.NewForConfig(config)
if err != nil {
log.Fatal(err)
}
return clientSet
}
// 由于在创建 deployment 的时候需要指定副本集,而且是一个 int32 的指针类型
func Int32ptr(i int32) *int32 {
return &i
}
// deployment 修改
func EditDeployment() {
deploymentClient := k8sConfig().AppsV1().Deployments("web")
// 在修改 deployment 之前肯定需要先找到对应的 deployment,找到 test-golang 的 deployment
deployment, err := deploymentClient.Get(context.TODO(), "test-golang", metav1.GetOptions{})
if err != nil {
log.Fatal(err)
}
// deployment.Spec.Replicas 获取的是一个指针,所以需要取地址
// 如果副本大于 2 就 - 1 ,否则 + 1
if *deployment.Spec.Replicas > 2 {
deployment.Spec.Replicas = Int32ptr(*deployment.Spec.Replicas - 1)
} else {
deployment.Spec.Replicas = Int32ptr(*deployment.Spec.Replicas + 1)
}
deployment, err = deploymentClient.Update(context.TODO(), deployment, metav1.UpdateOptions{})
if err != nil {
log.Fatal(err)
} else {
fmt.Printf("deployment : %s ,replocas=%d update success!\n", deployment.Name, *deployment.Spec.Replicas)
}
}
执行
[16:46:43 root@go testK8S]#go run main.go
deployment : test-golang ,replocas=2 update success!
K8S 节点查看
# 副本数以修改为 1
[16:49:16 root@k8s-master k8syaml]#kubectl get deployments.apps -n web test-golang
NAME READY UP-TO-DATE AVAILABLE AGE
test-golang 2/2 2 2 84m
# pod 变为 1
[16:33:47 root@k8s-master k8syaml]#kubectl get pod -n web
NAME READY STATUS RESTARTS AGE
test-golang-7f5b4bb549-4n9vr 1/1 Running 0 8s
test-golang-7f5b4bb549-rl4b6 1/1 Running 0 83m
2.3.4.2 修改 deployment 镜像
这里修改容器的镜像
package main
import (
"context"
"fmt"
"log"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/clientcmd"
)
// K8S 配置初始化
func k8sConfig() *kubernetes.Clientset {
kubeconfig := "etc/config"
config, err := clientcmd.BuildConfigFromFlags("", kubeconfig)
if err != nil {
log.Fatal(err)
}
clientSet, err := kubernetes.NewForConfig(config)
if err != nil {
log.Fatal(err)
}
return clientSet
}
// deployment 修改容器镜像
func EditImage() {
deploymentClient := k8sConfig().AppsV1().Deployments("web")
// 在修改 deployment 之前肯定需要先找到对应的 deployment,找到 test-golang 的 deployment
deployment, err := deploymentClient.Get(context.TODO(), "test-golang", metav1.GetOptions{})
if err != nil {
log.Fatal(err)
}
// 修改 deployment.Spec.Template.Spec.Containers.image 字段
// 需要更新的镜像,这里改为 nginx:1.21.3
deployment.Spec.Template.Spec.Containers[0].Image = "nginx:1.21.3"
deployment, err = deploymentClient.Update(context.TODO(), deployment, metav1.UpdateOptions{})
if err != nil {
log.Fatal(err)
} else {
fmt.Printf("deployment : %s image update success!\n", deployment.Name)
}
}
func main() {
EditImage()
}
[17:26:34 root@go testK8S]#go run main.go
deployment : test-golang ,image update success!
K8S 节点验证
# 通过 grep 过滤 nginx 镜像已经修改为了 nginx:1.21.3
[17:26:55 root@k8s-master k8syaml]#kubectl describe pod -n web test-golang-5ccbff5ff7- | grep image
Normal Pulled 24s kubelet Container image "nginx:1.21.3" already present on machine
Normal Pulled 22s kubelet Container image "nginx:1.21.3" already present on machine
Normal Pulled 20s kubelet Container image "nginx:1.21.3" already present on machine
2.4 service
service 获取、创建、修改、删除
2.4.1 service 获取
package main
import (
"context"
"fmt"
"log"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/clientcmd"
)
// K8S 配置初始化
func k8sConfig() *kubernetes.Clientset {
kubeconfig := "etc/config"
config, err := clientcmd.BuildConfigFromFlags("", kubeconfig)
if err != nil {
log.Fatal(err)
}
clientSet, err := kubernetes.NewForConfig(config)
if err != nil {
log.Fatal(err)
}
return clientSet
}
// namespace 获取
func GetNamespace() []string {
namespaceClient := k8sConfig().CoreV1().Namespaces()
namespaceList, err := namespaceClient.List(context.TODO(), v1.ListOptions{})
if err != nil {
log.Fatal(err)
}
namesapces := []string{}
for _, namespace := range namespaceList.Items {
namesapces = append(namesapces, namespace.Name)
}
return namesapces
}
// deployment 获取
func GetDeployment() {
for _, namespaces := range GetNamespace() {
deploymentClient := k8sConfig().AppsV1().Deployments(namespaces)
deploymentList, err := deploymentClient.List(context.TODO(), v1.ListOptions{})
if err != nil {
log.Fatal(err)
} else {
for _, deployment := range deploymentList.Items {
fmt.Printf("namespace:%s name:%s\n", deployment.Namespace, deployment.Name)
}
}
}
}
// deployment 删除
func DelDeployment() {
deploymentClient := k8sConfig().AppsV1().Deployments("web")
err := deploymentClient.Delete(context.TODO(), "web-tomcat-app1-deployment", v1.DeleteOptions{})
if err != nil {
log.Fatal(err)
} else {
fmt.Println("web deployment delete success!")
}
}
// svc 获取
func GetSvc() {
for _, namespace := range GetNamespace() {
svcClient := k8sConfig().CoreV1().Services(namespace)
svcList, err := svcClient.List(context.TODO(), v1.ListOptions{})
if err != nil {
log.Fatal(err)
} else {
// 获取 svc 基础信息
for _, svc := range svcList.Items {
fmt.Printf("\n-------------\nNameSpace:%s\nSvcName:%s\nClusterIP:%s\nLabels:%s\n",
svc.Namespace, svc.Name, svc.Spec.ClusterIP, svc.Labels)
// 获取 svc port 信息
for _, port := range svc.Spec.Ports {
fmt.Printf("Protocol:%s\nPodPort:%d\nNodePort:%d\n", port.Protocol, port.Port, port.NodePort)
}
}
}
}
}
func main() {
GetSvc()
}
[22:20:21 root@go testK8S]#go run main.go
-------------
NameSpace:default
SvcName:kubernetes
ClusterIP:172.30.0.1
Labels:map[component:apiserver provider:kubernetes]
Protocol:TCP
PodPort:443
NodePort:0
-------------
NameSpace:kube-system
SvcName:kube-dns
ClusterIP:172.30.0.10
Labels:map[k8s-app:kube-dns kubernetes.io/cluster-service:true kubernetes.io/name:CoreDNS]
Protocol:UDP
PodPort:53
NodePort:0
Protocol:TCP
PodPort:53
NodePort:0
Protocol:TCP
PodPort:9153
NodePort:0
-------------
NameSpace:kube-system
SvcName:metrics-server
ClusterIP:172.30.90.118
Labels:map[k8s-app:metrics-server]
Protocol:TCP
PodPort:443
NodePort:0
-------------
NameSpace:web
SvcName:web-tomcat-app1-service
ClusterIP:172.30.160.50
Labels:map[app:web-tomcat-app1-service-label]
Protocol:TCP
PodPort:80
NodePort:28080