创建K8s pod Webhook

news2024/9/26 3:28:36

目录

1.前提条件

2.开始创建核心组件Pod的Webhook

2.1.什么是Webhook

 2.2.在本地k8s集群安装cert-manager

2.3.创建一个空的文件夹

2.4. 生成工程框架

2.5. 生成核心组件Pod的API

2.6.生成Webhook

2.7.开始实现Webhook相关代码

2.7.1.修改相关配置

2.7.2.修改代码

2.7.3.按照最新配置更新yaml

2.7.4.集群运行测试

2.7.4.1.修改Makefile文件

2.7.4.2.将应用部署到k8s集群上

2.7.5.测试

2.7.5.1.准备测试Deployment的yaml配置

2.7.5.2.部署这个Pod demo

 2.7.5.3.停止测试

参考文章


1.前提条件

可以按之前的文章配置,配置好之后,我们会准备好以下内容:

  • 本地多节点集群
  • kubectl 客户端命令工具
  • Lens k8s dashboard 可视化客户端工具
  • golang开发语言
  • VScode Linux 版
  • kubebuilder

2.开始创建核心组件Pod的Webhook

        K8s的核心组件就那些几个:Deployment、Pod、Service、Ingress、ConfigMap、Secret、……

        在Kubebuilder的官方文档中,也有提到webhook的内容,但是比较简单,而且有些参考文章是基于CRD做的Webhook示例,此处我将演示核心组件Pod的Webhook。

图1 K8s核心组件

2.1.什么是Webhook

         从我的角度看,Webhook就是一个回调动作,举个例子方便理解:例如,我们希望在pod创建的时候,在annotation中增加一个标签,如author:geoff之类的,就可以利用这个webhook实现,当创建调用链完成之后,利用“回调”在这个创建动作之后丝滑地加入“增加annotation的额外动作”。可以结合Js的回调、java的AOP切片来理解。我们看看其中的原理:

图2 webhook基于k8s资源调用链中的admission 

        从图中可以看到,Webhook是在Mutating Admission或者Vaildating Admission阶段往Webhook发送一个“请求”并接受来自Webhook的“响应”。我们此时不妨大胆推测一下,实现这两点,要做些什么呢?我可以不负责任推测一下步骤:

  1. 在XXX Admission Controller配置一个请求,请求会往Webhook接受、处理并返回
  2. Webhook开发一个接收这个请求的Handler(类似Java的controller)

        事实也正如我们瞎想的哪样,确实核心就是这两个动作。这里我们看到,一共有两种Admission Controller,有点点区别:

  1. Mutating Admission Controller       # 可以修改资源
  2. Vaildating Admission Controller     # 验证资源,可以通过或者不通过

2.2.在本地k8s集群安装cert-manager

        这个算是提前准备了,需要注意的是,k8s集群的版本和cert-manage需要注意下,不然版本差别过多,可能会有些意想不到的问题

# 查看本地集群的版本
kind version

# 在集群上安装cert-maneger,其中v1.7.1就是cert-manager版本。
kubectl apply -f https://github.com/jetstack/cert-manager/releases/download/v1.7.1/cert-manager.yaml

# 验证对应的资源实例是否安装成功
kubectl get all -n cert-manager
# 看对应的Pod是否被成功创建,可能一开始pod的replicas=0,因为集群节点是image container,下载image可能比较慢
kubectl get pods -n cert-manager
图3 检查cert-manager安装状况

        事实上,有时候,get pods可能会发现无资源,这可能是local cluster有问题,建议先删除,后新建:

# 先删除本地的集群
kind delete cluster --name k8s-local-dev 
# 再新建
## 创建集群配置文件,1个master node,1个worker node。
cat << EOF > kind-clusters-mutil-config.yaml
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
- role: worker
EOF

## start to create cluster
kind create cluster --name k8s-local-dev --config ./kind-clusters-mutil-config.yaml

## copy kubeconfig to Lens kubecofig
## 不然Lens在Kind集群更新后,配置文件没更新,会打不开
cp ~/.kube/config /mnt/c/Users/${current_user}/.kube/config

2.3.创建一个空的文件夹

# 创建一个空的文件节夹
mkdir create-pod-webhook-demo
# 进入空文件夹
cd create-pod-webhook-demo

2.4. 生成工程框架

# 生成工程框架
kubebuilder init --domain geoff.wh.demo --repo k8s-operator/kubebuilder-webhook-demo

         生成文件目录如下, 此处,我不赘述了,上一篇文章已经有比较清晰的介绍了。

➜  create-pod-webhook-demo tree
.
├── Dockerfile
├── Makefile
├── PROJECT
├── README.md
├── config
│   ├── default
│   │   ├── kustomization.yaml
│   │   ├── manager_auth_proxy_patch.yaml
│   │   └── manager_config_patch.yaml
│   ├── manager
│   │   ├── controller_manager_config.yaml
│   │   ├── kustomization.yaml
│   │   └── manager.yaml
│   ├── prometheus
│   │   ├── kustomization.yaml
│   │   └── monitor.yaml
│   └── rbac
│       ├── auth_proxy_client_clusterrole.yaml
│       ├── auth_proxy_role.yaml
│       ├── auth_proxy_role_binding.yaml
│       ├── auth_proxy_service.yaml
│       ├── kustomization.yaml
│       ├── leader_election_role.yaml
│       ├── leader_election_role_binding.yaml
│       ├── role_binding.yaml
│       └── service_account.yaml
├── go.mod
├── go.sum
├── hack
│   └── boilerplate.go.txt
└── main.go

6 directories, 25 files

2.5. 生成核心组件Pod的API

        从这里之前,和创建Operator的步骤基本是一致的,从这里开始,要开始有点不一样了

# 定义API,此处要实现Pod的Webhook,因此直接按Pod的Api创建
kubebuilder create api --group core --version v1 --kind Pod
# 之后的option我们不创建Resource和Controller,因此都选择n

        之后的option我们不创建Resource和Controller,因此都选择n

图3 不创建Resource和Controller,选n

2.6.生成Webhook

# --Kind这里,可以指定现存的PAAS组件,也可以
kubebuilder create webhook --group core --version v1 --kind Pod --defaulting --webhook-version v1

        生成webhook的代码结构如下: 

➜  create-pod-webhook-demo tree
.
├── Dockerfile
├── Makefile
├── PROJECT
├── README.md
├── api
│   └── v1
│       ├── pod_webhook.go
│       └── webhook_suite_test.go
├── bin
│   └── controller-gen
├── config
│   ├── certmanager
│   │   ├── certificate.yaml
│   │   ├── kustomization.yaml
│   │   └── kustomizeconfig.yaml
│   ├── default
│   │   ├── kustomization.yaml
│   │   ├── manager_auth_proxy_patch.yaml
│   │   ├── manager_config_patch.yaml
│   │   ├── manager_webhook_patch.yaml
│   │   └── webhookcainjection_patch.yaml
│   ├── manager
│   │   ├── controller_manager_config.yaml
│   │   ├── kustomization.yaml
│   │   └── manager.yaml
│   ├── prometheus
│   │   ├── kustomization.yaml
│   │   └── monitor.yaml
│   ├── rbac
│   │   ├── auth_proxy_client_clusterrole.yaml
│   │   ├── auth_proxy_role.yaml
│   │   ├── auth_proxy_role_binding.yaml
│   │   ├── auth_proxy_service.yaml
│   │   ├── kustomization.yaml
│   │   ├── leader_election_role.yaml
│   │   ├── leader_election_role_binding.yaml
│   │   ├── role_binding.yaml
│   │   └── service_account.yaml
│   └── webhook
│       ├── kustomization.yaml
│       ├── kustomizeconfig.yaml
│       └── service.yaml
├── go.mod
├── go.sum
├── hack
│   └── boilerplate.go.txt
└── main.go

11 directories, 36 files

到这一步之后,我们直接转转入VScode开发

# 当前工程目录打开VScode
code .
图3 转入Vscode进行开发

2.7.开始实现Webhook相关代码

2.7.1.修改相关配置

        修改config/default/kustomize.yaml:

  1. 注释-crd 相关内容,因为我们没有CRD,只是实现Pod webhook
  2. 打开webhook、cert-manager相关配置,如下图所示
  3. 但是要注意属性缩进对齐,不然会报错
图4 修改config/default/kustomize.yaml的配置

        修改config/rdbc/kustomize.yaml:

1.注释 -role,这个也是和CRD相关,因为我们没有,所以注释掉

图4 注释config/rdbc/kustomize.yaml的role配置

        修改config/default/webhookcainjection_patch.yaml:

1.我们为了不搞这么复杂,我们只关心MutatingAdmision,因此可以直接注释掉ValidateAdmission

图5 注释config/default/webhookcainjection_patch.yaml中ValidateAdmission配置

2.7.2.修改代码

        因为核心组件Pod的Webhook和一般的CRD的webhook不一样,此处生成的pod_webhook.go只有Default()这个function,因此,我们需要直接重写整个代码,最重要的是Handle()方法。

        修改api/v1/pod_webhook.go文件:

/*
Copyright 2023.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package v1

import (
	"context"
	"encoding/json"
	"fmt"
	"net/http"

	corev1 "k8s.io/api/core/v1"
	"sigs.k8s.io/controller-runtime/pkg/client"
	logf "sigs.k8s.io/controller-runtime/pkg/log"
	"sigs.k8s.io/controller-runtime/pkg/webhook/admission"
)

// log is for logging in this package.
var podlog = logf.Log.WithName("pod-resource")

// 定义核心组件pod的webhook的主struct,类似于java的Class
type PodWebhookMutate struct {
	Client  client.Client
	decoder *admission.Decoder
}

// +kubebuilder:webhook:path=/mutate-core-v1-pod,mutating=true,failurePolicy=fail,sideEffects=None,groups=core,resources=pods,verbs=create;update,versions=v1,name=mpod.kb.io,admissionReviewVersions=v1
func (a *PodWebhookMutate) Handle(ctx context.Context, req admission.Request) admission.Response {
	pod := &corev1.Pod{}
	err := a.decoder.Decode(req, pod)
	if err != nil {
		return admission.Errored(http.StatusBadRequest, err)
	}

	// TODO: 变量marshaledPod是一个Map,可以直接修改pod的一些属性
	marshaledPod, err := json.Marshal(pod)
	if err != nil {
		return admission.Errored(http.StatusInternalServerError, err)
	}
	// 打印
	fmt.Println("======================================================")
	fmt.Println(string(marshaledPod))
	return admission.PatchResponseFromRaw(req.Object.Raw, marshaledPod)
}

func (a *PodWebhookMutate) InjectDecoder(d *admission.Decoder) error {
	a.decoder = d
	return nil
}


// 注释掉一开始生成的内容
// func (r *Pod) SetupWebhookWithManager(mgr ctrl.Manager) error {
// 	return ctrl.NewWebhookManagedBy(mgr).
// 		For(r).
// 		Complete()
// }

// // TODO(user): EDIT THIS FILE!  THIS IS SCAFFOLDING FOR YOU TO OWN!

// var _ webhook.Defaulter = &Pod{}

// // Default implements webhook.Defaulter so a webhook will be registered for the type
// func (r *Pod) Default() {
// 	podlog.Info("default", "name", r.Name)

// 	// TODO(user): fill in your defaulting logic.
// }

        修改api/v1/xxx_suite_test.go

        全部注释掉,替换一个简单的测试Function。这个测试也是有讲究的,有兴趣可以研究一下。

/*
Copyright 2023.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package v1

import (
	"fmt"
	"testing"
)

func TestFunc(t *testing.T) {
	// 打印
	fmt.Println("this is test function......")
}

        修改main.go文件:

import (
	......
    # 增加一个依赖包 
	v1 "k8s-operator/kubebuilder-webhook-demo/api/v1"
	......
)
......

// 注释掉
// if err = (&corev1.Pod{}).SetupWebhookWithManager(mgr); err != nil {
// 	setupLog.Error(err, "unable to create webhook", "webhook", "Pod")
// 	os.Exit(1)
// }

// 增加webhook注册
mgr.GetWebhookServer().Register("/mutate-core-v1-pod", &webhook.Admission{Handler: &v1.PodWebhookMutate{Client: mgr.GetClient()}})

......
图6 在main.go注册webhook endpoint

        修改Dockerfile

1.和上面一样,因为我们是创建Pod的Webhook,不需要自定义Controller,注释掉。

图7 注释Dockerfile中关于controller的内容

         修改Makefile文件

增加一个kind-load,方便将image上传到本地集群中

......
# local k8s cluster name
KUBE_CLUSTER = k8s-local-dev 
......
.PHONY: kind-load
kind-load: ## load the local image to the kind cluster
	kind load docker-image ${IMG} --name ${KUBE_CLUSTER}
......
图8 在Makefile增加kind-load命令

2.7.3.按照最新配置更新yaml

# 更新yaml,这里和之前main.go和xxx_webhook.go的注释有点关,生成的代码是依据注释实现的
make mainfests generate

        这一步比较重要,执行后会生成config/webhook/mainfests.yaml文件,切记执行

2.7.4.集群运行测试

2.7.4.1.修改Makefile文件

# 增加一个kind-load,方便将本地image上传到本地k8s集群中

......
# local k8s cluster name
KUBE_CLUSTER = k8s-local-dev 
......
.PHONY: kind-load
kind-load: ## load the local image to the kind cluster
    kind load docker-image ${IMG} --name ${KUBE_CLUSTER}
......

图9 增加kind-load,可以将image上传到kind创建的集群容器中

2.7.4.2.将应用部署到k8s集群上

以下是部署到集群的步骤:构建镜像、上传到集群容器中、部署

其中IMG是一个可以自行设置镜像名的变量,此处为:k8s-podwebhook-demo:1.0。

按如下命令执行后,即可在k8s集群中看到部署的CRD controller应用。

# 构建镜像(有时候会失败,可能是网络问题,多试几遍),IMG需要指定,不然后面部署还是有问题
make docker-build IMG=k8s-podwebhook-demo:1.0
# local镜像上传到Kind创建的k8s集群所在的所有node中(如果本地是)
make kind-load IMG=k8s-podwebhook-demo:1.0
# 部署controller
make deploy IMG=k8s-podwebhook-demo:1.0

        在这个过程中,bin/目录存在一些二进制的工具包,可以先删除,是之前make deploy时下载的,如果已存在,有可能会报错。

图10 bin目录应该要提前删除kustomize工具
图11 将webhook项目工程直接部署到本地k8s集群中
图12 在Lens上查看被部署到本地k8s集群的webhook应用
图13 在Lens上查看注册的MutatingAdmission实例

         这个MutatingAdmission的作用是注册一个endpoint,使得Pod在被创建后,往这个endpoint发送一个https请求(这也是为什么需要证书的原因)。事实上main.go中

// 增加webhook注册
mgr.GetWebhookServer().Register("/mutate-core-v1-pod", &webhook.Admission{Handler: &v1.PodWebhookMutate{Client: mgr.GetClient()}})

 这句就类似java controller,接受这个https的请求。

2.7.5.测试

2.7.5.1.准备测试Deployment的yaml配置

        这里需要说明,因为我们这里创建的是Pod Webhook,但是一般而言,我们不直接创建Pod,而是创建一个deployment,因为deployment最后也是会创建pod的。当然直接创建Pod也是可以的,这里创建一个pod-demo-ngnix.yaml文件去创建一个简单的pod,这个Pod只是一个基本的Ngnix镜像。

cat <<EOF >pod-demo-ngnix.yaml
apiVersion: v1
kind: Pod
metadata:
  name: pod-demo-ngnix
  labels:
    role: myrole
spec:
  containers:
    - name: web
      image: nginx
      ports:
        - name: web
          containerPort: 80
          protocol: TCP
EOF

2.7.5.2.部署这个Pod demo

# 部署这个pod demo实例
kubectl apply -f ./pod-demo-ngnix.yaml
图14 在创建pod的时候,webhook接受到了请求并在日志中体现

 2.7.5.3.停止测试

# 删除测试Pod
kubectl delete -f ./pod-demo-ngnix.yaml
# undeploy这个webhook
make undeploy

参考文章

8. kubebuilder 进阶: webhook - Mohuishou

使用kubebuilder开发kubernetes核心资源的webhook | 老 宋

调试运行中的 Pod | Kubernetes

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/929952.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

2023最新AI创作系统ChatGPT网站源码V2.6.0+详细图文搭建安装教程/GPT联网/支持ai绘画+Dall-E2绘画/支持MJ以图生图

一、AI系统 如何搭建部署AI创作ChatGPT系统呢&#xff1f;小编这里写一个详细图文教程吧&#xff01; SparkAi使用Nestjs和Vue3框架技术&#xff0c;持续集成AI能力到AIGC系统&#xff01; 程序核心功能 程序已支持ChatGPT3.5/4.0提问、AI绘画、Midjourney绘画&#xff08;…

Vue2向Vue3过度核心技术组件通信

目录 1 组件基础知识scoped解决样式冲突1.1 默认情况&#xff1a;1.2 代码演示1.3 scoped原理1.4 总结 2 组件基础知识data必须是一个函数2.1 data为什么要写成函数2.2 代码演示2.3 总结 3 组件通信3.1 什么是组件通信&#xff1f;3.2 组件之间如何通信3.3 组件关系分类3.4 通信…

leetcode 392. 判断子序列

2023.8.25 本题要判断子序列&#xff0c;可以使用动态规划来做&#xff0c;定义一个二维dp数组。 接下来就是常规的动态规划求解子序列的过程。 给出两种定义dp数组的方法。 二维bool型dp数组&#xff1a; class Solution { public:bool isSubsequence(string s, string t) …

升级Go 版本到 1.19及以上,Goland: file.Close() 报错: Unresolved reference ‘Close‘

错误截图 解决方法 File -> Settings -> Go -> Build Tags & Vendoring -> Custom tags -> 添加值 “unix” 原因 Go 1.19 引入了unix构建标签。因此&#xff0c;需要添加unix到自定义标签。 参考 https://blog.csdn.net/weixin_43940592/article/det…

VScode代码自动补全提示

VScode代码自动补全提示 打开设置 搜索 Suggest:Snippets Prevent Quick Suggestions &#xff0c;去掉勾选 CtrlShiftP打开setting.json文件&#xff0c;添加以下代码 "editor.suggest.snippetsPreventQuickSuggestions": false,"editor.quickSuggestions…

macOS - DOSbox

文章目录 关于 DOSbox安装使用启动设置启动盘、查看文件 debug 关于 DOSbox 官网&#xff1a; https://www.dosbox.com/文档&#xff1a;https://www.dosbox.com/wiki/Basic_Setup_and_Installation_of_DosBox下载&#xff1a; https://www.dosbox.com/download.php https://s…

Request对象和response对象

一、概念 request对象和response对象是通过Servlet容器&#xff08;如Tomcat&#xff09;自动创建并传递给Servlet的。 Servlet容器负责接收客户端的请求&#xff0c;并将请求信息封装到request对象中&#xff0c;然后将request对象传 递给相应的Servlet进行处理。类似地&…

改进YOLO系列:10.添加NAMAttention注意力机制

添加NAMAttention注意力机制 1. NAMAttention注意力机制论文2. NAMAttention注意力机制原理3. NAMAttention注意力机制的配置3.1common.py配置3.2yolo.py配置3.3yaml文件配置1. NAMAttention注意力机制论文 论文题目:NAM: Normalization-based Attention Module 论文…

软件设计师学习笔记4-寻址方式

目录 1.指令的基本概念 2.寻址方式 2.1寻址方式及其特点 2.2寻址方式图解 3.CISC和RISC 1.指令的基本概念 一条指令就是机器语言的一个语句&#xff0c;它是一组有意义的二进制代码&#xff0c;指令的基本格式为操作码字段地址码字段&#xff0c;其中操作码给出该指令的对…

pgadmin4树节点增删查(二)

十九&#xff0c;表 &#xff08;一&#xff09;查询 请求参数&#xff1a; gid1 sid1 did13799 scid2200pg模板&#xff1a; SELECT rel.oid, rel.relname AS name, rel.reltablespace AS spcoid,rel.relacl AS relacl_str,(CASE WHEN length(spc.spcname::text) > 0 T…

【LeetCode-中等题】238. 除自身以外数组的乘积

题目 题解一&#xff1a;暴力双指针—超时了 双指针暴力查找(需考虑begin end 和begin end i) 的情况 ----- 力扣示例超出时间限制 public int[] productExceptSelf(int[] nums) {int length nums.length;int begin 0;int end length -1;int i 0;int[] number new in…

基于python+pyqt实现opencv银行卡身份证等识别

效果展示 识别结果 查看处理过程 历史记录 完整演示视频&#xff1a; 无法粘贴视频........ 完整代码链接 视频和代码都已上传百度网盘&#xff0c;放在主页置顶文章

MATLAB图论合集(二)计算最小生成树

今天来介绍第二部分&#xff0c;图论中非常重要的知识点——最小生成树。作为数据结构的理论知识&#xff0c;Prim算法和克鲁斯卡尔算法的思想此处博主不详细介绍&#xff0c;建议在阅读本帖前熟练掌握。 对于无向带权图&#xff0c;在MATLAB中可以直接以邻接矩阵的方式创建出来…

研磨设计模式day11观察者模式

目录 场景 代码示例 定义 观察者模式的优缺点 本质 何时选用 简单变型-区别对待观察者 场景 我是一家报社&#xff0c;每当我发布一个新的报纸时&#xff0c;所有订阅我家报社的读者都可以接收到 代码示例 报纸对象 package day11观察者模式;import java.util.Observ…

stm32之DS18B20

DS18B20与stm32之间也是通过单总线进行数据的传输的。单总线协议在DHT11中已经介绍过。虽说这两者外设都是单总线&#xff0c;但时序电路却很不一样&#xff0c;DS18B20是更为麻烦一点的。 DS18B20 举例&#xff08;原码补码反码转换_原码反码补码转换_王小小鸭的博客-CSDN博客…

什么是计算机视觉,计算机视觉的主要任务及应用

目录 1. 什么是计算机视觉 2. 计算机视觉的主要任务及应用 2.1 图像分类 2.1.1 图像分类的主要流程 2.2 目标检测 2.2.1 目标检测的主要流程 2.3 图像分割 2.3.1 图像分割的主要流程 2.4 人脸识别 2.4.1 人脸识别的主要流程 对于我们人类来说&#xff0c;要想认出身边…

【80天学习完《深入理解计算机系统》】第十天 3.3 条件码寄存器【CF ZF SF OF】

专注 效率 记忆 预习 笔记 复习 做题 欢迎观看我的博客&#xff0c;如有问题交流&#xff0c;欢迎评论区留言&#xff0c;一定尽快回复&#xff01;&#xff08;大家可以去看我的专栏&#xff0c;是所有文章的目录&#xff09;   文章字体风格&#xff1a; 红色文字表示&#…

01.sqlite3学习——数据库概述

目录 重点概述总结 数据库标准介绍 什么是数据库&#xff1f; 数据库是如何存储数据的&#xff1f; 数据库是如何管理数据的&#xff1f; 数据库系统结构 常见关系型数据库管理系统 关系型数据库相关知识点 数据库与文件存储数据对比 重点概述总结 数据库可以理解为操…

串行FIR滤波器

串行 FIR 滤波器设计 串行设计&#xff0c;就是在 16 个时钟周期内对 16 个延时数据分时依次进行乘法、加法运算&#xff0c;然后在时钟驱动下输出滤波值。考虑到 FIR 滤波器系数的对称性&#xff0c;计算一个滤波输出值的周期可以减少到 8 个。串行设计时每个周期只进行一次乘…

网络安全(黑客)零基础自学

网络安全是什么&#xff1f; 网络安全&#xff0c;顾名思义&#xff0c;网络上的信息安全。 随着信息技术的飞速发展和网络边界的逐渐模糊&#xff0c;关键信息基础设施、重要数据和个人隐私都面临新的威胁和风险。 网络安全工程师要做的&#xff0c;就是保护网络上的信息安…