type
status
date
slug
summary
tags
category
icon
password
程序猿少不了和shell脚本打交道,可能没多少人想过去管理脚本,大多关键操作都只是存在文档中。运维则是经常面对一堆脚本,针对不同的自动化目标编写不同的脚本,日积月累,如果不进行管理,每次都需要重新学习重新编写,总有种做体力活的感觉。可惜市面上并没有很好的shell脚本管理方案,本文也只是探讨如何高效管理shell脚本,做个简单需求分析。并准备开个新坑,做个辅助工具给自己管理shell脚本,项目打算命名为quick-setup。

shell脚本管理的现状

不同的脚本语言的编程目标不同,shell脚本比较单纯,以自动化操作系统中的命令为编程目标,因此Unix和类Unix操作系统天然内置解释器,只需要按照规范编写脚本文件即可执行,非常便利。可能正是因为这种单纯的目标便利性,让shell脚本在绝大多数情况下是不需要进行管理的。因为针对某特定自动化目的的操作,编写一个脚本文件即可,底层依赖的都是特定的命令,不需要多文件管理;也因为其便利性,打开任意的文本编辑器编写文本即可,不需要依赖任何功能复杂的IDE。这样就没有其他语言那种各种依赖包管理、复杂的文本组织、开发框架等等存在的必要。所以,绝大多数情况下,大家管理好自己的shell脚本文件即可,没太多技巧,更别说管理工具了。
shell脚本的最佳实践,就是作为单独的文件跟随项目进行管理。大多数脚本都是特定的简单流程化操作,没有管理的必要,脚本跟随项目更新即可。还有一些场景,流程复杂,但是没多少可复用的片段。这些场景都不在本文的讨论范畴内,本文只讨论少数情况,脚本片段需要复用的场景。比如新服务器的自动化配置和部署,因为不同的项目有不同的部署目标,自然脚本会不一样;但很多部署脚本片段又是相同的,需要经验复用。如果脚本还是跟随项目更新,就意味着运维需要不断重写更新的片段,任何新的变化和经验都不能自动更新到项目中去,很多时候就是重新学习,做重复工作。而且分散的脚本,也很难做复用部分的版本管理。
常规的管理方案,就是把shell脚本按照自动化目的和场景,作为单独的文件,然后用目录结构进行分类管理。如果需要复用片段,就把片段单独抽离成文件,通过source的方式引入到其他脚本中。如果需要针对不同场景有不同的配置,就在脚本头部设置参数,让使用者可以根据场景改参数。如果需要版本管理,就作为git库管理起来。
更进一步,shell脚本也是可以进行结构化设计的,可以自己做个框架,把常用的功能和外壳都写进去,然后source引入要配置的模块。
常规的管理方案最大的问题是结构化设计和复用困难。
shell脚本不像别的语言,语法太弱,缺乏工具支持,很难进行结构化设计。哪怕通过目录定义了结构,通过source引用文件,每次使用的时候传递文件夹和一堆文件也很不方便。虽然解决了复用问题,但很容易越设计越使用困难,心智负担过重。
见过有的大神干脆把所有功能都丢一个脚本文件里面进行通用化结构设计的,框架和功能全部杂揉在一起,一个文件8000多行代码,有应用需求找对应的代码逻辑都困难,更别说维护和管理了。
总结下来,写shell脚本的常规体验就是,每次写都像是重新开始,基于记忆里的经验去google具体写法。或者好一点,去找自己整理总结的最新版本的框架外壳,copy到一个新的文件里面重新开始,经验很难沉淀。

需求分析

最终用户

得到一个单独的脚本文件,一键执行即可,或者类似curl xxx | bash的一键远程获取脚本内容到本地执行的体验。

集成工程师

通过配置编排脚本的业务逻辑,然后使用工具生成成品脚本,或者直接执行脚本。配置和工具命令越简单越好,进一步的,如果集成工程师在编排脚本业务逻辑的过程中,能够从工具获得更多的帮助简化设计过程最好。而且,集成工程师要能够非常方便地获取其他人维护的功能模块,和框架外壳。

模块维护工程师

开发和维护自己的功能模块,开发和维护过程越简单越好,不要比单独写简单脚本增加太多学习成本。

框架外壳工程师

这里的框架外壳是指最终呈现给用户的脚本的框架和框架的基本功能,而不是工具软件本身。工具本身是一个独立于脚本的软件、引擎、甚至是平台。有一些工程师是细化搞结构化设计的(比如我),那么由这些人负责维护脚本的框架外壳就好了。

工具设计与开发工程师

最复杂的工作应该由这部分人来承担,因为这些人喜欢折腾和设计,把工具作为一个引擎和平台,让其他人能够很方便地在工具软件的基础上拓展自己的应用。

概念设计与技术选型

根据需求分析应该有以下几种概念:
  1. 组件(就是前面说的“模块”),应该是具备独立功能的脚本。
  1. 组件库,就是一个存放组件的文件夹,可以包含多个组件,可以是git仓库,由模块维护工程师单独维护。
  1. 配置文件,通过配置来指导成品脚本的生成,以及可以配置组件的参数。
  1. 脚本框架(就是前面说的“框架外壳”),工具根据配置文件,将用户配置的组件列表塞入脚本框架,生成成品脚本。这部分由框架外壳工程师维护(这些人喜欢折腾),集成工程师可以选择不同人维护的脚本框架。
  1. 成品脚本,由集成工程师,根据需求,选用不同的人维护的脚本框架和组件,修改配置文件,使用工具生成最终的脚本,交付给最终用户使用。
当然,所有的角色可以是同一个人,划分角色只是为了让不同特点的人做自己擅长或是感兴趣的事情,然后通过工具制定的规范协同,大家不需要知道对方的存在,但是只要遵照规范开发,就能够相互复用各自的工作。
最后,就是工具的设计和开发工程师去实现这样的“引擎”了。
技术选型上,作为业务型软件,我的倾向是必须云原生。软件开发的更新和分享都非常方便,大势所趋,而脚本的代码即程序,天然适合云原生。软件的开发语言上,我对脚本语言不感冒,除了系统操作的shell脚本和web前端的JS脚本无可替代性外,其他能不用脚本绝不用脚本,python不在我的选择范围。综合下来首选golang,有比肩python的面向接口编程语法便利性,比肩Java的业务系统开发生态,比肩C++的性能。
要把脚本拆分为组件、配置文件、脚本框架三部分,由工具进行组装,那么yaml配置文件+Jinja2模板是很好的选择,刚好golang内置类Jinja2模板引擎。另外,golang出来的是二进制,不需要类似python脚本的解释器,进一步降低依赖,缩小体积,也是我喜欢的特点。
这个工具的核心目标是:
  1. 任何人都能够非常便利的开发自己的组件库,和脚本框架。
  1. 任何人都能够非常便利的使用别人开发的组件库和脚本框架,通过配置文件构建针对自己使用场景的脚本。
  1. 工具的核心应该足够小,部署足够便利,使用足够方便。
很早就想做一个这样的shell脚本管理工具了,因为一直没找到好用的,每次写脚本都像是一个重新学习的过程,难复用,太浪费时间。后来找到了一个知名运维自动化工具Ansible,发现很多设计理念非常相似,很值得借鉴。只是Ansible的主要目标是批量自动化运维多台主机,并非以shell脚本管理为目标,而且是以python为基础构建模块,并非原生shell,多多少少增加一些操作步骤。所以,既然感兴趣还是自己挖个坑,慢慢做吧。

功能设想

基于前面的概念设计和技术选型,能够设想这个工具可以拓展出非常多的可能性。
  1. 基于开发规范,可以构建出应用市场,而且这个应用市场是云原生的,任何人都可以分享和应用别人的组件和脚本框架,甚至是维护自己的应用市场,不需要服务器支持。
  1. 可以基于配置和命令增加UI,TUI或者是WEB为优选,通过UI更加便利得浏览应用市场(在线组件库),和本地组件库,以及配置参数组织自己的脚本配置。TUI直接可以SSH远程终端显示,而WEB需要浏览器,同样是可以远程访问,没什么本地依赖。
  1. 工具不仅可以生成shell脚本,甚至可以通过配置生成工程模板,同样是符合设计规范的。
  1. 还有非常多能够想象得到的拓展场景,慢慢发掘。
可以想象这么几个场景:
  1. 每次部署环境都要操作一系列命令,照着文档一条条操作,有变化的时候还不知道在哪里改脚本。有这个工具后,直接从应用市场中找到相关的组件,勾选要部署的,参数也在配置文件里面改,然后工具自动依次执行完成基于配置的自动化部署。
  1. 朋友不知道怎么部署环境,自己这边改好配置后,直接生产朋友需要的脚本丢给他。甚至是自己可以做个配置文件,丢个配置文件给他,再丢一条命令给他,命令能够自动下载工具,然后基于配置文件加载组件库和脚本框架,要改什么配置参数他自己在配置文件里面改就行了,直接在他本地执行基于配置的成品脚本。
  1. 朋友玩ROS2是新手,想要一套适合自己目的的工程模板,完全可以把这种工程模板当做组件写进去,然后丢给朋友一个配置文件和命令,朋友改改配置文件里面适合自己的参数,就能够生成自己想要的ROS2工程模板。
能够拓展的玩法很多,重点是基于规范,能够进行经验沉淀和高效复用,以及便利的分发,可以给运维过程节省很多时间。这所有的基础当然是有人维护组件库和脚本框架了,当然还有工具开发得支持这些功能构想,没人用就自己慢慢玩了。现在只是构想,挖个大坑自己慢慢填。
 
quick-setup如何简化shell脚本管理快速部署ROS2开发环境
Loading...