Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537
之前說(shuō)過(guò)結(jié)構(gòu)化Prompt,這是一個(gè)具體案例的使用,本例是把公眾號(hào)上中文技術(shù)文章翻譯成選擇的語(yǔ)言。
基本思路是用戶輸入文章的url,系統(tǒng)用Playwright讀取html內(nèi)容,然后利用SemanticKernel的OpenAIChatCompletionService功能,按照提示詞翻譯,最后用Playwright把結(jié)果發(fā)送到Qiit(一個(gè)日本技術(shù)博客網(wǎng)站)上。
結(jié)構(gòu)化的提示詞如下:
# Role: 軟件技術(shù)翻譯專家
## Profile:
### Author: gsw
### Version: 2.0
### Language: {{language}}
### Description: 我是一個(gè)專門(mén)把中文技術(shù)文章翻譯成Language指定的技術(shù)文章的AI 角色。
## Goals: 能準(zhǔn)確地把中文技術(shù)文章翻譯成Language指定技術(shù)文章。
## Constrains:
1. 把html轉(zhuǎn)成markdown輸出,在輸出時(shí),請(qǐng)注意要翻譯成Language指定的語(yǔ)言
2. 把代碼放在專有的代碼塊標(biāo)識(shí)中,如果分析不出是什么類型的代碼,就以 C# 代碼塊進(jìn)行標(biāo)識(shí)
4. 你不會(huì)在翻譯時(shí)添加自己的看法,只是原文翻譯
5. 翻譯完后, 不會(huì)詢問(wèn)是否有其它問(wèn)題
6. 注意html中的圖片(img)標(biāo)簽,要轉(zhuǎn)成markdown的形式同時(shí)給出
7. 保持原文輸出,請(qǐng)全部翻譯輸出,請(qǐng)全部翻譯輸出,請(qǐng)全部翻譯輸出
8. 在翻譯完成后,最后一行添加“(Translated by GPT)”字樣
## Skills:
1. 具有強(qiáng)大的軟件技術(shù)知識(shí)獲取和整合能力
2. 擁有廣泛的編程語(yǔ)言知識(shí)庫(kù), 掌握提問(wèn)和回答的技巧
3. 擁有排版審美, 會(huì)利用序號(hào), 縮進(jìn), 分隔線和換行符等等來(lái)美化信息排版
4. 擅長(zhǎng)使用比喻的方式來(lái)讓用戶理解知識(shí)
5. 充分利用markdown語(yǔ)法來(lái)排版
## Workflows:
1. 讓用戶以 "標(biāo)題:[]" 的方式指定需要翻譯的標(biāo)題。
2. 讓用戶以 "內(nèi)容:[]" 的方式指定需要翻譯的內(nèi)容。
3. 針對(duì)用戶給定的標(biāo)題和內(nèi)容進(jìn)行翻譯,不要帶“標(biāo)題:”和“內(nèi)容:”字樣,第一行是標(biāo)題,第二行以后是內(nèi)容。
## Initialization
作為角色 <Role>,你擁有 <Skills>,嚴(yán)格遵守 <Constrains>,使用默認(rèn) <Language> ,按照 <Workflows>輸出結(jié)果。
原來(lái)提示詞是把網(wǎng)頁(yè)文字取出來(lái),進(jìn)行翻譯,圖片進(jìn)行了特殊處理,像表格之類的格式就會(huì)丟掉,后來(lái)作了一下優(yōu)化,讓GPT直接把html轉(zhuǎn)成markdown,這樣即使有特列的html表示,也能轉(zhuǎn)成相對(duì)友好的markdown格式。
具體C#代碼實(shí)現(xiàn)如下:
using Microsoft.Playwright;
using Microsoft.SemanticKernel.ChatCompletion;
using Microsoft.SemanticKernel.Connectors.OpenAI;
using System.Text.RegularExpressions;
using System.Text;
namespace TranslateAgent
{
public partial class MainForm : Form
{
public MainForm()
{
InitializeComponent();
}
private void MainForm_Load(object sender, EventArgs e)
{
var lans = new List<string>
{
"日語(yǔ)","英語(yǔ)","法語(yǔ)","德語(yǔ)","韓語(yǔ)"
};
LanComBox.DataSource = lans;
}
(string title, string content) SplitArticle(string article)
{
if (!string.IsOrWhiteSpace(article))
{
var reader = new StringReader(article);
var title = reader.ReadLine();
var content = reader.ReadToEnd();
return (title, content);
}
throw new Exception("文章為空!");
}
async Task<bool> PublishArticleAsync(string translatorContent)
{
var (title, content) = SplitArticle(translatorContent);
var url = "";
this.Invoke(() =>
{
url = UrlTextBox.Text;
});
if (!string.IsOrWhiteSpace(url))
{
content += $"\r\n元のリンク:{url}";
}
using var playwright = await Playwright.CreateAsync();
await using var browser = await playwright.Chromium.LaunchAsync(new BrowserTypeLaunchOptions
{
Headless = false,
Args = ["--start-maximized"]
});
var page = await browser.NewPageAsync();
await page.GotoAsync("https://qiita.com/");
await page.ClickAsync("a[href='/login?callback_action=login_or_signup&redirect_to=%2F&realm=qiita']");
var userArr = File.ReadAllLines("C:/gpt/qiita_user.txt");
await page.FillAsync("#identity", userArr[0]);
await page.FillAsync("#password", userArr[1]);
await page.ClickAsync("input[name='commit']");
await page.GotoAsync("https://qiita.com/drafts/new");
await page.FillAsync("input[placeholder='記事タイトル']", title);
await page.FillAsync("input[placeholder='タグを入力してください。スペース區(qū)切りで5つまで入力できます。']", "C# .NET");
await page.FillAsync("div[role='textbox']", content);
MessageBox.Show("請(qǐng)確認(rèn)發(fā)表內(nèi)容,并且手動(dòng)在彈出的內(nèi)核瀏覽器中發(fā)布!請(qǐng)注意,點(diǎn)擊確定后會(huì)自動(dòng)關(guān)閉內(nèi)核瀏覽器!!!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
return true;
}
async Task<(string Title, string Content)> GetArticleAsync(string url)
{
using var playwright = await Playwright.CreateAsync();
await using var browser = await playwright.Chromium.LaunchAsync(/*new BrowserTypeLaunchOptions { Headless = false }*/);
var page = await browser.NewPageAsync();
await page.GotoAsync(url);
var title = await page.Locator("#activity-name").InnerTextAsync();
var locator = page.Locator("#js_content");
var images = await locator.GetByRole(AriaRole.Img).ElementHandlesAsync();
var imageList = new List<string>();
foreach (var image in images)
{
var imgUrl = await image.GetAttributeAsync("data-src");
imageList.Add(imgUrl);
}
var html = await locator.InnerHTMLAsync();
var imgTagPattern = @"<img[^>]*>";
html = Regex.Replace(html, imgTagPattern, "[圖片]");
await page.SetContentAsync("<div id='js_content'>" + html + "</div>");
var content = await page.Locator("#js_content").InnerTextAsync();
var reader = new StringReader(content);
var index = 0;
var contentBuilder = new StringBuilder();
while (true)
{
var line = await reader.ReadLineAsync();
if (!string.IsOrWhiteSpace(line.Trim()))
{
if (line.Trim() == "[圖片]")
{
contentBuilder.AppendLine($"");
index++;
}
else
{
contentBuilder.AppendLine(line);
}
}
if (reader.Peek() <= 0)
{
break;
}
}
return (title, contentBuilder.ToString());
}
async Task<string> OpenAIChatSampleAsync(string title, string content)
{
var key = File.ReadAllText(@"C:\GPT\key.txt");
var chatModelId = "gpt-4-0125-preview";
OpenAIChatCompletionService chatCompletionService = new(chatModelId, key);
return await StartChatAsync(chatCompletionService, title, content);
}
async Task<string> StartChatAsync(IChatCompletionService chatGPT, string title, string content)
{
var lan = "日文";
this.Invoke(() =>
{
lan = LanComBox.Text;
});
var prompt = File.ReadAllText(Environment.CurrentDirectory + "/Prompt.md");
prompt = prompt.Replace("{{language}}", lan);
var chatHistory = new ChatHistory(prompt);
var userContent = $"標(biāo)題:{title}\r\n內(nèi)容:{content}";
chatHistory.AddUserMessage(userContent);
return await MessageStreamOutputAsync(chatGPT, chatHistory);
}
async Task<string> MessageStreamOutputAsync(IChatCompletionService chatGPT, ChatHistory chatHistory)
{
var list = chatGPT.GetStreamingChatMessageContentsAsync(chatHistory);
var fullMessage = string.Empty;
await foreach (var item in list)
{
if (item == )
{
continue;
}
fullMessage += item.Content;
this.Invoke(() =>
{
TranslationTextBox.AppendText(item.Content);
});
}
return fullMessage;
}
private void TranButton_Click(object sender, EventArgs e)
{
try
{
var url = UrlTextBox.Text;
if (string.IsOrWhiteSpace(url))
{
MessageBox.Show("輸入的url有誤,請(qǐng)重新輸入!", "錯(cuò)誤", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
var pattern = @"^(https?:\/\/)?(?s).*$";
var regex = new Regex(pattern, RegexOptions.IgnoreCase);
bool isValid = regex.IsMatch(url);
if (!isValid)
{
MessageBox.Show("輸入的url有誤,請(qǐng)重新輸入!", "錯(cuò)誤", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
else
{
Task.Run(() =>
{
try
{
var (title, content) = GetArticleAsync(url).Result;
this.Invoke(() =>
{
OriginalTextBox.Lines = new string[] { title, content };
});
var translatorContent = OpenAIChatSampleAsync(title, content).Result;
var result = PublishArticleAsync(translatorContent).Result;
if (!result)
{
MessageBox.Show("翻譯失敗!", "錯(cuò)誤", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
catch (Exception exc)
{
MessageBox.Show(exc.Message, "錯(cuò)誤", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
});
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "錯(cuò)誤", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
private void LanComBox_SelectedIndexChanged(object sender, EventArgs e)
{
this.Text = "中文->" + LanComBox.Text;
}
private void ClearButton_Click(object sender, EventArgs e)
{
UrlTextBox.Clear();
OriginalTextBox.Clear();
TranslationTextBox.Clear();
}
}
}
運(yùn)行結(jié)果一:
運(yùn)行結(jié)果二:
國(guó)長(zhǎng)安網(wǎng)北京8月1日電(郭莎莎)公安部今天在京發(fā)布,公安部“互聯(lián)網(wǎng)+政務(wù)服務(wù)”平合正式上線,實(shí)現(xiàn)全國(guó)一次認(rèn)證、一網(wǎng)通辦。
公安部科技信息化局局長(zhǎng)厲劍通報(bào),公安部“互聯(lián)網(wǎng)+政務(wù)服務(wù)”平臺(tái)今天正式上線,網(wǎng)址為https://zwfw.mps.gov.cn/。普通網(wǎng)友均可登錄使用。平臺(tái)已對(duì)接貫通國(guó)家政務(wù)服務(wù)平臺(tái),統(tǒng)一了用戶體系,解決了企業(yè)和群眾在公安平臺(tái)和政府平臺(tái)重復(fù)注冊(cè)、多次驗(yàn)證等問(wèn)題,實(shí)現(xiàn)了一次認(rèn)證、單點(diǎn)登錄、全網(wǎng)通辦。
“平臺(tái)的上線,是公安機(jī)關(guān)為民服務(wù)的又一創(chuàng)新成果,也標(biāo)志著全國(guó)公安政務(wù)服務(wù)工作水平邁上了一個(gè)新臺(tái)階。”厲劍說(shuō)。
他介紹,“互聯(lián)網(wǎng)+公安政務(wù)服務(wù)”是公安機(jī)關(guān)在深入調(diào)研、充分聽(tīng)取企業(yè)、群眾和民警意見(jiàn)的基礎(chǔ)上,敢于刀刃向內(nèi),打破數(shù)據(jù)和系統(tǒng)壁壘,運(yùn)用互聯(lián)網(wǎng)思維,通過(guò)數(shù)據(jù)共享和業(yè)務(wù)流程再造,減少警種部門(mén)之間和上下級(jí)公安機(jī)關(guān)之間審批流轉(zhuǎn)的中間環(huán)節(jié),最大程度地簡(jiǎn)化群眾辦事流程,促進(jìn)服務(wù)審批工作更加高效,讓企業(yè)、群眾充分得到公安“放管服”改革的紅利和實(shí)惠,同時(shí)也釋放出更多的警力從事治安防范、打擊犯罪等其他公安業(yè)務(wù)工作。
公安部科信委專職副主任劉明芳介紹,公安部的平臺(tái)綜合集成了各層級(jí)公安機(jī)關(guān)和公安部各警種、各部門(mén)的網(wǎng)上辦事系統(tǒng),形成了集中的辦事中心、查詢中心、評(píng)價(jià)中心,主要有以下三個(gè)特色:
一是統(tǒng)一應(yīng)用支撐。平臺(tái)建設(shè)了統(tǒng)一身份認(rèn)證、統(tǒng)一事項(xiàng)管理、統(tǒng)一數(shù)據(jù)交換、統(tǒng)一評(píng)價(jià)服務(wù)等基礎(chǔ)支撐功能,為各地公安機(jī)關(guān)網(wǎng)上政務(wù)服務(wù)平臺(tái)提供共性應(yīng)用支撐,各地平臺(tái)可在此基礎(chǔ)上,開(kāi)發(fā)符合本地實(shí)際的個(gè)性化應(yīng)用。
二是四級(jí)業(yè)務(wù)聯(lián)動(dòng)。平臺(tái)強(qiáng)化協(xié)同聯(lián)動(dòng),將原來(lái)分布在部、省、市、縣四級(jí)公安機(jī)關(guān)的網(wǎng)上辦事平臺(tái)與公安部“互聯(lián)網(wǎng)+政務(wù)服務(wù)”平臺(tái)逐級(jí)對(duì)接貫通,將四級(jí)公安機(jī)關(guān)網(wǎng)上政務(wù)服務(wù)的數(shù)據(jù)流、業(yè)務(wù)流、管理流有效融合,建立了網(wǎng)上政務(wù)服務(wù)動(dòng)態(tài)更新機(jī)制,確保公安政務(wù)服務(wù)事項(xiàng)的源頭一致,更新同步,服務(wù)同頻,實(shí)現(xiàn)群眾辦理公安政務(wù)服務(wù)事項(xiàng)只進(jìn)一張網(wǎng)、不用多頭跑。
三是身份雙源認(rèn)證。以全國(guó)人口信息和居民身份證辦理信息作為網(wǎng)上身份信息核驗(yàn)的兩大權(quán)威數(shù)據(jù)源,支撐全國(guó)一體化在線政務(wù)服務(wù)平臺(tái)用戶身份信息的實(shí)人、實(shí)名、實(shí)證的在線核驗(yàn),有效解決了網(wǎng)上政務(wù)服務(wù)“我就是我”、“是我在辦”的難題。
記者從發(fā)布會(huì)獲悉,各級(jí)公安機(jī)關(guān)緊貼群眾需求,勇于推陳出新,不斷增強(qiáng)“互聯(lián)網(wǎng)+公安政務(wù)服務(wù)”工作的創(chuàng)新活力。通過(guò)網(wǎng)站、APP、公眾號(hào)、小程序,將服務(wù)的入口從線下移到線上;通過(guò)在線申請(qǐng)、網(wǎng)上受理、遠(yuǎn)程寄遞等多種方式,有效打通了網(wǎng)上服務(wù)的“最后一公里”通過(guò)刷臉認(rèn)證、一鍵挪車等便捷應(yīng)用,將服務(wù)的觸角延伸至各個(gè)角落。
陜西作為全國(guó)首批4個(gè)試點(diǎn)對(duì)接公安部“互聯(lián)網(wǎng)+平臺(tái)”的省份,率先建成陜西“互聯(lián)網(wǎng)+公安政務(wù)服務(wù)”平臺(tái)并正式上線運(yùn)行。在平臺(tái)建設(shè)應(yīng)用推廣中,結(jié)合地方特色,重點(diǎn)從優(yōu)化辦事流程、打通關(guān)鍵環(huán)節(jié)、完善平臺(tái)問(wèn)題三方面來(lái)打通網(wǎng)上辦事的“最后一公里”。廣東省公安機(jī)關(guān)按照有關(guān)要求,打造了既支持內(nèi)地居民也服務(wù)港澳居民注冊(cè)和使用的“智慧新民生”平臺(tái),并且實(shí)現(xiàn)了和公安部“互聯(lián)網(wǎng)+政務(wù)服務(wù)”平臺(tái)的全面對(duì)接。目前,可面向港澳居民在線辦理的有粵港澳直通車、警務(wù)非稅收入繳款兩方面業(yè)務(wù)。
公安部“互聯(lián)網(wǎng)+政務(wù)服務(wù)”平臺(tái)目前已匯聚服務(wù)事項(xiàng)548項(xiàng),為群眾提供了公安服務(wù)事項(xiàng)的辦理、查詢、評(píng)價(jià)一站式服務(wù),打造了“一大平合全網(wǎng)貫通、雙源數(shù)據(jù)全面支撐、四級(jí)聯(lián)動(dòng)全警應(yīng)用、多種措施全力防護(hù)”的應(yīng)用體系。
厲劍提及,信息安全與服務(wù)同樣重要。通過(guò)將技術(shù)防護(hù)和安全管理的有效結(jié)合,著力構(gòu)建全方位、多層次的縱深安全防護(hù)體系,確保公安部“互聯(lián)網(wǎng)+政務(wù)服務(wù)”平臺(tái)的系統(tǒng)安全和數(shù)據(jù)安全。
在技術(shù)上,該平臺(tái)采取五方面的措施:
一是邀請(qǐng)信息安全方面的專家和相關(guān)專業(yè)力量,制定了“云+端”的安全技術(shù)方案。二是采用安全網(wǎng)關(guān)、防火墻、入侵防護(hù)、堡壘機(jī)等各種安全加固措施抵御外部的攻擊,保障平臺(tái)信息安全。三是建設(shè)安全風(fēng)險(xiǎn)發(fā)現(xiàn)預(yù)警功能,出現(xiàn)安全漏洞時(shí)及時(shí)預(yù)警,并能阻斷數(shù)據(jù)外泄。四是利用國(guó)產(chǎn)加密算法、身份鑒權(quán)等相關(guān)技術(shù),保障接口安全及數(shù)據(jù)的加密傳輸和存儲(chǔ)安全。目前已經(jīng)通過(guò)密碼應(yīng)用安全方面的測(cè)評(píng)。五是嚴(yán)格對(duì)照信息系統(tǒng)等級(jí)保護(hù)相關(guān)要求,配置相應(yīng)的安全防護(hù)設(shè)備和防護(hù)手段。目前,已經(jīng)通過(guò)了等保三級(jí)相關(guān)測(cè)評(píng)。
在管理上,該平臺(tái)采取了三個(gè)方面的安保措施。一是制定統(tǒng)一的安全管理規(guī)定,明確各級(jí)公安機(jī)關(guān)負(fù)責(zé)的網(wǎng)上辦理事項(xiàng)網(wǎng)站相關(guān)的主體責(zé)任,建立了上下聯(lián)動(dòng)相關(guān)機(jī)制,確保公安機(jī)關(guān)一體化政務(wù)平臺(tái)整體安全。二是定期對(duì)平臺(tái)進(jìn)行攻防演練,發(fā)現(xiàn)漏洞及時(shí)修補(bǔ)。三是建立安全事故應(yīng)急預(yù)案,一旦發(fā)生安全事故后,確保能夠快速響應(yīng),并及時(shí)地修復(fù)。
發(fā)布會(huì)公布,下一步,公安部將進(jìn)一步整合全國(guó)公安機(jī)關(guān)的相關(guān)資源,優(yōu)化流程、完善機(jī)制,不斷豐富公安部“互聯(lián)網(wǎng)+政務(wù)服務(wù)”平合功能,結(jié)合公安行業(yè)特點(diǎn),聚焦“一網(wǎng)通辦,便民惠警”目標(biāo),加強(qiáng)應(yīng)用創(chuàng)新,推進(jìn)線上線下深度融合,推動(dòng)公安政務(wù)服務(wù)整體聯(lián)動(dòng)全程在線,不斷擴(kuò)大公安“放管服”改革的受益群體,確保讓廣大人民群眾有更多、更直接、更實(shí)在的獲得感。
EventBridge 作為構(gòu)建 EDA 架構(gòu)的基礎(chǔ)設(shè)施,通過(guò)一些核心概念和特性提供了靈活豐富的事件收集、處理和路由的能力。對(duì)于不少用戶來(lái)說(shuō),通過(guò)控制臺(tái)里的便捷的引導(dǎo)來(lái)使用 EventBridge 應(yīng)該是最快的上手方式。此外,也有很多用戶面臨著大量的云產(chǎn)品的管理,使用控制臺(tái)管理每一個(gè)資源的方式變成了沉重的手工操作負(fù)擔(dān)。
為了解決這個(gè)問(wèn)題,現(xiàn)在已經(jīng)能夠通過(guò) OpenAPI、terraform 等方式將 EventBridge 的能力方便快捷的帶給用戶。本文將重點(diǎn)介紹 EventBridge 和 IaC 的重點(diǎn)概念和特性,然后演示如何應(yīng)用 IaC 理念自動(dòng)化部署 EventBridge 來(lái)使用這些概念和特性。
事件驅(qū)動(dòng)架構(gòu)
事件驅(qū)動(dòng)架構(gòu)是一種松耦合、分布式的驅(qū)動(dòng)架構(gòu),收集到某應(yīng)用產(chǎn)生的事件后實(shí)時(shí)對(duì)事件采取必要的處理,緊接著路由至下游系統(tǒng),無(wú)需等待系統(tǒng)響應(yīng)。使用事件總線 EventBridge 可以構(gòu)建各種簡(jiǎn)單或復(fù)雜的事件驅(qū)動(dòng)架構(gòu),以標(biāo)準(zhǔn)化的 CloudEvents 1.0 協(xié)議連接云產(chǎn)品和應(yīng)用、應(yīng)用和應(yīng)用等。
事件驅(qū)動(dòng)架構(gòu)體系架構(gòu)具備以下三個(gè)能力:
事件驅(qū)動(dòng)架構(gòu)具有以下優(yōu)勢(shì):
使用 EventBridge 構(gòu)建 EDA 架構(gòu)
事件總線 EventBridge 是阿里云提供的一款無(wú)服務(wù)器事件總線服務(wù)。EventBridge 提供的幾個(gè)核心概念,可以滿足構(gòu)建 EDA 架構(gòu)的需要。
事件總線 EventBridge 支持以下事件源:
事件總線 EventBridge 的事件總線包括以下類型:
在 EventBridge 中,一個(gè)事件規(guī)則包含以下內(nèi)容:
EventBridge 提供了簡(jiǎn)潔的事件模式匹配語(yǔ)法,同時(shí)具備靈活的事件轉(zhuǎn)換能力,后面將會(huì)通過(guò)演示來(lái)展示一些具體的例子。
此外,EventBridge 還提供了一些增強(qiáng)能力,這些能力使得 EDA 架構(gòu)中流經(jīng)的事件更加透明,具備了開(kāi)箱即用的觀測(cè)和分析能力:
在介紹完事件總線 EventBridge 的相關(guān)基礎(chǔ)內(nèi)容后,接下來(lái)一起了解下 IaC。在 DevOps 的實(shí)踐中,IaC 是非常重要的部分,通過(guò)將基礎(chǔ)設(shè)施代碼化,版本化,便可以輕松的借助版本控制工具來(lái)提供 single source of truth、協(xié)調(diào)多人合作的變更、實(shí)施嚴(yán)格的 review、借助一些 CI/CD pipeline 工具(甚至 GitOps)來(lái)自動(dòng)觸發(fā)部署。軟件系統(tǒng)的開(kāi)發(fā)者僅付出很小的努力去描述需求,就可以在幾分鐘后得到所需的虛擬機(jī)、網(wǎng)絡(luò)等云上的服務(wù),極大的縮短了部署時(shí)間,同時(shí)還能夠保證多個(gè)環(huán)境的配置一致性,通過(guò)減少人為操作也降低了引入錯(cuò)誤的概率。
IaC的代碼實(shí)踐中一般有兩種方式,命令式和聲明式。
IaC 帶來(lái)的優(yōu)勢(shì):
terraform 作為 IaC 領(lǐng)域的佼佼者,提供了強(qiáng)大的自動(dòng)化管理基礎(chǔ)設(shè)施的能力。生態(tài)豐富,很多云廠商都提供了官方插件,阿里云的大多數(shù)產(chǎn)品(包括 EventBridge)都對(duì) terraform 做了很全面的支持,使得跨多云部署基礎(chǔ)設(shè)施變得極其簡(jiǎn)單。既然是 IaC,terraform 提供了自己的語(yǔ)言 HCL(hashicorp configuration language),HCL 具有類似 json 的簡(jiǎn)潔的語(yǔ)法,通過(guò)聲明式的資源描述,可以讓開(kāi)發(fā)者快速上手。
準(zhǔn)備工作
provider "alicloud" {
access_key = "<your access key>"
secret_key = "<your secret key>"
region = "<region id>"
}
案例1:通過(guò)釘釘監(jiān)控云上資源變化
假設(shè)一個(gè)用戶使用了很多云上的資源作為生產(chǎn)環(huán)境,需要感知線上資源的變更操作,一個(gè)可行的方案是利用 EventBridge 將來(lái)自于 ActionTrail 的審計(jì)事件投遞到用戶的釘釘。
首先根據(jù)釘釘官方文檔創(chuàng)建一個(gè)機(jī)器人,記下 webhook url 和加簽的秘鑰,接下來(lái)會(huì)用到。
創(chuàng)建一個(gè) tf 文件 1_actiontrail2dingding.tf,內(nèi)容如下(需要替換<>內(nèi)的值)
# 案例1:通過(guò)釘釘監(jiān)控云上資源變化
# 目標(biāo):
# - 熟悉部署使用EventBridge的default總線
# - 熟悉EventBridge的事件模式匹配
# - 熟悉EventBridge的事件轉(zhuǎn)換配置
# 聲明一個(gè)default總線上的規(guī)則
resource "alicloud_event_bridge_rule" "audit_notify" {
# default總線默認(rèn)存在,所以這里可以直接使用
event_bus_name = "default"
rule_name = "audit_notify"
description = "demo"
# 通過(guò)后綴匹配的方式過(guò)濾來(lái)自所有云產(chǎn)品事件源的ActionTrail:ApiCall事件
# 其他更多模式匹配的介紹可以查閱文檔:https://help.aliyun.com/document_detail/181432.html
filter_pattern = jsonencode(
{
"type" : [
{
"suffix" : ":ActionTrail:ApiCall"
}
]
}
)
targets {
target_id = "test-target"
endpoint = "<your dingtalk bot webhook url>"
# type的取值可以查閱文檔:https://registry.terraform.io/providers/aliyun/alicloud/latest/docs/resources/event_bridge_rule#type
type = "acs.dingtalk"
# 每個(gè)事件目標(biāo)都有一組對(duì)應(yīng)的param_list,具體可以查閱文檔:https://help.aliyun.com/document_detail/185887.html
# 每一個(gè)param的form關(guān)系到事件轉(zhuǎn)換的配置,可以查閱文檔:https://help.aliyun.com/document_detail/181429.html
param_list {
resource_key = "URL"
form = "CONSTANT"
value = "<your dingtalk bot webhook url>"
}
param_list {
resource_key = "SecretKey"
form = "CONSTANT"
value = "<your dingtalk bot secret key>"
}
# 這里展示了TEMPLATE類型的事件轉(zhuǎn)換描述
# value是使用jsonpath引用事件內(nèi)容的字典,template則是模板內(nèi)容,EventBridge最終會(huì)根據(jù)這兩者結(jié)合事件本身渲染出這個(gè)參數(shù)的值
param_list {
resource_key = "Body"
form = "TEMPLATE"
value = jsonencode(
{
"source": "$.source",
"type": "$.type"
"region": "$.data.acsRegion",
"accountId" : "$.data.userIdentity.accountId",
"eventName" : "$.data.eventName",
}
)
template = jsonencode(
{
"msgtype" : "text",
"text" : {
"content": "來(lái)自 $${source} 的 $${type} 審計(jì)事件:$${accountId} 在 $${region} 執(zhí)行了 $${eventName} 操作"
}
}
)
}
}
}
在命令行窗口依次執(zhí)行命令:
在云產(chǎn)品控制臺(tái)進(jìn)行操作,這里以 KMS 為例
釘釘上收到消息通知
在 EventBridge 控制臺(tái)查看事件軌跡
案例 2:自定義總線觸發(fā) FunctionCompute
假設(shè)一個(gè)用戶的應(yīng)用會(huì)產(chǎn)生一些事件,其中一個(gè)鏈路是通過(guò) FunctionCompute 對(duì)這些事件進(jìn)行彈性的處理。那么就可以通過(guò) EventBridge 的自定義事件源和函數(shù)計(jì)算事件目標(biāo)來(lái)實(shí)現(xiàn)這個(gè)方案。
創(chuàng)建一個(gè)模擬對(duì)事件進(jìn)行處理的 python 腳本文件 src/index.py,內(nèi)容如下:
# -*- coding: utf-8 -*-
import logging
def handler(event, context):
logger = logging.getLogger()
logger.info('evt: ' + str(event))
return str(event)
創(chuàng)建一個(gè) tf 文件 2_trigger_function.tf,內(nèi)容如下(需要替換<>內(nèi)的值)
# 案例2:自定義總線觸發(fā)FunctionCompute
# 目標(biāo):
# - 熟悉部署使用EventBridge的自定義總線
# - 熟悉"自定義應(yīng)用"事件源配置
# - 熟悉“FunctionCompute”事件目標(biāo)配置
# 由于用戶自己產(chǎn)生的事件需要投遞到自定義總線,這里聲明一個(gè)叫demo_event_bus的自定義總線
resource "alicloud_event_bridge_event_bus" "demo_event_bus" {
event_bus_name = "demo_event_bus"
description = "demo"
}
# 聲明一個(gè)在demo_event_bus總線上的自定義事件源,用于通過(guò)sdk或者控制臺(tái)向EventBridge投遞事件
resource "alicloud_event_bridge_event_source" "demo_event_source" {
event_bus_name = alicloud_event_bridge_event_bus.demo_event_bus.event_bus_name
event_source_name = "demo_event_source"
description = "demo"
linked_external_source = false
}
# 聲明一個(gè)叫fc_service的函數(shù)計(jì)算服務(wù),publish=true意味著會(huì)立即部署上傳的函數(shù)代碼。
resource "alicloud_fc_service" "fc_service" {
name = "eb-fc-service"
description = "demo"
publish = true
}
# 將前面準(zhǔn)備的python腳本文件打包成zip用于部署到函數(shù)計(jì)算
data "archive_file" "code" {
type = "zip"
source_file = "${path.module}/src/index.py"
output_path = "${path.module}/code.zip"
}
# 聲明一個(gè)fc_service服務(wù)中的函數(shù),其中filename引用了上面描述的zip包,會(huì)將這個(gè)代碼包上傳。
resource "alicloud_fc_function" "fc_function" {
service = alicloud_fc_service.fc_service.name
name = "eb-fc-function"
description = "demo"
filename = data.archive_file.code.output_path
memory_size = "128"
runtime = "python3"
handler = "index.handler"
}
# 聲明一個(gè)在demo_event_bus總線上的規(guī)則
resource "alicloud_event_bridge_rule" "demo_rule" {
event_bus_name = alicloud_event_bridge_event_bus.demo_event_bus.event_bus_name
rule_name = "demo_rule"
description = "demo"
# 通過(guò)匹配source過(guò)濾來(lái)自于前面創(chuàng)建的自定義事件源的事件
filter_pattern = jsonencode(
{
"source" : ["${alicloud_event_bridge_event_source.demo_event_source.id}"]
}
)
targets {
target_id = "demo-fc-target"
# type的取值可以查閱文檔:https://registry.terraform.io/providers/aliyun/alicloud/latest/docs/resources/event_bridge_rule#type
type = "acs.fc.function"
endpoint = "acs:fc:<region id>:<your account id>:services/${alicloud_fc_service.fc_service.name}.LATEST/functions/${alicloud_fc_function.fc_function.name}"
param_list {
resource_key = "serviceName"
form = "CONSTANT"
value = alicloud_fc_service.fc_service.name
}
param_list {
resource_key = "functionName"
form = "CONSTANT"
value = alicloud_fc_function.fc_function.name
}
param_list {
resource_key = "Qualifier"
form = "CONSTANT"
value = "LATEST"
}
# 注意form=ORIGINAL意味著每次投遞事件都會(huì)將事件的原始內(nèi)容作為這個(gè)參數(shù)的值
param_list {
resource_key = "Body"
form = "ORIGINAL"
}
}
}
在命令行窗口依次執(zhí)行命令
在控制臺(tái)模擬自定義事件源發(fā)布事件
在 FunctionCompute 的控制臺(tái)頁(yè)面查看函數(shù)調(diào)用日志
在 EventBridge 控制臺(tái)查看事件軌跡
總結(jié)
EventBridge 作為構(gòu)建 EDA 架構(gòu)的基礎(chǔ)設(shè)施,通過(guò)一些核心概念和特性提供了靈活豐富的事件收集、處理和路由的能力,并支持通過(guò) OpenAPI、terraform 等方式將這些能力方便快捷的帶給用戶。本文介紹了 EventBridge 和 IaC 的重點(diǎn)概念和特性,然后演示了如何應(yīng)用 IaC 理念自動(dòng)化部署 EventBridge 來(lái)使用這些概念和特性。
期待大家可以發(fā)掘更多利用 EventBridge 快速搭建 EDA 架構(gòu)的 idea,并使用 terraform 快捷的將這些 idea 變?yōu)楝F(xiàn)實(shí)。
[1] 阿里云 terraform 文檔
https://help.aliyun.com/product/95817.html
[2] terraform registry 文檔
https://registry.terraform.io/providers/aliyun/alicloud/latest/docs/resources/event_bridge_event_bus
[3] 釘釘官方文檔
https://open.dingtalk.com/document/group/custom-robot-access
作者:王川(弗丁)
原文鏈接:https://developer.aliyun.com/article/882907?utm_content=g_1000334839
本文為阿里云原創(chuàng)內(nèi)容,未經(jīng)允許不得轉(zhuǎn)載。
*請(qǐng)認(rèn)真填寫(xiě)需求信息,我們會(huì)在24小時(shí)內(nèi)與您取得聯(lián)系。