基于docker的Jenkin的服务平台搭建

项目拓扑图

项目环境: jenkins-2.440 sonarqube-9.9.4 apache-maven-3.9.6 gitlab-ce-12.4.2 java17 docker20

harbor.v2.6.0 centos7.9

项目目的: 模拟企业构建一个流行的持续集成和持续部署环境,可以更轻松地创建和管理构建环境,实现自动化构建和部署应用程序的目标,同时基于docker就更灵活

项目步骤: 

一. 安装gitlab服务器,作为代码托管服务器

二. 配置jenkin服务器,作为CICD工具

三. 配置harbor作为镜像仓库,方便镜像的上传与拉取

四. 配置sonarqube实现对代码的审查功能

五. 将jenkins中的pipline文件配置,以及其他配置集合起来

六. 改进,设置jenkins的slave节点,实现分流

1. 安装gitlab,作为代码托管服务器

1.1 安装相关依赖

yum -y install policycoreutils openssh-server openssh-clients postfix

1.2 启动ssh服务&设置为开机启动

systemctl enable sshd && sudo systemctl start sshd

1.3 关闭防火墙,防止通信受阻

systemctl stop firewalld && systemctl disable firewalld

1.4 官方下载gitlab rpm包,并且安装

wget https://mirrors.tuna.tsinghua.edu.cn/gitlab-ce/yum/el6/gitlab-ce-12.4.2-ce.0.el6.x
86_64.rpm
rpm -ivh gitlab-ce-12.4.2-ce.0.el6.x86_64.rpm

1.5. 更改gitlab配置文件,监听地址和端口(防止端口冲突)

vi /etc/gitlab/gitlab.rb
external_url 'http://192.168.118.181:82'
nginx['listen_port'] = 82

1.6. 重新加载配置文件,重新启动gitlab,并且查看网页

gitlab-ctl reconfigure
gitlab-ctl restart

1.7 添加组,创建用户,创建项目

添加My-group组,设为私有

在组里面中创建项目

创建用户

创建密码

将plf用户添加到组里面去,设置为owner权限

2. 安装jenkins,作为持续集成工具

2.1 安装jdk17,jenkins需要依赖jdk

wget https://download.oracle.com/java/17/latest/jdk-17_linux-x64_bin.rpm
rpm -ivh jdk-17_linux-x64_bin.rpm

安装目录为: /usr/lib/jvm/jdk-17-oracle-x64/bin/java

2.2 下载jenkins,并且安装

wget https://get.jenkins.io/redhat/jenkins-2.452-1.1.noarch.rpm
rpm -ivh jenkins-2.452-1.1.noarch.rpm

2.3 更改jenkins配置文件(将启动用户改为root)

vim /usr/lib/systemd/system/jenkins.serviceUser=root
Group=root

2.4 重新加载配置文件,并且启动

systemctl daemon-reload
systemctl restart jenkins

2.5 登录jenkins网站,进行相关配置

初始配置密码  cat /var/lib/jenkins/secrets/initialAdminPassword

2.6 安装Role 角色管理插件,实现对项目的更细颗粒度管理

2.7 开启全局角色安全配置

2.8 创建相关角色,分配权限

创建rolebase角色,分配全局登录权限

创建项目角色role1,分配匹配到的项目的所有权限

2.9 创建用户,为用户分配相关角色

创建plf用户

将用户分配角色,rolebase和role1,实现登录功能以及对项目的管理

用plf用户进行登录,只可以看到My.用户开头的项目

2.10 安装git插件以及凭证插件,以及git工具

 安装git

yum install -y git

安装git插件以及crendiential

2.11 在gitlab服务器和jenkins设置ssh免密登录,以及凭证设置

[root@jenkins ~]# ssh-keygen -t rsa
[root@jenkins ~]# ssh-copy-id root@192.168.118.181

在gitlab ui界面中也要设置上传 公钥

在jenkins上设置ssh gitlab的凭证,将jenkins私钥添加进去,进行SSH验证

在My_pro项目中进行配置 git服务器 以及 凭证

进行构建,测试是否成功

2.12 安装maven工具

下载maven,并且安装

wget https://dlcdn.apache.org/maven/maven-3/3.9.6/binaries/apache-maven-3.9.6-bin.tar.gz
tar -xvf apache-maven-3.9.6-bin.tar.gz

移动到/opt/maven 目录,并且加入环境变量中

mv apache-maven-3.9.6/* /opt/mavenvim /etc/profile
export MAVEN_HOME=/opt/maven
export PATH=$PATH:$MAVEN_HOME/binsource /etc/profilemvn -v 查看版本

2.13 在jenkins中配置指定maven和jdk的路径

配置环境变量

2.14 设置maven本地仓库,更改aliyun镜像地址

mkdir /root/repo
vi /opt/maven/conf/settings.xml#将repo 仓库改
/root/repo/#添加aliyun私服地址
http://maven.aliyun.com/nexus/content/groups/public/

2.15 Git hook自动触发构建

#轮询SCM性能不佳

开启流水线中的 webhook触发器

默认gitlab不支持,所以gitlab上也要进行配置开启,允许webhook服务

并且还要配置,webhook指向的jenkins项目地址

最后 关闭认证过程,gitlab的

最后测试,认证成功

2.16 构建邮箱触发通知

开启网易发送邮件功能,保存授权密码 VLMQSHORTMDCAKVD

在jenkins配置邮件服务器相关参数

 配置网易邮件凭证

进行测试,邮箱构建成功

设置邮件发送模板

<!DOCTYPE html>
<html>
<head><meta charset="UTF-8"><title>${ENV, var="JOB_NAME"}-第${BUILD_NUMBER}次构建日志</title>
</head><body leftmargin="8" marginwidth="0" topmargin="8" marginheight="4"offset="0">
<table width="95%" cellpadding="0" cellspacing="0"style="font-size: 11pt; font-family: Tahoma, Arial, Helvetica, sans-serif"><tr><td>(本邮件是程序自动下发的1,请勿回复!)</td></tr><tr><td><h2><font color="#0000FF">构建结果 - ${BUILD_STATUS}</font></h2></td></tr><tr><td><br /><b><font color="#0B610B">构建信息</font></b><hr size="2" width="100%" align="center" /></td></tr><tr><td><ul><li>项目名称&nbsp;:&nbsp;${PROJECT_NAME}</li><li>构建编号&nbsp;:&nbsp;第${BUILD_NUMBER}次构建</li><li>触发原因:&nbsp;${CAUSE}</li><li>构建日志:&nbsp;<a href="${BUILD_URL}console">${BUILD_URL}console</a></li><li>构建&nbsp;&nbsp;Url&nbsp;:&nbsp;<a href="${BUILD_URL}">${BUILD_URL}</a></li><li>工作目录&nbsp;:&nbsp;<a href="${PROJECT_URL}ws">${PROJECT_URL}ws</a></li><li>项目&nbsp;&nbsp;Url&nbsp;:&nbsp;<a href="${PROJECT_URL}">${PROJECT_URL}</a></li></ul></td></tr><tr><td><b><font color="#0B610B">Changes Since LastSuccessful Build:</font></b><hr size="2" width="100%" align="center" /></td></tr><tr><td><ul><li>历史变更记录 : <a href="${PROJECT_URL}changes">${PROJECT_URL}changes</a></li></ul> ${CHANGES_SINCE_LAST_SUCCESS,reverse=true, format="Changes for Build #%n:<br />%c<br />",showPaths=true,changesFormat="<pre>[%a]<br />%m</pre>",pathFormat="&nbsp;&nbsp;&nbsp;&nbsp;%p"}</td></tr><tr><td><b>Failed Test Results</b><hr size="2" width="100%" align="center" /></td></tr><tr><td><prestyle="font-size: 11pt; font-family: Tahoma, Arial, Helvetica, sans-serif">$FAILED_TESTS</pre><br /></td></tr><tr><td><b><font color="#0B610B">构建日志 (最后 100行):</font></b><hr size="2" width="100%" align="center" /></td></tr><tr><td><textarea cols="80" rows="30" readonly="readonly"style="font-family: Courier New">${BUILD_LOG, maxLines=100}</textarea></td></tr>
</table>
</body>
</html>
3 安装SonarQube实现代码审查

3.1 安装postsql且创建sonar数据库(当前的sonarqube已经不支持,mysql)

sudo yum install -y https://download.postgresql.org/pub/repos/yum/reporpms/EL-6-x86_64/pgdg-redhat-repo-latest.noarch.rpm
sudo yum install -y postgresql15-server
sudo service postgresql-15 initdb
sudo chkconfig postgresql-15 on
sudo service postgresql-15 startsystemctl enable postgresql-15
systemctl start postgresql-15
[root@jenkins conf]# su postgres
bash-4.2$ psql
psql (15.6)
Type "help" for help.postgres=# create database sonar;

3.2 安装sonarqube(java版本为17)

https://binaries.sonarsource.com/Distribution/sonarqube/sonarqube-9.9.4.87374.zip

下载完成后上传到linux服务器中

[root@jenkins ~]# unzip sonarqube-9.9.4.87374.zip
[root@jenkins ~]# mv sonarqube-9.9.4.87374/* /opr/sonar

准备环境并且配置相关配置

[root@jenkins opt]# useradd sonar   #创建sonar用户配置用于启动sonar
[root@jenkins opt]# chmod -R sonar:sonar sonar #将文件权限的所属都改为sonar[root@jenkins opt]# vim sonar/conf/sonar.properties
sonar.jdbc.username=postgres   #设置为数据库的账户和密码;默认postsql就会生成postgres和密码
sonar.jdbc.password=postgressonar.jdbc.url=jdbc:postgresql://localhost/sonar 
#设置连接的数据库的地址和数据库

 启动sonar使用sonar用户启动

su sonar /opt/sonar/bin/linux-x86-64/sonar.sh start

启动成功,访问 192.168.118.182:9000 (端口可以在配置文件中更改)https://binaries.sonarsource.com/Distribution/sonarqube/sonarqube-9.9.4.87374.zip

3.3 Sonar和Jenkins整合实现代码审查

首先在jenkins中安装sonarqube scanner的插件

在安装sonarscanner的软件

在jenkins中配置sonarqube服务器的环境

获取token并且配置sonarqube凭证 squ_d631e058089b8927f2da702ce55b178bcd4eb149

4. Harbor仓库搭建

4.1 首先先安装Docker并且启动docker

yum install -y epel-release
yum install -y yum-utils
yum-config-manager     --add-repo     https://mirrors.ustc.edu.cn/docker-ce/linux/centos/docker-ce.repo
yum install -y docker-ce docker-ce-cli containerd.io
systemctl start docker
cat >>/etc/docker/daemon.json <<EOF
{"registry-mirrors":["https://reg-mirror.qiniu.com"]}
EOF
systemctl daemon-reload
systemctl restart docker

4.2 下载harbor压缩包,并且安装

wget https://github.com/goharbor/harbor/releases/download/v2.10.2/harbor-offline-installer-v2.10.2.tgztar -xvf harbor-offline-installer-v2.10.2.tgz

更改配置文件,设置为本机ip地址

vim /opt/harbor/harbor.yml

4.3 启动harbor 安装文件,下载相关镜像

4.3 进行访问 harbor 

4.4 添加用户,创建项目,分配角色

5 准备测试服务器,并且将jenkins进行联动

5.1 在测试机器上安装docker,初始化环境

5.2 编写dockerfile文件,进行镜像的构建

#FROM java:8
FROM openjdk:8-jdk-alpine
ARG JAR_FILE
COPY ${JAR_FILE} app.jar
EXPOSE 9001
ENTRYPOINT ["java","-jar","/app.jar"]

5.3 编写sonar文件,进行审查

# must be unique in a given SonarQube instance
sonar.projectKey=My_pro
# this is the name and version displayed in the SonarQube UI. Was mandatory prior to SonarQube 6.1.
sonar.projectName=My_pro
sonar.projectVersion=1.0# Path is relative to the sonar-project.properties file. Replace "\" by "/" on Windows.
# This property is optional if sonar.modules is set.
sonar.sources=.
sonar.exclusions=**/test/**,**/target/**
sonar.java.binaries=.sonar.java.source=17
sonar.java.target=17
#sonar.java.libraries=**/target/classes/**# Encoding of the source code. Default is default system encoding
sonar.sourceEncoding=UTF-8

5.3 编写jenkins流水线脚本,实现代码的拉取,审查,编译,打包,上传,部署

//git凭证ID
def git_auth = "5011e58f-4eef-4a0b-abf3-141adc28972b"
//git的url地址
def git_url = "git@192.168.118.181:itheima/tensquare_back.git"
//镜像的版本号
def tag = "latest"
//Harbor的url地址
def harbor_url = "192.168.118.184:85"
//镜像库项目名称
def harbor_project = "tensquare"
//Harbor的登录凭证ID
def harbor_auth = "9b338fcd-6db0-43df-be49-667f8f736299"
node{stage('拉取代码'){checkout scmGit(branches: [[name: "*/${branch}"]], extensions: [], userRemoteConfigs: [[credentialsId: "${git_auth}", url: "${git_url}"]])}stage("代码审查"){def scannerHome = tool 'sonar-scanner'//引用当前JenkinsSonarQube环境withSonarQubeEnv('sonarqube') {sh """cd ${project_name}${scannerHome}/bin/sonar-scanner"""}}stage('编译,工程,上传镜像'){sh 'mvn -f ${project_name} clean package dockerfile:build'def imageName="${project_name}:${tag}"sh "docker tag ${imageName} ${harbor_url}/${harbor_project}/${imageName}"withCredentials([usernamePassword(credentialsId: '9b338fcd-6db0-43df-be49-667f8f736299', passwordVariable: 'password', usernameVariable: 'username')]) {sh "docker login -u ${username} -p ${password} ${harbor_url}"sh "docker push ${harbor_url}/${harbor_project}/${imageName}"sh "echo 镜像上传成功"}}}

jenkin参数化构建,拉取代码过程,可能有不同的master分支参数,设置参数

编译项目,打标签,并且上传镜像

def imageName="${project_name}:${tag}"sh "docker tag ${imageName} ${harbor_url}/${harbor_project}/${imageName}"

(因为要登录harbor可能会设计到账户和密码,采取harbor的凭证ID)

5.4 在测试机上向harbor仓库拉去镜像,并且部署到机器上

 sshPublisher(publishers: [sshPublisherDesc(configName: 'master_server', transfers: [sshTransfer(cleanRemote: false, excludes: '', execCommand: "/opt/jenkins_shell/deploy.sh $harbor_url  $harbor_project $project_name $tag $port", execTimeout: 120000, flatten: false, makeEmptyDirs: false, noDefaultExcludes: false, patternSeparator: '[, ]+', remoteDirectory: '', remoteDirectorySDF: false, removePrefix: '', sourceFiles: '')], usePromotionTimestamp: false, useWorkspaceInPromotion: false, verbose: false)])

上传脚本到部署机器上  /opt/jenkins_shell/deploy.sh

#! /bin/sh
#接收外部参数
harbor_url=$1
harbor_project_name=$2
project_name=$3
tag=$4
port=$5imageName=$harbor_url/$harbor_project_name/$project_name:$tagecho "$imageName"#查询容器是否存在,存在则删除
containerId=`docker ps -a | grep -w ${project_name}:${tag}  | awk '{print $1}'`
if [ "$containerId" !=  "" ] ; then#停掉容器docker stop $containerId#删除容器docker rm $containerIdecho "成功删除容器"
fi#查询镜像是否存在,存在则删除
imageId=`docker images | grep -w $project_name  | awk '{print $3}'`if [ "$imageId" !=  "" ] ; then#删除镜像docker rmi -f $imageIdecho "成功删除镜像"
fi# 登录Harbor
docker login -u eric -p Harbor123456 $harbor_url# 下载镜像
docker pull $imageName# 启动容器
docker run -di -p $port:$port $imageNameecho "容器启动成功"

同时要设置ssh免密通道,将jenkins服务器上的公钥发送到测试机上

ssh-copy-id root@192.168.118.184

同时在jenkins中相关ssh配置,实现远程发送shell命令

6 进行代码上传,测试流程是否成功

6.1 将相关的配置放入到项目目录下

6.2 配置gitlab服务器地址

6.3 进行代码的上传

6.4 进行jenkins的构建

6.5 构建成功,进行访问,并且查看相关的日志输出

6.6 代码审查结果查看

6.7 邮件发送通知查看 

6.8 harbor查看相关的镜像是否上传成功

7. 改进,增加jenkins的slave节点

7.1 开启代理程序的TCP端口

7.2 新建节点

7.3 在slave 服务器上启动节点

curl -sO http://192.168.118.182:8888/jnlpJars/agent.jar
java -jar agent.jar -url http://192.168.118.182:8888/ -secret 80ae1fbe59ce71730735814ad979f55d82b7b5da3d088ac759c4cf2837bbe361 -name slave1 -workDir "/root/jenkins"

运行结果,显示成功

7.4 在jenkins中的pipline脚本中指定slave节点,即可指定slave运行

node('slave') {stage('check out') { checkout([$class: 'GitSCM', branches: [[name: '*/master']], 
doGenerateSubmoduleConfigurations: false, extensions: [], submoduleCfg: [], 
userRemoteConfigs: [[credentialsId: '68f2087f-a034-4d39-a9ff-1f776dd3dfa8', url: 
'git@192.168.66.100:itheima_group/tensquare_back_cluster.git']]])}
}

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

读天才与算法:人脑与AI的数学思维笔记03_AlphaGo

1. 国际象棋 1.1. 1997年计算机“深蓝”&#xff08;Deep Blue&#xff09;击败了顶尖国际象棋手&#xff0c;但机器取代数学研究机构还言之尚早 1.2. 下国际象棋与数学的形式化证明颇有相似之处&#xff0c;但学者认为中国围棋的思维方式更能够体现数学家思考的创造性和直觉…

使用lambda表达式Collectors.toMap 遇到的报错,带有源码分析

概述 正常hashMap中的key和value都允许为null&#xff0c;但是在list转map中&#xff0c;使用lambda表达式要求key和value都不能为null。这很反常识 起因 本身上游返回contentId和traceId 内容id和跟踪id&#xff0c;但是项目人员变动修改了接口没有给traceId导致 代码 pu…

kafka---topic详解

一、分区与高可用 在Kafka中,事件(events 事件即消息)是以topic的形式进行组织的;同时topic是分区(partitioned)的,这意味着一个topic分布在Kafka broker上的多个“存储桶”(buckets)上。这种数据的分布式放置对于可伸缩性非常重要,因为它允许客户端应用程序同时从多个…

MySQL Explan执行计划详解

Explan执行计划 首先我们采用explan执行计划 执行一条sql&#xff0c;发现返回了12个列&#xff0c;下面会详细解释每一列 1、ID列 id列的值是代表了select语句执行顺序&#xff0c;是和select相关联的&#xff1b;id列的值大的会优先执行&#xff0c;如果id列为空最后执行&a…

【数据挖掘】实验8:分类与预测建模

实验8&#xff1a;分类与预测建模 一&#xff1a;实验目的与要求 1&#xff1a;学习和掌握回归分析、决策树、人工神经网络、KNN算法、朴素贝叶斯分类等机器学习算法在R语言中的应用。 2&#xff1a;了解其他分类与预测算法函数。 3&#xff1a;学习和掌握分类与预测算法的评…

大数据------JavaWeb------JDBC(完整知识点汇总)

JDBC 定义 全称为Java数据库连接&#xff08;Java DataBase Connectivity&#xff09;&#xff1a;是使用java语句来操作所有关系型数据库的一套API JDBC本质 它是官方定义的一套操作所有关系型数据库的规则&#xff08;即接口&#xff09;&#xff0c;各个数据库厂商会去实现…

Day 16 Linux服务管理和日志管理

服务管理 启动服务&#xff1a;systemctl start 服务名 停止服务&#xff1a;systemctl stop 服务名 重启服务&#xff1a;systemctl restart 服务名 重新加载配置文件&#xff1a;systemctl reload 服务名&#xff08;期间并不停止服务进程&#xff09; 查看服务运行状态…

pycharm/idea专业版过期永久解决

1、在file-settings-plungins中找到设置 2、点击增加如图网址3、下载安装此插件 4、按照如下步骤操作即可 5、如果又过期了重复4步骤即可&#xff0c;idea编辑器也是如此操作

如何用ChatGPT进行论文撰写?

原文链接&#xff1a;如何用ChatGPT进行论文撰写&#xff1f;https://mp.weixin.qq.com/s?__bizMzUzNTczMDMxMg&mid2247601619&idx1&snb686fbe87dedfac2df3a6afe780b2ffe&chksmfa820c34cdf5852251dca64597024ea62ddbde280086535ec251f4b62b848d9f9234688384e6…

深度学习 Lecture 9 信息增益、One-hot、回归树、集成树、随机森林、XGBoost模型

一、信息增益&#xff08;Information Gain) 决定使用什么特征来划分一个节点取决于什么样的特征选择最能减少熵&#xff08;也就是使纯度最大化&#xff09; 在决策树中&#xff0c;熵的减少被称为信息增益。 所以如何选择呢&#xff1f; 假设现在有三个特征可以选择&#…

政安晨:【深度学习神经网络基础】(十一)—— 激活函数的导数以及在反向传播中的应用

目录 线性激活函数的导数 Softmax激活函数的导数 S型激活函数的导数 双曲正切激活函数的导数 ReLU激活函数的导数 如何在反向传播中应用 批量训练和在线训练 随机梯度下降 反向传播权重更新 选择学习率和动量 Nesterov动量 政安晨的个人主页&#xff1a;政安晨 欢迎…

Go 语言中的 GIF 图像处理完全指南:`image/gif`的技术与实践

Go 语言中的 GIF 图像处理完全指南&#xff1a;image/gif的技术与实践 概述安装与基础设置导入 image/gif 包初步配置示例&#xff1a;设置一个简单的 GIF 编码环境 读取与解码 GIF 图像读取 GIF 文件解析 GIF 数据 创建与编码 GIF 图像创建 GIF 图像编码 GIF 图像 处理 GIF 动…

中文编程入门(Lua5.4.6中文版)第十二章 Lua 协程 参考《愿神》游戏

在《愿神》的提瓦特大陆上&#xff0c;每一位冒险者都拥有自己的独特力量——“神之眼”&#xff0c;他们借助元素之力探索广袤的世界&#xff0c;解决谜题&#xff0c;战胜敌人。而在提瓦特的科技树中&#xff0c;存在着一项名为“协同程序”的高级秘术&#xff0c;它使冒险者…

使用Canal同步MySQL 8到ES中小白配置教程

&#x1f680; 使用Canal同步MySQL 8到ES中小白配置教程 &#x1f680; 文章目录 &#x1f680; 使用Canal同步MySQL 8到ES中小白配置教程 &#x1f680;**摘要****引言****正文**&#x1f4d8; 第1章&#xff1a;初识Canal1.1 Canal概述1.2 工作原理解析 &#x1f4d8; 第2章&…

企业网站制作如何被百度收录

1、网站在百度中的整体评分 说俗点就是网站的权重&#xff0c;在优化过程中我们会见到很多网站出现秒收的情况&#xff0c;发布的文章几分钟就可以收录&#xff0c;这个通过SITE语法都可以去查询&#xff0c;那么这跟自己的网站权重以及内容更新习惯是有非常重要的关联。 我们…

Real3DPortrait照片对口型,数字人,音频/视频驱动数字人

先看效果 上传一张图片和一段音频&#xff0c;照片如下&#xff1a; 合成后效果如下&#xff1a; 照片对口型-音频驱动 支持音频驱动和视频驱动&#xff0c;视频可以使照片有参照视频中的口型和和动作。 项目地址 https://github.com/yerfor/Real3DPortrait 我的环境 win…

PVE grub resue错误修复 lvmid BUG

服务器断电后启动不起来&#xff0c;显示grub resue 找了半天没有找到修复方法。看官方文档有一处Recovering from grub “disk not found” error when booting from LVM 极为类似。https://pve.proxmox.com/wiki/Recover_From_Grub_Failure 下面是处理过程。 使用PVE 6.4启…

单例模式详解

什么是单例模式 首先&#xff0c;单例模式是一种设计模式&#xff0c;按字面意思&#xff0c;指一个类只能创建一个对象&#xff0c;当创建出多个对象的时候&#xff0c;就会出现报错异常 单例模式为何出现&#xff1f; 1.资源共享:某些情况下&#xff0c;多个对象都需要共享一…

双向链表也叫双链表

双向链表也叫双链表 双向链表也叫双链表 每个节点都有两个指针&#xff0c;分别指向 直接前驱节点、直接后继节点 双向链表中任意一个节点&#xff0c;都可以通过通过它的前驱节点和后继节点&#xff0c;访问其他节点 节点如下 节点定义 ListNode // 节点的值 T element; /…

康谋技术 | 深入探讨:自动驾驶中的相机标定技术

随着自动驾驶技术的快速发展&#xff0c;多传感器的数据采集和融合可以显著提高系统的冗余度和容错性&#xff0c;进而保证决策的快速性和正确性。在项目开发迭代过程中&#xff0c;传感器标定扮演着至关重要的角色&#xff0c;它位于数据采集平台与感知融合算法之间&#xff0…