构建--> 部署-->
这一篇中我们会写一些关于自动化部署的代码。我们会使用 Powershell 书写这类代码。
你将发现这篇文章中涉及的东西非常具体,有的要求甚至相当苛刻且可能不具有通用性。这是因为部署从来都是跟环境打交道,部署过程中协作的组建太多,相互之间的交集不可能太大。可能唯一能够通用的是自动化部署的基本原则(只是这篇文章的基本原则):
- 每一次自动化部署结束之后,应用程序都会有相同的初始状态。
- 自动化部署的机器非常干净,只有相应的 Windows Server 系统和 .NET Framework。尤其是,不会有 Visual Studio。
我们需要公开一些基本的环境信息:
- 64-bit Windows Server 2008/2012/2012 R2或者 64-bit Windows 7/8/8.1
- 我们的工程是使用 Microsoft Visual Studio 2013 开发的;
- .NET Framework 版本为 4.5
- ASP.NET MVC 的版本为 5.0.0
- Microsoft Build Tool 的版本为 12.0
关于 MSBuild 这里需要多说几句。在 Visual Studio 2013 发布之前,MSBuild 是随 .NET Framework 一起发布的。这意味着我们可以不用安装 Visual Studio 就可以构建 .NET 应用程序。
这是多么美好的世界啊!因此,上一句话是假的。尤其是当你构建 ASP.NET Web 应用程序的时候,你马上就会遇到 “Cannot found … WebApplication.target” 的错误。如果你 StackOverflow 一下就可以知道,我们需要做的是安装 Visual Studio 或者从另外一台安装了 Visual Studio 的机器上将相关的文件拷贝出来。这真是——丢人的设计!Linux 的拥趸又有了发泄的空间。
于是微软决定正视这个问题。从 Visual Studio 2013 开始,MSBuild 将与 Visual Studio 而不是.NET Framework 一起发布。这引来了一片骂声。我不得不说,大家在生活中不论遇到什么事情都要保持足够的冷静,往往先发脾气的得不到任何的好处。事实是,由于 .NET Framework 发布的周期是相对较长的,因此微软目前越来越倾向于使用 NuGet 进行类库的发布,这样有助于削减 .NET Framework 基础类库的大小,并缩短基础类库的发布周期。相应的 MSBuild 和 Visual Studio 的发布周期也希望进行独立的变化。MSBuild 将和 Visual Studio 保持发布周期的一致性,并不意味这 MSBuild 依赖于 Visual Studio。因此我们当然可以下载 MSBuild 的独立安装包 Microsoft Build Tools,并在一台没有 Visual Studio 的服务器上进行自动化构建。
再次强调,如果幸运,你可以直接运行这篇文章中的例子。但是你不要指望将这篇文章的脚本拷贝到你的工程就可以正常工作。因为部署是一个因地制宜的任务,需要具体分析。你可能会遇到各种各样的环境问题,但是我认为最重要的还是思路。
部署是什么
简单来说,部署就是 “构建(Build)” –> “拷贝” –> “配置”。那么我们就开始一个一个解决它。这一篇将着眼于构建。
编译和构建应用程序 – 思路
如何构建应用程序呢?答案是先把需要的东西都拷贝过来,然后再用工具构建。好极了,我们需要拷贝什么东西呢?当然是先把源代码拷贝过来。
|
光源代码还不行,因为我们的程序依赖于第三方库(箭头代表依赖关系)。
|
例如,对于我们构建的那个简简单单的 ASP.NET MVC 5 的应用程序,我们就需要在构建之前下载它依赖的类库:
- Microsoft.AspNet.Mvc 5.0.0
- Microsoft.AspNet.Razor 3.0.0
- Microsoft.AspNet.WebPages 3.0.0
- Microsoft.Web.Infrastructure 1.0.0.0
源代码和依赖库都拷贝完了,那么接下来我们就需要将构建工具也拷贝过来:
|
对于我们来说,构建的工具只有一个:
- MSBuild
如今工具,源代码一应俱全,我们可以开始编译了。
安装 MSBuild
如果你做实验的机器上安装了 Visual Studio 2013——Express 版本的也是可以的——那么你可以跳过这一步,否则请下载 Microsoft Build Tools 并安装。
下载应用程序的代码
我们的代码是现成的,只需要从 git repository clone 下来就可以了。你也可以从这个地址 clone 到一个范例代码,并转换到相应的 commit。
|
好了,完成了,到目前为止一切都是那么的轻松愉快。
下载应用的依赖库
我们将使用 nuget 管理包的依赖。因此我们首先要下载 NuGet 的命令行客户端,可以从这里下载。
接下来的行为都需要明确的目录结构。为了便于说明,我们将建立如下的目录结构。
|
其中,src 目录存放 Solution 的源代码,而 build 目录存放自动化构建所需的各种工具和脚本。其中自动化构建需要的工具将放在 build/tools 目录下。因此我们也会将 nuget.exe 放在这个目录下。
接下来我们在 build 目录下建立 deploy.ps1 脚本,我们将在这个脚本中完成接下来的任务。我们先来下载依赖的包。NuGet 的包管理是通过 package.config 文件进行的。需要指出的是 package.config也具有一定的层次关系。首先 Solution 级别的包信息存储在两个地方:
- 第一个是 Solution 目录下的 .nuget/package.config 文件,这个文件中存储的是非特定项目使用的包(如果并没有这种类型的包,则该目录不存在,或者该目录下没有任何文件);
- 第二个是 Solution 目录下的 packages/repositories.config 文件,这个文件存储了该解决方案下的每一个工程的 packages.config 文件的路径。
而 Solution 下的每一个 Project 的包定义存储在 Project 目录下的 package.config 中。
为了下载这些依赖的包是否需要人为遍历这些 config 文件呢?原来是,而从 nuget 2.7 开始,可以直接支持 Solution 范围内的包下载,于是额我们就可以使用如下的简单函数完成包的下载了。
|
其中,$global_nugetPath 是 nuget.exe 的路径,而 $global_solutionFilePath 是工程文件(在这里是 FromZero.App.csproj)的路径。
接下来需要确定的是构建工具的位置,我们可以使用注册表查找 MSBuild 的位置的,由于我们使用了 2013 版本的 MSBuild(Toolset 的版本号为 12.0),因此我们的查找脚本为:
|
上述两步完成之后,就可以编译我们的工程了:
|
你迫不及待的试验了你的代码,但是却发现出了问题,MSBuild 报告无法找到Microsoft.WebApplication.targets 文件。这是怎么回事,我们已经明明在 MSBuild 中安装了Microsoft.WebApplication.targets 了啊?这是因为为了保持和 Microsoft Visual Studio 2010 SP1 的工程的兼容性,Visual Studio 2012/2013 的工程默认将 $(VisualStudioVersion) 环境变量设置为 10.0。这样,target 文件的查询路径就成了:
|
而不是:
|
因此我们需要修正这个环境变量。请使用文本编辑器打开 FromZero.App.csproj 文件,找到如下的定义:
|
将其中的 VisualStudioVersion 节替换为:
|
再次运行:祝贺你,你已经能够成功的下载所有的依赖,并完成工程的编译了!在本文的结束,附上 deploy.ps1 到目前为止的所有代码:
|
2、
简单来说,部署就是 “构建(Build)” –> “拷贝(打包)” –> “配置”。在前一篇中,我们介绍了“构建”,那么这一篇就说说拷贝(好像我们更习惯于说打包,那么以后我们就叫它打包吧)的事情。为什么要打包呢?在应用程序发布的时候我们当然只希望发布运行时需要的文件,而其他的文件,例如:工程文件,源代码等等是不需要进行发布的。因此我们需要将运行时所需的文件分离出来,做成一个干净的 Package。
打包 – 思路
只需要解决楚两个问题,打包就完成了:第一个问题是,我们打的包应该有怎样的目录结构;第二个问题是,应该拷贝哪些文件夹到包的哪些目录里去。
应该拷贝哪些文件
在回答第一个问题之前,我们先来看看有哪些文件需要进行拷贝。构建好的程序集(.dll 和 .exe)需要拷贝,没错,但是除了它们以外还有其他文件需要进行拷贝。如果在 Visual Studio 中打开 Web Project,并观察每一个文件的 Build Action 属性,你会发现几乎所有的文件都属于以下四种 Build Action:
- None:这意味着这个文件在构建过程中将不做任何处理。典型的例子是 Readme 或者 EULA(End User License Agreement) 文件。这种文件不会在打包中进行拷贝;
- Compile:这类文件会在构建过程中进行编译,编译结果会嵌入到生成的程序集(dll 或者 exe)中。这类文件在打包的时候是不会进行拷贝的;
- Content:这个文件不会在构建过程中进行编译。但是这个文件属于整个工程发布的一个部分。因此这类文件在打包的时候会进行拷贝;
- Embedded Resources:这个文件的内容将作为一种嵌入式资源在构建过程中嵌入到程序集中。这个文件在打包的过程中不会被拷贝;
因此,除了构建好的程序集之外,所有 Build Action 为 Content 的文件类型也会在打包的时候被拷贝。
以我们的工程为例:
|
那么需要拷贝的文件为:
- .\bin 文件夹下的所有文件;
- 所有 Build Action 为 Content 属性的文件:Global.asax、packages.config、Web.config、Index.cshtml。
包的目录结构
在上一节我们介绍了,所有构建生成的程序集和 Build Action 为 Content 的文件都会在打包过程中进行拷贝。那么它们会拷贝到什么地方去呢?答案是拷贝到相应的目录下面去。以我们的工程为例,假设我们希望将构建好的工程拷贝到一个名为 Package 的目录下去,那么这个 Package 目录在打包完毕之后应该是这个样子的:
|
等一下,Controller 和 Properties 目录到哪里去了?由于这两个目录下面没有一个文件需要进行发布,因此这个目录也就不会创建。
假设你的确需要一个 Controller 目录进行发布,该怎么办呢?那么我们可以利用规则创建一个 0KB 的 placeholder 文件。并且将这个文件的 Build Action 属性设置为 Content。
至此我们已经可以总结出打包的规则了:
- 拷贝所有构建过程中生成的程序集文件,以及 Build Action 为 Content 的文件;
- 将所有需要拷贝的文件拷贝到一个和其所在的工程目录对应的目录下面,如果某一个目录下没有一个文件需要在打包中进行拷贝,则不生成这个目录。
打包-代码
我们是否需要自己解析工程的 XML 结构然后按照上述规则进行打包呢?幸运的是,完全不用:这是因为在 ASP.NET Web 工程中会引用 $(VSToolsPath)\Web\Microsoft.Web.Publishing.targets,其中定义的 _WPPCopyWebApplication 过程正是我们以上描述的过程。我们只需要在上一个例子的基础上修改 Compile-Project 函数:
|
其中:
$global_msBuildPath是 msbuild.exe 的所在位置;/t:Rebuild:首先执行 Rebuild 过程,这将删除上一次的构建结果,然后重新构建整个项目;/t:_WPPCopyWebApplication:将该项目进行打包;/p:WebProjectOutputDir='$global_buildDirPath\Package\':将整个打包结果存放在 buildDir 下的 Package 目录下。如果这个目录不存在则创建这个目录;/p:UseWPP_CopyWebApplication=True:从 Visual Studio 2010 开始,我们可以使用 Web.config.\$(Configuration).config 文件对 Web.config 在不同的编译选项下进行修正。为了使用能够这个功能,需要设定此变量值为True;/p:PipelineDependsOnBuild=False:如果将UseWPP_CopyWebApplication设置为True,则必须将PipelineDependsOnBuild变量设置为False否则将导致 MSBuild 的 Targets 的循环引用。具体的技术细节请参见这里。
这么长的一坨命令非常不容易维护,因此我们可以将这些命令放在一个 MSBuild 工程中。首先,我们建立一个 XML 文件,不妨命名为 Deploy.xml:
|
这样,我们只需要在 Compile-Project 函数中用 MSBuild 调用这个 Deploy.xml 文件,并将希望的包的输出目录赋值给 $(WebAppPublishDir) 变量即可:
|
到现在,Compile-Project 函数已经不止是在编译工程了,它还具备了打包的能力,因此我们将其重命名为 Deploy-Project。
附:deploy.ps1 到目前为止的代码
|
3、
Here are some easy-to-use functions for zipping up a directory and unzipping usingPowershell. The functions use the opensource SharpZipLib library, a Zip, GZip, Tar and BZip2 library written entirely in C# for the .NET platform. So you'll need to download this and reference the SharpZipLib assembly in the appropriate place in the functions below.
function ZipFiles($sourcePath,$zipFilename)
{
# Reference the SharpZipLib assembly here
[System.Reflection.Assembly]::LoadFrom("C:\ICSharpCode.SharpZipLib.dll") $zip = New-Object ICSharpCode.SharpZipLib.Zip.FastZip
$zip.CreateZip($zipFilename,$sourcePath, $true,"")
} function UnzipFiles($zipFilename,$destinationPath)
{
# Reference the SharpZipLib assembly here
[System.Reflection.Assembly]::LoadFrom("C:\ICSharpCode.SharpZipLib.dll") $zip = New-Object ICSharpCode.SharpZipLib.Zip.FastZip
$zip.ExtractZip($zipFilename,$destinationPath,"")
} 我去!!!!!!发上去5分钟,TMD被踩了三次,大神能不能提出点高明的意见啊???!!!
光踩不发表意见怎么共同进步啊?
怎么显出你大神啊?
踩的很爽吧??!!!
转载自:http://shuaigelingfei.iteye.com/blog/2019982
构建--> 部署-->的更多相关文章
- 使用jekins自动构建部署java maven项目(jdk1.7+tomcat7.0+jenkins2.19.3)
1.下载jenkins 地址:https://jenkins.io/index.html 本人下载了2.19.3版本的war包:jenkins.war 2.安装jenkins 拷贝jenkins.wa ...
- Jenkins详细安装与构建部署使用教程(转)
Jenkins是一个开源软件项目,旨在提供一个开放易用的软件平台,使软件的持续集成变成可能.Jenkins是基于Java开发的一种持续集成工具,用于监控持续重复的工作,功能包括:1.持续的软件版本发布 ...
- Ant + Jenkies +Tomcat 自动构建部署Web项目
前言:博主资历尚浅,很多东西都还在刚起步学习的阶段,这几天开发任务比较轻,就在自己window系统下,模拟部署远程服务器,利用Jenkies + Ant + Tomcat 搭建了一个自动发布部署的环境 ...
- Jenkins具体安装与构建部署使用教程
Jenkins是一个开源软件项目.旨在提供一个开放易用的软件平台,使软件的持续集成变成可能. Jenkins是基于Java开发的一种持续集成工具,用于监控持续反复的工作,功能包含:1.持续的软件版本号 ...
- dokcer自动化构建部署java web 基于jenkins+maven+nuxus容器
# dokcer自动化构建部署java web 基于jenkins+maven+nuxus容器 #环境centos 7.4 docker 18.03.0-ce # nuxus,创建maven本地源(可 ...
- Cocos Creator—最佳构建部署实践
这篇文章主要是我们团队在使用Cocos Creator过程中的一些关于部署方面的实践总结,标题党了一回,严格来说,应该是<快看漫画游戏研发团队使用Cocos Creator构建部署最佳实践> ...
- 使用Docker+Jenkins自动构建部署
环境 Windows 10 Docker Version 18.06.1-ce-win73 (19507) 运行jenkins 运行jenkins 容器 docker run -d --name ln ...
- Jenkins详细安装与构建部署使用教程
版权声明:本文为博主林炳文Evankaka原创文章,转载请注明出处http://blog.csdn.net/evankaka 目录(?)[+] Jenkins是一个开源软件项目,旨在提供一个开 ...
- 使用jenkins进行项目的自动构建部署
jenkins 简介 Jenkins是基于Java开发的一种持续集成工具,用于监控持续重复的工作,功能包括:持续的软件版本发布/测试项目和监控外部调用执行的工作. 官网地址地址: https://je ...
- jenkins 构建部署时tomcat7 内存溢出解决方案
在使用jenkins构建部署时一直出现tomcat7内存溢出 WARNING: Unexpected node monitoring termination: Clock Difference jav ...
随机推荐
- selenium中CSS选择器定位
selenium元素定位,CSS选择器定位效率会高很多. CSS选择器用于选择你想要的元素的样式的模式.表格摘自“菜鸟教程”,具体用法可去查阅 选择器 示例 示例说明 CSS .class .intr ...
- jsp 遍历集合——关于获取集合的长度
一,关于获取集合长度问题 在jsp页面中不能通过${list.size}取列表长度,而是 EL表达式不能获取集合的长度 如:${list.size} <%@ taglib uri="h ...
- 页面对象(Page Object)模式
内容转载自 https://www.cnblogs.com/yytesting/p/6973474.html 页面对象(Page Object)模式是目前自动化测试领域普遍使用的设计模式之一,此模式可 ...
- Kotlin 扩展
Kotlin 可以对一个类的属性和方法进行扩展,且不需要继承或使用 Decorator 模式. 扩展是一种静态行为,对被扩展的类代码本身不会造成任何影响. 扩展函数 扩展函数可以在已有类中添加新的方法 ...
- SparkStreaming流处理
一.Spark Streaming的介绍 1. 流处理 流式处理(Stream Processing).流式处理就是指源源不断的数据流过系统时,系统能够不停地连续计算.所以流式处理没有什么 ...
- Python中怎么读写文件
python中对文件的操作大概分为三步:打开文件.操作文件(读.写.追加写入).关闭文件. 1.无论对文件做哪种操作,操作前首先要保证文件被打开了,即需要一个打开的操作. 例:open(XXX.txt ...
- Linux中python3,django,redis以及mariab的安装
1. Linux中python3,django,redis以及mariab的安装 2. CentOS下编译安装python3 编译安装python3.6的步骤 1.下载python3源码包 wget ...
- 【数论】卢卡斯定理模板 洛谷P3807
[数论]卢卡斯定理模板 洛谷P3807 >>>>题目 [题目] https://www.luogu.org/problemnew/show/P3807 [输入格式] 第一行一个 ...
- 【 P3952】 时间复杂度 大模拟题解
题目链接 完全模拟 1.模拟结果 当我们的模拟程序执行结束时,直接执行模拟结果函数,用于比对我们的结果和数据给出的结果. bool yes(char a[],char b[]) { ;i<=;+ ...
- vue v-if控制显隐,页面加载出现闪现 v-cloak
<div id="divApp"> <div v-if="type === 'A'" v-cloak> A </div> & ...