CloudFormation 的資源註冊表功能允許開發者擴充套件 CloudFormation 的原生功能,以管理 AWS 生態系統之外的資源,或實作更精細的資源控制。本文以 DynamoDB 專案和 RDS 資料函式倉管理為例,逐步講解如何建立和使用自定義資源型別,並探討了 schema 的定義、處理程式的編寫以及測試驗證的策略。透過理解這些概念和實踐,開發者可以更好地利用 CloudFormation 管理複雜的雲端基礎設施。
在CloudFormation中建立自定義資源登入檔
AWS CloudFormation 提供了一個強大的資源註冊表功能,允許使用者建立和管理自定義資源型別。本文將探討如何建立和使用自定義資源登入檔,以及如何利用此功能擴充套件CloudFormation的功能。
使用DynamoDB專案作為資源註冊表示例
首先,我們來建立一個簡單的CloudFormation範本,用於在DynamoDB表中新增專案。以下是一個示例範本:
Resources:
MyTableItem:
Type: "AwsCommunity::DynamoDB::Item"
Properties:
TableName: !Ref TableName
Item:
configItem:
S: "exampleConfig"
configValue:
S: "exampleValue"
內容解密:
此範本定義了一個名為MyTableItem的資源,使用AwsCommunity::DynamoDB::Item型別,將一個專案新增到指定的DynamoDB表中。TableName屬性參照了一個名為TableName的引數,Item屬性定義了要新增的專案的屬性和值。
擴充套件註冊表功能
登入檔中提供了數十種不同的公共資源型別,例如,可以建立MongoDB Atlas叢集、管理CloudFlare CDN例項,甚至設定Atlassian Opsgenie或DataDog監控。
然而,我們也可以透過建立自己的資源型別並使用它們來充分利用登入檔。因此,讓我們在下一節中重構我們的資料函式庫自定義資源。
建立和使用私有擴充套件
要啟用登入檔,我們首先需要了解登入檔資源處理程式的限制和細微差別。在前面的章節中,我們的Lambda函式在公共網路中執行,並透過本機Python MySQL驅動程式連線到同樣託管在公共網路上的RDS例項。
準備資料函式庫基礎設施
我們將提供與上一章相同的堆積疊。如果您仍然擁有它,請隨意跳過此步驟:
$ aws cloudformation deploy \
--stack-name rds \
--template-file rds.yaml
當RDS例項準備就緒後,我們可以繼續對我們的資源型別進行建模。
為CloudFormation登入檔建模資源型別
CloudFormation要求擴充套件開發人員正確建模資源型別。這對於提供可靠性、故障排除以及擴充套件的可測試性至關重要。
schema剖析
此模型在AWS提供的schema中定義,可以在https://docs.aws.amazon.com/cloudformation-cli/latest/userguide/resource-type-schema.html檢視。該schema非常豐富且可擴充套件,但在本章中,我們將只介紹一些重要的部分:
replacementStrategy屬性定義了當我們對資源進行更新時,CloudFormation的行為。properties欄位是一個屬性陣列,我們為自定義資源型別標識這些屬性,以及資料型別、正規表示式模式和最小/最大長度。required欄位包含必需屬性的列表,即我們不希望CloudFormation生成並明確要求使用者定義的屬性。handlers欄位具有每個處理程式(建立、讀取、更新和刪除)的一組IAM許可權。
引導專案
我們將安裝新的AWS軟體並使用它來引導擴充套件開發程式碼:
-
要使用擴充套件,我們需要CloudFormation CLI(這與AWS CLI不同!)和AWS SAM CLI。讓我們按照以下方式安裝它們:
Linux / Windows / MacOS
$ pip install cloudformation-cli aws-sam-cli
MacOS installation with brew
$ brew update $ brew install cloudformation-cli aws-sam-cli
2. 要開發資源型別處理程式,我們還需要CloudFormation CLI的Python外掛。讓我們也安裝它:
```bash
$ pip install cloudformation-cli-python-plugin
-
現在我們可以使用互動式選單引導程式碼函式庫:
$ cfn init
4. 我們將構建自定義資源型別,因此第一個問題的答案很明確:
```
Initializing new project
Do you want to develop a new resource(r) or a module(m) or a hook(h)?.
>> r
- 對於資源型別名稱,我們必須遵循慣用的命名語法。第一部分代表更廣泛的組織,如我們的公司;第二部分指的是服務或範圍,最後是實際的資源。在此示例中,我將為每個部分選擇一些直接了當的名稱:
What's the name of your resource type?
(Organization::Service::Resource)
>> Org::Storage::Database
內容解密:
此步驟建立了一個新的CloudFormation擴充套件專案,使用cfn init命令,並按照提示進行組態。選擇r以建立新的資源型別,並按照約定命名資源型別。
執行與驗證
完成上述步驟後,我們成功建立了一個自定義資源登入檔,並為CloudFormation擴充套件開發做好了準備。接下來,我們可以根據需要進一步開發和測試我們的自定義資源型別。
隨著雲端計算技術的不斷發展,CloudFormation的自定義資源註冊表功能將變得越來越重要。未來,我們可以期待看到更多根據此功能的創新應用和解決方案。同時,AWS也將繼續擴充套件和改進CloudFormation的功能,以滿足使用者日益增長的需求。
graph LR
A[開始] --> B[建立自定義資源登入檔]
B --> C[定義資源型別]
C --> D[開發資源型別處理程式]
D --> E[測試和驗證]
E --> F[佈署和使用]
圖表翻譯: 此圖表展示了建立和使用CloudFormation自定義資源登入檔的流程。首先,我們開始建立自定義資源登入檔,然後定義資源型別。接下來,我們開發資源型別處理程式,並進行測試和驗證。最後,我們佈署和使用自定義資源型別。
內容解密:
此圖表清晰地展示了建立和使用CloudFormation自定義資源登入檔的步驟。透過遵循這些步驟,我們可以成功地建立和管理自定義資源型別,從而擴充套件CloudFormation的功能。
建立自訂資源登入檔以供 CloudFormation 使用
前言
在現代雲端基礎設施的管理中,AWS CloudFormation 提供了一個強大的工具,用於定義和佈署基礎設施資源。然而,在某些情況下,我們需要使用自訂資源來滿足特定的需求。本文將指導您如何建立自己的資源登入檔,以供 CloudFormation 使用。
步驟一:建立專案
首先,我們需要使用 CloudFormation CLI 來建立一個新的專案。這個工具可以幫助我們快速初始化一個資源提供者專案。
- 執行以下命令以建立新專案:
cfn init
2. 按照提示輸入專案相關資訊,包括資源型別的名稱和描述。
### 步驟二:選擇程式語言和設定
1. 選擇您偏好的程式語言。在本例中,我們選擇最新的 Python 版本:
Select a language for code generation: [1] go [2] java [3] python36 [4] python37 [5] python38 [6] python39 (enter an integer):
6
2. 使用 Docker 進行平台無關的封裝:
Use docker for platform-independent packaging (Y/n)?
Y
### 步驟三:檢視專案結構
成功初始化專案後,您將看到以下目錄結構:
```plaintext
.
├── README.md
├── docs
│ ├── README.md
│ ├── memo.md
│ └── tag.md
├── example_inputs
│ ├── inputs_1_create.json
│ ├── inputs_1_invalid.json
│ └── inputs_1_update.json
├── org-storage-database.json
├── requirements.txt
├── resource-role.yaml
├── rpdk.log
├── src
│ └── org_storage_database
│ ├── __init__.py
│ ├── handlers.py
│ └── models.py
└── template.yml
步驟四:編輯 Schema 檔案
- 開啟
org-storage-database.json檔案並修改描述和屬性:
{ “typeName”: “Org::Storage::Database”, “description”: “Manage a MySQL database on a shared RDS instance”, “sourceUrl”: “https://github.com/aws-cloudformation/aws-cloudformation-rpdk.git", “replacementStrategy”: “delete_then_create”, “properties”: { “DatabaseName”: { “type”: “string”, “pattern”: “^[A-Za-z0-9]+$” }, “DatabaseUser”: { “type”: “string”, “pattern”: “^[A-Za-z0-9]+$” }, “DatabasePassword”: { “type”: “string”, “pattern”: “^[A-Za-z0-9]+$”, “minLength”: 8 } }, “required”: [ “DatabaseName”, “DatabaseUser”, “DatabasePassword”, “RdsHost”, “RdsUser”, “RdsPassword” ], “primaryIdentifier”: [ “/properties/DatabaseName” ], “handlers”: { “create”: { “permissions”: [] }, “read”: { “permissions”: [] } } }
#### 內容解密:
- `typeName`:定義了資源型別的名稱。
- `description`:提供了對資源型別的簡要描述。
- `replacementStrategy`:指定了更新資源時的策略。
- `properties`:定義了資源的屬性,包括資料函式庫名稱、使用者名稱和密碼等。
- `required`:列出了建立資源所需的必要屬性。
- `primaryIdentifier`:指定了資源的主要識別符。
- `handlers`:定義了不同操作的許可權。
### 步驟五:生成專案檔案
執行以下命令以根據 schema 生成專案檔案:
```bash
cfn generate
步驟六:編輯處理程式(Handlers)
- 新增一個
dbclient.py檔案,以建立一個類別來管理資料函式庫連線:
dbclient.py
import pymysql
class DbClient: def init(self, endpoint, user, password): self.con = pymysql.connect( host=endpoint, user=user, password=password ) self.cursor = self.con.cursor()
CREATE_DB = "CREATE DATABASE {};"
CREATE_USER = "CREATE USER '{}'@'%' IDENTIFIED BY '{}';"
GRANT = "GRANT ALL PRIVILEGES ON {}.* TO '{}'@'%';"
FLUSH = "FLUSH PRIVILEGES;"
DELETE_DB = "DROP DATABASE {}"
#### 內容解密:
- `__init__` 方法初始化了資料函式庫連線。
- 定義了多個靜態 SQL 查詢範本,用於建立資料函式庫、使用者、授權和刪除資料函式庫。
## 在AWS CloudFormation中建立與使用私有擴充套件:探討RDS資源管理
在前一章中,我們已經瞭解瞭如何使用AWS CloudFormation來管理和佈署資源。在本章中,我們將探討如何建立和使用私有擴充套件,以更好地管理RDS資源。
### 建立私有擴充套件的必要性
AWS CloudFormation提供了許多內建資源型別,但有時我們需要管理特定的資源或執行自定義邏輯。這時,建立私有擴充套件就變得非常必要。私有擴充套件允許我們定義自定義資源型別,並使用AWS CloudFormation來管理和佈署這些資源。
### 建立RDS資源的私有擴充套件
在我們的例子中,我們將建立一個私有擴充套件來管理RDS資源。我們將定義一個自定義資源型別`My::RDS::Database`,並使用它來建立和管理RDS資料函式庫例項。
#### 步驟1:定義資源型別
首先,我們需要定義資源型別的結構和屬性。在我們的例子中,`My::RDS::Database`資源型別將具有以下屬性:
- `DatabaseName`:資料函式庫名稱
- `DatabaseUser`:資料函式庫使用者名稱
- `DatabasePassword`:資料函式庫密碼
- `RdsHost`:RDS例項主機名稱
- `RdsUser`:RDS例項使用者名稱
- `RdsPassword`:RDS例項密碼
#### 步驟2:實作資源邏輯
接下來,我們需要實作資源邏輯,包括建立、更新、刪除和讀取資源。我們將使用Python來實作這些邏輯。
```python
class DbClient:
def __init__(self, host, user, password):
self.host = host
self.user = user
self.password = password
self.cursor = self._get_db_connection()
def _get_db_connection(self):
# 建立與RDS例項的連線
# 省略實作細節
pass
def db_exists(self, db):
query = "SHOW DATABASES LIKE '{}'".format(db)
if self.cursor.execute(query):
return True
return False
def user_exists(self, user):
query = "SELECT user FROM mysql.user where user='{}'".format(user)
if self.cursor.execute(query):
return True
return False
def create_or_update(self, db, user, pw):
if self.db_exists(db):
self.delete_db(db)
if self.user_exists(user):
self.delete_user(user)
self.cursor.execute("CREATE USER '{}'@'%' IDENTIFIED BY '{}'".format(user, pw))
self.cursor.execute("CREATE DATABASE {}".format(db))
self.cursor.execute("GRANT ALL PRIVILEGES ON {}.{} TO '{}'@'%'".format(db, '*', user))
self.cursor.execute("FLUSH PRIVILEGES")
def delete(self, db, user):
if self.db_exists(db):
self.delete_db(db)
if self.user_exists(user):
self.delete_user(user)
def change_user_password(self, user, pw):
if not self.user_exists(user):
raise ValueError('User {} does not exist!'.format(user))
self.cursor.execute("ALTER USER '{}'@'%' IDENTIFIED BY '{}'".format(user, pw))
步驟3:實作處理程式
現在,我們需要實作處理程式來處理建立、更新、刪除和讀取資源的請求。
@resource.handler(Action.CREATE)
def create_handler(session, request, callback_context):
host, rds_user, rds_pw = get_db_connection_parameters(request)
db, user, pw = get_db_properties(request)
client = DbClient(host, rds_user, rds_pw)
if client.user_exists(user) or client.db_exists(db):
return ProgressEvent.failed(HandlerErrorCode.AlreadyExists)
try:
client.create_or_update(db, user, pw)
progress.status = OperationStatus.SUCCESS
except Exception as e:
return ProgressEvent.failed(HandlerErrorCode.HandlerInternalFailure)
return read_handler(session, request, callback_context)
@resource.handler(Action.UPDATE)
def update_handler(session, request, callback_context):
# 省略實作細節
pass
@resource.handler(Action.DELETE)
def delete_handler(session, request, callback_context):
host, rds_user, rds_pw = get_db_connection_parameters(request)
db, user, _ = get_db_properties(request)
client = DbClient(host, rds_user, rds_pw)
if not (client.db_exists(db) or client.user_exists(user)):
return ProgressEvent.failed(HandlerErrorCode.NotFound)
try:
client.delete(db, user)
except Exception as e:
return ProgressEvent.failed(HandlerErrorCode.HandlerInternalFailure)
return ProgressEvent(status=OperationStatus.SUCCESS)
測試和驗證
最後,我們需要測試和驗證我們的私有擴充套件,以確保它能夠正確地工作。
測試策略
- 建立測試案例:編寫測試案例來驗證建立、更新、刪除和讀取資源的邏輯。
- 執行測試:執行測試案例,以確保私有擴充套件能夠正確地工作。