使用fastapi和pulumi搭建基于Azure云的IAC Restful API服务 — 对外发布

news2024/11/28 4:44:40

图片

图片

前言

在IAC(即Infrastructure As Code,基础设施即代码)领域,Terraform 是一个老牌工具,使用HCL(HashiCorp Configuration Language)语言来编写配置文件。它支持几乎所有主流的云提供商,如AWS、Azure、GCP等,通过如下几个关键步骤管理基础设施:编写配置文件、初始化环境、生成执行计划、应用计划以及查看状态。

Pulumi 则是一个较新的IAC工具,支持使用多种常见的编程语言(如TypeScript、Python、Go、C#)来编写基础设施代码,而不仅限于声明式语法。这带来了许多灵活性和优势:

  1. 使用常用编程语言:Pulumi允许使用者使用熟悉的编程语言编写基础设施配置,这样可以使用语言本身的功能,如条件语句、循环、函数和模块化,提高代码的可读性和重用性。

  2. 更好的集成:Pulumi在与现有开发工具链(如CI/CD管道、测试框架等)集成方面表现出色,因此可以使用流行的编程生态系统中的库和工具。这对DevOps团队来说非常有吸引力。

  3. 灵活的状态管理:虽然Terraform也有状态文件用于记录资源的现实状态,Pulumi进一步简化了状态管理,允许使用不同的存储后端,包括云存储和Pulumi自己的服务。

  4. 更高的可扩展性:Pulumi支持JavaScript、TypeScript、Python、Go和C#等多种语言,这让它能够适应更广泛的需求和团队技术栈,可以更灵活地处理复杂的基础设施场景。

本文使用Python语言, 以pulumi作为后端IAC工具,服务端采用FastAPI框架提供Restful能力,来实现基于Azure云的IAC Restful API服务

架构设计

图片

架构说明:

  • 开发人员调用http接口来进行IAC操作

  • FastAPI服务端分为2个部分,一个gateway负责对外提供restful api服务,一个backend端负责解析前端数据,调用pulumi模块生成IAC代码

  • 任务信息会存入mysql数据库,起到任务追溯的作用以及作为资源cmdb的数据源

  • IAC操作完成后,会将此次操作变更同步进入资源CMDB

Pulumi模块说明

与经典的命令行模式执行pulumi来进行资源创建/变更不同,在本架构中使用Pulumi Automation来实现IAC能力。Pulumi Automation提供了一种编程接口,使得基础设施管理过程可以完全自动化和自定义。

Pulumi模块支持哪些资源

该模块涉及:

Azure资源模块

Resource GroupAks Cluster(ManagedCluster)Aks Nodepool(AgentPool)Availability SetContainer RegistryData FactoryDatabricks Access ConnectorDatabricks WorkspaceKey VaultLoad BalancerMysql Flexible ServerMysql Single ServerNetwork InterfaceNetwork Security GroupPrivate ZoneRecovery Service VaultRedisRole AssignmentRoute TableStorage AccountSubnetUser Assigned IdentityVirtual Machine

目前我们的pulumi模块现已支持以上azure资源

感兴趣的可以联系我们,提供相关代码模块

主要特点

  1. 集成灵活性:利用Pulumi Automation,可以更轻松地将基础设施管理操作嵌入到现有的应用程序或平台中。这对于需要与其他系统进行复杂交互的场景尤为适用,例如动态响应用户请求或事件驱动的基础设施变更。

  2. 复用性和模块化:通过将Pulumi的命令行操作封装在代码中,Pulumi Automation允许我们创建更具复用性和模块化的基础设施管理代码库。这对于大型团队和复杂项目尤其有价值,因为代码更易于维护和共享。

  3. 状态和并行处理:使用Pulumi Automation,可以更细致地管理资源状态和并行操作。我们可以根据具体情况编写代码来处理不同的资源状态,以及根据依赖关系有序地创建或销毁资源,这可以显著提升执行效率和可靠性。

  4. 错误处理和重试机制:通过编写自定义的错误处理和重试逻辑,Pulumi Automation可以更健壮地应对基础设施操作中的各种可能错误。我们可以在代码中捕获异常并进行适当的重试或回滚动作,而不必依赖于外部脚本或手动操作。

依赖模块

需求python 3.7+, 执行pip install -r requirements.txt来安装依赖模块

requirements.txt

pulumi>=3.0.0,<4.0.0pulumi-azure-native>=1.0.0,<2.0.0fastapi[all]jsonify>=0.5,<0.6pydantic>=1.9.1,<1.9.2pymysqlpyparsingpulumi_azure

实验步骤

前置条件

Python 

需求python 3.7+, 执行pip install -r requirements.txt来安装依赖模块 

Service Principal

服务主体必须对该订阅具有完全访问权限

pulumi环境变量

必须配置PULUMI_CONFIG_PASSPHRASE供pulumi连接到您的stack,若您使用非本地文件作为backend,则还需配置相应的backend所需字段

mysql数据库(可选)

用以记录资源创建任务信息

资源CMDB(可选)

根据自身需要,可配置一个资源CMDB,存放云资源实时参数配置与状态,以供实际使用

流程说明

图片

  • FastAPI gateway将异步调用backend方法,传递前端参数给到后端方法

  • FastAPI后端将参数入库,并调用pulumi模块,生成IAC代码

  • Pulumi模块内部使用Azure API,进行IAC操作

以下步骤为可选步骤

  • 资源信息同步至cmdb

  • FastAPI接口提供资源信息查询

步骤一、创建fastapi应用服务端

使用以下代码创建fastapi app(即对外restful api服务)

app.py

@auto_deploy_api.post("/create_resource")
async def create_res(VERABLES_DICT: Item, backgroundTasks: BackgroundTasks):
    VERABLES = VERABLES_DICT.VERABLES
    try:
        # 启动异步任务,因为创建资源耗时较长,http请求不应也无法一直保持
        backgroundTasks.add_task(create_resource, VERABLES, id)
        return {"message": "Task running at backend", "id": id}
    except auto.StackAlreadyExistsError:
        return HTTPException(status_code=409,detail="application already exists")
    except Exception as e:
        return Response(status_code=500, content=repr(e))

步骤二、集成fastapi与pulumi模块

将pulumi模块与fastapi服务集成在同一目录下,文件架构如下:

图片

app.py:fastapi 应用入口文件,定义restful接口

auto_deploy_inline.py:调用pulumi模块,执行IAC操作

pulumi_resources/IAC_resource:存放pulumi模块

create_resource 

def create_resource(VERABLES, task_id):
    project_name = VERABLES["GLOBAL_VARS"]["PROJECT_NAME"]
    app_name = VERABLES["GLOBAL_VARS"]["APPLICATION_NAME"]
    env = VERABLES["GLOBAL_VARS"]["ENV"]
    stack_name = "%s-%s-%s-stack" % (project_name, app_name, env)
    try:
        # 此方法处理前端传入的参数,调用pulumi模块,进行资源创建,此处仅以网络资源为例
        def resource_init():
            if "RESOURCE_GROUP" not in VERABLES.keys():
                raise Exception("Resource group is mandatory")
            rg = ResourceGroup(VERABLES["RESOURCE_GROUP"]["NAME"], location)
            if "NETWORK" in VERABLES.keys():
                if "ROUTE_TABLE" in VERABLES["NETWORK"].keys():
                    for rt_ele in VERABLES["NETWORK"]["ROUTE_TABLE"]:
                        RouteTable(rt_ele["name"], location, None, **rt_ele)
                if "NETWORK_SECURITY_GROUP" in VERABLES["NETWORK"].keys():
                    for nsg_ele in VERABLES["NETWORK"]["NETWORK_SECURITY_GROUP"]:
                        NetworkSecurityGroup(nsg_ele["name"], location, None, **nsg_ele)
             
 
        resource_stack = auto.create_or_select_stack(stack_name=stack_name,
                                                     project_name=app_name,
                                                     program=resource_init)
 
 
        update_resource_creation_task_record(data_dict)
        print("Start preview...")
        resource_up_res = resource_stack.preview(on_output=print)
        print("Preview OK...")
        time.sleep(1)
        print("Start up...")
        resource_up_res = resource_stack.up(on_output=print)
        print("Up OK...")
        data_dict["status"] = "successed"
        update_resource_creation_task_record(data_dict)
        return (resource_up_res.stdout)
    except Exception as e:
        data_dict["status"] = "failed"
        data_dict["output"] = repr(e)
        update_resource_creation_task_record(data_dict)

步骤三、启动fastapi应用

cd $YOURPATH/resource_deploy/auto_deploy_fastapi
uvicorn app:auto_deploy_api --host 0.0.0.0 --port 8000

步骤四、Postman调用接口创建资源

接下来,我们就可以通过http请求的方式,调用pulumi的IAC能力,操作Azure云的资源了

图片

示例payload

payload

{
    'VERABLES': {
        'GLOBAL_VARS': {
            'PROJECT_NAME': 'auto',
            'APPLICATION_NAME': 'auto',
            'ENV': 'dev',
            'LOCATION': 'chinanorth3',
            'SUBSCRIPTION_ID': '***********'
        },
        'RESOURCE_GROUP': {
            'NAME': 'test-pulumi-rg',
            'TAGS': {
                'ApplicationID': 'ITPlatform',
                'ApplicationName': 'ITPlatform'
            }
        },
        'NETWORK': {
            'ROUTE_TABLE': [{
                'name': 'test-rt01',
                'resource_group_name': 'test-network-rg01',
                'routes': [{
                    'name': 'rule1',
                    'address_prefix': '0.0.0.0/0',
                    'next_hop_type': 'VirtualAppliance',
                    'next_hop_ip_address': '10.20.128.140'
                }]
            }],
            'NETWORK_SECURITY_GROUP': [{
                'name': 'test-nsg01',
                'resource_group_name': 'test-network-rg01',
                'rules': [{
                    'access': 'Allow',
                    'destination_address_prefix': '*',
                    'destination_port_range': '*',
                    'direction': 'Inbound',
                    'name': 'rule1',
                    'priority': 1001,
                    'protocol': '*',
                    'source_address_prefixes': ['10.20.2.0/24'],
                    'source_port_range': '*'
                }]
            }]
        }
}

附言

用类似的方法,可以创建删除资源的接口与查看任务状态的接口,示例如下:

app.py

@auto_deploy_api.delete("/delete_resource")
async def delete_res(VERABLES_DICT: Item, backgroundTasks: BackgroundTasks):
    VERABLES = VERABLES_DICT.VERABLES
    try:
        # 启动异步任务,因为删除资源耗时较长,http请求不应也无法一直保持
        backgroundTasks.add_task(delete_resource, VERABLES)
        return {"message": "Will delete"}
    except auto.StackNotFoundError:
        return HTTPException(status_code=404,detail="application not found")
    except Exception as e:
        return Response(status_code=500, content=repr(e))
 
@auto_deploy_api.post("/stack_status")
async def delete_res(VERABLES_DICT: Item):
    VERABLES = VERABLES_DICT.VERABLES
    try:
        data = get_stack_status(VERABLES["ID"])
        return data
    except auto.StackNotFoundError:
        return HTTPException(status_code=404,detail="id not found")
    except Exception as e:
        return Response(status_code=500, content=repr(e))

auto_deploy_inline.py

def delete_resource(VERABLES):
    stack_name = VERABLES["GLOBAL_VARS"]["STACK_NAME"]
    project_name = VERABLES["GLOBAL_VARS"]["PROJECT_NAME"]
    client_id, client_secret, client_tenant = get_azure_sp()
    def resource_init():
        pass
 
    resource_stack = auto.create_or_select_stack(stack_name=stack_name,
                                                 project_name=app_name,
                                                 program=resource_init)
    resource_stack.refresh(on_output=print)
    resource_destroy_res = resource_stack.destroy(on_output=print)
  
    return (resource_destroy_res.stdout)
 
 
def get_stack_status(id):
    data = get_task_record(id)
    if len(data) == 0:
        raise auto.StackNotFoundError
    data_dict = {"id": id, "stack_name": data[0][1], "status": data[0][3],
                 "payload": data[0][2], "output": data[0][4]}
 
    return data_dict

调用方式:

图片

图片

另外,若配置了资源CMDB,可在FastAPI Gateway上配置资源信息查询接口,示例如下:

图片

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

贝锐蒲公英异地组网方案:实现制药设备远程监控、远程运维

公司业务涉及放射性药品的生产与销售&#xff0c;在全国各地拥有20多个分公司。由于药品的特殊性&#xff0c;在日常生产过程中&#xff0c;需要符合药品监管规范要求&#xff0c;对各个分部的气相、液相设备及打印机等进行监管&#xff0c;了解其运行数据及工作情况。 为满足这…

[极客大挑战 2020]Roamphp4-Rceme

rce,rce,rce!!! 右键源代码里给了提示&#xff0c;有备份文件index.php.swp,大伙都做到这来了&#xff0c;应该不用写了吧。看源码 <?php error_reporting(0); session_start(); if(!isset($_SESSION[code])){$_SESSION[code] substr(md5(mt_rand().sha1(mt_rand)),0,5);…

电脑上使用备忘录怎么查看编辑时间?能显示时间的备忘录

在快节奏的生活中&#xff0c;很多人喜欢使用备忘录来记录日常事项和重要信息。备忘录不仅能帮助我们捕捉灵感&#xff0c;还能确保重要任务不被遗漏。然而&#xff0c;有时候我们需要知道某条记录的编辑时间&#xff0c;以便于回溯和整理信息。如果备忘录不能显示编辑时间&…

matplotlib 做饼图

饼图可以很好地帮助用户快速了解整体市场数据的占比分配 import matplotlib.pyplot as pltexplode (0,0.1,0,0) labels Frogs,Hogs,Dogs,Logs sizes [15, 30, 45, 10] fig,ax plt.subplots() # colors 设置图形颜色 ;pctdistance&#xff1a;设置百分比标签与圆心的距离&am…

【配置】Notion自动化备份到github方案

步骤 打开notion网页&#xff0c;获取到需要的值 token_v2 找到请求getSpaces的 Cookie 值 token_v2 space_id 找到请求getSpaces的响应结果space,如下图&#xff1a; file_token 找个页面点击导出&#xff0c;之后拿到这个配置项 注意&#xff1a;配置项会过期&#xff0c…

华为---静态路由-浮动静态路由及负载均衡(二)

7.2 浮动静态路由及负载均衡 7.2.1 原理概述 浮动静态路由(Floating Static Route)是一种特殊的静态路由&#xff0c;通过配置去往相同的目的网段&#xff0c;但优先级不同的静态路由&#xff0c;以保证在网络中优先级较高的路由&#xff0c;即主路由失效的情况下&#xff0c…

计算机毕业设计Python深度学习房价预测 房价可视化 链家爬虫 房源爬虫 房源可视化 卷积神经网络 大数据毕业设计 机器学习 人工智能 AI

基于python一/二手房数据爬虫分析预测系统可视化 商品房数据Flask框架&#xff08;附源码&#xff09; 项目介绍python语言、Flask框架、MySQL数据库、Echarts可视化 sklearn机器学习 多元线性回归预测模型、requests爬虫框架 链家一手房 一手房数据商品房数据、分析可视化预测…

QT中利用QMovie实现动态加载效果

1、效果 2、代码 #include "widget.h" #include "ui_widget.h" #include <QLabel> #include <QMovie>

蓝桥杯-明年再战了

差几名省一(唉唉唉)&#xff0c;ne555定义错类型了&#xff0c;导致后面大部分没写完&#xff0c;检查了一个小时才检查出来.........

【漏洞复现】万户-ezOFFICE DownloadServlet 任意文件下载漏洞

免责声明&#xff1a; 本文内容旨在提供有关特定漏洞或安全漏洞的信息&#xff0c;以帮助用户更好地了解可能存在的风险。公布此类信息的目的在于促进网络安全意识和技术进步&#xff0c;并非出于任何恶意目的。阅读者应该明白&#xff0c;在利用本文提到的漏洞信息或进行相关测…

100多个ChatGPT指令提示词分享

当前&#xff0c;ChatGPT几乎已经占领了整个互联网。全球范围内成千上万的用户正使用这款人工智能驱动的聊天机器人来满足各种需求。然而&#xff0c;并不是每个人都知道如何充分有效地利用ChatGPT的潜力。其实有许多令人惊叹的ChatGPT指令提示词&#xff0c;可以提升您与ChatG…

stm32学习-硬件I2C读取MPU6050

配置流程 第一步&#xff1a;配置I2C外设&#xff0c;对I2C外设进行初始化&#xff08;替换上一篇文章的I2C_Init&#xff09; 第二步&#xff1a;控制外设电路&#xff0c;实现指定地址写的时序&#xff08;替换上一篇文章的WriteReg&#xff09; 第三步&#xff1a;控制外…

Golang | Leetcode Golang题解之第169题多数元素

题目&#xff1a; 题解&#xff1a; func majorityElement(nums []int) (ans int) {cnts : 0for _, v : range nums {if v ans {cnts} else if cnts 0 {ans v} else {cnts--}}return }

东郊到家类型小程序APP软件基于SpringBoot开发的系统源码

项目背景 在快节奏的现代生活中&#xff0c;人们越来越追求高效、便捷的生活方式。上门服务作为一种新型的服务模式&#xff0c;正逐渐受到广大用户的青睐。而这一切的背后&#xff0c;离不开技术的强大支撑。今天&#xff0c;我们就来探讨一下上门服务类型软件的技术魅力&…

蓝牙模块在工业自动化中的应用

随着科技的快速发展&#xff0c;工业自动化已成为现代工业生产的重要组成部分。蓝牙模块作为一种无线通信技术&#xff0c;其在工业自动化领域的应用日益广泛。本文将探讨蓝牙模块在工业自动化领域的具体应用场景&#xff0c;分析蓝牙模块如何提升工业自动化的效率和灵活性&…

【C++LeetCode】【热题100】两数之和【简单】-不同效率的题解【2】

题目&#xff1a; 暴力方法&#xff1a; class Solution { public:vector<int> twoSum(vector<int>& nums, int target) {vector<int> res;bool flagfalse;for(int i0;i<nums.size();i){int tempValuetarget-nums[i];//求解另一个值for(int ji1;j…

推荐 2 个 牛牛牛 的 PDF 开源神器!

推荐两个在 GitHub 上都斩获 12k 星星的 PDF 神器&#xff1a;OCRmyPDF 可让你的 PDF 扫描件变得可搜索&#xff1b;Marker 以高准确性快速将 PDF 文档转换为 Markdown 格式 01 让你的 PDF 扫描件变得可搜索 在数字化时代&#xff0c;我们经常需要处理扫描的PDF文件&#xff0c…

自定义模板DIY专属CSDN个人主页!HTML+CSS个性化全攻略

个人主页&#xff1a;学习前端的小z 个人专栏&#xff1a;HTML5和CSS3悦读 本专栏旨在分享记录每日学习的前端知识和学习笔记的归纳总结&#xff0c;欢迎大家在评论区交流讨论&#xff01; 文章目录 &#x1f4af;如何通过HTMLCSS自定义模板diy出自己的个性化csdn主页&#x…

Qt扩展-轻量数学公式计算

轻量数学公式计算 一、概述二、代码结构三、简单使用四、解析支持1. 操作数2. 运算符3. 括号 一、概述 这个是我写得简单的一个数学计算公式工具。easy-math-parser 是一个用C编写的简单工具包&#xff0c;支持四个操作字符串的计算工具&#xff0c;灵感来自Muparser。 在这个…

【面试干货】throw 和 throws 的区别

【面试干货】throw 和 throws 的区别 1、throw1.1 示例 2、throws2.1 示例 3、总结 &#x1f496;The Begin&#x1f496;点点关注&#xff0c;收藏不迷路&#x1f496; 在Java中&#xff0c;throw和throws都与异常处理紧密相关&#xff0c;但它们在使用和含义上有明显的区别。…