隨著 ToB (企業(yè)服務(wù))的興起和 ToC (消費(fèi)互聯(lián)網(wǎng))產(chǎn)品進(jìn)入成熟期,線上故障帶來(lái)的損失越來(lái)越大,代碼質(zhì)量越來(lái)越重要,而「質(zhì)量?jī)?nèi)建」正是 DevOps 核心理念之一。
《 DevOps 代碼質(zhì)量實(shí)戰(zhàn)( Java 版)》 為 CODING DevOps 代碼質(zhì)量實(shí)戰(zhàn)系列 的最后一課,同時(shí)也是本系列的 Java 版,楊周老師將以 Java Spring 為例,講解代碼規(guī)范、Git workflow 、持續(xù)集成、代碼生成 API 文檔、修改 maven 包、單元測(cè)試、Docker 等內(nèi)容。
課程主題
DevOps 代碼質(zhì)量實(shí)戰(zhàn)( Java 版)
課程時(shí)間
8 月 13 日(周四) 19:00
課程講師
楊周
CODING 布道師
CODING DevOps 架構(gòu)師
連續(xù)創(chuàng)業(yè)者、DIY/Linux 玩家、知乎小 V,曾在創(chuàng)新工場(chǎng)、百度擔(dān)任后端開(kāi)發(fā)。十余年一線研發(fā)和帶隊(duì)經(jīng)驗(yàn),經(jīng)歷了 ToB 、ToC 、O2O 、國(guó)內(nèi)、出海各種項(xiàng)目,見(jiàn)證了云計(jì)算時(shí)代的誕生,擅長(zhǎng)研發(fā)最佳實(shí)踐:Code Review 、DevOps 、Git Workflow 、敏捷開(kāi)發(fā)、架構(gòu)、極客辦公硬件。
課程大綱 增量檢查 Java 代碼規(guī)范 制品庫(kù):修改 maven 包 持續(xù)集成:Java 單元測(cè)試 持續(xù)交付:Docker 自動(dòng)部署:K8s
掃描 海報(bào)二維碼 即可預(yù)約系列課程
隨著 ToB (企業(yè)服務(wù))的興起和 ToC (消費(fèi)互聯(lián)網(wǎng))產(chǎn)品進(jìn)入成熟期,線上故障帶來(lái)的損失越來(lái)越大,代碼質(zhì)量越來(lái)越重要,而「質(zhì)量?jī)?nèi)建」正是 DevOps 核心理念之一。 《 DevOps 代碼質(zhì)量實(shí)戰(zhàn)( PHP 版)》 為 CODING DevOps 代碼質(zhì)量實(shí)戰(zhàn)系列 的第二課,同時(shí)也是本系列的 PHP 版,楊周老師將以 PHP Laravel 為例,為同學(xué)們講解代碼規(guī)范、Git workflow 、持續(xù)集成、代碼生成 API 文檔、開(kāi)發(fā) composer 包、單元測(cè)試、Docker 等內(nèi)容。
課程主題
DevOps 代碼質(zhì)量實(shí)戰(zhàn)( PHP 版)
課程時(shí)間
8 月 12 日(周三) 19:00
講師簡(jiǎn)介
楊周
CODING 布道師
CODING DevOps 架構(gòu)師
連續(xù)創(chuàng)業(yè)者、DIY/Linux 玩家、知乎小 V,曾在創(chuàng)新工場(chǎng)、百度擔(dān)任后端開(kāi)發(fā)。十余年一線研發(fā)和帶隊(duì)經(jīng)驗(yàn),經(jīng)歷了 ToB 、ToC 、O2O 、國(guó)內(nèi)、出海各種項(xiàng)目,見(jiàn)證了云計(jì)算時(shí)代的誕生,擅長(zhǎng)研發(fā)最佳實(shí)踐:Code Review 、DevOps 、Git Workflow 、敏捷開(kāi)發(fā)、架構(gòu)、極客辦公硬件。
課程大綱 增量檢查 PHP 代碼規(guī)范 制品庫(kù)與 Fork:修改 composer 包 持續(xù)集成:PHP 單元測(cè)試 持續(xù)交付:Laravel Docker 自動(dòng)部署:K8s
掃描 海報(bào)二維碼 即可預(yù)約系列課程
隨著 ToB (企業(yè)服務(wù))的興起和 ToC (消費(fèi)互聯(lián)網(wǎng))產(chǎn)品進(jìn)入成熟期,線上故障帶來(lái)的損失越來(lái)越大,代碼質(zhì)量越來(lái)越重要,而「質(zhì)量?jī)?nèi)建」正是 DevOps 核心理念之一。本次 CODING DevOps 代碼質(zhì)量實(shí)戰(zhàn)系列第一課: 《 DevOps 代碼質(zhì)量實(shí)戰(zhàn):代碼規(guī)范與 Git Flow 》 ,將由 CODING 布道師、CODING DevOps 架構(gòu)師 楊周 老師主講,為同學(xué)們?cè)敿?xì)講解提高代碼質(zhì)量的最佳實(shí)踐,不只適合新項(xiàng)目,也為老項(xiàng)目提供完善的漸進(jìn)式方案。
課程主題
DevOps 代碼質(zhì)量實(shí)戰(zhàn):代碼規(guī)范與 Git Flow
課程時(shí)間
8 月 11 日(周二) 19:00
課程講師
楊周
CODING 布道師
CODING DevOps 架構(gòu)師
連續(xù)創(chuàng)業(yè)者、DIY/Linux 玩家、知乎小 V,曾在創(chuàng)新工場(chǎng)、百度擔(dān)任后端開(kāi)發(fā)。十余年一線研發(fā)和帶隊(duì)經(jīng)驗(yàn),經(jīng)歷了 ToB 、ToC 、O2O 、國(guó)內(nèi)、出海各種項(xiàng)目,見(jiàn)證了云計(jì)算時(shí)代的誕生,擅長(zhǎng)研發(fā)最佳實(shí)踐:Code Review 、DevOps 、Git Workflow 、敏捷開(kāi)發(fā)、架構(gòu)、極客辦公硬件。
課程大綱 Code Review Lint:增量檢查代碼規(guī)范 Git workflow Fork:修改第三方包
掃描 海報(bào)二維碼 即可預(yù)約系列課程
一款產(chǎn)品從設(shè)計(jì)、開(kāi)發(fā)到上線,最初的靈感可能會(huì)在不同工具間流轉(zhuǎn),團(tuán)隊(duì)內(nèi)會(huì)產(chǎn)生大量額外的操作、溝通和消耗。
為了打破這些壁壘,讓工作流程更暢通,團(tuán)隊(duì)能專注于打磨產(chǎn)品, CODING 與在線產(chǎn)品原型設(shè)計(jì)與協(xié)作平臺(tái) 墨刀 合作推出實(shí)用小功能 —— CODING 事項(xiàng)內(nèi)的上傳附件功能現(xiàn)已支持 從外部引入墨刀原型 。
在事項(xiàng)當(dāng)前頁(yè)直接查看設(shè)計(jì)原型圖,團(tuán)隊(duì)內(nèi)部能夠更加快捷高效地對(duì)設(shè)計(jì)原型進(jìn)行討論、修改、更新,帶來(lái)更加順滑的工作體驗(yàn)。 CODING 標(biāo)準(zhǔn)版現(xiàn)已 完全免費(fèi) , 不限人數(shù)使用!
操作指南
簡(jiǎn)單 3 步實(shí)現(xiàn)墨刀原型引入
1 、登錄 墨刀 ,選擇需要導(dǎo)入進(jìn)事項(xiàng)的墨刀原型,點(diǎn)擊 [分享] 按鈕,選擇 [嵌入第三方] 并復(fù)制代碼。
2 、前往 CODING 事項(xiàng)管理,進(jìn)入任意史詩(shī)、需求、任務(wù)或缺陷中,在添加附件中選擇 [外部引入] - [墨刀原型] 。
3 、通過(guò)粘貼墨刀的嵌入代碼,將原型與事項(xiàng)關(guān)聯(lián),就能在 CODING 中直接查看設(shè)計(jì)原型了!
CODING 標(biāo)準(zhǔn)版現(xiàn)已完全免費(fèi), 點(diǎn)擊了解更多
https://coding.net/pricing
CODING DevOps 8 月直播課來(lái)了~!這次 CODING 為大家?guī)?lái)了兩場(chǎng)系列直播課,每系列包含 3 節(jié)課程,循序漸進(jìn),由淺入深,爭(zhēng)取在每晚 1 小時(shí)的課時(shí)內(nèi),結(jié)合實(shí)例為各位同學(xué)帶來(lái)最豐富的學(xué)習(xí)內(nèi)容。
那么一起來(lái)看看課程詳情以及報(bào)名方式,文末還有福利活動(dòng),千萬(wàn)別錯(cuò)過(guò)——
8 月直播課 第一系列
CODING DevOps 代碼質(zhì)量實(shí)戰(zhàn)系列直播課
開(kāi)課時(shí)間
8 月 11 日 - 13 日,每晚 19:00 - 20:00
隨著 ToB (企業(yè)服務(wù))的興起和 ToC (消費(fèi)互聯(lián)網(wǎng))產(chǎn)品進(jìn)入成熟期,線上故障帶來(lái)的損失越來(lái)越大,代碼質(zhì)量越來(lái)越重要,而「質(zhì)量?jī)?nèi)建」正是 DevOps 核心理念之一?!?CODING DevOps 代碼質(zhì)量實(shí)戰(zhàn)系列直播課》將詳細(xì)講解提高代碼質(zhì)量的最佳實(shí)踐,不只適合新項(xiàng)目,也為老項(xiàng)目提供完善的漸進(jìn)式方案。
課程安排
《 DevOps 代碼質(zhì)量實(shí)戰(zhàn):代碼規(guī)范與 Git Flow 》
《 DevOps 代碼質(zhì)量實(shí)戰(zhàn)( PHP 版)》
《 DevOps 代碼質(zhì)量實(shí)戰(zhàn)( Java 版)》
講師
楊周 - CODING 布道師、CODING DevOps 架構(gòu)師
掃描海報(bào)二維碼
回復(fù) [ 1 ] 立即報(bào)名
8 月直播課 第二系列
CODING DevOps 微服務(wù)項(xiàng)目實(shí)戰(zhàn)系列直播課
開(kāi)課時(shí)間
8 月 18 日 - 20 日,每晚 19:00 - 20:00
近年來(lái),工程項(xiàng)目的結(jié)構(gòu)越來(lái)越復(fù)雜,需要接入合適的持續(xù)集成流水線形式,才能滿足更多變的需求,《 CODING DevOps 微服務(wù)項(xiàng)目實(shí)戰(zhàn)系列直播課》將與大家一同探討為什么現(xiàn)代開(kāi)發(fā)活動(dòng)需要 DevOps,并通過(guò)示例介紹持續(xù)集成流水線的進(jìn)階能力、結(jié)合 Demo 深入講解如何在 Kubernetes 集群進(jìn)行灰度發(fā)布,幫助大家解放重復(fù)性勞動(dòng),更優(yōu)雅地提升生產(chǎn)效率,更快交付成果。
課程安排
《 DevOps 微服務(wù)項(xiàng)目實(shí)戰(zhàn):DevOps 初體驗(yàn)》
《 DevOps 微服務(wù)項(xiàng)目實(shí)戰(zhàn):CI 進(jìn)階用法》
《 DevOps 實(shí)戰(zhàn):基于 Nginx-ingress 的自動(dòng)化灰度發(fā)布》
講師
王寬 - CODING DevOps 開(kāi)發(fā)工程師
何晨哲 - CODING DevOps 全棧工程師
王煒 - CODING DevOps 后端開(kāi)發(fā)工程師
掃描海報(bào)二維碼
回復(fù) [ 2 ] 立即報(bào)名
福利環(huán)節(jié)
成功 報(bào)名課程 ,并轉(zhuǎn)發(fā)本文或活動(dòng)海報(bào)至 朋友圈
集贊滿 30 贈(zèng)送 CODING 洋蔥猴 小抱枕一只
集贊滿 50 贈(zèng)送 CODING 洋蔥猴 大抱枕一只
掃描海報(bào)二維碼
添加 [ CODING 服務(wù)小助手] 并發(fā)送截圖
您的洋蔥猴抱枕正翹首以待~
我目前是 github+coding+自建的 Gitea,github 主要用來(lái)分享、展示一些代碼(同性交友?),大部分倉(cāng)庫(kù)在這三個(gè)平臺(tái)都同步更新。三家都挺穩(wěn)定的。GitHub 很穩(wěn)定的一直被 ban ; Coding 還沒(méi)遇見(jiàn)過(guò)不穩(wěn)定的情況;自建的 Gitea 也還可以,具體看服務(wù)器吧。 以前掛了幾個(gè)靜態(tài)頁(yè)面在 GitHub,前段時(shí)間在 Coding 也搞了一下,試用幾天后覺(jué)得還不錯(cuò),就把網(wǎng)址解析改到 Coding pages 了。目前沒(méi)出現(xiàn)訪問(wèn)不穩(wěn)定的問(wèn)題。 Github Action 和 Coding 的 持續(xù)集成都在用,免費(fèi)的額度都不少,Github Action 就不說(shuō)了,Coding 的 持續(xù)集成是基于 Jenkins 的,挺好用的。 比較私密的東西都在自建的 Gitea 。 或許有人會(huì)說(shuō)為啥不用 Gitee,我個(gè)人覺(jué)得 Gitee 的界面實(shí)在是不合我胃口。我現(xiàn)在只在需要下 github 上的一些資源,但網(wǎng)絡(luò)不太方便時(shí)才會(huì)用到 Gitee(登錄碼云克隆要用到的 github 倉(cāng)庫(kù),然后下載之,emmm,有點(diǎn)像反代??);碼云的訪問(wèn)在國(guó)內(nèi)是最快的,官方還有一個(gè)項(xiàng)目叫碼云極速下載,里面鏡像了很多 GitHub 知名項(xiàng)目,并且一直在更新;還有對(duì)于免費(fèi)用戶受限的 Pages 服務(wù)。其他的細(xì)節(jié)就不甚了解了。 有很多老用戶說(shuō)以前的東西丟了,大概率是沒(méi)找到,我自己在以前的 coding 上也上傳了一點(diǎn)東西,并沒(méi)丟(可能是因?yàn)槲乙恢睕](méi)換手機(jī)號(hào)),他們給我都遷移到團(tuán)隊(duì)版了,現(xiàn)在只有團(tuán)隊(duì)版了,5 人以下團(tuán)隊(duì)永久免費(fèi)用所有服務(wù)(對(duì)于我這種個(gè)人用戶是絕對(duì)夠用了) 因?yàn)楝F(xiàn)在 Coding 也是我主要用的平臺(tái)了,當(dāng)然希望 Coding 越來(lái)越好啦,現(xiàn)在的體驗(yàn)挺好的,而且背靠騰訊云這個(gè)大樹(shù)應(yīng)該不會(huì)輕易垮掉吧??。就我接觸過(guò)的來(lái)講,騰訊云 /coding 這一套比華為云的 devcloud 好用,且好看??。 以上觀點(diǎn)來(lái)自一個(gè)沒(méi)怎么接觸實(shí)際業(yè)務(wù)的學(xué)生 我看到有 V 友說(shuō)了有個(gè)叫 teambition 的似乎也不錯(cuò),回頭試試去(他家網(wǎng)站 ico 好像湯不熱啊??) -------------------------------- teambition 差評(píng),注冊(cè)賬號(hào)必須手機(jī)驗(yàn)證碼,然鵝我等了半天,試了兩次都沒(méi)收到驗(yàn)證碼,不整了,滾回去學(xué)習(xí)了
作者:王煒,CODING DevOps 后端開(kāi)發(fā)工程師,擁有多年研發(fā)經(jīng)驗(yàn),云原生、DevOps 、Kubernetes 資深愛(ài)好者,Servicemesher 服務(wù)網(wǎng)格中文社區(qū)成員。獲得 Kubernetes CKA 、CKAD 認(rèn)證。
前言
在 Kubernetes 上的應(yīng)用實(shí)現(xiàn)灰度發(fā)布,最簡(jiǎn)單的方案是引入官方的 Nginx-ingress 來(lái)實(shí)現(xiàn)。
我們通過(guò)部署兩套 deployment 和 services,分別代表灰度環(huán)境和生產(chǎn)環(huán)境,通過(guò)負(fù)載均衡算法,實(shí)現(xiàn)對(duì)兩套環(huán)境的按照灰度比例進(jìn)行分流,進(jìn)而實(shí)現(xiàn)灰度發(fā)布。
通常的做法是當(dāng)項(xiàng)目打包新鏡像后,通過(guò)修改 yaml 文件的鏡像版本,執(zhí)行 kubectl apply 的方式來(lái)更新服務(wù)。如果發(fā)布流程還需要進(jìn)行灰度發(fā)布,那么可以通過(guò)調(diào)整兩套服務(wù)的配置文件權(quán)重來(lái)控制灰度發(fā)布,這種方式離不開(kāi)人工執(zhí)行。如果項(xiàng)目數(shù)量多,灰度的時(shí)間跨度過(guò)長(zhǎng),人為誤操作的概率將大大增加,過(guò)于依賴于人工執(zhí)行,這對(duì)于 DevOps 工程實(shí)踐是不能忍受的。
那么,有沒(méi)有一種方式能夠?qū)崿F(xiàn)無(wú)需人工干預(yù)的自動(dòng)化灰度呢?例如在代碼更新后,自動(dòng)發(fā)布到預(yù)發(fā)布和灰度環(huán)境,并在一天的時(shí)間內(nèi)自動(dòng)將灰度比例從 10% 權(quán)重提高到 100%,且能夠隨時(shí)終止,灰度通過(guò)后自動(dòng)發(fā)布到生產(chǎn)環(huán)境?
答案是肯定的,利用 CODING DevOps 就能夠滿足此類需求。
Nginx-ingress 架構(gòu)和原理
迅速回顧一下 Nginx-ingress 的架構(gòu)和實(shí)現(xiàn)原理:
Nginx-ingress 通過(guò)前置的 Loadbalancer 類型的 Service 接收集群流量,將流量轉(zhuǎn)發(fā)至 Nginx-ingress Pod 內(nèi)并對(duì)配置的策略進(jìn)行檢查,再轉(zhuǎn)發(fā)至目標(biāo) Service ,最終將流量轉(zhuǎn)發(fā)至業(yè)務(wù)容器。
傳統(tǒng)的 Nginx 需要我們配置 conf 文件策略。但 Nginx-ingress 通過(guò)實(shí)現(xiàn) Nginx-ingress-Controller 將原生 conf 配置文件和 yaml 配置文件進(jìn)行了轉(zhuǎn)化,當(dāng)我們配置 yaml 文件的策略后, Nginx-ingress-Controller 將對(duì)其進(jìn)行轉(zhuǎn)化,并且動(dòng)態(tài)更新策略,動(dòng)態(tài) Reload Nginx Pod ,實(shí)現(xiàn)自動(dòng)管理。
那么 Nginx-ingress-Controller 如何能夠動(dòng)態(tài)感知集群的策略變化呢?方法有很多種,可以通過(guò) webhook admission 攔截器,也可以通過(guò) ServiceAccount 與 Kubernetes Api 進(jìn)行交互,動(dòng)態(tài)獲取。 Nginx-ingress-Controller 使用后者來(lái)實(shí)現(xiàn)。所以在部署 Nginx-ingress 我們會(huì)發(fā)現(xiàn) Deployment 內(nèi)指定了 Pod 的 ServiceAccount,以及實(shí)現(xiàn)了 RoleBinding,最終達(dá)到 Pod 能夠與 Kubernetes Api 交互的目的。
實(shí)現(xiàn)方案預(yù)覽
為了實(shí)現(xiàn)以上目標(biāo),我們?cè)O(shè)計(jì)了以下持續(xù)部署流水線。
此持續(xù)部署流水線主要實(shí)現(xiàn)了以下幾個(gè)步驟: 自動(dòng)部署到預(yù)發(fā)布環(huán)境 是否進(jìn)行 A/B 測(cè)試 自動(dòng)灰度發(fā)布(自動(dòng)進(jìn)行 3 次逐漸提升灰度比例) 發(fā)布到生產(chǎn)環(huán)境
同時(shí),本文案例還演示了從 Git 提交代碼到自動(dòng)觸發(fā)持續(xù)集成的步驟: 提交代碼后觸發(fā)持續(xù)集成,自動(dòng)構(gòu)建鏡像 鏡像構(gòu)建完成后,自動(dòng)推送鏡像到制品庫(kù) 觸發(fā)持續(xù)部署
1 、提交代碼后觸發(fā)持續(xù)集成,自動(dòng)構(gòu)建鏡像并推送到制品庫(kù)
2 、觸發(fā)持續(xù)部署,并發(fā)布到預(yù)發(fā)布環(huán)境
3 、人工確認(rèn):進(jìn)行 A/B 測(cè)試(或跳過(guò)直接進(jìn)入自動(dòng)灰度)
進(jìn)行 A/B 測(cè)試時(shí),只有 Header 包含 location=shenzhen 可以訪問(wèn)新版本,其他用戶訪問(wèn)生產(chǎn)環(huán)境仍然為舊版本。
4 、人工確認(rèn):是否自動(dòng)灰度發(fā)布(自動(dòng)進(jìn)行 3 輪逐漸提升灰度比例,每輪間隔 30s )
第一次灰度:新版本 30% 的灰度比例,此時(shí)訪問(wèn)生產(chǎn)環(huán)境大約有 30% 的流量進(jìn)入新版本灰度環(huán)境:
30s 后自動(dòng)進(jìn)行第二輪灰度:新版本 60% 的灰度比例:
60s 后自動(dòng)進(jìn)行第三輪灰度:新版本 90% 的灰度比例:
本案例中,我們配置了自動(dòng)化灰度發(fā)布將會(huì)以 3 次漸進(jìn)式進(jìn)行,每次提高 30% 的比例,每次持續(xù) 30s 后自動(dòng)進(jìn)入下一個(gè)灰度階段。在不同的灰度階段,會(huì)發(fā)現(xiàn)請(qǐng)求新版本出現(xiàn)的概率越來(lái)越高。漸進(jìn)式的灰度可根據(jù)業(yè)務(wù)需要進(jìn)行任意配置,例如持續(xù) 1 天時(shí)間分 10 次自動(dòng)進(jìn)行灰度,直至發(fā)布到生產(chǎn)環(huán)境而無(wú)需人工值守。
5 、灰度完成,30s 后發(fā)布到生產(chǎn)環(huán)境
項(xiàng)目源碼和原理分析
項(xiàng)目源碼地址: https://wangweicoding.coding.net/public/nginx-ingress-gray/nginx-ingress-gray/git ├── Jenkinsfile # 持續(xù)集成腳本 ├── deployment │ ├── canary │ │ └── deploy.yaml # 灰度發(fā)布部署文件 │ ├── dev │ │ └── deploy.yaml # 預(yù)發(fā)布部署文件 │ └── pro │ └── deploy.yaml # 生產(chǎn)部署文件 ├── docker │ ├── Dockerfile │ └── html │ └── index.html ├── nginx-ingress-init │ ├── nginx-ingress-deployment # nginx-ingress 部署文件 │ │ ├── ClusterRoleBinding.yaml │ │ ├── RoleBinding.yaml │ │ ├── clusterRole.yaml │ │ ├── defaultBackendService.yaml │ │ ├── defaultBackendServiceaccount.yaml │ │ ├── deployment.yaml │ │ ├── nginxDefaultBackendDeploy.yaml │ │ ├── roles.yaml │ │ ├── service.yaml │ │ └── serviceAccount.yaml │ └── nginx-ingress-helm # nginx-ingress Helm 包 │ └── nginx-ingress-1.36.3.tgz └── pipeline # 持續(xù)部署流水線模板 ├── gray-deploy.json # 灰度發(fā)布流水線 ├── gray-init.json # 灰度發(fā)布初始化(首次運(yùn)行) └── nginx-ingress-init.json # nginx-ingress 初始化(首次運(yùn)行)
灰度環(huán)境和生產(chǎn)環(huán)境主要由 deployment/canary/deploy.yaml 和 deployment/pro/deploy.yaml 來(lái)實(shí)現(xiàn),主要是實(shí)現(xiàn)了兩套環(huán)境的: Deployment Service Ingress
A/B 測(cè)試和灰度由配置的 Ingress 進(jìn)行控制: apiVersion: extensions/v1beta1 kind: Ingress metadata: annotations: kubernetes.io/ingress.class: nginx # nginx=nginx-ingress| qcloud=CLB ingress nginx.ingress.kubernetes.io/canary: "true" # 開(kāi)啟灰度 nginx.ingress.kubernetes.io/canary-by-header: "location" # A/B 測(cè)試用例 Header key nginx.ingress.kubernetes.io/canary-by-header-value: "shenzhen" # A/B 測(cè)試用例 Header value name: my-ingress namespace: pro spec: rules: - host: nginx-ingress.coding.pro http: paths: - backend: serviceName: nginx-canary servicePort: 80 path: /
A/B 測(cè)試主要由注解 nginx.ingress.kubernetes.io/canary-by-header 和 nginx.ingress.kubernetes.io/canary-by-header-value 進(jìn)行控制,來(lái)匹配請(qǐng)求 Header 的 Key 和 Value 。 apiVersion: extensions/v1beta1 kind: Ingress metadata: annotations: kubernetes.io/ingress.class: nginx # nginx=nginx-ingress| qcloud=CLB ingress nginx.ingress.kubernetes.io/canary: "true" nginx.ingress.kubernetes.io/canary-weight: 30 name: my-ingress namespace: pro spec: rules: - host: nginx-ingress.coding.pro http: paths: - backend: serviceName: nginx-canary servicePort: 80 path: /
而灰度則由注解 nginx.ingress.kubernetes.io/canary-weight 控制,值范圍可以是 0-100 ,對(duì)應(yīng)灰度權(quán)重比例。在 Nginx-ingress ,負(fù)載均衡算法主要由 加權(quán)輪詢 的算法來(lái)實(shí)現(xiàn)分流。
整體架構(gòu)圖如所示:
環(huán)境準(zhǔn)備 K8S 集群,推薦使用騰訊云 容器服務(wù) ; 開(kāi)通 CODING DevOps ,提供鏡像構(gòu)建和流水線的部署能力。
實(shí)踐步驟
1 、克隆源碼并推送至自己的 CODING Git 倉(cāng)庫(kù) ``` $ git clone https://e.coding.net/wangweicoding/nginx-ingress-gray/nginx-ingress-gray.git $ git remote set-url origin https://you coding git $ git add . $ git commit -a -m 'first commit' $ git push -u origin master ```
注意,推送前請(qǐng)將 deployment/dev 、 deployment/canary 、 deployment/pro 文件夾的 deploy.yaml image 修改為自己的制品庫(kù)鏡像地址。
2 、創(chuàng)建持續(xù)集成流水線
使用“自定義構(gòu)建過(guò)程”創(chuàng)建構(gòu)建計(jì)劃,并選擇使用代碼倉(cāng)庫(kù)的 Jenkinsfile
3 、新增云賬號(hào)并創(chuàng)建持續(xù)部署流水線,復(fù)制項(xiàng)目的 pipeline Json 模板到創(chuàng)建的流水線內(nèi)( 3 個(gè))
為了便于使用模板,創(chuàng)建持續(xù)部署流水線應(yīng)用名為:nginx-ingress
創(chuàng)建繼續(xù)創(chuàng)建空白部署流程,復(fù)制 Json 模板到持續(xù)部署流水線中,一共創(chuàng)建三條流水線: nginx-ingress-init - 用于初始化 nginx-ingress gray-init - 用于首次初始化環(huán)境 gray-deploy - 用于演示灰度發(fā)布 注意:請(qǐng)將以上流水線的云賬號(hào)選擇為自己的云賬號(hào),另外 gray-deploy 流水線中,請(qǐng)重新配置“啟動(dòng)所需制品”和“觸發(fā)器”。
4 、初始化 nginx-ingress (首次運(yùn)行)
首次運(yùn)行 nginx-ingress 流水線將自動(dòng)為您部署 nginx-ingress 。部署成功后,運(yùn)行 kubectl get svc | grep nginx-ingress-controller 獲取 Ningx-ingress 的 EXTERNAL-IP ,此 IP 為集群請(qǐng)求入口 IP 。并為本機(jī)配置 Host ,便于訪問(wèn)。
5 、初始化灰度發(fā)布(首次運(yùn)行)
首次運(yùn)行 gray-init 流水線將自動(dòng)部署一套完整的環(huán)境,否則自動(dòng)化灰度流水線將會(huì)失敗。
6 、自動(dòng)觸發(fā)灰度發(fā)布
現(xiàn)在,您可以嘗試修改項(xiàng)目 docker/html/index.html 文件,推送后將自動(dòng)觸發(fā)構(gòu)建和持續(xù)部署,觸發(fā)后,進(jìn)入“持續(xù)部署”頁(yè)面,查看部署詳情和流程。
總結(jié)
我們主要利用了 CODING 持續(xù)部署 的 等待 階段,通過(guò)對(duì)不同灰度比例的階段設(shè)定等待時(shí)間,自動(dòng)化逐一運(yùn)行灰度階段,最終實(shí)現(xiàn)無(wú)人工值守的自動(dòng)化灰度發(fā)布。
利用 等待 階段,可以實(shí)現(xiàn)平滑的發(fā)布流程,只有當(dāng)發(fā)布出現(xiàn)問(wèn)題,才需要人工介入。配合持續(xù)部署通知功能,可以很方便的將當(dāng)前發(fā)布狀態(tài)推送到企業(yè)微信、釘釘?shù)葏f(xié)作工具。
為了方便展示,案例中對(duì)灰度比例和等待時(shí)間進(jìn)行了硬編碼,你也可以使用階段的“自定義參數(shù)”來(lái)實(shí)現(xiàn)對(duì)灰度比例和等待實(shí)現(xiàn)進(jìn)行動(dòng)態(tài)控制,針對(duì)當(dāng)前的發(fā)布等級(jí)動(dòng)態(tài)輸入灰度比例和流程控制,使得發(fā)布更加靈活。
生產(chǎn)建議
本文的 Nginx-ingress 采用 deployment 的部署方式來(lái)實(shí)現(xiàn)。 Nginx-ingress 作為 Kubernetes 集群的邊緣網(wǎng)關(guān),承擔(dān)著所有入口流量,其高可用性直接決定了 Kubernetes 集群的高可用性。
在生產(chǎn)環(huán)境,部署 Nginx-ingress 建議遵循以下幾點(diǎn): 推薦使用 DaemonSet 的方式部署,避免節(jié)點(diǎn)故障。 通過(guò)標(biāo)簽選擇器,將 Nginx-ingress-controller 部署在獨(dú)立的 Node 節(jié)點(diǎn)(如高主頻、高網(wǎng)絡(luò)、高 IO 節(jié)點(diǎn))或者低負(fù)載的節(jié)點(diǎn)。 如果采用 Deployment 的方式部署,可以為 Nginx-ingress 配置 HPA 水平伸縮。
服務(wù)不停歇,運(yùn)維不休息。運(yùn)維的工作長(zhǎng)達(dá) 7x24 小時(shí),故而每年的 7 月 24 日被視為運(yùn)維日,代表著運(yùn)維全天候的保障系統(tǒng)穩(wěn)定,維護(hù)業(yè)務(wù)正常運(yùn)行,時(shí)刻準(zhǔn)備著一線工作的召喚。
騰訊運(yùn)維技術(shù)開(kāi)放日 是由騰訊云,TEG 技術(shù)工程事業(yè)群,及 CODING DevOps 共同發(fā)起的,面向運(yùn)維人員的技術(shù)開(kāi)放日。旨在分享和交流騰訊內(nèi)部在運(yùn)維方面的實(shí)踐經(jīng)驗(yàn),打造騰訊內(nèi)部與外部共同交流、共同進(jìn)步的運(yùn)維技術(shù)生態(tài)圈。
第二屆騰訊運(yùn)維技術(shù)開(kāi)放日,將邀請(qǐng) 包括 CODING 高級(jí)技術(shù)專家周紀(jì)海在內(nèi)的四位騰訊內(nèi)部講師 ,分享騰訊在微服務(wù)致力、集群管理、DevOps 、持續(xù)部署等領(lǐng)域的實(shí)踐經(jīng)驗(yàn)和獨(dú)到見(jiàn)解,與現(xiàn)場(chǎng)參與者共同探討運(yùn)維進(jìn)階之路。
活動(dòng)時(shí)間
2020 年 7 月 23 日 19:30
講師陣容
↑ 掃描上方二維碼 ↑
第二屆騰訊運(yùn)維技術(shù)開(kāi)放日等你來(lái)!
在敏捷研發(fā)的過(guò)程中,或者項(xiàng)目結(jié)束后的復(fù)盤階段,度量并分析團(tuán)隊(duì)成員在周期內(nèi)的工作負(fù)荷、完成的工作量與工作動(dòng)態(tài),能夠讓管理者清晰的認(rèn)識(shí)到團(tuán)隊(duì)成員的工作負(fù)載與工作效率;團(tuán)隊(duì)成員間也可以相互查看對(duì)方所參與的項(xiàng)目,近期工作動(dòng)態(tài)或近期事項(xiàng)。
效能度量的主要功能為統(tǒng)計(jì)團(tuán)隊(duì)成員在一段時(shí)間內(nèi)的計(jì)劃事項(xiàng)數(shù)、完成事項(xiàng)數(shù)和所編輯的 Wiki 數(shù)以供分析。這些數(shù)據(jù)將會(huì)在趨勢(shì)面板上進(jìn)行顯示。并且還可以自行設(shè)置分組并添加其它成員,方便快速查看團(tuán)隊(duì)成員近期工作概覽。
使用準(zhǔn)備
團(tuán)隊(duì)擁有者或管理員在 [團(tuán)隊(duì)管理] -> [權(quán)限配置] 中為相應(yīng)的用戶組的勾選「效能度量」的「查看頁(yè)面」權(quán)限。勾選完成后處于該用戶組的成員的工作臺(tái)會(huì)出現(xiàn)效能度量的功能入口。
趨勢(shì)面板
面板將會(huì)反映所添加成員的工作量趨勢(shì)圖,以三個(gè)數(shù)據(jù)維度進(jìn)行展示:計(jì)劃事項(xiàng)數(shù)、完成事項(xiàng)數(shù)和 Wiki 編輯數(shù)??梢赃x擇日、周、月三種統(tǒng)計(jì)周期視圖進(jìn)行查看,通過(guò)下方的滾輪橫軸進(jìn)行左右拖拉日期。
計(jì)劃事項(xiàng)數(shù)
將會(huì)統(tǒng)計(jì)處理人在一個(gè)時(shí)間周期內(nèi)開(kāi)始和截止時(shí)間所安排的事項(xiàng)總數(shù),納入統(tǒng)計(jì)的事項(xiàng)包含史詩(shī)、需求、任務(wù)、缺陷和子任務(wù)。 如果事項(xiàng)填寫(xiě)了開(kāi)始和結(jié)束時(shí)間,那么處在這個(gè)時(shí)間周期的每一天的事項(xiàng)數(shù) +1 ; 如果事項(xiàng)只填寫(xiě)了開(kāi)始時(shí)間,那么開(kāi)始時(shí)間所在當(dāng)天事項(xiàng)數(shù) +1 ; 如果事項(xiàng)只填寫(xiě)了截止時(shí)間,那么截止時(shí)間所在當(dāng)天事項(xiàng)數(shù) +1 。
具體的計(jì)數(shù)原理請(qǐng)參考 計(jì)劃事項(xiàng)數(shù)計(jì)數(shù)方式 。
完成事項(xiàng)數(shù)
將會(huì)統(tǒng)計(jì)處理人在固定周期內(nèi)完成的事項(xiàng)總數(shù)。這里的完成事項(xiàng)定義涵蓋史詩(shī)、需求、任務(wù)、缺陷和子任務(wù)。若對(duì)這些事項(xiàng)做出了完成操作,即狀態(tài)類型從“非已完成”到“已完成”,則視該事項(xiàng)被定義為完成。 如果在時(shí)間周期內(nèi)且周期結(jié)束后狀態(tài)類型仍然是“已完成”,那么完成事項(xiàng)數(shù) +1 。
具體的計(jì)數(shù)原理請(qǐng)參考 完成事項(xiàng)數(shù)計(jì)數(shù)方式 。
編輯 Wiki 數(shù)
將會(huì)統(tǒng)計(jì)團(tuán)隊(duì)成員更新過(guò)的 Wiki 篇數(shù)。若在同一個(gè)周期內(nèi)對(duì)同一篇文檔進(jìn)行修改并執(zhí)行了“提交文檔”,那么編輯 Wiki 數(shù)算為 1 篇。
添加成員與分組管理
在「添加成員」中可以通過(guò)成員姓名或搜索項(xiàng)目一鍵添加項(xiàng)目?jī)?nèi)成員,添加進(jìn)圖表的成員可移除。在「分組」下拉組件中可進(jìn)行添加分組、刪除和重命名等操作,添加的成員默認(rèn)進(jìn)入當(dāng)前選擇的分組中。分組為用戶自行設(shè)置,并不會(huì)在團(tuán)隊(duì)內(nèi)公開(kāi)顯示該分組,屬于個(gè)性化查看功能。
成員工作概覽頁(yè)
在效能度量頁(yè)面中點(diǎn)擊任意成員,可進(jìn)入成員的工作概覽頁(yè)。頁(yè)面包含: 成員名稱和頭像; 最近活躍時(shí)間; 參與的項(xiàng)目; 近期事項(xiàng); 該成員近期的工作動(dòng)態(tài)。
近期事項(xiàng)
近期事項(xiàng)的統(tǒng)計(jì)內(nèi)容包含: 已完成,查詢近 1 個(gè)月完成的事項(xiàng),按照完成時(shí)間逆序排; 進(jìn)行中,查詢狀態(tài)類型為“進(jìn)行中”的事項(xiàng),按截止時(shí)間逆序排; 未開(kāi)始,查詢狀態(tài)類型為“未開(kāi)始”的事項(xiàng),按截止時(shí)間逆序排。
工作動(dòng)態(tài)
工作動(dòng)態(tài)為成員的日常協(xié)作動(dòng)態(tài),可按分類查詢,包含: 項(xiàng)目協(xié)同 代碼倉(cāng)庫(kù) 持續(xù)集成 持續(xù)部署 Wiki 文件網(wǎng)盤 ...
權(quán)限控制
該功能涉及到的權(quán)限模塊名稱為效能度量,具有“查看”權(quán)限。每個(gè)團(tuán)隊(duì)的擁有者和項(xiàng)目管理員將默認(rèn)勾選「查看功能」權(quán)限點(diǎn)。
計(jì)數(shù)方式詳情
計(jì)劃事項(xiàng)數(shù)計(jì)數(shù)方式 如果事項(xiàng)填寫(xiě)了開(kāi)始和結(jié)束時(shí)間,那么處在這個(gè)時(shí)間段里的每一天的事項(xiàng)數(shù) +1 ; 如果事項(xiàng)只填寫(xiě)了開(kāi)始時(shí)間,那么開(kāi)始時(shí)間所在當(dāng)天事項(xiàng)數(shù) +1 ; 如果事項(xiàng)只填寫(xiě)了截止時(shí)間,那么截止時(shí)間所在當(dāng)天事項(xiàng)數(shù) +1 。
例如表 1:
依據(jù)表 1 的數(shù)據(jù),該成員的計(jì)劃事項(xiàng)統(tǒng)計(jì)結(jié)果如下:
若同一個(gè)事項(xiàng)的時(shí)間跨越了 2 個(gè)周期,那么將在兩個(gè)周期中分別計(jì)數(shù) +1 。例如事項(xiàng) A 在的開(kāi)始和截止時(shí)間為 2020 年 1 月 25 日 —— 2020 年 2 月 4 日,那么事項(xiàng) A 在 1 月和 2 月都被計(jì)算為 1 個(gè)事項(xiàng)。
完成事項(xiàng)數(shù)計(jì)數(shù)方式
事項(xiàng)在一個(gè)周期內(nèi)被做了 1 次完成動(dòng)作,且周期結(jié)束后狀態(tài)類型為“已完成”,則完成事項(xiàng)數(shù) +1 。
事項(xiàng)反復(fù)打開(kāi)和完成的計(jì)算方式 事項(xiàng)在一個(gè)周期內(nèi)被完成過(guò),但周期結(jié)束前狀態(tài)類型為“已完成”,則完成事項(xiàng)數(shù) +1 ; 事項(xiàng)在一個(gè)周期內(nèi)被完成過(guò),但周期結(jié)束前狀態(tài)類型為非“已完成”,則不貢獻(xiàn)完成事項(xiàng)數(shù); 事項(xiàng)在第一個(gè)周期內(nèi)被完成,直到第二個(gè)周期才被打開(kāi),且第二個(gè)周期結(jié)束前狀態(tài)類型為“已完成”,則這兩個(gè)周期內(nèi)完成事項(xiàng)數(shù)分別 +1 。
例如表 2,為事項(xiàng) A 在 1-4 月的狀態(tài)情況:
那么事項(xiàng) A 在 1-4 月被計(jì)算的完成事項(xiàng)數(shù)分別為:1,0,1,0 。 關(guān)于 CODING,了解更多
背景
如何做團(tuán)隊(duì)技術(shù)文章分享和沉淀?這是一個(gè)老生常談的話題。常見(jiàn)的技術(shù)選型可以是 Confluence 、Dokuwiki 、Gitbook 等。
但對(duì)于敏捷團(tuán)隊(duì)來(lái)說(shuō),這些都不夠優(yōu)雅,我們希望能把技術(shù)文章像代碼一樣進(jìn)行協(xié)作和版本管理。更新技術(shù)文章后,能夠自動(dòng)部署到公司的 K8S 集群。那么,CODING DevOps + Hexo 一定是你的不二之選,這也是 CODING 目前的實(shí)踐。
Hexo 是一個(gè)快速、簡(jiǎn)潔且高效的博客框架。我們只需要書(shū)寫(xiě) Markdown 格式的技術(shù)文章,通過(guò)命令能夠直接生成靜態(tài)頁(yè)面,方便瀏覽和部署。
本文將介紹如何使用 CODING DevOps 建立流水線,推送技術(shù)文章到 Git 倉(cāng)庫(kù)后,自動(dòng)觸發(fā)流水線執(zhí)行構(gòu)建并部署到 K8S 集群。
準(zhǔn)備 K8S 集群,推薦使用騰訊 TKE 開(kāi)通 CODING DevOps 克隆代碼倉(cāng)庫(kù): https://wangweicoding.coding.net/public/blog/blog/git
實(shí)現(xiàn)效果 提交新文章,自動(dòng)觸發(fā)構(gòu)建流程 生成靜態(tài)頁(yè)面,構(gòu)建 Docker 鏡像 鏡像構(gòu)建成功,自動(dòng)觸發(fā)部署流程 部署成功,新文章發(fā)布
實(shí)踐步驟
1. 克隆代碼并推送到自己的 CODING Git 倉(cāng)庫(kù) git clone https://e.coding.net/wangweicoding/blog.git git remote set-url origin [CODING Git Url] git push
2. 開(kāi)通 CODING 制品庫(kù)
開(kāi)通 Docker 類型的制品庫(kù),并記錄倉(cāng)庫(kù)地址和制品庫(kù)名稱,將在下一個(gè)階段用到。
3. 開(kāi)通 CODING 持續(xù)集成,并配置構(gòu)建任務(wù)
選擇“自定義構(gòu)建過(guò)程”,并配置來(lái)源使用代碼倉(cāng)庫(kù)的 Jenkinsfile
項(xiàng)目?jī)?nèi)的 Jenkinsfile 主要是用來(lái)生成靜態(tài)頁(yè)面,以及構(gòu)建鏡像并推送鏡像到制品庫(kù)。 pipeline { agent any stages { stage('檢出') { steps { checkout([ $class: 'GitSCM', branches: [[name: env.GIT_BUILD_REF]], userRemoteConfigs: [[url: env.GIT_REPO_URL, credentialsId: env.CREDENTIALS_ID]] ]) } } stage('生成靜態(tài)頁(yè)面') { steps { script { sh 'npm install -g hexo-cli' # 安裝 Hexo sh 'npm install' # 安裝依賴 sh 'hexo g' # 生成靜態(tài)頁(yè)面 } } } stage('構(gòu)建') { steps { echo '構(gòu)建中...' script { // 此處請(qǐng)修改 dockerServer 、dockerPath 、imageName 替換為自己項(xiàng)目的值 dockerServer = 'wangweicoding-docker.pkg.coding.net' dockerPath = '/blog/blog' imageName = "${dockerServer}${dockerPath}/blog:${env.GIT_BUILD_REF}" def customImage = docker.build(imageName) // 推送 Docker 鏡像到倉(cāng)庫(kù) docker.withRegistry("https://${dockerServer}", CODING_ARTIFACTS_CREDENTIALS_ID) { customImage.push() } } } } } }
注意:請(qǐng)將 Jenkinsfile 內(nèi)變量 dockerServer 、dockerPath 、imageName 修改為自己的制品庫(kù)地址、制品庫(kù)名 、制品名。
4. 開(kāi)通 CODING 持續(xù)部署,并配置 K8S 云賬號(hào)
進(jìn)入“團(tuán)隊(duì)管理” -> "部署設(shè)置",配置 Kubernetes 云賬號(hào)( Kubeconfig 或 Service Account ),以便 CODING 持續(xù)部署部署應(yīng)用到目標(biāo)集群。
如果你是騰訊云用戶,可以按照操作提示一鍵綁定 TKE 集群。
5. 為持續(xù)部署配置應(yīng)用和部署流程
進(jìn)入持續(xù)部署控制臺(tái),點(diǎn)擊“創(chuàng)建應(yīng)用”,為了方便直接使用本文的部署模板,應(yīng)用名請(qǐng)輸入 blog ,并勾選 支持 Kubernetes 部署 。
應(yīng)用創(chuàng)建后,接下來(lái)創(chuàng)建部署流程:
復(fù)制代碼倉(cāng)庫(kù)的 pipeline.json 的內(nèi)容,黏貼至部署流程的“編輯 JSON”框內(nèi)。 注意:界面中的“啟動(dòng)所需制品”和“觸發(fā)器”需要重新選擇自己的項(xiàng)目和倉(cāng)庫(kù),并在部署 deployment 和 services 階段,重新選擇自己剛才創(chuàng)建的云賬號(hào)。
編輯完成后,點(diǎn)擊保存即可。
我們創(chuàng)建的持續(xù)部署流水線主要定義這幾項(xiàng)配置: 配置了 3 個(gè)“啟動(dòng)所需制品”,并配置了默認(rèn)版本。分別是: services.yaml,Kubernetes Services 部署文件,提供外網(wǎng)訪問(wèn)的 LoadBalancer 。 deploy.yaml,Kubernetes Deployment 部署文件,用于更新鏡像版本。 docker 鏡像,需要自動(dòng)更新的鏡像版本。 配置了 CODING Docker 倉(cāng)庫(kù) “自動(dòng)觸發(fā)器”,當(dāng)鏡像構(gòu)建完成并推送到鏡像倉(cāng)庫(kù)時(shí),自動(dòng)觸發(fā)部署流程。 部署 services.yaml 和 deploy.yaml 。
當(dāng)鏡像更新,觸發(fā)器自動(dòng)觸發(fā),持續(xù)部署能夠直接獲取到本次構(gòu)建的版本號(hào),通過(guò)對(duì) deployment 鏡像版本的自動(dòng)綁定,實(shí)現(xiàn)自動(dòng)部署新的鏡像。
deploy.yaml apiVersion: apps/v1 kind: Deployment metadata: name: blog namespace: blog labels: app: blog spec: replicas: 2 selector: matchLabels: app: blog template: metadata: labels: app: blog spec: containers: - name: blog image: wangweicoding-docker.pkg.coding.net/blog/blog/blog # 此處的鏡像版本將被自動(dòng)替換為本次構(gòu)建的版本。 ports: - containerPort: 80 imagePullSecrets: - name: dockersecret # 集群憑據(jù),需要手動(dòng)創(chuàng)建
Deployment 中的 image: wangweicoding-docker.pkg.coding.net/blog/blog/blog ,image 會(huì)被 CODING 持續(xù)部署自動(dòng)替換為本次構(gòu)建的鏡像版本,實(shí)現(xiàn)自動(dòng)綁定 Docker 制品。所以這里只需要完整的制品 URL 即可,無(wú)需 TAG 版本號(hào)。 注意:請(qǐng)將 image 修改為自己的 Docker 鏡像地址。deployment 文件內(nèi)使用了 imagePullSecrets,配置部署前請(qǐng)使用以下方法提前創(chuàng)建。 kubectl create secret docker-registry myregcred \ --docker-server= \ --docker-username= \ --docker-password= \ -n namespace
service.yaml apiVersion: v1 kind: Service metadata: name: blog namespace: blog spec: selector: app: blog ports: - protocol: TCP port: 80 targetPort: 80 type: LoadBalancer # 提供 Hexo 外網(wǎng)訪問(wèn) IP
6. 發(fā)布文章
編輯項(xiàng)目 source/_posts/ 目錄下的文章,并推送到 CODING Git 倉(cāng)庫(kù),此時(shí)會(huì)自動(dòng)觸發(fā)構(gòu)建,構(gòu)建成功后,會(huì)自動(dòng)觸發(fā)博客發(fā)布的部署流程。
寫(xiě)在最后
我們使用 CODING DevOps 實(shí)現(xiàn)了將 Hexo 全自動(dòng)部署到 K8S 集群,能夠非常方便地對(duì)技術(shù)文章統(tǒng)一管理以及沉淀。不僅是 Hexo,其他任意構(gòu)建為 Docker 鏡像的前端和后端項(xiàng)目,都可以用本文的思想進(jìn)行配置,實(shí)現(xiàn)自動(dòng)觸發(fā),自動(dòng)部署到 K8S 集群。
結(jié)合持續(xù)部署的“人工確認(rèn)”階段,我們能夠很方便地實(shí)現(xiàn)發(fā)布的審批流,使得發(fā)布更加安全。另外,自動(dòng)觸發(fā)器不僅可以使用 CODING Docker 鏡像倉(cāng)庫(kù)觸發(fā),還能夠使用 Webhook 觸發(fā)。通過(guò) Webhook 調(diào)用流水線,可以非常方便地將 CODING 持續(xù)部署和內(nèi)部 CI 系統(tǒng)打通,滿足更多的使用場(chǎng)景。
當(dāng)然,CODING 持續(xù)部署可以實(shí)現(xiàn)更多的應(yīng)用場(chǎng)景,例如:灰度發(fā)布、藍(lán)綠 /金絲雀發(fā)布等,我們將在后續(xù)帶給大家更多的實(shí)踐內(nèi)容。 關(guān)于 CODING,了解更多。
2020 年秋招在即,許多預(yù)備程序員即將踏入工作崗位,但是苦于沒(méi)有應(yīng)聘求職的經(jīng)驗(yàn),十分害怕在秋招中踩坑。在眾多應(yīng)聘者中,青澀的你如何才能脫穎而出呢? 所以今天,CODING 給大家來(lái)送福利了——我們聯(lián)合猿圈學(xué)堂,為想要就業(yè) IT 崗位的小伙伴提供一次真實(shí)的企業(yè)秋招模擬筆試,模擬筆試是以比賽的形式進(jìn)行,我們?yōu)榇蠹覝?zhǔn)備了超多獎(jiǎng)品,表現(xiàn)優(yōu)異者還可以得到企業(yè)內(nèi)推資格!心動(dòng)的話就趕快行動(dòng)吧~
詳細(xì)信息和報(bào)名方式請(qǐng)看下方海報(bào)↓↓↓
CODING 中提供了內(nèi)置云主機(jī)用來(lái)執(zhí)行持續(xù)集成( CI )中的構(gòu)建計(jì)劃,能夠勝任大部分構(gòu)建任務(wù)。但如果碰上了大型項(xiàng)目的構(gòu)建,或者需要在本地服務(wù)器生成構(gòu)建成果,單個(gè)計(jì)算資源就顯得有點(diǎn)捉急了。針對(duì)這一部分需求,CODING 現(xiàn)已支持接入第三方計(jì)算資源作為構(gòu)建節(jié)點(diǎn),甚至可以接入多個(gè)服務(wù)器共同作為構(gòu)建節(jié)點(diǎn)池,打造專屬的計(jì)算集群。
下面將會(huì)以騰訊云 CVM 為例,演示如何在 CODING 持續(xù)集成中接入自己的計(jì)算資源。
開(kāi)通安全組
在購(gòu)買了 騰訊云 CVM 后,第一件要做的事情就是開(kāi)放相應(yīng)的 安全組策略 ,入站和出站規(guī)則都需要設(shè)置。
登錄服務(wù)器
在 [操作] 中點(diǎn)擊登錄,按照提示輸入 root 密碼。如果忘記密碼可以在 [更多] > [密碼 /密鑰] 中點(diǎn)擊 [重置密碼] 后再次輸入即可。
做完上述操作并成功登錄服務(wù)器后,可以選擇 Docker 或 cci-agent 兩種方式將服務(wù)器接入至構(gòu)建節(jié)點(diǎn)池。如果想使用與 CODING 官方提供的運(yùn)行節(jié)點(diǎn)一致的環(huán)境,請(qǐng)選擇使用 Docker 運(yùn)行構(gòu)建節(jié)點(diǎn)。如果想使用節(jié)點(diǎn)上自帶的環(huán)境,譬如需要使用 MacOS 上的 Xcode 編譯 iOS 應(yīng)用,請(qǐng)選擇 cci-agent 方式進(jìn)行接入。
接入構(gòu)建節(jié)點(diǎn)池
使用 Docker (推薦)
使用 Docker 的前提是服務(wù)器上已經(jīng)安裝了 Docker 。需要注意的是,部分 openVZ 虛擬化的服務(wù)器因內(nèi)核較低,無(wú)法成功安裝 Docker,當(dāng)然我們的騰訊云 CVM 是沒(méi)有這個(gè)問(wèn)題的。下面使用 curl 命令安裝 Docker 。 curl -fsSL https://get.docker.com/ | sh
待 Docker 安裝完成后,前往 CODING 進(jìn)入 [項(xiàng)目] > [持續(xù)集成] > [構(gòu)建節(jié)點(diǎn)] ,在構(gòu)建節(jié)點(diǎn)頁(yè)復(fù)制配置命令。
等待一小會(huì),等鏡像構(gòu)建完成后便會(huì)提示構(gòu)建成功。
在 CODING 構(gòu)建節(jié)點(diǎn)頁(yè)也可以看到新注冊(cè)上線的服務(wù)器。
手動(dòng)接入 cci-agent
在 CODING 的構(gòu)建節(jié)點(diǎn)頁(yè)一鍵生成初始化命令,并在服務(wù)器中運(yùn)行該命令。
執(zhí)行 cci-agent 啟動(dòng)命令。 ./cci-agent up -d
配置完成后會(huì)出現(xiàn)在節(jié)點(diǎn)池中。
在安裝過(guò)程中,節(jié)點(diǎn)狀態(tài)會(huì)不斷變化。關(guān)于節(jié)點(diǎn)的狀態(tài)說(shuō)明: 閑置:構(gòu)建節(jié)點(diǎn)此時(shí)空閑。 占用:構(gòu)建節(jié)點(diǎn)已被分配到構(gòu)建任務(wù)中使用。 準(zhǔn)備中:構(gòu)建節(jié)點(diǎn)正在準(zhǔn)備構(gòu)建環(huán)境。 開(kāi)啟:只有處于開(kāi)啟狀態(tài)的節(jié)點(diǎn)才能被分配使用,如果關(guān)閉節(jié)點(diǎn)不會(huì)影響正在運(yùn)行的構(gòu)建任務(wù)。 刪除:節(jié)點(diǎn)將會(huì)脫離 CODING 持續(xù)集成服務(wù),但只會(huì)刪除工作空間和相關(guān)的配置信息,之前產(chǎn)生的全局緩存文件仍會(huì)保留。
使用自定義節(jié)點(diǎn)
計(jì)算資源接入成功后,在 [構(gòu)建計(jì)劃] > [設(shè)置] 中選擇使用自定義節(jié)點(diǎn)。
保存修改后,觸發(fā)構(gòu)建任務(wù)后就可以在自己的計(jì)算資源集群中執(zhí)行持續(xù)集成任務(wù)了。使用自定義節(jié)點(diǎn)不會(huì)占用 CODING 團(tuán)隊(duì)配額,不受并行上限限制。并且服務(wù)器集群規(guī)模越大,構(gòu)建大型項(xiàng)目的速度也會(huì)越快。
點(diǎn)擊查看幫助文檔了解更多
云開(kāi)發(fā)中的云函數(shù)是云開(kāi)發(fā) Cloudbase 的一個(gè)重要的功能,開(kāi)發(fā)者可以借助其中的云函數(shù)來(lái)實(shí)現(xiàn)一些復(fù)雜的業(yè)務(wù)邏輯,來(lái)實(shí)現(xiàn)諸如圖片處理、數(shù)據(jù)處理等復(fù)雜的邏輯。同時(shí),云函數(shù)的免運(yùn)維、快速部署等特性也可以大大簡(jiǎn)化開(kāi)發(fā)者的工作量,讓開(kāi)發(fā)者把更多的精力投放在業(yè)務(wù)邏輯的開(kāi)發(fā)上。
在進(jìn)行云開(kāi)發(fā)中云函數(shù)的開(kāi)發(fā)時(shí),我們可能會(huì)經(jīng)常重復(fù)“編寫(xiě)函數(shù)代碼->部署”這個(gè)過(guò)程,這個(gè)過(guò)程繁瑣而又不得不做,有沒(méi)有一種方式可以讓機(jī)器幫我們 自動(dòng)部署函數(shù) ,減少我們做這些重復(fù)的工作,把更多的精力都投放在更有價(jià)值的事情上呢?我們可以借助 CODING CI,來(lái)實(shí)現(xiàn)云函數(shù)的自動(dòng)化部署,簡(jiǎn)化我們的工作量。
接下來(lái),我將介紹一下如何構(gòu)建一個(gè)流水線,實(shí)現(xiàn)自動(dòng)化部署云開(kāi)發(fā)中的云函數(shù)。
1. 工作流梳理
我們先梳理一下流水線的工作流。這是一個(gè)只有單一步驟的簡(jiǎn)單工作流。 在推送步驟中我們還是借助 TCB CLI 工具完成云開(kāi)發(fā)中云函數(shù)的部署。流程的結(jié)果我們可以通過(guò) WebHook 消息通知到企業(yè)微信。
2. 在 CODING 中創(chuàng)建 DevOps 項(xiàng)目
登錄 CODING 工作臺(tái),進(jìn)入全部項(xiàng)目模塊,新建一個(gè)項(xiàng)目。 選擇新建項(xiàng)目時(shí)的所用到的模板,這里選擇 DevOps 模板,進(jìn)入下一步。 填寫(xiě)項(xiàng)目名稱、項(xiàng)目描述,完成創(chuàng)建。
3. 創(chuàng)建云開(kāi)發(fā)環(huán)境
輸入網(wǎng)址: https://console.cloud.tencent.com/tcb/env/index,如果沒(méi)有授權(quán)會(huì)彈出以下畫(huà)面。 點(diǎn)擊訪問(wèn)管理,進(jìn)入授權(quán)。創(chuàng)建一個(gè)云開(kāi)發(fā)環(huán)境,這里命名環(huán)境為 mytest 。
4. 設(shè)置 SecretId 和 SecretKey
在流水線中,一般不會(huì)使用特權(quán)賬號(hào)的 SecretKey (主賬號(hào)的最高權(quán)限 SecretKey,擁有騰訊云控制臺(tái)的所有權(quán)),都是按需授權(quán),所以需要對(duì) SecretKey 的權(quán)限進(jìn)行訪問(wèn)控制。使用主賬號(hào)登錄 https://console.cloud.tencent.com/cam/capi,根據(jù)提示創(chuàng)建子用戶,選擇自定義創(chuàng)建,選擇類型為可訪問(wèn)資源并接收消息。填寫(xiě)用戶信息,選擇訪問(wèn)方式為編程訪問(wèn)。 對(duì)子用戶進(jìn)行權(quán)限策略關(guān)聯(lián),對(duì)于云開(kāi)發(fā)產(chǎn)品的訪問(wèn)控制有一個(gè)預(yù)設(shè)策略名字叫 QcloudAccessForTCBRole ,對(duì)賬號(hào)授權(quán)該策略,將擁有云開(kāi)發(fā)( TCB )對(duì)云資源的訪問(wèn)權(quán)限。直接在搜索框中搜索該策略即可。 下一步,完成子用戶的創(chuàng)建,請(qǐng)保存好 SecretId 和 SecretKey 信息。
5. 創(chuàng)建 TCB 云開(kāi)發(fā)項(xiàng)目
在本地使用 TCB CLI 創(chuàng)建一個(gè)云開(kāi)發(fā)項(xiàng)目。 tcb init 如果您沒(méi)有登錄 tcb,這里需要掃碼登錄。選擇關(guān)聯(lián)的環(huán)境,這里我選擇 mytest 環(huán)境,輸入項(xiàng)目名稱 mytest ,選擇開(kāi)發(fā)語(yǔ)言,目前支持 PHP 、Java 和 Node 三種語(yǔ)言,這里我選擇 Node,選擇云開(kāi)發(fā)模板,這里我選擇 Hello World 模板。 √ 選擇關(guān)聯(lián)環(huán)境 · mytest - [mytest-1ae5c0:空] √ 請(qǐng)輸入項(xiàng)目名稱 · mytest √ 選擇開(kāi)發(fā)語(yǔ)言 · Node √ 選擇云開(kāi)發(fā)模板 · Hello World √ 創(chuàng)建項(xiàng)目 mytest 成功!
我們將本地倉(cāng)庫(kù)與 CODING 遠(yuǎn)端倉(cāng)庫(kù)進(jìn)行關(guān)聯(lián)。 cd mytest git init #這里需要注意 username 為你的 CODING 賬戶名,tcb-fun 是代碼倉(cāng)庫(kù)名 git remote add origin [email?protected] :username/tcb-fun.git git add . git commit -m "Initial commit" git push -u origin master
6. CODING CI 設(shè)置
SecretId 和 SecretKey 信息屬于敏感信息,我們需要以 CODING 憑據(jù)的形式保存在項(xiàng)目配置中,使用憑據(jù)后你的敏感信息將不會(huì)出現(xiàn)在構(gòu)建日志和 Jenkinsfile 中,這樣會(huì)更加安全。進(jìn)入項(xiàng)目,依次選擇項(xiàng)目設(shè)置、開(kāi)發(fā)者選項(xiàng)、憑據(jù)管理,錄入一個(gè)憑據(jù)。 CODING 為我們提供了原生調(diào)用騰訊云產(chǎn)品的能力,在這里我們選擇憑據(jù)類型為云 API 秘鑰,填寫(xiě)好憑據(jù)名稱、SecretId 和 SecretKey 信息,授權(quán)在持續(xù)集成中使用憑據(jù)。 接下來(lái)我們回到項(xiàng)目,選擇構(gòu)建計(jì)劃模塊,創(chuàng)建一個(gè)持續(xù)集成任務(wù)。 填寫(xiě)計(jì)劃名稱,選擇代碼源為 CODING 代碼倉(cāng)庫(kù),配置來(lái)源使用靜態(tài)配置的 Jenkinsfile 。 根據(jù)前面我們梳理的流程,開(kāi)始撰寫(xiě) Jenkinsfile 文件,這里我們需要選擇文本編輯器。 pipeline { agent any stages { stage('檢出') { steps { echo '[檢出]正在從目標(biāo)代碼庫(kù)檢出最新源碼...' checkout([ $class: 'GitSCM', branches: [[name: env.GIT_BUILD_REF]], userRemoteConfigs: [[ url: env.GIT_REPO_URL, credentialsId: env.CREDENTIALS_ID ]] ]) echo '[檢出]檢出源碼成功.' } } stage('部署') { steps { echo '[部署]準(zhǔn)備部署云函數(shù).' sh 'npm i -g @cloudbase/cli' withCredentials([cloudApi(credentialsId: env.CREDENTIALSID, secretIdVariable: 'CLOUD_API_SECRET_ID', secretKeyVariable: 'CLOUD_API_SECRET_KEY')]){ sh 'tcb login --apiKeyId "${CLOUD_API_SECRET_ID}" --apiKey "${CLOUD_API_SECRET_KEY}"' } sh 'tcb functions:deploy --force --all' echo '[部署]部署云函數(shù)成功.' } } stage('事件消息') { steps { echo '[事件消息]持續(xù)部署流程完成.' } } } }
保存 Jenkinsfile,下一步需要我們將憑據(jù)添加到環(huán)境變量中。切換到變量與緩存選項(xiàng)卡,在流程環(huán)境變量中添加環(huán)境變量,變量名填寫(xiě) CREDENTIALSID,類別選擇 CODING 憑據(jù),選擇默認(rèn)值為剛剛添加的憑據(jù)信息,保存修改。
7. 測(cè)試與驗(yàn)證
通過(guò)以上步驟,我們已經(jīng)構(gòu)建好了云開(kāi)發(fā)中云函數(shù)持續(xù)部署流水線,我們可以使用 push 代碼來(lái)觸發(fā)流水線自動(dòng)部署。 在 CODING 項(xiàng)目的構(gòu)建計(jì)劃中可以看到每一次的構(gòu)建任務(wù)的運(yùn)行狀態(tài)。 點(diǎn)擊構(gòu)建任務(wù),進(jìn)入到任務(wù)詳情,點(diǎn)擊每一個(gè)步驟都可以看到日志詳情。我們看到整個(gè)流水線已經(jīng)跑完,狀態(tài)正常,在日志中也看到云開(kāi)發(fā)中云函數(shù)部署成功的提示。 我們回到云開(kāi)發(fā)控制臺(tái),進(jìn)入 mytest 環(huán)境,查看云函數(shù)列表,已經(jīng)可以看到我們剛剛部署的云函數(shù)。測(cè)試調(diào)用云函數(shù),其功能正常。
作者:校園布道師談笑
IT 運(yùn)維告警現(xiàn)狀
目前 IT 運(yùn)維領(lǐng)域保證服務(wù)運(yùn)行正常的主要方法是對(duì)相關(guān)運(yùn)維指標(biāo)進(jìn)行實(shí)時(shí)監(jiān)控,并根據(jù)經(jīng)驗(yàn)設(shè)定一些規(guī)則,通過(guò)將實(shí)時(shí)監(jiān)控的數(shù)據(jù)與規(guī)則進(jìn)行對(duì)比,當(dāng)某個(gè)指標(biāo)監(jiān)控值不符合設(shè)定的規(guī)則時(shí),則判定為異常的狀況,這樣的話就會(huì)發(fā)送對(duì)應(yīng)的告警到告警平臺(tái)。告警平臺(tái)收到通知后,會(huì)分配給對(duì)應(yīng)的運(yùn)維人員進(jìn)行處理,運(yùn)維人員去根據(jù)告警信息來(lái)排查,最終定位故障的根本原因,并對(duì)故障進(jìn)行修復(fù)。從這個(gè)流程可以看出,整個(gè)過(guò)程是以告警為中心,所以告警的質(zhì)量是至關(guān)重要的。
但在實(shí)際運(yùn)維過(guò)程中,我們可以發(fā)現(xiàn)這個(gè)過(guò)程中其實(shí)存在很多問(wèn)題。首先,監(jiān)控系統(tǒng)的規(guī)則難以設(shè)定。因?yàn)橐?guī)則是基于專家經(jīng)驗(yàn)設(shè)定的,隨著系統(tǒng)規(guī)模變大,復(fù)雜度提高,監(jiān)控覆蓋的完善,監(jiān)控指標(biāo)數(shù)量指數(shù)性增加,指標(biāo)形態(tài)千變?nèi)f化,基于專家經(jīng)驗(yàn)的規(guī)則設(shè)定力不從心,誤報(bào)率、漏報(bào)率居高不下。運(yùn)維人員可能會(huì)遭遇告警風(fēng)暴,每天被數(shù)千個(gè)告警轟炸,難以應(yīng)付。故障發(fā)生后,對(duì)若干個(gè)告警逐一排查找故障根因,效率極低,大大增加故障的恢復(fù)時(shí)間。故障有可能無(wú)法預(yù)知,有些本來(lái)可以避免的故障還是發(fā)生了。
智能化告警的理念和相關(guān)技術(shù)
為了解決上述問(wèn)題,在智能運(yùn)維領(lǐng)域,智能化告警的概念出現(xiàn)了。智能化告警主要解決 4 個(gè)問(wèn)題:一、精準(zhǔn)告警,拒絕告警風(fēng)暴;二、快速故障定位;三、進(jìn)行故障預(yù)測(cè),避免故障發(fā)生;四、規(guī)則設(shè)置自動(dòng)化,不再通過(guò)人工經(jīng)驗(yàn)來(lái)設(shè)置規(guī)則。
智能異常檢測(cè)的核心理念是利用機(jī)器學(xué)習(xí)算法,對(duì)歷史數(shù)據(jù)的規(guī)律自動(dòng)學(xué)習(xí),從而實(shí)現(xiàn)規(guī)則設(shè)置自動(dòng)化。這樣的話,就不再需要人工設(shè)置大量的規(guī)則,絕大部分情況下自動(dòng)學(xué)習(xí)的規(guī)則會(huì)更加準(zhǔn)確合理,大大提高告警產(chǎn)生的質(zhì)量。
智能異常檢測(cè)的技術(shù)有指標(biāo)異常檢測(cè)、日志異常檢測(cè)、根因分析和故障預(yù)測(cè)。指標(biāo)異常檢測(cè)一般分為單指標(biāo)異常檢測(cè)和多指標(biāo)異常檢測(cè)。單指標(biāo)異常檢測(cè)即時(shí)間序列異常檢測(cè),算法分為基于統(tǒng)計(jì)的算法、無(wú)監(jiān)督學(xué)習(xí)算法和有監(jiān)督分類算法三類?;诮y(tǒng)計(jì)的算法非常簡(jiǎn)單和容易實(shí)現(xiàn),但只能處理簡(jiǎn)單場(chǎng)景。常用的無(wú)監(jiān)督學(xué)習(xí)算法有 IForest 孤立森林、LOF 局部異常因子、One-Class-SVM 、Autoencoder 自編碼器等,這類算法無(wú)需打標(biāo)數(shù)據(jù),準(zhǔn)確度比較高,但特征選取難。有監(jiān)督分類的常用算法有 XGBoost 、GBDT 、決策樹(shù)、支持向量機(jī),這類算法非常準(zhǔn)確,但是打標(biāo)數(shù)據(jù)難以得到。多指標(biāo)異常檢測(cè)即綜合多個(gè)指標(biāo)判斷異常,需要先將數(shù)據(jù)降維,再使用有監(jiān)督分類和無(wú)監(jiān)督學(xué)習(xí)這兩類檢測(cè)算法。
日志是系統(tǒng)中信息頗為豐富的半結(jié)構(gòu)化數(shù)據(jù),采用日志異常檢測(cè),可以識(shí)別系統(tǒng)實(shí)時(shí)日志中的異常,有利于問(wèn)題發(fā)現(xiàn)和定位。日志檢測(cè)使用的方法有自然語(yǔ)言處理和日志模式識(shí)別。自然語(yǔ)言處理時(shí)文本向量化+深度學(xué)習(xí),理解日志中的文本信息,可識(shí)別潛在異常,結(jié)合人工反饋、標(biāo)注,不斷進(jìn)行模型完善和優(yōu)化。日志模式識(shí)別是對(duì)正常日志的模式進(jìn)行提取,對(duì)有別于正常模式的日志進(jìn)行發(fā)現(xiàn),結(jié)合特征工程,對(duì)模式匹配結(jié)果不斷進(jìn)行自學(xué)習(xí)和調(diào)整。
根因分析的核心理念是利用數(shù)據(jù)挖掘算法挖掘出指標(biāo)之間的相互影響關(guān)系,當(dāng)有關(guān)聯(lián)的指標(biāo)同時(shí)產(chǎn)生告警,則認(rèn)為影響告警側(cè)的告警為根因告警,被影響的告警為衍生告警,運(yùn)維人員收到的告警只是根因告警,這樣只需排查根因告警就可以確定故障的根因,極大提高故障根因定位的效率。根因分析可以極大縮短故障根因定位時(shí)間和故障恢復(fù)時(shí)間,減少故障帶來(lái)的損失。
根因分析可以分析指標(biāo)間的影響關(guān)系。利用 Pearson correlation,Spearman correlation,Kendall correlation,J-measure,Two-sample test 算法,可以進(jìn)行聯(lián)動(dòng)分析,判斷多個(gè)指標(biāo)是否經(jīng)常一起波動(dòng)或增長(zhǎng)。利用 FP-Growth,Apriori 算法,關(guān)聯(lián)歷史上經(jīng)常一起發(fā)生的事件,進(jìn)行頻繁項(xiàng)分析。下鉆分析,利用關(guān)聯(lián)關(guān)系匹配,尋找根因。
故障預(yù)測(cè)的核心理念是利用算法學(xué)習(xí)指標(biāo)歷史的變化規(guī)律,并根據(jù)規(guī)律預(yù)測(cè)指標(biāo)將來(lái)的變化趨勢(shì),對(duì)有可能發(fā)生故障的情況提前發(fā)出告警。對(duì)未來(lái)的故障進(jìn)行預(yù)測(cè),運(yùn)維人員可以提前介入,避免故障的發(fā)生,減少不必要的損失。
故障預(yù)測(cè)的方法有很多種,但主要分為三類:傳統(tǒng)統(tǒng)計(jì)方法、機(jī)器學(xué)習(xí)算法和深度學(xué)習(xí)算法。傳統(tǒng)統(tǒng)計(jì)方法有 ARIMA 、Holt-Winters 、Prophet 等,適用于預(yù)測(cè)穩(wěn)態(tài)或差分穩(wěn)態(tài)指標(biāo)。機(jī)器學(xué)習(xí)算法有 XGBoost 、GBDT 等,采用特征工程根據(jù)場(chǎng)景構(gòu)造輸入特征,適用于預(yù)測(cè)多變量指標(biāo)。深度學(xué)習(xí)算法有 RNN 循環(huán)神經(jīng)網(wǎng)絡(luò)、LSTM 長(zhǎng)短期記憶網(wǎng)絡(luò)等,采用歷史數(shù)據(jù)滑窗方式,將預(yù)測(cè)問(wèn)題轉(zhuǎn)化為監(jiān)督學(xué)習(xí)問(wèn)題,使用神經(jīng)網(wǎng)絡(luò)提取特征,這類算法在絕大多數(shù)指標(biāo)上都表現(xiàn)的非常好,準(zhǔn)確率很高,但因?yàn)橛?jì)算量大,對(duì)資源要求相對(duì)比較高,性能較差。
智能化告警實(shí)踐
基于以上智能告警的理念和相關(guān)方法,結(jié)合過(guò)往的實(shí)踐,我們將介紹一下在單指標(biāo)異常檢測(cè)、根因分析和故障預(yù)測(cè)方面的實(shí)戰(zhàn)方案。
這張圖片展示的是單指標(biāo)異常檢測(cè)的整體框架圖,主要包括離線模塊和在線模塊兩個(gè)方面。離線模塊主要是對(duì)歷史數(shù)據(jù)的學(xué)習(xí)和分析。我們?cè)诖罅康膶?shí)驗(yàn)過(guò)程中發(fā)現(xiàn),難以找到一種就是萬(wàn)能的異常檢測(cè)算法對(duì)所有指標(biāo)都表現(xiàn)的比較好,某種算法通常只對(duì)特定形態(tài)的指標(biāo)表現(xiàn)較好,所以我們首先對(duì)指標(biāo)進(jìn)行分類操作。分類之后,我們可以確定每個(gè)指標(biāo)分別對(duì)應(yīng)使用的算法。接下來(lái)就可以進(jìn)行算法模型參數(shù)的訓(xùn)練,將樣本庫(kù)的數(shù)據(jù)作為測(cè)試數(shù)據(jù),對(duì)模型進(jìn)行評(píng)估。離線模塊是一個(gè)定時(shí)任務(wù),可以定時(shí)對(duì)某個(gè)指標(biāo)重新進(jìn)行分類和模型訓(xùn)練,保證模型的時(shí)效性和準(zhǔn)確性。
在線模塊主要是利用離線模塊訓(xùn)練好的模型,對(duì)實(shí)時(shí)產(chǎn)生的監(jiān)控?cái)?shù)據(jù)進(jìn)行檢測(cè)。判斷指標(biāo)的健康狀況期,主要步驟就是以實(shí)時(shí)監(jiān)控?cái)?shù)據(jù)為模型輸入,判斷指標(biāo)是否異常,如果異常的話就進(jìn)行相應(yīng)的告警。此外,對(duì)模型輸出的異常提供了一個(gè)人工審核的過(guò)程,這樣的話審核的結(jié)果就保存到樣本庫(kù)中。
我們對(duì)大量的指標(biāo)進(jìn)行具體分析后,發(fā)現(xiàn)所有的指標(biāo)都可以近似分為三大類。第一類是周期分量,這類指標(biāo)有明顯的波動(dòng)周期。第二類是趨勢(shì)分量,變化比較平緩,一般緩緩升高或降低,比如磁盤使用量這種指標(biāo)。第三類是穩(wěn)定分量,往往只在一個(gè)區(qū)間波動(dòng),比如服務(wù)詳細(xì)時(shí)間這種指標(biāo)。數(shù)據(jù)分解也是將數(shù)據(jù)分解成這三個(gè)分量。
受此啟發(fā),我們首先對(duì)時(shí)序數(shù)據(jù)進(jìn)行了分解,之后可以把一個(gè)指標(biāo)分解成趨勢(shì)分量、周期分量以及穩(wěn)定分量。然后分別計(jì)算這三個(gè)分量與原始曲線的一個(gè)皮爾遜相關(guān)系數(shù),系數(shù)最大的哪個(gè)分量就是指標(biāo)的類別。
完成分類指標(biāo)后,就可以確定用什么算法進(jìn)行檢測(cè)。為了保證可靠性,我們給每種類型的指標(biāo)都提供了兩種算法,并進(jìn)行投票決策。對(duì)于周期性指標(biāo)我們提供同比算法和基于預(yù)測(cè)的異常檢測(cè)算法;對(duì)于趨勢(shì)性指標(biāo)我們使用環(huán)比算法和孤立森林算法;對(duì)于穩(wěn)定性指標(biāo)我們使用 3-sigma 算法和四分位數(shù)算法。算法參數(shù)訓(xùn)練使用指標(biāo)過(guò)去 7 天的歷史數(shù)據(jù),模型參數(shù)的選取采用網(wǎng)絡(luò)搜索方式確定。
這張圖展示的是根因分析的主要流程。在關(guān)聯(lián)關(guān)系分析方面,我們提供了三種方式:強(qiáng)關(guān)聯(lián)分析、頻繁項(xiàng)挖掘和相關(guān)性分析。通過(guò)這三種方法得到指標(biāo)的關(guān)聯(lián)關(guān)系,有的指標(biāo)關(guān)聯(lián)關(guān)鍵后,就可以對(duì)告警進(jìn)行根因分析。首先將各個(gè)監(jiān)控系統(tǒng)的告警統(tǒng)一接入到我們系統(tǒng)中,并做格式統(tǒng)一處理。利用高級(jí)壓縮的一些方法,將一些無(wú)效的告警過(guò)濾掉,有效的告警進(jìn)入根因分析環(huán)節(jié),得出根因分析報(bào)告,運(yùn)維人員根據(jù)這個(gè)報(bào)告定位問(wèn)題。
離線部分的數(shù)據(jù)來(lái)源是指標(biāo)的歷史數(shù)據(jù),輸出為模型;在線部分根據(jù)模型進(jìn)行計(jì)算后得到預(yù)測(cè)數(shù)據(jù),作為故障預(yù)測(cè)的數(shù)據(jù)基礎(chǔ)。由于 LSTM (長(zhǎng)短期記憶網(wǎng)絡(luò))能很好抓住實(shí)踐序列上下文可能存在的聯(lián)系的特性,在絕大部分情況下效果都很好,因此算法選擇方面,我們選擇 LSTM 算法作為預(yù)測(cè)模型。
這是一個(gè)故障預(yù)測(cè)的效果圖,指標(biāo)是一個(gè) Web 系統(tǒng)的訪問(wèn)量,藍(lán)線代表實(shí)際值,黃線代表預(yù)測(cè)者。紅點(diǎn)是我們預(yù)測(cè) Web 訪問(wèn)量在這個(gè)時(shí)間點(diǎn)可能會(huì)達(dá)到系統(tǒng)所能承載的最大的訪問(wèn)量。因此,我們可以提前發(fā)出通知,這樣運(yùn)維人員可以提前進(jìn)行資源增加或擴(kuò)容等操作,來(lái)防止訪問(wèn)量太大導(dǎo)致的服務(wù)質(zhì)量下降。
總結(jié)
發(fā)現(xiàn)故障是整個(gè)告警質(zhì)量的決定性環(huán)節(jié),所以智能異常檢測(cè)要引入更多更優(yōu)的算法,將誤報(bào)率和漏報(bào)率控制在 1% 以內(nèi)。在故障定位環(huán)節(jié),如何根據(jù)已有的數(shù)據(jù)分析出更加全面的關(guān)聯(lián)關(guān)系是重點(diǎn),結(jié)合多維下鉆分析,給出更精確的故障根因。解決故障環(huán)節(jié)可以引入故障自愈,實(shí)現(xiàn)定位到問(wèn)題后,自動(dòng)修復(fù),進(jìn)一步提高運(yùn)維自動(dòng)化。
點(diǎn)擊觀看完整課程視頻
微服務(wù)測(cè)試的痛點(diǎn)與挑戰(zhàn)
這張圖可以形象地展示單體服務(wù)和微服務(wù)的對(duì)比,單體應(yīng)用就像左邊巨大的集裝箱,軟件模塊和應(yīng)用都包括其中;而微服務(wù)就像是由一個(gè)小集裝箱組成,微小的服務(wù)組成一個(gè)龐大、完整的系統(tǒng)。單體服務(wù)是一個(gè)大而全的應(yīng)用體,而微服務(wù)由拆分成出來(lái)的很多小服務(wù)來(lái)組成一個(gè)龐大而完整的系統(tǒng)。
微服務(wù)是一種架構(gòu)模式,是面向服務(wù)型架構(gòu) SOA 的一種變體,提倡將單一應(yīng)用程序逐漸還原劃分成小的服務(wù),服務(wù)間互相協(xié)調(diào)、互相配合,為用戶提供最終價(jià)值。微服務(wù)架構(gòu)風(fēng)格就是一些小而自治的服務(wù)協(xié)同工作形成松耦合的系統(tǒng)。另外,我們需要盡量避免一個(gè)統(tǒng)一的、集中式的服務(wù)管理機(jī)制,對(duì)具體的一個(gè)服務(wù)而言,應(yīng)該根據(jù)上下文選擇合適的語(yǔ)言工具對(duì)其進(jìn)行構(gòu)建。
結(jié)合下方的這張圖,我們可以理解微服務(wù)構(gòu)建的核心其實(shí)是中間領(lǐng)域的業(yè)務(wù)邏輯,圍繞著這個(gè)領(lǐng)域業(yè)務(wù)邏輯,會(huì)有一些微服務(wù)去進(jìn)行拆分構(gòu)建。
微服務(wù)具有專注、自治、獨(dú)立進(jìn)程、獨(dú)立部署和技術(shù)異構(gòu)的特點(diǎn),即每個(gè)服務(wù)只限定于特定的業(yè)務(wù)而專注做一件事情,每個(gè)服務(wù)承擔(dān)的是單一職責(zé),但是它也需要達(dá)到一定規(guī)模能夠完整的處理特定的領(lǐng)域業(yè)務(wù)。很多人都會(huì)被微服務(wù)的“微”這個(gè)詞所誤導(dǎo),認(rèn)為微服務(wù)就是要拆分的越小越好。但是其實(shí)為了“微”而將同一領(lǐng)域的業(yè)務(wù)拆分到不同的服務(wù),只會(huì)徒勞增加軟件的復(fù)雜度和維護(hù)困難。
我們可以圍繞應(yīng)用的業(yè)務(wù)能力進(jìn)行分組,每個(gè)小組的開(kāi)發(fā)組人員開(kāi)發(fā)微服務(wù)的技術(shù)可以不受限制。每個(gè)服務(wù)小組可以使用不同的技術(shù)架構(gòu)和存儲(chǔ)技術(shù),有針對(duì)性地解決一些性能瓶頸問(wèn)題。每個(gè)服務(wù)是互相獨(dú)立部署互不影響的,這樣的話我們可以實(shí)現(xiàn)獨(dú)立打包、獨(dú)立測(cè)試和獨(dú)立附屬,減少部署時(shí)間,提升研發(fā)效率。
微服務(wù)架構(gòu)測(cè)試具有三個(gè)痛點(diǎn):一、如何測(cè)試微服務(wù)的外部依賴是否正常;二、如何在微服務(wù)架構(gòu)下驗(yàn)證系統(tǒng)的整個(gè)功能是否符合預(yù)期;三、這么多微服務(wù)的部署和測(cè)試,應(yīng)如何開(kāi)展。按照以上痛點(diǎn)我們可以看到,微服務(wù)測(cè)試是一種驗(yàn)證成本高、結(jié)果不穩(wěn)定、反饋周期長(zhǎng)的測(cè)試。
測(cè)試金字塔
測(cè)試金字塔其實(shí)是一種方法論,解決微服務(wù)測(cè)試的關(guān)鍵在于將微服務(wù)的測(cè)試按照不同的力度來(lái)分組。測(cè)試金字塔的概念由麥克科恩首先提出。測(cè)試是分層次的,我們看到圖片左邊,這個(gè)金字塔被分為三個(gè)層次,從下往上分別是單元測(cè)試、服務(wù)測(cè)試、界面測(cè)試,從下往上測(cè)試的運(yùn)行速度是逐漸減慢的,外物依賴或者服務(wù)間的依賴從下到上會(huì)依賴更多。這個(gè)測(cè)試金字塔的另外一個(gè)重要特征是,從下往上對(duì)每一層的測(cè)試代碼是逐層減少的。下方應(yīng)該寫(xiě)一些小而快的測(cè)試,往上應(yīng)該編寫(xiě)一些粗粒度的測(cè)試,編寫(xiě)更少的高層次測(cè)試。
然而實(shí)際中如果以這個(gè)金字塔圖來(lái)作為指導(dǎo),會(huì)過(guò)于籠統(tǒng)簡(jiǎn)單,所以我們會(huì)采用右邊的分為四層的測(cè)試金字塔來(lái)做內(nèi)部測(cè)試的指導(dǎo)思想。底層是單元測(cè)試,在這之上是集成測(cè)試,再往上是端到端的測(cè)試,頂層是探索測(cè)試。
作為開(kāi)發(fā)人員或測(cè)試人員,應(yīng)該關(guān)注金字塔的哪些部分呢?微服務(wù)開(kāi)發(fā)人員應(yīng)更多關(guān)注位于塔基底部的單元測(cè)試與集成測(cè)試。在這兩層需要開(kāi)發(fā)人員編寫(xiě)一定量的測(cè)試代碼來(lái)保證覆蓋,應(yīng)該寫(xiě)許多小而快的單元測(cè)試覆蓋絕大部分的業(yè)務(wù)場(chǎng)景,再寫(xiě)一定的粗粒度的集成測(cè)試,來(lái)測(cè)試重要系統(tǒng)之間外部依賴的交互是否正常。測(cè)試人員和質(zhì)量保證人員應(yīng)更多關(guān)注金字塔上面兩層,測(cè)試人員可以依據(jù) BDD 的規(guī)范來(lái)編寫(xiě)測(cè)試用例,用于校驗(yàn)系統(tǒng)功能的交互是否正常,還可以用非常規(guī)的手段進(jìn)行破壞性的探索測(cè)試。
單元測(cè)試是測(cè)試金字塔的底基,它的定義沒(méi)有標(biāo)準(zhǔn)答案。從編程角度來(lái)看,在函數(shù)式語(yǔ)言中我們可以認(rèn)為一個(gè)函數(shù)是一個(gè)單元,在面向?qū)ο蟮恼Z(yǔ)言中一個(gè)方法或者一個(gè)類可以表示一個(gè)單元。單元測(cè)試具有能夠及時(shí)發(fā)現(xiàn) bug 、利于重構(gòu)、保證代碼質(zhì)量的優(yōu)勢(shì),我們系統(tǒng)中需要編寫(xiě)得最多的其實(shí)就是單元測(cè)試。
微服務(wù)的測(cè)試一般是對(duì)入棧適配器、業(yè)務(wù)邏輯和出棧適配器這三部分進(jìn)行測(cè)試。入棧適配器測(cè)試的是 Controller API 是否正確;業(yè)務(wù)邏輯部分測(cè)試 Service 業(yè)務(wù)邏輯是否正確,而出棧適配器部分測(cè)試的是 SQL 邏輯是否正確。單元測(cè)試一般會(huì)遵循一個(gè)通用的 3A 結(jié)構(gòu):Arrange,Act,Assert,這樣寫(xiě)出來(lái)的代碼更有閱讀性和表達(dá)力。
在微服務(wù)架構(gòu)下我們所理解的集成測(cè)試是測(cè)試應(yīng)用與外部依賴的集成。第三方外部服務(wù)依賴主要有兩種類:第一種是微服務(wù)會(huì)依賴第三方系統(tǒng)的服務(wù);第二種是系統(tǒng)內(nèi)部的微服務(wù)與微服務(wù)之間,一種服務(wù)可能會(huì)依賴另一種微服務(wù)來(lái)實(shí)現(xiàn)自身邏輯。對(duì)應(yīng)這兩種情況會(huì)有不同的策略,第一種策略是準(zhǔn)備真實(shí)的外部服務(wù)的依賴,第二種是使用測(cè)試替身隔絕外部依賴。進(jìn)行集成測(cè)試的時(shí)候我們通常會(huì)使用一些,依賴第三方服務(wù)的話會(huì)采用 WireMock 或者 mountebank,而微服務(wù)之間的依賴調(diào)用會(huì)使用 Spring-Cloud-Contract 或者 Pact 。
微服務(wù)之間的測(cè)試會(huì)使用契約測(cè)試,服務(wù)之間的接口文檔就是一個(gè)契約。契約測(cè)試可以解決聯(lián)調(diào)成本過(guò)高,接口變動(dòng)把控困難,契約變化時(shí)提供一種可立即被服務(wù)端和消費(fèi)端發(fā)現(xiàn)的方式,這三種痛點(diǎn)。契約測(cè)試的提供者指微服務(wù)接口的提供者,消費(fèi)者指微服務(wù)接口的消費(fèi)者。契約文件是微服務(wù)提供者和消費(fèi)者共同定義的接口規(guī)范,包括接口的訪問(wèn)路徑和輸出數(shù)據(jù)。
CDC 的核心思想在于從消費(fèi)者業(yè)務(wù)實(shí)現(xiàn)的角度出發(fā),由消費(fèi)者自己定義需要的測(cè)試數(shù)據(jù)格式以及交互細(xì)節(jié),并驅(qū)動(dòng)生成一份消費(fèi)者契約。然后生產(chǎn)者根據(jù)契約來(lái)實(shí)現(xiàn)自己的邏輯,并在服務(wù)提供者端進(jìn)行測(cè)試驗(yàn)證。契約文檔應(yīng)該被轉(zhuǎn)換成一個(gè)存根。生產(chǎn)者會(huì)根據(jù)契約編寫(xiě)契約驗(yàn)證測(cè)試,契約驗(yàn)證測(cè)試通過(guò)會(huì)將契約文件轉(zhuǎn)換為存根,存根會(huì)被消費(fèi)者引用,契約的修改會(huì)導(dǎo)致任意一方測(cè)試的失敗。這樣的話可以保證契約被消費(fèi)者和生產(chǎn)者共同遵守。
契約測(cè)試適用于微服務(wù)接口的消費(fèi)者和提供者由不同的團(tuán)隊(duì)維護(hù),或提供者接口被多個(gè)消費(fèi)者消費(fèi)這樣的場(chǎng)景中。
端到端測(cè)試主要用于驗(yàn)證工作流程中的所有流程,以檢查一切是否按照預(yù)期工作,確保系統(tǒng)以統(tǒng)一的方式工作,從而滿足業(yè)務(wù)需求。端到端測(cè)試的難點(diǎn)在于安裝和配置相關(guān)依賴,測(cè)試數(shù)據(jù)的自動(dòng)準(zhǔn)備二號(hào)服務(wù)的自動(dòng)部署。
微服務(wù)測(cè)試藍(lán)圖
做微服務(wù)測(cè)試需要做 TDD,也就是測(cè)試在先,編碼在后的開(kāi)發(fā)實(shí)踐。有別于以往的先編碼、后測(cè)試的開(kāi)發(fā)過(guò)程,而是在編程之前,先寫(xiě)測(cè)試腳本或設(shè)計(jì)測(cè)試用例。TDD 可以增加開(kāi)發(fā)人員代碼質(zhì)量的信心,有利于代碼設(shè)計(jì)和重構(gòu),以及快速迭代和持續(xù)交付。
微服務(wù)測(cè)試推進(jìn)主要分為四步:第一步是工具,依照微服務(wù)測(cè)試層次,階段選擇合適的測(cè)試框架與工具;第二步是依據(jù)測(cè)試金字塔制定規(guī)范,貫穿生命周期始終,明確開(kāi)發(fā)、測(cè)試人員的職責(zé);第三步是自動(dòng)化,貫穿 CI 、CD 流程,與 DevOps 的融合;第四步是測(cè)試平臺(tái)搭建,以容器化技術(shù)搭建測(cè)試平臺(tái),以 namespace 隔離不同測(cè)試環(huán)境。
點(diǎn)擊觀看完整課程視頻
什么是質(zhì)量?jī)?nèi)建
隨著時(shí)間的推移,我們項(xiàng)目的開(kāi)發(fā)效率會(huì)逐漸降低,直到幾年之后整個(gè)項(xiàng)目可能就無(wú)法維護(hù),只能推倒重來(lái)。具體的表現(xiàn)首先就是隨著時(shí)間推移,我們會(huì)發(fā)現(xiàn)整個(gè)需求列表里面能做的需求越來(lái)越少,因?yàn)槊慨?dāng)我們?cè)黾右粋€(gè)新特性,需要改動(dòng)的代碼就非常多,所以最后每提出一個(gè)新的需求,團(tuán)隊(duì)評(píng)估出來(lái)的改動(dòng)成本都非常高,導(dǎo)致最后難以增加新的特性。
第二個(gè)表現(xiàn)就是缺陷難以修復(fù)。我們做出來(lái)的系統(tǒng)只要有人用就會(huì)有反饋一些線上的故障,一開(kāi)始代碼很簡(jiǎn)單的時(shí)候修復(fù)起來(lái)是很快的,但是隨著代碼越來(lái)越復(fù)雜、代碼行數(shù)越來(lái)越多,我們會(huì)發(fā)現(xiàn)定位問(wèn)題太難了。尤其是現(xiàn)在我們的項(xiàng)目采用的是非常復(fù)雜的架構(gòu),所以當(dāng)用戶線上報(bào)錯(cuò)的時(shí)候,我們很難去定位到是哪里出了問(wèn)題。但其實(shí)只要定位到了問(wèn)題,修復(fù)起來(lái)是很快的。
第三個(gè)表現(xiàn)我們稱之為“打地鼠現(xiàn)象”,簡(jiǎn)單來(lái)說(shuō)就是當(dāng)你“按”下一個(gè)缺陷的時(shí)候,又會(huì)蹦出來(lái)幾個(gè)新的缺陷。這樣會(huì)導(dǎo)致大家在工作的過(guò)程中壓力非常大、心情也會(huì)比較沉重。
所以對(duì)于這些挑戰(zhàn),我們也有想辦法去解決,CI 、CD 以及 DevOps 的出現(xiàn)都讓我們看到了很好的方向。但是我看到很多團(tuán)隊(duì)其實(shí)只是靠 DevOps 解決了一些基本的問(wèn)題,并沒(méi)有解決核心的問(wèn)題。這是為什么呢?因?yàn)楹诵膯?wèn)題主要是靠開(kāi)發(fā)人員的能力提升來(lái)解決的,但由于改變一個(gè)人是很難的,所以企業(yè)往往會(huì)繞開(kāi)這些問(wèn)題。所以我今天分享的內(nèi)容主要會(huì)涉及到開(kāi)發(fā)人員如何去寫(xiě)代碼等一些實(shí)踐。
我們?cè)趧傞_(kāi)始啟動(dòng)一個(gè)項(xiàng)目的時(shí)候,我們會(huì)制定一些代碼規(guī)范,所以代碼相對(duì)來(lái)說(shuō)是比較清晰的。但是隨著需求的演變,在實(shí)現(xiàn)這些需求的時(shí)候,每個(gè)人都會(huì)選擇最低成本、最保險(xiǎn)的方式。這就會(huì)導(dǎo)致沒(méi)有人敢去大幅度地改動(dòng)代碼,只會(huì)在里面追加一些代碼,造成了代碼里面有大量的重復(fù)、過(guò)長(zhǎng)的方法。同時(shí)開(kāi)始的時(shí)候設(shè)計(jì)的架構(gòu)也是非常清晰的,但是如果后續(xù)沒(méi)有很好的落地、監(jiān)控、自動(dòng)化地發(fā)現(xiàn)問(wèn)題,架構(gòu)就會(huì)在這過(guò)程中腐化,變得一團(tuán)亂。
Deming 先生曾提出“問(wèn)題發(fā)現(xiàn)得越早,修復(fù)的成本越低”,這句話也是我們?nèi)ソ档蛙浖_(kāi)發(fā)成本、更高效地保證質(zhì)量的重要原則。所以我們采用質(zhì)量?jī)?nèi)建的方式,可以把整個(gè)軟件質(zhì)量的保障內(nèi)嵌到開(kāi)發(fā)的過(guò)程中去,而不是留到后面再去檢測(cè),因?yàn)樵酵笮迯?fù)的成本越高。
85% 的缺陷都是在代碼編碼階段引入的,然而大部分的缺陷并不是在編碼的時(shí)候發(fā)現(xiàn)的,而是在后面的單元測(cè)試、功能測(cè)試、集成測(cè)試發(fā)現(xiàn)的,越往后發(fā)現(xiàn)的缺陷越多。按照剛剛那個(gè)原則,假如在編碼階段發(fā)現(xiàn)的缺陷只需要 1 分鐘就能解決,那么單元測(cè)試階段需要 4 分鐘,功能測(cè)試階段需要 10 分鐘,而到了上線之后再發(fā)現(xiàn)可能就需要 640 分鐘,這個(gè)成本是非常高的。
那么質(zhì)量?jī)?nèi)建的方式是怎么樣的呢?首先我們通過(guò)自動(dòng)化測(cè)試、重構(gòu)、簡(jiǎn)單設(shè)計(jì)等手段,可以使在編碼階段引入的缺陷變少,因?yàn)槲覀兇a寫(xiě)清楚了,bug 就藏不住了。同時(shí)當(dāng)我們做到自動(dòng)化測(cè)試等工作時(shí),在編碼階段發(fā)現(xiàn)的缺陷也變多了。那么通過(guò)質(zhì)量?jī)?nèi)建,我們?cè)诰幋a階段就把大部分的問(wèn)題都捕獲到,同時(shí)引入的缺陷也更少,它就降低了軟件的開(kāi)發(fā)成本。
大家可能會(huì)有一個(gè)疑惑,就開(kāi)始開(kāi)發(fā)人員原本只用寫(xiě)功能就行了,現(xiàn)在卻還要寫(xiě)測(cè)試代碼,而且測(cè)試代碼的比例和實(shí)踐代碼的比例不一定,這樣會(huì)不會(huì)增加成本。這里想跟大家說(shuō)一下,很多人會(huì)把我們編寫(xiě)代碼的時(shí)間當(dāng)成整個(gè)軟件開(kāi)發(fā)的時(shí)間,其實(shí)不是。在編寫(xiě)玩代碼之后,還得開(kāi)發(fā)自測(cè),然后還要去聯(lián)調(diào),之后還要進(jìn)行內(nèi)部測(cè)試、線上故障修復(fù)等,所以整個(gè)軟件開(kāi)發(fā)有這么多的過(guò)程,而我們現(xiàn)在解決問(wèn)題的辦法是在第一階段投入更多的時(shí)間,做更多的測(cè)試、更多的代碼優(yōu)化等,從而減少后面所要花費(fèi)的時(shí)間。根據(jù)剛剛說(shuō)的修復(fù)時(shí)間越晚,成本越高的原則,我們這樣做是劃算的。
技術(shù)債與質(zhì)量門禁
技術(shù)債是什么呢?債是一種比喻,與我們金融方面所說(shuō)的債務(wù)意思相同,那么在我們技術(shù)范疇里面也有這樣的債務(wù)問(wèn)題。在我們編寫(xiě)代碼的過(guò)程中留下了一些重復(fù)的代碼,或者沒(méi)有起好名字、沒(méi)有給出注釋,類似這樣的問(wèn)題就是我們欠下的技術(shù)債。
對(duì)比金融里的債務(wù),技術(shù)債也有相應(yīng)的特性。首先這個(gè)債我們必須得還,否則到了后面越欠越多可能會(huì)把整個(gè)團(tuán)隊(duì)壓垮了,導(dǎo)致大家沒(méi)有動(dòng)力去開(kāi)發(fā)新的功能。同時(shí)技術(shù)債是有利息的,假如最開(kāi)始寫(xiě)代碼的人留下了問(wèn)題沒(méi)有去解決,那么下一個(gè)接手這個(gè)代碼的人可能就沒(méi)法理解這個(gè)代碼,就不敢大膽地去改代碼,越晚就越不敢。
既然技術(shù)債存在這么多問(wèn)題,大家為什么還要去欠債呢?因?yàn)榧夹g(shù)債也有好處,有的時(shí)候我們要做的產(chǎn)品并不是一個(gè)非??孔V的產(chǎn)品,我們就會(huì)追求更快,用一個(gè)比較粗糙的手段做完交給客戶去進(jìn)行測(cè)試。得到反饋之后,靠譜的話我們就會(huì)用心去優(yōu)化、迭代;不靠譜的話我們就會(huì)放棄這個(gè)項(xiàng)目,這是它的成本也很低。所以由于互聯(lián)網(wǎng)行業(yè)的這種快節(jié)奏,人們會(huì)傾向于欠下很多的技術(shù)債務(wù),從而快速試錯(cuò)。當(dāng)我得到反饋,確認(rèn)用戶的痛點(diǎn)之后再來(lái)進(jìn)行代碼的優(yōu)化。當(dāng)然我今天更想講的我們?yōu)槭裁磿?huì)欠下債務(wù),其實(shí)還是是因?yàn)閼B(tài)度以及習(xí)慣問(wèn)題。如果我們能改掉我們的壞習(xí)慣,我們就會(huì)少欠下一些技術(shù)債。
當(dāng)我們搭建好一個(gè)項(xiàng)目的基礎(chǔ)框架,寫(xiě)了一些示例的代碼,后面就會(huì)上很多的人來(lái)做一些新需求。這個(gè)時(shí)候就會(huì)出現(xiàn)“失控”,我們會(huì)發(fā)現(xiàn)一開(kāi)始的代碼非常整潔,但是人一多之后就會(huì)形成“破窗效應(yīng)”——簡(jiǎn)單來(lái)說(shuō)就是一旦一扇窗戶上出現(xiàn)了一個(gè)破洞,那么很快上面的破洞就會(huì)越來(lái)越多。代碼庫(kù)也是如此,當(dāng)一個(gè)人沒(méi)有按照規(guī)范寫(xiě)代碼,同時(shí)沒(méi)有人制止,那么很快其他人也會(huì)紛紛開(kāi)始這樣做,很快代碼就會(huì)變得亂七八糟。
那么應(yīng)對(duì)這種“破窗效應(yīng)”的方法就是“童子軍軍規(guī)”,就是不管原來(lái)的質(zhì)量怎么樣,我們也得保證我們接手處理完之后,代碼的質(zhì)量要比原先好上一點(diǎn)、干凈一點(diǎn),哪怕是改一個(gè)變量命名也好,改一個(gè)格式也好,人人都這樣做的話我們的代碼庫(kù)就會(huì)越來(lái)越干凈、質(zhì)量越來(lái)越高。這種方式就是我們所謂的“質(zhì)量門禁”。
接下來(lái)講一下償還技術(shù)債,首先第一點(diǎn)是并非所有技術(shù)債都應(yīng)償還,或者說(shuō)技術(shù)債的償還應(yīng)該有一個(gè)優(yōu)先級(jí),我們更應(yīng)該關(guān)注的是那些頻繁地需要變更的代碼。第二點(diǎn)是應(yīng)用童子軍規(guī)則,也就是有債就還,不要拖欠太久,保證每次提交代碼的時(shí)候比接手時(shí)要干凈一點(diǎn)。第三點(diǎn)是先償還高息技術(shù)債,就是看哪些問(wèn)題不處理的話帶來(lái)的后果會(huì)更嚴(yán)重,我們就優(yōu)先處理這些問(wèn)題。接著是分期償還技術(shù)債,將我們的技術(shù)債管理起來(lái),每次迭代的時(shí)候就一邊做有客戶價(jià)值的工作,一邊償還技術(shù)債。這里很關(guān)鍵的就是不能依賴開(kāi)發(fā)人員的自覺(jué)性,而是在迭代的時(shí)候就要明確那哪一塊要優(yōu)化、要重構(gòu),分到個(gè)人的頭上,同時(shí)后面要進(jìn)行評(píng)測(cè)、驗(yàn)收,經(jīng)過(guò)這樣一個(gè)流程正式地去對(duì)待技術(shù)債。
自動(dòng)化
自動(dòng)化是一個(gè)實(shí)踐,我們經(jīng)常會(huì)聽(tīng)到像自動(dòng)化發(fā)布、自動(dòng)化打包、自動(dòng)化構(gòu)建、自動(dòng)化測(cè)試等,尤其是自動(dòng)化測(cè)試是一個(gè)反復(fù)被強(qiáng)調(diào)的一個(gè)實(shí)踐。我們的流水線其實(shí)整個(gè)都是自動(dòng)化的,構(gòu)建是自動(dòng)化的,檢查是自動(dòng)化的,包括后面的測(cè)試和部署也都是自動(dòng)化的。
有一個(gè)原則叫自動(dòng)化一切,就是“一切能被自動(dòng)化的都應(yīng)該被自動(dòng)化”。除了常見(jiàn)的編譯、檢查、測(cè)試和部署,服務(wù)器的配置也可以進(jìn)行自動(dòng)化,甚至業(yè)務(wù)上的一些部署,比如一些遷移之類的,能自動(dòng)化的我們都把它自動(dòng)化。我們作為開(kāi)發(fā)人員,最擅長(zhǎng)的其實(shí)就是寫(xiě)代碼,很多人會(huì)覺(jué)得自己的工作沒(méi)什么挑戰(zhàn),這是因?yàn)槟闾焯於荚谑止さ刈鲆恍┲貜?fù)的事情,當(dāng)然沒(méi)有挑戰(zhàn)了。這時(shí)候你可以嘗試去自動(dòng)化一些事情,你會(huì)發(fā)現(xiàn)很好玩,也能學(xué)到新的東西,個(gè)人能力能得到成長(zhǎng),同時(shí)做的事情也有價(jià)值。
我體會(huì)到自動(dòng)化的幾個(gè)好處,跟大家分享一下。第一個(gè)是沉淀知識(shí),就是把知識(shí)沉淀到了自動(dòng)化的腳本里面,而不是存在于某個(gè)人的腦子里。而對(duì)于掌握知識(shí)的這個(gè)人來(lái)說(shuō),他也減少了被打斷的可能。第二點(diǎn)就是自動(dòng)化能夠提高效率,解放生產(chǎn)力,這一點(diǎn)其實(shí)是一個(gè)很明顯的好處,原來(lái)手工要花五個(gè)小時(shí)的事情,自動(dòng)化可能幾分鐘就跑完了。最后一點(diǎn)就是固化流程,降低出錯(cuò)率。也就是將我們的這個(gè)流程固化下來(lái)了,原本一件事情今天是 A 做,明天是 B 做,他們?cè)谧龅臅r(shí)候可能就基于自己的理解來(lái)做,中間就會(huì)引入一些錯(cuò)誤。而自動(dòng)化就可以規(guī)避這種問(wèn)題。
其他有效實(shí)踐
①結(jié)對(duì)編程:結(jié)對(duì)編程是我非常推崇的實(shí)踐,很多人認(rèn)為結(jié)對(duì)編程就是一個(gè)人寫(xiě)一個(gè)人看,這樣就浪費(fèi)了一個(gè)人,其實(shí)不是的。其實(shí)結(jié)對(duì)編程有點(diǎn)像汽車?yán)?領(lǐng)航員會(huì)看地圖然后告訴 driver 前方的路線,例如前面的彎道該怎么走,所以他的視野會(huì)更加宏觀,看得更遠(yuǎn),也有助于對(duì)我們的 driver 做一個(gè)思維上的引導(dǎo)。寫(xiě)代碼的時(shí)候也是這樣的,操作鍵盤的人在考慮代碼該怎么敲,而另一個(gè)人則是在引領(lǐng)思路,所以他倆是在互相配合的。
②代碼評(píng)審:代碼評(píng)審就是大家坐在一起,分享代碼的收獲、踩過(guò)的坑以及解決問(wèn)題的方法、技巧。這是一個(gè)開(kāi)發(fā)人員的交流活動(dòng),而不是一個(gè)類似于質(zhì)量門禁的東西,這是有溫度的一場(chǎng)交流、分享,傳播有價(jià)值的東西。
③暴徒式編程:暴徒式編程是結(jié)對(duì)編程的一種方式,由一個(gè)人操作鍵盤,同時(shí)設(shè)置定時(shí),每隔一段時(shí)間換人。其他人就負(fù)責(zé)盯著大屏幕告訴他該怎么操作,這個(gè)也是一個(gè)很好的學(xué)習(xí)手段。
小波老師將在完整視頻中繼續(xù)為大家?guī)?lái)
更多精彩分享以及重構(gòu)的在線演示
點(diǎn)擊觀看完整視頻
本文首先會(huì)和大家分享當(dāng)前整個(gè)應(yīng)用生命周期的演變歷程,然后講解云計(jì)算模式下 DevOps 建設(shè)包含的過(guò)程、流程規(guī)范和標(biāo)準(zhǔn),最后講解云原生時(shí)代到來(lái)會(huì)帶來(lái)哪些改變,以及標(biāo)準(zhǔn)化的建設(shè)會(huì)有哪些改變和突破。
應(yīng)用的演變歷程
企業(yè)數(shù)字化轉(zhuǎn)型過(guò)程和云的迭代發(fā)展是相互作用的。在 2007 年之前主要用物理機(jī)來(lái)作為我們當(dāng)前應(yīng)用的載體。而在 2007 年,KVM 誕生,它能讓底層操作系統(tǒng)和一些虛擬的網(wǎng)絡(luò)設(shè)備做一些虛擬化的輸出。2007 年 - 2010 年是虛擬化發(fā)展較好的周期,VMware 和 openstack 是當(dāng)時(shí)的代表生態(tài)。到了 2013 年 Docker 開(kāi)服,云計(jì)算迎來(lái)了蓬勃發(fā)展的周期。2014 年,企業(yè)的部分業(yè)務(wù)開(kāi)始逐步遷移云上。2017 年后到今天為止,在云原生的模式下,開(kāi)發(fā)人員或者整個(gè) it 部門更聚焦在業(yè)務(wù)的發(fā)展上,所有我們不關(guān)心的部分可以全部由云來(lái)管理。云開(kāi)發(fā)不必關(guān)心開(kāi)發(fā)在哪里,云服務(wù)不關(guān)心調(diào)用到哪里,而云資源方面也不用關(guān)心運(yùn)行到了哪里。這就是從基礎(chǔ)設(shè)施上云到業(yè)務(wù)上云,再到當(dāng)前的全棧云,這樣的一條全企業(yè)數(shù)字化轉(zhuǎn)型之路。
在物理機(jī)階段,使用的是單體架構(gòu),這樣的架構(gòu)系統(tǒng)封閉、無(wú)法復(fù)用,且高度耦合,內(nèi)部交互復(fù)雜。而在第二階段,采用了面向服務(wù)的 SOA 架構(gòu),這種架構(gòu)通常需要 ESB 進(jìn)行系統(tǒng)集成,進(jìn)行應(yīng)用模塊解耦,需要統(tǒng)一部署。但是這種架構(gòu)通常需要較大規(guī)模的團(tuán)隊(duì),且可能存在職責(zé)割裂。第三階段是當(dāng)前使用的比較多的微服務(wù)架構(gòu),它能充分利用 DevOps,完全解耦能充分利用云化資源自動(dòng)彈性伸縮等特性,支持高可用,能升級(jí)、擴(kuò)容但不中斷業(yè)務(wù)。
這張圖片能較好的展示應(yīng)用的生命周期管理,以應(yīng)用為中心,在應(yīng)用之上是基礎(chǔ)資源管理層面,這個(gè)層面可以管理應(yīng)用對(duì)應(yīng)的資產(chǎn)、環(huán)境、資源、流水線、部署和監(jiān)控,這是以基礎(chǔ)資源為核心思想下 DevOps 的建設(shè)方向。隨著越來(lái)越云化和微服務(wù)化,我們關(guān)注的視角從基礎(chǔ)資源逐步轉(zhuǎn)成服務(wù)思想。
云計(jì)算模式下的 DevOps
在物理機(jī)時(shí)代,隨著業(yè)務(wù)的發(fā)展,可能會(huì)出現(xiàn)基礎(chǔ)設(shè)施增長(zhǎng),軟件復(fù)雜度提升,流量沖擊和更新頻率變高這些問(wèn)題?;A(chǔ)設(shè)施增長(zhǎng)和軟件復(fù)雜程度提升會(huì)給運(yùn)維帶來(lái)壓力,流量沖擊要求運(yùn)維的測(cè)試要有多樣的變化,更高的更新頻率要求研發(fā)人員的快速反饋以及更靈活的需求變更。
在這樣的情況下,DevOps 建設(shè)迫在眉睫,企業(yè)需要提升應(yīng)用交付的效率和質(zhì)量,需要越來(lái)越多樣化的應(yīng)用部署方式。DevOps 建設(shè)要首先要做的是敏捷的建設(shè),因此需要更靈活的需求管理工具,在整個(gè)應(yīng)用交付階段需要自動(dòng)化構(gòu)建和環(huán)境快速管理。然后在測(cè)試的階段,我們需要做自動(dòng)化測(cè)試,才能在流程中管控好質(zhì)量,另外還需要有一個(gè)統(tǒng)一的制品管理。從軟件開(kāi)發(fā)到應(yīng)用交付之間,需要有一套統(tǒng)一的制品庫(kù)將所有的制品進(jìn)行統(tǒng)一納管,基于統(tǒng)一的制品可以進(jìn)行智能化的驗(yàn)收測(cè)試。在這整個(gè)階段,核心準(zhǔn)則是版本控制一切,內(nèi)建質(zhì)量、自動(dòng)化,過(guò)程度量。
這個(gè)圖片是端到端的 DevOps 能力圖譜,建設(shè)的重點(diǎn)在圖譜下方的持續(xù)交付工具鏈。我們需要采取統(tǒng)一的代碼管理工具,幫助我們自動(dòng)化的提升代碼的質(zhì)量。在安全方面,我們也會(huì)運(yùn)用安全掃描工具集成到流程中,讓它進(jìn)行自動(dòng)編譯。另外,在持續(xù)部署階段,要做好數(shù)據(jù)庫(kù)的發(fā)布,對(duì)不同版本的接口做好管理,并結(jié)合一些好的自動(dòng)化的工具做自動(dòng)化測(cè)試。這些功能點(diǎn)需要一個(gè)交付部署流水線串連起來(lái)。
我們可以看到,在端到端的能力中會(huì)有很多步驟,也需要非常多的工具去執(zhí)行,如何將這些工具進(jìn)行很好的串連呢?在企業(yè)生產(chǎn)過(guò)程中,核心目標(biāo)有三項(xiàng):效率、質(zhì)量和成本,因此可以沿用制造業(yè)的流水線來(lái)幫助我們快速的生產(chǎn)軟件。流水線中我們需要關(guān)注 4 項(xiàng)指標(biāo):發(fā)布頻率、變更時(shí)長(zhǎng)、服務(wù)恢復(fù)時(shí)長(zhǎng)和變更失敗率。
云原生帶來(lái)的改變
云原生是一個(gè)復(fù)雜的東西,它包含開(kāi)發(fā)過(guò)程、應(yīng)用依賴、編排管理、流程管理、數(shù)據(jù)分析以及非常多的組件。在云計(jì)算的模式下,我們可以做到快速交付應(yīng)用、成果快速發(fā)布,但是我們交付的產(chǎn)品是否能給業(yè)務(wù)帶來(lái)增長(zhǎng),滿足客戶的需要呢?這就涉及到如何將應(yīng)用交付轉(zhuǎn)變?yōu)閮r(jià)值交付。通過(guò)可靠、可重復(fù)的流水線,快速進(jìn)行軟件生產(chǎn),提升應(yīng)用效率和軟件交付效率,這就是應(yīng)用交付。而價(jià)值交付是指能夠快速地響應(yīng)市場(chǎng)變化,在客戶需求不確定的情況下,生產(chǎn)出客戶滿意的軟件。
如何實(shí)現(xiàn)價(jià)值交付?要基于可靠可重復(fù)的流水線,簡(jiǎn)歷自動(dòng)化的應(yīng)用交付體系。將敏捷過(guò)程全面融入到 DevOps 體系中。架構(gòu)全面微服務(wù)轉(zhuǎn)型,基礎(chǔ)設(shè)施云化,讓開(kāi)發(fā)專注于業(yè)務(wù)開(kāi)發(fā)。將運(yùn)營(yíng)納入到 DevOps 范疇,實(shí)現(xiàn)數(shù)字化運(yùn)營(yíng)。
點(diǎn)擊觀看課程完整視頻。
DevOps 涉獵的范圍非常的廣泛,包括軟件研發(fā)全生命周期的方方面面,對(duì)于剛開(kāi)始涉及 DevOps 的人來(lái)說(shuō)會(huì)有種盲人摸象的感覺(jué),這正是 DevOps 轉(zhuǎn)型的一個(gè)難點(diǎn)。在 DevOps 轉(zhuǎn)型過(guò)程中,標(biāo)準(zhǔn)化是重要手段。那么,標(biāo)準(zhǔn)化關(guān)注的具體是什么內(nèi)容呢?
DevOps 的轉(zhuǎn)型目標(biāo)在于縮短前置時(shí)間,加快部署頻率,提高系統(tǒng)的可用性,減少服務(wù)恢復(fù)時(shí)間,降低變更失敗率。這就要求我們?cè)谠O(shè)計(jì)運(yùn)行平臺(tái)的時(shí)候,除了具備自動(dòng)恢復(fù)功能的以外,還要提供豐富的運(yùn)維監(jiān)控?cái)?shù)據(jù)以及強(qiáng)大的數(shù)據(jù)分析能力,這樣能夠幫助運(yùn)維人員在極短的時(shí)間之內(nèi)恢復(fù)服務(wù)。變更失敗的原因主要有 2 個(gè),一是功能質(zhì)量沒(méi)有達(dá)標(biāo),二是需求理解不到位。
圖片中是我們整理的一些標(biāo)準(zhǔn)化的關(guān)注點(diǎn)。作為產(chǎn)品經(jīng)理或業(yè)務(wù)分析的人員,需要關(guān)注需求如何順利到達(dá)研發(fā)團(tuán)隊(duì),并能夠適應(yīng)他們進(jìn)行敏捷的開(kāi)發(fā)。作為研發(fā)人員需要關(guān)注的點(diǎn)相對(duì)比較多,尤其是要關(guān)注配置信息標(biāo)準(zhǔn)化管理。
標(biāo)準(zhǔn)化的目的是為了實(shí)現(xiàn)自動(dòng)化,包括集成的自動(dòng)化、部署的自動(dòng)化、測(cè)試的自動(dòng)化和運(yùn)維的自動(dòng)化。下圖是一個(gè)典型的 DevOps 循環(huán)圖。我們認(rèn)為業(yè)務(wù)敏捷是前提,DevOps 流程是從敏捷型需求為起點(diǎn),經(jīng)過(guò)了運(yùn)維監(jiān)控這個(gè)最后的節(jié)點(diǎn)回到計(jì)劃,實(shí)現(xiàn)閉環(huán)。
編碼過(guò)程標(biāo)準(zhǔn)化的重點(diǎn)在于測(cè)試驅(qū)動(dòng)的開(kāi)發(fā),這也是敏捷要求的一個(gè)標(biāo)準(zhǔn),但是實(shí)際上能做到這個(gè)標(biāo)準(zhǔn)的團(tuán)隊(duì)并不是很多。測(cè)試驅(qū)動(dòng)開(kāi)發(fā)首先要面向接口做一些測(cè)試和開(kāi)發(fā),面向接口做測(cè)試的時(shí)候需要關(guān)注接口名稱、接口協(xié)議、接口參數(shù)名稱和類型、接受條件。其次我們需要關(guān)注數(shù)據(jù),包括每個(gè)接口輸入的數(shù)據(jù)以及其得出的結(jié)果。針對(duì)引用的相對(duì)復(fù)雜業(yè)務(wù)邏輯的其他服務(wù),需使用 mock 工具來(lái)減少依賴。每個(gè)測(cè)試用例的測(cè)試場(chǎng)景需要完整注釋。
最后我們總結(jié)一下前面的內(nèi)容:一、需求敏捷化是起點(diǎn)。二、TDD 開(kāi)發(fā)模式是快速迭代開(kāi)發(fā)時(shí)代保障軟件質(zhì)量基線的有效手段。三、注重環(huán)境配置文件的標(biāo)準(zhǔn)化,保證程序的可測(cè)試性。四、研發(fā)流程的標(biāo)準(zhǔn)化是建立自動(dòng)化 CI 、CD 流程的前提,而 CI 、CD 流程的自動(dòng)化是實(shí)現(xiàn) DevOps 的關(guān)鍵點(diǎn)。五、Jenkins 是實(shí)現(xiàn) CI 、CD 流程的有效工具,但是在處理復(fù)雜業(yè)務(wù)場(chǎng)景時(shí)還需要有其他合適工具的幫襯。六、服務(wù)器運(yùn)行環(huán)境的標(biāo)準(zhǔn)化,可以促進(jìn)流程腳本的標(biāo)準(zhǔn)化。
點(diǎn)擊觀看課程完整視頻。
由于“候補(bǔ)”了幾天一直沒(méi)動(dòng)靜,看到一張時(shí)間不理想的票,就先拿下了。但是,“候補(bǔ)”的票我還沒(méi)取消。12306 的系統(tǒng)能識(shí)別出,我已經(jīng)在同方向的列車上買過(guò)類似的票嗎?我的“候補(bǔ)”資格是不是系統(tǒng)自動(dòng)會(huì)忽略了? 感覺(jué),今年 12306 的系統(tǒng)算法,太黑盒了,黃牛沒(méi)譜,乘客沒(méi)底
沒(méi)有發(fā)違反推特規(guī)則
http://139.224.233.92/1.jpeg
鍵政號(hào)玩了幾天漲了 1000+fo 莫名其妙凍結(jié)了,1000+fo 沒(méi)了,不能做任何操作。 提交工單幫助客服郵件什么都不回復(fù)一個(gè)月了 這是不是被“民主了”
有沒(méi)有屌大的懂解凍 唯一一張比較出格的圖片: http://139.224.233.92/2.jpeg
請(qǐng)問(wèn) Twitter 有辦法批量取消關(guān)注未 follow 我的人嗎follow 加到 5000 多就被限制 follow 了,現(xiàn)在懶的手動(dòng)取消. . .
https://twitter.com/settings/your_twitter_data/twitter_interests/interest
在 Twitter 上,經(jīng)常會(huì)看到類似上圖這樣使用編號(hào) id 的賬號(hào),雖然名字、簡(jiǎn)介、推文看上去都挺正常,但總讓我感覺(jué)是水軍,所以我看到 id 就 block,不管他說(shuō)什么??
我想問(wèn)一下這種 id 是怎么來(lái)的?可以直接認(rèn)為是水軍嗎?
自動(dòng)登錄后提示:We have detected unusual activity on your account. For your security, your account has been locked until you change your password.
選擇開(kāi)始修改密碼會(huì)進(jìn)入:Help Center>Submit A Ticket>Report A Problem 這個(gè)頁(yè)面,
在這里點(diǎn)擊:RESET MY PASSWORD 會(huì)進(jìn)入 Find your Twitter account 的頁(yè)面,然后下一步就會(huì)回到上面的 Report A Problem 頁(yè)面
無(wú)限循環(huán)……
請(qǐng)教一下各位這樣該怎么辦?先謝謝了!
https://twitter.com/Songxwn
為什么大部分的推文底下就有翻譯按鈕,而個(gè)別的推文下面沒(méi)有翻譯選項(xiàng)呢?特別是有的小語(yǔ)種,沒(méi)有翻譯簡(jiǎn)直…
早上起床看國(guó)聯(lián)外卡,順便刷刷推特,發(fā)現(xiàn) tweetdeck 登不進(jìn)去,一直跳轉(zhuǎn)mobile.twitter.com 。下午短暫恢復(fù)了一段時(shí)間,現(xiàn)在又登不進(jìn)去了。twitter 網(wǎng)頁(yè)的廣告太多,又不想用第三方客戶端,只有 tweetdeck 可以用了,twitter 在搞毛。。
中文圈那種微博風(fēng)格的我實(shí)在感覺(jué)沒(méi)啥意思 不是發(fā)吃的自拍就是撩妹抖精靈或者無(wú)聊的雞湯段子
https://twitter.com/sharekuma_/status/1096226903713697793
像上面這個(gè)鏈接,不是轉(zhuǎn)發(fā)也不是引用,而是里面無(wú)框套了一層。 這是什么結(jié)構(gòu)?這個(gè)結(jié)構(gòu)的英文怎么說(shuō)?有沒(méi)有辦法快速跳到原貼?

若干月前在 Twitter 上誤設(shè)置了“將你發(fā)布的媒體內(nèi)容標(biāo)記為可能包含敏感內(nèi)容”,導(dǎo)致使用蘋果的小伙伴看不到我推文的圖片。如今想改回來(lái),但發(fā)現(xiàn)只能將新發(fā)布的推文設(shè)置為非敏感內(nèi)容。請(qǐng)問(wèn)有什么方法可以將之前發(fā)布的(或所有的)、標(biāo)記為敏感的內(nèi)容取消敏感標(biāo)記?(發(fā)布的內(nèi)容均為非敏感內(nèi)容)
機(jī)型:mi8 系統(tǒng):MIUI 10 Twitter 版本:7.78.0 安裝途徑:Google Play 現(xiàn)象:點(diǎn)開(kāi)一條推文之后直接閃退
不知道有沒(méi)有 v 友遇到一樣的問(wèn)題
受夠了被貼標(biāo)簽,受夠了審查和禁言,現(xiàn)在只想找一個(gè)地方暢所欲言。本人目前在國(guó)內(nèi)做 DevOps,推特的日常內(nèi)容會(huì)偏向科技和時(shí)事的吐槽,歡迎互 fo。 ID: @ tacehtoel 傳送門: https://twitter.com/tacehtoel