client-go
这是k8s官方提供的与kubernetes集群通信的Go客户端,可以直接通过这个sdk来操纵k8s集群。这里来过一下这个库的一些使用方式。
安装
下载go语言
我用两个阿里云服务器搭建了一个k3s集群,简单记录一下如何在阿里云的宝塔linux服务器上安装go:
wget https://mirrors.aliyun.com/golang/go1.26.2.linux-amd64.tar.gz
然后如下操作即可:
rm -rf /usr/local/go && tar -C /usr/local -xzf go1.26.2.linux-amd64.tar.gz
添加如下命令到/etc/profile文件中:
export PATH=$PATH:/usr/local/go/bin
随后验证一下即可:
go version

然后记得修改镜像源,防止由于代理问题导致不能正常拉取需要的库:
go env -w GOPROXY=https://mirrors.aliyun.com/goproxy/,direct

————————————————
安装sdk库
直接按照官方给的安装最新版本的即可:
go get k8s.io/client-go@latest
在实际使用中还需要添加如下的库:
go get k8s.io/api@latest
go get k8s.io/apimachinery@latest
后续就基于这些sdk库来简单操作一下k8s集群。
功能场景
官方提供了一些example来进行参考:
https://github.com/kubernetes/client-go/tree/master/examples
后续基于这个来进行简单了解一下场景下的代码使用方式。
注意在单linxu环境中运行要先在服务器中创建一个go项目,在一个单独的文件夹下执行如下命令即可:
go mod init main

这样后续代码运行需要的库就会加在这个go.mod文件中。
基本功能
展示一下如何连接k8s集群以及查看集群中的信息,使用代码如下:
package main
import (
"context"
"fmt"
"os"
"path/filepath"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
"k8s.io/client-go/tools/clientcmd"
"k8s.io/client-go/util/homedir"
)
func main() {
// 创建配置(自动识别 k3s/k8s)
config, configPath, clusterType, err := getKubeConfig()
if err != nil {
fmt.Printf("❌ 连接失败: %v\n", err)
fmt.Println("\n提示:")
fmt.Println(" - k3s 用户: sudo go run k8s_simple_example.go")
fmt.Println(" - k8s 用户: go run k8s_simple_example.go")
return
}
fmt.Printf("✓ 集群类型: %s\n", clusterType)
fmt.Printf("✓ 配置文件: %s\n", configPath)
clientset, err := kubernetes.NewForConfig(config)
if err != nil {
panic(err.Error())
}
fmt.Println("✓ 连接成功\n")
// 3. 查看所有 Pods
fmt.Println("=== Pod 信息 ===")
pods, err := clientset.CoreV1().Pods("").List(context.TODO(), metav1.ListOptions{})
if err != nil {
panic(err.Error())
}
fmt.Printf("总共 %d 个 Pod:\n", len(pods.Items))
for i, pod := range pods.Items {
fmt.Printf("%d. [%s] %s\n", i+1, pod.Namespace, pod.Name)
fmt.Printf(" IP: %s | 节点: %s | 状态: %s\n",
pod.Status.PodIP, pod.Spec.NodeName, pod.Status.Phase)
}
// 4. 查看节点信息
fmt.Println("\n=== 节点信息 ===")
nodes, err := clientset.CoreV1().Nodes().List(context.TODO(), metav1.ListOptions{})
if err != nil {
panic(err.Error())
}
fmt.Printf("总共 %d 个节点:\n", len(nodes.Items))
for i, node := range nodes.Items {
fmt.Printf("\n%d. 节点: %s\n", i+1, node.Name)
// IP 地址
for _, addr := range node.Status.Addresses {
if addr.Type == "InternalIP" {
fmt.Printf(" 内网IP: %s\n", addr.Address)
}
}
// 资源信息
fmt.Printf(" CPU: %s (可用: %s)\n",
node.Status.Capacity.Cpu().String(),
node.Status.Allocatable.Cpu().String())
fmt.Printf(" 内存: %s (可用: %s)\n",
node.Status.Capacity.Memory().String(),
node.Status.Allocatable.Memory().String())
// 系统信息
fmt.Printf(" 系统: %s\n", node.Status.NodeInfo.OSImage)
fmt.Printf(" 版本: %s\n", node.Status.NodeInfo.KubeletVersion)
}
// 5. 查看命名空间
fmt.Println("\n=== 命名空间 ===")
namespaces, err := clientset.CoreV1().Namespaces().List(context.TODO(), metav1.ListOptions{})
if err != nil {
panic(err.Error())
}
fmt.Printf("总共 %d 个命名空间: ", len(namespaces.Items))
for i, ns := range namespaces.Items {
if i > 0 {
fmt.Print(", ")
}
fmt.Print(ns.Name)
}
fmt.Println()
}
// getKubeConfig 自动获取 Kubernetes 配置(k3s/k8s 通用)
func getKubeConfig() (*rest.Config, string, string, error) {
// 配置文件路径(按优先级)
configPaths := []struct {
path string
name string
}{
{os.Getenv("KUBECONFIG"), "环境变量"},
{"/etc/rancher/k3s/k3s.yaml", "k3s"},
{filepath.Join(homedir.HomeDir(), ".kube/config"), "k8s"},
{"/etc/kubernetes/admin.conf", "k8s"},
}
for _, cp := range configPaths {
if cp.path == "" {
continue
}
if _, err := os.Stat(cp.path); err == nil {
if config, err := clientcmd.BuildConfigFromFlags("", cp.path); err == nil {
return config, cp.path, cp.name, nil
}
}
}
return nil, "", "", fmt.Errorf("未找到配置文件")
}
这里的代码实现了匹配环境是k3s还是k8s,尽量实现两种集群的灵活配置。
添加进代码后执行如下命令即可:
go get k8s.io/client-go@latest
go get k8s.io/apimachinery@latest
go mod tidy
执行这个命令后会自动下载项目中需要的库,就需要挨个挨个单独下载了。最后执行效果如下:
go run 1.go

和运行kubectl获取到的结果一样。
管理pod
这里主要是为了实现我在dast中设计的功能场景:拉取外部镜像库并创建对应的pod。基于这个点,主要涉及到两个功能实现:
- 拉取镜像库中的镜像
- 将对应镜像创建为pod
如果是公开镜像,就不需要单独搞个镜像库了,但是我这里的扫描模块都是特制的,故这里准备将相关代码制成镜像后push到镜像库中,然后再在k3s集群拉取并创建pod时pull下来,那么这样的话就需要配置登陆凭证,不然拉不下来。
最后调研下来,准备基于下面两种方式结合来实现CI以及推送镜像到容器镜像服务:
- GitHub Actions
- GHCR(github container registry),容器镜像仓库服务
都是github提供的非常方便的用于实现这方面的功能,下面来看看要如何实现。
基本说明
Github Actions:
Github Actions是一种持续集成和持续交付(CI/CD)平台,可用于自动执行生成、测试和部署管道。主要通过工作流来实现自动化。工作流是一个可配置的自动化过程,它将运行一个或多个作业,在仓库的.github/workflow目录中定义,一个仓库可以有多个工作流,每个工作流都可以执行一组不同的任务。
GHCR:
这是github提供的容器镜像服务,可以通过github actions构建镜像并推送到这个镜像仓库中,后续可以直接从这个镜像仓库拉取对应的镜像,形如:
docker pull ghcr.io/your-githubname/imagename
#私有的话还需要先login
下面来基于一个nginx的docker文件实现ci构建以及push,这里就直接在已有的代码库上操作了,在根目录新建dockerfile文件如下:
FROM nginx:alpine
COPY . /usr/share/nginx/html
EXPOSE 80
然后新建workflow文件:

修改成如下具体模版文件内容后commit即可:
name: Build CTF Image
on:
push:
branches:
- main
jobs:
docker:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Login GHCR
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and Push
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: ghcr.io/${{ github.repository_owner }}/ctf-web:latest
后续就会自动构建并推送镜像,最后可以在自己的github packages看到对应的镜像文件(位置在个人 =》 profile =〉packages):

后续就可以自行拉取对应的镜像并构建容器:

后续就不多说了。
自行理解一下这里的workflow文件**,有一个点值得提一下**:
在提交commit到main分支,就会自动执行一次ci操作,这里有个关键配置就是permissions,设置了packages可写,也就是可以把镜像推送到对应的镜像仓库中,如果这里没写直接指明这个点,就会报错:
buildx failed with: ERROR: failed to build: denied: installation not allowed to Write organization package
如果就是不写这个配置,还可以通过直接修改这个代码库的配置来达到同样的目的:

点击settings =》 actions => general :

拉到最下面修改配置即可:

将github_token的默认权限改成了任意可读可写,后续也就可以直接push镜像到packages上了。但实际不用改,像之前那样在模版文件中加个权限设置即可。
——————
最后再提一个点,在自动运行工作流时,是可以在github actions上看到对应的日志的:

基于这个页面来查看构建情况,未执行成功github还会给你发送邮件通知,还是很贴心的。
并且这样配置的镜像是不需要权限验证的,直接拉就行,并且在k3s集群中也可以直接针对ghcr.io拉镜像:

可以正常访问到对应镜像的nginx页面:

并且拉取的镜像也会保存在本地:

后续直接用就行。
这里也就不做pull权限验证了,在具体私人自行落地时修改对应的packages权限即可:

补充
这里补充一个知识点,k8s的默认镜像拉取策略为:

这里的Always则代表:

每次拉取镜像时都会优先查询镜像仓库的digest,只有相同的才使用本地缓存的进行概念股,否则都是使用新的镜像。这样很方便用于我的dast的pod镜像管理,我正准备将所有扫描模块的镜像都设置成latest,这样新拉的pod,就正好是新的pod。简单测试如下:
原来的dockerfile文件改成:
FROM nginx:latest
RUN echo 'wow,wow,wow,it is a test for using' > /usr/share/nginx/html/index.html
EXPOSE 80
等待GitHub actions拉起:

再重新在集群里面新建容器即可:
kubectl create deployment ctf-web --image=ghcr.io/fupanc-w1n/ctf-web:latest
kubectl get pods
kubectl exec -it ctf-web-78c68b7f65-f4r2r -- sh

成功实现远端镜像变化集群拉取的镜像也会变化,这对于后续dast开发的自动化更新为新pod容器非常重要。
————————————————
示例代码
这里主要实现的功能有如下:
- 可传入镜像名称以及要创建几个pod
- 修改、删除pod数量
代码如下:
- 创建pod代码:
package main
import (
"context"
"fmt"
"os"
"path/filepath"
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/rest"
"k8s.io/client-go/tools/clientcmd"
"k8s.io/client-go/util/homedir"
)
func main() {
// 连接集群
config, configPath, clusterType, err := getKubeConfig()
if err != nil {
fmt.Printf("❌ 连接失败: %v\n", err)
return
}
fmt.Printf("✓ 集群类型: %s\n", clusterType)
fmt.Printf("✓ 配置文件: %s\n", configPath)
clientset, err := kubernetes.NewForConfig(config)
if err != nil {
panic(err.Error())
}
fmt.Println("✓ 连接成功\n")
// ==================== 测试参数(硬编码) ====================
namespace := "default"
deploymentName := "test-nginx-deployment"
imageName := "ghcr.io/fupanc-w1n/ctf-web:latest"
replicas := int32(3)
// ==================== 1. 创建 Deployment ====================
fmt.Println("=== 创建 Deployment ===")
err = createDeployment(clientset, namespace, deploymentName, imageName, replicas)
if err != nil {
fmt.Printf("❌ 创建失败: %v\n", err)
} else {
fmt.Printf("✓ 成功创建 Deployment: %s (副本数: %d, 镜像: %s)\n\n", deploymentName, replicas, imageName)
}
}
// ==================== 核心函数 ====================
// createDeployment 创建 Deployment
func createDeployment(clientset *kubernetes.Clientset, namespace, name, image string, replicas int32) error {
deploymentsClient := clientset.AppsV1().Deployments(namespace)
deployment := &appsv1.Deployment{
ObjectMeta: metav1.ObjectMeta{
Name: name,
},
Spec: appsv1.DeploymentSpec{
Replicas: &replicas,
Selector: &metav1.LabelSelector{
MatchLabels: map[string]string{
"app": name,
},
},
Template: corev1.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{
Labels: map[string]string{
"app": name,
},
},
Spec: corev1.PodSpec{
Containers: []corev1.Container{
{
Name: "app",
Image: image,
Ports: []corev1.ContainerPort{
{
ContainerPort: 80,
},
},
},
},
},
},
},
}
_, err := deploymentsClient.Create(context.TODO(), deployment, metav1.CreateOptions{})
return err
}
// ==================== 配置加载函数 ====================
func getKubeConfig() (*rest.Config, string, string, error) {
configPaths := []struct {
path string
name string
}{
{os.Getenv("KUBECONFIG"), "环境变量"},
{"/etc/rancher/k3s/k3s.yaml", "k3s"},
{filepath.Join(homedir.HomeDir(), ".kube/config"), "k8s"},
{"/etc/kubernetes/admin.conf", "k8s"},
}
for _, cp := range configPaths {
if cp.path == "" {
continue
}
if _, err := os.Stat(cp.path); err == nil {
if config, err := clientcmd.BuildConfigFromFlags("", cp.path); err == nil {
return config, cp.path, cp.name, nil
}
}
}
return nil, "", "", fmt.Errorf("未找到配置文件")
}
运行效果如下:

成功创建了三个pod。
- pod扩容:
package main
import (
"context"
"fmt"
"os"
"path/filepath"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
"k8s.io/client-go/tools/clientcmd"
"k8s.io/client-go/util/homedir"
)
func main() {
// 连接集群
config, configPath, clusterType, err := getKubeConfig()
if err != nil {
fmt.Printf("❌ 连接失败: %v\n", err)
return
}
fmt.Printf("✓ 集群类型: %s\n", clusterType)
fmt.Printf("✓ 配置文件: %s\n", configPath)
clientset, err := kubernetes.NewForConfig(config)
if err != nil {
panic(err.Error())
}
fmt.Println("✓ 连接成功\n")
// ==================== 测试参数(硬编码) ====================
namespace := "default"
deploymentName := "test-nginx-deployment"
// ==================== 1. 修改副本数(扩容) ====================
fmt.Println("\n=== 修改副本数(扩容到 5 个) ===")
newReplicas := int32(5)
err = scaleDeployment(clientset, namespace, deploymentName, newReplicas)
if err != nil {
fmt.Printf("❌ 扩容失败: %v\n", err)
} else {
fmt.Printf("✓ 成功扩容到 %d 个副本\n\n", newReplicas)
}
}
// scaleDeployment 修改 Deployment 副本数(扩缩容)
func scaleDeployment(clientset *kubernetes.Clientset, namespace, name string, replicas int32) error {
deploymentsClient := clientset.AppsV1().Deployments(namespace)
// 获取当前 Deployment
deployment, err := deploymentsClient.Get(context.TODO(), name, metav1.GetOptions{})
if err != nil {
return fmt.Errorf("获取 Deployment 失败: %v", err)
}
// 修改副本数
deployment.Spec.Replicas = &replicas
// 更新 Deployment
_, err = deploymentsClient.Update(context.TODO(), deployment, metav1.UpdateOptions{})
return err
}
func getKubeConfig() (*rest.Config, string, string, error) {
configPaths := []struct {
path string
name string
}{
{os.Getenv("KUBECONFIG"), "环境变量"},
{"/etc/rancher/k3s/k3s.yaml", "k3s"},
{filepath.Join(homedir.HomeDir(), ".kube/config"), "k8s"},
{"/etc/kubernetes/admin.conf", "k8s"},
}
for _, cp := range configPaths {
if cp.path == "" {
continue
}
if _, err := os.Stat(cp.path); err == nil {
if config, err := clientcmd.BuildConfigFromFlags("", cp.path); err == nil {
return config, cp.path, cp.name, nil
}
}
}
return nil, "", "", fmt.Errorf("未找到配置文件")
}
运行效果如下:

成功扩容到5个。缩容的话也是一样的,把newReplicas设置成2即可:

其实都一样的,重点就是可以直接在初始化指定replicas来创建多个pod,然后再指定replicas来扩缩pod,然后删除的话直接删除对应的deployment即可:
package main
import (
"context"
"fmt"
"os"
"path/filepath"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
"k8s.io/client-go/tools/clientcmd"
"k8s.io/client-go/util/homedir"
)
func main() {
// 连接集群
config, configPath, clusterType, err := getKubeConfig()
if err != nil {
fmt.Printf("❌ 连接失败: %v\n", err)
return
}
fmt.Printf("✓ 集群类型: %s\n", clusterType)
fmt.Printf("✓ 配置文件: %s\n", configPath)
clientset, err := kubernetes.NewForConfig(config)
if err != nil {
panic(err.Error())
}
fmt.Println("✓ 连接成功\n")
// ==================== 测试参数(硬编码) ====================
namespace := "default"
deploymentName := "test-nginx-deployment"
// ==================== 4. 删除 Deployment ====================
fmt.Println("\n=== 删除 Deployment ===")
// 取消注释下面这行来删除 Deployment
err = deleteDeployment(clientset, namespace, deploymentName)
if err != nil {
fmt.Printf("❌ 删除失败: %v\n", err)
} else {
fmt.Printf("✓ 成功删除 Deployment: %s\n", deploymentName)
}
}
// deleteDeployment 删除 Deployment
func deleteDeployment(clientset *kubernetes.Clientset, namespace, name string) error {
deploymentsClient := clientset.AppsV1().Deployments(namespace)
deletePolicy := metav1.DeletePropagationForeground
err := deploymentsClient.Delete(context.TODO(), name, metav1.DeleteOptions{
PropagationPolicy: &deletePolicy,
})
return err
}
func getKubeConfig() (*rest.Config, string, string, error) {
configPaths := []struct {
path string
name string
}{
{os.Getenv("KUBECONFIG"), "环境变量"},
{"/etc/rancher/k3s/k3s.yaml", "k3s"},
{filepath.Join(homedir.HomeDir(), ".kube/config"), "k8s"},
{"/etc/kubernetes/admin.conf", "k8s"},
}
for _, cp := range configPaths {
if cp.path == "" {
continue
}
if _, err := os.Stat(cp.path); err == nil {
if config, err := clientcmd.BuildConfigFromFlags("", cp.path); err == nil {
return config, cp.path, cp.name, nil
}
}
}
return nil, "", "", fmt.Errorf("未找到配置文件")
}
效果如下:

成功通过删除deployment来删除了相关的pod。
————————————
配置分发
众所周知,pod都是基于镜像拉起的无状态容器,在一些情况下需要基于同一个镜像拉起不同工作细则的容器,目前的思路是代码逻辑+ConfigMap,通过ConfigMap往pod容器中挂载文件或设置环境变量,然后通过代码构造来动态读取pod容器中的配置信息,从而实现同一镜像不同工作细则的pod容器。pod中的代码就不多说了,这里就看看代码如何通过configmap实现文件挂载,大致需要实现的流程如下:
- 创建configmap
- 创建deployment时需指定卷挂载把 ConfigMap 挂到容器内目录
- 应用deployment
示例代码如下:
package main
import (
"context"
"fmt"
"os"
"path/filepath"
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/rest"
"k8s.io/client-go/tools/clientcmd"
"k8s.io/client-go/util/homedir"
)
func main() {
// 配置参数
namespace := "default"
configMapName := "scanner-json1"
deploymentName := "nginx-json-demo1"
localFilePath := "/tmp/k3s-demo/config.json" // 本地文件路径
mountPath := "/app/config" // 容器内挂载路径
// 创建 k8s 客户端
config, configPath, clusterType, err := getKubeConfig()
if err != nil {
fmt.Printf("获取 kubeconfig 失败: %v\n", err)
os.Exit(1)
}
fmt.Printf("✓ 使用配置: %s (%s)\n", configPath, clusterType)
clientset, err := kubernetes.NewForConfig(config)
if err != nil {
fmt.Printf("创建 k8s 客户端失败: %v\n", err)
os.Exit(1)
}
ctx := context.Background()
// 步骤1: 从本地文件创建 ConfigMap
if err := createConfigMapFromFile(ctx, clientset, namespace, configMapName, localFilePath); err != nil {
fmt.Printf("创建 ConfigMap 失败: %v\n", err)
os.Exit(1)
}
fmt.Printf("✓ ConfigMap '%s' 创建成功\n", configMapName)
// 步骤2: 创建 Deployment,挂载 ConfigMap
if err := createDeploymentWithConfigMap(ctx, clientset, namespace, deploymentName, configMapName, mountPath); err != nil {
fmt.Printf("创建 Deployment 失败: %v\n", err)
os.Exit(1)
}
fmt.Printf("✓ Deployment '%s' 创建成功,ConfigMap 已挂载到 %s\n", deploymentName, mountPath)
}
// getKubeConfig 获取 Kubernetes 配置(自动检测多种路径)
func getKubeConfig() (*rest.Config, string, string, error) {
configPaths := []struct {
path string
name string
}{
{os.Getenv("KUBECONFIG"), "环境变量"},
{"/etc/rancher/k3s/k3s.yaml", "k3s"},
{filepath.Join(homedir.HomeDir(), ".kube/config"), "k8s"},
{"/etc/kubernetes/admin.conf", "k8s"},
}
for _, cp := range configPaths {
if cp.path == "" {
continue
}
if _, err := os.Stat(cp.path); err == nil {
if config, err := clientcmd.BuildConfigFromFlags("", cp.path); err == nil {
return config, cp.path, cp.name, nil
}
}
}
return nil, "", "", fmt.Errorf("未找到配置文件")
}
// createConfigMapFromFile 从本地文件创建 ConfigMap
func createConfigMapFromFile(ctx context.Context, clientset *kubernetes.Clientset, namespace, name, filePath string) error {
// 读取本地文件内容
content, err := os.ReadFile(filePath)
if err != nil {
return fmt.Errorf("读取文件 %s 失败: %w", filePath, err)
}
// 提取文件名作为 ConfigMap 的 key
fileName := filepath.Base(filePath)
// 构造 ConfigMap 对象
configMap := &corev1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Name: name,
Namespace: namespace,
},
Data: map[string]string{
fileName: string(content),
},
}
// 创建 ConfigMap
_, err = clientset.CoreV1().ConfigMaps(namespace).Create(ctx, configMap, metav1.CreateOptions{})
if err != nil {
return fmt.Errorf("创建 ConfigMap 失败: %w", err)
}
return nil
}
// createDeploymentWithConfigMap 创建 Deployment 并挂载 ConfigMap
func createDeploymentWithConfigMap(ctx context.Context, clientset *kubernetes.Clientset, namespace, deploymentName, configMapName, mountPath string) error {
replicas := int32(1)
deployment := &appsv1.Deployment{
ObjectMeta: metav1.ObjectMeta{
Name: deploymentName,
Namespace: namespace,
},
Spec: appsv1.DeploymentSpec{
Replicas: &replicas,
Selector: &metav1.LabelSelector{
MatchLabels: map[string]string{
"app": deploymentName,
},
},
Template: corev1.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{
Labels: map[string]string{
"app": deploymentName,
},
},
Spec: corev1.PodSpec{
Containers: []corev1.Container{
{
Name: "nginx",
Image: "nginx:latest",
VolumeMounts: []corev1.VolumeMount{
{
Name: "json-volume",
MountPath: mountPath,
ReadOnly: true,
},
},
},
},
Volumes: []corev1.Volume{
{
Name: "json-volume",
VolumeSource: corev1.VolumeSource{
ConfigMap: &corev1.ConfigMapVolumeSource{
LocalObjectReference: corev1.LocalObjectReference{
Name: configMapName,
},
},
},
},
},
},
},
},
}
// 创建 Deployment
_, err := clientset.AppsV1().Deployments(namespace).Create(ctx, deployment, metav1.CreateOptions{})
if err != nil {
return fmt.Errorf("创建 Deployment 失败: %w", err)
}
return nil
}
新建文件:
mkdir -p /tmp/k3s-demo
cat > /tmp/k3s-demo/config.json <<'EOF'
{
"target": "example.com",
"mode": "scan",
"threads": 10
}
EOF

随后运行go文件即可:

随后可以查看相关内容:
kubectl describe configmap scanner-json1

成功在configmap中存入键值对,再进入pod容器查看是否成功挂载:
kubectl exec -it nginx-json-demo1-f6f7bf48c-vk9w2 -- sh

成功通过client-go库实现文件挂载,当然还可以设置环境变量等等,这里就不多说了,后续dast的策略配置分发就基于这个configmap了。
——————————————————
暂时就先这样,目前还没有涉及到什么新建Services来开放应用到外部,都是直接在自己的集群里面调用的。
参考文章: