Hanny的传奇基础设施即代码解决方案。
项目描述
Infrable
Hanny的传奇基础设施即代码解决方案。
# Install
pip install -U infrable # requires python >= 3.10
# Bootstrap a new project
infrable init
目录
- 序言
- 第一章 - 混沌
- 第二章 - 主机和服务
- 第三章 - 模板
- 第四章 - 部署或恢复工作流
- 第五章 - 命令、任务和工作流
- 第六章 - 环境和开关
- 第七章 - 元数据和秘密
- 第八章 - 自定义模块
序言
在一个由闪烁的灯光包围的无限虚空中,Hanny醒来时记忆空洞,只有她的名字在她的脑海中回响。她发现自己漂浮在一个介于有形世界的Python代码和虚幻宇宙之间的领域。一个合成声音在她周围回荡,提到了一个关键的基础设施迁移项目,但她对此一无所知。她的记忆,曾经是Python王国的钥匙,无法提供任何答案。她被困在一个星际迷宫中,承担着一个她无法回忆的技术使命,她唯一的是机械键盘和附近屏幕上飞逝的代码行。
第一章 - 混沌
在她的不满的空虚中,Hanny开始回忆起前世的片段:在地球上的过去,一个迫在眉睫的基础设施迁移项目威胁着一切。人类在与混乱的基础设施和准备不足的工具包作斗争。Python开发者与复杂的工具作斗争,而绝望地寻找声明性配置管理也徒劳无功。在这片混乱之中,Hanny被抛入宇宙,一个不愿意的骑士,被赋予了一个令人难以置信的任务:找到一个简单但能够驾驭这场即将到来的灾难的解决方案。
第二章 - 主机和服务
在顿悟的一刹那,Hanny理解了基础设施的复杂性:主机和它们所承载的服务,这是任何系统的关键骨干。她认识到维护一个单一参考来源,一个完整、和谐的文档,捕捉这些基本关系的重要性。她致力于维护这个单一真理来源的原则,开始艰苦的文档工作,将每一个细节都倾注到名为"infra.py"的整合证明中。
infra.py
from infrable import Host, Service
# Hosts/ -----------------------------------------------------------------------
dev_host = Host(fqdn="dev.example.com", ip="127.0.0.1")
beta_host = Host(fqdn="beta.example.com", ip="127.0.0.1")
prod_host = Host(fqdn="prod.example.com", ip="127.0.0.1")
# /Hosts -----------------------------------------------------------------------
# Services/ --------------------------------------------------------------------
dev_web = Service(host=dev_host, port=8080)
beta_web = Service(host=beta_host, port=8080)
prod_web = Service(host=prod_host, port=8080)
dev_nginx = Service(host=dev_host, port=80)
beta_nginx = Service(host=beta_host, port=80)
prod_nginx = Service(host=prod_host, port=80)
# /Services --------------------------------------------------------------------
列出主机和服务
infrable hosts
infrable services
第三章 - 模板
逐渐拼凑起零散的记忆,Hanny意识到主机部署的配置文件应该作为模板来维护,从"infra.py"中按需提取值。回到地球后,挑战是缺乏一个连贯的系统来记录这些文件的目标位置,这是一个组织问题,构成了一个重大的障碍。然后,在一个天才的时刻,Hanny提出了一个突破性的解决方案。她将在配置模板中直接记录文件的路径。于是,她以新的活力,开始在配置文件中添加重要的细节,作为头注释,这是一个传奇性的举动,有望改变基础设施迁移的面貌。
infra.py
template_prefix = "https://github.com/username/repository/blob/main"
templates/nginx/web.j2
# vim: syn=nginx
# ---
# src: {{ template_prefix }}/{{ _template.src }}
# dest: {{ dev_nginx.host }}:/etc/nginx/sites-enabled/web
# chmod: 644
# chown: root:root
# ---
server {
listen {{ dev_nginx.port }};
listen [::]:{{ dev_nginx.port }}
server_name {{ dev_nginx.host.fqdn }} www.{{ dev_nginx.host.fqdn }};
location / {
proxy_pass http://127.0.0.1:{{ dev_web.port }};
include proxy_params;
}
}
注意:_template.src是一个特殊变量,在所有模板中可用。
第四章 - 部署或恢复工作流
在充满不确定性的广阔天地中,Hanny清楚地意识到:在推送之前,审查通过"infra.py"生成的文件并与当前部署的配置进行比较的重要性。这个过程将拦截任何实时更改,并确保它们包含在模板中。她的谨慎性格也认识到维护所使用配置的本地备份的必要,这提供了一种保险。为了解决任何复杂问题,她构想了一个安全措施:部署或恢复工作流程。这承诺缓解人为错误,同时确保可以轻松地回滚和恢复服务,这是Hanny在宇宙故事中的又一成功步骤。
部署工作流程
infrable files deploy [path]
## Same as
# infrable files gen [path]
# infrable files pull
# infrable files backup
# infrable files push
为蛇人
from infrable import files
files.deploy(path)
## Same as
# files.gen(path)
# files.pull()
# files.backup()
# files.push()
flowchart TD;
A[gen: generate artifacts from templates and infra.py as .new files] --> B[pull: for each generated artifact pull the currently deployed version from server as .old files];
B --> C[backup: copy the artifacts in a local backup directory for easy recovery in case of failure];
C --> E[diff: compare the .new and .old files];
E -- push: for each result --> F{is there any difference?};
F -- yes --> H[display the diff];
F -- no --> G[skip and delete artifacts];
H --> I{confirm push?};
I -- yes --> J[push the file onto the server];
I -- no --> K[skip and delete artifacts];
差异示例
--- .infrable/files/root@dev.example.com/etc/monit/conf.d/system.cfg.old
+++ .infrable/files/root@dev.example.com/etc/monit/conf.d/system.cfg.new
@@ -1,13 +1,14 @@
check system dev.example.com
- if memory usage > 85% then alert
+ # if memory usage > 85% then alert
if cpu usage (user) > 80% for 3 cycles then alert
if cpu usage (system) > 80% for 3 cycles then alert
Push? (y, n, all) [y]:
恢复工作流程
infrable files recover [path]
## Same as
# infrable files revert [path]
# infrable files push
为蛇人
from infrable import files
files.recover(path)
## Same as
# files.revert(path)
# files.push()
flowchart TD;
A[revert: copy the artifacts from the given or latest backup directory into artifacts directory but in reverse order] --> B[diff: compare the .new and .old files];
B --> C[push: run the steps for the push workflow]
第五章 - 命令、任务和工作流
随着Hanny深入了解基础设施迁移的复杂性,她遇到了一个关键的认识:需要超越仅仅推送配置。为了实现无缝过渡,测试、服务重启和其他部署后的操作是必不可少的。她以不懈的决心,在"infra.py"中集成了一个功能,以在主机上执行远程命令,这是一个增强部署过程的能力。
# Run a command on a host by name
infrable remote dev_host "sudo systemctl reload nginx"
# Or by service name
infrable remote dev_nginx "sudo systemctl reload nginx"
# Or all affected hosts (as per files diff)
infrable remote affected-hosts "sudo systemctl reload nginx"
# Or
infrable files affected-hosts | infrable remote - "sudo systemctl reload nginx"
Hanny对卓越的追求并未停止;她认识到松散命令执行的不充分,承认结构化组织的必要性。因此,她构想了一个新概念——创建“任务”,这些是设计用于简化操作的命令组。
infra.py
import typer
# Tasks/ -----------------------------------------------------------------------
dev_nginx.typer = typer.Typer(help="dev_nginx specific tasks.")
@dev_nginx.typer.command(name="reload")
def reload_dev_nginx():
"""[TASK] Reload nginx: infrable dev-nginx reload"""
assert dev_nginx.host, "Service must have a host to reload"
dev_nginx.host.remote().sudo.nginx("-t")
dev_nginx.host.remote().sudo.systemctl.reload.nginx()
# /Tasks -----------------------------------------------------------------------
运行任务
infrable dev-nginx reload
在她为实现这一愿景而努力的过程中,一个绝妙的想法闪过她的脑海——将这些任务编排成连贯的序列,她称之为“工作流程”,这标志着基础设施管理新时代的到来。
infra.py
from infrable import concurrent, paths
# Workflows/ -----------------------------------------------------------------------
deploy = typer.Typer(help="Deployment workflows.")
@deploy.command(name="dev-nginx")
def deploy_dev_nginx():
"""[WORKFLOW] Deploy dev_nginx files: infrable deploy dev-nginx"""
files.deploy(paths.templates / "nginx")
cmd = "sudo nginx -t && sudo systemctl reload nginx && echo success || echo failed"
fn = lambda host: (host, host.remote().sudo(cmd))
for host, result in concurrent(fn, files.affected_hosts()):
print(f"{host}: {result}")
# /Workflows -----------------------------------------------------------------------
运行工作流程
infrable deploy dev-nginx
第六章 - 环境和开关
进步的喜悦迅速被为多个环境中的每个主机独立定义模板、任务和工作流程的艰巨性所抵消。汉妮敏锐的眼睛疲惫地眨着,手指因不停地敲击而疼痛。就在那时,她突然意识到另一个重要的现实:服务与主机的关系取决于环境。环境——“开发”、“测试”、“生产”等——决定了服务的部署位置。她思考着是否可以切换环境,提出了一个关键问题:如果“infra.py”文件能够根据环境调整值会怎样?这将极大地简化部署过程,利用相同的模板、任务和工作流程定义在不同主机上。抓住这个灵感,汉妮开发了‘Switch’,这是一种巧妙的机制,允许在“infra.py”中进行环境相关的值调整。有了‘Switch’,基础设施迁移不再是迷宫般的导航,而是一次探索和创新之旅。随着她每编写出一行代码,任务的重量都在减轻。于是,汉妮在宇宙的寂静中继续前行,她的精神不可战胜,她的热情难以驯服。
infra.py
from infrable import Switch, Host, Service
# Environments/ ----------------------------------------------------------------
dev = "dev"
beta = "beta"
prod = "prod"
environments = {dev, beta, prod}
env = Switch(environments, init=dev) # <-- Defining a switch for different environments
current_env = env()
# /Environments ----------------------------------------------------------------
# Hosts/ -----------------------------------------------------------------------
dev_host = Host(fqdn="dev.example.com", ip="127.0.0.1")
beta_host = Host(fqdn="beta.example.com", ip="127.0.0.2")
prod_host = Host(fqdn="prod.example.com", ip="127.0.0.3")
managed_hosts = env( # <-- Switching hosts based on the environment
dev=[dev_host],
beta=[beta_host],
prod=[prod_host],
)
# /Hosts -----------------------------------------------------------------------
# Services/ --------------------------------------------------------------------
web = Service(
host=env.strict(dev=dev_host, beta=beta_host, prod=prod_host), # <-- Strict switch
port=8080,
)
nginx = Service(port=80, host=web.host) # <-- No need to use switch here
# /Services --------------------------------------------------------------------
更新模板以使用可切换的值
templates/nginx/proxy_params.j2
# vim: syn=nginx
# ---
# src: {{ template_prefix }}/{{ _template.src }}
# dest:
# {% for host in managed_hosts %} # <-- Yes, you can
# - loc: {{ host }}:/etc/nginx/proxy_params
# {% endfor %}
# chmod: 644
# chown: root:root
# ---
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
管理开关
# Switch current environment
infrable switch env [dev|beta|prod]
# Check the current switch value
infrable switch env
# See other options for the switch
infrable switch env --options
# If you name a switch "env", you get an alias for convenience
infrable env [dev|beta|prod]
# Check all switch values
infrable switches
第七章 - 元数据和秘密
神秘的面纱笼罩着汉妮最新的任务。她渴望能够访问那些未被版本控制系统眼睛触及的机密值,并将这些值与主机和服务进行对比。这是一个艰巨的挑战——在不增加复杂性的情况下,将这些机密密钥嵌入Python迷宫中。她沉思着,目光聚焦于宇宙中散落的星星。如果简单是发明的母亲,汉妮将是其虔诚的弟子。她遵循着伟大的Python传统——简单,凭借从前挑战中获得的智慧,投入到眼前的任务中。她制定了一个优雅的策略。她的解决方案是诗人的梦想,是程序员的喜悦,她成就的欣慰在宇宙的寂静中回荡。
infra.py
from infrable import Meta, readfile
common_secret_key = readfile("secrets/common/secret_key") # <-- Read a secret file
web = Service(
meta=Meta(secret_key=common_secret_key), # <-- Attach metadata to items
host=env(dev=dev_host, beta=beta_host, prod=prod_host),
port=8080,
)
管理机密
# Hide secrets from git
echo /secrets/ >> .gitignore
# Update the secrets by hand
vim secrets/common/secret_key
第八章 - 自定义模块
当天体的寂静包围着她时,汉妮盯着最后一行代码,终于松了一口气。Python大师克服了重重困难,在基础设施迁移的广阔星系中开辟了一条道路。在她的手中,人类掌握了对抗不可避免的基础设施迁移的幽灵的武器,不仅一次,而且可能是无数次。他们不再会在迁移面前挣扎,因为‘infrable’已经到来。
但宇宙的无限空间若能证明什么,那就是无限的成长潜力。汉妮始终是一个有远见的人,她看到了创建工具箱的艰辛背后。她设想了一个不断进化的机制,一个由全球Python同行集体智慧增强的协作系统。就在这时,她突然意识到Python中蕴含的适应性。其他程序员可以创建Python模块并将它们拼接到现有的“infra.py”中,从而扩展和提高其功能,技能和代码的协同作用将“infrable”提升到未知的领域。
modules/mycloud.py
from dataclasses import dataclass
from typer import Typer
from infrable import Host, infra
@dataclass
class MyCloud:
"""MyCloud Python library."""
secret_api_key: str
typer: Typer | None = None
def provision_ubuntu_host(self, fqdn: str):
ip = self.api.create_ubuntu_host(fqdn)
return MyCloudUbuntuHost(fqdn=fqdn, ip=ip)
@dataclass
class MyCloudUbuntuHost(Host):
"""MyCloud's customized Ubuntu server."""
def setup(self):
self.install_mycloud_agent()
def install_mycloud_agent(self):
raise NotImplementedError
workflows = Typer()
@workflows.command()
def provision_ubuntu_host(fqdn: str, setup: bool = True):
"""[WORKFLOW] Provision Ubuntu host."""
# Get the MyCloud instance from infra.py
cloud = next(iter(infra.item_types[MyCloud].values()))
# Provision the host
host = cloud.provision_ubuntu_host(fqdn)
if setup:
host.setup()
name = fqdn.split(".")[0].replace("-", "_")
print("Add the host to the infra.py file.")
print(f"{name} = {repr(host}")
在infra.py中插入模块
infra.py
from modules import mycloud
# Clouds/ ----------------------------------------------------------------------
cloud = mycloud.MyCloud(secret_api_key=readfile("secrets/mycloud/secret_api_key"))
cloud.typer = mycloud.workflows
# /Clouds ----------------------------------------------------------------------
运行模块工作流程
infra cloud --help
项目详情
下载文件
下载适合您平台文件。如果您不确定选择哪个,请了解更多关于安装包的信息。
源分布
构建分发版
infrable-0.1.40.tar.gz的哈希值
算法 | 哈希摘要 | |
---|---|---|
SHA256 | 63082ce7dd53fa048ee127d80d8ca0cf49f8444ff942fc7bf278bf42f1d4619d |
|
MD5 | de268def11a14b41881d6a436dd91b2b |
|
BLAKE2b-256 | f744606bb4e2b943ea918c92e827311439f34c9fc04287cc401ff730a6e6be09 |
infrable-0.1.40-py3-none-any.whl的哈希值
算法 | 哈希摘要 | |
---|---|---|
SHA256 | d2c66d4a546c9a65df48513c78e6a9b440b6bec9d89f30772412b506edbb06ff |
|
MD5 | ab96d4ffc9b2446114d31df09a5596e1 |
|
BLAKE2b-256 | 7c25a5dcd6b594119493c5ad3647cf51cd469c8e0397311ba1d12ccc6d967d1f |