使用 docker buildx 构建跨平台 Go 镜像

news2024/11/27 12:33:25

目录

  1. 前提

  2. docker buildx

    1. 启用 Buildx

    2. builder 实例

    3. 构建驱动

  3. buildx 的跨平台构建策略

  4. 一次构建多个架构 Go 镜像实践

    1. 源代码和 Dockerfile

    2. 执行跨平台构建

    3. 验证构建结果

  5. 如何交叉编译 Golang 的 CGO 项目

    1. 准备交叉编译环境和依赖

    2. 交叉编译 CGO 示例

  6. 总结

  7. 参考链接​​​​​​

在不同操作系统和处理器架构上运行应用是很普遍的场景,因此为不同平台单独构建发布版本是一种常见做法。当我们用来开发应用的平台与部署的目标平台不同时,实现这一目标并不容易。例如在 x86 架构上开发一个应用程序并将其部署到 ARM 平台的机器上,通常需要准备 ARM 平台的基础设施用于开发和编译。

一次构建多处部署的镜像分发大幅提高了应用的交付效率,对于需要跨平台部署应用的场景,利用 docker buildx 构建跨平台的镜像也是一种快捷高效的解决方案。

前提

大部分镜像托管平台支持多平台镜像,这意味着镜像仓库中单个标签可以包含不同平台的多个镜像,以 docker hub 的 python 镜像仓库为例,3.9.6 这个标签就包含了 10 个不同系统和架构的镜像(平台 = 系统 + 架构):

通过 docker pull 或 docker run 拉取一个支持跨平台的镜像时,docker 会自动选择与当前运行平台相匹配的镜像。由于该特性的存在,在进行镜像的跨平台分发时,我们不需要对镜像的消费做任何处理,只需要关心镜像的生产,即如何构建跨平台的镜像。

docker buildx

默认的 docker build 命令无法完成跨平台构建任务,我们需要为 docker 命令行安装 buildx 插件扩展其功能。buildx 能够使用由 Moby BuildKit 提供的构建镜像额外特性,它能够创建多个 builder 实例,在多个节点并行地执行构建任务,以及跨平台构建。

启用 Buildx

macOS 或 Windows 系统的 Docker Desktop,以及 Linux 发行版通过 deb 或者 rpm 包所安装的 docker 内置了 buildx,不需要另行安装。

如果你的 docker 没有 buildx 命令,可以下载二进制包进行安装:

  1. 首先从 Docker buildx 项目的 release 页面找到适合自己平台的二进制文件。
  2. 下载二进制文件到本地并重命名为 docker-buildx,移动到 docker 的插件目录 ~/.docker/cli-plugins
  3. 向二进制文件授予可执行权限。

如果本地的 docker 版本高于 19.03,可以通过以下命令直接在本地构建并安装,这种方式更为方便:

$ export DOCKER_BUILDKIT=1
$ docker build --platform=local -o . git://github.com/docker/buildx
$ mkdir -p ~/.docker/cli-plugins
$ mv buildx ~/.docker/cli-plugins/docker-buildx

使用 buildx 进行构建的方法如下:

docker buildx build .

buildx 和 docker build 命令的使用体验基本一致,还支持 build 常用的选项如 -t-f等。

builder 实例

docker buildx 通过 builder 实例对象来管理构建配置和节点,命令行将构建任务发送至 builder 实例,再由 builder 指派给符合条件的节点执行。我们可以基于同一个 docker 服务程序创建多个 builder 实例,提供给不同的项目使用以隔离各个项目的配置,也可以为一组远程 docker 节点创建一个 builder 实例组成构建阵列,并在不同阵列之间快速切换。

使用 docker buildx create 命令可以创建 builder 实例,这将以当前使用的 docker 服务为节点创建一个新的 builder 实例。要使用一个远程节点,可以在创建示例时通过 DOCKER_HOST 环境变量指定远程端口或提前切换到远程节点的 docker context。下面以远程节点创建一个新的 builder 实例并通过命令行选项指定其驱动、目标平台和实例名称:

$ export DOCKER_HOST=tcp://10.10.150.66:2375
$ docker buildx create --driver docker-container --platform linux/amd64,linux/arm64 --name remote-builder
remote-builder

docker buildx ls 将列出所有可用的 builder 实例和实例中的节点:

$ docker buildx ls
NAME/NODE         DRIVER/ENDPOINT         STATUS   PLATFORMS
remote-builder    docker-container                 
  remote-builder0 tcp://10.10.150.66:2375 inactive linux/amd64*, linux/arm64*
default *         docker                           
  default         default                 running  linux/amd64, linux/386

实例创建之后可以继续向它添加新的节点,通过 docker buildx create 命令的 --append <node> 选项可将节点加入到 --name <builder> 选项指定的 builder 实例:

 $ docker buildx create --name default --append remote-builder0

docker buildx inspectdocker buildx stop 和 docker buildx rm 命令用于管理一个实例的生命周期。

docker buildx use <builder> 将切换到所指定的 builder 实例。

构建驱动

buildx 实例通过两种方式来执行构建任务,两种执行方式被称为使用不同的「驱动」:

  • docker 驱动:使用 Docker 服务程序中集成的 BuildKit 库执行构建。
  • docker-container 驱动:启动一个包含 BuildKit 的容器并在容器中执行构建。

docker 驱动无法使用一小部分 buildx 的特性(如在一次运行中同时构建多个平台镜像),此外在镜像的默认输出格式上也有所区别:docker 驱动默认将构建结果以 Docker 镜像格式直接输出到 docker 的镜像目录(通常是 /var/lib/overlay2),之后执行 docker images 命令可以列出所输出的镜像;而 docker container 则需要通过 --output 选项指定输出格式为镜像或其他格式。

为了一次性构建多个平台的镜像,下文将使用 docker container 驱动的 builder 实例。

buildx 的跨平台构建策略

根据构建节点和目标程序语言不同,buildx 支持以下三种跨平台构建策略:

  1. 通过 QEMU 的用户态模式创建轻量级的虚拟机,在虚拟机系统中构建镜像。
  2. 在一个 builder 实例中加入多个不同目标平台的节点,通过原生节点构建对应平台镜像。
  3. 分阶段构建并且交叉编译到不同的目标架构。

QEMU 通常用于模拟完整的操作系统,它还可以通过用户态模式运行:以 binfmt_misc 在宿主机系统中注册一个二进制转换处理程序,并在程序运行时动态翻译二进制文件,根据需要将系统调用从目标 CPU 架构转换为当前系统的 CPU 架构。最终的效果就像在一个虚拟机中运行目标 CPU 架构的二进制文件。Docker Desktop 内置了 QEMU 支持,其他满足运行要求的平台可通过以下方式安装:

$ docker run --privileged --rm tonistiigi/binfmt --install all

这种方式不需要对已有的 Dockerfile 做任何修改,实现的成本很低,但显而易见效率并不高。

将不同系统架构的原生节点添加到 builder 实例中可以为跨平台编译带来更好的支持,而且效率更高,但需要有足够的基础设施支持。

如果构建项目所使用的程序语言支持交叉编译(如 C 和 Go),可以利用 Dockerfile 提供的分阶段构建特性:首先在和构建节点相同的架构中编译出目标架构的二进制文件,再将这些二进制文件复制到目标架构的另一镜像中。下文会使用 Go 实现一个具体的示例。这种方式不需要额外的硬件,也能得到较好的性能,但只有特定编程语言能够实现。

一次构建多个架构 Go 镜像实践

源代码和 Dockerfile

下面将以一个简单的 Go 项目作为示例,假设示例程序文件 main.go 内容如下:

package main

import (
	"fmt"
	"runtime"
)

func main() {
	fmt.Println("Hello world!")
	fmt.Printf("Running in [%s] architecture.\n", runtime.GOARCH)
}

定义构建过程的 Dockerfile 如下:

FROM --platform=$BUILDPLATFORM golang:1.14 as builder

ARG TARGETARCH

WORKDIR /app
COPY main.go /app/main.go
RUN GOOS=linux GOARCH=$TARGETARCH go build -a -o output/main main.go

FROM alpine:latest
WORKDIR /root
COPY --from=builder /app/output/main .
CMD /root/main

构建过程分为两个阶段:

  • 在一阶段中,我们将拉取一个和当前构建节点相同平台的 golang 镜像,并使用 Go 的交叉编译特性将其编译为目标架构的二进制文件。
  • 然后拉取目标平台的 alpine 镜像,并将上一阶段的编译结果拷贝到镜像中。

执行跨平台构建

执行构建命令时,除了指定镜像名称,另外两个重要的选项是指定目标平台和输出格式。

docker buildx build 通过 --platform 选项指定构建的目标平台。Dockerfile 中的 FROM 指令如果没有设置 --platform 标志,就会以目标平台拉取基础镜像,最终生成的镜像也将属于目标平台。此外 Dockerfile 中可通过 BUILDPLATFORMTARGETPLATFORMBUILDARCH 和 TARGETARCH 等参数使用该选项的值。当使用 docker-container 驱动时,这个选项可以接受用逗号分隔的多个值作为输入以同时指定多个目标平台,所有平台的构建结果将合并为一个整体的镜像列表作为输出,因此无法直接输出为本地的 docker images 镜像。

docker buildx build 支持丰富的输出行为,通过--output=[PATH,-,type=TYPE[,KEY=VALUE] 选项可以指定构建结果的输出类型和路径等,常用的输出类型有以下几种:

  • local:构建结果将以文件系统格式写入 dest 指定的本地路径, 如 --output type=local,dest=./output
  • tar:构建结果将在打包后写入 dest 指定的本地路径。
  • oci:构建结果以 OCI 标准镜像格式写入 dest 指定的本地路径。
  • docker:构建结果以 Docker 标准镜像格式写入 dest 指定的本地路径或加载到 docker 的镜像库中。同时指定多个目标平台时无法使用该选项。
  • image:以镜像或者镜像列表输出,并支持 push=true 选项直接推送到远程仓库,同时指定多个目标平台时可使用该选项。
  • registry:type=image,push=true 的精简表示。

对本示例我们执行如下 docker buildx build 命令:

$ docker buildx build --platform linux/amd64,linux/arm64,linux/arm -t registry.cn-hangzhou.aliyuncs.com/waynerv/arch-demo -o type=registry .

该命令将在当前目录同时构建 linux/amd64、 linux/arm64 和 linux/arm 三种平台的镜像,并将输出结果直接推送到远程的阿里云镜像仓库中。

构建过程可拆解如下:

  1. docker 将构建上下文传输给 builder 实例。
  2. builder 为命令行 --platform 选项指定的每一个目标平台构建镜像,包括拉取基础镜像和执行构建步骤。
  3. 导出构建结果,镜像文件层被推送到远程仓库。
  4. 生成一个清单 JSON 文件,并将其作为镜像标签推送给远程仓库。

验证构建结果

运行结束后可以通过 docker buildx imagetools 探查已推送到远程仓库的镜像:

$ docker buildx imagetools inspect registry.cn-hangzhou.aliyuncs.com/waynerv/arch-demo:latest
Name:      registry.cn-hangzhou.aliyuncs.com/waynerv/arch-demo:latest
MediaType: application/vnd.docker.distribution.manifest.list.v2+json
Digest:    sha256:e2c3c5b330c19ac9d09f8aaccc40224f8673e12b88ff59cb68971c36b76e95ca
           
Manifests: 
  Name:      registry.cn-hangzhou.aliyuncs.com/waynerv/arch-demo:latest@sha256:cb6a7614ee3db03c8858e3680b1585f32a6fe3de9b371e37e25cf42a83f6e0ba
  MediaType: application/vnd.docker.distribution.manifest.v2+json
  Platform:  linux/amd64
             
  Name:      registry.cn-hangzhou.aliyuncs.com/waynerv/arch-demo:latest@sha256:034aa0077a452a6c2585f8b4969c7c85d5d2bf65f801fcc803a00d0879ce900e
  MediaType: application/vnd.docker.distribution.manifest.v2+json
  Platform:  linux/arm64
             
  Name:      registry.cn-hangzhou.aliyuncs.com/waynerv/arch-demo:latest@sha256:db0ee3a876fb789d2e733471385eef0a056f64ee12d9e7ef94e411469d054eb5
  MediaType: application/vnd.docker.distribution.manifest.v2+json
  Platform:  linux/arm/v7

最后在不同的平台以 latest 标签拉取并运行镜像,验证构建结果是否正确。 使用 Docker Desktop 时,其本身集成的虚拟化功能可以运行不同平台的镜像,可以直接以 sha256 值拉取镜像:

$ docker run --rm registry.cn-hangzhou.aliyuncs.com/waynerv/arch-demo:latest@sha256:cb6a7614ee3db03c8858e3680b1585f32a6fe3de9b371e37e25cf42a83f6e0ba
Hello world!
Running in [amd64] architecture.
$ docker run --rm registry.cn-hangzhou.aliyuncs.com/waynerv/arch-demo:latest@sha256:034aa0077a452a6c2585f8b4969c7c85d5d2bf65f801fcc803a00d0879ce900e
Hello world!
Running in [arm64] architecture.

如何交叉编译 Golang 的 CGO 项目

支持交叉编译到常见的操作系统和 CPU 架构是 Golang 的一大优势,但以上示例中的解决方案只适用于纯 Go 代码,如果项目中通过 cgo 调用了 C 代码,情况会变得更加复杂。

准备交叉编译环境和依赖

为了能够顺利编译 C 代码到目标平台,首先需要在编译环境中安装目标平台的 C 交叉编译器(通常基于 gcc),常用的 Linux 发行版会提供大部分平台的交叉编译器安装包,可以直接通过包管理器安装。

其次还需要安装目标平台的 C 标准库(通常标准库会作为交叉编译器的安装依赖,不需要单独安装),另外取决于你所调用的 C 代码的依赖关系,可能还需要安装一些额外的 C 依赖库(如 libopus-dev 之类)。

我们将使用 amd64 架构的 golang:1.14 官方镜像作为基础镜像执行编译,其使用的 Linux 发行版为 Debian。假设交叉编译的目标平台是 linux/arm64,则需要准备的交叉编译器为 gcc-aarch64-linux-gnu,C 标准库为 libc6-dev-arm64-cross,安装方式为:

$ apt-get update
$ apt-get install gcc-aarch64-linux-gnu

libc6-dev-arm64-cross 会同时被安装。

得益于 Debian 包管理器 dpkg 提供的多架构安装能力,假如我们的代码依赖 libopus-dev 等非标准库,可通过 <library>:<architecture> 的方式安装其 arm64 架构的安装包:

$ dpkg --add-architecture arm64
$ apt-get update
$ apt-get install -y libopus-dev:arm64

交叉编译 CGO 示例

假设有如下 cgo 的示例代码:

package main

/*
#include <stdlib.h>
*/
import "C"
import "fmt"

func Random() int {
    return int(C.random())
}

func Seed(i int) {
    C.srandom(C.uint(i))
}

func main()  {
    rand := Random()
    fmt.Printf("Hello %d\n", rand)
}

将使用的 Dockerfile 如下:

FROM --platform=$BUILDPLATFORM golang:1.14 as builder
ARG TARGETARCH
RUN apt-get update && apt-get install -y gcc-aarch64-linux-gnu
WORKDIR /app
COPY . /app/
RUN if [ "$TARGETARCH" = "arm64" ]; then CC=aarch64-linux-gnu-gcc && CC_FOR_TARGET=gcc-aarch64-linux-gnu; fi && \
  CGO_ENABLED=1 GOOS=linux GOARCH=$TARGETARCH CC=$CC CC_FOR_TARGET=$CC_FOR_TARGET go build -a -ldflags '-extldflags "-static"' -o /main main.go

Dockerfile 中通过 apt-get 安装了 gcc-aarch64-linux-gnu 作为交叉编译器,示例程序较为简单因此不需要额外的依赖库。在执行 go build 进行编译时,需要通过 CC 和 CC_FOR_TARGET 环境变量指定所使用的交叉编译器。

为了基于同一份 Dockerfile 执行多个目标平台的编译(假设目标架构只有 amd64/arm64),最下方的 RUN 指令使用了一个小技巧,通过 Bash 的条件判断语法来执行不同的编译命令:

  • 假如构建任务的目标平台是 arm64,则指定 CC 和 CC_FOR_TARGET 环境变量为已安装的交叉编译器(注意它们的值有所不同)。
  • 假如构建任务的目标平台是 amd64,则不指定交叉编译器相关的变量,此时将使用默认的 gcc 作为编译器。

最后使用 buildx 执行构建的命令如下:

$ docker buildx build --platform linux/amd64,linux/arm64 -t registry.cn-hangzhou.aliyuncs.com/waynerv/cgo-demo -o type=registry .

总结

有了 Buildx 插件的帮助,在缺少基础设施的情况下,我们也能使用 docker 方便地构建跨平台的应用镜像。

但默认通过 QEMU 虚拟化目标平台指令的方式有明显地性能瓶颈,如果编写应用的语言支持交叉编译,我们可以通过结合 buildx 和交叉编译获得更高的效率。

本文最后介绍了一种进阶场景的解决方案:如何对使用了 CGO 的 Golang 项目进行交叉编译,并给出了编译到 linux/arm64 平台的示例。

参考链接

  • Leverage multi-CPU architecture support
  • Docker Buildx
  • docker buildx build
  • C? Go? Cgo! - go.dev
  • Cross-Compiling Golang (CGO) Projects

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

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

相关文章

供水设备远程监控客户案例

一、客户介绍 客户积累多年的技术研发和工程运维经验&#xff0c;对传统的恒压供水工程所面临的维护难、维修难、运维效率低和能耗管控弱等诸多问题有深刻的体会&#xff0c;经过广泛调研&#xff0c;客户最终选择使用蓝蜂物联网的云平台和边缘计算产品对恒压供水设备和工程进行…

数据处理指令(一)—— 搬移指令MOV、MVN

数据处理指令指的是和数学运算、逻辑运算相关的指令&#xff0c;比如加减乘、与或非、赋值比较等 目录 1、MOV —— 直接搬移 (1) MOV 指令格式 (2) MOV生成指令的策略&#xff08;MOV的优点&#xff09; (3) MOV 只能搬移“立即数”的原因&#xff08;MOV的缺点&#x…

问卷设计一:问卷题目哪些有类型和注意要点?

问卷法常被人们应用于社会调查中&#xff0c;它能反馈出最真实的社会信息。所以&#xff0c;很多企业为了最大程度地了解市场&#xff0c;也经常使用问卷调查法进行研究。不过&#xff0c;想要发挥出问卷法的最大用处&#xff0c;前提是要将问卷设计规范并且可量化。 想要设计…

用ArkTs在鸿蒙系统上画一个世界杯海报

偶然看到了CSDN关于世界杯的征文活动&#xff1a; 用代码画一个足球&#xff1f; 哈哈很有意思&#xff01; 想了想&#xff0c;画一个自定义View&#xff08;足球&#xff09;&#xff0c;当然是使用Canvas了&#xff0c;但除了Canvas还有没有其它方法呢&#xff1f;那是必须…

c语言算数转换 操作符

【题目名称】下面代码的结果是&#xff1a;( b)#include <stdio.h> int main() {int a, b, c;a 5;c a;b c, c, a, a;//逗号表达式从左向右以此计算 表达式结果是最后一个表达式b a c; //a9 先算加后算加等printf("a %d b %d c %d\n:", a, b, c);retu…

【软件测试】工作瓶颈?测试的出路在哪?

目录&#xff1a;导读前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09;前言 3年软件测试经验&am…

【内网安全-隧道技术】SMB、ICMP、DNS隧道、SSH协议

目录 一、基础知识 二、隧道技术 1、简介&#xff1a; 2、SMB隧道 3、ICMP隧道 4、DNS隧道 5、SSH协议 6、控制上线-插件 一、基础知识 【内网安全-基础】基础知识、信息收集、工具https://blog.csdn.net/qq_53079406/article/details/128292587?spm1001.2014.3001.55…

Seata 术语

爬虫组件分析目录概述需求&#xff1a;设计思路实现思路分析1.TC (Transaction Coordinator) - 事务协调者2.TM (Transaction Manager) - 事务管理器3.RM参考资料和推荐阅读Survive by day and develop by night. talk for import biz , show your perfect code,full busy&…

[附源码]Nodejs计算机毕业设计基于的防疫隔离服务系统Express(程序+LW)

该项目含有源码、文档、程序、数据库、配套开发软件、软件安装教程。欢迎交流 项目运行 环境配置&#xff1a; Node.js Vscode Mysql5.7 HBuilderXNavicat11VueExpress。 项目技术&#xff1a; Express框架 Node.js Vue 等等组成&#xff0c;B/S模式 Vscode管理前后端分…

ruoyi-vue 集成electron详细步骤

刚使用ruoyi-vue开始集成electron的可以直接去这个地址下载源码 ruoyi-vue-electron: 使用ruoyi-vue集成electron 集成步骤&#xff1a; 1、在ruoyi-vue项目中安装electron相关插件 //进入ruoyi-ui 按顺序执行安装以下4个插件yarn add electron yarn add electron-devtools-…

5、英飞凌-AURIX-TC3X7: PWM实验之使用 GTM -TOM 实现

目录5、英飞凌-AURIX-TC3X7&#xff1a; PWM实验之使用 GTM -TOM 实现1、GTM -TOM简介2、TOM框图3、TOM全局通道控制--TGC0, TGC14、实验简介4.1、实验目的4.2、TC3X7 GTM 简介4.3、具体配置流程5、具体实现5.1、Cpu0_Main.c5.2、TOM_PWM.C5.3、TOM_PWM.h5、英飞凌-AURIX-TC3X7…

StyleGAN系列

1. Progressive Growing of GANs for Improved Quality, Stability, and Variation (PGGAN) 作者&#xff1a; Tero Karras Timo Aila Samuli Laine Jaakko Lehtinen 基于一个理论&#xff0c;高分辨率的图像相对于较小分辨率的图像&#xff0c;是更难train的&#xff0c;…

List<T>, IQueryable, IEnumerable 关系和区别

最近在修项目的历史代码&#xff0c;发现搞混了很多拓展方法&#xff0c;写一篇博客澄清一下。 概念需要&#xff1a;iqueryable不应该和ienumerable比而应该和ilist比&#xff0c;ienumerable是这两者的父接口。 问题&#xff1a;IQueryable, IEnumerable的&#xff1f; &…

Linux vi/vim

vi/vim 的使用 基本上 vi/vim 共分为三种模式&#xff0c;分别是命令模式&#xff08;Command mode&#xff09;&#xff0c;输入模式&#xff08;Insert mode&#xff09;和底线命令模式&#xff08;Last line mode&#xff09;。 这三种模式的作用分别是&#xff1a; 命令模…

数据分析可视化-FineReport 图表排序接口

1. 概述 1.1 应用场景 图表数据展示的顺序是由图表绑定的数据顺序决定的&#xff0c;一般建议在 SQL 中排好序再用图表实现。 但总有些场景不支持提前在 SQL 中排好序&#xff0c;或需要图表实现动态排序&#xff0c;此时可参考本文方法使用排序接口实现。 1.2 功能简介 Fi…

文本转语音免费 微软Azure官网

使用跨 140 种语言和变体的 400 种神经网络语音吸引全球受众。使用极具表现力和类似人类的声音&#xff0c;使文本阅读器和已启用语音的助理等方案栩栩如生。神经网络文本转语音支持多种朗读风格&#xff0c;包括新闻广播、客户服务、呼喊、耳语以及高兴、悲伤等情感。 地址 文…

数据结构---二叉堆

二叉堆二叉堆自我调整插入节点&#xff08;上浮&#xff09;删除节点(下沉)构建二叉堆(所有非叶子节点依次“下沉”)二叉堆本质上是一种完全二叉树&#xff0c;它分为两个类型。最大堆最小堆 最大堆的任何一个父节点的值&#xff0c;都大于或等于它左、右孩子\节点的值 最小堆…

【实测】windows安装部署go实录(超详细)

之前我的课程中&#xff0c;关于go语言的安装是主要展示了mac的&#xff0c;windows的就一笔带过了。 结果被我说着了&#xff08;可能在第一步直接被劝退&#xff09;&#xff0c;好多用windows的小伙伴部署go语言环境各种问题各种坑&#xff0c;网上教程看了个一知半解。没办…

网络工程毕业设计 SSM药品管理系统(源码+论文)

文章目录1 项目简介2 实现效果2.1 界面展示3 设计方案3.1 概述3.2 系统流程3.2.1 添加信息流程3.2.2 操作流程3.2.3删除信息流程3.3 系统结构设计4 项目获取1 项目简介 Hi&#xff0c;各位同学好呀&#xff0c;这里是M学姐&#xff01; 今天向大家分享一个今年(2022)最新完成…

域0day-(CVE-2022-33679)容易利用吗

前言 最近twitter上关于CVE应该CVE-2022-33679比较火了&#xff0c;但是资料也是比较少&#xff0c;下面来唠唠吧。 kerberos认证原理 先了解几个概念 认证服务(Authentication server&#xff09;:简称AS,认证客户端身份提供认证服务。 域控服务器(Domain Control&#x…