使用 Pulumi 打造自己的多雲管理平臺

亞馬遜雲開發者發表於2023-03-12

前言

在公有云技術與產品飛速發展的時代,業務對於其自身的可用性提出了越來越高的要求,當跨區域容災已經無法滿足業務需求的情況下,我們通常會考慮多雲部署我們的業務平臺,以規避更大規模的風險。但在多雲平臺部署的架構下,多雲資源的管理成為了一個耗時耗力,管理與運維成本頗高的難點。這導致了第一,雲管人員需要精通掌握兩家甚至多家雲廠商的技術與服務產品,或者第二,多支獨立團隊分別運維與管理導致的高團隊成本等諸多痛點。所以公有云資源納管平臺(以下簡稱雲管平臺)應運而生。

亞馬遜雲科技開發者社群為開發者們提供全球的開發技術資源。這裡有技術文件、開發案例、技術專欄、培訓影片、活動與競賽等。幫助中國開發者對接世界最前沿技術,觀點,和專案,並將中國優秀開發者或技術推薦給全球雲社群。如果你還沒有關注/收藏,看到這裡請一定不要匆匆劃過,點這裡讓它成為你的技術寶庫!

雲管平臺簡化了運管人員的操作流程,降低了公有云產品的技術門檻,但是在多雲產品的集中式納管上,卻難度重重。其一,不同公有云廠商,使用獨立的 infrastructure-as-code (以下簡稱 IaC )體系或者服務,譬如亞馬遜雲科技的 Cloudformation 服務;其二,不論雲廠商還是開源的 IaC 產品,均使用標記語言或者類標記語言編寫程式碼,鮮有使用 Java, Python 或者 Golang 等開發語言的執行時,這對於精通於開發語言的,雲管平臺的開發人員導致了額外學習成本,需要從0開始學習標記語言,往往會導致開發團隊的牴觸甚至拒絕;其三,標記語言執行過程中,更傾向於將整體堆疊執行完畢之後,輸出對應的 outputs,但在執行過程中,存在難以直接迴圈呼叫 outputs,無法寫入資料庫等諸多難點,這增大了編寫難度以及程式碼編寫工作量。有沒有一款產品,能夠適配主流公有云 IaC,又可以使用高階程式語言編寫程式碼呢?

什麼是 Pulumi?

Pulumi 是非常流行的,現代化 IaC 平臺。Pulumi 引入了主流程式語言,譬如 JavaScript,Python,Java,Golang,.NET,以及標記語言 YAML,可以使用上述語言,透過 Pulumi SDK 管理不同雲廠商的資源。Pulumi 目前已經支援了主流公有云廠商譬如亞馬遜雲科技,微軟 Azure,谷歌雲與阿里雲,及其生態譬如 Fastly,Akamai,Cloudflare,Kubernetes,Kong,Apache Kafka 等。

Pulumi 的組成如下圖所示:

每一個 Pulumi 專案包含至少一個程式組,程式組由程式語言書寫,描述不同資源的運作

以及彼此之間的關係。

以下以 Python 程式碼為例,描述我們在 Pulumi 中建立了 web-sg 名稱安全組,並附加該安全組,以 ’ami-6869aa05’為映象,建立了例項規格為 t2.micro 的 EC2 虛擬機器。

import pulumi
import pulumi_aws as aws

group = aws.ec2.SecurityGroup('web-sg',
    description='Enable HTTP access',
    ingress=[
        { 'protocol': 'tcp', 'from_port': 80, 'to_port': 80, 'cidr_blocks': ['0.0.0.0/0'] }
    ])

server = aws.ec2.Instance('web-server',
    ami='ami-6869aa05',
    instance_type='t2.micro',
    vpc_security_group_ids=[group.name] 
)

pulumi.export('public_ip', server.public_ip)
pulumi.export('public_dns', server.public_dns)

Pulumi 如何工作 Pulumi 的運作由幾個部分組成:

第一,語言處理中樞。Language Host 負責執行 Pulumi 的程式,併為您的開發語言準備好與之對應的環境,譬如 Python3.7。語言中樞由兩部分組成:

1.執行器。它會協助 Pulumi 準備並設定好相應的 Runtime(執行時);

2.執行時。它會負責為您編寫的程式做好執行準備,並在過程中監控程式的執行。

第二,資源提供方 Provider。

資源提供方透過資源外掛(Resource Plugin,用來管理資源)與原生 SDK 協作,來管理雲端資源。

有了上述兩部分組成,Engine 引擎就可以實現雲端資源的管理。引擎已經被封裝進 pulumi cli,無需額外安裝與部署。

如何建立一個 Pulumi 專案

1.安裝 Pulumi(以 Linux 為例)
curl -fsSL https://get.pulumi.com | sh
2.安裝執行時(以 Python 為例)

請閱讀 如何在 Linux 上安裝 Python3 本文不再複述

3.配置許可權

請閱讀 安裝或更新最新版本的 Amazon CLI ,完成 Amazon CLI 的安裝,本文不再複述

請閱讀 配置 Amazon CLI 完成完成許可權配置,本文不再複述

4.建立新專案

$mkdir newproject && cd newproject
$pulumi new aws-python

Pulumi new 的命令列會透過互動式的方式,為您建立新的專案與新的堆疊(stack),並安裝好所有需要的元件(Module)。


5.部署這個專案

執行 pulumi up 進行專案部署

執行成功後,我們可以在 S3 中看到有 pulumi 建立出來的 S3 桶


6.調整專案部署

我們要在已經部署的專案中,做出一些調整。之前的部署結束後,我們建立了一個 S3 桶,這次我們需要為其新增一個 index.html 並將其託管為靜態站點

6.1建立站點首頁
#touch index.html
在其中新增文字:

<html>
    <body>
        <h1>Hello, Amazon!</h1>
    </body>
</html>

儲存後,編輯__main__.py

在結尾處新增:

bucketObject = s3.BucketObject( ‘index.html’, bucket=bucket.id, source=pulumi.FileAsset(‘index.html’))

再次執行 pulumi up 變更部署

6.2 調整部署

這次我們需要編輯 S3 bucket 的屬性,使其託管靜態站點,並調整 Bucket ACL,使其可以被匿名訪問。

編輯 main.py

替換 bucket segment,使其成為:

bucket = s3.Bucket('my-bucket',
    website=s3.BucketWebsiteArgs(
        index_document="index.html",
))

在結尾處,增加輸出:

pulumi.export('bucket_endpoint', pulumi.Output.concat('http://', bucket.website_endpoint))

執行 Pulumi up,釋出專案變更後,得到輸出結果:

Outputs:
  + bucketEndpoint: "http://my-bucket-e7bfd5a.s3-website-us-west-2.amazonaws.com"
    bucketName    : "my-bucket-e7bfd5a"

訪問 bucketEndpoint,我們可以看到

7.銷燬專案

我們可以執行 pulumi destroy 銷燬專案。

結論

透過這個簡單的案例,我們展示了透過 pulumi 可以輕鬆的建立,管理與刪除一個專案,在專案中,我們可以建立,調整,管理,刪除與專案相關的 Resource,將 pulumi 與程式語言相結合,可以實現雲管平臺的個性化需求,並透過雲管平臺的幾次點選,實現複雜邏輯下,不同雲服務的組合,滿足業務場景的需求。

額外案例

我們會額外提供幾個 pulumi program,方便大家直觀的瞭解到 pulumi 的編碼方式。

  1. 建立一個名稱為 “DocumentDBCluster”Amazon DocumentDB 的 Cluster,自動備份儲存15天,必須開啟刪除保護。然後將 DocumentDB Cluster Endpoint 輸出。
import pulumi
import pulumi_aws as aws

docdb = aws.docdb.Cluster("docdb",
    backup_retention_period=5,
    cluster_identifier="DocumntDBCluster",
    engine="docdb",
    master_password="mustbeeightchars",
    master_username="foo",
    deletion_protection=True,
    skip_final_snapshot=True)
pulumi.export('DocumentCluster_endpoint', docdb.endpoint)

下面是一個稍微複雜一些的場景:

  1. 場景共由五個部分組成,第一部分,環境定義;第二部分,建立 SSH&HTTP 的安全組,第三部分,建立 EC2 並附加 EIP,第四部分,建立 Aurora ServerlessV2,第五部分,輸出。大家能夠透過下列 python 程式碼與場景逐一對應。
import pulumi
import pulumi_aws as aws

config = pulumi.Config()
availability_zone = config.require("availabilityZone")
environment_type = config.get("environmentType")
if environment_type is None:
    environment_type = "dev"
ami_id = config.get("amiID")
if ami_id is None:
    ami_id = ""
ami_id_value = "/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2" if ami_id == "" else aws.get_ssm_parameter_string().value
key_pair_name = config.require("keyPairName")
db_instance_identifier = config.get("dbInstanceIdentifier")
if db_instance_identifier is None:
    db_instance_identifier = "mydatabase"
db_username = config.get("dbUsername")
if db_username is None:
    db_username = "postgres"
db_password = config.require("dbPassword")

web_app_security_group = aws.ec2.SecurityGroup("webAppSecurityGroup",
    name="webAppSG",
    description="Allow HTTP/HTTPS and SSH inbound and outbound traffic",
    ingress=[
        aws.ec2.SecurityGroupIngressArgs(
            ip_protocol="tcp",
            from_port=80,
            to_port=80,
            cidr_ip="0.0.0.0/0",
        ),
        aws.ec2.SecurityGroupIngressArgs(
            ip_protocol="tcp",
            from_port=443,
            to_port=443,
            cidr_ip="0.0.0.0/0",
        ),
        aws.ec2.SecurityGroupIngressArgs(
            ip_protocol="tcp",
            from_port=22,
            to_port=22,
            cidr_ip="0.0.0.0/0",
        ),
])

web_app_instance = aws.ec2.Instance("webAppInstance",
    availability_zone=availability_zone,
    image_id=ami_id_value,
    instance_type="t2.small",
    key_name=key_pair_name,
    security_groups=[web_app_security_group.id,default,])
web_app_eip = aws.ec2.EIP("webAppEIP",
    vpc=True,
instance=web_app_instance.id)

web_app_database = aws.rds.Cluster("webAppDatabase",
    cluster_identifier=db_instance_identifier,
    engine="aurora-postgresql",
    engine_mode="provisioned",
    engine_version="13.6",
    database_name=db_username,
    master_username=db_username,
    master_password=db_password,
    serverlessv2_scaling_configuration=aws.rds.ClusterServerlessv2ScalingConfigurationArgs(
        max_capacity=1,
        min_capacity=0.5,
    ))
web_app_database_instance = aws.rds.ClusterInstance("webAppDatabaseInstance",
    cluster_identifier=web_app_database.id,
    instance_class="db.serverless",
    engine=web_app_database.engine,
    engine_version=web_app_database.engine_version)

pulumi.export("websiteURL", web_app_eip.id.apply(lambda id: f"http://{id}"))
pulumi.export("webServerPublicDNS", web_app_instance.public_dns_name)
pulumi.export("webAppDatabaseEndpoint", web_app_database.endpoint)

參考資源:

瞭解 Pulumi 的 Registry

https://www.pulumi.com/registry?trk=cndc-detail/

安裝 Python3

https://docs.aws.amazon.com/zh_cn/parallelcluster/latest/ug/i...

安裝或更新最新版本的 Amazon CLI

https://docs.aws.amazon.com/zh_cn/cli/latest/userguide/gettin...

配置 Amazon CLI

https://docs.aws.amazon.com/zh_cn/cli/latest/userguide/cli-ch...

本篇作者

付曉明
亞馬遜雲解決方案架構師,負責雲端計算解決方案的諮詢與架構設計,同時致力於資料庫,邊緣計算方面的研究和推廣。在加入亞馬遜雲科技之前曾在金融行業 IT 部門負責網際網路券商架構的設計,對分散式,高併發,中介軟體等具有豐富經驗。

文章來源:https://dev.amazoncloud.cn/column/article/6309e39986218f3ca3e...

相關文章