天天看點

python自動化架構 部署到伺服器_持續傳遞之Jenkins+Ansible+Python搭建自動化部署架構(win版)...

前言

無論是為新需求添加的代碼,還是靜态配置的變更,應用的任何變動都要經過部署這道工序才能最終落地。但通常,新的部署意味着應用重新開機、服務中斷。工程師和測試人員經常在深夜搞得筋疲力盡,甚至焦頭爛額。進入持續傳遞的時代後,這個痛點隻會更加突顯,因為持續傳遞意味着持續部署。例如,在測試環境小時級的持續內建場景中,如果沒有辦法将部署過程流程化、自動化,顯然會頻繁打斷最終的傳遞過程,大幅降低開發測試效率。

是以,我們想要的應該是:一個易用、快速、穩定、容錯力強,必要時有能力迅速復原的部署系統。

部署的需求

單機部署過程高度抽象後其實就三個步驟:在目标機器上執行指令停掉運作中的服務

把提前準備好的變更包傳上機器覆寫原來的目錄

運作指令把服務再跑起來

假設我們實作了一個自動部署程式,簡單地順序執行上面的步驟,讓我們一起來檢驗是否能滿足釋出的需求:易用:執行腳本就好,填入參數,一鍵執行。

快速:自動化肯定比手工快,并且有提升空間。比如,因為有版本的概念,我們可以跳過相同版本的部署,或是某些步驟。

穩定:因為這個程式邏輯比較簡單,而且執行步驟并不多,沒有交叉和并行,是以穩定性也沒什麼大的挑戰。

容錯性強:表現一般,腳本碰到異常狀況隻能停下來,但因為版本間是隔離的,不至于弄壞老的服務,通過人工介入仍能恢複。

復原順滑:因為每個版本都是完整的可執行産物,是以復原可以視作使用舊版本重新做一次部署。甚至我們可以在目标機器上緩存舊版本産物,實作超快速復原。

通過這個程式的簡單執行過程,我們可以看到這套流程的簡單實作,基本滿足了我們部署的需求。而且,可以通過添加更複雜的控制流,獲得更大的提升空間。

而如今架構基本上告别了單點世界,面向叢集的部署帶來了更高次元的問題。當部署的目标是一組機器而不是一台機器時,主要問題就變成了如何協調整個過程。比如,追蹤、同步一組機器目前部署進行到了哪一步,編排叢集的部署指令就成為了更核心功能。

落地方案

技術架構

主要特點使用 Jenkins 作為一站式部署平台,友善選擇參數,自動協調各主機,自動運作部署指令,自動通知等

支援快速復原指定舊版本

支援面向叢集進行編排、追蹤和同步任務

實作釘釘自動化通知及跳轉功能

技術選型執行引擎:Ansible

自動通知:釘釘webhook & python

Jenkins 插件:Shell:執行 shell 腳本

Active Choices Plugin:動态互動參數

AnsiColor:彩色輸出,非必須

環境配置Ansible: 2.9.0

Python: 2.7.5

CentOS: 7.6

Java: 1.8.0_73

Jenkins: 2.164.3

預備知識

Ansible

Ansible是什麼?Ansible 是一個自動化運維管理工具,支援 Linux/Windows 跨平台的配置管理,任務分發等操作,可以幫我們大大減少在變更環境時所花費的時間。與其他三大主流的配置管理工具 Chef、Puppet、Salt 相比,Ansible 最大的特點在于“agentless”,即無需在目标機器裝安裝 agent 程序,即可通過 SSH 或者 PowerShell 對一個環境中的叢集進行中心化的管理。

是以,這個“agentless” 特性,可以大大減少我們配置管理平台的學習成本,尤其适合于第一次嘗試使用此類配置管理工具。

Ansible能做什麼?

正如其他配置管理工具一樣,Ansible 可以幫助我們完成一些批量任務,或者完成一些需要經常重複的工作比如:同時在 100 台伺服器上安裝 nginx 服務,并在安裝後啟動它們

比如:将某個檔案一次性拷貝到 100 台伺服器上

比如:每當有新伺服器加入工作環境時,你都要為新伺服器部 redis 服務,也就是說你需要經常重複的完成相同的工作

這些場景中我們都可以使用到 Ansible

Ansible架構

Ansible工作原理

Ansible特性子產品化:調用特定的子產品,完成特定任務

有 Paramiko,PyYAML,Jinja2(模闆語言)三個關鍵子產品

支援自定義子產品

基于 Python 語言實作

部署簡單,基于 python 和 SSH(預設已安裝),agentless

安全,基于 OpenSSH

支援 playbook 編排任務

幂等性:一個任務執行1遍和執行n遍效果一樣,不因重複執行帶來意外情況

無需代理不依賴 PKI(無需ssl)

可使用任何程式設計語言寫子產品

YAML 格式,編排任務,支援豐富的資料結構

較強大的多層解決方案

Ansible主要組成部分PLAYBOOKS:任務劇本(任務集),編排定義 Ansible 任務集的配置檔案,由 Ansible 順序依次執行,通常是 JSON 格式的 YML 檔案

INVENTORY:Ansible 管理主機的清單 /etc/anaible/hosts

MODULES:Ansible 執行指令的功能子產品,多數為内置的核心子產品,也可自定義, ansible-doc–l 可檢視子產品

PLUGINS:子產品功能的補充,如連接配接類型插件、循環插件、變量插件、過濾插件等,該功能不常用

API:供第三方程式調用的應用程式程式設計接口

ANSIBLE:組合 INVENTORY、 API、 MODULES、PLUGINS 的綠框,可以了解為是 Ansible 指令工具,其為核心執行工具

注意事項執行 Ansible 的主機一般稱為主要端,中控,master 或堡壘機

主要端 Python 版本需要2.6或以上

被控端 Python 版本小于2.4需要安裝 python-simplejson

被控端如開啟 SELinux 需要安裝 libselinux-python

windows 不能做為主要端

具體實作

環境規劃

搭建 Master 環境(Linux)

這裡以 Centos 7.x yum安裝為例:# yum install ansible

檢視版本:# ansible --version

ansible 2.9.0

config file = /etc/ansible/ansible.cfg

configured module search path = [u'/root/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']

ansible python module location = /usr/lib/python2.7/site-packages/ansible

executable location = /usr/bin/ansible

python version = 2.7.5 (default, Jun 20 2019, 20:27:34) [GCC 4.8.5 20150623 (Red Hat 4.8.5-36)]

配置檔案:

配置檔案描述/etc/ansible/ansible.cfg主配置檔案,配置ansible工作特性

/etc/ansible/hosts主機清單

/etc/ansible/roles/存放角色的目錄

/usr/bin/ansible主程式,臨時指令執行工具

/usr/bin/ansible-doc檢視配置文檔,子產品功能檢視工具

/usr/bin/ansible-galaxy下載下傳/上傳優秀代碼或Roles子產品的官網平台

/usr/bin/ansible-playbook定制自動化任務,編排劇本工具

/usr/bin/ansible-pull遠端執行指令的工具

/usr/bin/ansible-vault檔案加密工具

/usr/bin/ansible-console基于Console界面與使用者互動的執行工具

搭建受控端環境(window)

主機要求Ansible 從 1.7+ 版本開始支援 Windows,但前提是管理機必須為 Linux 系統,遠端主機的通信方式也由SSH變更為PowerShell,同時管理機必須預安裝 Python 的 Winrm 子產品,方可和遠端 Windows 主機正常通信,但 PowerShell 需4.0+版本且Management Framework 4.0+版本。

Ansible 可以管理包括 Windows 7、8.1和10的桌面作業系統以及包括Windows Server 2008、2008 R2、2012、2012 R2、2016和2019的伺服器作業系統。

簡單總結如下:管理機必須為 Linux 系統且需預安裝 Python 和 Winrm 子產品

底層通信基于 PowerShell,版本為3.0+,Management Framework 版本為4.0+

遠端主機開啟 Winrm 服務

更新 Upgrading PowerShell 和 .NET Framework

可以使用 Upgrade-PowerShell.ps1 腳本來更新它們

這是如何從PowerShell運作此腳本的示例:$url = "https://raw.githubusercontent.com/jborean93/ansible-windows/master/scripts/Upgrade-PowerShell.ps1"

$file = "$env:temp\Upgrade-PowerShell.ps1"

$username = "Administrator"

$password = "Password"

(New-Object -TypeName System.Net.WebClient).DownloadFile($url, $file)

Set-ExecutionPolicy -ExecutionPolicy Unrestricted -Force

# Version can be 3.0, 4.0 or 5.1

&$file -Version 5.1 -Username $username -Password $password -Verbose

完成後,将需要删除自動登入并将執行政策重新設定為預設值 Restricted。可以使用以下PowerShell指令執行此操作:# This isn't needed but is a good security practice to complete

Set-ExecutionPolicy -ExecutionPolicy Restricted -Force

$reg_winlogon_path = "HKLM:\Software\Microsoft\Windows NT\CurrentVersion\Winlogon"

Set-ItemProperty -Path $reg_winlogon_path -Name AutoAdminLogon -Value 0

Remove-ItemProperty -Path $reg_winlogon_path -Name DefaultUserName -ErrorAction SilentlyContinue

Remove-ItemProperty -Path $reg_winlogon_path -Name DefaultPassword -ErrorAction SilentlyContinue

該腳本通過檢查是否需要安裝哪些程式(例如.NET Framework 4.5.2)以及所需的PowerShell版本來工作。如果需要重新啟動 username 并且 password 已設定和參數,則腳本将從重新啟動後自動重新啟動并登入。該腳本将繼續執行,直到不需要其他操作并且PowerShell版本與目标版本比對為止。如果未設定 usernam 和 password 參數,腳本将提示使用者手動重新啟動并在需要時登入。下次登入使用者時,腳本将從上次停止的地方繼續,然後繼續該過程,直到不需要其他操作為止。

注意:如果在 Server 2008 上運作,則必須安裝SP2。如果在 Server 2008 R2 或 Windows 7 上運作,則必須安裝SP1

Windows Server 2008 隻能安裝 PowerShell 3.0,指定較新的版本将導緻腳本失敗

在 username 和 password 參數都存儲在系統資料庫中的純文字。確定腳本完成後運作清除指令,以確定主機上仍沒有存儲憑據。

WinRM 記憶體修補程式

在 PowerShell v3.0 上運作時,WinRM 服務存在一個錯誤,該錯誤會限制 WinRM 可用的記憶體量。沒有安裝此修補程式,Ansible 将無法在 Windows 主機上執行某些指令。這些修補程式應作為系統引導或映像過程的一部分進行安裝 腳本 Install-WMF3Hotfix.ps1可用于在受影響的主機上安裝此修補程式$url = "https://raw.githubusercontent.com/jborean93/ansible-windows/master/scripts/Install-WMF3Hotfix.ps1"

$file = "$env:temp\Install-WMF3Hotfix.ps1"

(New-Object -TypeName System.Net.WebClient).DownloadFile($url, $file)

powershell.exe -ExecutionPolicy ByPass -File $file -Verbose

WinRM 安裝程式

一旦将 Powershell 更新到至少3.0版,最後一步就是配置 WinRM 服務,以便 Ansible 可以連接配接到它。WinRM 服務的兩個主要元件決定着 Ansible 與 Windows 主機的接口方式:listener和和service配置設定。可以使用腳本 ConfigureRemotingForAnsible.ps1 來設定基礎。該腳本使用自簽名證書設定HTTP和HTTPS偵聽器,并Basic 在服務上啟用身份驗證選項。

要使用此腳本,請在PowerShell中運作以下指令:$url = "https://raw.githubusercontent.com/ansible/ansible/devel/examples/scripts/ConfigureRemotingForAnsible.ps1"

$file = "$env:temp\ConfigureRemotingForAnsible.ps1"

(New-Object -TypeName System.Net.WebClient).DownloadFile($url, $file)

powershell.exe -ExecutionPolicy ByPass -File $file

WinRM 監聽

WinRM 服務在一個或多個端口上偵聽請求。這些端口中的每一個都必須具有建立和配置的偵聽器。要檢視 WinRM 服務上正在運作的目前偵聽器,請運作以下指令:winrm enumerate winrm/config/Listener

Listener

Address = *

Transport = HTTP

Port = 5985

Hostname

Enabled = true

URLPrefix = wsman

CertificateThumbprint

ListeningOn = 10.0.2.15, 127.0.0.1, 192.168.56.155, ::1, fe80::5efe:10.0.2.15%6, fe80::5efe:192.168.56.155%8, fe80::

ffff:ffff:fffe%2, fe80::203d:7d97:c2ed:ec78%3, fe80::e8ea:d765:2c69:7756%7

Listener

Address = *

Transport = HTTPS

Port = 5986

Hostname = SERVER2016

Enabled = true

URLPrefix = wsman

CertificateThumbprint = E6CDAA82EEAF2ECE8546E05DB7F3E01AA47D76CE

ListeningOn = 10.0.2.15, 127.0.0.1, 192.168.56.155, ::1, fe80::5efe:10.0.2.15%6, fe80::5efe:192.168.56.155%8, fe80::

ffff:ffff:fffe%2, fe80::203d:7d97:c2ed:ec78%3, fe80::e8ea:d765:2c69:7756%7

在上面的示例中,激活了兩個偵聽器。一種是通過 HTTP 監聽端口5985,另一種是通過HTTPS監聽端口5986。一些有用的關鍵選項是:Transport:無論偵聽器是通過HTTP還是HTTPS運作,建議對HTTPS使用偵聽器,因為資料已加密,無需進行任何進一步更改。

Port:監聽器運作的端口,預設情況下是5985用于HTTP和5986 TTPS的端口。該端口可以更改為所需的任何端口,并與主機var對應ansible_port。

Prefix:要偵聽的URL字首,預設為wsman。如果更改此 ansiblewinrmpath 設定,則必須将主機 var 設定為相同的值。

CertificateThumbprint:如果運作在HTTPS偵聽器上,這是連接配接中使用的 Windows 證書存儲中證書的指紋。

要獲驗證書本身的詳細資訊,請在PowerShell中使用相關的證書指紋運作以下指令:$thumbprint = "E6CDAA82EEAF2ECE8546E05DB7F3E01AA47D76CE"

Get-ChildItem -Path cert:\LocalMachine\My -Recurse | Where-Object { $_.Thumbprint -eq $thumbprint } | Select-Object *

設定 WinRM 偵聽器

可以通過三種方式設定WinRM偵聽器:使用了 HTTP 或 HTTPS的。在域環境之外運作并且需要一個簡單的偵聽器時,這是最容易使用的選項。與其他選項不同,此過程還具有為所需的端口打開防火牆并啟動WinRM服務的額外好處。winrm quickconfigwinrm quickconfig -transport:https使用組政策對象。當主機是域的成員時,這是建立偵聽器的最佳方法,因為配置是自動完成的,無需任何使用者輸入。有關組政策對象的更多資訊,請參閱 組政策對象文檔。

使用 PowerShell 建立具有特定配置的偵聽器。這可以通過運作以下 PowerShell 指令來完成:$selector_set = @{

Address = "*"

Transport = "HTTPS"

}

$value_set = @{

CertificateThumbprint = "E6CDAA82EEAF2ECE8546E05DB7F3E01AA47D76CE"

}

New-WSManInstance -ResourceURI "winrm/config/Listener" -SelectorSet $selector_set -ValueSet $value_set

設定Windows遠端管理

檢視 winrm service listener:winrm e winrm/config/listener

為 winrm service 配置 auth:winrm set winrm/config/service/auth @{Basic="true"}

為 winrm service 配置加密方式為允許非加密:winrm set winrm/config/service @{AllowUnencrypted="true"}

好了,遠端 Windows 主機配置到此結束,我們驗證配置的是否有問題。

Inventory 主機清單

Ansible 必須通過 Inventory 來管理主機。Ansible 可同時操作屬于一個組的多台主機,組和主機之間的關系通過 inventory 檔案配置。# vi /etc/ansible/hosts

[Dev_ALL]

172.16.106.14 ansible_ssh_user="xxxx" ansible_ssh_pass="xxxx" ansible_ssh_port=5985 ansible_connection="winrm" ansible_winrm_server_cert_validation=ignore

172.16.106.180 ansible_ssh_user="xxxx" ansible_ssh_pass="xxxx" ansible_ssh_port=5985 ansible_connection="winrm" ansible_winrm_server_cert_validation=ignore

172.16.106.199 ansible_ssh_user="xxxx" ansible_ssh_pass="xxxx" ansible_ssh_port=5985 ansible_connection="winrm" ansible_winrm_server_cert_validation=ignore

[Dev_AutoTest]

172.16.106.14 ansible_ssh_user="xxxx" ansible_ssh_pass="xxxx" ansible_ssh_port=5985 ansible_connection="winrm" ansible_winrm_server_cert_validation=ignore

[Dev_FunctionTest]

172.16.106.180 ansible_ssh_user="xxxx" ansible_ssh_pass="xxxx" ansible_ssh_port=5985 ansible_connection="winrm" ansible_winrm_server_cert_validation=ignore

[Dev_Develop]

172.16.106.199 ansible_ssh_user="xxxx" ansible_ssh_pass="xxxx" ansible_ssh_port=5985 ansible_connection="winrm" ansible_winrm_server_cert_validation=ignore

[Release_AutoTest]

172.16.106.191 ansible_ssh_user="xxxx" ansible_ssh_pass="xxxx" ansible_ssh_port=5985 ansible_connection="winrm" ansible_winrm_server_cert_validation=ignore

[Release_Develop]

172.16.106.153 ansible_ssh_user="xxxx" ansible_ssh_pass="xxxx" ansible_ssh_port=5985 ansible_connection="winrm" ansible_winrm_server_cert_validation=ignore

[Release_FunctionTest]

172.16.106.185 ansible_ssh_user="xxxx" ansible_ssh_pass="xxxx" ansible_ssh_port=5985 ansible_connection="winrm" ansible_winrm_server_cert_validation=ignore

[Release_ALL]

172.16.106.191 ansible_ssh_user="xxxx" ansible_ssh_pass="xxxx" ansible_ssh_port=5985 ansible_connection="winrm" ansible_winrm_server_cert_validation=ignore

172.16.106.153 ansible_ssh_user="xxxx" ansible_ssh_pass="xxxx" ansible_ssh_port=5985 ansible_connection="winrm" ansible_winrm_server_cert_validation=ignore

172.16.106.185 ansible_ssh_user="xxxx" ansible_ssh_pass="xxxx" ansible_ssh_port=5985 ansible_connection="winrm" ansible_winrm_server_cert_validation=ignore

參數說明:ansiblesshuser:使用者名

ansiblesshpass:密碼

ansiblesshport:端口号

ansible_connection:與主機的連接配接類型

主機說明:Dev_ALL:所有dev版本環境

Dev_AutoTest:dev版本自動化測試環境

Dev_FunctionTest:dev版本功能測試環境

Dev_Develop:dev版本開發環境

Release_ALL:所有release版本環境

Release_AutoTest:release版本自動化測試環境

Release_Develop:release版本開發環境

Release_FunctionTest:release版本功能測試環境

使用 ansible 對 Release_AutoTest 組内的主機進行 ping 子產品測試# ansible Release_AutoTest -m win_ping

172.16.106.191 | SUCCESS => {

"changed": false,

"ping": "pong"

}

PlayBook 任務劇本

PlayBook 是 Ansible 的腳本檔案,使用 YAML 語言編寫,包含需要遠端執行的核心指令、定義任務具體内容,等等。

通常情況下,我們用腳本的方式使用 Ansible,隻要使用好 Inventory 和 PlayBook 這兩個元件就可以了,即:使用 PlayBook 編寫 Ansible 腳本,然後用 Inventory 維護好需要管理的機器清單。這樣,就能解決 90% 以上使用 Ansible 的需求。

但如果你有一些更複雜的需求,比如通過代碼調用 Ansible,可能還要用到 API 元件。感興趣的話,你可以參考 Ansible 的官方文檔。

劇本、資源路徑/home/ansible/playbooks 劇本存放目錄

/home/ansible/python python攪拌

完整劇本# vi server-deploy.yaml

[[email protected] playbooks]# vi v3c-deploy.yaml

# ---------------------------------

# 1.各變量指派

# 2.初始化目錄,包括:程式目錄,下載下傳目錄,資源備份目錄(如果不存在)

# 3.結束正在運作的服務程序(等待3秒)

# 4.清空資源目錄

# 5.備份 Data/Files 目錄

# 6.備份 Data/projects 目錄

# 7.清空程式目錄

# 8.下載下傳 server 程式檔案

# 9.解壓檔案

# 10.清空&還原 Data/projects 目錄

# 11.啟動 server 服務

# ---------------------------------

- hosts: "{{target}}"

remote_user: htsd

vars:

package:

root_url: "http://172.16.106.188:8081/repository/app-{{branch}}-info/server/"

deploy:

app_path: "C:\\app\\app-{{branch}}-info\\server"

package_path: C:\app\package

res_path: C:\app\res

PsExec_path: C:\app\tools\PSTools

tasks:

# --------------------初始化目錄--------------------

- name: 建立程式目錄

win_file:

path: "{{deploy.app_path}}"

state: directory

become: yes

- debug:

msg: "{{deploy.app_path}}"

- name: 建立下載下傳目錄

win_file:

path: "{{deploy.package_path}}"

state: directory

become: yes

- debug:

msg: "{{deploy.package_path}}"

- name: 建立資源備份目錄

win_file:

path: "{{deploy.res_path}}"

state: directory

become: yes

- debug:

msg: "{{deploy.package_path}}"

# -------------------備份及結束程序------------------

- name: 結束 Server 程序

win_shell: Stop-Process -Name "app.Server" -Force

ignore_errors: true

- name: 等待3秒停止 Server 程序

win_wait_for_process:

process_name_pattern: app.Server

state: absent

timeout: 3

- name: 清空資源目錄

win_shell: |

$TargetFolder = "{{deploy.res_path}}"

$Files = get-childitem $TargetFolder -force

Foreach ($File in $Files)

{

$FilePath=$File.FullName

Remove-Item -Path $FilePath -Recurse -Force

}

- name: 備份 Data/Files 目錄

win_shell: Copy-Item "{{deploy.app_path}}\Data\Files" -Destination {{deploy.res_path}} -Recurse

ignore_errors: yes

- name: 備份 Data/projects 目錄

win_shell: Copy-Item "{{deploy.app_path}}\Data\projects" -Destination {{deploy.res_path}} -Recurse

ignore_errors: yes

- name: 清空程式目錄

win_shell: |

$TargetFolder = "{{deploy.app_path}}"

$Files = get-childitem $TargetFolder -force

Foreach ($File in $Files)

{

$FilePath=$File.FullName

Remove-Item -Path $FilePath -Recurse -Force

}

# ----------------下載下傳&更新程式------------------------

- name: 下載下傳 server 程式檔案

win_get_url:

url: "{{package.root_url}}{{package_name}}"

dest: "{{deploy.package_path}}"

force: no

- debug:

msg: "{{package_name}}"

- name: 遞歸解壓檔案後删除zip包

win_unzip:

src: "{{deploy.package_path}}/{{package_name}}"

dest: "{{deploy.app_path}}"

recurse: yes

delete_archive: yes

- name: 删除原 Data/Files 目錄

win_shell: rmdir /s/q "{{deploy.app_path}}\Data\Files"

args:

executable: cmd.exe

ignore_errors: yes

- name: 删除原 Data/projects 目錄

win_shell: rmdir /s/q "{{deploy.app_path}}\Data\projects"

args:

executable: cmd.exe

ignore_errors: yes

- name: 還原 Data/Files 目錄

win_shell: Copy-Item "{{deploy.res_path}}\Files" -Destination "{{deploy.app_path}}\Data" -Recurse

ignore_errors: yes

- name: 還原 Data/projects 目錄

win_shell: Copy-Item "{{deploy.res_path}}\projects" -Destination "{{deploy.app_path}}\Data" -Recurse

ignore_errors: yes

# -------------------------啟動-------------------------

- name: 啟動 app-server

win_shell: "{{deploy.PsExec_path}}/psexec.exe -accepteula -nobanner -i 1 -s -d {{deploy.app_path}}//app.Server.exe"

register: output

ignore_errors: yes

# - name: 列印日志

# debug: var=output

復原部署

由于各種各樣的原因,部署的版本可能會出現異常,這時候可能需要緊急復原版本,我們可以手動去復原版本,但是缺點也很明顯,當主機執行個體過多時,手動復原明顯是不再明智的,是以我們可結合 Jenkins+Ansible 這兩者來做到一個通用的服務版本復原政策。

Jenkins 執行#!/usr/bin/env bash

echo '版本類型:'$Branch

echo '環境類型:'$Hosts

echo '檔案名稱:'$Package_Name

ansible-playbook /home/ansible/playbooks/server-deploy.yaml --extra-vars "package_name=$Package_Name branch=$Branch target=$Hosts"

Jenkins 執行日志:

釘釘通知

Jenkins 調用:

python 腳本:# coding=utf-8

'''

@author: zuozewei

@file: notification.py

@time: 2019/4/25 18:00

@description:dingTalk通知類

'''

import os, jenkins, json

from dingtalkchatbot.chatbot import DingtalkChatbot

from jsonpath import jsonpath

JOB_NAME = str(os.getenv("JOB_NAME"))

BUILD_URL = str(os.getenv("BUILD_URL")) + "console"

BUILD_NUMBER = str(os.getenv("BUILD_NUMBER"))

Package_Name = str(os.getenv("Package_Name"))

VERSION = Package_Name.split('-')[4].replace('.zip','')

Branch = str(os.getenv("Branch"))

Hosts = str(os.getenv("Hosts"))

Branch_Name = ''

Eev = ''

Host_name = ''

if Branch == 'dev':

Branch_Name = '開發版'

if Hosts == 'Dev_ALL':

Eev = 'Dev所有環境'

Host_name = '- 172.16.106.175' + '\n' + \

'- 172.16.106.155' + '\n' + \

'- 172.16.106.115' + '\n'

elif Hosts == 'Dev_AutoTest':

Eev = 'Dev自動化測試環境'

Host_name = '- 172.16.106.175' + '\n'

elif Hosts == 'Dev_FunctionTest':

Eev = 'Dev功能測試環境'

Host_name = '- 172.16.106.155' + '\n'

elif Hosts == 'Dev_Develop':

Eev = 'Dev開發環境'

Host_name = '- 172.16.106.115' + '\n'

elif Branch == 'release':

Branch_Name = '預覽版'

if Hosts == 'Release_ALL':

Eev = 'Release所有環境'

Host_name = '- 172.16.106.58' + '\n' + \

'- 172.16.106.168' + '\n' + \

'- 172.16.106.203' + '\n'

elif Hosts == 'Release_AutoTest':

Eev = 'Release自動化測試環境'

Host_name = '- 172.16.106.58' + '\n'

elif Hosts == 'Release_FunctionTest':

Eev = 'Release功能測試環境'

Host_name = '- 172.16.106.203' + '\n'

elif Hosts == 'Release_Develop':

Eev = 'Release開發環境'

Host_name = '- 172.16.106.168' + '\n'

print("【版本類型】:" + Branch_Name)

print("【環境類型】:" + Eev)

print("【主機清單】:" + Host_name)

# 連接配接jenkins

server = jenkins.Jenkins(url="http://172.16.106.251:8080", username='xxx', password="xxx")

# 擷取指定項目編譯狀态

BUILD_STATUS = server.get_build_info(JOB_NAME, int(BUILD_NUMBER))['result']

print("【BUILD_STATUS】:" + BUILD_STATUS)

build_info = server.get_build_info(JOB_NAME, int(BUILD_NUMBER))

# dict字典轉json資料

build_info_json = json.dumps(build_info)

# 把json字元串轉json對象

build_info_jsonobj = json.loads(build_info_json)

causes = jsonpath(build_info_jsonobj, '$.actions..shortDescription')

def packagNotification():

title = 'xxx部署通知'

textFail = '#### ' + JOB_NAME + ' # ' + BUILD_NUMBER + ' \n' + \

'##### 部署狀态: ' + BUILD_STATUS + ' \n' + \

'##### **版本類型**: ' + Branch_Name + '\n' + \

'##### **目前版本**: ' + VERSION + '\n' + \

'##### **檔案名稱**: ' + Package_Name + '\n' + \

'##### **觸發類型**: ' + str(causes[0]) + '\n' + \

'##### **部署日志**: [檢視詳情](' + BUILD_URL + ') \n' + \

'##### **關注人**: @186xxxx2487 \n' + \

'##### **部署環境**: ' + Eev + '\n' + \

'##### **執行主機**: \n' + \

Host_name + '\n' + \

'> ###### xxx技術團隊 \n '

textSuccess = '#### ' + JOB_NAME + ' # ' + BUILD_NUMBER + ' \n' + \

'##### **部署狀态**: ' + BUILD_STATUS + '\n' + \

'##### **版本類型**: ' + Branch_Name + '\n' + \

'##### **目前版本**: ' + VERSION + '\n' + \

'##### **檔案名稱**: ' + Package_Name + '\n' + \

'##### **觸發類型**: ' + str(causes[0]) + '\n' + \

'##### **部署日志**: [檢視詳情](' + BUILD_URL + ') \n' + \

'##### **部署環境**: ' + Eev + '\n' + \

'##### **執行主機**: \n' + \

Host_name + '\n' + \

'> ###### xxx技術團隊 \n '

if BUILD_STATUS == 'SUCCESS':

dingText = textSuccess

else:

dingText = textFail

sendding(title, dingText)

def sendding(title, content):

at_mobiles = ['186xxxx2487']

Dingtalk_access_token_v3c = 'https://oapi.dingtalk.com/robot/send?access_token=xxxxxxxxxx'

# 初始化機器人小丁

xiaoding1 = DingtalkChatbot(Dingtalk_access_token_v3c)

# Markdown消息@指定使用者

xiaoding1.send_markdown(title=title, text=content, at_mobiles=at_mobiles)

if __name__ == "__main__":

packagNotification()

通知效果:

注意:如果主機比較多的情況,建議不要使用這種寫死的方式,可以考慮放到一個配置檔案進行讀取。

小結

在今天這篇文章中,主要基于 Ansible 系統的能力,和大家分享了搭建一套部署系統的過程。在搭建過程中,你最需要關注的幾部分内容是:利用 Inventory 做好部署目标的管理

利用 PlayBook 編寫部署過程的具體邏輯

利用 Jenkins 對主機叢集進行排程、追蹤和同步任務

利用 Python 腳本釘釘自動化通知及跳轉功能

至此,我們要搭建的整個自動部署系統,也算是順利完成了。

參考資料:

[1]:https://blog.51cto.com/191226139/2066936

[2]:https://docs.ansible.com/ansible/latest/user_guide/windows.html

[3]:持續傳遞36講 王潇俊

本文資源:

https://github.com/7DGroup/Jenkins-CI/tree/master/jenkins-ansible-python