Docker的深入浅出
目录
Docker引擎
Docker镜像 (镜像由多个层组成,每层叠加之后,从外部看来就如一个独立的对象。镜像内部是一个精简的操作系统(OS),同时还包含应用运行所必须的文件和依赖包)
Docker容器
应用容器化--Docker化
最佳实践
Docker Compose 初识 (python工具)--> 一个声明式的配置文件YAML描述
Docker Swarm --> 安全集群、编排引擎
Docker网络
卷
Docker Stack
安全
容器为什么出现
容器的作用
容器的应用场景
虚拟机的不足: OS的认证,OS占用额外的CPU、RAM和存储,启动较慢并且可移植性较差
容器的运行不会独占操作系统。实际上,运行在相同宿主机上的容器是共享一个操作系统的,这样就能够节省大量的系统资源。容器同时还能节省大量花费在许可证上的开销,以及为OS打补丁等运维成本。
对容器发展影响比较大的技术包括内核命名空间(Kernel Namespace)、控制组(Control Group)、联合文件系统(Union File System),当然更少不了Docker。
容器技术很早就有了,只是Docker的出现让大众所接受
运行中的容器共享宿主机的内核。这意味着一个基于Windows的容器化应用在Linux主机上是无法运行的。但现在已经成为可能。
Kubernetes: Kubernetes是保证容器部署和运行的软件体系中很重要的一部分
CRI能够帮助Kubernetes实现将运行时环境从Docker快速替换为其他容器运行时
Docker用于创建、管理和编排容器。 -- 旧金山
Docker引擎是用于运行和编排容器的基础设施工具。
GitHub上的docker/docker库也被转移到了moby/moby,并且拥有了项目自己的Logo。Logo
Moby项目的目标是基于开源的方式,发展成为Docker上游,并将Docker拆分为更多的模块化组件。
许多Docker内置的组件都可以替换为第三方的组件。良性的竞争是创新之母
OCI是一个旨在对容器基础架构中的基础组件进行标准化的管理委员会。
Docker的安装目前很方便,此处不进行笔记记录。
Docker的更新大致步骤如下:
需要重视升级操作的每个前置条件,包括确保容器配置了正确的重启策略;在Swarm Mode模式下使用服务时,需要确保正确配置了draining node。当完成了上述前置条件的检查之后,可以通过如下步骤完成升级操作。
(1)停止Docker守护程序。
(2)移除旧版本Docker。
(3)安装新版本Docker。
(4)配置新版本的Docker为开机自启动。
(5)确保容器重启成功。
Docker在Linux底层支持几种不同的存储驱动的具体实现,每一种实现方式都采用不同方法实现了镜像层和写时复制。虽然底层实现的差异不影响用户与Docker之间的交互,但是对Docker的性能和稳定性至关重要。
注意: 如果读者修改了正在运行Docker主机的存储引擎类型,则现有的镜像和容器在重启之后将不可用,这是因为每种存储驱动在主机上存储镜像层的位置是不同的。切换到原来的存储驱动,之前的镜像和容器就可以继续使用了。
如果读者希望在切换存储引擎之后还能够继续使用之前的镜像和容器,需要将镜像保存为Docker格式,上传到某个镜像仓库,修改本地Docker存储引擎并重启,之后从镜像仓库将镜像拉取到本地,最后重启容器。
Docker存储驱动的选择
在Linux上,Docker可选择的一些存储驱动包括AUFS(最原始也是最老的)、Overlay2(*)、Device Mapper、Btrfs和ZFS。
Device Mapper配置: 为了达到Device Mapper在生产环境中的最佳性能,需要将底层实现修改为direct-lvm模式。这种模式下通过使用基于裸块设备(Raw Block Device)的LVM精简池(LVM thin pool)来获取更好的性能。
运维视角: 下载镜像、运行新的容器、登录新容器、在容器内运行命令,以及销毁容器
开发视角: Dockerfile,将应用容器化,并在容器中运行它们
通过docker version 来确认客户端和服务端是否都已经成功运行,并且可以互相通信
镜像: 将Docker镜像理解为一个包含了OS文件系统和应用的对象会很有帮助
在Docker主机上运行docker image ls命令
docker container run 来启动容器
-it 参数会将Shell切换到容器终端。
按Ctrl-PQ组合键,可以在退出容器的同时还保持容器运行。这样Shell就会返回到Docker主机终端。可以通过查看Shell提示符来确认。 (依次按P 然后按Q键)
docker container exec 重新进入容器内部
使用stop和rm , 分别停止和移除已建立的容器
docker ps -a 和 docker container ls -a 应该是等价的,列出所有的容器包括未运行的
开发---- Dockerfile 并将其容器化
基于Dockerfile构建新的镜像
如果自动拉取有问题,可以手动先执行docker pull 下来基础的镜像
Docker引擎
基于开放容器计划(OCI)相关标准的要求,Docker引擎采用了模块化的设计原则,其组件是可替换的。
总体逻辑的组成
Docker首次发布时,Docker引擎由两个核心组件构成:LXC和Docker daemon。
Docker daemon是单一的二进制文件,包含诸如Docker客户端、Docker API、容器运行时、镜像构建等。
LXC提供了对诸如命名空间(Namespace)和控制组(CGroup)等基础工具的操作能力,它们是基于Linux内核的容器虚拟化技术。
早期的Docker架构
Docker公司开发了名为Libcontainer的自研工具,用于替代LXC。Libcontainer的目标是成为与平台无关的工具,可基于不同内核为Docker上层提供必要的容器交互功能。
在Docker 0.9版本中,Libcontainer取代LXC成为默认的执行驱动。
然后进行拆解Docker daemon,将其模块化,目的是小而专的工具可以组装为大型工具。
OCI制定相关的标准。
runc: 是OCI容器运行时规范的参考实现。创建容器,这一点它非常拿手,速度很快。直接下载它或基于源码编译二进制文件,即可拥有一个全功能的runc。但它只是一个基础工具,并不提供类似Docker引擎所拥有的丰富功能。
containerd: Docker引擎技术栈中,containerd位于daemon和runc所在的OCI层之间。Kubernetes也可以通过cri-containerd使用containerd。如今containerd还能够完成一些除容器生命周期管理之外的操作。不过,所有的额外功能都是模块化的、可选的,便于自行选择所需功能。
daemon使用一种CRUD风格的API,通过gRPC与containerd进行通信。
虽然名叫containerd,但是它并不负责创建容器,而是指挥runc去做。整个流程如下所示
在旧模型中,所有容器运行时的逻辑都在daemon中实现,启动和停止daemon会导致宿主机上所有运行中的容器被杀掉。将所有的用于启动、管理容器的逻辑和代码从daemon中移除,意味着容器运行时与Docker daemon是解耦的,有时称之为“无守护进程的容器(daemonless container)。Docker daemon的维护和升级工作不会影响到运行中的容器。
shim组件
shim是实现无daemon的容器不可或缺的工具。
一旦容器进程的父进程runc退出,相关联的containerd-shim进程就会成为容器的父进程。作为容器的父进程
保持所有STDIN和STDOUT流是开启状态,从而当daemon重启的时候,容器不会因为管道(pipe)的关闭而终止。
将容器的退出状态反馈给daemon。
Docker镜像 (镜像由多个层组成,每层叠加之后,从外部看来就如一个独立的对象。镜像内部是一个精简的操作系统(OS),同时还包含应用运行所必须的文件和依赖包)
拉取操作会将镜像下载到本地Docker主机,读者可以使用该镜像启动一个或者多个容器。
镜像与容器的关系
在镜像上启动的容器全部停止之前,镜像是无法被删除的。镜像中还不包含内核——容器都是共享所在Docker主机的内核。容器仅包含必要的操作系统。
Windows镜像要远大于Linux镜像,镜像中分层也更多。
镜像存储的背景知识
镜像仓库 官方 Docker Hub
Docker命令行是通过镜像名字和标签来定位的
从官方仓库拉取镜像时,格式 docker image pull <repository>:<tag>
例:
$ docker image pull mongo:3.3.11 //该命令会从官方Mongo库拉取标签为3.3.11的镜像
$ docker image pull redis:latest //该命令会从官方Redis库拉取标签为latest的镜像
如果不加标签,就是拉取latest的版本,但不意味着是最新的,并且使用latest标签时需要谨慎。latest是一个非强制标签,不保证指向仓库中最新的镜像!
如果希望从第三方镜像仓库服务获取镜像(非Docker Hub),则需要在镜像仓库名称前加上第三方镜像仓库服务的DNS名称。
镜像标签: 一个镜像可以根据用户需要设置多个标签。在docker image pull命令中指定-a参数来拉取仓库中的全部镜像。如果发现标签指向了相同的IMAGE ID,这意味着这两个标签属于相同的镜像。
Docker提供--filter参数来过滤docker image ls命令返回的镜像列表内容
那些没有标签的镜像被称为悬虚镜像,在列表中展示为<none>:<none>。通常出现这种情况,是因为构建了一个新镜像,然后为该镜像打了一个已经存在的标签。
可以通过docker image prune命令移除全部的悬虚镜像。如果添加了-a参数,Docker会额外移除没有被使用的镜像(那些没有被任何容器使用的镜像)
dangling:可以指定true或者false,仅返回悬虚镜像(true),或者非悬虚镜像(false)。
before:需要镜像名称或者ID作为参数,返回在指定镜像之前被创建的全部镜像。
since:与before类似,不过返回的是指定镜像之后创建的全部镜像。
label:根据标注(label)的名称或者值,对镜像进行过滤。docker image ls命令输出中不显示标注内容。
其他的过滤方式可以使用reference。
应用:
只显示官方镜像: $ docker search alpine --filter "is-official=true"
只显示自动创建的仓库: $ docker search alpine --filter "is-automated=true"
搜索: docker search命令允许通过CLI的方式搜索Docker Hub。读者可以通过“NAME”字段的内容进行匹配,并且基于返回内容中任意列的值进行过滤。 ** 默认情况下,Docker只返回25行结果。但是,读者可以指定--limit参数来增加返回内容行数,最多为100行。
镜像的组成:
除了在pull的过程中可以查看镜像的分层,使用docker image inspect 命令可以查看镜像的分层
注意: docker history命令显示了镜像的构建历史记录,但其并不是严格意义上的镜像分层。例如,有些Dockerfile中的指令并不会创建新的镜像层。比如ENV、EXPOSE、CMD以及ENTRY- POINT。不过,这些命令会在镜像中添加元数据。
原理: 所有的Docker镜像都起始于一个基础镜像层,当进行修改或增加新的内容时,就会在当前镜像层之上,创建新的镜像层。例如:
上层镜像层中的文件覆盖了底层镜像层中的文件。这样就使得文件的更新版本作为一个新镜像层添加到镜像当中。例如:
Docker通过存储引擎(新版本采用快照机制)的方式来实现镜像层堆栈,并保证多镜像层对外展示为统一的文件系统。Linux上可用的存储引擎有AUFS、Overlay2、Device Mapper、Btrfs以及ZFS。
共享镜像层: 多个镜像之间可以并且确实会共享镜像层。这样可以有效节省空间并提升性能。
如果修复前和修复后的镜像标签是相同的,就无法区分出新旧,那么需要使用镜像摘要(散列值),因为散列值是基于内容的,内容变更意味着摘要一定会改变。只需要在docker image ls命令之后添加--digests参数即可在本地查看镜像摘要。
如果使用摘要值进行拉取,可以保证准确拉取。
镜像层才是实际数据存储的地方,镜像层之间是完全独立的。镜像的唯一标识是一个加密ID,即配置对象本身的散列值。每个镜像层同时会包含一个分发散列值(Distribution Hash)。这是一个压缩版镜像的散列值,当从镜像仓库服务拉取或者推送镜像的时候,其中就包含了分发散列值,该散列值会用于校验拉取的镜像是否被篡改过。
多架构镜像: 一个镜像标签之下可以支持多个平台和架构。镜像仓库服务API支持两种重要的结构:Manifest列表(新)和Manifest。
某些软件也并非跨平台的。在这个前提下,Manifest列表是可选的——在没有Manifest列表的情况下,镜像仓库服务会返回普通的Manifest。
通过docker image rm命令从Docker主机删除该镜像。如果某个镜像层被多个镜像共享,那只有当全部依赖该镜像层的镜像都被删除后,该镜像层才会被删除。先停止并删除基于该镜像的容器,然后才能删除该镜像。
删除某主机上的全部镜像: $ docker image rm $(docker image ls -q) -f
Docker容器
容器是镜像的运行时实例。虚拟机和容器最大的区别是容器更快并且更轻量级——与虚拟机运行在完整的操作系统之上相比,容器会共享其所在主机的操作系统/内核。
启动容器的简便方式是使用docker container run命令。该命令可以携带很多参数,其基础的格式docker container run <image> <app>。-it参数可以将当前终端连接到容器的Shell终端之上。
容器与虚拟机
从更高层面上来讲,Hypervisor是硬件虚拟化(Hardware Virtualization)——Hypervisor将硬件物理资源划分为虚拟资源;另外,容器是操作系统虚拟化(OS Virtualization)——容器将系统资源划分为虚拟资源。
每个虚拟机都需要有自己的操作系统来声明、初始化并管理这些虚拟资源,每个操作系统都占用一定的资源。容器模型具有在宿主机操作系统中运行的单个内核。在一台主机上运行数十个甚至数百个容器都是可能的——容器共享一个操作系统/内核。 容器的共享导致不需要初始化内核,因此启动要比虚拟机快。
如果在Linux中遇到无权限访问的问题,需要确认当前用户是否属于本地Docker UNIX组。如果不是,可以通过usermod -aG docker <user>来添加,然后退出并重新登录Shell,改动即可生效。
//使用System V在Linux系统中执行该命令
$ service docker status
docker start/running, process 29393
//使用Systemd在Linux系统中执行该命令
$ systemctl is-active docker active
比较简单启动容器的命令: $ docker container run -it ubuntu:latest /bin/bash 。命令中使用了-it参数使容器具备交互性并与终端进行连接;最终,在命令中指定了运行在容器中的程序,Linux示例中是Bash Shell。Docker默认非TLS网络端口为2375,TLS默认端口为2376。
如果通过输入exit退出Bash Shell,那么容器也会退出(终止)。原因是容器如果不运行任何进程则无法存在——杀死Bash Shell即杀死了容器唯一运行的进程,导致这个容器也被杀死。这对于Windows容器来说也是一样的——杀死容器中的主进程,则容器也会被杀死。
容器的生命周期(从创建、运行、休眠,直至销毁的整个过程)
docker container stop命令中指定容器的名称或者ID。具体格式为docker container stop <container-id or container-name>。
使用docker container exec命令连接到重启后的容器。$ docker container exec -it percy bash
尽管上面的示例阐明了容器的持久化特性,还是需要指出卷(volume)才是在容器中存储持久化数据的首选方式
通过在docker container rm命令后面添加-f参数来一次性删除运行中的容器是可行的。但是,删除容器的最佳方式还是分两步,先停止容器然后删除。因为给了时间反应,而不是突然杀停。
利用重启策略进行容器的自我修复: 建议在运行容器时配置好重启策略。这是容器的一种自我修复能力,可以在指定事件或者错误后重启来完成自我修复
容器支持的重启策略包括always、unless-stopped和on-failed。always策略是一种简单的方式。除非容器被明确停止,比如通过docker container stop命令,否则该策略会一直尝试重启处于停止状态的容器。
--restart always策略有一个很有意思的特性,当daemon重启的时候,停止的容器也会被重启。always和unless-stopped的最大区别,就是那些指定了--restart unless-stopped并处于Stopped(Exited)状态的容器,不会在Docker daemon重启的时候被重启。
on-failure策略会在退出容器并且返回值不是0的时候,重启容器。就算容器处于stopped状态,在Docker daemon重启的时候,容器也会被重启。
添加-d参数可以在后台运行。
一个事例:
在构建镜像时指定默认命令是一种很普遍的做法,因为这样可以简化容器的启动。这也为镜像指定了默认的行为,并且从侧面阐述了镜像的用途——可以通过Inspect镜像的方式来了解所要运行的应用。
快速清理会没有反应的情况,不建议使用
应用容器化--Docker化
容器能够简化应用的构建、部署和运行过程。
(1)编写应用代码。
(2)创建一个Dockerfile,其中包括当前应用的描述、依赖以及该如何运行这个应用。
(3)对该Dockerfile执行docker image build命令。
(4)等待Docker将应用程序构建到Docker镜像中。
Dockerfile
通常将Dockerfile放到构建上下文的根目录下。
以alpine镜像作为当前镜像基础,指定维护者(maintainer)为“nigelpoultion@hotmail.com”,安装Node.js和NPM,将应用的代码复制到镜像当中,设置新的工作目录,安装依赖包,记录应用的网络端口,最后将app.js设置为默认运行的应用。
RUN指令会在FROM指定的alpine基础镜像之上,新建一个镜像层来存储这些安装内容。
COPY. / src指令将应用相关文件从构建上下文复制到了当前镜像中,并且新建一个镜像层来存储。
RUN npm install指令会根据package.json中的配置信息,使用npm来安装当前应用的相关依赖包。npm命令会在前文设置的工作目录中执行,并且在镜像中新建镜像层来保存相应的依赖文件。
通过ENTRYPOINT指令来指定当前镜像的入口程序。
构建: docker image build -t web:latest . << don't forget the period (.)
通过docker image inspect web:latest,会列出Dockerfile中设置的所有配置项。
docker login 可以登陆 docker hub
为镜像打标签的示例: docker image tag web:latest nigelpoulton/web:latest。
后台运行并且指定了端口映射: docker container run -d --name c1 -p 80:8080 web:latest
Dockerfile译述: Dockerfile中的注释行,都是以#开头的 , 通常使用大写。
新增镜像层的指令包括FROM、RUN以及COPY,而新增元数据的指令包括EXPOSE、WORKDIR、ENV以及ENTERPOINT。一个基本的原则是,如果指令的作用是向镜像中增添新的文件或者程序,那么这条指令就会新建镜像层;如果只是告诉Docker如何完成构建或者如何运行应用程序,那么就只会增加镜像的元数据。
可以通过docker image history来查看在构建镜像的过程中都执行了哪些指令
基本的构建过程是,运行临时容器>在该容器中运行Dockerfile中的指令>将指令运行结果保存为一个新的镜像层>删除临时容器。
**通过将命令都写在一个RUN中,可以减少层的建设。另一个问题是开发者通常不会在构建完成后进行清理。当使用RUN执行一个命令时,可能会拉取一些构建工具,这些工具会留在镜像中移交至生产环境。这是不合适的!
多阶段构建能够在不增加复杂性的情况下优化构建过程。多阶段构建方式使用一个Dockerfile,其中包含多个FROM指令。每一个FROM指令都是一个新的构建阶段(Build Stage),并且可以方便地复制之前阶段的构件。
重点在于COPY --from指令,它从之前的阶段构建的镜像中仅复制生产环境相关的应用代码,而不会复制生产环境不需要的构件。
示例Dockerfile代码:
FROM node:latest AS storefront
WORKDIR /usr/src/atsea/app/react-app
COPY react-app .
RUN npm install
RUN npm run build
FROM maven:latest AS appserver
WORKDIR /usr/src/atsea
COPY pom.xml .
RUN mvn -B -f pom.xml -s /usr/share/maven/ref/settings-docker.xml dependency \:resolve
COPY . .
RUN mvn -B -s /usr/share/maven/ref/settings-docker.xml package -DskipTests
FROM java:8-jdk-alpine AS production
RUN adduser -Dh /home/gordon gordon
WORKDIR /static
COPY --from=storefront /usr/src/atsea/app/react-app/build/ .
WORKDIR /app
COPY --from=appserver /usr/src/atsea/target/AtSea-0.0.1-SNAPSHOT.jar .
ENTRYPOINT ["java", "-jar", "/app/AtSea-0.0.1-SNAPSHOT.jar"]
CMD ["--spring.profiles.active=postgres"]
最佳实践
1、利用构建缓存 --> 缓存命中能显著加快构建过程
如果在开头无法找到符合要求的镜像层,则设置缓存无效并构建该镜像层,后续的指令将全部执行而不会再尝试查找构建缓存。
通过对docker image build命令加入--no-cache=true参数可以强制忽略对缓存的使用。
COPY和ADD指令会检查复制到镜像中的内容自上一次构建之后是否发生了变化。Docker会计算每一个被复制文件的Checksum值,并与缓存镜像层中同一文件的checksum进行对比。如果不匹配,那么就认为缓存无效并构建新的镜像层。
2、合并镜像 --> 有好有坏 缺点是无法共享镜像层 ,存储空间低效利用,push pull 操作镜像体积更大
执行docker image build命令时,可以通过增加--squash参数来创建一个合并的镜像。
3、使用no-install-recommends --> 这能够确保APT仅安装核心依赖(Depends中定义)包,而不是推荐和建议的包
Docker Compose 初识 (python工具)--> 一个声明式的配置文件YAML描述
Docker Compose,它能够在Docker节点上,以单引擎模式(Single-Engine Mode)进行多容器应用的部署和管理。Docker Stack,它能够以Swarm模式对Docker节点上的多容器应用进行部署和管理。
示例Yaml文件
version是必须指定的,而且总是位于文件的第一行。它定义了Compose文件格式(主要是API)的版本。建议使用最新版本。
services用于定义不同的应用服务。上边的例子定义了两个服务。
networks用于指引Docker创建新的网络。默认情况下,Docker Compose会创建bridge网络。这是一种单主机网络,只能够实现同一主机上容器的连接。当然,也可以使用driver属性来指定不同的网络类型。
volumes用于指引Docker来创建新的卷。
build:.指定Docker基于当前目录(.)下Dockerfile中定义的指令来构建一个新镜像。该镜像会被用于启动该服务的容器。
command:python app.py指定Docker在容器中执行名为app.py的Python脚本作为主程序。因此镜像中必须包含app.py文件以及Python,这一点在Dockerfile中可以得到满足。
ports:指定Docker将容器内(-target)的5000端口映射到主机(published)的5000端口。这意味着发送到Docker主机5000端口的流量会被转发到容器的5000端口。容器中的应用监听端口5000。
networks:使得Docker可以将服务连接到指定的网络上。这个网络应该是已经存在的,或者是在networks一级key中定义的网络。对于Overlay网络来说,它还需要定义一个attachable标志,这样独立的容器才可以连接上它(这时Docker Compose会部署独立的容器而不是Docker服务)。
volumes:指定Docker将counter-vol卷(source:)挂载到容器内的/code(target:)。counter-vol卷应该是已存在的,或者是在文件下方的volumes一级key中定义的。
Docker Compose 会将所有的资源名称中加上前缀 目录名_
常用的启动一个Compose应用的方式就是docker-compose up命令。它会构建所需的镜像,创建网络和卷,并启动容器。
如果不是默认的yml名字,应该使用-f 来指定docker-compose.yml的名字。
Docker Compose会将项目名称(counter-app)和Compose文件中定义的资源名称(web-fe)连起来。
docker compose 帮助手册命令全集
Docker Compose会在部署服务之前创建网络和卷。
我们在 Docker 主机对卷中文件的修改,会立刻反应到应用中。
docker-compose restart命令会重启已停止的Compose应用。如果用户在停止该应用后对其进行了变更,那么变更的内容不会反映在重启后的应用中,这时需要重新部署应用使变更生效。
Compose文件应该被当作代码,因此应该将其保存在源控制库中。
Docker Swarm --> 安全集群、编排引擎
从集群角度来说,一个Swarm由一个或多个Docker节点组成。节点会被配置为管理节点(Manager)或工作节点(Worker)。管理节点负责集群控制面(Control Plane),进行诸如监控集群状态、分发任务至工作节点等操作。工作节点接收来自管理节点的任务并执行。
Swarm的配置和状态信息保存在一套位于所有管理节点上的分布式etcd数据库中。无需管理,作为Swarm一部分被安装。Swarm使用TLS进行通信加密、节点认证和角色授权。
2377/tcp:用于客户端与Swarm进行安全通信。
7946/tcp与7946/udp:用于控制面gossip分发。
4789/udp:用于基于VXLAN的覆盖网络。
搭建Swarm的过程有时也被称为初始化Swarm,大体流程包括初始化第一个管理节点>加入额外的管理节点>加入工作节点>完成。
docker swarm init --advertise-addr 10.0.0.1:2377 --listen-addr 10.0.0.1:2377
--advertise-addr指定其他节点用来连接到当前管理节点的IP和端口 ; --listen-addr指定用于承载Swarm流量的IP和端口。其设置通常与--advertise-addr相匹配,但是当节点上有多个IP的时候,可用于指定具体某个IP。并且,如果--advertise-addr设置了一个远程IP地址(如负载均衡的IP地址),该属性也是需要设置的。建议执行命令时总是使用这两个属性来指定具体IP和端口。
Swarm模式下的操作默认运行于2337端口。
在mgr1上执行docker swarm join-token命令来获取添加新的工作节点和管理节点到Swarm的命令和Token。 工作节点和管理节点的接入命令中使用的接入Token(SWMTKN...)是不同的。因此,一个节点是作为工作节点还是管理节点接入,完全依赖于使用了哪个Token。
示例:
docker swarm join --token SWMTKN-1-0uahebax...c87tu8dx2c 10.0.0.1:2377 --advertise-addr 10.0.0.4:2377 --listen-addr 10.0.0.4:2377
--advertise-addr与--listen-addr属性是可选的。在网络配置方面,请尽量明确指定相关参数,这是一种好的实践。
MANAGER STATUS一列无任何显示的节点是工作节点。注意,mgr2的ID列还显示了一个星号(*),这个星号会告知用户执行docker node ls命令所在的节点。
也总是仅有一个节点处于活动状态。通常处于活动状态的管理节点被称为“主节点”(leader),而主节点也是唯一一个会对Swarm发送控制命令的节点。也就是说,只有主节点才会变更配置,或发送任务到工作节点。如果一个备用(非活动)管理节点接收到了Swarm命令,则它会将其转发给主节点。
关于管理器高可用性的最佳实践
部署奇数个管理节点。
不要部署太多管理节点(建议3个或5个)。 --> 更多的节点意味着需要更多的时间达到共识
部署奇数个管理节点有利于减少脑裂(Split-Brain)情况的出现机会。
Docker提供了自动锁机制来锁定Swarm,这会强制要求重启的管理节点在提供一个集群解锁码之后才有权从新接入集群。
命令: docker swarm update --autolock=true
执行docker swarm unlock命令来为重启的管理节点解锁Swarm。该命令需要在重启的节点上执行,同时需要提供解锁码。
使用docker service create命令创建一个新的服务。
使用--replicas参数告知Docker应该总是有5个此服务的副本。最后,告知Docker哪个镜像用于副本——重要的是,要了解所有的服务副本使用相同的镜像和配置。
Swarm会一直确保实际状态能够满足期望状态的要求。
关于服务更为详细的信息可以使用docker service inspect命令查看。
一个简单的docker service scale命令即可对web-fe服务进行扩容。
创建一个覆盖网络,与要创建的服务结合使用。覆盖网络是创建于底层异构网络之上的一个新的二层容器网络。
创建一个新的服务,并将其接入uber-net网络
通过对服务声明-p 80:80参数,会建立Swarm集群范围的网络流量映射,到达Swarm任何节点80端口的流量,都会映射到任何服务副本的内部80端口。
默认的模式,是在Swarm中的所有节点开放端口——即使节点上没有服务的副本——称为入站模式(Ingress Mode)。此外还有主机模式(Host Mode),即仅在运行有容器副本的节点上开放端口。
每次更新两个副本,并且中间间隔20s。
Swarm服务的日志可以通过执行docker service logs命令来查看。Docker节点默认的配置是,服务使用json-file日志驱动,其他的驱动还有journald(仅用于运行有systemd的Linux主机)、syslog、splunk和gelf。
json-file和journald是较容易配置的,二者都可用于docker service logs命令。命令格式为docker service logs <service-name>。
Docker网络
Docker网络架构源自一种叫作容器网络模型(CNM)的方案,该方案是开源的并且支持插接式连接。Libnetwork是Docker对CNM的一种实现,提供了Docker核心网络架构的全部功能。不同的驱动可以通过插拔的方式接入Libnetwork来提供定制化的网络拓扑。
不过其实抽象来讲,CNM定义了3个基本要素:沙盒(Sandbox)、终端(Endpoint)和网络(Network)。
终端与常见的网络适配器类似,这意味着终端只能接入某一个网络。因此,如果容器需要接入到多个网络,就需要多个终端。
单机桥接网络
每个Docker主机都有一个默认的单机桥接网络。除非读者通过命令行创建容器时指定参数--network,否则默认情况下,新创建的容器都会连接到该网络。
多机覆盖网络
Docker为覆盖网络提供了本地驱动。这使得创建覆盖网络非常简单,只需要在docker network create命令中添加--d overlay参数。
接入现有网络
将容器化应用连接到网络
Macvlan的缺点是需要将主机网卡(NIC)设置为混杂模式(Promiscuous Mode),这在大部分公有云平台上是不允许的。所以Macvlan对于公司内部的数据中心网络来说很棒(假设公司网络组能接受NIC设置为混杂模式),但是Macvlan在公有云上并不可行。
服务发现
允许容器和Swarm服务通过名称互相定位。唯一的要求就是需要处于同一个网络当中。其底层实现是利用了Docker内置的DNS服务器,为每个容器提供DNS解析功能。
每个启动时使用了--name参数的Swarm服务或者独立的容器,都会将自己的名称和IP地址注册到Docker DNS服务。这意味着容器和服务副本可以通过Docker DNS服务互相发现。
示例:
Swarm支持两种服务发布模式,两种模式均保证服务从集群外可访问。通过Ingress模式发布的服务,可以保证从Swarm集群内任一节点(即使没有运行服务的副本)都能访问该服务;以Host模式发布的服务只能通过运行服务副本的节点来访问。
不能使用简单格式发布Host模式下的服务。
完整格式如--publish published=5000,target=80,mode=host。该方式采用逗号分隔多个参数,并且逗号前后不允许有空格。
Docker使用Libnetwork实现了基础服务发现功能,同时还实现了服务网格,支持对入站流量实现容器级别负载均衡。
1、VXLAN
Docker使用VXLAN隧道技术创建了虚拟二层覆盖网络。
以太网(veth)适配器接入本地Br0虚拟交换机
卷
在容器中持久化数据的方式推荐采用卷。
Docker卷挂载到容器的/code目录
创建一个卷: docker volume create myvol
默认情况下,Docker创建新卷时采用内置的local驱动。恰如其名,本地卷只能被所在节点的容器使用。使用-d参数可以指定不同的驱动。
块存储:相对性能更高,适用于对小块数据的随机访问负载。目前支持Docker卷插件的块存储例子包括HPE 3PAR、Amazon EBS以及OpenStack块存储服务(Cinder)。
文件存储:包括NFS和SMB协议的系统,同样在高性能场景下表现优异。支持Docker卷插件的文件存储系统包括NetApp FAS、Azure文件存储以及Amazon EFS。
对象存储:适用于较大且长期存储的、很少变更的二进制数据存储。通常对象存储是根据内容寻址,并且性能较低。支持Docker卷驱动的例子包括Amazon S3、Ceph以及Minio。
此外,还可以通过在Dockerfile中使用VOLUME指令的方式部署卷。具体的格式为VOLUME <container-mount-point。但是,在Dockerfile中无法指定主机目录。这是因为主机目录通常情况下是相对主机的一个目录,意味着这个目录在不同主机间会变化,并且可能导致构建失败。
在集群节点间共享存储
数据损坏: 容器A为了提高速度并没有真实的将数据写入,而且写入到了缓存中等待后续慢慢写入;而容器B已经将数据写入了,这时候,两个容器都认为自己已经将数据写入卷中,但是Node2的容器B对A的情况是不知道的,就造成了数据损坏。
Docker Stack
Stack能够在单个声明文件中定义复杂的多服务应用。Stack还提供了简单的方式来部署应用并管理其完整的生命周期:初始化部署 > 健康检查 > 扩容 > 更新 > 回滚,以及其他功能!
步骤: 在Compose文件中定义应用,然后通过docker stack deploy命令完成部署和管理。
示例程序的目录:
1、网络
该文件中定义了3个网络:front-tier、back-tier以及payment。默认情况下,这些网络都会采用overlay驱动,新建对应的覆盖类型的网络。但是payment网络比较特殊,需要数据层加密。
如果需要加密数据层,有两种选择。
在docker network create命令中指定-o encrypted参数。
在Stack文件中的driver_opts之下指定encrypted:'yes'。
2、密钥
密钥属于顶级对象,在当前Stack文件中定义了4个。
4个密钥都被定义为external。这意味着在Stack部署之前,这些密钥必须存在。
在应用部署时按需创建密钥也是可以的,只需要将file: <filename>替换为external: true。但该方式生效的前提是,需要在主机文件系统的对应路径下有一个文本文件,其中包含密钥所需的值,并且是未加密的。这种方式存在明显的安全隐患。
3、服务
部署中的主要操作都在服务这个环节。每个服务都是一个JSON集合(字典),其中包含了一系列关键字。
完整的示例程序文件:
示例服务:
image关键字是服务对象中唯一的必填项。
Docker Stack和Docker Compose的一个区别是,Stack不支持构建。这意味着在部署Stack之前,所有镜像必须提前构建完成。
secret关键字中定义了两个密钥:revprox_cert以及revprox_key。这两个密钥必须在顶级关键字secrets下定义,并且必须在系统上已经存在。
networks关键字确保服务所有副本都会连接到front-tier网络。网络相关定义必须位于顶级关键字networks之下,如果定义的网络不存在,Docker会以Overlay网络方式新建一个网络。
部署约束是一种拓扑感知定时任务,是一种很好的优化调度选择的方式。Swarm目前允许通过如下几种方式进行调度。
节点ID,如node.id==o2p4kw2uuw2a。
节点名称,如node.hostname==wrk-12。
节点角色,如node.role!=manager。
节点引擎标签,如engine.labels.operatingsystem==ubuntu16.04。
节点自定义标签,如node.labels.zone==prod1。
部署应用
部署命令: docker stack deploy -c docker-stack.yml seastack
可以运行docker network ls以及docker service ls命令来查看应用的网络和服务情况。
网络是先于服务创建的。这是因为服务依赖于网络,所以网络需要在服务启动前创建。
Docker将Stack名称附加到由他创建的任何资源名称前作为前缀。在本例中,Stack名为seastack,所以所有资源名称的格式都如:seastack_<resource>。例如,payment网络的名称是seastack_payment。而在部署之前创建的资源则没有被重命名,比如密钥。
另一个需要注意的点是出现了新的名为seastack_default的网络。该网络并未在Stack文件中定义,那为什么会创建呢?每个服务都需要连接到网络,但是visualizer服务并没有指定具体的网络。因此,Docker创建了名为seastack_default的网络,并将visualizer连接到该网络。
读者可以通过两个命令来确认当前Stack的状态。docker stack ls列出了系统中全部Stack,包括每个Stack下面包含多少服务。docker stack ps <stack-name>针对某个指定Stack展示了更详细的信息,例如期望状态以及当前状态。
管理应用:
Stack是由普通的Docker资源构建而来:网络、卷、密钥、服务等。这意味着可以通过普通的Docker命令对其进行查看和重新配置,例如docker network、docker volume、docker secret、docker service等。
推荐方式是通过声明式方式修改,即将Stack文件作为配置的唯一声明。这样,所有Stack相关的改动都需要体现在Stack文件中,然后更新重新部署应用所需的Stack文件。所有应用/Stack都应采用该方式进行更新。所有的变更都应该通过Stack文件进行声明,然后通过docker stack deploy进行部署。
安全
安全本质就是分层!通俗地讲,拥有更多的安全层,就能拥有更多的安全性。而Docker提供了很多安全层。
Docker Swarm模式:默认是开启安全功能的。无须任何配置,就可以获得加密节点ID、双向认证、自动化CA配置、自动证书更新、加密集群存储、加密网络等安全功能。
Docker内容信任(Docker Content Trust, DCT):允许用户对镜像签名,并且对拉取的镜像的完整度和发布者进行验证。
Docker安全扫描(Docker Security Scanning):分析Docker镜像,检查已知缺陷,并提供对应的详细报告。
Docker密钥:使安全成为Docker生态系统中重要的一环。Docker密钥存储在加密集群存储中,在容器传输过程中实时解密,使用时保存在内存文件系统,并运行了一个最小权限模型。
Linux安全技术。Namespace。Control Group(自定义设置共享资源)。Capability(选择容器运行所所需的root用户权限)。MAC。Seccomp。
Docker平台安全技术。Swarm模式。Docker安全扫描(镜像的二进制扫描)。Docker内容信任机制(镜像的完整性和发布者)。Docker密钥(通过docker secret子命令来管理密钥,可以通过在运行docker service create命令时附加--secret,从而为某个服务指定密钥)。
每个优秀的容器平台都应该使用命名空间和控制组技术来构建容器。
Docker容器是由各种命名空间组合而成的。再次强调一遍,Docker容器本质就是命名空间的有组织集合。
Swarm模式的安全配置: 加密节点ID。基于TLS的认证机制。安全准入令牌。支持周期性证书自动更新的CA配置。加密集群存储(配置DB)。加密网络。
向某个现存的Swarm中加入管理者和工作者所需的唯一凭证就是准入令牌。
令牌格式: PREFIX - VERSION - SWARM ID - TOKEN。
准入令牌保存在集群配置的数据库中,默认是加密的。
相关文章:
Docker的深入浅出
目录 Docker引擎 Docker镜像 (镜像由多个层组成,每层叠加之后,从外部看来就如一个独立的对象。镜像内部是一个精简的操作系统(OS),同时还包含应用运行所必须的文件和依赖包) Docker容器 应用容器化--Docker化 最佳…...
导航守卫router.beforeEach
router.beforeEach 是一个全局前置守卫,在每次路由跳转之前都会触发。 //index.jsrouter.beforeEach((to, from, next) > {// 打印即将要进入的目标路由信息console.log(即将要进入的目标路由信息:, to)// 打印当前正要离开的路由信息console.log(当前正要离开的…...
Perl语言的软件开发工具
Perl语言的软件开发工具 引言 在当今软件开发的世界中,随着互联网的快速发展和信息技术的不断进步,编程语言和开发工具的选择变得尤为重要。特别是在处理大量数据、实现快速原型以及网络编程等领域,Perl语言凭借其独特的优势而受到广泛青睐…...
在 Linux 系统下,解压 `.tar.gz`
在 Linux 系统下,解压 .tar.gz 文件通常使用 tar 命令。.tar.gz 文件是一种压缩归档文件,它首先使用 tar 命令将多个文件打包为一个 .tar 文件,然后再使用 gzip 压缩生成 .tar.gz 文件。 解压 .tar.gz 文件的命令 要解压 .tar.gz 文件,可以使用以下命令: tar -xzvf fil…...
Deepseek
1.Deepseek是什么? deepseek是一家人工智能科技公司所开发的能够进行人工智能对话的一个应用,它的主要目标是大规模的研发与应用。deepseek-R1是它的开源推理模型,主要负责处理复杂任务并且可以免费使用。 2.Deepseek可以做什么? Deepseek…...
oracle如何查询历史最大进程数?
oracle如何查询历史最大进程数? SQL> desc dba_hist_resource_limitName Null? Type---------------------------------------------------- -------- ------------------------------------SNAP_ID …...
强一致性算法:Raft
目录 什么是 Raft 算法? Leader的选举 投票分裂后的选举过程 Raft算法日志复制过程 修复不一样的日志 数据安全性的保证 什么是 Raft 算法? Raft 算法是一种是一种用于管理复制日志的强一致性算法,用于保证分布式系统中节点数据的一致…...
8.flask+websocket
http是短连接,无状态的。 websocket是长连接,有状态的。 flask中使用websocket from flask import Flask, request import asyncio import json import time import websockets from threading import Thread from urllib.parse import urlparse, pars…...
是德科技 | PCIe 7.0 互连— PCIe的尽头会是光吗?
伴随大语言模型和相关训练系统迅猛增长、对非结构化数据处理的需求急剧上升,市场对算力的需求也是呈指数级增加。PCIe作为计算机和服务器中使用广泛的高速数据传输技术发展迅猛,今年4月份PCI-SIG已经批准 Draft 0.5版基础规范,目前0.7版本基础…...
Aitken 逐次线性插值
Aitken 逐次线性插值 用 Lagrange 插值多项式 L n ( x ) L_n(x) Ln(x)计算函数近似值时,如需增加插值节点,那么原来算出的数据均不能利用,必须重新计算。为克服这个缺点,可用逐次线性插值方法求得高次插值。 令 I i 1 , i 2…...
Orange 开源项目介绍
Orange 开源项目 项目兼容单体架构与微服务架构两种模式,集成了包括部门管理、用户管理、菜单配置、角色分配、字典维护以及日志记录在内的多种系统管理功能。 项目体验 Orange 官网: http://hengzq.cn在线体验: http://tiny.hengzq.cn项目文档: http://hengzq.cn/…...
【高级架构师】多线程和高并发编程(三):锁(下)深入ReentrantReadWriteLock
文章目录 4、深入ReentrantReadWriteLock4.1 为什么要出现读写锁4.2 读写锁的实现原理4.3 写锁分析4.3.1 写锁加锁流程概述4.3.2 写锁加锁源码分析4.3.3 写锁释放锁流程概述&释放锁源码 4.4 读锁分析4.4.1 读锁加锁流程概述4.4.1.1 基础读锁流程4.4.1.2 读锁重入流程4.4.1.…...
如何在Node.js中使用中间件处理请求
Node.js作为一种基于事件驱动、非阻塞I/O模型的运行环境,广泛用于构建高性能的Web应用。在Node.js中,处理中间件是处理HTTP请求和响应的一个常见方式,特别是在使用Express框架时,中间件扮演着至关重要的角色。本文将介绍如何在Nod…...
Kotlin 2.1.0 入门教程(十三)异常、Nothing
创建自定义异常 可以通过创建继承内置 Exception 类来定义自定义异常。这允许你创建更符合应用程序需求的特定错误类型。 要创建一个自定义异常,可以定义一个继承 Exception 的类: class MyException : Exception("My message")在这个例子中…...
Unity 打造游戏资源加密解密系统详解
在游戏开发中,保护游戏资源不被轻易破解和盗用至关重要。本文将详细介绍如何在 Unity 中打造一个游戏资源加密解密系统,并提供技术详解和代码实现。 一、加密方案选择 1.1 对称加密 优点: 加密解密速度快,适合加密大量数据。 缺点: 密钥管…...
HarmonyOS Next 方舟字节码文件格式介绍
在开发中,可读的编程语言要编译成二进制的字节码格式才能被机器识别。在HarmonyOS Next开发中,arkts会编译成方舟字节码。方舟字节码长什么样呢?我们以一个demo编译出的abc文件: 二进制就是长这样,怎么去理解呢&…...
二层、三层小总结
一、网络隔离 1、物理隔离。搭建两套完全独立的网络,这也是最土豪最安全的做法。 2、二层隔离。使用Vlan隔离,使用不同Vlan或者Pvlan等。 3、三层隔离。路由隔离。 4、设备特性隔离。比如端口隔离swichport protected,或者ACL等。 5、安全…...
Window系统通过Docker本地安装ollama和deepseek
在 Windows 系统上安装 Ollama 和 DeepSeek 的步骤如下: 安装 Ollama 安装 WSL(Windows Subsystem for Linux): 如果还没有安装 过WSL的(安装过的你直接跳过就行了),可以按照以下步骤进行安装&…...
云原生后端|实践?
云原生(Cloud Native)是一种构建和运行应用程序的方法,它充分利用云计算的优势,包括弹性、可扩展性、高可用性和自动化运维。云原生后端开发通常涉及微服务架构、容器化、持续集成/持续部署(CI/CD)、服务网…...
1.1 Spring生态全景解读
1.1 Spring生态全景解读 1.1.1 Spring Framework发展历程与技术演进(深度解析版) 技术演进路线图与里程碑事件: 2003.10 - Spring 1.0 发布→ 核心特性:XML Bean配置、AOP基础支持→ 企业痛点:解决EJB复杂性问题&am…...
跨境商家系统搭建||反向海淘系统的搭建
反向海淘系统的搭建主要涉及以下几个方面的工作: 一、需求分析 在搭建反向海淘系统之前,首先需要进行需求分析。这包括明确系统的目标用户群体,了解他们的购物习惯、需求和期望。同时,还需要分析市场上的竞争对手,了…...
LeetCode数学相关算法题(1)【C语言版】
2520. 统计能整除数字的位数 给你一个整数 num ,返回 num 中能整除 num 的数位的数目。 如果满足 nums % val 0 ,则认为整数 val 可以整除 nums 。 示例 1: 输入:num 7 输出:1 解释:7 被自己整除&…...
云消息队列 ApsaraMQ Serverless 演进:高弹性低成本、更稳定更安全、智能化免运维
如今,消息队列已成为分布式架构中不可或缺的关键服务,为电商、物联网、游戏和教育等行业,提供了异步解耦、集成、高性能和高可靠的核心价值。 过去一年,我们发布了云消息队列 ApsaraMQ 全系列产品 Serverless 化,面向…...
github - 使用
注册账户以及创建仓库 要想使用github第一步当然是注册github账号了, github官网地址:https://github.com/。 之后就可以创建仓库了(免费用户只能建公共仓库),Create a New Repository,填好名称后Create,之后会出现一些仓库的配置信息,这也是一个git的简单教程。 Git…...
cmos晶体管
CMOS晶体管 一、PMOS和NMOS介绍 PN结: P-type和N-type组合在一起,变成一个PN结(二极管)。在P端给高电压,N端给低电压时,可以导通。否则不导通。 NMOS:有四个端口:gate、source、…...
pip3命令全解析:Python3包管理工具的详细使用指南
pip3命令全解析:Python3包管理工具的详细使用指南 一、基本使用二、升级和更新三、其他常用命令四、换源操作五、注意事项六、帮助信息pip3命令使用说明 pip3 是 Python 3 的包管理工具,用于安装、升级和卸载 Python 3 的包。以下是 pip3 的常用命令及详细说明: 一、基本使…...
统计 product 表中 detail 字段包含 xxx 的产品数量
您可以使用以下 SQL 查询语句来统计 product 表中 detail 字段包含 oss.kxlist.com 的产品数量: SELECT COUNT(*) FROM product WHERE INSTR(detail, oss.kxlist.com) > 0;mysql> SELECT COUNT(*)-> FROM product-> WHERE INSTR(detail, oss.kxlist.co…...
Kafka 集群原来是使用ZK管理,现在新版本是怎么管理的?
目录 基于 ZooKeeper 的管理模式 基于 KRaft 的管理模式 迁移到 KRaft 模式的优势 迁移步骤 Kafka 早期依赖 ZooKeeper(ZK)进行元数据管理、集群协调等工作,但在新版本(Kafka 2.8.0 及之后)引入了 KRaft 模式来替代 ZooKeeper 进行管理。下面详细介绍这两种管理模式以…...
【Java并发编程之什么是指令重排序?如何避免指令重排序?】
Java并发编程之什么是指令重排序? 1.1 指令重排序的原因1.2 指令重排序的示例1.3 指令重排序的影响1.4 如何避免指令重排序带来的问题?1.5 使用原子类1.6 使用 final 关键字1.7 内存屏障(Memory Barrier)1.8 总结在Java中,指令重排序是指编译器和处理器为了提高程序执行效…...
渲影医析Lab学术版
渲影医析 Lab 是武汉渲影软件研发的框架式、模块化、流程化的影像组学分析设计软件,尤其适合处理多模态脑影像数据。通过将影像分析流程细分为可视化节点,并以节点连接的方式构建数据流程,赋予了临床医学研究者、生物医药科研工作者自主设计多…...
利用Minio实现大文件分片上传、断点续传、秒传
利用Minio实现大文件分片上传、断点续传、秒传 demo来自B站蜗牛哥,gitee仓库:minio-upload: 使用vue3 elementplus minio springboot 实现大文件的分片上传、断点续传、秒传的功能demo - Gitee.com 后端暴露端口方法 获取上传进度,identifier…...
查出 product 表中所有 detail 字段包含 xxx 的完整记录
您可以使用以下 SQL 查询语句来查出 product 表中所有 detail 字段包含 oss.kxlist.com 的完整记录: SELECT * FROM product WHERE INSTR(detail, oss.kxlist.com) > 0;下面是detail字段包含的完整内容 <p><img style"max-width:100%;" src…...
Linux系统编程之信号基础知识
概述 信号是Linux系统中用于进程间通信的一种机制,允许一个进程通知另一个进程发生了某些特定事件。信号可以来自硬件中断、用户输入,也可以来自其他进程或者内核本身。信号是一种异步通知机制,当某个事件发生时,操作系统会向目标…...
【C语言标准库函数】标准输入输出函数详解[4]:二进制文件读写函数
目录 一、fread() 函数 1.1. 函数简介 1.2. fread 使用场景 1.3. 注意事项 1.4. 示例 二、fwrite() 函数 2.1. 函数简介 2.2. fwrite 使用场景 2.3. 注意事项 2.4. 示例 三、总结 在 C 语言中,二进制文件读写函数允许以二进制形式对文件进行读写操作&…...
图像锐化(QT)
如果不使用OpenCV,我们可以直接使用Qt的QImage类对图像进行像素级操作来实现锐化。锐化算法的核心是通过卷积核(如拉普拉斯核)对图像进行处理,增强图像的边缘和细节。 以下是一个完整的Qt应用程序示例,展示如何使用Qt…...
Apache Kafka 消息清理之道
前言 消息的清理是 MQ 中间件的基本能力,可以避免 MQ 的存储占用空间无序增长。与其他消息产品不同,Apache Kafka(以下简称 Kafka) 中 topic 上的消息被消费后不会被马上清除,而是由 topic 级别的清理策略来控制。本文将简要介绍 Kafka 中的…...
JVM ①-类加载 || 内存区域
这里是Themberfue 终于结束了网络层的学习,当然,我们学习的知识也只是冰山一角,想要了解更多的知识,还请大家养成主动探索的习惯~~~接下来我们将对 JVM 的一些机制进行简单的讲解,对于 Java程序员来说,本身…...
物理信息机器学习(PIML)的基础探讨及技术实现
在传统机器学习方法迅速发展并在图像识别、语音处理、自然语言处理等领域取得显著突破的同时,科学计算、工程设计以及自然系统建模等领域常常面临数据不足、噪声干扰以及模型泛化能力弱的问题。单纯依赖数据驱动的“黑箱”模型在处理物理问题时,往往难以兼顾数据拟合与物理解…...
【浏览器多开】Google Chrome 谷歌浏览器分身术
谷歌浏览器分身术(多开): 复制已有谷歌浏览器图标—>右键–>属性的目标栏中,添加 --user-data-dir自定义文件夹路径 参数。 例如: C:\MySpace\02Installed\Chrome\Chrome-bin\99.0.4844.51\chrome.exe –user-d…...
《量化绿皮书》Chapter 3 Calculus and Linear Algebra 微积分与线性代数(二)
《A Practical Guide To Quantitative Finance Interviews》,被称为量化绿皮书,是经典的量化求职刷题书籍之一,包含以下七章: Chapter 1 General Principles 通用技巧 Chapter 2 Brain Teasers 脑筋急转弯 Chapter 3 Calculus and…...
单片机成长之路(51基础篇) - 008 C51 的标示符和关键字
标准 C 语言定义了 32 个关键字,如下表(ANSI C的32个关键字): C51在此基础上针对单片机功能进行了扩展,详情见下表(C51编译器扩充关键字): C 51的数据类型 51单片机使用的C语言的存储器类型分为以下几种:...
嵌入式AI革命:DeepSeek开源如何终结GPU霸权,开启单片机智能新时代?
2025年,全球AI领域最震撼的突破并非来自算力堆叠的超级模型,而是中国团队DeepSeek通过开源策略,推动大模型向微型化、低功耗场景的跨越。相对于当人们还在讨论千亿参数模型的训练成本被压缩到600万美金而言,被称作“核弹级别”的操…...
Deno vs Node.js:性能对比深度解析
1. 引言 Deno 和 Node.js 都是基于 V8 引擎的 JavaScript 运行时环境,然而它们在架构、模块管理、安全性和性能方面存在显著差异。Deno 由 Node.js 的原始作者 Ryan Dahl 开发,旨在解决 Node.js 设计上的一些问题,比如包管理、安全模型和 Ty…...
【R】Dijkstra算法求最短路径
使用R语言实现Dijkstra算法求最短路径 求点2、3、4、5、6、7到点1的最短距离和路径 1.设置data,存放有向图信息 data中每个点所在的行序号为起始点序号,列为终点序号。 比如:值4的坐标为(1,2)即点1到点2距离为4;值8的坐标为(6,7)…...
网络安全治理架构图 网络安全管理架构
网站安全攻防战 XSS攻击 防御手段: - 消毒。 因为恶意脚本中有一些特殊字符,可以通过转义的方式来进行防范 - HttpOnly 对cookie添加httpOnly属性则脚本不能修改cookie。就能防止恶意脚本篡改cookie 注入攻击 SQL注入攻击需要攻击者对数据库结构有所…...
@emotion/styled / styled-components创建带有样式的 React 组件
一、安装依赖 npm install emotion/styled styled-components 二、使用 import styled from emotion/styled; import styled from styled-components;// 创建一个带样式的按钮 const StyledButton styled.buttonbackground-color: #4caf50;color: white;padding: 10px 20px…...
Gemini 2.0模型更新:谷歌最新AI大模型全面开启智能时代
引言 2025年2月5日,谷歌人工智能实验室(Google DeepMind)发布了最新的Gemini 2.0模型系列更新,包括2.0 Flash、Flash-Lite和Pro实验版本。这些AI大模型的发布标志着人工智能技术在性能、效率和多模态能力上的进一步突破ÿ…...
MySQL 主从复制原理及其工作过程
一、MySQL主从复制原理 MySQL 主从同步是一种数据库复制技术,它通过将主服务器上的数据更改复制到一个或多个从服务器,实现数据的自动同步。 主从同步的核心原理是将主服务器上的二进制日志复制到从服务器,并在从服务器上执行这些日志…...
详解在Pytest中忽略测试目录的三种方法
关注开源优测不迷路 大数据测试过程、策略及挑战 测试框架原理,构建成功的基石 在自动化测试工作之前,你应该知道的10条建议 在自动化测试中,重要的不是工具 你是否曾因无关或过时的代码导致测试失败? 这可能会增加调试和故障排除…...
ZoneMinder index.php存在SQL注入漏洞(CVE-2024-43360)
免责声明: 本文旨在提供有关特定漏洞的深入信息,帮助用户充分了解潜在的安全风险。发布此信息的目的在于提升网络安全意识和推动技术进步,未经授权访问系统、网络或应用程序,可能会导致法律责任或严重后果。因此,作者不对读者基于本文内容所采取的任何行为承担责任。读者在…...