1.云原生DevOps落地方案
2.nmap扫描的-P0和-Pn参数的区别
3.多个系统源代码暴露在互联网,超四百万公民个人隐私信息存在泄露的风险
4.3d稀疏卷积——spconv源码剖析(三)
云原生DevOps落地方案
DevOps简述
顾名思义,DevOps是开发(Development)与运维(Operations)的融合,旨在打破开发与运维之间的隔阂,促进开发、运营和质量保障(QA)等部门之间的溯源码项目交流与协作。通过小规模、快速迭代的方式开发和部署产品,以便快速应对客户需求的变化。DevOps强调开发运维一体化,强化团队间的沟通与快速反馈,实现快速交付产品和提高交付质量。
DevOps并非新工具集,而是一种思想、一种文化,旨在改变传统开发运维模式,采用最佳实践。通常通过CI/CD(持续集成、持续部署)自动化工具和流程实现DevOps理念,以流水线形式改变开发人员和测试人员发布软件的方式。随着Docker和Kubernetes(以下简称k8s)等技术的普及,容器云平台基础设施不断完善,加速了开发和运维角色的融合,使云原生的DevOps实践成为未来趋势。以下将基于混合容器云平台详细讲解云原生DevOps的落地方案。
云原生DevOps特点
DevOps是PaaS平台中关键功能模块,包括以下重要能力:支持代码克隆、编译代码、运行脚本、构建发布镜像、部署yaml文件以及部署Helm应用等环节;支持丰富的流水线设置,如资源限额、流水线运行条数、推送代码以及推送镜像触发流水线运行等,提供端到端高效流水线能力;提供开箱即用的对话小说源码镜像仓库中心;提供流水线缓存功能,可自由配置整个流水线或每个步骤的运行缓存,在代码克隆、编译代码、构建镜像等步骤利用缓存缩短运行时间,提升执行效率。
云原生DevOps实现
简单来说,云原生DevOps内部功能设计主要通过k8s提供的自定义controller功能实现,基本逻辑是根据业务需求抽象出多个CRD(Custom Resource Definition,自定义资源对象),编写对应的controller实现业务逻辑。为了实现CI/CD功能,抽象出多个CRD对象,如下所示:
我们知道配置流水线通常需要对接代码仓库,包括仓库地址、仓库授权信息等,因此需要3个CRD对象来记录源代码仓库的相关信息。
设计好DevOps中与仓库相关的3个CRD对象后,需要再定义3个CRD对象来描述流水线相关的信息。
pipeline步骤功能有多种类型,包括运行脚本、构建发布镜像、发布应用模板、部署YAML、部署应用等。为了提供这些功能,采用Jenkins作为底层CI/CD工具,docker registry作为镜像仓库中心,minio作为日志存储中心等。这些服务运行在pipeline所在项目的命名空间下。综上,设计的CI/CD系统功能实现逻辑如下:
如上,第一次运行流水线时,系统会在数据面k8s中部署Jenkins、minio等基础工具的升级 c 源码服务,同时在管理面启动一个goroutine,实时同步数据面中流水线的作业状态到管理面的CRD对象中。当触发pipeline执行逻辑时,会产生一个pipelineExecution CRD对象,记录本次运行pipeline的状态信息。当goroutine(syncState)发现有新的执行实例产生时,会通过Jenkins引擎接口启动Jenkins server端流水线作业的运行,Jenkins server端收到信息后会启动单独的一个Jenkins slave pod进行流水线作业的响应。同时,goroutine(syncState)会不断通过引擎接口轮询pipeline执行实例的运行情况,更新pipelineExecution CRD的状态(运行成功或失败等)。当pipeline执行实例发生状态变化时,会触发其对应的controller业务逻辑,通过Jenkins引擎接口与Jenkins server通信进行不同操作,如暂停流水线的运行、运行完毕清除不需要的资源等。当流水线作业发生状态变化时,又会通过goroutine(syncState)更改pipeline执行实例的状态,进而触发对应的controller业务代码进行不同业务逻辑处理,循环往复,直至流水线运行结束。这就是整个pipeline执行时的一个逻辑流程。
CRD定义
以下是详细的CRD结构体讲解,敏感信息使用了’*‘代替。
pipelineSetting:该结构体保存着整个项目下所有pipeline的运行环境信息,如CPU/内存资源限额、缓存路径以及流水线运行的最大并行个数等,不同功能的配置信息保存在不同的CRD下。
pipeline:该结构体记录着流水线的配置元信息,如该流水线对接哪个项目代码、与仓库通信的认证信息以及上次该流水线运行的结果等。如下图所示:
详细的结构字段讲解如下:
pipelineExecution:流水线执行实例,每当流水线运行一次,会产生一个该对象记录着流水线的芙清源码执行结果等信息。如下图所示:
详细的结构字段讲解如下:
至此,我们完成了流水线功能的基础对象定义。
controller实现
除了抽象出对应的CRD外,还需要编写对应的controller代码实现对应的业务逻辑,如当pipeline运行时,需要产生pipeline执行实例,并实时同步其运行的状态信息等。
当触发流水线执行逻辑时,系统会根据pipeline CRD对象和该流水线对应的代码仓库中的配置文件(.cubepaas.devops.yml)产生一个pipelineExecution CRD对象,这时会触发pipelineExecution对应的controller运行业务逻辑。以下只摘取重要的代码逻辑,如下所示:
其中,deploy函数的逻辑是第一次运行时通过判断数据面中是否存在pipeline的命名空间,如果存在就代表基础资源已经配置完成,直接走reconcileRb函数,该函数的逻辑见下面;如果不存在,就会在数据面中初始化必要的基础资源,如pipeline命名空间、Jenkins、docker、minio服务、配置configMap、secret等。
reconcileRb函数的功能是遍历所有namespace,对其调谐rolebindings,目的是让pipeline serviceAccount(jenkins)对该project下的所有namespace具有所需的操作权限,这样Jenkins server才能够在数据面中正常提供CI/CD基础服务。
goroutine(syncState)的代码逻辑比较简单,当产生新的pipeline执行实例时就会启动Jenkins server端流水线作业的运行并实时同步其运行状态到pipeline执行实例中。代码逻辑如下:
缓存支持
云环境下的流水线是通过启动容器来运行具体的功能步骤,每次运行流水线可能会被调度到不同的计算节点上,这会导致一个问题:容器运行完不会保存数据,每当流水线重新运行时,又会重新拉取代码、jsoup源码android编译代码、下载依赖包等,失去了本地宿主机编译代码、构建镜像时缓存的作用,大大延长了流水线运行时间,浪费了很多不必要的时间、网络和计算成本等。为了提高用户使用流水线的体验,加入支持缓存的功能。
为了让流水线具有缓存功能,需要在流水线运行时加入持久化数据的能力。首先想到的是k8s提供的本地持久化存储(即Local Persistent Volume,以下简称Local PV),或依赖远程存储服务器来提供持久化,远程存储效率依赖于网络,并且还需要保证远程存储高可用,这会带来很多复杂性,也一定程度上失去了缓存的作用。综合考虑,我们选择本地存储实现缓存,但是k8s提供的Local PV是需要和节点绑定在一起的,也就是说一旦流水线调度到某个节点上运行,那么下次运行还会绑定到该节点运行,虽然实现了缓存的作用,但是也造成了流水线每次只能在该节点上运行,如果有多条流水线同时跑,可能会导致该节点资源耗尽或者缓存冲突,失去了云平台本身根据资源使用情况平衡调度的特性。
因此,为了平衡缓存与调度间的关系,我们采用了挂载hostPath Volume方式,这样依托于k8s强大的容器调度能力,我们可以同时运行很多条流水线而不用担心资源耗尽或缓存冲突的问题,但是流水线每次运行时可能会被调度到不同的节点上,如果当前节点没有运行过流水线,则起不到缓存的作用。那么如何解决hostPath Volume缓存与调度间的尴尬关系呢?我们巧妙地利用了k8s提供的亲和性调度特性,当流水线运行时我们会记录当前运行节点,下次运行时通过设置Pod的亲和性优先调度到该节点上,随着流水线运行次数越来越多,我们会得到一个运行节点列表。如下所示:
执行实例调度信息会保存到pipeline CRD对象中,每次运行流水线时,系统会根据节点列表设置Pod的亲和性,默认我们会取最近运行流水线的个节点,原则是最近运行流水线的节点优先级越高。代码如下:
创新性的“Hostpath Volume + 亲和性调度”缓存设计方案,不仅实现了流水线的并发性缓存功能,而且实现复杂度低,可自由配置任一阶段、步骤的缓存开关以及缓存路径。无缓存与有缓存运行的对比如下图所示,可见通过缓存加速大大提高了流水线的运行效率。
HCaaS DevOps使用
以上设计在HCaaS平台上得到实现()。在HCaaS控制台上点击DevOps标签,通过代码授权后,即可通过UI界面轻松地编辑流水线,也可通过编辑yaml文件配置具体的功能步骤,如图所示:
通过点击查看日志,你可以看到pipeline各个阶段运行的详细日志信息,如下图所示:
注意首次运行pipeline时系统会从网络下载Jenkins、docker、minio以及其他pipeline-tools镜像,请稍作等待。如果长时间未运行,请查看网络是否有问题。
nmap扫描的-P0和-Pn参数的区别
1.-P0和-Pn两个选项的效果是一样的,就是不进行主机发现,而直接进行更深层次的扫描,如服务版本扫描或系统类型扫描。
2.有两处说明-P0和-Pn的效果是一样的。
一、man和help的解释
这是man nmap对-P0的解释
-P0: Treat all hosts as online -- skip host discovery
这是nmap --help对-Pn的解释
-Pn: Treat all hosts as online -- skip host discovery
两处解释一样,可以证明-P0和-Pn参数的效果一样。
二、nmap的源代码
在nmap的源代码:zenmap/zenmapCore/NmapOptions.py中有
# Sets of options that should be treated as equivalent from the point of
# view of the external interface. For example, ops["--timing"] means the
# same thing as ops["-T"].
EQUIVALENT_OPTIONS = (
("debug", "d"),
("help", "h"),
("iL", "i"),
("max-parallelism", "M"),
("osscan-guess", "fuzzy"),
("oG", "oM", "m"),
("oN", "o"),
("sP", "sn"),
("P", "PE", "PI"),
("PA", "PT"),
("P0", "PD", "PN", "Pn"),
("rH", "randomize-hosts"),
("source-port", "g"),
("timing", "T"),
("verbose", "v"),
("version", "V"),
For example, ops["--timing"] means the
# same thing as ops["-T"]
这句话的解释就是--timing和-T的参数效果一样,所以以此类推:-P0、-PD、-PN、-Pn四个参数效果一样。
多个系统源代码暴露在互联网,超四百万公民个人隐私信息存在泄露的风险
截至年3月,绿盟科技创新研究院监测到上万个互联网中暴露的DevOps资产存在未授权访问情况,源代码仓库成为“重灾区”。这些暴露的源代码仓库包含了境内多家机构的重要系统源代码,部分源代码中硬编码了数据存储服务配置信息,存在敏感信息意外泄露的风险。事件敏感,以下仅示例部分脱敏案例,并已上报给相关监管机构。
案例1:某沿海地区的科技公司使用Gitblit维护多个医疗IT系统源代码时配置错误,导致这些系统存在未经授权的访问漏洞。结果,包括某大学附属医院的排班系统在内的多个平台源代码被公开暴露在互联网上。暴露源代码中包含数据库连接详细信息,导致约万名病人的姓名、身份证号、住址等信息以及近1万名医护人员的姓名、****、学历和身份证等个人隐私信息暴露,存在严重隐私泄露风险。
案例2:某互联网科技有限公司使用Gogs维护开发系统的源代码时配置错误,系统被暴露在互联网中并允许未经授权访问。暴露源代码中含有详细的数据库连接信息,导致大约万公民的姓名、手机号、身份证号码等个人隐私信息暴露,存在严重隐私数据泄露风险。
案例3:某教育科技有限公司使用Gitea维护开发系统的源代码时配置错误,系统存在未经授权的访问漏洞。暴露源代码中包含数据库连接详细信息,导致大约万学员姓名、手机、QQ号等个人隐私信息暴露,存在严重隐私数据泄露风险。
此类安全事件不仅暴露了系统的源代码,还暴露了公民的个人隐私信息及敏感数据。这些泄露可能带来数据被不法分子出售、公民面临电诈风险、安全漏洞暴露以及关键基础设施单位存在安全隐患等严重后果。案例显示,数据泄露风险来源于配置错误,导致源代码、敏感信息被不安全方式暴露在互联网上。
云计算技术广泛应用,但带来了安全风险问题。DevOps流程在提升开发、测试和部署效率的同时,也引入了云上安全风险,尤其是源代码、敏感信息的不当管理。绿盟科技创新研究院通过云上网络空间的测绘,揭示云组件暴露面,识别攻击面,以深入了解可能隐藏的安全风险。
针对此类事件,监管部门开始采取行动。如衡阳市网信办对某开发应用网站数据库存在未授权访问漏洞、泄露公民个人信息的公司进行了行政处罚。企业可通过利用绿盟公有云测绘技术、敏感泄露发现服务以及EASM服务,加强自身风险暴露面的发现与防护。定期对内外部和上下游供应链人员进行安全培训,也能有效减少数据泄露事件。
综上,源代码暴露事件对国家安全、关键基础设施单位、企业和公民隐私构成严重威胁。应加强技术监控、提高安全意识、定期进行安全培训,以有效应对云上安全风险。
3d稀疏卷积——spconv源码剖析(三)
构建Rulebook
下面看ops.get_indice_pairs,位于:spconv/ops.py
构建Rulebook由ops.get_indice_pairs接口完成
get_indice_pairs函数具体实现:
主要就是完成了一些参数的校验和预处理。首先,对于3d普通稀疏卷积,根据输入shape大小,kernel size,stride等参数计算出输出输出shape,子流行稀疏卷积就不必计算了,输出shape和输入shape一样大小
准备好参数之后就进入最核心的get_indice_pairs函数。因为spconv通过torch.ops.load_library加载.so文件注册,所以这里通torch.ops.spconv.get_indice_pairs这种方式来调用该函数。
算子注册:在src/spconv/all.cc文件中通过Pytorch提供的OP Register(算子注册的方式)对底层c++ api进行了注册,可以python接口形式调用c++算子
同C++ extension方式一样,OP Register也是Pytorch提供的一种底层扩展算子注册的方式。注册的算子可以通过 torch.xxx或者 tensor.xxx的方式进行调用,该方式同样与pytorch源码解耦,增加和修改算子不需要重新编译pytorch源码。用该方式注册一个新的算子,流程非常简单:先编写C++相关的算子实现,然后通过pytorch底层的注册接口(torch::RegisterOperators),将该算子注册即可。
构建Rulebook实际通过python接口get_indice_pairs调用src/spconv/spconv_ops.cc文件种的getIndicePairs函数
代码位于:src/spconv/spconv_ops.cc
分析getIndicePairs直接将重心锁定在GPU逻辑部分,并且子流行3d稀疏卷积和正常3d稀疏卷积分开讨论,优先子流行3d稀疏卷积。
代码中最重要的3个变量分别为:indicePairs,indiceNum和gridOut,其建立过程如下:
indicePairs代表了稀疏卷积输入输出的映射规则,即Input Hash Table 和 Output Hash Table。这里分配理论最大的内存,它的shape为{ 2,kernelVolume,numAct},2表示输入和输出两个方向,kernelVolume为卷积核的volume size。例如一个3x3x3的卷积核,其volume size就是(3*3*3)。numAct表示输入有效(active)特征的数量。indiceNum用于保存卷积核每一个位置上的总的计算的次数,indiceNum对应中的count
代码中关于gpu建立rulebook调用create_submconv_indice_pair_cuda函数来完成,下面具体分析下create_submconv_indice_pair_cuda函数
子流线稀疏卷积
子流线稀疏卷积是调用create_submconv_indice_pair_cuda函数来构建rulebook
在create_submconv_indice_pair_cuda大可不必深究以下动态分发机制的运行原理。
直接将重心锁定在核函数:
prepareSubMGridKernel核函数中grid_size和block_size实则都是用的整形变量。其中block_size为tv::cuda::CUDA_NUM_THREADS,在include/tensorview/cuda_utils.h文件中定义,大小为。而grid_size大小通过tv::cuda::getBlocks(numActIn)计算得到,其中numActIn表示有效(active)输入数据的数量。
prepareSubMGridKernel作用:建立输出张量坐标(通过index表示)到输出序号之间的一张哈希表
见:include/spconv/indice.cu.h
这里计算index换了一种模板加递归的写法,看起来比较复杂而已。令:new_indicesIn = indicesIn.data(),可以推导得出index为:
ArrayIndexRowMajor位于include/tensorview/tensorview.h,其递归调用写法如下:
接着看核函数getSubMIndicePairsKernel3:
位于:include/spconv/indice.cu.h
看:
上述写法类似我们函数中常见的循环的写法,具体可以查看include/tensorview/kernel_utils.h
NumILP按默认值等于1的话,其stride也是gridDim.x*blockDim.x。索引最大值要小于该线程块的线程上限索引blockDim.x * gridDim.x,功能与下面代码类似:
参考: blog.csdn.net/ChuiGeDaQ...