一.說明
最開始培訓完入行的2年里,進的幾家公司和面試遇到的基本都是機器在200個虛擬機以下,運維加上我也就1-2個人。
這種都是自己說了算,做了什么操作自己記住就行了,添加權限也都是開發說一下這邊就給加上了,流程配合之間都靠嘴對嘴的傳遞,當然也可能用qq和微信。
工作環境還是很重要的,現在待的項目運維多的時候5個,虛擬機300往上,還有一大堆別的雲產品要維護。這就有必要進行分工了,而不是大家誰閑着就做,那會導致需求人找不到誰在負責,而且負責人也會來回變動。
那需求就來了,根據日常工作發現如下問題:
1.開發不知道找誰能把這件事做成
2.開發來申請添加權限、用qq之類的進行說明描述
3.因為每個人負責一塊,都參與工作,沒人知道整體進度
4.某個運維做了一些操作別人不太清楚
5.這塊他負責的,現在他請假了,接手后不知道怎么做
那看看開發怎么怎么解決上述問題的:
1.產品經理有需求要提jira
2.在jira上有任務表,可以看到每個人接到的任務,涉及哪一塊
3.代碼寫完后合並到master分支要開發組長去確認,注釋也寫的很多
具體還會有相應的工作流,將每個需求都從頭到尾追蹤好,后面上線測試環境甚至生產環境都有相應的管理流程。
二.初代設計
最開始想的是在內部confluence(一個筆記網站)上記錄下我們有哪些任務要做,按照日期划分,每天都記錄下,任務名稱后面寫上名字。
當然對於外部的需求,例如加權限,解決一些jenkins發版上的配置錯誤等等都是完成后來這里補。
現在想想真的很蠢,這記錄和沒記錄的區別完全不大,雖然知道誰什么時間做了哪件事,但維護起來實在費心費力,和其它組的交互也是原始的嘴對嘴交流。
同時這個也完全看不出[任務進度]、[誰在划水]、[某類任務數量]、[當月故障數量]等等,也就是只記錄了,但統計非常困難,需要人工去數。
在發現開發用jira后,探索了一下,發現確實很好用,可以實現我們的需求。通過搭配釘釘通知和看版,再建立好清晰完善的工作流程,可以最大效率避免在開發流程上花時間。
三.效果展示
用jira建立2個項目,一個是對外工單用於外部需求的處理,一個是對內工單只內部使用記錄任務。
給區分開是因為夾雜在一起會很亂,內部都好說就幾個人大家都按照任務進行類別創建,比如購買服務器就建立[資金管理]任務,處理故障就建立[故障處理]任務。
但開發是不管這些的,人家不管是申請權限、處理報錯、申請資源全都是[故障處理]這個默認問題類型。所以要精簡為2-3類最好,這里是權限和其它類型。
外部任務:
1.權限申請,這里權限申請會搭配釘釘腳本做超時通知,用戶要定時續期權限,當然可以調整更大的選項,例如6個月。單獨添加申請人選項,是因為申請者可能還沒有jira,或者是外包人員
當權限超過規定期限,會給jira的工單發布者和管理員均發送一個釘釘消息
2.其它任務
內部任務:
1.服務管理,這里是內部的任務,例如發版、搭建服務、備份數據等等操作。對於一個大任務一定要拆開成版本,也就是合集,把任務去細化。
不然你隨便寫個k8s優化那就假大空了,沒有一個目標和划水沒有區別,做2天感覺煩躁就懶得做了,就沒有意義了。同時對於生產等重要操作,要編寫配套任務的《操作用例》,你沒猜錯,就是對標測試的《測試用例》。因為運維不求快求穩,文檔操作不出事,比出現問題后補救要成本小得多。
2.報警可以選擇幾個類別,這里后面會做zabbix聯動建立jira任務,其實zabbix本身就可以針對每條報警做處理和記錄,但放到jira是統一管理了。
3.其它類別,都是自己人,可以把問題做的細致一點,這樣利於后面用jira的篩選器做統計。比如統計某人這個月發版多少次,鼠標勾選幾下就出來結果了。
像我自從工單建立后,正式生產發版一共10次
四.工單運作流程
對於外部工單,設置為默認經辦人是運維組長,到他那里后,看到釘釘通知,再進行后續任務分配,將人員調動起來。
可以根據jira中查詢每個人的任務量,再到grafana上進行綜合展示,這里還沒做完,后續再補圖,相當於做內部的《看板》,將大家的任務狀態用大盤做可視化。
這樣就會通過大屏看板一目了然,可以找到誰這周任務最少,或者做的拖沓,本來[ELK日志分析]建設這個大項目,里面有3個jira任務,預計是14天完成,結果第一個人任務2周過去了還沒完結,說明有問題。
對於這種,說明任務太有挑戰性,就多給他分配外部工單進行鍛煉,騰出其它組員的時間,晚上加班/值班,也都多安排他來。工單盡量要區分清楚,用強制選項的填選來規定,而不是都在備注里填,很多人懶得去備注里寫。
通知腳本
我是編寫python腳本定時去獲取jira上每個人的最新任務,進行對應人釘釘通知,每個人一個私有釘釘群,由其他運維同事拉一個3人組,加上機器人后再退掉即可,這樣省的麻煩別的同事了。
效果如下,這樣每個人就有一個私人通知的釘釘群,未來也可以增加入gitlab等等其它的私人通知,所以叫[信息通知小助手],群名稱叫[辦公信息通知]。
圖中可以看到第一個是我發布的任務別人完成了,當發布任務時,被發布者會收到這個信息,會寫明誰發布的和一些簡要說明。當接單人員完成后,發布者可以知道完成了,具體信息也都會加到附件和評論里,方便查閱。
當然也可以加一些別的工作流程,例如增加一個開始任務也進行通知一下,尤其對開發流程有復雜的工作流,當測試環境上線需要通知測試進行業務功能測試、測試人員完成后確認再通知開發人員進行uat環境上線,這就要每個環境都通知。
申請機器人
1.先添加一個機器人
2.選擇自定義類型
3.選擇關鍵字,這里意思是發送的信息,必須帶上這些關鍵字才能發成功,也就是圖片里的通知:xxx開頭。復制好token,寫到后續的配置文件里去。
具體腳本
定時跑的的腳本,可以設置三分鍾一次,那就3分鍾檢查一次有沒有新任務。
jira_notice.py
#!/usr/bin/python3
#釘釘token關鍵字jira
import datetime, os, sys, json, requests, configparser
from jira import JIRA
from datetime import datetime
from datetime import timedelta
#讀取配置文件
CONF_SITE="/data/tools/python_lib/script_conf.cfg"
cfg = configparser.ConfigParser()
cfg.read(CONF_SITE)
#[jira的url、jira賬號、jira密碼、]
JIRA_URL = cfg['jira']['jira_url']
JIRA_USERNAME = cfg['jira']['jira_username']
JIRA_PASSWORD = cfg['jira']['jira_password']
ISSUE_INFO_FILE = cfg['jira']['issue_info_file']
ISSUE_INFO_SIZE = cfg['jira']['issue_info_size']
START_STATUS_LIST = cfg['jira']['start_status'].split(',')
STOP_STATUS_LIST = cfg['jira']['stop_status'].split(',')
DD_URL = cfg['dingding']['dd_url']
def write_cfg(file_dict):
#將字典寫入到配置文件里
with open(ISSUE_INFO_FILE, 'w') as fp:
fp.write(str(file_dict))
def read_cfg():
#讀取配置文件內容
with open(ISSUE_INFO_FILE, 'r') as fp:
data = fp.read()
file_dict = eval(data)
return file_dict
def new_notice(notice_url, nowtime, title, is_summary, is_project, is_type, notice_type, is_notice, key_name):
#[拼接字符串]
msg = """### %s \n
> 時間: %s \n
> 概要: %s \n
> 項目: %s \n
> 類型:%s \n
> %s: %s \n
> 地址: [任務地址](%s/browse/%s?) \n
"""
headers = {'Connection': 'close', "Content-Type": "application/json"}
data = {"msgtype": "markdown",
"markdown": {
"title": title,
"text": msg %(title, nowtime, is_summary, is_project, is_type, notice_type, is_notice, JIRA_URL, key_name)
}
}
print(title)
print(notice_url)
r = requests.post(notice_url, data=json.dumps(data), headers=headers, verify=False)
print(r.text)
def jcpzrw_notice(notice_url, nowtime, is_summary, title, is_created, is_apply, is_duration, key_name):
#[拼接字符串]
msg = """### %s \n
> 時間: %s \n
> 概要: %s \n
> 申請日期: %s \n
> 申請人: %s \n
> 使用時長:%s \n
> 地址: [任務地址](%s/browse/%s?) \n
"""
headers = {'Connection': 'close', "Content-Type": "application/json"}
data = {"msgtype": "markdown",
"markdown": {
"title": title,
"text": msg %(title, nowtime, is_summary, is_created, is_apply, is_duration, JIRA_URL, key_name)
}
}
print(title)
r = requests.post(notice_url, data=json.dumps(data), headers=headers, verify=False)
print(r.text)
def main():
#[時間]
nowtime = datetime.now()
nowtime = str(nowtime.strftime('%Y-%m-%d %H:%M:%S'))
#讀取記錄
if os.path.exists(ISSUE_INFO_FILE):
issue_data_dict = read_cfg()
else:
issue_data_dict = {}
#查詢最近24小時內所有更新的issu
jira = JIRA(basic_auth=(JIRA_USERNAME, JIRA_PASSWORD), options = {'server': JIRA_URL})
query_sql = 'updated >= -24h ORDER BY updated DESC'
query_info = jira.search_issues(query_sql ,maxResults=100000)
print("循環檢查jira任務")
for i in query_info: #循環任務
key_name = i.key #不能直接用,直接用是一個對象
issue = jira.issue(key_name)
is_summary = str(issue.fields.summary) #概要
is_project = str(issue.fields.project) #項目名
is_type = str(issue.fields.issuetype) #類型
is_assignee = str(issue.fields.assignee) #經辦人
is_creator = str(issue.fields.creator) #創建人
is_status = str(issue.fields.status) #狀態
#查看狀態是否是新建或者結束
if is_status in STOP_STATUS_LIST:
#查看是否在記錄中
if key_name in issue_data_dict.keys():
if issue_data_dict[key_name][1] == "start": #issue從開始變為結束通知
one_user = "creator"
else:
one_user = "none"
else:
one_user = "creator"
job_status = "stop"
else:
#查看是否在記錄中
if key_name in issue_data_dict.keys():
if is_assignee != issue_data_dict[key_name][0]: #經辦人變了通知
one_user = "assignee"
elif issue_data_dict[key_name][1] == "stop": #狀態重置了通知
one_user = "assignee"
else:
one_user = "none"
else:
one_user = "assignee"
job_status = "start"
#把記錄寫入到字典中
issue_data_dict[key_name] = [is_assignee, job_status]
jira_name_list = cfg.sections()
#發送通知
if one_user == "assignee":
if is_assignee in jira_name_list:
dd_token = cfg[is_assignee]['dd_token']
notice_url = DD_URL + dd_token
title = "通知: jira新增任務" + key_name
new_notice(notice_url, nowtime, title, is_summary, is_project, is_type, "報告人", is_creator, key_name)
else:
print(key_name + "中報告人的釘釘並未被記錄")
elif one_user == "creator":
if is_creator in jira_name_list:
dd_token = cfg[is_creator]['dd_token']
notice_url = DD_URL + dd_token
title = "通知: jira完成任務" + key_name
new_notice(notice_url, nowtime, title, is_summary, is_project, is_type, "經辦人", is_assignee, key_name)
else:
print(key_name + "經辦人的釘釘並未被記錄")
else:
print(key_name + "已經通知過,跳過通知")
#清理字典文件,不要太龐大
while len(issue_data_dict) > int(ISSUE_INFO_SIZE):
tmp_key = list(issue_data_dict.keys())[0]
if tmp_key == "JCPZRW_Usage_list":
continue
else:
del issue_data_dict[tmp_key]
write_cfg(issue_data_dict)
main()
配置文件腳本,因為我這里對所有pyton腳本進行了統一管理,凡是配置都放到固定文件里,就單獨做了一個文件。這里填寫jira地址和賬號密碼,用於調用API,不一定非要管理賬號,只要可以看到所有項目即可,因為要統計項目信息。
最后面的張三李四是每個人的釘釘顯示中文名稱,jira賬號名和他的釘釘機器人的token號。1000是臨時文件保存多少issue信息,防止過大。后面的status是jira工作流的狀態信息,一般《新建》代表任務開始,《關閉》代表任務完成,這里默認即可。最后notice_user表示權限過期時候通知哪些管理員。
script_conf.cfg
[jira]
jira_url = http://10.0.1.1:8080
jira_username = admin
jira_password = 123456
issue_info_file = /tmp/jira_issue_info.dict
issue_info_size = 1000
start_status = 待辦,待處理,已登記,新建,NEW
stop_status = DONE,線上驗證通過,關閉,問題關閉,已驗收,已關閉
jcpzrw_notice_user = 張三,李四
[dingding]
dd_url = https://oapi.dingtalk.com/robot/send?access_token=
[張三]
jira_name=zhangsan
dd_token=cdasdsadasd2dadas
[李四]
jira_name=lisi
dd_token=adasdadada