注:本文要求讀者對(duì)Ansible和 Jenkins有一定的認(rèn)識(shí)。
題記: 幸福的家庭都是相似的 不幸的家庭各有各的不幸
行業(yè)內(nèi)各巨頭的自動(dòng)化運(yùn)維架構(gòu)都各種功能各種酷炫票编,如下圖月腋,讓人可望不可及◇凹埽現(xiàn)在最終的樣子大家都知道了,但問(wèn)題是如何根據(jù)自己團(tuán)隊(duì)當(dāng)前的情況一步步向那個(gè)目標(biāo)演進(jìn)榆骚?
筆者所在團(tuán)隊(duì)辜窑,三個(gè)半開(kāi)發(fā),要維護(hù)幾十臺(tái)云機(jī)器寨躁,部署了十來(lái)個(gè)應(yīng)用穆碎,這些應(yīng)用90%都是遺留系統(tǒng)。應(yīng)用系統(tǒng)的編譯打包基本在程序員自己的電腦上职恳。分支管理也清一色的 dev 分支開(kāi)發(fā)所禀,測(cè)試通過(guò)后,再合并到 master 分支放钦。生產(chǎn)環(huán)境的應(yīng)用配置要登錄上具體的機(jī)器看才知道色徘,更不用說(shuō)配置中心及配置版本化了。
對(duì)了操禀,連基本的機(jī)器級(jí)別的基礎(chǔ)監(jiān)控都沒(méi)有褂策。
我平時(shí)的工作是 50% 業(yè)務(wù)開(kāi)發(fā),50% 運(yùn)維颓屑。面對(duì)這么多問(wèn)題斤寂,我就想啊,如何在低成本情況下實(shí)現(xiàn)自動(dòng)化運(yùn)維揪惦。本文就是總結(jié)我在這方面一些經(jīng)驗(yàn)和實(shí)踐遍搞。希望對(duì)讀者有幫助。
別說(shuō)話器腋,先上監(jiān)控和告警
事情有輕重緩急溪猿,監(jiān)控和告警是我覺(jué)得一開(kāi)始就要做的,即使業(yè)務(wù)開(kāi)發(fā)被拖慢纫塌。只有知道了當(dāng)前的情況诊县,你才好做下一步計(jì)劃。
現(xiàn)在市面上監(jiān)控系統(tǒng)很多:Zabbix措左、Open-Falcon依痊、Prometheus。最終作者選擇了 Prometheus媳荒。因?yàn)椋?/p>
- 它是拉模式的
- 它方便使用文本方式來(lái)配置抗悍,有利于配置版本化
- 插件太多了,想要監(jiān)控什么钳枕,基本都會(huì)有現(xiàn)成的
- 以上三者缴渊,我基本都要重新學(xué),我為什么不學(xué)一個(gè) Google SRE 書(shū)上推薦的呢鱼炒?
之前我們已經(jīng)介紹過(guò)衔沼,人少機(jī)器多,所以昔瞧,安裝 Prometheus 的過(guò)程也必須要自動(dòng)化指蚁,同時(shí)版本化。筆者使用的是 Ansible + Git 實(shí)現(xiàn)自晰。最終樣子如下:
這里需要簡(jiǎn)單介紹一下:
- Prometheus Server 負(fù)責(zé)監(jiān)控?cái)?shù)據(jù)收集和存儲(chǔ)
- Prometheus Alert manager 負(fù)責(zé)根據(jù)告警規(guī)則進(jìn)行告警凝化,可集成很多告警通道
- node-exporter 的作用就是從機(jī)器讀取指標(biāo),然后暴露一個(gè) http 服務(wù)酬荞,Prometheus 就是從這個(gè)服務(wù)中收集監(jiān)控指標(biāo)搓劫。當(dāng)然 Prometheus 官方還有各種各樣的 exporter。
使用 Ansible 作為部署工具的一個(gè)好處是太多現(xiàn)成的 role 了混巧,安裝Prometheus 時(shí)枪向,我使用的是現(xiàn)成的:prometheus-ansble
有了監(jiān)控?cái)?shù)據(jù)后,我們就可以對(duì)數(shù)據(jù)進(jìn)行可視化咧党,Grafana 和 Prometheus 集成得非常好秘蛔,所以,我們又部署了 Grafana:
在 Grafana 上查看 nodex-exporter 收集的數(shù)據(jù)的效果圖大概如下:
可是傍衡,我們不可能24小時(shí)盯著屏幕看CPU負(fù)載有沒(méi)有超吧深员?這時(shí)候就要上告警了,Promehtues 默認(rèn)集成了 N 多告警渠道蛙埂”嬉海可惜沒(méi)有集成釘釘。但也沒(méi)有關(guān)系箱残,有好心的同學(xué)開(kāi)源了釘釘集成 Prometheus 告警的組件:prometheus-webhook-dingtalk滔迈。接著,我們告警也上了:
完成以上工作后被辑,我們的基礎(chǔ)監(jiān)控的架子就完成了燎悍。為我們后期上 Redis 監(jiān)控、JVM 監(jiān)控等更上層的監(jiān)控做好了準(zhǔn)備盼理。
配置版本化要從娃娃抓起
在搭建監(jiān)控系統(tǒng)的過(guò)程中谈山,我們已經(jīng)將配置抽離出來(lái),放到一個(gè)單獨(dú)的代碼倉(cāng)庫(kù)進(jìn)行管理宏怔。以后所有部署奏路,我們都會(huì)將配置和部署邏輯分離畴椰。
關(guān)于如何使用 Ansible 進(jìn)行配置管理,可以參考這篇文章:How to Manage Multistage Environments with Ansible 鸽粉。我們就是使用這種方式來(lái)組織環(huán)境變量的斜脂。
├── environments/ # Parent directory for our environment-specific directories
│ │
│ ├── dev/ # Contains all files specific to the dev environment
│ │ ├── group_vars/ # dev specific group_vars files
│ │ │ ├── all
│ │ │ ├── db
│ │ │ └── web
│ │ └── hosts # Contains only the hosts in the dev environment
│ │
│ ├── prod/ # Contains all files specific to the prod environment
│ │ ├── group_vars/ # prod specific group_vars files
│ │ │ ├── all
│ │ │ ├── db
│ │ │ └── web
│ │ └── hosts # Contains only the hosts in the prod environment
│ │
│ └── stage/ # Contains all files specific to the stage environment
│ ├── group_vars/ # stage specific group_vars files
│ │ ├── all
│ │ ├── db
│ │ └── web
│ └── hosts # Contains only the hosts in the stage environment
│
現(xiàn)階段,我們所有的配置都以文本的方式存儲(chǔ)触机,將來(lái)要切換成使用Consul做配置中心帚戳,也非常的方便,因?yàn)?Ansible2.0以上的版本已經(jīng)原生集成了consule: consul_module
Tips: Ansible 的配置變量是有層次的儡首,這為我們的配置管理提供了非常大的靈活性片任。
Jenkins 化:將打包交給 Jenkins
我們要將所有的項(xiàng)目的打包工作交給 Jenkins。當(dāng)然蔬胯,現(xiàn)實(shí)中我們是先將一些項(xiàng)目放到 Jenkins 上打包对供,逐步將項(xiàng)目放上 Jenkins。
首先我們要有 Jenkins氛濒。搭建 Jenkins 同樣有現(xiàn)成的 Ansible 腳本:ansible-role-jenkins犁钟。注意了,在網(wǎng)上看到的大多文章告訴你 Jenkins 都是需要手工安裝插件的泼橘,而我們使用的這個(gè) ansible-role-jenkins 實(shí)現(xiàn)了自動(dòng)安裝插件涝动,你只需要加一個(gè)配置變量 jenkins_plugins 就可以了,官方例子如下:
---
- hosts: all
vars:
jenkins_plugins:
- blueocean
- ghprb
- greenballs
- workflow-aggregator
jenkins_plugin_timeout: 120
pre_tasks:
- include_tasks: java-8.yml
roles:
- geerlingguy.java
- ansible-role-jenkins
搭建好 Jenkins 后炬灭,就要集成 Gitlab 了醋粟。我們?cè)瓉?lái)就有Gitlab了,所以重归,不需要重新搭建米愿。如何集成就不細(xì)表了,網(wǎng)絡(luò)上已經(jīng)很多文章鼻吮。
最終 Jenkins 搭建成以下這個(gè)樣子:
關(guān)于 Jenkins master 與 Jenkins agent 的連接方式育苟,由于網(wǎng)絡(luò)環(huán)境各不相同,網(wǎng)上也有很多種方式椎木,大家自行選擇適合的方式违柏。
好,現(xiàn)在我們需要告訴 Jenkins 如何對(duì)我們的業(yè)務(wù)代碼進(jìn)行編譯打包香椎。有兩種方法:
- 界面上設(shè)置
- 使用 Jenkinsfile:類似于 Dockerfile 的一種文本文件漱竖,具體介紹:Using a Jenkinsfile
作者毫不猶豫地選擇了第2種,因?yàn)橐皇抢诎姹净蠓ィ欢庆`活馍惹。
Jenkinsfile 類似這樣:
pipeline {
agent any
stages {
stage('Build') {
steps {
sh './gradlew clean build'
archiveArtifacts artifacts: '**/target/*.jar', fingerprint: true
}
}
}
}
那么 Jenkinsfile 放哪里呢?和業(yè)務(wù)代碼放在一起,類似這樣每個(gè)工程各自管理自己的 Jenkinsfile:
這時(shí)万矾,我們就可以在 Jenkins 上創(chuàng)建一個(gè) pipleline Job了:
關(guān)于分支管理悼吱,我們?nèi)松伲粤急罚ㄗh所有項(xiàng)目統(tǒng)一在 master 分支進(jìn)行開(kāi)發(fā)并發(fā)布后添。
讓 Jenkins 幫助我們執(zhí)行 Ansible
之前我們都是在程序員的電腦執(zhí)行 Ansible 的,現(xiàn)在我們要把這項(xiàng)工作交給 Jenkins们颜。具體操作:
- 在 Jenkins 安裝 Ansible 插件
- 在 Jenkinsfile 中執(zhí)行
withCredentials([sshUserPrivateKey(keyFileVariable:"deploy_private",credentialsId:"deploy"),file(credentialsId: 'vault_password', variable: 'vault_password')]) {
ansiblePlaybook vaultCredentialsId: 'vault_password', inventory: "environments/prod", playbook: "playbook.yaml",
extraVars:[
ansible_ssh_private_key_file: [value: "${deploy_private}", hidden: true],
build_number: [value: "${params.build_number}", hidden: false]
]
}
這里需要解釋下:
-
ansiblePlaybook
是 Jenkins ansible 插件提供的 pipeline 語(yǔ)法,類似手工執(zhí)行:ansible-playbook
猎醇。 -
withCredentials
是 Credentials Binding 插件的語(yǔ)法窥突,用于引用一些敏感信息,比如執(zhí)行 Ansible 時(shí)需要的 ssh key 及 Ansible Vault 密碼硫嘶。 - 一些敏感配置變量阻问,我們使用 Ansible Vault 技術(shù)加密。
Ansible 腳本應(yīng)該放哪沦疾?
我們已經(jīng)知道各個(gè)項(xiàng)目各自負(fù)責(zé)自己的自動(dòng)化構(gòu)建称近,所以,Jenkinfile 就放到各自項(xiàng)目中哮塞。那項(xiàng)目的部署呢刨秆?同樣的道理,我們覺(jué)得也應(yīng)該由各個(gè)項(xiàng)目自行負(fù)責(zé)忆畅,所以衡未,我們的每個(gè)要進(jìn)行部署的項(xiàng)目下都會(huì)有一個(gè) ansible
目錄,用于存放 Ansible 腳本家凯。類似這樣:
但是缓醋,怎么用呢?我們會(huì)在打包階段將 Ansible 目錄進(jìn)行 zip 打包绊诲。真正部署時(shí)送粱,再解壓執(zhí)行里面的 playbook。
快速為所有的項(xiàng)目生成 Ansible 腳本及Jenkinsfile
上面掂之,我們將一個(gè)項(xiàng)目進(jìn)行 Jenkins 化和 Ansible 化抗俄,但是我們還有很多項(xiàng)目需要進(jìn)行同樣的動(dòng)作∈澜ⅲ考慮到這是體力活橄镜,而且以后我們還會(huì)經(jīng)常做這樣事,所以筆者決定使用 cookiecutter 技術(shù)自動(dòng)生成 Jenkinsfile 及 Ansible 腳本冯乘,創(chuàng)建一個(gè)項(xiàng)目洽胶,像這樣:
小結(jié)
我們小團(tuán)隊(duì)的自動(dòng)化運(yùn)維實(shí)施的順序大概為:
- 上基礎(chǔ)監(jiān)控
- 上 Gitlab
- 上 Jenkins,并集成 Gitlab
- 使用 Jenkins 實(shí)現(xiàn)自動(dòng)編譯打包
- 使用 Jenkins 執(zhí)行 Ansible
以上只是一個(gè)架子,基于這個(gè)“架子”姊氓,就可以向那些大廠的高大上的架構(gòu)進(jìn)行演進(jìn)了丐怯。比如:
- CMDB的建設(shè):我們使用 ansible-cmdb 根據(jù) inventory 自動(dòng)生成當(dāng)前所有機(jī)器的情況
- 發(fā)布管理:Jenkins 上可以對(duì)發(fā)布的每個(gè)階段進(jìn)行定制。藍(lán)綠發(fā)布等發(fā)布方式可以使用通過(guò)修改 Ansible 腳本和 Inventory 實(shí)現(xiàn)翔横。
- 自動(dòng)擴(kuò)縮容:通過(guò)配置 Prometheus 告警規(guī)則读跷,調(diào)用相應(yīng) webhook 就可以實(shí)現(xiàn)
- ChatOps: ChatOps實(shí)戰(zhàn)
以上就是筆者關(guān)于自動(dòng)化運(yùn)維的一些實(shí)踐。還在演進(jìn)路上禾唁。希望能與大家交流效览。