极狐GitLab 企业级 CI/CD 规模化落地实践指南(一)
目录
template 引用,减少代码冗余,增强 CI/CD 构建扩展性
问题 1:代码冗余,低效实践
问题 2:维护性难,工作量大
➤ local
➤ file
➤ remote
➤ template
收益 1:一处修改,多处生效
收益 2:高效构建,简单便捷
Component,打造 CI/CD Pipeline 单一可信源,简化 CI/CD Pipeline 构建
Component 仓库的构建
Component 的发布
Component 的引用
Runner,CI/CD 高效构建的利器
专有 + 共享,更多灵活选择
动态扩缩容,提高资源使用率
合规流水线,助力流水线的安全合规使用
极狐GitLab CI 内置于极狐GitLab 一体化平台,提供开箱即用的 CI/CD 能力,也是受众多用户喜爱的 CI 工具之一。极狐GitLab CI 独特的设计机制和企业级功能特性,能够帮助企业在大规模落地 CI/CD 实践时,提高 CI/CD 构建效率、降低 Pipeline 维护成本,同时还能保持足够的安全合规性。
本文从 CI/CD Pipeline 的构建入手,讲述极狐GitLab CI 三大方面的使用:
-
通过
template
、component
来缩短 Pipeline 编写时间、提高维护性; -
通过 Runner 的“花式”玩法来满足不同场景下的 CI/CD Pipeline 运行需求,同时降低使用成本;
-
用合规框架来保障 CI/CD Pipeline 的合规使用。
template 引用,减少代码冗余,增强 CI/CD 构建扩展性
在企业内部,一种很常见的场景就是:不同团队或者不同产品线都有自己独有的项目,每个项目都有对应的 CI/CD 流水线,随着项目的增多,流水线的数量也会不断增加,一个企业内部有可能存在数百甚至上千条流水线。
因为 CI/CD 流水线是软件交付(从编码到上线)的自动化展现形式,因此大部分流水线之间会有比较高的相似度,甚至有一些 stage 或者 job 是完全一样的,比如在云原生交付场景下需要将应用程序打包成镜像,使用极狐GitLab CI 进行构建的代码如下:
build:image: docker:lateststage: buildservices:- docker:20.10.7-dindscript:- docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" $CI_REGISTRY- docker build -t $CI_REGISTRY_IMAGE:1.0.0 .- docker push $CI_REGISTRY_IMAGE:1.0.0
此外,如果都是 java 或者 golang 项目,其编译或者测试的命令可能也是类似的。这种“重复”会随着流水线的增加而增加,以下问题也会随之而来:
问题 1:代码冗余,低效实践
如果每一条流水线都有一个 stage 或者 job 是相似的,大约有 10 行代码,那么数百上千条流水线,其重复的代码数量就是成千上万条。这种代码冗余在软件研发领域本身就是一种低效实践,如果不及时进行重构,随着项目的演进,就会变成技术债。
问题 2:维护性难,工作量大
在对 CI/CD Pipeline 进行优化的过程中,需要对流水线的部分内容进行改造,比如需要升级 dind 的版本,抑或为了安全地构建镜像,将构建方式从 dind 转向 kaniko,那么对应的代码就要变成:
services:- docker:24.0.3-dind
及:
build:stage: buildimage:name: registry.jihulab.com/jh-xiaomage-devops/go-demo/kaniko:debugentrypoint: [""]script:- mkdir -p /kaniko/.docker- echo "{\"auths\":{\"${CI_REGISTRY}\":{\"auth\":\"$(printf "%s:%s" "${CI_REGISTRY_USER}" "${CI_REGISTRY_PASSWORD}" | base64 | tr -d '\n')\"}}}" > /kaniko/.docker/config.json- >-/kaniko/executor--context "${CI_PROJECT_DIR}"--dockerfile "${CI_PROJECT_DIR}/Dockerfile"--destination "${CI_REGISTRY_IMAGE}:1.0.0"
这时就要对所有的流水线进行改造,数百条乃至上千条流水线的改造将是一个巨大的工作量,且大量代码的“复制粘贴”过程,很难避免不出错。
在软件研发领域,解决冗余代码的重要手段就是通过抽象 + 复用:也就是将相同(或者相似)的内容抽象成模版,将模版“存储”在某一个地方,其他地方只需要简单引用模版即可。
对于 CI/CD Pipeline 来说也是一样。极狐GitLab template 就是极狐GitLab CI 内置的模版引擎功能,可以将抽象之后的模版存储在项目仓库中,其他项目通过 include
语法就可完成 template 的引用。
极狐GitLab template 的用法比较灵活,首先需要将“制作”模版,也就是将“重复”的代码提取出来,保存在一个 YAML 文件中。比如上面的镜像构建内容,可以写到一个 docker-image-build.gitlab-ci.yml 文件中。接下来使用 include
进行引用。根据模版存储的位置不同,include
的引用有以下四种方式:
➤ local
模版位于当前项目中,使用 local
关键字来引用。使用语法如下:
include: - local: '/templates/docker-image-build.gitlab-ci.yml'
➤ file
模版和项目位于同一实例,但是不同仓库,使用 file
关键字来引用。使用语法如下:
include - project: xiaomage/templates - ref: main file: /templates/docker-image-build.gitlab-ci.yml
➤ remote
引用远端仓库中的流水线,通常是不同实例之间的引用。使用语法如下:
include: - remote: 'https://jihulab.com/xiaomage/teamplates/raw/main/docker-image-build.gitlab-ci.yml'
➤ template
极狐GitLab 内置模版的引用。极狐GitLab 根据自身多年的经验,沉淀了众多可以直接复用的模版,使用 template 语法即可使用。最典型的就是极狐GitLab DevSecOps 模版的引用。极狐GitLab DevSecOps 有密钥扫描、依赖项扫描、SAST、DAST、容器镜像扫描、模糊测试及许可证合规检测功能,所有功能两行代码即可开启。
因此,使用 template 能带来以下收益:
收益 1:一处修改,多处生效
如果需要对流水线的内容进行优化,比如将 dind
的版本进行升级,则只需要在模版中进行修改,其他引用的地方会随之生效,真正实现“一处修改,多处生效”,这完全避免了“一处变更,处处修改”所带来的重复劳动,而且流水线的冗余度也会降低。
收益 2:高效构建,简单便捷
template 可以实现多级嵌套,也就是模版里面引用模版。这样做的好处就是,可以将模版的内容细粒度化,可能是一个 stage,也可能是一个 job,比如容器镜像构建是一个模版,容器镜像安全扫描又是一个模版。如果要对新项目构建一条流水线,则可以直接使用多个 template 进行“搭积木”的方式就可快速完成流水线的构建,然后根据项目的实际构建流程来对参数或者流程做一些变更即可。
当然,为了高效的使用模版,还有一个问题需要注意,那就是模版中变量的覆盖。
为了灵活使用模版,使用同一套模版,构建出多个不同的实例。关键在于模版中变量的使用。比如,构建容器镜像时 tag 可能会随着版本的不同而不同,此时可以将 tag 设置为一个变量:
variables:IMAGE_TAG: 1.0.0build:image: docker:lateststage: buildservices:- docker:20.10.7-dindscript:- docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" $CI_REGISTRY- docker build -t $CI_REGISTRY_IMAGE:$IMAGE_TAG .- docker push $CI_REGISTRY_IMAGE:$IMAGE_TAG
在引用的地方直接进行变量覆盖即可:
variables:IMAGE_TAG: "2.0.0"include: - remote: 'https://jihulab.com/xiaomage/teamplates/raw/main/docker-image-build.gitlab-ci.yml'
覆盖之后,镜像 tag 的值从默认的 1.0.0
就变成了 2.0.0
,这样就能满足不同场景的诉求,兼具高效和灵活。
Component,打造 CI/CD Pipeline 单一可信源,简化 CI/CD Pipeline 构建
template 的使用大大降低了用户构建 CI/CD Pipeline 的难度,通过引用 + 参数覆盖的模式就能够快速构建出对应场景的 Pipeline,但是目前并没有一个 template 的单一可信源,来方便用户找到自己想用的 Pipeline,同时也无法让愿意贡献的用户将可用的 template 贡献出来,来共同打造 Pipeline 的繁荣生态。
为此,极狐GitLab 推出了 CI/CD Component 这一特色功能,其目的就是打造 CI/CD Pipeline 的单一可信源,通过将不同流水线(或者单独的作业)变成不同的 component,然后发布到 component 仓库,其他用户可以在此仓库中通过搜索来找到自己想要的 component,在构建流水线的时候直接引用即可,多个组件的引用就能够快速搭建起整个完整的流水线,这极大的改变了用户使用 CI/CD 的体验。
更为重要的是用户可以将自己认为已经得到实践的一些优秀流水线(或者单独的作业)以 component 的形式发布到 component 仓库,通过不同用户的不断贡献、迭代来共同打造繁荣的 CI/CD Pipeline 生态,最终构建企业内部 CI/CD Pipeline 单一可信源,提高 CI/CD Pipeline 构建效率的同时,安全性也得到了很大的提升。
注意:CI/CD Component 目前处于实验阶段。
CI/CD Component 示意图
因此,componnt 的核心是:component 仓库的构建、 component 的发布及 component 的引用。
Component 仓库的构建
通过创建一个极狐GitLab 仓库,并且将其标记为 component 仓库来构建一个初始的 component 仓库。该仓库至少需要两个文件 README.md
和 template.yml
:
-
README.md
可以对仓库中包含的 component 进行描述,方便用户学习使用; -
template.yml
就是 component 的具体内容。
可以通过不同的目录结构(分支、tag 等)来实现不同 component 的区分,比如:
├── template.yml
├── README.md
├── .gitlab-ci.yml
├── forntend/
│ └── template.yml
└── backend/└── template.yml
上述目录表示,在此 component 仓库中有三个可用的 component:
-
根目录下
template.yml
表示的 component; -
frontend 目录下
template.yml
表示的 component; -
backend 目录下
template.yml
表示的 component。
可以通过项目 → 设置 → 通用 → 可见性、项目功能、通用 → 开启 CI/CD 目录资源来将一个仓库标记为 component 仓库。
Component 的发布
如果需要发布一个 component,则需要将对应的内容写入到某个 template.yml
内,然后将该文件推送至 component 仓库即可。以上述镜像构建为例,将下述内容写入到某个 template.yml
中:
spec: inputs: stage: default: test image: default: docker:latest tags: default: tags image_tag: default: 1.0.0component-job-build-image: image: $[[ inputs.image ]] stage: $[[ inputs.stage ]] tags: - $[[ inputs.tags ]] script: - docker login -u "$REGISTRY_USER" -p "$REGISTRY_PWD" REGISTRY_URL - docker build -t dllhb/cicd-component:$[[ inputs.image_tag ]] . - docker push dllhb/cicd-component:$[[ inputs.image_tag ]]
然后推送至 jh.instance.url/username/component-project
目录下。参数说明:
-
jh.instance.url
:极狐GitLab 私有化部署实例地址; -
username
:极狐GitLab 用户名; -
component-project
:component 仓库名称。
上述 component 位于仓库根目录下,有一个 component-job-build-image
job。
Component 的引用
如果想要在其他 Pipeline 中引用上述发布的 component,在 .gitlab-ci.yml
中用如下语法引用:
include: - component: jh.instance.url/username/component-project@main inputs: stage: build image: docker:latest tags: cicd image_tag: 2.0.0stages: [build]
需要注意的地方有:
-
在
include
中完整写入 component(也就是tempate.yml
存在的路径)的路径,通过 @ 来明确引用的是 component 的哪个版本(可以用分支、commit hash、tag 等表示); -
在
inputs
中写入具体的参数。
触发 CI/CD Pipeline,可以看到 component-job-build-image job
执行成功:
同样地,如果想要将 dind
的构建方式换为 kaniko
,则无需替换上述 component 的内容,只需要再次发布一个以 kaniko 为主题的 component 即可。
这有很多种做法来实现,比如将 template.yml
放在 component 仓库的另外一个目录(非根目录下,因为根目录下已经有 dind
的 component)、分支、tag 下来表示这是不同的 component;比如针对上述的 component,main 分支表示 dind
component,那么可以新建一个 kaniko
分支来存放 kaniko 对应的 component,最后在 .gitlab-ci.yml
中引用的时候指明分支即可:
include: - component: jh-jhma.gitlab.cn/cicd-component/cicd-component-demo@kaniko inputs: stage: build image: gcr.io/kaniko-project/executor:debug tags: cicd image_tag: 2.0.0stages: [build]
当然,镜像也要由原来的
dind
改为kinako
,这只需要修改inputs
的参数即可。
运行 CI/CD Pipeline 可以得到相同的结果。
component 的引入拉开了极狐GitLab CI/CD 使用新范式的序幕。这种通过用户贡献来打造 CI/CD Pipeline 单一可信源的做法,对于用户构建完整的 Pipeline 有着巨大帮助,不仅加速了 CI/CD Pipeline 的构建,还大大降低了用户学习繁杂 YAML 语法的成本。
以上所演示的代码均存储在极狐GitLab 私有化部署实例上,地址为 https://jh-jhma.gitlab.cn/cicd-component。
Runner,CI/CD 高效构建的利器
Runner 是极狐GitLab CI 的一个重要组件,它能够帮助运行 CI/CD 流水线中所定义的 Job。当研发人员提交代码变更后,极狐GitLab 就会“通知” Runner 去按照 .gitlab-ci.yml
定义的流水线步骤完成变更代码的构建、测试、部署等,此过程中 Runner 会根据所选择的 executor(比如针对 PowerShell 的 shell、针对容器的 docker 等)来针对不同环境进行 Job 的运行。关于 executor 的选择可以参考极狐GitLab 执行器官网。
Runner 像是一个“agent”,接受“server”端(极狐GitLab 实例)的请求,因此为了满足不同场景的需求,Runner 要能够满足在不同 OS、不同 CPU 架构上以不同的安装方式来运行。
专有 + 共享,更多灵活选择
Runner 分为专有和共享两大类:
-
专有:指 Runner 只给指定的项目用,通常是使用项目的一些信息( Runner register token)来将 Runner 注册到对应的项目下面;
-
共享:指 Runner 是针对整个极狐GitLab 实例的,意味着整个实例下面的所有项目都可以使用这些 Runner,至于如何用、谁先用、谁后用是由极狐GitLab 的内部调度机制来实现的。
专有 Runner 的最大优势在于:
-
节省时间:专有 Runner 只给对应的项目运行 CI/CD 流水线,因此不用排队去等待共享 Runner 来执行 CI/CD 流水线,且随着项目、流水线的增加,排队将耗费大量时间;
-
自主可控:专有 Runner 是用户自己安装在自己可控的服务器上,在使用过程中如果要对流水线过程进行 Debug 或者对 Runner 配置进行修改,甚至想获取某些运行过程中的数据,则可以直接登陆到对应的 Runner 中进行操作。
专有 Runner 的配置信息
共享 Runner 的好处也是显而易见的:用户无需了解 Runner 的过多信息,也无需自己安装运维等。是一种比较省事的方式。
因此,用户可以根据自身的需求,来选择不同方式的 Runner 来完成相应的 CI/CD 流水线运行。
动态扩缩容,提高资源使用率
Runner 可以和云资源动态伸缩的特性紧密绑定,实现 Runner 的动态伸缩:当有 CI/CD 流水线需要运行的时候,Runner 使用一些资源(CPU、内存等)来执行所有 Job,当 CI/CD 流水线运行结束(成功或失败)后,对应的资源被释放,对环境进行恢复。
比如说,可以使用容器来运行 Runner,最典型的就是使用 Kubernetes 来运行极狐GitLab Runner。
当执行 CI/CD 时,Kubernetes 会动态创建一个 pod,pod 会根据 .gitlab-ci.yml
文件中描述的 stage 以及对应的镜像来生成相应的容器(所有容器在一个 pod 内,共享 pod 内部资源),流水线的运行都在容器内部,当流水线运行结束,pod 会删除,运行过程中的数据、所需的资源会被释放。
此外,还可以使用云厂商提供的 serverless 产品实现 Runner 的动态扩所容,提高资源的使用率。
合规流水线,助力流水线的安全合规使用
流水线使用过程中还会遇到一个场景:某一个流程是需要所有项目的流水线都必须运行的,比如在镜像构建结束必须进行镜像安全扫描,如果有安全漏洞就需要终止流水线的运行。这种情况下的解决方案往往是针对所有项目在流水线中使用 include
加入容器镜像扫描环节,但是随着项目数量的增多(成百乃至上千),这意味着巨大的重复工作量,而且无法确保操作的精准度。
而正确的解决方案就是:合规流水线。
合规流水线是极狐GitLab CI/CD 流水线内置的一个安全功能,主要是确保群组内的所有项目都能够运行指定的合规作业。通过在群组级别配置好合规框架,选择好每个项目都必须运行的合规流水线作业,则此群组下面的所有项目都会运行此合规作业,甚至后续在该群组下新创建的项目也会默认执行此合规作业。
合规流水线的使用,首先需要在群组级别进行合规框架的配置。在群组 → 设置 → 通用 → 合规框架中,选择新建合规框架,然后填入合规框架名称、描述、合规流水线配置(也就是合规流水线所存储的位置),最后选择一个背景颜色即可。
如将此合规框架设置为群组的默认合规框架,则此群组下面新建的项目都会默认使用此合规框架,默认运行此合规流水线,而且在项目页面会有合规框架的标签生成。
接着需要将合规流水线写入到此群组下面的一个项目(比如 Compliance-Pipeline)中。以容器镜像构建和扫描流水线为例,在 .gitlab-ci.yml
文件中写入如下内容:
include: - remote: 'https://jihulab.com/xiaomage/teamplates/raw/main/docker-image-build.gitlab-ci.yml'- template: Security/Container-Scanning.gitlab-ci.yml
后续所有的新建项目都会执行容器镜像构建和容器镜像扫描这两个作业,而不是项目自带的流水线。
如果想要项目自带的流水线也被执行,只需要将合规流水线的内容和项目自带流水线的内容进行合并即可。比如自带流水线需要使用 cosgin 对打包的容器镜像进行签名和验证,防止镜像被篡改:
stages:- singature- verficationimage-singature:stage: singaturetags:- cosignimage: name: dllhb/cosign:1.0.0entrypoint: [""]before_script:- mkdir ~/.docker- cat "$DOCKER_CRED_FILE" > ~/.docker/config.json- cat "$COSIGN_KEY" > /tmp/cosign.key- export COSIGN_PASSWORD="$COSIGN_PASSWORD"script:- cosign sign --key /tmp/cosign.key $CI_REGISTRY_IMAGE:1.0.0image-verfication:stage: verficationtags:- cosignimage: name: dllhb/cosign:1.0.0entrypoint: [""]before_script:- cat "$COSIGN_PUB" > /tmp/cosign.pub- export COSIGN_PASSWORD="$COSIGN_PASSWORD"script:- cosign verify --key /tmp/cosign.pub $CI_REGISTRY_IMAGE:1.0.0
需要将上述流水线引入到合规流水线当中:
include:- project: 'Compliance-Pipeline-Group/regular-pipeline'file: '.gitlab-ci.yml'
最终该群组下的其他项目的流水线都会执行容器镜像的打包、扫描、签名及验证这四个步骤。
因此合规框架的选择,是为了标记某些项目必须满足某些合规要求或者需要额外的监督,然后通过执行合规流水线来完成合规工作的完成。
相关文章:

极狐GitLab 企业级 CI/CD 规模化落地实践指南(一)
目录 template 引用,减少代码冗余,增强 CI/CD 构建扩展性 问题 1:代码冗余,低效实践 问题 2:维护性难,工作量大 ➤ local ➤ file ➤ remote ➤ template 收益 1:一处修改,多…...

springBoot 简单的demo
springBoot 学习开始 场景开发流程1、创建项目2、导入依赖3、创建启动springBoot 项目的主入口程序4、创建业务程序5、在MainApplication文件运行程序6、将文件打包成jar包 遇到的问题未解决 希望大哥们帮忙--本地运行jar包报错 场景 浏览器发送hello请求,返回“he…...
[国产MCU]-BL602开发实例-实时时钟(RTC)
RTC 文章目录 RTC1、RTC介绍2、RTC使用实例RTC(real-time clock)为操作系统中的实时时钟设备,为操作系统提供精准的实时时间和定时报警功能。当设备下电后,通过外置电池供电,RTC继续记录操作系统时间;设备上电后,RTC提供实时时钟给操作系统,确保断电后系统时间的连续性。…...

大数据Flink(六十三):SqlClient工具的使用
文章目录 SqlClient工具的使用 一、入门...

哈威比例多路阀控制放大器
多路比例阀放大器控制负载敏感原理的比例多路换向阀,它用于与负载无关的、无级调节液压执行元件的运动速度。 多个执行元件可以同时和相互无关地进行工作。 这种类型的阀主要用于行走液压机械(例如:起重控制系统)。 通过选择执行元…...
Java bean 是个什么概念?
Java bean可以把它比作一个"智能的容器",它具备封装数据的能力。 Java bean是一种可重用的软件组件,它主要用于在Java应用程序中存储和传递数据。它是一种符合特定规范的Java类,通过封装数据和提供访问方法,使数据的管…...

微服务系列文章之 Springboot+Vue实现登录注册
一、springBoot 创建springBoot项目 分为三个包,分别为controller,service, dao以及resource目录下的xml文件。 UserController.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 …...
【Docker】如何在设计 dockerfile 过程中,设置容器启动后的定时任务
如何在设计 dockerfile 过程中,设置容器启动后的定时任务 jwensh 2023.08.14 文章目录 如何在设计 dockerfile 过程中,设置容器启动后的定时任务1. 基于 alpine 设计 dockerfile 过程中,设置容器启动后的定时任务2. 基于 CentOS 设计 Dockerf…...
【leetcode】第三章 哈希表part01
242.有效的字母异位词 使用HashMap public boolean isAnagram(String s, String t) {HashMap<Character,Integer> map new HashMap();int sLen s.length();int tLen t.length();if (sLen ! tLen) return false;// 统计词频for (int i 0; i < s.length(); i) {ch…...

Docker中Tomcat部署步骤
第一次访问没有东西。...
pycharm 安装库
这是另一种方式。 搜索到的安装库的方式多数是:在桌面上winR键运行终端,输入命令,安装不了,发现安装不了。 1、打开pycharm; 2、软件下部的Terminal终端(需要运行一个代码才能出现,任何代码都可)…...

使用 Ploomber、Arima、Python 和 Slurm 进行时间序列预测
推荐:使用 NSDT场景编辑器助你快速搭建可二次编辑的3D应用场景 简短的笔记本说明 笔记本由 8 个任务组成,如下图所示。它包括建模的大多数基本步骤 - 获取数据清理、拟合、超参数调优、验证和可视化。作为捷径,我拿起笔记本并使用Soorgeon工具…...

springboot第35集:微服务与flutter安卓App开发
Google Playplay.google.com/apps/publis…[1]应用宝open.qq.com/[2]百度手机助手app.baidu.com/[3]360 手机助手dev.360.cn/[4]vivo 应用商店dev.vivo.com.cn/[5]OPPO 软件商店(一加)open.oppomobile.com/[6]小米应用商店dev.mi.com/[7]华为应用市场dev…...
java 把list转成json
在Java中,将List转换成JSON格式是非常常见的任务。JSON是一种轻巧的数据交换格式,非常适合于Web应用程序,特别是前端开发。 使用Java将List转换成JSON格式的最简单方法是通过JSON库。最常用的JSON库是 Jackson,它提供了快速&…...

R语言实现随机生存森林(2)
library(survival) library(randomForestSRC) help(package"randomForestSRC") #构建普通的随机生存森林 data(cancer,package"survival") lung$status<-lung$status-1 rfsrc.fit1 <- rfsrc(Surv(time, status) ~ ., lung,ntree 100,block.size 1,…...
泛型类接口方法学习
一、泛型 1 概念 泛型(Generics),广泛的类型。最大用途是给集合容器添加标签,让开发人员知道容器里面放到是什么类型,并且自动对放入集合的元素进行类型检查。 类比实参和形参,我们在对方法中的变量操作时,并没有指…...

Docker自动化部署安装(十)之安装SonarQube
这里选择的是: sonarqube:9.1.0-community (推荐使用) postgres:9.6.23 数据库(sonarqube7.9及以后便不再支持mysql,版本太低的话里面的一些插件会下载不成功的) 1、docker-sonarqube.yml文件 version: 3 services:sonarqube:container_name: sonar…...
[QT/C++]如何得知鼠标事件是由触摸事件转换而来的,使得鼠标触摸事件分离
依据来源:https://doc.qt.io/qt-5/qml-qtquick-mouseevent.html 具体是在event事件或者mouse系列事件中捕获到鼠标事件后,用如下代码判断鼠标事件是否由触摸事件转换而来的 if(mouseEvent->source()Qt::MouseEventSynthesizedBySystem){qDebug()<&…...

消防态势标绘工具,为消防基层工作助力
背景介绍 无人机测绘技术在消防领域的应用越来越普及,高清的二维正射影像和倾斜摄影实景三维模型能为消防态势标绘提供高质量的素材,消防队急需一个简便易用的、能够基于这些二三维的高清地图成果进行态势标绘的工具软件,使得消防“六熟悉”…...

网络协议栈-基础知识
1、分层模型 1.1、OSI七层模型 1、OSI(Open System Interconnection,开放系统互连)七层网络模型称为开放式系统互联参考模型 ,是一个逻辑上的定义,一个规范,它把网络从逻辑上分为了7层。 2、每一层都有相关…...

地震勘探——干扰波识别、井中地震时距曲线特点
目录 干扰波识别反射波地震勘探的干扰波 井中地震时距曲线特点 干扰波识别 有效波:可以用来解决所提出的地质任务的波;干扰波:所有妨碍辨认、追踪有效波的其他波。 地震勘探中,有效波和干扰波是相对的。例如,在反射波…...

解决Ubuntu22.04 VMware失败的问题 ubuntu入门之二十八
现象1 打开VMware失败 Ubuntu升级之后打开VMware上报需要安装vmmon和vmnet,点击确认后如下提示 最终上报fail 解决方法 内核升级导致,需要在新内核下重新下载编译安装 查看版本 $ vmware -v VMware Workstation 17.5.1 build-23298084$ lsb_release…...
数据链路层的主要功能是什么
数据链路层(OSI模型第2层)的核心功能是在相邻网络节点(如交换机、主机)间提供可靠的数据帧传输服务,主要职责包括: 🔑 核心功能详解: 帧封装与解封装 封装: 将网络层下发…...
实现弹窗随键盘上移居中
实现弹窗随键盘上移的核心思路 在Android中,可以通过监听键盘的显示和隐藏事件,动态调整弹窗的位置。关键点在于获取键盘高度,并计算剩余屏幕空间以重新定位弹窗。 // 在Activity或Fragment中设置键盘监听 val rootView findViewById<V…...
iOS性能调优实战:借助克魔(KeyMob)与常用工具深度洞察App瓶颈
在日常iOS开发过程中,性能问题往往是最令人头疼的一类Bug。尤其是在App上线前的压测阶段或是处理用户反馈的高发期,开发者往往需要面对卡顿、崩溃、能耗异常、日志混乱等一系列问题。这些问题表面上看似偶发,但背后往往隐藏着系统资源调度不当…...
return this;返回的是谁
一个审批系统的示例来演示责任链模式的实现。假设公司需要处理不同金额的采购申请,不同级别的经理有不同的审批权限: // 抽象处理者:审批者 abstract class Approver {protected Approver successor; // 下一个处理者// 设置下一个处理者pub…...
python爬虫——气象数据爬取
一、导入库与全局配置 python 运行 import json import datetime import time import requests from sqlalchemy import create_engine import csv import pandas as pd作用: 引入数据解析、网络请求、时间处理、数据库操作等所需库。requests:发送 …...
日常一水C
多态 言简意赅:就是一个对象面对同一事件时做出的不同反应 而之前的继承中说过,当子类和父类的函数名相同时,会隐藏父类的同名函数转而调用子类的同名函数,如果要调用父类的同名函数,那么就需要对父类进行引用&#…...

解析两阶段提交与三阶段提交的核心差异及MySQL实现方案
引言 在分布式系统的事务处理中,如何保障跨节点数据操作的一致性始终是核心挑战。经典的两阶段提交协议(2PC)通过准备阶段与提交阶段的协调机制,以同步决策模式确保事务原子性。其改进版本三阶段提交协议(3PC…...

对象回调初步研究
_OBJECT_TYPE结构分析 在介绍什么是对象回调前,首先要熟悉下结构 以我们上篇线程回调介绍过的导出的PsProcessType 结构为例,用_OBJECT_TYPE这个结构来解析它,0x80处就是今天要介绍的回调链表,但是先不着急,先把目光…...