news 2026/5/12 10:12:35

基础设施模板CLI工具:Boilerplates

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
基础设施模板CLI工具:Boilerplates

Boilerplates CLI

Boilerplates是一个用于管理基础设施模板(boilerplates)的复杂集合,并配备了一个Python CLI工具。它支持Terraform、Docker、Ansible、Kubernetes等多种技术,帮助您快速生成、定制和部署配置模板。

功能特性

  • 多技术模板支持:提供Docker Compose、Terraform、Ansible、Kubernetes、Packer等基础设施模板。
  • 交互式变量收集:通过交互式CLI提示,引导用户为模板变量输入值。
  • 智能默认值管理:支持保存常用变量的默认值,并在多个项目中复用。
  • Git仓库集成:模板库基于Git管理,支持添加、更新和移除自定义模板仓库。
  • Jinja2模板渲染:使用Jinja2引擎渲染模板,支持条件语句和变量替换。
  • 模块化架构:通过模块系统(Module)组织不同技术的模板和命令。
  • 配置文件管理:提供配置管理功能,存储用户默认值和偏好设置。
  • 安全与验证:包含模板语法验证、变量类型检查和路径安全防护。

安装指南

使用安装脚本(推荐)

通过自动化安装脚本安装Boilerplates CLI:

# 安装最新版本curl-fsSL https://raw.githubusercontent.com/christianlempa/boilerplates/main/scripts/install.sh|bash# 安装特定版本curl-fsSL https://raw.githubusercontent.com/christianlempa/boilerplates/main/scripts/install.sh|bash-s -- --version v1.2.3

安装脚本使用pipx为CLI工具创建一个隔离环境。安装完成后,终端中即可使用boilerplates命令。

依赖要求

  • Python 3+
  • Git(用于模板库管理)
  • pipx(用于隔离安装,安装脚本会自动检查)

使用说明

基础命令

# 查看帮助信息boilerplates --help# 查看版本boilerplates --version# 更新模板库boilerplates repo update# 列出所有已配置的库boilerplates repo list

模板操作

# 列出所有可用的Docker Compose模板boilerplates compose list# 查看特定模板的详细信息boilerplates compose show nginx# 生成模板(交互式模式)boilerplates compose generate authentik# 生成模板到自定义输出目录boilerplates compose generate nginx my-nginx-server# 非交互式模式,直接指定变量值boilerplates compose generate traefik my-proxy\--varservice_name=traefik\--vartraefik_enabled=true\--vartraefik_host=proxy.example.com\--no-interactive

管理默认值

# 设置变量的默认值boilerplates compose defaultssetcontainer_timezone"America/New_York"boilerplates compose defaultssetrestart_policy"unless-stopped"

模板库管理

# 添加自定义模板库boilerplates repoaddmy-templates https://github.com/user/templates\--directory library\--branch main# 移除模板库boilerplates repo remove my-templates

核心代码

CLI主入口 (cli/__main__.py)

#!/usr/bin/env python3""" Main entry point for the Boilerplates CLI application. This file serves as the primary executable when running the CLI. """from__future__importannotationsimportimportlibimportloggingimportpkgutilimportsysfrompathlibimportPathfromtypingimportOptionalfromtyperimportTyper,Context,Optionfromrich.consoleimportConsoleimportcli.modulesfromcli.core.registryimportregistryfromcli.coreimportrepo# Using standard Python exceptions instead of custom ones# NOTE: Placeholder version - will be overwritten by release script (.github/workflows/release.yaml)__version__="0.0.0"app=Typer(help="CLI tool for managing infrastructure boilerplates.\n\n[dim]Easily generate, customize, and deploy templates for Docker Compose, Terraform, Kubernetes, and more.\n\n [white]Made with 💜 by [bold]Christian Lempa[/bold]",add_completion=True,rich_markup_mode="rich",)console=Console()defsetup_logging(log_level:str="WARNING")->None:"""Configure the logging system with the specified log level. Args: log_level: The logging level (DEBUG, INFO, WARNING, ERROR, CRITICAL) Raises: ValueError: If the log level is invalid RuntimeError: If logging configuration fails """numeric_level=getattr(logging,log_level.upper(),None)ifnotisinstance(numeric_level,int):raiseValueError(f"Invalid log level '{log_level}'. Valid levels: DEBUG, INFO, WARNING, ERROR, CRITICAL")try:logging.basicConfig(level=numeric_level,format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',datefmt='%Y-%m-%d %H:%M:%S')logger=logging.getLogger(__name__)logger.setLevel(numeric_level)exceptExceptionase:raiseRuntimeError(f"Failed to configure logging:{e}")@app.callback(invoke_without_command=True)defmain(version:Optional[bool]=Option(None,"--version","-v",help="Show the application version and exit",),log_level:str=Option("WARNING","--log-level","-l",help="Set the logging level (DEBUG, INFO, WARNING, ERROR, CRITICAL)",),ctx:Context=None,)->None:"""Main entry point for the boilerplates CLI. Args: version: Show version information log_level: Logging level for the application ctx: Typer context object """ifversion:console.print(f"Boilerplates CLI [bold]v{__version__}[/bold]")raiseSystemExit(0)try:setup_logging(log_level)except(ValueError,RuntimeError)ase:console_err.print(f"[red]Failed to set up logging:{e}[/red]")sys.exit(1)# Discover and register modules_discover_modules()# Register repository management commandsapp.add_typer(repo.app,name="repo")ifctx.invoked_subcommandisNone:console.print(app.info.help)raiseSystemExit(0)def_discover_modules()->None:"""Dynamically discover and register all modules in the modules package."""try:for_,name,_inpkgutil.iter_modules(cli.modules.__path__):module_path=f"cli.modules.{name}"try:importlib.import_module(module_path)logger.debug(f"Successfully imported module:{name}")exceptExceptionase:logger.warning(f"Failed to import module '{name}':{e}")continuelogger.info(f"Module discovery completed. Total modules:{len(list(registry.iter_module_classes()))}")exceptExceptionase:logger.error(f"Module discovery failed:{e}")raiseif__name__=="__main__":app()

变量集合管理 (cli/core/collection.py)

from__future__importannotationsfromcollectionsimportdefaultdictfromtypingimportAny,Dict,List,Optional,Set,Unionimportloggingfrom.variableimportVariablefrom.sectionimportVariableSection logger=logging.getLogger(__name__)classVariableCollection:"""Manages variables grouped by sections and builds Jinja context."""def__init__(self,spec:dict[str,Any])->None:"""Initialize VariableCollection from a specification dictionary. Args: spec: Dictionary containing the complete variable specification structure Expected format (as used in compose.py): { "section_key": { "title": "Section Title", "prompt": "Optional prompt text", "toggle": "optional_toggle_var_name", "description": "Optional description", "vars": { "var_name": { "description": "Variable description", "type": "str", "default": "default_value", ... } } } } """ifnotisinstance(spec,dict):raiseValueError("Spec must be a dictionary")self._sections:Dict[str,VariableSection]={}# NOTE: The _variable_map provides a flat, O(1) lookup for any variable by its name,# avoiding the need to iterate through sections. It stores references to the same# Variable objects contained in the _set structure.self._variable_map:Dict[str,Variable]={}self._initialize_sections(spec)# Validate dependencies after all sections are loadedself._validate_dependencies()def_initialize_sections(self,spec:dict[str,Any])->None:"""Initialize sections from the spec."""forsection_key,section_datainspec.items():ifnotisinstance(section_data,dict):continue# Create VariableSectionsection_dict={"key":section_key,"title":section_data.get("title",section_key.title()),"description":section_data.get("description"),"toggle":section_data.get("toggle"),"required":section_data.get("required",section_key=="general"),}# Handle dependenciesifneeds:=section_data.get("needs"):section_dict["needs"]=needs section=VariableSection(section_dict)# Add variables to sectionif"vars"insection_dataandisinstance(section_data["vars"],dict):forvar_name,var_datainsection_data["vars"].items():ifnotisinstance(var_data,dict):continue# Create Variablevar_dict=var_data.copy()var_dict["name"]=var_name var_dict["origin"]="template"variable=Variable(var_dict)# Store in section and flat mapsection.variables[var_name]=variable self._variable_map[var_name]=variable self._sections[section_key]=sectiondef_validate_dependencies(self)->None:"""Validate that all section dependencies exist."""forsection_key,sectioninself._sections.items():fordepinsection.needs:ifdepnotinself._sections:logger.warning(f"Section '{section_key}' depends on non-existent section '{dep}'")defget_section(self,section_key:str)->Optional[VariableSection]:"""Get a section by its key."""returnself._sections.get(section_key)defget_sections(self)->Dict[str,VariableSection]:"""Get all sections."""returnself._sections.copy()defis_section_satisfied(self,section_key:str)->bool:"""Check if a section's dependencies are satisfied."""section=self._sections.get(section_key)ifnotsection:returnFalse# General section is always satisfiedifsection_key=="general":returnTrue# Check all dependenciesfordepinsection.needs:dep_section=self._sections.get(dep)ifnotdep_sectionornotdep_section.is_enabled():returnFalsereturnTruedefget_jinja_context(self)->Dict[str,Any]:"""Build Jinja2 template contextfromallvariables.Returns:Dictionary mapping variable names to their valuesfor更多精彩内容 请关注我的个人公众号 公众号(办公AI智能小助手) 对网络安全、黑客技术感兴趣的朋友可以关注我的安全公众号(网络安全技术点滴分享)
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/9 12:02:00

苹果M系列芯片表现:MacBook Pro运行anything-llm流畅吗?

苹果M系列芯片表现:MacBook Pro运行anything-llm流畅吗? 在生成式AI席卷全球的今天,越来越多开发者开始将大语言模型从云端“搬”回本地。不是因为算力过剩,而是出于对数据隐私、响应速度和离线可用性的刚性需求。尤其对于自由职业…

作者头像 李华
网站建设 2026/5/9 10:33:01

Open-AutoGLM部署实战手册(新手避坑+性能调优全收录)

第一章:Open-AutoGLM部署实战概述Open-AutoGLM 是一个面向自动化自然语言处理任务的开源大模型部署框架,旨在简化从模型加载、推理服务构建到生产环境集成的全流程。其核心优势在于支持多后端推理引擎(如 Hugging Face Transformers、vLLM 和…

作者头像 李华
网站建设 2026/5/1 7:10:46

LangFlow与意图识别结合:构建智能对话路由系统

LangFlow与意图识别结合:构建智能对话路由系统 在企业级AI应用快速落地的今天,一个常见的挑战浮现出来:如何让强大的大语言模型(LLM)真正“听懂”用户,并做出精准、高效的服务响应?尤其是在客服…

作者头像 李华
网站建设 2026/5/9 9:05:41

Groq LPU推理速度实测:比GPU快10倍的流水线架构

Groq LPU推理速度实测:比GPU快10倍的流水线架构 在智能问答系统日益普及的今天,用户早已不再满足于“能回答”,而是追求“秒回”——尤其是在处理企业文档、财报分析或技术手册这类复杂任务时,哪怕多等半秒,体验都会大…

作者头像 李华
网站建设 2026/5/10 1:06:21

前端开发者必看:深度克隆 JSON 对象的实战指南(附避坑技巧)

前端开发者必看:深度克隆 JSON 对象的实战指南(附避坑技巧)前端开发者必看:深度克隆 JSON 对象的实战指南(附避坑技巧)为什么你复制的 JSON 数据总在“悄悄”被修改?浅拷贝 vs 深拷贝&#xff1…

作者头像 李华
网站建设 2026/5/5 23:02:09

LangFlow构建多模态AI系统的实践案例分享

LangFlow构建多模态AI系统的实践案例分享 在智能客服系统开发的日常中,你是否曾为一个简单的知识库问答功能调试数小时?当产品同事提出“能不能加个判断,如果答案不确定就转人工”,原本清晰的代码逻辑瞬间变得错综复杂。更别提团队…

作者头像 李华