经过一年半的 bootstrapping(一种再抽样统计方法),Lyft 让 Level 5 实现区分非常相似,但又不完全相同的两辆汽车。Level 5 是自动驾驶等级分类的最高级别,可以实现完全自动
经过一年半的 bootstrapping(一种再抽样统计方法),Lyft 让 Level 5 实现区分非常相似,但又不完全相同的两辆汽车。Level 5 是自动驾驶等级分类的最高级别,可以实现完全,由车辆完成所有驾驶操作,人类驾驶员不需要集中注意力,不限定道路和环境。
Lyft 的工程师和操作人员花费大量的时间了解每辆车的微妙差异和独特环境。从云计算模块开始,Lyft 构建了一个名为 Flexo 的汽车部署平台,以确保能自动构建车队软件,并为每个自动驾驶汽车(AV)部署相同的环境。如今,每辆汽车都使用相同的磁盘映像,工程师和操作人员都拥有稳定的工作环境。 本文介绍了这款 Level 5 自动驾驶部署平台的构建过程和技术细节。
在 Level 5 中,硬件团队会在内部运营自己的 AV 车队。由于现在 AV 发展仍处于初期阶段,因此车队必须提供两种截然不同的用例。一个是运营团队执行诸如班车服务和数据收集等任务的稳定平台,另一个则是为不断改进堆栈的软件工程师的开发平台。这两组用户的要求完全不同:运营团队需要具有最少选项和高度可预测行为的一站式设备平台,而工程师需要最大的灵活性,以便他们可以快速迭代。
作者从一个基于 Salt 的简单配置管理系统开始,该系统根据需要车辆的用户类型配置车辆。操作方法是首先复制该软件,在汽车中重新配置高性能计算机(HPC),并从源代码构建。同样,工程师可以根据自己的需要提取分支,构建和重新配置 HPC。这种方法因为开发很早,汽车不会被频繁使用,在早期汽车数量不多的时候能正常工作,可以使用汽车 HPC 来构建软件堆栈。随着 AV 车队扩大规模,软件堆栈复杂性增加,每当任务类型发生变化时,就会浪费大量时间来重新配置和构建数十辆汽车。显然,该方法还有待提升!
在研发 Level 5 车辆早期,作者讨论了磁盘交换与网络连接在删除记录传感器数据方面的优缺点。 根据每天每台车发送数据大小作者选择了磁盘交换。选择该方法的原因有很多,包括高速以太网电缆和连接器的机械刚性,以及无法保证车库中的高速网络端口。最重要的是,车辆的周转时间对车队的生产率至关重要。我们可以在任何地方在 30 秒内更换驱动器,但使用 50 Gbps 以太网连接回收 4TB 的驱动器需要大约 10 分钟。此外,车库可以快速建造并移动到任何位置。由于磁盘可以邮寄,因此对高速网络并不是一项硬性要求。
这就是作者采用一种流程来交换数据驱动器进出汽车的原因。作者采用类似的方法在启动驱动器上部署软件。
简而言之,Flexo 构建了引导驱动器。这是一个硬件和软件解决方案,可以使用完整的软件刻录数十个相同的硬盘,从 Linux 引导加载程序到每天构建的自动驾驶汽车软件的特定版本,并为任务类型设置配置信息。
在高层次上,Flexo 是一个标准的 Ubuntu 18.04 服务器系统,使用以下方法构建:
-
-
-
-
-
用于监控 Telegraf 和 Wavefront
Flexo 示意图
Flexo 部署平台将 git 存储库中托管的源代码转换为可以在 AV 计算机上引导的磁盘映像。其可以分解为以下功能组件:
-
图像构建器:负责从存储在 git 存储库中的源代码构建可启动文件系统
-
图像刻录机:采用这些可引导文件系统并将它们刻录到多个硬盘驱动器上
-
-
-
Flexo 的主要任务是构建和管理图像。图像只是完整可启动文件系统的tar压缩存档,然后使用图像刻录机来刻录启动驱动器。这些图像通常约为 100 多 GB,因为图像中包括高清(HD)地图。Lyft 已使用容器多年,因此选择 Docker 作为构建图像的自然选择工具。Docker 定义了一种成熟且灵活的语言和工具链,用于构建容器图像。在用例中,作者只使用 Docker 作为构建映像的工具,而不运行 Docker。因此,作者需要手动安装引导加载程序(grub),内核及容器内的初始虚拟内存盘。
作者使用几种不同的 Dockerfiles,具体取决于对图像的配置。下面是文中使用的 Dockerfiles 的大致内容:
-
从标准的 Ubuntu 16.04 docker 镜像开始
-
安装一个 linux 内核和 grub,以便映像可以在裸机上启动(docker 镜像没有内核,因为容器在运行时与主机共享内核)。
-
复制相关软件存储库
-
具体而言,使用 SaltStack 配置文件系统进行所需的配置
-
设置用户和权限
-
安装所有需要的 Ubuntu 软件包
-
安装和配置 systemd 单元和 udev 规则以查找车辆特定数据(见下文)
-
安装系统构建依赖项
-
根据设置配置项构建自己的软件
-
将图像导出为 tar 文件
现在,发布经理通常只要批准了新版本的生产用途,就会手动开始构建图像。作者正在寻找方法将这一过程标准化。由于使用了容器技术,映像构建组件与其运行的主机分离。
图像构建完全与车辆无关,因为从硬件角度来看,同代的所有车辆都是相同的,甚至在运行时也会处理代际差异。但是,作者需要保留一些车辆特有的数据,包括车辆的身份(以便跟踪记录的数据和日志),加密密钥和证书以及校准参数。由于 Flexo 创建的启动驱动器都可以安装到任何车辆中,因此添加了永远不会以 USB 记忆棒的形式从汽车中移除的本地存储。
映像刻录机组件负责将可启动文件系统构建到多个硬盘驱动器上。该组件需要处理 20 多个硬盘驱动器,这些硬盘驱动器在系统打开时由操作员插入和拔出。
每个硬盘驱动器由唯一的 sync_all_image_to_disk @ sd * systemd 单元管理。鉴于可以随时添加和删除硬盘驱动器,作者利用 udev-- Linux 内核使用的通用设备管理器,支持 udev 而不是cron 作业,以便作者可以在插入磁盘后立即启动图像刻录过程。作者使用 udev 规则为每个硬盘驱动器启动系统作业:
ENV{DEVTYPE}==”disk”, ENV{ID_PART_TABLE_UUID}==”00000000-*”, TAG+=”systemd”, ENV{SYSTEMD_WANTS}+=”sync_all_images_to_disk@$kernel.service”
该规则使用 $ kernel udev 替换 systemd 单元实例到硬盘设备路径。systemd 单元通过 %i 标识符将设备路径传递给 sync_all_images_to_disk 脚本:
ExecStart=/usr/local/bin/sync_all_images_to_disk /dev/%i
这意味着刻录过程与构建过程完全分离,是在插入驱动器时启动的。作者为操作员创建了一种精简的方式来判断何时准备就绪,这在下面的硬件部分中有所概述。当作者开发系统时,擦除了Flexo 系统本身的 O / S 驱动器,标记 Flexo 应该使用的硬盘。每个 Flexo 驱动器都有一个以 00000000 开头的磁盘 GUID。udev 规则使用基于 ID_PART_TABLE_UUID 环境变量的附加过滤器,仅为标记为 Flexo 驱动器的磁盘启动 sync_all_images_to_disk @作业:
ENV{ID_PART_TABLE_UUID}==”00000000-*”
标记驱动器也有助于解决操作员的操作错误。如果错误插入非 Flexo 驱动器,则不会覆盖该驱动器。
每个 Flexo 硬盘驱动器都支持多个版本的完整软件堆栈。作者使用 GRUB 作为操作员的主要 UI,以便在任务开始时选择要引导的映像:
主 GRUB 配置维护硬盘驱动器的每个分区中可用的映像列表。每个映像都提供带有内核和初始虚拟内存盘配置的辅助 GRUB 引导加载程序。图像从主引导加载程序链式加载,尽可能地分离每个图像。并且一个映像中的错误配置不会影响硬盘驱动器的其他映像。
从上图中可以看出,每种分区类型都使用 UUID 前缀来指示它是什么类型的分区。作者还为文件系统添加了 UUID 前缀。值得注意的是,让 Flexo 的这部分稳定是非常耗时的。今天的图像刻录机流程不到 1000 行 BASH,但是每一行都需要做很多工作才能做到正确,因为这些低级工具的文档记录性能很差,相关论坛和博客也不多。
例如,Linux 支持动态安装文件系统,因为我们在每个驱动器上创建多达 12 个分区,而系统中最多有 24 个驱动器,而为了保持内核始终是最新的,会导致内核和系统级别的大量资源争用。作者不得不使用大量的读/写锁,并在最终变得稳定之前对 partprobe 进行显式调用以更新内核的新分区视图。
作者在设计 Flexo 之前遇到的一个痛点是,每个启动盘的状态会随着时间的推移而漂移,因为启动盘将留在车内并由连续的任务重用。而要完成本文中的任务,必须要将之前的任务清除,以便之前的任务不会对下一个任务产生影响。为此,作者使用 overlayroot 包在现有图像的顶部提供可写层。硬盘驱动器上的覆盖分区用作在运行时存储图像更改的临时位置。作者使用带有随机密码的 crypt 后端来确保在重新启动时擦除实时系统期间所做的任何更改。对于所有操作目标图像,GRUB 配置中的 overlayroot 设置已打开:
overlayroot=”crypt:dev=/dev/disk/by-partuuid/55555555-<DISK_ID>-555555555555,mkfs=1,fstype=ext4,recurse=0"
此功能与操作团队总是在任务之间重新启动计算机的指令相结合,大大减少了工程师花在支持运营团队上的时间。
在开发 Flexo 系统时,作者很快意识到将硬盘从一个系统移动到另一个系统进行测试会导致迭代周期延长。作者开始利用 kvm 和 OVMF 来加速开发。OVMF提供类似于汽车中的计算机的UEFI bios。此虚拟化测试环境还包括用于汽车标识的本地 USB 驱动器。通过类似于以下的 kvm 命令启动给定硬盘驱动器的测试环境:
kvm -m 4096 -bios OVMF.fd -drive format=raw,file=/dev/sdk -drive format=raw,file=”car_data.img” — vnc :59
作者可以测试从 BIOS 到 Flexo 系统本身的 AV 软件堆栈(包括图形部分)的实际启动的完整启动顺序。甚至可以包括车辆特定USB记忆棒的虚拟版本(上面的 car_data.img)。并非所有项都能在 VM 中正确启动,但足以验证大多数系统设置。
由于每辆车至少需要一个启动盘(作者通常会保留多个启动盘,以便在一个启动盘在使用时不必等待新的启动盘),每个 Flexo 系统都是标准的机架式服务器,有 24 个驱动器托架,允许批量交换驱动器,并为每个存放汽车的站点保留了几个系统。
I / O 吞吐量是最重要的指标。将整个工作集保存在 RAM 中对于高速刻录磁盘至关重要,因此作者为 Flexo 计算机提供尽可能多的 RAM。由于 Flexo 系统的磁盘刻录部分是自运行的,作者使用 ledmon 来控制机箱 LED 以指示磁盘状态。插入磁盘后,LED 会变暗,然后在刻录过程中开始快速闪烁。最后,亮红灯表示驱动器已准备好被取出并移动到车辆上。
Lyft 所有的汽车和 AV 运营商现在都在使用 Flexo 部署平台。由于可启动图像完全可工作,任务启动时间大幅减少,开发人员也不再对 O / S 的状态存疑。稳定的环境使得其在故障排除过程中可以减少变化因素。
随着车队的扩展,Flexo 部署平台将部署到多个系统。Lyft 正在考虑将图像构建器组件移动到云端,以确保所有 Flexo 系统中的图像都相同。Lyft 还希望扩展 Flexo,使其能够为特定开发人员构建映像,并在云中不断测试映像。在加速开发循环并尽可能快地向开发人员提供反馈方面,Flexo 部署流程将发挥关键作用。
时间:2019-09-10 23:59 来源: 转发量:次