52、构建生产部署流程

构建生产部署流程

在软件开发过程中,将应用程序部署到生产环境是一个至关重要的环节。一个高效、安全且可扩展的部署流程能够确保应用程序的稳定运行,减少故障和停机时间。本文将详细介绍如何构建一个生产部署流程,包括本地服务器安装、远程服务器上传以及针对特定应用服务器的部署等方面。

1. 编写安装到服务器的构建文件

在Tomcat 4.0部署中,我们对代码进行了一定简化,因为我们总是部署到本地主机。但在部署时,我们仍需严谨操作,将文件复制到 CATALINA_HOME/webapps 目录下,这样服务器重启时应用程序也会随之重启。

首先,我们设置一些属性来指向目标目录和文件:

<property name="target.deploy.directory"
  location="${env.CATALINA_HOME}/webapps"/>   
<property name="webapp.expanded.dir"
 location="${target.deploy.directory}/${target.appname}" />  
<property name="webapp.copied.file"
 location="${target.deploy.directory}/${target.appname}.war" />  

我们先复制未展开的WAR文件以便服务器重启,然后将其展开以安装到运行中的服务器。

1.1 卸载当前安装

卸载目标可以通过向 http://localhost:8080/manager/remove?path=/${target.appname} 发送 <get> 请求来实现,但我们在此省略该步骤。实际上,我们可以覆盖端口,大多数生产服务器运行在端口80。

另一个可考虑的选项是完全关闭应用服务器,这样可以确保所有生成的线程被销毁,所有内存被释放。如果这样做,部署后就不需要在Tomcat中注册应用程序,而是需要重启Tomcat,这是一项更具挑战性的任务。

1.2 清理安装

在生产环境中,我们总是清理之前的文件集。从Tomcat卸载应用程序后,等待几秒钟,然后删除展开和未展开状态的WAR文件。

<target name="clean" depends="unload" 
    description="clean up: unload app and delete all files">
  <sleep seconds="${target.sleep.seconds}" />  
  <delete file="${webapp.copied.file}" />   
  <delete dir="${webapp.expanded.dir}" />   
</target>  

有些服务器并不总是卸载所有库,特别是包含 javax 包的JAR文件。我们可以将 failonerror 标志设置为 false 以继续执行,但在解压时可能会遇到问题。如果这是一个常见问题,每次部署时都需要关闭Web服务器。

1.3 复制文件

清理完成后,我们复制新文件:

<target name="install-files" depends="clean">
  <copy file="${target.warfile}" 
    tofile="${webapp.copied.file}"/>
  <unzip src="${webapp.copied.file}" 
    dest="${webapp.expanded.dir}"/>
</target>

这样我们就可以通过服务器重启或管理URL调用运行应用程序。较为谨慎的做法是重启服务器,但我们选择热更新。

1.4 加载应用程序

再次通过管理URL调用启动程序,向 http://localhost:8080/manager/install?path=/${target.appname}&war=file://${webapp.expanded.dir} 发送 <get> 请求。整个过程包括删除、复制和展开操作,比平时多花费几秒钟,但总共仍只需15 - 20秒。

2. 上传到远程服务器

我们需要将本地安装和配置文件传输到远程服务器,目前选择使用FTP。所有操作都在顶级的 deploy.xml 文件中进行,该文件位于 webapp 目录下,负责管理部署。

2.1 配置上传

首先,Ant必须确定远程端所需的文件。为避免混淆并维护安全性,我们只发送必要的文件。如果为不同目标构建不同的WAR文件,确保没有人将它们安装在错误的机器上至关重要,去除其他构建和配置文件有助于实现这一点。

通过命令行定义远程主机名,例如 ant -Dhostname=eiger ,构建文件会加载该主机名的属性文件,并列出所需的文件。

<property name="config.file" 
  location="${systems.dir}/${hostname}.properties"/>
<property file="${config.file}" />    
<property file="${systems.dir}/common.properties" /> 
<property name="servertype.file" 
  location="${servertypes.dir}/${target.servertype}.properties"/>
<property file="${servertype.file}" /> 
<property name="redeploy.dir" location="dist/redeploy" />  
<property name="remote.config.file" 
  location="${remote.dir}/install-${hostname}.properties"/>
<property name="remote.build.file" 
  location="${remote.dir}/${target.servertype}.xml"/>

构建时的配置文件包含的信息比上传的文件更多,可能包含服务器密码等敏感信息。

我们还从这些属性中派生其他值,以便目标系统在必要时在其配置文件中定义不同的FTP和Telnet登录账户,或SSH隧道连接的不同服务器和端口:

<property name="ftp.server" value="${target.server}"/>
<property name="ftp.port" value="21"/>  
<property name="telnet.server" value="${target.server}"/>
<property name="telnet.port" value="23"/>  
<property name="ftp.userid" value="${login.userid}"/>
<property name="ftp.password" value="${login.password}"/>
<property name="telnet.userid" value="${login.userid}"/>
<property name="telnet.password" value="${login.password}"/>

构建文件还会读取应用服务器特定的配置文件,这些文件说明了服务器的特性,可用于控制WAR文件的生成。

2.2 构建上传文件目录

基于配置细节,Ant知道要上传哪些文件,并将它们复制到新的重新部署目录,将配置文件与WAR文件本身结合起来。

<target name="build-deployment-package" depends="init">
  <copy todir="${redeploy.dir}" file="${warfile}"/>
  <copy todir="${redeploy.dir}" file="${remote.config.file}"/>
  <copy todir="${redeploy.dir}" file="${remote.build.file}"/>
  <copy todir="${redeploy.dir}" file="${remote.dir}/build.xml"/>
  <copy todir="${redeploy.dir}" 
    file="${remote.dir}/common.properties"/>
</target>

本地部署可以直接从该目录运行,这是测试过程的最简单方法。通过快速测试 ${hostname} 是否等于 ${env.HOSTNAME} ,构建文件可以在本地系统上以这种方式进行部署。

<target name="install-local"
  depends="build-deployment-package" 
  if="is.localhost">
  <ant dir="${redeploy.dir}" inheritall="false"/>
</target>
2.3 上传文件

我们依靠可靠的 <ftp> 任务进行部署,连续调用三次。

<target name="upload" depends="build-deployment-package"  
    unless="is.localhost" >

  <echo>connecting to ${target.server}
    as ${ftp.userid} into ${ftp.remotedir}
  </echo>
  <ftp server="${ftp.server}" port="${ftp.port}"
    action="mkdir"                                   
    remotedir="${ftp.remotedir}"
    userid="${ftp.userid}"
    password="${ftp.password}"
    verbose="true" passive="true"
    ignoreNoncriticalErrors="true"
    />

  <ftp server="${ftp.server}" port="${ftp.port}"
    remotedir="${ftp.remotedir}"
    userid="${ftp.userid}" password="${ftp.password}"
    depends="true" verbose="true" passive="true"
    binary="true"
    ignoreNoncriticalErrors="true"
    >
    <fileset dir="${redeploy.dir}">                  
      <include name="**/*.war"/>                     
    </fileset>                                       
  </ftp>  

  <ftp server="${ftp.server}" port="${ftp.port}"
    remotedir="${ftp.remotedir}"
    userid="${ftp.userid}" password="${ftp.password}"
    depends="true" verbose="true" passive="true"
    binary="false"
    ignoreNoncriticalErrors="true"
    >
    <fileset dir="${redeploy.dir}">                  
      <include name="**/*.xml"/>                     
      <include name="**/*.properties"/>              
    </fileset>
  </ftp>  
</target> 

第一次 <ftp> 调用创建目标目录,第二次上传WAR文件,第三次以文本模式上传XML和属性文件,以便 <telnet> 可以将行尾转换为适合目标的格式。

2.4 准备运行远程构建

文件上传到远程服务器后,需要远程运行构建。这就需要用到 <telnet>

在调用 <telnet> 之前,我们需要解决不同服务器不同提示的问题,通过定义支持的不同目标平台的初始提示,以及将提示重置为我们可控内容所需的不同命令。如果不处理,Ant可能会将程序输出误认为是提示。

<target name="unix-prompts" if="target.isUnix">
  <property name="telnet.prompt.command"
    value="export PS1=${telnet.prompt}"/>
  <property name="telnet.initial.prompt" value="$"/>
</target>
<target name="windows-prompts" unless="target.isUnix">
  <property name="telnet.prompt.command"
    value="PROMPT ${telnet.prompt}"/>
  <property name="telnet.initial.prompt" value="&gt;"/>
</target>

如果要支持更多平台,可以将这些设置提取到特定于平台的设置文件中,根据 target.platform 属性动态加载。

2.5 远程调用Ant
<target name="install-remote"
    depends="upload,unix-prompts,windows-prompts"
    unless="is.localhost">
  <telnet server="${telnet.server}"  port="${telnet.port}"
      userid="${telnet.userid}" password="${telnet.password}"
      timeout="${telnet.timeout}" >
    <read string="${telnet.initial.prompt}"/>
    <write>${telnet.prompt.command}</write>   
    <read string="${telnet.prompt}"/>
    <write>cd ${telnet.cd.directory}</write>  
    <read string="${telnet.prompt}"/>
    <write>ant</write>                        
    <read string="${telnet.prompt}"/>  
  </telnet>
</target>

该目标使用提供的用户名和密码连接到远程服务器,设置了超时时间以确保远程运行构建文件的最大可能时间足够。然后通过网络发送三条命令。

要使此操作生效,Ant必须已经安装并在运行构建的账户路径中。如果构建失败,本地构建文件不会察觉,只有在测试时才会检测到问题。

3. 远程部署实战

实际运行构建时,可能会发现过程非常平常。在配置了Java、Tomcat和Ant的远程系统上设置正确的密码可能比较繁琐,但构建本身运行良好。以下是完整构建的一个片段,省略了之前的FTP上传和后续的功能测试。

install-remote:
   [telnet] Red Hat Linux release 7.1 (Seawolf)
   [telnet] Kernel 2.4.2-2 on an i686
   [telnet] login:
   [telnet] tomcat4
   [telnet]  Password:
   [telnet]  
   [telnet] [tomcat4@eiger tomcat4]$
   [telnet] export PS1=[done]
   [telnet]  [done]
   [telnet] cd /home/tomcat4/install
   [telnet] [done]
   [telnet] ant
   [telnet] Buildfile: build.xml
   [telnet] init:
   [telnet] install:
   [telnet] init:
   [telnet] unload:
   [telnet]       [get] Getting: 
                   http://127.0.0.1:8080/manager/remove?path=/antbook
   [telnet]      [echo] OK - Removed application at context path /antbook
   [telnet] clean:
   [telnet]    [delete] Deleting: /home/tomcat4/tomcat4.0/webapps/antbook.war
   [telnet]    [delete] Deleting directory 
                           /home/tomcat4/tomcat4.0/webapps/antbook
   [telnet] install-files:
   [telnet]      [copy] Copying 1 file to /home/tomcat4/tomcat4.0/webapps
   [telnet]     [unzip] Expanding: 
                   /home/tomcat4/tomcat4.0/webapps/antbook.war into 
                   /home/tomcat4/tomcat4.0/webapps/antbook
   [telnet] deploy:
   [telnet]       [get] Getting: 
                     http://127.0.0.1:8080/manager/install?path=/antbook
                       &war=file:///home/tomcat4/tomcat4.0/webapps/antbook
   [telnet]      [echo] OK - Installed application at context path /antbook
   [telnet] default:
   [telnet] BUILD SUCCESSFUL
   [telnet] Total time: 35 seconds
   [telnet] [done]

日志显示Ant已成功登录到远程服务器,并运行了刚刚上传的远程Ant构建。如果远程构建失败,本地构建会继续进行,我们可以通过修改 <telnet> 任务来等待 BUILD SUCCESSFUL 字符串,若收到 BUILD FAILED 消息则在几分钟后超时。目前我们依靠功能测试和后续将编写的新测试来检测问题。

4. 回顾部署流程

这个部署流程看似复杂,但我们从中获得了可扩展性、灵活性和更高的安全性。

  • 可扩展性 :添加新服务器只需添加两个配置文件(一个本地和一个远程),无需修改构建文件本身。开发人员可以轻松将其系统添加到项目中,而无需将密码存储在SCM系统中,单个受信任和安全的服务器可以确保生产系统的详细信息安全。
  • 灵活性 :我们现在可以支持多种不同的服务器类型。每种服务器都需要自己的安装构建文件,根据本地主机的配置文件安装Web应用程序,但具体细节由其自行处理。这些文件可以在项目之间重用,也可以定制以执行额外任务,如配置应用服务器本身。
  • 安全性 :完美的安全是一个遥远的理想,但我们的部署流程适用于安全系统,服务器控制使Tomcat管理应用程序仅对本地调用者可用。通过在 <ftp> 上使用 passive="true" 选项以及自定义 <ftp> <telnet> 的端口和服务器选项,它也可以通过SSH隧道工作。

我们还获得了与希望控制该过程的运维团队合作的能力。他们可以在自己的系统上保留服务器的配置文件并运行代码。我们甚至可以通过电子邮件或CD进行部署,无论文件如何到达服务器,在命令提示符下运行 ant 即可安装应用程序。

这个强大的构建过程虽然未深入探讨生成自定义WAR文件的内容,但步骤很明显,即使用每个目标和每个服务器的配置文件中的属性来控制 <webdoclet> <war> 。切换目标时需要在系统上进行干净构建,为避免每次都手动操作,可以将目标服务器的名称保存到 dist 目录中的属性文件中,下次构建时加载并与当前目标进行比较,服务器名称不同时触发清理操作。

5. 部署到特定应用服务器

不同的应用服务器有各自的部署步骤,下面我们将介绍Tomcat 4.0和4.1的部署情况。

5.1 部署到Tomcat 4.0

我们已经展示了如何部署到Tomcat 4.0,但管理Servlet存在安全风险,任何人都可以获取Base64编码的认证字符串并控制Web服务器。由于 <get> 任务不支持摘要认证,无法安全地将其部署到生产系统。

为确保安全,必须使用IP地址阀来保护Servlet,限制对给定IP地址的访问。在 server.xml 中添加以下片段,可配置阀以允许本地服务器进行管理请求:

<Context path="/manager" docBase="manager" 
  debug="0" privileged="true">
  <Valve 
    className="org.apache.catalina.valves.RemoteAddrValve"
    allow="127.0.0.1" />         
</Context>

前面介绍的部署过程在如此配置的系统中可以完美运行。

5.2 部署到Tomcat 4.1

在撰写本文时,Tomcat 4.1仍处于Alpha版本阶段。它包含一些使其成为开发目标极具吸引力的特性,如JMX管理API、重新设计的用于与构建工具集成的管理小程序,以及用于安装和删除应用程序的Ant任务:

<install url="http://${target.server}:${target.port}/manager"
    username="${target.username}"
    password="${target.password}"
        path="${target.appname}"
         war="file://${webapp.path}"/>

除了 <install> 任务,还有 <reload> <remove> 任务用于重新加载和删除Web应用程序,以及 <list> 任务用于列出所有已加载的应用程序。这些任务将请求传递给重新设计的管理小程序,似乎可以直接替代我们一直在使用的Tomcat 4.0部署目标,但需要一个 failonerror 标志,以便在应用程序缺失时告诉 <remove> 任务不中断构建。

如果现在要使用它,需要在卸载应用程序之前使用 <http> 测试 <condition> 任务来探测应用程序是否正在运行。实际上,这些任务只是向我们在之前章节中构建的相同URL发送HTTP GET请求,它们可能也适用于Tomcat 4.0。与我们的 <get> 请求一样,密码以Base64编码通过网络传输,并不安全。

我们对这些任务的想法很感兴趣,但尚未深入测试其长期效果。手册声称这些任务仅适用于本地主机,但这实际上是服务器端的配置问题,当前的Tomcat 4.1 Alpha版本仍然允许远程管理。为了安全的生产部署,必须像Tomcat 4.0一样将服务器配置为仅进行本地管理。要了解更多关于这些任务的信息,请参考Tomcat文档。

综上所述,构建一个完善的生产部署流程需要综合考虑多个方面,包括本地和远程部署的各个环节,以及不同应用服务器的特点。通过合理的配置和优化,可以实现一个高效、安全且可扩展的部署方案,确保应用程序在生产环境中的稳定运行。

构建生产部署流程

6. 不同部署方式的对比分析

为了更清晰地了解整个部署流程,我们对本地部署和远程部署进行对比分析。以下是两者的主要区别:
| 对比项 | 本地部署 | 远程部署 |
| — | — | — |
| 部署环境 | 本地主机,通常用于开发和测试 | 远程服务器,用于生产环境 |
| 文件传输 | 无需进行文件传输,直接在本地操作 | 需要通过FTP等方式将文件上传到远程服务器 |
| 安全性 | 相对较低,主要依赖本地系统的安全设置 | 要求更高,需要考虑网络传输安全、服务器访问控制等 |
| 复杂度 | 较低,操作简单,配置相对较少 | 较高,涉及远程服务器的配置、权限管理等 |
| 可扩展性 | 有限,主要针对本地开发环境 | 高,可以方便地添加新的远程服务器 |

通过这个表格,我们可以直观地看到本地部署和远程部署在各个方面的差异。在实际应用中,我们可以根据具体需求选择合适的部署方式。

7. 部署流程的优化建议

虽然当前的部署流程已经具备了可扩展性、灵活性和安全性等优点,但仍然有一些可以优化的地方。以下是一些建议:
- 自动化测试集成 :在部署前后增加自动化测试环节,确保应用程序在部署后能够正常运行。可以使用JUnit、Selenium等测试框架进行单元测试、集成测试和UI测试。
- 日志监控与分析 :加强对部署过程和应用程序运行时的日志监控,及时发现和解决潜在问题。可以使用ELK Stack(Elasticsearch、Logstash、Kibana)等工具进行日志收集、存储和分析。
- 版本管理与回滚机制 :建立完善的版本管理系统,记录每次部署的版本信息。同时,实现回滚机制,当部署出现问题时能够快速恢复到上一个稳定版本。
- 并发部署优化 :对于多个服务器的部署场景,可以考虑采用并发部署的方式,提高部署效率。可以使用Ansible、Puppet等自动化运维工具实现并发部署。

8. 部署流程的流程图

下面是整个生产部署流程的mermaid流程图:

graph LR
    classDef startend fill:#F5EBFF,stroke:#BE8FED,stroke-width:2px;
    classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px;
    classDef decision fill:#FFF6CC,stroke:#FFBC52,stroke-width:2px;

    A([开始]):::startend --> B(编写安装到服务器的构建文件):::process
    B --> C(上传到远程服务器):::process
    C --> D(远程部署实战):::process
    D --> E{部署是否成功?}:::decision
    E -->|是| F(回顾部署流程):::process
    E -->|否| G(进行问题排查与修复):::process
    G --> C
    F --> H(部署到特定应用服务器):::process
    H --> I([结束]):::startend

这个流程图展示了生产部署流程的主要步骤,包括构建文件编写、远程上传、部署实战、问题排查和特定服务器部署等。通过这个流程图,我们可以更清晰地了解整个部署过程的逻辑和顺序。

9. 常见问题及解决方案

在实际的部署过程中,可能会遇到一些常见问题,以下是一些问题及对应的解决方案:
- 文件上传失败 :可能是由于网络问题、FTP配置错误或文件权限问题导致。可以检查网络连接、确认FTP服务器配置是否正确,并确保文件具有正确的读写权限。
- 远程构建失败 :可能是因为Ant未安装、环境变量配置错误或构建文件存在语法错误。可以检查Ant是否已正确安装并配置到系统路径中,检查环境变量设置,以及仔细检查构建文件的语法。
- 应用程序启动失败 :可能是由于配置文件错误、依赖库缺失或端口冲突等原因。可以检查配置文件的参数是否正确,确保所有依赖库都已正确安装,以及检查端口是否被其他应用程序占用。
- 安全认证问题 :可能是密码错误、认证方式不支持或服务器配置限制。可以检查密码是否正确,确认使用的认证方式是否被服务器支持,以及检查服务器的安全配置。

10. 未来发展趋势

随着技术的不断发展,生产部署流程也在不断演进。以下是一些未来可能的发展趋势:
- 容器化部署 :Docker等容器技术的广泛应用,使得应用程序的部署更加轻量级、可移植和易于管理。通过容器化部署,可以将应用程序及其依赖打包成一个独立的容器,在不同的环境中快速部署。
- 无服务器架构 :无服务器架构将基础设施管理的工作交给云服务提供商,开发人员只需关注应用程序的业务逻辑。这种架构可以降低运维成本,提高开发效率。
- 人工智能与自动化运维 :利用人工智能技术实现自动化的故障预测、问题诊断和修复。通过机器学习算法分析大量的日志数据和性能指标,提前发现潜在问题并自动采取措施。
- DevOps文化的深入发展 :DevOps强调开发和运维团队的紧密合作,通过自动化工具和流程实现快速、频繁的部署。未来,DevOps文化将更加深入人心,推动软件开发和部署的效率提升。

总结

构建一个高效、安全且可扩展的生产部署流程是软件开发过程中的重要环节。通过本文的介绍,我们详细了解了从本地服务器安装到远程服务器上传,再到特定应用服务器部署的整个过程。同时,我们还对不同部署方式进行了对比分析,提出了优化建议,展示了部署流程的流程图,并解决了一些常见问题。

在未来,随着技术的不断进步,我们需要不断关注新的发展趋势,及时调整和优化部署流程,以适应不断变化的需求。通过合理的规划和实践,我们可以确保应用程序在生产环境中的稳定运行,为用户提供更好的服务。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值