【Kubernetes① 基础】一、容器基础

news2024/11/23 3:55:46

目录

  • 一、进程
  • 二、隔离与限制
  • 三、容器镜像


一、进程

  1. 容器技术的兴起源于PaaS技术(平台即服务)的普及;
  2. Docker公司发布的Docker项目具有里程碑式的意义;
  3. Docker项目通过“容器镜像”解决了应用打包这个根本性难题(CloudFoundry)。

容器本身的价值非常有限,真正有价值的是容器编排
容器只是一种特殊的进程

  • 容器到底是怎么回事?

容器实际上就是一种沙盒技术,沙盒就是能够像集装箱一样把应用“装”起来,这样应用之间就会因为有了边界而不会相互干扰;被装进集装箱的应用也可以被方便地“搬来搬去”。这就是PaaS最理想的状态。

  • 边界的实现手段

假设有一个计算加法的小程序,输入来自一个文件,计算结果输出到另一文件中。计算机只认识0和1,因此最终这段程序会被翻译为二进制文件,再加上所需的数据(输入文件中),放在磁盘上,就等于一个程序,也叫代码的“可执行镜像”,然后就可在计算机上运行这个程序。运行过程如下:

  1. os从程序中发现输入数据保存在文件中,会将这些数据加载到内存中待命;
  2. os读到加法指令,指示CPU完成加法操作;
  3. CPU与内存协作进行加法计算,会使用寄存器存放数值、内存堆栈保存执行的命令和变量;同时计算机里还有被打开的文件,以及各种I/O设备在不断的调用中修改自己的状态。

因此,程序一旦被执行,就从磁盘上的二进制文件变成了由 {计算机上内存数据+寄存器的值+堆栈中的指令+被打开的文件+各种设备的状态信息} 组成的一个集合。
因此,进程的静态表现 = 存储在磁盘中;动态表现 = 运行起来变成计算机中数据和状态的总和。

容器的核心功能就是:通过约束和修改进程的动态表现,为其创造一个“边界”。对于Docker等大多数Linux容器来说,Croups技术是用来制造约束的主要手段;Namespace技术是用来修改进程视图的主要方法。

  • Namespace技术

假设我Linux上已拥有Docker,首先创建一个容器:

docker run -it gcc:9.2.0 /bin/bash
# 启动容器,在容器中执行命令/bin/bash,并为我分配一个终端来与这个容器交互

-it :告诉Docker在启动容器后为我们分配一个文本输入/输出环境(TTY),与容器的标准输入关联,这样就可以与Docker容器进行交互;
gcc:9.2.0: 我已拉取到Docker中的镜像文件;
在这里插入图片描述
/bin/bash:在Docker容器中运行的程序。
至此我的ubuntu变成了宿主机,容器在此宿主机上运行。再在容器中运行命令:ps
在这里插入图片描述
在容器外在运行ps命令:
在这里插入图片描述
可以看到,再Docker内最开始执行的是/bin/bash,因此他是容器内部的1号进程(PID=1),而在容器外部,他的PID不再是1。这就意味着容器中正在执行的这两个进程,已经被Docker隔离到了与宿主机完全不同的世界中。什么原理呢?

当我们在宿主机上运行一个/bin/bash程序,os会为其分配一个PID(如图5302),粗略地将/bin/bash理解为公司的第5302号员工,1号是CEO。现在我们想通过Docker在容器运行这个/bin/bash程序,这时,Docker会在这个第5302号员工入职时给他一个”障眼法“,让他永远看不到前面的5301位员工,因此他就会误以为自己是公司的第一位员工(对应容器内的PID=1)。
这种机制实际上就是对被隔离的应用的进程空间动了手脚,使这些进程只能看到重新计算过的PID(例如PID=1),实际上在宿主机中他还是第5302号进程。

这种技术就是Linux中的Namespace机制,他只是Linux创建进程的一个可选参数。如Linux中创建进程的系统调用(之一)是clone() ,这个系统调用会为我们创建一个新进程,并返回他的PID:

int pid = clone(main_function, stack_size, SIGCHLD, NULL);

而当我们使用clone()系统调用创建一个新进程时,可以在参数中指定CLONE_NEWPID参数:

int pid = clone(main_function, stack_size, SIGCHLD | CLONE_NEWPID, NULL);

此时这个新创建的进程会看见一个全新的进程空间,在此空间中,他的PID就是1,他既看不到宿主机中真正的进程空间,也看不到其他PID Namespace中的具体情况。而在真实的宿主机空间中,这个进程的PID是他的真实数值(比如5302)。
PID Namespace外,Linux还提供了Mount、UTS、IPC、Network、User这些Namespace。

这就是Linux容器实现的最基本原理。因此,Docker实际在创建容器进程时,指定了该进程所需要启用的一组Namespace参数,这样该容器只能看到当前Namespace所限定的资源、文件、设备、状态或配置了,而对于宿主机及其他不相关程序就完全不透明。

因此,容器实际上就是一种特殊的容器而已。

二、隔离与限制

虚拟机与容器均有“为进程划分一个独立的空间”思想。

  • 对比虚拟机与容器

在这里插入图片描述

虚拟机的工作原理中,Hypervisor的软件是虚拟机最主要的部分,他通过硬件虚拟化功能模拟出了运行一个操作系统所需要的各种硬件,如CPU、内存等,然后在这些虚拟的硬件上安装了一个客户操作系统,这样用户的应用进程就可以在这个虚拟机中运行了。Docker使用一个名为Docker引擎的软件替换了Hypervisor,Docker不严谨的也可称为是轻量级虚拟化技术。
但二者拥有本质不同:Hypervisor会创建实体虚拟机,并对应用的隔离环境负责;而Docker并不会真正的在宿主机中创建一个Docker容器,他帮用户启动的还是原来的应用进程,只不过为其加上了各种Namespace参数,因此真正对隔离环境负责的还是宿主机本身,甚至Docker可以去掉。因此对比图应该如下:
在这里插入图片描述
因此容器相较于虚拟机的好处:

  1. 使用虚拟化作为沙盒必须由Hypervisor创建一个真实存在的虚拟机,且里面需要运行一个完整的客户操作系统,因此带来了额外的资源消耗和占用。实验表明,一个与逆行CentOS的KVM在不做任何优化的情况下,虚拟机本身要占用100~200MB内存。而Docker使用Namespace作为隔离手段,不需要完整的客户操作系统,使得容器额外的资源占用几乎可忽略不计;
  2. 用户应用对宿主机操作系统的系统调用会被Hypervisor拦截和处理,又是一层性能消耗,尤其对计算资源、网络、磁盘I/O的损耗很大;容器化后的用户应用仍为宿主机上的普通进程,因此不产生性能损耗。

summary:敏捷,高性能

  • 隔离

有利就有弊:Linux Namespace最主要的问题:隔离的不彻底。由于容器只是宿主机上的特殊进程,因此容器间共用同一宿主机的操作内核,带来了一系列问题:

  1. 容器通过Mount Namespace挂载其他版本的操作系统文件有的会行不通,如Windows上运行Linux容器、低版本Linux宿主机上运行高版本Linux容器等。
  2. Linux内核中很多对象不能被Namespace化。例如时间,若在容器中使用settimeofday(2)系统调用修改时间,则整个宿主机时间会被随之修改,因此在容器中部署应用时需要考虑“什么能做、什么不能做”。尽管可以使用Seccomp技术对所有发起的系统调用进行过滤和甄别,但会拖累系统性能,同时也不知道要开启或禁用哪些系统调用。
  • 限制

隔离之后为什么要进行限制?以PID Namespace为例,虽然容器内的1号进程在“障眼法”下无法看到容器外的其他信息,但在宿主机上,他作为第5302号进程与其他所有进程间存在平等的竞争关系。这意味着虽然第5302号进程表面被隔离起来了,但他所能够使用到的资源(如CPU、内存等)可随时被宿主机上其他进程或容器占用,同时也可能自己用光资源。显然这作为一个沙盒不合理。

  • Cgroups

Linux Cgroups的主要作用是限制一个进程组能够使用的资源上限(包括CPU、内存、网络带宽等)。此外还可进行优先级设置、审计、挂起和恢复进程等。

Linux、中,Cgroups向用户暴露出来的操作接口是文件系统,他以文件和目录的形式组织在/sys/fs/cgroup路径下,使用如下命令可显示:

mount -t cgroup

在这里插入图片描述

如图所示,输出结果是一系列文件系统目录。/sys/fs/cgroup下有许多诸如cpu、memory等的子目录,也称子系统,这些都是这台机器当前可被Cgroups限制的资源种类。在子系统对应的资源种类下,可以看到这类资源具体可以被限制的方法。以CPU子系统为例:
在这里插入图片描述
可以注意输出中有cpu.cfs_quota_us、cpu.cfs_period_us等关键词,这两个参数组合使用可以限制进程长度在period一段时间内,只能分配到总量为quota的CPU时间。

这样的配置文件如何使用呢?(以CPU为例)

首先在对应的子系统下创建目录,这个目录称为一个控制组,操作系统会在新创建的目录下自动生成该子系统的资源限制文件。
在这里插入图片描述
然后运行一个死循环脚本(该程序的PID是3750),该进程将CPU占满(使用top命令查看)。
在这里插入图片描述
在这里插入图片描述
接下来查看demo_container目录下的文件quota,此时发现quota还没有任何限制(=-1),CPU的period默认是100ms(10000us)。
在这里插入图片描述
接下来,修改这些文件内容来设限:向quota文件写入20ms(20000us),这个操作意味着在每100ms(period)时间里被该控制组限制的进程只能使用20ms(quota)的CPU时间,即该进程只能使用到20%的CPU带宽。然后将该进程的PID写入tasks文件,如上设置即可生效。
注意命令执行过程为:

1. sudo -i
2. cd /sys/fs/cgroup/cpu/demo_container
3. echo 20000 > cpu.cfs_quota_us
4. cat cpu.cfs_quota_us
5. echo 3750 > tasks
6. cat tasks

不能直接echo,也不能sudo echo…,权限不够。
在这里插入图片描述
然后使用top命令查看cpu利用率下降到了20%。
在这里插入图片描述
我们自己创建的demo_container目录可以通过rmdir demo_container命令删除。

除了CPU子系统外,Cgroups的每一项子系统都有其独有的资源限制能力,如:

  • blkio(block I/O):为块设备限定I/O限制,一般用于磁盘等设备;
  • cpuset:为进程分配单独的CPU核以及对应的内存节点;
  • memory:为进程设定内存使用限制。
  • 等等

对于Docker等Linux容器来说,Cgroups只需在每个子系统下面为每个容器创建一个控制组(新建一个容器目录),启动容器之后,将这个容器的PID写入控制组的tasks文件即可。而为控制组中的资源文件赋值,通过docker run命令中的参数:

docker run -it --cpu-period=100000 --cpu-quota=20000 image_name /bin/bash # 以mysql镜像为例

然后查看Cgroups中该容器的控制组中资源配置文件信息:
在这里插入图片描述
左侧为容器内部文件系统信息,右侧为宿主机文件系统信息。可以发现,在容器内部的/sys/fs/cgroup/cpu子系统下没有其他目录,前面提到这是因为Namespace给他施了一个“障眼法”,使其只能看见自己沙盒内部的情况;而在宿主机的/sys/fs/cgroup/cpu子系统下新增了一个docker目录。进入这个docker目录,发现多了刚刚所创建的容器的控制组。
在这里插入图片描述
进入该容器的控制组,查看资源配置信息,与docker run命令中所指定的参数一致:这意味着,这个容器只能使用20%的CPU带宽。
在这里插入图片描述

  • 总结

一个正在运行的容器其实就是一个启用了多个Namespace的应用进程,这个进程所能够使用的资源受Cgroups配置的限制。因此,容器是一个单进程模型。因此用户的应用进程实际就是容器中PID=1的进程,也是其他后续所创建的所有进程的父进程,这意味着,一个容器中无法同时运行两个应用,除非找一个PID=1的程序来担任这两个进程的父进程(比如systemd或supervisord)。

与Namespace相似,Cgroups本身也有许多不完善之处,最典型的是/proc文件系统的问题。

/proc目录下存储的是记录当前内核运行状态的一系列特殊文件,用户可以通过访问这些文件查看系统以及当前正在运行的进程信息。如CPU使用情况、内存占用率等。这些文件也是top指令的主要数据来源。

若在容器中执行top命令会发现他显示的信息是宿主机中的信息,而非当前容器的数据。(目前已修正)
在这里插入图片描述

三、容器镜像

  • 容器中的进程看到的文件系统是如何的?

这是一个关于Mount Namespace的问题,容器中的应用进程理应看到一套完全独立的文件系统,这样他在自己的容器目录下进行操作(例如/tmp),就完全不会受宿主机及其他容器的影响。

真实情况呢?

用如下程序验证:

#define _GNU_SOURCE
#include <sys/mount.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <sched.h>
#include <signal.h>
#include <unistd.h>
#include <stdlib.h>

#define STACK_SIZE (1024 * 1024)
static char container_stack[STACK_SIZE];

char* const container_args[] = {
    "/bin/bash",
    NULL
};

int container_main(void *arg) {
    printf("Container - inside the container!\n");
    execv(container_args[0], container_args);
    printf("Something's wrong");
    
    return 1;
}

int main() {
    printf("Parent - start a container!\n");
    
    pid_t container_pid = clone(container_main, container_stack+STACK_SIZE, CLONE_NEWNS | SIGCHLD, NULL);
    printf("%d\n", container_pid);
    waitpid(container_pid, NULL, 0);
    
    printf("Parent - container stopped!\n");

    return 0;
}

编译运行:

1. gcc -o test_clone_func test_clone_func.c
2. ./test_clone_func

遇到的问题:
在这里插入图片描述
clone()函数返回的pid为-1,证明创建失败。查阅clone()参数使用发现,我们在函数中使用CLONE_NEWNS时需要管理员权限。
在这里插入图片描述
因此我们需要将第二步替换成如下:

2. sudo ./test_clone_func

这样就进入了这个“容器”中。在容器中执行ls命令,会发现/tmp目录与宿主机相同!
在这里插入图片描述
Monut Namespace修改的是容器进程对文件系统的“挂载点”的认知,即只有在“挂载”这个操作发生之后才能改变进程视图,在此之前会直接继承宿主机的各个挂载点。因此在创建新进程时除了要启用Mount Namespace外,还要告诉容器那些目录需要重新挂载(比如/tmp):

int container_main(void *arg) {
    printf("Container - inside the container!\n");
    mount("none", "/tmp", "tmpfs", 0, "");  # 以“tmpfs”内存盘格式重新挂载/tmp目录
    execv(container_args[0], container_args);
    printf("Something's wrong");
    
    return 1;
}

此时再查看容器中的/tmp文件,为空,意味挂载生效:
在这里插入图片描述
在这里插入图片描述

因此,Mount Namespace的使用与其他Namespace不同的是:对容器进程视图的修改一定要伴随挂载操作才能生效。

  • 如何实现容器看到的文件系统是一个隔离了的隔离环境,而不是继承宿主机的文件系统呢(容器镜像:rootfs)?

只需在容器启动之前重新挂载他的整个根目录“/”即可,由于Namespace的存在,这个挂载操作对宿主机并不可见。
在Linux操作系统中有一个chroot命令(change root file system),可以在shell中改变进程的根目录到指定位置。假设有一个$HOME/test目录,想把它作为/bin/bash的根目录:

# 创建test目录和几个lib文件夹
1. mkdir -p $HOME/test
2. mkdir -p $HOME/test/{bin,lib64,lib}  # 注意,之间一定不能有空格
3. cd $T
# 把bash命令复制到test目录下对应的bin文件夹中
4. cp -v /bin/{bash,ls} $HOME/test/bin
# 把bash命令所需要的so文件复制到test目录下对应的lib文件夹中
# 使用ldd命令查找so文件
5. T=$HOME/test
6. list="$(ldd /bin/ls | egrep -o '/lib.*\.[0-9]')"
7. for i in $list; do cp -v "$i" "${T}${i}"; done
# 执行chroot命令,将/bin/bash的根目录更改为$HOME/test
8. chroot $HOME/test /bin/bash
# 查看根目录是否被“修改”
9. ls /
# 此时发现输出内容是$HOME/test内容,而非宿主机。

Mount Namespace正是基于对chroot的改进才发明出的,也是第一个Namespace。

容器镜像:通常在容器根目录下挂载整个操作系统的文件系统(如Ubuntu 20.04的ISO),这个挂载在容器根目录上为容器进程提供隔离后执行环境的文件系统成为“容器镜像”,或rootfs(根文件系统)。

Docker项目最核心的原理:为待创建的用户进程:

  • 启用Linux Namespace配置;
  • 设置指定的Cgroups参数;
  • 切换进程的根目录(change root)

但rootfs只是一个操作系统所包含的目录、配置和文件,并不包括操作系统的内核。操作系统只有在开机启动时才会加载指定版本的内核镜像。同一台机器上的所有容器共享宿主机的操作系统内核,因此如果应用需要配置内核参数实际上会修改宿主机的,一经修改则对所有容器来说都是被修改过的。

由于rootfs的存在,容器拥有一重要特性:一致性。对于PaaS来说,由于云端与本地服务器环境不同,应用打包是一个极其麻烦的问题,而容器镜像(rootfs)将整个操作系统与应用一起打包,应用与他运行时所需的依赖都被封撞到了一起。(对于一个应用,操作系统本身才是他运行时所需要的最完整的依赖库)。

这种下沉到操作系统级别的运行环境的一致性,填平了应用在本地开发和远端执行环境之间难以逾越的鸿沟。
  • 新问题:难道每开发一次或升级现有的就要重复制作一次rootfs吗?

例如我用Ubuntu操作系统的ISO做了一个rootfs并安装了Java环境,来部署我的Java应用,我的同事在发布他的java应用是我希望直接使用我的rootfs而不是再重复一遍这个步骤。

因此Docker在镜像设计中引入了“层(layer)”概念,这些修改都基于旧的rootfs,其他修改以增量方式添加,所有人只需要维护一个相对于base rootfs修改的增量内容。用户制作镜像的每一步操作都会生成一个层,即增量rootfs。这种想法使用了UnionFS(Union file system)联合文件系统的能力:

UnionFS:将不同位置的目录联合挂载到同一目录下,且相同文件名的文件合并。

1. mkdir A B C
2. touch ./A/a.txt ./A/common.txt ./B/b.txt ./B/common.txt
3. #向./A/common.txt写入"hello A",./B/common.txt写入"hello B"
# 通过联合挂载将A B两个目录挂载到同一目录C上
4. sudo mount -t aufs -o dirs=./A:./B none ./C

在这里插入图片描述
在这里插入图片描述

此时如果在目录C中对a.txt b.txt commom.txt做修改,也会在对应目录A B中生效。
在这里插入图片描述
若想取消挂载:

sudo umount A B C

在这里插入图片描述

那对于相同文件名且内容也相同的呢?将./A/common.txt与./B/common.txt内容都修改为"hello world"后在挂载到C上,再对./C/common.txt做修改:
在这里插入图片描述
同上,对于相同文件,只有A目录下的文件被修改了,说明默认是A文件夹下的。
在这里插入图片描述
目前docker支持的联合文件系统有很多种,包括:AUFS、overlay、overlay2、DeviceMapper、VSF等。查看本机Docker所使用的UnionFS:例如我的是overlay2。

docker info

在这里插入图片描述

  • 容器镜像(rootfs)

容器的rootfs由如下三部分组成(以ubuntu镜像为例):
在这里插入图片描述

  1. 只读层

挂载方式为readonly+whiteout,这些层都以增量的方式包含了镜像的一部分。

  1. 可读可写层

容器rootfs的最上面一层,挂载方式为read write,写入文件之前,这个目录是空的,一旦容器有了修改操作,修改的内容就会以增量的方式出现在该层中。对于删除操作会在可读可写层生成一个whiteout文件,把只读层文件内容“遮挡”起来。如删除只读层中的一个foo文件,这个操作实际上是在可读可写层创建一个.wh.foo文件,对应于只读层ro+wh的挂载方式。

对于修改后的容器,可使用docker commit和push指令保存这个修改后的可读可写层,而原先只读层的内容不会发生任何改变。

  1. Init层

这是一个以-init结尾的层,存在于只读层和可读可写层之间,是由Docker项目单独生成的一个内部层,用来存放/etc/hosts、/etc/resolv.conf等信息。这些文件本来属于只读层的一部分,但是用户在启动容器时需要写入一些指定的值(比如hostname等),且这些修改只对当前容器有效,并不希望在docker commit时提交这些信息,因此设立一个Init层,单独挂载这些文件的修改。

docker镜像相同的层间可以共享
  • Docker Volume(数据卷)

宿主机如何获取容器进程中新建的文件?容器中的进程怎么才能访问到宿主机上的文件和目录?

Volume机制允许将宿主机上的指定目录或文件挂载到容器中进行读取和修改。

docker run -v /test ...

在宿主机上创建一个临时目录/var/lib/docker/volumes/[VOLUME_ID]/_data,并将它挂载到容器的/test目录上。

docker run -v /home:/test

直接将宿主机的/home目录挂载到容器的/test目录上。

原理是什么?当容器进程被创建后,尽管开启了Mount Namespace,但在执行chroot(或pivot_root)之前容器进程可以看到宿主机上的整个文件系统,因此只需在容器rootfs准备好后chroot执行之前,将指定的宿主机目录挂载到指定的容器目录在宿主机上对应的目录上(具体路径参照overlay2原理)即可。由于挂载操作时容器已经创建,即Mount Namespace已经开启,因此这个挂载事件只对容器可见,宿主机看不到容器内部的这个挂载点。这就是绑定挂载。实际上就是一个inode替换过程。

这里的容器进程是指Docker创建的一个容器初始化进程(dockerinit),而非应用进程(ENTRYPOINT+CMD)。dockerinit会负责完成根目录的准备、挂载设备和目录、配置hostname等一系列需要在容器内进行的初始化操作,最后它通过execv()系统调用,让应用进程取代自己成为容器中PID=1的进程。

绑定挂载(bind mount):将一个目录或文件而非整个设备挂载到指定目录上,在挂载点上进行的任何操作只发生在被挂载的目录或文件上,原挂载点的内容会被隐藏起来且不受影响。(例如对容器/test目录的实际操作会发生在宿主机/home上,而原/test内容不会被影响。)

在这里插入图片描述
容器的/test目录挂载在rootfs的可读可写层,但不会被docker commit提交。(因为docker commit发生在宿主机空间,而该挂载操作对宿主机不可见,始终以为容器/test目录对应在宿主机上的路径始终为空。但新建目录不是挂载操作,因此commit的镜像中会多出一个/test空目录。)

参考书籍:《深入剖析Kubernetes》 张磊著。

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

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

相关文章

大模型还能让我们望梅止渴多久?

大模型梦碎的时间点似乎越来越近。过去一周&#xff0c;有关人工智能的消息糟糕多于积极。 周初&#xff0c;诺贝尔物理学奖和化学奖接连砸向时下正热的人工智能领域。这些奖项出人意料且鼓舞人心&#xff0c;意味着人工智能的确已经根本性地改变了我们生活和科学体系的方方面…

个人用数据挖掘笔记(待补充)

文章目录 零、复习事前准备一、绪论期末主观题 二、数据仓库&OLAP理论数据仓库数据仓库多维建模概念分层&#xff08;把底层概念映射到更高层、更一般的概念&#xff09;维度分层数值分层 建模方式数据立方体组成星形模型&#xff08;Star schema&#xff09;雪花模型&…

2024 kali系统2024版本,可视化界面汉化教程(需要命令行更改),英文版切换为中文版,基于Debian创建的kali虚拟机

我的界面如下所示 1. 安装 locales sudo apt install locales 2. 生成中文语言环境 sudo locale-gen zh_CN.UTF-8 如果你希望安装繁体中文&#xff0c;可以加入&#xff1a; sudo locale-gen zh_TW.UTF-8 3. 修改 /etc/default/locale 文件 确保有以下内容 LANGzh_CN.UT…

关于学生宿舍一进五出智能模块电表的功能介绍

一进五出学生宿舍智能模块电表石家庄光大远通电气有限公司精心打造的五进一出宿舍智能模块电表&#xff0c;正以其卓越之姿&#xff0c;引领着校园生活的智能化变革。这不仅仅是一块电表&#xff0c;它是智慧校园的守护者&#xff0c;专为新建或焕新的学生公寓量身定制&#xf…

ZStack ZROP首个商用版本发布,打造云的可持续发展框架

经过长时间的研发和测试&#xff0c;ZStack ZROP IT服务中台V4.2.0版本正式发布。ZROP 是针对ZStack全系列产品运营、运维、一体化的自研平台。作为第一个商用版本&#xff0c;ZROP V4.2.0支持包含ZStack Cloud、ZStack Cube、ZStack ZStone、ZStack Zaku、ZStack Edge、ZStack…

【已解决】HarmonyOS NEXT / DevEco Studio项目错误:ArkTS:ERROR Failed to execute es2abc

开发环境 操作系统&#xff1a; Mac mini M1、MacOS 14.2.1IDE&#xff1a;DevEco Studio NEXT Developer Beta1&#xff0c;Build Version: 5.0.3.403compatibleSdkVersion&#xff1a;5.0.0(12) 问题描述 在执行完“Clean Project”之后重新运行项目&#xff0c;出现错误&…

JavaScript 中三点运算符的应用:函数参数传参与扩展运算符详解

目录 非 VIP 用户可前往公众号“前端基地”进行免费阅读 函数参数传参 替代arguments 作为形参参数的位置限制 利用对象解构与扩展运算符提取参数对象属性 扩展运算符 数组连接 数组克隆 对象合并 对象克隆 非 VIP 用户可前往公众号“前端基地”进行免费阅读 函数参数…

通过PyTorch 手写数字识别 入门神经网络 详细讲解

通过PyTorch 手写数字识别 入门神经网络 数据集 MNIST数据集中有手写数字图片7万张&#xff0c;划分训练集6万张&#xff0c;划分测试集1万张。 每张图片都会有一张标签&#xff0c;也就是代表着图片的真实值&#xff08;真实含义&#xff09;。 概念 计算机是如何读取图片的…

鸿蒙开发案例:记忆翻牌

【游戏简介】 记忆翻牌游戏是一种经典的益智游戏&#xff0c;玩家需要翻开隐藏的卡片&#xff0c;找出所有成对的图案。每翻开一对卡片&#xff0c;如果图案相同&#xff0c;则这对卡片会永久显示出来&#xff0c;否则会在一段时间后自动翻回背面。游戏的目标是在尽可能短的时…

LabVIEW提高开发效率技巧----跨平台开发

在如今的多平台环境下&#xff0c;开发者常常面临不同操作系统的需求&#xff0c;如Windows、Linux和RT&#xff08;实时&#xff09;系统等。而LabVIEW作为一种强大的开发工具&#xff0c;提供了支持跨平台开发的能力&#xff0c;但要使其无缝迁移&#xff0c;开发者需要掌握一…

干货分享 | 同星多设备间的时间戳同步机制TSync功能与使用

随着汽车网络测试的通道数量不断增加&#xff0c;时常需要多个同星设备同时连接在同一台电脑的同一个TSMaster应用程序&#xff0c;并进行多设备同时执行CAN报文收发和记录等功能&#xff0c;必然有多设备之间的时间戳同步以及设备与电脑上操作系统的时间同步的要求。 为了满足…

5G 双卡双通演进

█ 双卡技术的演进历程 前面我有提到&#xff0c;世界上第一台双卡手机&#xff0c;诞生于 2004 年。 之所以会有双卡手机的出现&#xff0c;和当时特殊的历史背景有关。那一时期&#xff0c;中国大陆市场只有两家移动通信运营商&#xff0c;分别是中国移动和中国联通。中国移…

轻松入门:Maven核心功能详解

White graces&#xff1a;个人主页 &#x1f649;专栏推荐:Java入门知识&#x1f649; ⛳️点赞 ☀️收藏⭐️关注&#x1f4ac;卑微小博主&#x1f64f; ⛳️点赞 ☀️收藏⭐️关注&#x1f4ac;卑微小博主&#x1f64f; 目录 Maven Maven核心功能 1. 项目构建 2. 依赖管…

超材料光子晶体和禁带分析实例_CST电磁仿真教程

光子晶体是由周期性排列的不同折射率的介质制造的光学结构&#xff0c;可被视为广义超材料metamaterial的一种。本期我们演示设计一个基于光频能带(PBG,photonics band gap) 的二维光子晶体波导&#xff0c;能带分析方法也可适用于微波波段&#xff08;EBG,electromagetic band…

QT事件与网络通信

闹钟 头文件 #ifndef MAINWINDOW_H #define MAINWINDOW_H#include <QMainWindow> #include <QTimer> #include <QTextToSpeech> // 添加此行以引入QTextToSpeech类QT_BEGIN_NAMESPACE namespace Ui { class MainWindow; } QT_END_NAMESPACEclass MainWin…

通信接入技术

一、xDSL 1、xDSL&#xff1a;利用电话线中的高频信息传输数据&#xff0c;高频信号损耗大&#xff0c;容易受噪声干扰。【速率越高&#xff0c;传输距离越近】 1.1 ADSL虚拟拨号&#xff1a;采用专门的协议PPPover Ethernet&#xff0c;拨号后直接由验证服务器进行检验&#…

免费版视频压缩软件:让视频处理更便捷

现在不少人已经习惯通过视频来记录生活、传播信息和进行娱乐的重要方式。但是由于设备大家现在录制的文件都会比较大&#xff0c;这时候就比较需要一些缩小视频的工具了。今天我们一起来探讨视频压缩软件免费版来为我们带来的生动世界。 1.Foxit视频压缩大师 链接直达&#x…

【论文笔记】Adversarial Diffusion Distillation

Abstract 本文提出了一种新的训练方法&#xff0c;在保持较高图像质量的前提下&#xff0c;仅用1~4步就能有效地对大规模传统图像扩散模型进行采样&#xff0c;使用分数蒸馏(score distillation)&#xff0c;来利用大规模现成的图像扩散模型作为教师信号&#xff0c;并结合对抗…

CVE-2022-26965靶机渗透

​ 开启环境 ​ ​ 进入环境 ​ ​ 使用弱口令admin登录 ​ ​ 利用cms主题构造木马 ​ 需要将主题中的info.php文件修改&#xff0c;再打包成zip再上传&#xff0c;通过网络搜索找到Github中的Pluck CMS&#xff0c;进入后随便下载任一主题 https://github.com/sear…

解锁编程的力量:SPL的学习之旅

SPL 一、前言二、集算器应用场景三、下载四、集算器的基本使用 一、前言 一种面向结构化数据的程序计算语言 集算器又称&#xff1a;SPL&#xff08;Structured Process Language&#xff09; 敏捷计算是集算器的主要特征 二、集算器应用场景 数据准备&#xff08;跑批&…