特色

Apollo无人驾驶

原创文章,转载请注明: 转载自慢慢的回味

本文链接地址: Apollo无人驾驶

深入研究Apollo的代码是学习自动驾驶的很好途径。很多前沿科技,比如图像识别,激光雷达,多传感器融合,路径规划都可以直接完整的学习。

Apollo架构图

第一部分 感知模块Perception

感知模块输入来源于汽车物理感知设备,主要包含激光雷达,摄像头,毫米波雷达等。通过深度学习网络做实时检测障碍物(3D obstacles perception),进行障碍物分类,跟踪,识别周围环境如树木,人,其他交通参与者,交通灯等信息,为后续路径规划,控制等做辅助。通过高精地图,定位模块提供的位置,启动路口交通信号灯检测。

使用VSCode 调试Apollo无人车代码 深入研究Apollo的代码是学习自动驾驶的很好途径。很多前沿科技,比如图像识别,激光雷达,多传感器融合,路径规划都可以直接完整的学习。能够直接调试代码是比读代码更能加深理解。
Apollo无人车的消息流转 Apollo由无数的组件构成,每个组件独立运行,通过消息来进行相互依赖。每个组件构建在Cyber RT框架上,处理一组输入并产生其输出数椐。Launch 文件提供组件入口,DAG 文件配置组件依赖的消息输入等。
Apollo自动驾驶的点云CNN分割 这儿以单元测试cnn_segmentation_test.cc的测试cnn_segmentation_sequence_test为例来分析Apollo自动驾驶的点云CNN分割。
Apollo自动驾驶车道检测 本篇以单元测试camera_lib_lane_postprocessor_darkscnn_lane_postprocessor_test.cc的测试camera_lane_postprocessor_point_test为例来分析Apollo自动驾驶怎么进行车道检测。
利用DarkSCNN算法对摄像头拍摄到的路面图片进行预测,来获取车道线在以车辆坐标系下的位置。
Apollo自动驾驶Yolo障碍物检测 本篇以单元测试camera_lib_obstacle_detector_yolo_yolo_obstacle_detector_test.cc的测试demo_test为例来分析Apollo自动驾驶怎么使用Yolo算法来进行障碍物检测。
单元测试的Yolo算法基于Yolo V3改进,是单尺度检测的。

第二部分 规划模块Planning

规划模块为自动驾驶车辆规划时空轨迹。输出安全合理的运动轨迹信息,供控制模块执行。

Cartesian与Frenet坐标系转换公式推导 车在道路上行驶,以车的视角来看,车就如同在一条光滑的曲线上移动,且不时带有左右偏移。为了算法简单,我们选择了Frenet坐标系,它可以把直角坐标系下的复杂轨迹转换为只有S,L两个维度的简单曲线。
Apollo参考线优化之DiscretePointsReferenceLineSmoother Apollo的的规划算法基于Frenet坐标系,因此道路中心线的平滑性控制着车辆是否左右频繁晃动,而高精地图的道路中心线往往不够规划。Apollo在/modules/planning/reference_line中包含了多种参考线平滑算法:DiscretePointsReferenceLineSmoother(离散点平滑法,包括FEM_POS_DEVIATION_SMOOTHING有限元位置差异和COS_THETA_SMOOTHING余弦),QpSplineReferenceLineSmoother(三次样条插值法),SpiralReferenceLineSmoother(螺旋曲线法)。本篇以单元测试discrete_points_reference_line_smoother_test.cc的测试TEST_F(DiscretePointsReferenceLineSmootherTest, smooth)为例来分析Apollo对参考线reference line进行离散点平滑(FEM_POS_DEVIATION_SMOOTHING)的原理。
Apollo二次规划算法(piecewise jerk path optimizer)解析 Apollo里面最重要的模块就是感知和规划模块,规划模块最重要的是路径规划和速度规划任务,对应ROS机器人里面的局部规划。Apollo的规划模块首先根据当前的情况进行多场景(scenario)调度,每个场景又包含一个或者多个阶段(stage),每个阶段又由多个具有独立功能的小模块任务(task)完成。这篇文章就主要解读一下路径规划piecewise jerk path optimizer这个任务。任务最终会生成轨迹(trajectory):每个点的位姿和速度信息,进而输出给控制模块去控制车辆。
Apollo二次规划算法(piecewise jerk speed optimizer)解析 Apollo里面最重要的模块就是感知和规划模块,规划模块最重要的是路径规划和速度规划任务,对应ROS机器人里面的局部规划。Apollo的规划模块首先根据当前的情况进行多场景(scenario)调度,每个场景又包含一个或者多个阶段(stage),每个阶段又由多个具有独立功能的小模块任务(task)完成。前面介绍了路径规划piecewise jerk speed optimizer这个任务,这篇文章就解读一下速度规划piecewise jerk speed optimizer这个任务。SL规划保证车辆的横向偏移足够平滑,ST规划保证车辆的前进方向速度变化足够平滑。

本作品采用知识共享署名 4.0 国际许可协议进行许可。

特色

ROS小车实现介绍

原创文章,转载请注明: 转载自慢慢的回味

本文链接地址: ROS小车实现介绍

ROS机器人操作系统是一个很有前景的框架。通过实现一个ROS小车来了解机器人自主导航的原理。

第一部分 ROS地图的创建与导航

机器人在一个陌生的环境自主导航,就得通过自己的传感器和环境交互学习环境,进而创建环境地图,然后在地图上实现导航。不管是SLAM制图还是Teb局部规划,其核心的作用就是:因为运动和观察都有误差,我们通过优化参数来使得运动和观察的误差最小。

同时定位与制图-SlamGMapping 通过小车自带的里程计和激光雷达创建地图。
ROS导航-MoveBase ROS导航节点的主程序。MoveBase包通过全局规划器和局部规划器,利用代价地图costmap来实现当前地点到目标地点的导航。其中,costmap由map和小车传感器共同决定。现在通过对其的源码解读来了解这个框架是怎么完成这个任务的。
全局规划器-NavfnROS 机器人导航路径的规划可以分为两种:全局规划和局部规划。对事先已经知道的静态信息进行的规划为全局规划,如根据高清地图进行的规划,全局规划器就如同平时生活中的地图导航一样,这是一个大尺度的规划。基于传感器信息进行的机器人控制为局部路径规划,这是一个小尺度的规划。大范围内的静态信息不易改变,只需要定期更新高清地图就可以保证规划有效性。局部范围的动态信息则需要摄像头,激光雷达等设备及时回馈,变化频繁。
局部规划器-TebLocalPlannerROS 由于Teb算法能很好的支持阿克曼小车,即模型类似于汽车一样的机器人,这儿使用TebLocalPlannerROS进行局部规划。Teb局部规划器包(teb_local_planner)是作为一个局部规划器(base_local_planner)插件的形式融入2D导航栈的。它基于时间的弹性算法来优化局部轨迹,满足:轨迹的时间尽量短即速度和加速度尽量大;和障碍物能明显分离;以及必须满足机器人动力学约束。
非线性优化 非线性优化
G2O优化解析-手动微分 TebLocalPlannerROS依赖的G2O优化解析。G2O是一个开源的C++框架,用于优化基于图形的非线性误差函数。g2o被设计为易于扩展到各种各样的问题,一个新的问题通常可以在几行代码中指定。当前的实现为SLAM和BA的几个变体提供了解决方案,机器人技术和计算机视觉中的一系列问题都涉及到最小化可以用图形表示的非线性误差函数,典型的例子是同步定位和映射(SLAM)或束调整(BA)。这些问题的总体目标是最大限度地找到能够解释受到高斯噪声影响后的一组测量数据的参数或状态变量的配置。通过把优化问题设计成图的模式:带优化的变量称为顶点,对于待优量的限制条件为边。限制条件可理解成损失函数,这个函数是优化的关键,我们要通过不断的迭代获取最小的损失,从而推断出优化后的顶点而求解。G2O是一个开源的C++框架,用于解决非线性最小二乘问题。G2O的性能可与针对特定问题的最先进方法的实现相媲美。本文通过曲线上的点受高斯噪声影响后,利用G2O设计图模型,然后经过手动计算微分实现来重新拟合曲线。
G2O优化解析-自动微分 TebLocalPlannerROS依赖的G2O优化解析。上文G2O优化解析-手动微分我们学过用G2O来实现拟合曲线,但是大多情况下微分并不好计算,因为我们可能根本就不知道目标函数是什么,而是只知道一些断断续续的约束函数。导数主要以梯度和黑森函数的形式存在于机器学习中,自动微分(AD),也称为算法微分或简称“自动微分”,是一系列技术,类似于反向传播,但比反向传播更为普遍,用于高效、准确地计算以计算机程序表示的数值函数的导数。

第二部分 小车的下位机控制

在得到上位机发出的速度命令后,控制小车运动。这儿的下位机有STM32系统支持。

上位机与下位机通信 一般情况,上位机由ROS框架运行在Ubuntu的树莓派构成,下位机由STM32F103VET6芯片板载电机,舵机,陀螺仪,里程计等构成。里程计提供ROS需要的速度信息,陀螺仪提供加速度方向等信息给ROS,再加上连接到树莓派上的激光雷达,ROS就可以进行SLAM制图和导航了。下位机接收到ROS下发的速度信息后,转换成电机的PWM信号和舵机的PWM信号进行方向和速度控制。
小车电机和舵机控制 在STM32的代码中,通过运动学方程,从上位机得到的目标速度:Move_X, Move_Y, Move_Z中求解出阿克曼小车电机MOTOR_A,MOTOR_B的目标转速和舵机Servo的PWM值。从而控制驱动轮的电机电压来通过PID达到目标速度,控制舵机的角度来控制方向轮的角度从而控制小车方向。

本作品采用知识共享署名 4.0 国际许可协议进行许可。

特色

Tensorflow源码解读

原创文章,转载请注明: 转载自慢慢的回味

本文链接地址: Tensorflow源码解读

TensorFlow是一个灵活的端到端的机器学习框架。通过底层的代码调试更能够了解它的原理。

第一部分 Tensorflow c lib的编译

Tensorflow的下载和编译 本篇介绍编译的过程及注意事项。

第二部分 Tensorflow Eclipse环境的搭建

由于我们是要研究tensorflow的实现,所以用一个简单的c程序来调用tensorflow c library来用gdb调试。
正常的使用python写程序,然后由python调用so文件,但那样没办法调试到tensorflow内部。

TensorFlow工程创建及设置
基于tensorflow c lib调试的主程序
使用VSCode 调试tensorflow c lib的简单方法

第三部分 Tensorflow 源码调试

本部分介绍Tensorflow的实现机制。

  • 启动后,ops和op kernels的定义由静态变量声明
  • 然后根据用户程序生成计算图,查找ops的声明调用ops的factory函数注册ops并付给图中的node
  • 对生成的图进行优化剪裁
  • 创建executor,把root node喂给executor开始计算图的执行,完成后返回给主线程结束程序
TensorFlow op和op kernel的注册 TensorFlow so文件加载时完成TensorFlow op和op kernel的注册。另一篇TF Operation的注册
TensorFlow图的构建 本文就来分析tensorflow图的构建,以及运行图的设备和线程池的创建。TensorFlow使用数据流图将计算表示为独立的指令之间的依赖关系,数据流是一种用于并行计算的常用编程模型。在数据流图中,节点表示计算单元,边缘表示计算使用或产生的数据。
TensorFlow Session的创建 本文介绍TensorFlow Session的创建。TensorFlow使用Session 类来表示客户端程序(通常用Python 程序,但也提供了其他语言的类似接口,这儿就是用C接口)与 C++ 运行时之间的连接。Session 对象使我们能够访问本地机器中的设备和使用分布式 TensorFlow 运行时的远程设备。它还可缓存关于Graph 的信息,使您能够多次高效地运行同一计算。Session接受Graph参数和Options选项参数,Options参数可以指定使用的设备等信息。
TensorFlow Session的Setup TensorFlow Session的Setup完成整个Session的创建,设置输入数据类型(feeds)和输出数据类型(fetches)。然后利用图Graph创建基于Session的基本图,开启线程器(Exectors)等待Session开始。
TensorFlow Executor的创建 Session中的Executeors是一个线程池,用来执行每个节点Node的计算。在上一篇Session的setup中,其中调用了GetOrCreateExecutors类创建Executeors。direct_session.cc中的GetOrCreateExecutors方法用于获取设置callable_options的inputs,fetches,target,然后继续调用CreateExecutors方法创建executors。
tf-operation的创建 以AddNOp为例说明Operation怎样从ops的定义创建具体的kernel实例。
TensorFlow计算图的创建 Tensorflow机器学习任务的核心就是根据用户定义的图graph模型以及参数求解方式进行抽象之后,生成一个由节点和有向边组成,可以确定一个唯一的计算逻辑用有向无环图,称之为计算图。它定义了数据的流转方式,数据的计算方式,以及各种计算之间的相互依赖关系等。节点包括计算节点(Operation)、存储节点(Variable)和数据节点(Placeholder)3类,用于计算数据和存储数据。有向边表示数据的流转方式和依赖。
TensorFlow计算图的优化 Tensorflow计算图的优化相当重要,通过对其优化可以显著降低无用代码对计算资源的消耗,尤其在深度学习时,每一此迭代时间的缩短可以大大加速整个学习结果的求解,降低的资源消耗又可以容纳更多的输入并行计算。常见的优化有常量折叠,公共表达式折叠,内联函数展开,算数优化,修剪不可达节点,调试代码去除,自动并行计算,循环优化,内存优化等。
TF 计算图的执行 TF计算图优化完成后,在Session开始执行后就轮到TF 计算图的执行了。Tensorflow会根据计算图的节点信息,首先找到一个没有输入的节点作为根节点,创建一个task交给线程池取执行。每个节点完成后会根据Edge通知下游节点计算,直到所有节点完成计算,然后输出结果。
Tensorflow C API实现卷积计算 一个基于C API实现的进行卷积计算的示例。
Tensorflow 算法优化器验证 通过一个很简单的程序来验算法优化器的功能。如下程序,通过原图:输入数据->取负数->取负数->取倒数->取倒数->得到结果,经过优化计算图直接变成:输入数据->得到结果,计算节点数目大大减小了。
Tensorflow 函数式编程的测试 本文通过一个简单的程序来验证Tensorflow能够进行函数式编程的底层支持。从此也说明,Tensorflow在2.0发布之前的1.15版本底层已经支持函数式编程,进而能够实现动态图计算。

第四部分 Tensorflow常用实例

本部分介绍Tensorflow一些常用的实例。

Tensorflow Embedding原理 Embedding(嵌入)指的是把低维的流形嵌入到高维空间中。举个简单的例子,三维空间的球体(地球)是一个二维流形嵌入在三维空间(欧几里得空间),即地球上的任意一个点只需一个二维的经纬度就可以表达,但三维空间中用x,y,z。深度学习领域假设“自然的原始数据是低维的流形嵌入到原始数据所在的高维空间中”。所以,深度学习的过程就是把高维原始数据(图像,句子)再回映射到低维流形中,从而是数据变得可分,而这个映射就叫嵌入(Embedding)。比如文档Embedding,就是把每篇文档所组成的单词映射到一个低维的表征向量,使得每篇文档可以用一个表征向量来表示,即Embedding就是从原始数据提取出来的Feature,也就是通过神经网络映射之后的低维向量。
Tensorflow Pooling池化原理 池化(Pooling):也称为欠采样或下采样。主要用于特征降维,在保持旋转、平移、伸缩等不变性的前提下,压缩数据和参数的数量,减小过拟合,同时提高模型的容错性。常用的有按均值池化(mean-pooling):更大地保留图像背景信息,按最大值池化(max-pooling):更多的保留纹理信息。
Tensorflow 文本分类实例
Tensorflow Conv2D和MaxPool2D原理 卷积神经网络(CNN)是指在所有网络中,至少优一层使用了卷积运算运算的神经网络,因此命名为卷积神经网络。那么什么是卷积呢?如果需要卷积一个二位图片,首先定义一个卷积核(kernel),即权重矩阵,它能表面每一次卷积那个方向的值更重要,然后逐步在二维输入数据上“扫描卷积”。当卷积核“滑动”的同时进行卷积:计算权重矩阵和扫描所得的数据矩阵的乘积,求和后得到一个像素输出。
Tensorflow 图像CNN分类解析 自从Yann Lecun最早将CNN用于手写数字识别后,卷积神经网络在多个方向持续火爆:如语音识别、人脸识别、通用物体识别等。与普通神经网络的最大区别为:卷积神经网络包含了由卷积层和池化层构成的特征抽取器。卷积层由卷积核做卷积运算替代全连接神经网络的矩阵计算。卷积核表示一组共享的权值,位于不同地方的权值可以模拟人眼对图像识别的局部感受野:一般认为人对外界的认知是从局部到全局的,而图像的空间联系也是局部的像素联系较为紧密,而距离较远的像素相关性则较弱。共享的权值还可以大大降低权值参数量。所以卷积核的局部感受野可以解决全连接计算将图像展开为向量丢失的空间信息;共享权值减少的参数可以提高训练效率和避免网络过拟合。
Tensorflow LSTM原理 LSTM是RNN的一种cell实现。那么什么是RNN呢?RNN是一种特殊的神经网络结构, 它是根据“人的认知是基于过往的经验和记忆”这一观点而提出的,它使网络对前面的内容的一种“记忆”功能。隐藏层中,一个序列当前的输出与前面的输出也有关,具体的表现形式为网络会对前面的信息进行记忆并应用于当前输出的计算中,即隐藏层之间的节点不再无连接而是有连接的,并且隐藏层的输入不仅包括输入层的输出还包括上一时刻隐藏层的输出,所有前面的结果可以影响后面的输出。所以它广泛运用于文本生成,机器翻译,机器写小说,语音识别等。

本作品采用知识共享署名 4.0 国际许可协议进行许可。

在AWS使用EKS

原创文章,转载请注明: 转载自慢慢的回味

本文链接地址: 在AWS使用EKS

使用AWS的EKS来托管Kubernetes是比较复杂,按照如下的方法可以创建出一个满足大部分使用环境的EKS。

1 创建一个IAM用户(Root用户操作)

在AWS中创建一个IAM用户,权限够用就行。

在AWS管理控制台,点击”Add users”:

其它页面默认就好。最后保存好下载的CSV文件,里面包含的Access Key和Secret Access Key在AWS CLI里面会用到。

2 创建策略和角色(Root用户操作)
2.1 创建EKS集群角色

给EKS集群创建一个角色:”testEKSClusterRole”,它包含一个策略: AmazonEKSClusterPolicy。

2.2 创建集群节点组角色

创建角色”testEKSNodeRole”,包含如下策略:
AmazonEKSWorkerNodePolicy
AmazonEC2ContainerRegistryReadOnly
AmazonEKS_CNI_Policy

2.3 给IAM用户添加权限

用户需要如下4个权限。你也可以创建一个用户组,并给其赋予权限,然后加入用户。

赋予受管策略”AmazonEC2FullAccess”, “AmazonVPCReadOnlyAccess”, “AmazonEC2FullAccess”。

添加一个包含如下内容的自定义策略:”TestEKSPolicy”

(请修改账号ID675892200046)

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": "eks:*",
            "Resource": "*"
        },
        {
            "Action": [
                "ssm:GetParameter",
                "ssm:GetParameters"
            ],
            "Resource": [
                "arn:aws:ssm:*:675892200046:parameter/aws/*",
                "arn:aws:ssm:*::parameter/aws/*"
            ],
            "Effect": "Allow"
        },
        {
            "Action": [
                "kms:CreateGrant",
                "kms:DescribeKey"
            ],
            "Resource": "*",
            "Effect": "Allow"
        },
        {
            "Action": [
                "logs:PutRetentionPolicy"
            ],
            "Resource": "*",
            "Effect": "Allow"
        }
    ]
}

添加一个包含如下内容的自定义策略:”IamLimitedAccess”

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": "iam:CreateServiceLinkedRole",
            "Resource": "*",
            "Condition": {
                "StringEquals": {
                    "iam:AWSServiceName": [
                        "eks.amazonaws.com",
                        "eks-nodegroup.amazonaws.com",
                        "eks-fargate.amazonaws.com"
                    ]
                }
            }
        },
        {
            "Sid": "VisualEditor1",
            "Effect": "Allow",
            "Action": [
                "iam:CreateInstanceProfile",
                "iam:TagRole",
                "iam:RemoveRoleFromInstanceProfile",
                "iam:DeletePolicy",
                "iam:CreateRole",
                "iam:AttachRolePolicy",
                "iam:PutRolePolicy",
                "iam:AddRoleToInstanceProfile",
                "iam:ListInstanceProfilesForRole",
                "iam:PassRole",
                "iam:DetachRolePolicy",
                "iam:DeleteRolePolicy",
                "iam:ListAttachedRolePolicies",
                "iam:DeleteOpenIDConnectProvider",
                "iam:DeleteInstanceProfile",
                "iam:GetRole",
                "iam:GetInstanceProfile",
                "iam:GetPolicy",
                "iam:DeleteRole",
                "iam:ListInstanceProfiles",
                "iam:CreateOpenIDConnectProvider",
                "iam:CreatePolicy",
                "iam:ListPolicyVersions",
                "iam:GetOpenIDConnectProvider",
                "iam:TagOpenIDConnectProvider",
                "iam:GetRolePolicy"
            ],
            "Resource": [
                "arn:aws:iam::675892200046:role/testEKSNodeRole",
                "arn:aws:iam::675892200046:role/testEKSClusterRole",
                "arn:aws:iam::675892200046:role/aws-service-role/eks-nodegroup.amazonaws.com/AWSServiceRoleForAmazonEKSNodegroup",
                "arn:aws:iam::675892200046:instance-profile/*",
                "arn:aws:iam::675892200046:policy/*",
                "arn:aws:iam::675892200046:oidc-provider/*"
            ]
        },
        {
            "Sid": "VisualEditor2",
            "Effect": "Allow",
            "Action": "iam:GetRole",
            "Resource": "arn:aws:iam::675892200046:role/*"
        },
        {
            "Sid": "VisualEditor3",
            "Effect": "Allow",
            "Action": "iam:ListRoles",
            "Resource": "*"
        }
    ]
}
3 创建EKS集群(IAM用户)
3.1 创建EKS集群控制平面

在EKS产品页面,点击”Create Cluster”。

如果你没有在”Custer service role”下拉列表中看见角色,请检查第2步。

在子网”Subnets”中, 3个子网就好了。
在集群端点访问”Cluster endpoint access”中,选 “Public”就好,生产环境,请选择”Private”。
在网络插件”Networking add-ons”中,默认就好。



3.2 添加工作节点到集群

当集群创建成功了”Active”, 点击Compute标签中的”Add node group”来创建工作节点。


你可以配置 “SSH login”进入到工作节点。

4 设置AWS CLI 工具和Kubectl 工具(IAM用户)
4.1 配置AWS CLI

安装AWS CLI后,运行”aws configure”来配置第一步中的IAM账号:

curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
unzip awscliv2.zip
sudo ./aws/install
aws configure
[awscli@bogon ~]$ aws sts get-caller-identity
{
    "UserId": "AIDAZ2XSQQJXKNKFI4YDF",
    "Account": "675892200046",
    "Arn": "arn:aws:iam::675892200046:user/TestEKSUser"
}
4.2 配置Kubectl
[awscli@bogon ~]$ aws eks --region us-east-1 update-kubeconfig --name TestEKSCluster
Updated context arn:aws:eks:us-east-1:675892200046:cluster/TestEKSCluster in /home/awscli/.kube/config
5 设置EKS的存储EFS
5.1 创建接入EFS的策略(Root用户操作)

自定义一策略:”TestEKSAccessEFSPolicy”

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "elasticfilesystem:DescribeAccessPoints",
                "elasticfilesystem:DescribeFileSystems"
            ],
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "elasticfilesystem:CreateAccessPoint"
            ],
            "Resource": "*",
            "Condition": {
                "StringLike": {
                    "aws:RequestTag/efs.csi.aws.com/cluster": "true"
                }
            }
        },
        {
            "Effect": "Allow",
            "Action": "elasticfilesystem:DeleteAccessPoint",
            "Resource": "*",
            "Condition": {
                "StringEquals": {
                    "aws:ResourceTag/efs.csi.aws.com/cluster": "true"
                }
            }
        }
    ]
}
5.2 创建访问EFS的角色(Root用户操作)

创建角色”TestEKSAccessEFSRole”并分配策略”TestEKSAccessEFSPolicy”。

在信任关系”Trust relationships”中,修改如下内容。
替换”oidc.eks.us-east-1.amazonaws.com/id/98F61019E9B399FA9B7A43A19B56DF14″为你EKS的”OpenID Connect provider URL”。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "Federated": "arn:aws:iam::675892200046:oidc-provider/oidc.eks.us-east-1.amazonaws.com/id/98F61019E9B399FA9B7A43A19B56DF14"
            },
            "Action": "sts:AssumeRoleWithWebIdentity",
            "Condition": {
                "StringEquals": {
                    "oidc.eks.us-east-1.amazonaws.com/id/98F61019E9B399FA9B7A43A19B56DF14:sub": "system:serviceaccount:kube-system:efs-csi-controller-sa"
                }
            }
        }
    ]
}

5.3 为OpenID Connect创建Identity Provider(Root用户操作)

填入提供URL和审计URL “sts.amazonaws.com”, 点击”Get thumbprint”, 然后单击”Add provider”。

5.4 在EKS中创建服务账户(IAM用户)

创建文件”efs-service-account.yaml”,包含如下内容,然后”kubectl apply -f efs-service-account.yaml”创建账户,注意修改account id。

apiVersion: v1
kind: ServiceAccount
metadata:
  name: efs-csi-controller-sa
  namespace: kube-system
  labels:
    app.kubernetes.io/name: aws-efs-csi-driver
  annotations:
    eks.amazonaws.com/role-arn: arn:aws:iam::675892200046:role/TestEKSAccessEFSRole
5.5 创建EFS CSI 插件(IAM用户)

执行如下命令获取EFS插件的安装yaml文件:driver.yaml

kubectl kustomize "github.com/kubernetes-sigs/aws-efs-csi-driver/deploy/kubernetes/overlays/stable/ecr?ref=release-1.3" > driver.yaml

上面已经创建了服务账号,所以driver.yaml文件里面的”efs-csi-controller-sa”段可以去掉。

接着运行命令 “kubectl apply -f driver.yaml”创建CSI插件。

apiVersion: v1
kind: ServiceAccount
metadata:
  name: efs-csi-controller-sa
  namespace: kube-system
  labels:
    app.kubernetes.io/name: aws-efs-csi-driver
  annotations:
    eks.amazonaws.com/role-arn: arn:aws:iam::675892200046:role/TestEKSAccessEFSRole
---
apiVersion: v1
kind: ServiceAccount
metadata:
  labels:
    app.kubernetes.io/name: aws-efs-csi-driver
  name: efs-csi-node-sa
  namespace: kube-system
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  labels:
    app.kubernetes.io/name: aws-efs-csi-driver
  name: efs-csi-external-provisioner-role
rules:
- apiGroups:
  - ""
  resources:
  - persistentvolumes
  verbs:
  - get
  - list
  - watch
  - create
  - delete
- apiGroups:
  - ""
  resources:
  - persistentvolumeclaims
  verbs:
  - get
  - list
  - watch
  - update
- apiGroups:
  - storage.k8s.io
  resources:
  - storageclasses
  verbs:
  - get
  - list
  - watch
- apiGroups:
  - ""
  resources:
  - events
  verbs:
  - list
  - watch
  - create
  - patch
- apiGroups:
  - storage.k8s.io
  resources:
  - csinodes
  verbs:
  - get
  - list
  - watch
- apiGroups:
  - ""
  resources:
  - nodes
  verbs:
  - get
  - list
  - watch
- apiGroups:
  - coordination.k8s.io
  resources:
  - leases
  verbs:
  - get
  - watch
  - list
  - delete
  - update
  - create
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  labels:
    app.kubernetes.io/name: aws-efs-csi-driver
  name: efs-csi-provisioner-binding
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: efs-csi-external-provisioner-role
subjects:
- kind: ServiceAccount
  name: efs-csi-controller-sa
  namespace: kube-system
---
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app.kubernetes.io/name: aws-efs-csi-driver
  name: efs-csi-controller
  namespace: kube-system
spec:
  replicas: 2
  selector:
    matchLabels:
      app: efs-csi-controller
      app.kubernetes.io/instance: kustomize
      app.kubernetes.io/name: aws-efs-csi-driver
  template:
    metadata:
      labels:
        app: efs-csi-controller
        app.kubernetes.io/instance: kustomize
        app.kubernetes.io/name: aws-efs-csi-driver
    spec:
      containers:
      - args:
        - --endpoint=$(CSI_ENDPOINT)
        - --logtostderr
        - --v=2
        - --delete-access-point-root-dir=false
        env:
        - name: CSI_ENDPOINT
          value: unix:///var/lib/csi/sockets/pluginproxy/csi.sock
        image: 602401143452.dkr.ecr.us-west-2.amazonaws.com/eks/aws-efs-csi-driver:v1.3.8
        imagePullPolicy: IfNotPresent
        livenessProbe:
          failureThreshold: 5
          httpGet:
            path: /healthz
            port: healthz
          initialDelaySeconds: 10
          periodSeconds: 10
          timeoutSeconds: 3
        name: efs-plugin
        ports:
        - containerPort: 9909
          name: healthz
          protocol: TCP
        securityContext:
          privileged: true
        volumeMounts:
        - mountPath: /var/lib/csi/sockets/pluginproxy/
          name: socket-dir
      - args:
        - --csi-address=$(ADDRESS)
        - --v=2
        - --feature-gates=Topology=true
        - --extra-create-metadata
        - --leader-election
        env:
        - name: ADDRESS
          value: /var/lib/csi/sockets/pluginproxy/csi.sock
        image: 602401143452.dkr.ecr.us-west-2.amazonaws.com/eks/csi-provisioner:v2.1.1
        imagePullPolicy: IfNotPresent
        name: csi-provisioner
        volumeMounts:
        - mountPath: /var/lib/csi/sockets/pluginproxy/
          name: socket-dir
      - args:
        - --csi-address=/csi/csi.sock
        - --health-port=9909
        image: 602401143452.dkr.ecr.us-west-2.amazonaws.com/eks/livenessprobe:v2.2.0
        imagePullPolicy: IfNotPresent
        name: liveness-probe
        volumeMounts:
        - mountPath: /csi
          name: socket-dir
      hostNetwork: true
      nodeSelector:
        kubernetes.io/os: linux
      priorityClassName: system-cluster-critical
      priorityClassName: system-cluster-critical
      serviceAccountName: efs-csi-controller-sa
      volumes:
      - emptyDir: {}
        name: socket-dir
---
apiVersion: apps/v1
kind: DaemonSet
metadata:
  labels:
    app.kubernetes.io/name: aws-efs-csi-driver
  name: efs-csi-node
  namespace: kube-system
spec:
  selector:
    matchLabels:
      app: efs-csi-node
      app.kubernetes.io/instance: kustomize
      app.kubernetes.io/name: aws-efs-csi-driver
  template:
    metadata:
      labels:
        app: efs-csi-node
        app.kubernetes.io/instance: kustomize
        app.kubernetes.io/name: aws-efs-csi-driver
    spec:
      affinity:
        nodeAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            nodeSelectorTerms:
            - matchExpressions:
              - key: eks.amazonaws.com/compute-type
                operator: NotIn
                values:
                - fargate
      containers:
      - args:
        - --endpoint=$(CSI_ENDPOINT)
        - --logtostderr
        - --v=2
        env:
        - name: CSI_ENDPOINT
          value: unix:/csi/csi.sock
        image: 602401143452.dkr.ecr.us-west-2.amazonaws.com/eks/aws-efs-csi-driver:v1.3.8
        imagePullPolicy: IfNotPresent
        livenessProbe:
          failureThreshold: 5
          httpGet:
            path: /healthz
            port: healthz
          initialDelaySeconds: 10
          periodSeconds: 2
          timeoutSeconds: 3
        name: efs-plugin
        ports:
        - containerPort: 9809
          name: healthz
          protocol: TCP
        securityContext:
          privileged: true
        volumeMounts:
        - mountPath: /var/lib/kubelet
          mountPropagation: Bidirectional
          name: kubelet-dir
        - mountPath: /csi
          name: plugin-dir
        - mountPath: /var/run/efs
          name: efs-state-dir
        - mountPath: /var/amazon/efs
          name: efs-utils-config
        - mountPath: /etc/amazon/efs-legacy
          name: efs-utils-config-legacy
      - args:
        - --csi-address=$(ADDRESS)
        - --kubelet-registration-path=$(DRIVER_REG_SOCK_PATH)
        - --v=2
        env:
        - name: ADDRESS
          value: /csi/csi.sock
        - name: DRIVER_REG_SOCK_PATH
          value: /var/lib/kubelet/plugins/efs.csi.aws.com/csi.sock
        - name: KUBE_NODE_NAME
          valueFrom:
            fieldRef:
              fieldPath: spec.nodeName
        image: 602401143452.dkr.ecr.us-west-2.amazonaws.com/eks/csi-node-driver-registrar:v2.1.0
        imagePullPolicy: IfNotPresent
        name: csi-driver-registrar
        volumeMounts:
        - mountPath: /csi
          name: plugin-dir
        - mountPath: /registration
          name: registration-dir
      - args:
        - --csi-address=/csi/csi.sock
        - --health-port=9809
        - --v=2
        image: 602401143452.dkr.ecr.us-west-2.amazonaws.com/eks/livenessprobe:v2.2.0
        imagePullPolicy: IfNotPresent
        name: liveness-probe
        volumeMounts:
        - mountPath: /csi
          name: plugin-dir
      dnsPolicy: ClusterFirst
      hostNetwork: true
      nodeSelector:
        beta.kubernetes.io/os: linux
      priorityClassName: system-node-critical
      serviceAccountName: efs-csi-node-sa
      tolerations:
      - operator: Exists
      volumes:
      - hostPath:
          path: /var/lib/kubelet
          type: Directory
        name: kubelet-dir
      - hostPath:
          path: /var/lib/kubelet/plugins/efs.csi.aws.com/
          type: DirectoryOrCreate
        name: plugin-dir
      - hostPath:
          path: /var/lib/kubelet/plugins_registry/
          type: Directory
        name: registration-dir
      - hostPath:
          path: /var/run/efs
          type: DirectoryOrCreate
        name: efs-state-dir
      - hostPath:
          path: /var/amazon/efs
          type: DirectoryOrCreate
        name: efs-utils-config
      - hostPath:
          path: /etc/amazon/efs
          type: DirectoryOrCreate
        name: efs-utils-config-legacy
---
apiVersion: storage.k8s.io/v1
kind: CSIDriver
metadata:
  annotations:
    helm.sh/hook: pre-install, pre-upgrade
    helm.sh/hook-delete-policy: before-hook-creation
    helm.sh/resource-policy: keep
  name: efs.csi.aws.com
spec:
  attachRequired: false

等一会,”efs-csi-controller*”应该就绪了。

5.6 创建EFS文件系统(Root用户操作)

在Amazon EFS产品中,点击”Create file system”开始创建:

选择”Standard”作为存储类,这样可用区里面的所有节点都可以访问。

创建完成后,等待”Network”可用,然后点击”Manage”按钮添加集群安全组。

5.7 创建Kubernetes里面的存储类(IAM用户)

安装如下内容创建”storageclass.yaml”,并运行”kubectl apply -f storageclass.yaml”来创建。

注意修改”fileSystemId”成你自己的,通过如下图查询。

kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
  name: efs-sc
provisioner: efs.csi.aws.com
parameters:
  provisioningMode: efs-ap
  fileSystemId: fs-04470c1ed1eab275c
  directoryPerms: "700"
  gidRangeStart: "1000" # optional
  gidRangeEnd: "2000" # optional
  basePath: "/dynamic_provisioning" # optional
6 部署Jenkins来测试(IAM用户)
6.1 部署Jenkins

注意设置存储类为efs-sc。

helm repo add jenkinsci https://charts.jenkins.io/
helm install my-jenkins jenkinsci/jenkins –version 4.1.17 –set persistence.storageClass=efs-sc

6.2 验证结果

等Jenkins启动后,可以采用端口转发来临时访问。

[awscli@bogon ~]$ kubectl port-forward svc/my-jenkins --address=0.0.0.0 8081:8080
Forwarding from 0.0.0.0:8081 -> 8080
Handling connection for 8081
Handling connection for 8081
Handling connection for 8081
Handling connection for 8081
Handling connection for 8081
Handling connection for 8081
Handling connection for 8081
Handling connection for 8081
Handling connection for 8081
Handling connection for 8081
Handling connection for 8081
Handling connection for 8081
Handling connection for 8081

7 集群自动伸缩
7.1 创建一个自动伸缩策略供EKS使用

首先创建一个策略:”TestEKSClusterAutoScalePolicy”

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "autoscaling:DescribeAutoScalingGroups",
                "autoscaling:DescribeAutoScalingInstances",
                "autoscaling:DescribeLaunchConfigurations",
                "autoscaling:DescribeTags",
                "autoscaling:SetDesiredCapacity",
                "autoscaling:TerminateInstanceInAutoScalingGroup",
                "ec2:DescribeLaunchTemplateVersions",
                "ec2:DescribeInstanceTypes"
            ],
            "Resource": "*"
        }
    ]
}
7.2 创建一个自动伸缩角色供EKS使用

接着创建一个角色:”TestEKSClusterAutoScaleRole”,使用上面创建的策略:”TestEKSClusterAutoScalePolicy”,并且按照如下设置”trusted entities”。
注意open id需要从你的EKS集群详情页面获取。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Federated": "arn:aws:iam::675892200046:oidc-provider/oidc.eks.us-east-1.amazonaws.com/id/BEDCA5446D2676BB0A51B7BECFB36773"
      },
      "Action": "sts:AssumeRoleWithWebIdentity",
      "Condition": {
        "StringEquals": {
          "oidc.eks.us-east-1.amazonaws.com/id/BEDCA5446D2676BB0A51B7BECFB36773:sub": "system:serviceaccount:kube-system:cluster-autoscaler"
        }
      }
    }
  ]
}
7.3 部署cluster scaler

使用如下命令获取部署文件。

wget https://raw.githubusercontent.com/kubernetes/autoscaler/master/cluster-autoscaler/cloudprovider/aws/examples/cluster-autoscaler-autodiscover.yaml

然后修改”cluster-autoscaler-autodiscover.yaml” :

1 添加annotation “eks.amazonaws.com/role-arn” 到服务账号 ServiceAccount “cluster-autoscaler”上,见下面的代码。

2 在Deployment “cluster-autoscaler”中,修改 为你的集群名字,如”TestEKSCluster”。

3 添加2个参数(- –balance-similar-node-groups – –skip-nodes-with-system-pods=false)到步骤2处代码的下一行。

4 添加注解annotation “cluster-autoscaler.kubernetes.io/safe-to-evict 在代码行”prometheus.io/port: ‘8085’”下面。

5 在https://github.com/kubernetes/autoscaler/releases找到对应的镜像版本,需要和你的EKS Kubernetes版本一致。

6 最后,运行”kubectl apply -f cluster-autoscaler-autodiscover.yaml”来创建。

---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: cluster-autoscaler
  namespace: kube-system
  labels:
    k8s-addon: cluster-autoscaler.addons.k8s.io
    k8s-app: cluster-autoscaler
  annotations:
    eks.amazonaws.com/role-arn: arn:aws:iam::675892200046:role/TestEKSClusterAutoScaleRole
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: cluster-autoscaler
  labels:
    k8s-addon: cluster-autoscaler.addons.k8s.io
    k8s-app: cluster-autoscaler
rules:
  - apiGroups: [""]
    resources: ["events", "endpoints"]
    verbs: ["create", "patch"]
  - apiGroups: [""]
    resources: ["pods/eviction"]
    verbs: ["create"]
  - apiGroups: [""]
    resources: ["pods/status"]
    verbs: ["update"]
  - apiGroups: [""]
    resources: ["endpoints"]
    resourceNames: ["cluster-autoscaler"]
    verbs: ["get", "update"]
  - apiGroups: [""]
    resources: ["nodes"]
    verbs: ["watch", "list", "get", "update"]
  - apiGroups: [""]
    resources:
      - "namespaces"
      - "pods"
      - "services"
      - "replicationcontrollers"
      - "persistentvolumeclaims"
      - "persistentvolumes"
    verbs: ["watch", "list", "get"]
  - apiGroups: ["extensions"]
    resources: ["replicasets", "daemonsets"]
    verbs: ["watch", "list", "get"]
  - apiGroups: ["policy"]
    resources: ["poddisruptionbudgets"]
    verbs: ["watch", "list"]
  - apiGroups: ["apps"]
    resources: ["statefulsets", "replicasets", "daemonsets"]
    verbs: ["watch", "list", "get"]
  - apiGroups: ["storage.k8s.io"]
    resources: ["storageclasses", "csinodes", "csidrivers", "csistoragecapacities"]
    verbs: ["watch", "list", "get"]
  - apiGroups: ["batch", "extensions"]
    resources: ["jobs"]
    verbs: ["get", "list", "watch", "patch"]
  - apiGroups: ["coordination.k8s.io"]
    resources: ["leases"]
    verbs: ["create"]
  - apiGroups: ["coordination.k8s.io"]
    resourceNames: ["cluster-autoscaler"]
    resources: ["leases"]
    verbs: ["get", "update"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: cluster-autoscaler
  namespace: kube-system
  labels:
    k8s-addon: cluster-autoscaler.addons.k8s.io
    k8s-app: cluster-autoscaler
rules:
  - apiGroups: [""]
    resources: ["configmaps"]
    verbs: ["create","list","watch"]
  - apiGroups: [""]
    resources: ["configmaps"]
    resourceNames: ["cluster-autoscaler-status", "cluster-autoscaler-priority-expander"]
    verbs: ["delete", "get", "update", "watch"]
 
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: cluster-autoscaler
  labels:
    k8s-addon: cluster-autoscaler.addons.k8s.io
    k8s-app: cluster-autoscaler
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: cluster-autoscaler
subjects:
  - kind: ServiceAccount
    name: cluster-autoscaler
    namespace: kube-system
 
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: cluster-autoscaler
  namespace: kube-system
  labels:
    k8s-addon: cluster-autoscaler.addons.k8s.io
    k8s-app: cluster-autoscaler
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: cluster-autoscaler
subjects:
  - kind: ServiceAccount
    name: cluster-autoscaler
    namespace: kube-system
 
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: cluster-autoscaler
  namespace: kube-system
  labels:
    app: cluster-autoscaler
spec:
  replicas: 1
  selector:
    matchLabels:
      app: cluster-autoscaler
  template:
    metadata:
      labels:
        app: cluster-autoscaler
      annotations:
        prometheus.io/scrape: 'true'
        prometheus.io/port: '8085'
        cluster-autoscaler.kubernetes.io/safe-to-evict: "false"
    spec:
      priorityClassName: system-cluster-critical
      securityContext:
        runAsNonRoot: true
        runAsUser: 65534
        fsGroup: 65534
      serviceAccountName: cluster-autoscaler
      containers:
        - image: k8s.gcr.io/autoscaling/cluster-autoscaler:v1.23.0
          name: cluster-autoscaler
          resources:
            limits:
              cpu: 100m
              memory: 600Mi
            requests:
              cpu: 100m
              memory: 600Mi
          command:
            - ./cluster-autoscaler
            - --v=4
            - --stderrthreshold=info
            - --cloud-provider=aws
            - --skip-nodes-with-local-storage=false
            - --expander=least-waste
            - --node-group-auto-discovery=asg:tag=k8s.io/cluster-autoscaler/enabled,k8s.io/cluster-autoscaler/TestEKSCluster
            - --balance-similar-node-groups
            - --skip-nodes-with-system-pods=false
          volumeMounts:
            - name: ssl-certs
              mountPath: /etc/ssl/certs/ca-certificates.crt #/etc/ssl/certs/ca-bundle.crt for Amazon Linux Worker Nodes
              readOnly: true
          imagePullPolicy: "Always"
      volumes:
        - name: ssl-certs
          hostPath:
            path: "/etc/ssl/certs/ca-bundle.crt"
7.4 部署metrics server

使用metrics server我们可以获取pods的metrics,着色HPA的基础。

apiVersion: v1
kind: ServiceAccount
metadata:
  labels:
    k8s-app: metrics-server
  name: metrics-server
  namespace: kube-system
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  labels:
    k8s-app: metrics-server
    rbac.authorization.k8s.io/aggregate-to-admin: "true"
    rbac.authorization.k8s.io/aggregate-to-edit: "true"
    rbac.authorization.k8s.io/aggregate-to-view: "true"
  name: system:aggregated-metrics-reader
rules:
- apiGroups:
  - metrics.k8s.io
  resources:
  - pods
  - nodes
  verbs:
  - get
  - list
  - watch
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  labels:
    k8s-app: metrics-server
  name: system:metrics-server
rules:
- apiGroups:
  - ""
  resources:
  - pods
  - nodes
  - nodes/stats
  - namespaces
  - configmaps
  verbs:
  - get
  - list
  - watch
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  labels:
    k8s-app: metrics-server
  name: metrics-server-auth-reader
  namespace: kube-system
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: extension-apiserver-authentication-reader
subjects:
- kind: ServiceAccount
  name: metrics-server
  namespace: kube-system
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  labels:
    k8s-app: metrics-server
  name: metrics-server:system:auth-delegator
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: system:auth-delegator
subjects:
- kind: ServiceAccount
  name: metrics-server
  namespace: kube-system
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  labels:
    k8s-app: metrics-server
  name: system:metrics-server
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: system:metrics-server
subjects:
- kind: ServiceAccount
  name: metrics-server
  namespace: kube-system
---
apiVersion: v1
kind: Service
metadata:
  labels:
    k8s-app: metrics-server
  name: metrics-server
  namespace: kube-system
spec:
  ports:
  - name: https
    port: 443
    protocol: TCP
    targetPort: https
  selector:
    k8s-app: metrics-server
---
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    k8s-app: metrics-server
  name: metrics-server
  namespace: kube-system
spec:
  selector:
    matchLabels:
      k8s-app: metrics-server
  strategy:
    rollingUpdate:
      maxUnavailable: 0
  template:
    metadata:
      labels:
        k8s-app: metrics-server
    spec:
      containers:
      - args:
        - --cert-dir=/tmp
        - --secure-port=4443
        - --kubelet-insecure-tls
        - --kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname
        - --kubelet-use-node-status-port
        - --metric-resolution=15s
        image: k8s.gcr.io/metrics-server/metrics-server:v0.5.2
        imagePullPolicy: IfNotPresent
        livenessProbe:
          failureThreshold: 3
          httpGet:
            path: /livez
            port: https
            scheme: HTTPS
          periodSeconds: 10
        name: metrics-server
        ports:
        - containerPort: 4443
          name: https
          protocol: TCP
        readinessProbe:
          failureThreshold: 3
          httpGet:
            path: /readyz
            port: https
            scheme: HTTPS
          initialDelaySeconds: 20
          periodSeconds: 10
        resources:
          requests:
            cpu: 100m
            memory: 200Mi
        securityContext:
          readOnlyRootFilesystem: true
          runAsNonRoot: true
          runAsUser: 1000
        volumeMounts:
        - mountPath: /tmp
          name: tmp-dir
      nodeSelector:
        kubernetes.io/os: linux
      priorityClassName: system-cluster-critical
      serviceAccountName: metrics-server
      volumes:
      - emptyDir: {}
        name: tmp-dir
---
apiVersion: apiregistration.k8s.io/v1
kind: APIService
metadata:
  labels:
    k8s-app: metrics-server
  name: v1beta1.metrics.k8s.io
spec:
  group: metrics.k8s.io
  groupPriorityMinimum: 100
  insecureSkipTLSVerify: true
  service:
    name: metrics-server
    namespace: kube-system
  version: v1beta1
  versionPriority: 100
7.5 测试集群伸缩cluster scaling

部署一个niginx来测试:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  labels:
    app: nginx
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.14.2
        ports:
        - containerPort: 80

目前只有1个节点。

[awscli@bogon ~]$ kubectl top node
NAME                            CPU(cores)   CPU%   MEMORY(bytes)   MEMORY%
ip-172-31-17-148.ec2.internal   52m          2%     635Mi           19%
[awscli@bogon ~]$ kubectl top pods --all-namespaces
NAMESPACE     NAME                                  CPU(cores)   MEMORY(bytes)
default       nginx-deployment-9456bbbf9-qlpcb      0m           2Mi
kube-system   aws-node-m6xjs                        3m           34Mi
kube-system   cluster-autoscaler-5c4d9b6d4c-k2csm   2m           22Mi
kube-system   coredns-d5b9bfc4-4bvnn                1m           12Mi
kube-system   coredns-d5b9bfc4-z2ppq                1m           12Mi
kube-system   kube-proxy-x55c8                      1m           10Mi
kube-system   metrics-server-84cd7b5645-prh6c       3m           16Mi
 
现在,我们把上面创建的测试POD副本设置到30,应为当前节点容量不够,一会儿后,一个新的节点(ip-172-31-91-231.ec2.internal)启动并加入到了集群。
[awscli@bogon ~]$ kubectl top node
NAME                            CPU(cores)   CPU%   MEMORY(bytes)   MEMORY%
ip-172-31-17-148.ec2.internal   66m          3%     726Mi           21%
ip-172-31-91-231.ec2.internal   774m         40%    569Mi           17%
[awscli@bogon ~]$ kubectl top pods --all-namespaces
NAMESPACE     NAME                                  CPU(cores)   MEMORY(bytes)
default       nginx-deployment-9456bbbf9-2tgpl      0m           2Mi
default       nginx-deployment-9456bbbf9-5jdsm      0m           2Mi
default       nginx-deployment-9456bbbf9-5vt9l      2m           2Mi
default       nginx-deployment-9456bbbf9-8ldm7      0m           2Mi
default       nginx-deployment-9456bbbf9-9m499      0m           2Mi
default       nginx-deployment-9456bbbf9-cpmqs      0m           2Mi
default       nginx-deployment-9456bbbf9-d6p4k      2m           2Mi
default       nginx-deployment-9456bbbf9-f2z87      2m           2Mi
default       nginx-deployment-9456bbbf9-f8w2f      0m           2Mi
default       nginx-deployment-9456bbbf9-fwjg4      0m           2Mi
default       nginx-deployment-9456bbbf9-kfmv8      0m           2Mi
default       nginx-deployment-9456bbbf9-knn2t      0m           2Mi
default       nginx-deployment-9456bbbf9-mq5sv      0m           2Mi
default       nginx-deployment-9456bbbf9-plh7h      0m           2Mi
default       nginx-deployment-9456bbbf9-qlpcb      0m           2Mi
default       nginx-deployment-9456bbbf9-tz22s      0m           2Mi
default       nginx-deployment-9456bbbf9-v6ccx      0m           2Mi
default       nginx-deployment-9456bbbf9-v9rc8      0m           2Mi
default       nginx-deployment-9456bbbf9-vwsfr      0m           2Mi
default       nginx-deployment-9456bbbf9-x2jnb      0m           2Mi
default       nginx-deployment-9456bbbf9-xhllv      0m           2Mi
default       nginx-deployment-9456bbbf9-z7hhr      0m           2Mi
default       nginx-deployment-9456bbbf9-zj7qc      0m           2Mi
default       nginx-deployment-9456bbbf9-zqptw      0m           2Mi
kube-system   aws-node-f4kf4                        2m           35Mi
kube-system   aws-node-m6xjs                        3m           35Mi
kube-system   cluster-autoscaler-5c4d9b6d4c-k2csm   3m           26Mi
kube-system   coredns-d5b9bfc4-4bvnn                1m           12Mi
kube-system   coredns-d5b9bfc4-z2ppq                1m           12Mi
kube-system   kube-proxy-qqrw9                      1m           10Mi
kube-system   kube-proxy-x55c8                      1m           10Mi
kube-system   metrics-server-84cd7b5645-prh6c       4m           16Mi
8 在EKS中访问ECR

应为EKS托管的Node Group中的Node,我们不能修改上面的docker配置文件,所有不能用我们自己的Harbor除非你有正确的证书。所以采用AWS ECR就没有这些麻烦了。

8.1 创建repository

首先创建一个内联策略:”TestEKSonECRPolicy”,然后才能创建docker repository, 获取login token并上传镜像。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": [
                "ecr:CreateRepository",
                "ecr:GetDownloadUrlForLayer",
                "ecr:DescribeRegistry",
                "ecr:GetAuthorizationToken",
                "ecr:UploadLayerPart",
                "ecr:ListImages",
                "ecr:DeleteRepository",
                "ecr:PutImage",
                "ecr:UntagResource",
                "ecr:BatchGetImage",
                "ecr:CompleteLayerUpload",
                "ecr:DescribeImages",
                "ecr:TagResource",
                "ecr:DescribeRepositories",
                "ecr:InitiateLayerUpload",
                "ecr:BatchCheckLayerAvailability"
            ],
            "Resource": "*"
        }
    ]
}

在ECR产品页面创建:

8.2 在EKS中拉取镜像

需要确认你的EKS node role托管角色有策略: AmazonEC2ContainerRegistryReadOnly

8.3 在EKS中推送镜像

运行如下命令获取login token.(注意修改ECR端点成你的).

aws ecr get-login-password --region us-east-1 | docker login --username AWS --password-stdin 675892200046.dkr.ecr.us-east-1.amazonaws.com

为Jenkins命名空间创建一个secret token,然后Jenkins中的pipeline就可以使用docker推送镜像到ECR中。

kubectl create secret generic awsecr --from-file=.dockerconfigjson=config.json  --type=kubernetes.io/dockerconfigjson -n jenkins

本作品采用知识共享署名 4.0 国际许可协议进行许可。

Apollo自动驾驶Yolo障碍物检测

原创文章,转载请注明: 转载自慢慢的回味

本文链接地址: Apollo自动驾驶Yolo障碍物检测

本篇以单元测试camera_lib_obstacle_detector_yolo_yolo_obstacle_detector_test.cc的测试demo_test为例来分析Apollo自动驾驶怎么使用Yolo算法来进行障碍物检测。
单元测试的Yolo算法基于Yolo V3改进,是单尺度检测的。

Yolo算法来进行障碍物检测(type-id)

7个对象的信息

type      alpha     xmin     ymin     xmax     ymax height  width   long     type_probs       visible_ratios[0-3]         cut_off_ratios[0-1]
   3 0 0  1.198  1229.00   626.00  1774.00   996.00  1.142  1.450  4.151 0 0 0 0  0.500    0  0.000  0.000  0.628  0.372  0.023  0.074
   3 0 0 -1.278   553.00   675.00   794.00   853.00  1.608  1.631  4.254 0 0 0 0  0.500    0  0.571  0.000  0.000  0.429  0.039  0.169
   3 0 0 -1.150    16.00   543.00   642.00   995.00  1.515  1.686  4.116 0 0 0 0  0.500    0  0.000  0.460  0.540  0.000  0.047  0.138
   3 0 0 -1.460   850.00   682.00   930.00   740.00  1.606  1.838  3.782 0 0 0 0  0.500    0  0.883  0.000  0.000  0.117  0.012  0.013
   3 0 0 -1.379   905.00   686.00   947.00   728.00  1.112  1.359  3.224 0 0 0 0  0.500    0  0.859  0.000  0.000  0.141  0.019  0.030
   9 0 0  0.693  1008.00   679.00  1033.00   708.00  0.570  1.045  1.451 0 0 0 0  0.456    0  0.000  0.000  0.817  0.183  0.059  0.040
  10 0 0  0.653  1747.00   564.00  1856.00   886.00  1.749  0.498  0.501 0 0 0 0  0.499    0  0.000  0.000  0.440  0.560  0.122  0.209

本测试使用的Yolo网络模型

继续阅读“Apollo自动驾驶Yolo障碍物检测”本作品采用知识共享署名 4.0 国际许可协议进行许可。

Apollo参考线优化之DiscretePointsReferenceLineSmoother

原创文章,转载请注明: 转载自慢慢的回味

本文链接地址: Apollo参考线优化之DiscretePointsReferenceLineSmoother

Apollo的的规划算法基于Frenet坐标系,因此道路中心线的平滑性控制着车辆是否左右频繁晃动,而高精地图的道路中心线往往不够规划。Apollo在/modules/planning/reference_line中包含了多种参考线平滑算法:DiscretePointsReferenceLineSmoother(离散点平滑法,包括FEM_POS_DEVIATION_SMOOTHING有限元位置差异和COS_THETA_SMOOTHING余弦),QpSplineReferenceLineSmoother(三次样条插值法),SpiralReferenceLineSmoother(螺旋曲线法)。本篇以单元测试discrete_points_reference_line_smoother_test.cc的测试TEST_F(DiscretePointsReferenceLineSmootherTest, smooth)为例来分析Apollo对参考线reference line进行离散点平滑(FEM_POS_DEVIATION_SMOOTHING)的原理。

离散点平滑法原理

Apollo默认采用的平滑算法,其将参考线平滑构造成了一个二次优化问题,并使用osqp求解器进行求解。那么通过构建它的代价函数及约束条件就可以利用二次优化框架直接求解。
1 首先在参考线上隔相同距离打点(P_k(x_k,y_k)),绿色的曲线就是算法将要得到的理想曲线。

2 然后列出代价函数:

    \[ cost=cost_{smooth}+cost_{length}+cost_{deviation} \]

其中,cost_{smooth}为平滑度代价,cost_{length}为长度代价,cost_{deviation}为相对原始点偏离代价。

    \[ cost_{smooth}=\sum_{k=0}^{n-3}\parallel (x_k+x_{k+2})-2x_{k+1} \parallel^2_2 \]

    \[ cost_{length}=\sum_{k=0}^{n-2}\parallel y_{k+1}-y_k \parallel^2_2 \]

    \[ cost_{deviation}=\sum_{k=0}^{n-1}\parallel z_k-z_{k-ref} \parallel^2_2 \]

cost_{smooth}要求相邻的3点尽量在同一条直线上,cost_{length}要求相邻2点不能太长,cost_{deviation}要求曲线上的点不能离参考点太远。在FEM_POS_DEVIATION_SMOOTHING算法中,cost_{smooth}的权重远远大于其它2个。

继续阅读“Apollo参考线优化之DiscretePointsReferenceLineSmoother”本作品采用知识共享署名 4.0 国际许可协议进行许可。

Apollo自动驾驶车道检测

原创文章,转载请注明: 转载自慢慢的回味

本文链接地址: Apollo自动驾驶车道检测

本篇以单元测试camera_lib_lane_postprocessor_darkscnn_lane_postprocessor_test.cc的测试camera_lane_postprocessor_point_test为例来分析Apollo自动驾驶怎么进行车道检测。
利用DarkSCNN算法对摄像头拍摄到的路面图片进行预测,来获取车道线在以车辆坐标系下的位置。

摄像头输出图片

DarkSCNN输出的车道线Mask图

融合到原图上的车道线


继续阅读“Apollo自动驾驶车道检测”本作品采用知识共享署名 4.0 国际许可协议进行许可。