持续交付之Jenkins+Ansible+Python搭建自动化部署框架(win版)

网友投稿 706 2022-05-30

前言

部署的需求

落地方案

技术架构

主要特点

技术选型

环境配置

前言

部署的需求

落地方案

技术架构

主要特点

技术选型

环境配置

预备知识

Ansible

Ansible是什么?

Ansible能做什么?

Ansible架构

Ansible工作原理

Ansible特性

Ansible主要组成部分

注意事项

具体实现

环境规划

搭建 Master 环境(Linux)

搭建受控端环境(window)

主机要求

升级 Upgrading PowerShell 和 .NET Framework

WinRM 内存修补程序

WinRM 安装程序

WinRM 监听

设置 WinRM 侦听器

设置Windows远端管理

Inventory 主机清单

PlayBook 任务剧本

剧本、资源路径

完整剧本

回滚部署

Jenkins 执行

钉钉通知

小结

前言

无论是为新需求添加的代码,还是静态配置的变更,应用的任何变动都要经过部署这道工序才能最终落地。但通常,新的部署意味着应用重启、服务中断。工程师和测试人员经常在深夜搞得筋疲力尽,甚至焦头烂额。进入持续交付的时代后,这个痛点只会更加突显,因为持续交付意味着持续部署。例如,在测试环境小时级的持续集成场景中,如果没有办法将部署过程流程化、自动化,显然会频繁打断最终的交付过程,大幅降低开发测试效率。

因此,我们想要的应该是:一个易用、快速、稳定、容错力强,必要时有能力迅速回滚的部署系统。

部署的需求

单机部署过程高度抽象后其实就三个步骤:

在目标机器上执行命令停掉运行中的服务

把提前准备好的变更包传上机器覆盖原来的目录

运行命令把服务再跑起来

假设我们实现了一个自动部署程序,简单地顺序执行上面的步骤,让我们一起来检验是否能满足发布的需求:

易用:执行脚本就好,填入参数,一键执行。

快速:自动化肯定比手工快,并且有提升空间。比如,因为有版本的概念,我们可以跳过相同版本的部署,或是某些步骤。

稳定:因为这个程序逻辑比较简单,而且执行步骤并不多,没有交叉和并行,所以稳定性也没什么大的挑战。

容错性强:表现一般,脚本碰到异常状况只能停下来,但因为版本间是隔离的,不至于弄坏老的服务,通过人工介入仍能恢复。

回滚顺滑:因为每个版本都是完整的可执行产物,所以回滚可以视作使用旧版本重新做一次部署。甚至我们可以在目标机器上缓存旧版本产物,实现超快速回滚。

通过这个程序的简单执行过程,我们可以看到这套流程的简单实现,基本满足了我们部署的需求。而且,可以通过添加更复杂的控制流,获得更大的提升空间。

而如今架构基本上告别了单点世界,面向集群的部署带来了更高维度的问题。当部署的目标是一组机器而不是一台机器时,主要问题就变成了如何协调整个过程。比如,追踪、同步一组机器目前部署进行到了哪一步,编排集群的部署命令就成为了更核心功能。

落地方案

技术架构

主要特点

使用 Jenkins 作为一站式部署平台,方便选择参数,自动协调各主机,自动运行部署命令,自动通知等

支持快速回滚指定旧版本

支持面向集群进行编排、追踪和同步任务

实现钉钉自动化通知及跳转功能

技术选型

执行引擎:Ansible

自动通知:钉钉webhook & python

Jenkins 插件:

Shell:执行 shell 脚本

Active Choices Plugin:动态交互参数

AnsiColor:彩色输出,非必须

环境配置

持续交付之Jenkins+Ansible+Python搭建自动化部署框架(win版)

Ansible: 2.9.0

Python: 2.7.5

CentOS: 7.6

Java: 1.8.0_73

Jenkins: 2.164.3

预备知识

Ansible

Ansible 是一个自动化运维管理工具,支持 Linux/Windows 跨平台的配置管理,任务分发等操作,可以帮我们大大减少在变更环境时所花费的时间。与其他三大主流的配置管理工具 Chef、Puppet、Salt 相比,Ansible 最大的特点在于“agentless”,即无需在目标机器装安装 agent 进程,即可通过 SSH 或者 PowerShell 对一个环境中的集群进行中心化的管理。所以,这个“agentless” 特性,可以大大减少我们配置管理平台的学习成本,尤其适合于第一次尝试使用此类配置管理工具。

正如其他配置管理工具一样,Ansible 可以帮助我们完成一些批量任务,或者完成一些需要经常重复的工作

比如:同时在 100 台服务器上安装 nginx 服务,并在安装后启动它们

比如:将某个文件一次性拷贝到 100 台服务器上

比如:每当有新服务器加入工作环境时,你都要为新服务器部 redis 服务,也就是说你需要经常重复的完成相同的工作

这些场景中我们都可以使用到 Ansible

模块化:调用特定的模块,完成特定任务

有 Paramiko,PyYAML,Jinja2(模板语言)三个关键模块

支持自定义模块

基于 Python 语言实现

部署简单,基于 python 和 SSH(默认已安装),agentless

安全,基于 OpenSSH

支持 playbook 编排任务

幂等性:一个任务执行1遍和执行n遍效果一样,不因重复执行带来意外情况

无需代理不依赖 PKI(无需ssl)

可使用任何编程语言写模块

YAML 格式,编排任务,支持丰富的数据结构

较强大的多层解决方案

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)]

配置文件:

搭建受控端环境(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 服务

可以使用 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 参数都存储在注册表中的纯文本。确保脚本完成后运行清除命令,以确保主机上仍没有存储凭据。

在 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

一旦将 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 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。如果更改此 ansible_winrm_path 设置,则必须将主机 var 设置为相同的值。

CertificateThumbprint:如果运行在HTTPS侦听器上,这是连接中使用的 Windows 证书存储中证书的指纹。

要获取证书本身的详细信息,请在PowerShell中使用相关的证书指纹运行以下命令:

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

可以通过三种方式设置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

查看 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

参数说明:

ansible_ssh_user:用户名

ansible_ssh_pass:密码

ansible_ssh_port:端口号

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 # --------------------------------- # 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 执行日志:

钉钉通知

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 脚本钉钉自动化通知及跳转功能

至此,我们要搭建的整个自动部署系统,也算是顺利完成了

相关资源:

https://github.com/zuozewei/blog-example/tree/master/Jenkins-ci/jenkins-ansible-python

参考资料:

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

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

[3]:持续交付36讲 王潇俊

Jenkins ssh Windows 自动化测试 运维

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:LiteOS内核源码分析系列十三 动态内存Bestfit分配算法 (1)
下一篇:GraphQL技术怎样?有什么缺点?
相关文章