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

[root@localhost 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

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
为了减轻多服务器配置和操作工作量以及安全性,特研究此课题,理论上可以同步所有想同步的文件,并且做到一键操作,不需要切换用户,不需要多次操作脚本,中途不需要输入任何字。 1, hosts文件 2, play.yml文件 剧本文件,按标准放到tasks文件夹内,因后面脚本写了路径,如果不愿意放tasks文件夹,需要改后面sh脚本路径参数 3, rsync_notice.py文件 钉钉机器人发送消息文件,此文件放在tools文件夹内,会调用备份日志进行分析,过滤后,发送到钉钉群内。各位同事可修改文件里的Webhoo为自己的机器人key 4, deploy.sh 文件 调用py钉钉文件发消息,并且处理备份日志,删除近期日志等后续事宜,请放在tools文件夹内 1.3.3. 功能基本介绍 1, 在对应脚本里基本都有注释,这里简单介绍下 2, 剧本文件需要在主控机器(备份机器),root用户下运行,运行一次即可,后续sh及py脚本会自动处理。一键搞定所有事情,中途无需手动干预; 3, 自行修改host文件为自己项目地址,bak为备份文件服务器,为安全起见,hosts文件进行了vault加密,密码123456,运行剧本文件,请加—ask-vault-pass 4, 再次提醒,在脚本运行完成后,为保险起见,可将hosts文件中的root密码删除,或修改复杂密码,不会影响后续同步功能。 5, 剧本流程介绍: 1) 主控被控端安装rsync及相关依赖软件; 2) 主控与被控端添加备份用户,rsync; 3) 主控端即备份服务器建立备份文件夹,设置归属用户; 4) 主控及被控端自动切换rsync用户,使用rsync用户配置免密访问所有被控端,即便服务器被黑,rsync用户访问也做不了什么; 5) 主控端即备份服务器使用rsync用户增加同步、日志记录、钉钉发送消息等定时任务; 6) 定时任务里各个需要同步的源地址及项目名称,请自行修改; 7) 日志为叠加记录,钉钉消息发完后,会按日期进行备份,同时删除原日志,因为钉钉消息每天都发,避免冗余数据; 6, 钉钉消息脚本介绍: 1) 访问实时备份日志,考虑到钉钉消息,只需要知道同步是否成功,其余数据不关心,所以读取后,进行数据处理,取出服务器地址、成功标识,或未成功标识; 2) 调用钉钉机器人接口,采取markdown形式,此形式可以定义一个固定的标题,比如:rsync同步情况汇总,这样在钉钉机器人安全设置里,只需要将标题设为关键字即可,具体发送内容千奇百怪也没关系。另外两种方式各有弊端,未研究。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值