前言
在公有云技術與產品飛速發展的時代,業務對於其自身的可用性提出了越來越高的要求,當跨區域容災已經無法滿足業務需求的情況下,我們通常會考慮多雲部署我們的業務平臺,以規避更大規模的風險。但在多雲平臺部署的架構下,多雲資源的管理成為了一個耗時耗力,管理與運維成本頗高的難點。這導致了第一,雲管人員需要精通掌握兩家甚至多家雲廠商的技術與服務產品,或者第二,多支獨立團隊分別運維與管理導致的高團隊成本等諸多痛點。所以公有云資源納管平臺(以下簡稱雲管平臺)應運而生。
亞馬遜雲科技開發者社群為開發者們提供全球的開發技術資源。這裡有技術文件、開發案例、技術專欄、培訓影片、活動與競賽等。幫助中國開發者對接世界最前沿技術,觀點,和專案,並將中國優秀開發者或技術推薦給全球雲社群。如果你還沒有關注/收藏,看到這裡請一定不要匆匆劃過,點這裡讓它成為你的技術寶庫! |
雲管平臺簡化了運管人員的操作流程,降低了公有云產品的技術門檻,但是在多雲產品的集中式納管上,卻難度重重。其一,不同公有云廠商,使用獨立的 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 的編碼方式。
- 建立一個名稱為 “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)
下面是一個稍微複雜一些的場景:
- 場景共由五個部分組成,第一部分,環境定義;第二部分,建立 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...