文档结构  
翻译进度:已翻译     翻译赏金:10 元 (?)    ¥ 我要打赏

有时你不得不使用一个Windows系统,而不是你习惯的Linux机器来运行你的 Spring Boot 应用程序。也许你得调用一些本地的类库,这些类库依赖于Windows 操作系统底层,或者有其他什么原因。但是使用我们已经习惯使用的持续集成(CI)工具应该是必须的。

Windows?没问题,但是如果没有亲爱的Ansible可万万不行!

不管怎样,如果我们不得不要将我们的应用程序运行在Windows上,那是没问题的。但是我们不应该因此就被迫放弃我们现代软件开发的一些原则,比如 持续集成 (CI) 和持续部署(CD),或者对重复任务进行自动化,比如配置好一台服务器并且让我们的应用程序在上面运行。

第 1 段(可获 1.58 积分)

在我们目前的CI-Pipeline中,我们有一个Jenkins构建与测试我们的Spring Boot应用程序,并使用Ansible来配置(Linux)机器,以便我们可以在其上部署和运行我们的应用程序。 为什么不在Windows boxes上也这么做呢?

这似乎是白日做梦? Ansible不就是那个类似Unix/SSH的东西吗? 它该如何与Windows一起工作? 我们的Jenkins在Linux上运行 - 它有能力管理Windows环境吗?

windows_is_coming

嗯,这是可能的,有一种方法可以在这里使用Ansible🙂从版本1.7开始,Ansible还支持管理Windows机器! Ansible可以在本机PowerShell远程处理(和Windows远程管理WinRM)的帮助下执行此操作,而不是使用SSH,正如您在文档中读到的那样。

第 2 段(可获 1.59 积分)

你喜欢这个想法吗? 让我们去试试吧!

获取一个Windows(Vagrant)box

首先我们需要一个Windows box,以便我们在其上施展魔法。 如果你没有一个备用的box,那么微软的开发者网站已经为你提供了一些。 这真的让我感到惊讶,但是您可以下载Vagrant的镜像! 打开https://developer.microsoft.com/en-us/microsoft-edge/tools/vms,并选择一个虚拟机,如Vagrant平台的Microsoft Edge on Windows 10 Stable (14.xxx)。 您需要在您的计算机上运行一些虚拟化软件 - 例如,我的Mac上安装了VirtualBox。下载MSEdge.Win10_RS1.Vagrant.zip并解压缩。 于是:Windows Vagrant box dev-msedge.box就准备好了。

第 3 段(可获 1.66 积分)

因为微软似乎并没有给出这个box的元数据,所以我们需要通过以下方式添加:

vagrant box add dev-msedge.box --name "windows10"

最后我们需要安装Vagrant并配置agrantfile文件, 该文件可以在 与本文相关的github项目示例中找到:

Vagrant.configure("2") do |config|
  config.vm.box = "windows10"
  config.vm.guest = :windows
 
  # Configure Vagrant to use WinRM instead of SSH
  config.vm.communicator = "winrm"
 
  # Configure WinRM Connectivity
  config.winrm.username = "IEUser"
  config.winrm.password = "Passw0rd"
 
  config.vm.provider "virtualbox" do |vb|
     # Display the VirtualBox GUI when booting the machine
     vb.gui = true
   end
end

因为我们使用Windows,Vagrantfile主要调整Vagrant配置选项以使用WinRM而不是SSH。您可以在vagrant winrm文档中阅读更多详细信息。要启动一个完整的Windows 10,您只需克隆资源库并运行vagrant up。等待几秒钟,您的Windows box就可以运行了:

第 4 段(可获 1.24 积分)

windows10_vagrant_box

只有一件事情可能会导致vagrant up陷入“等待机器启动时超时[...]”。这是因为Microsoft没有以某种方式配置网络列表管理策略Windows远程管理(WinRM)完全可以与Vagrant一起工作。 为了解决这个问题,我们需要在(Windows box启动并运行后)手动进入“本地安全策略/网络列表管理策略(Local Security Policy / Network List Management Policies)”,在网络(Network)上双击,进入“网络位置(Network Location)”选项卡,将“位置类型(Location type)”设置为“私有(private )”,“用户权限(User permissions)” 设置为用户可以更改位置(User can change location)。 做出这些改变后,我们的vagrant up就可以正常工作了。

第 5 段(可获 1.28 积分)

使Windows Ansible准备就绪

在Windows box与Ansible进行平滑的协同工作前还需要一些步骤。 这些步骤完全依赖于Windows版本。

如果你正在使用上面提到的从developer.microsoft.com下载的Windows版本,那就没什么太多的事情要做。 因为Powershell 3.0或更高版本对于Ansible和Windows 10是开箱即用的,我们只需要在Windows box中运行此脚本即可为Ansible配置远程处理。 最简单的方法是使用iwr和iex Powershell命令:

第 6 段(可获 1.35 积分)

iwr https://raw.githubusercontent.com/ansible/ansible/devel/examples/scripts/ConfigureRemotingForAnsible.ps1 -UseBasicParsing | iex

使用旧版本可能会导致更复杂的安装过程。有时您需要通过运行以下命令来允许脚本执行(这是许多可能的解决方案之一,这只是“恰好使其正常工作”的一种方式):

Set-ExecutionPolicy -ExecutionPolicy Unrestricted -Scope CurrentUser

如果没有Powershell 3.0或更高版本(请参阅powershell-版本-和它们的-windows-版本的列表)。要查看Powershell版本,请运行

get-host

要升级到Powershell 3.0,还给你准备了另外一个脚本

我们还需要知道Windows box的一些安全认证。您也可以使用Kerberos进行操作,但是应该警告您配置是相当复杂的。我会建议您使用良好的旧的管理帐户,这是使用Ansible连接到Windows box除Kerberos之外的第二个可能的选项。看看我们的Microsoft Edge Windows 10 Vagrant Box安装说明告诉了我们所有需要的秘密(IEUser和Passw0rd!)。

第 7 段(可获 1.93 积分)

测试Ansible连接

以上差不多就是所有我们需要的为Windows box测试Ansible的内容了。 为了试一试,我们需要一个ansible的可执行的脚本。 这应该包含一个具有我们的Windows box的IP(在本例中是localhost)的hostsfile和一个正确的Ansible配置。 我们的github仓库提供了一个可用的配置示例

ansible_user: IEUser
ansible_password: Passw0rd!
ansible_port: 55986
ansible_connection: winrm
ansible_winrm_server_cert_validation: ignore

加上我们可运行的Windows 10 Vagrant Box和准备好的Ansible,我们可以运行第一次连接测试。 一个很好的方法是使用win_ping模块,这是许多Ansible Windows模块之一。 只需确保在Linux或Mac上安装最新的Ansible发行版。 写这篇文章时是2.2.0.0,我通过PyPI从pip安装。 在Windows上安装ansible是另外一个故事了...要开始测试,请键入以下命令:

第 8 段(可获 1.85 积分)
ansible restexample-windows-dev -i hostsfile -m win_ping

如果你得到SUCCESS,这表示一切都没有问题:

127.0.0.1 | SUCCESS => {
    "changed": false, 
    "ping": "pong"
}

但是如果你得到UNREACHABLE!,那意味着可能有很大麻烦。这可能会导致需要大量工作去调试。就我而言,复查或多次核对证书很有帮助(尝试登出再登入你的Windows box)。如果你得到超时的结果,那么检查你是否完成了上文 使Windows Ansible准备就绪 中里描述的所有步骤。

准备一个可运行且可搭建的Spring Boot App

这是非常容易的一部分,但是如果你想要部署一个Spring Boot app,你必须有一个工作示例,对吧!?! 🙂 你可以花几分钟自己搭建一个(e.g. 利用 Spring Initializr 或者参考非常棒的 Spring starter guides),使用你已经搭建过的,或者直接用这个blog用的示例文件 (一个非常简单的 REST service app).

第 9 段(可获 1.86 积分)

无论你选择哪种方式: 确保有一个正在运行的能够产生可运行Spring Boot jar-File的构建。在我们的示例restexamples中,通过运行下列语句你可以得到所需的restexamples-0.0.1-SNAPSHOT.jar

mvn clean package

对于Windows配置的ansible playbooks的建议

在你开始为配置Windows box写你第一个ansible playbook之前,先让我给你一些建议。如果你以前有用Ansible来管理Unix类计算机的经验,一开始你可能还不了解下述这些事情:

更新Ansible到最新版本。每次更新Ansible对Windows的支持都会越来越好。很多Windows模块只能在latest最新的Ansible版本下运行——因此保证你安装了最新的版本

第 10 段(可获 1.54 积分)

不要觉得Ansible Windows的文档和你过去常用的文档在质量或数量上有得一比。在这里我不想困扰任何人并且伟大的工作还是由Ansible团队完成的!但是在Windows上从事Ansible工作并不是唯一的你采用过的光鲜的方式。有时你必须尝试3-5个不同的模块,直到最终找到一个工作方案来解决你的问题。

总是保证路径中主反斜线后面跟着一个反斜线。如果你有一个这样的路径 C:\temp 你就应该在你的草稿本上写上这个:

"C:\\temp"

不要幻想这样一个路径 C:\ProgramFiles (x86)\XYZ 会工作。尤其是当你遇到一个相当重要的需要Java运行时环境(JRE) 来启动Java应用程序的情况.。如果你使用这个安装好的,也可以试着使用可变路径而不是像Oracle这样放在一个成功安装的JRE之后的方案:

第 11 段(可获 1.95 积分)
"C:\\\ProgramData\\\Oracle\\\Java\\\javapath\\\java.exe"

一个完整的例子

这篇博客所示例项目已经附带一个完整的Ansible文档,该文档能展示如何设置 一个Windows box,这样我们就可以在其上部署和运行一个 Spring Boot 应用程序。对该程序让我们有个更详细的了解吧!

首先,我们准备好 Windows box来处理我们的新部署:

- hosts: "{{host}}"
  vars:
    spring_boot_app_path: "C:\\spring-boot\\{{spring_boot_app_name}}"
    path_to_java_exe: "C:\\ProgramData\\Oracle\\Java\\javapath\\java.exe"
 
  tasks:
  - name: Create directory C:\spring-boot\spring_boot_app_name, if not there
    win_file: path={{spring_boot_app_path}} state=directory
 
  - name: Install nssm (non-sucking service manager) via chocolatey
    win_chocolatey:
      name: nssm

在定义了一些必要的路径后,我们创建一个部署自己的Spring Boot应用程序的目录并借助于Windows的软件包管理器chocolatey的帮助下来安装 非吞服务管理程序(nssm),这两个都在和各种Windows box一同运行的情况下能帮上大忙。

第 12 段(可获 1.3 积分)

后者将给Windows带来云端打包管理的功能,这你可能已经在Linux和Mac(使用冲泡)机器上使用过。而nssm将使我们有能力作为真正的Windows服务商,来运行我们的Spring Boot应用程序,并具有重启后自动重新启动的所有好处。通过许多可能的解决方案进行了几次实验,我发现这是一种非常优雅的方式在Windows上运行Spring Boot应用程序。

接下来的步骤可能并不直观,却是非常有趣的。我花了一些时间来弄清楚这些,接下来我们将会讨论到这些改变:

第 13 段(可获 1.26 积分)
  - name: Stop Spring Boot service, if there - so we can extract JRE & other necessary files without Windows file handle problems
    win_service:
      name: "{{spring_boot_app_name}}"
      state: stopped
    ignore_errors: yes
 
  - name: Install Java Runtime Environment (JRE) 8 via chocolatey
    win_chocolatey:
      name: jre8
 
  - name: Copy Spring Boot app´s jar-File to directory C:\spring-boot\spring_boot_app_name
    win_copy:
      src: "{{spring_boot_app_jar}}"
      dest: "{{spring_boot_app_path}}\\{{spring_boot_app_name}}.jar"

首先要停止 Spring Boot 服务,它将接管我们的 Spring Boot 应用程序。 好吧 - 我听到你说这很奇怪。确实如此,但它与第一次执行我们的 playbook 没有关系 - 但是其他情况下,请从第二条开始。

因为 Windows 具有称为共享冲突错误的“好功能”:如果正在运行的进程对文件或目录有一个句柄,Windows无法让您修改或删除它。 但这正是我们想要做的:我们希望能够更新使用过的JRE或其他文件,以使我们的Spring Boot应用程序运行正常。 所以这就像一个错失的建议:总是先停止你的进程或服务,然后再采取行动!

第 14 段(可获 1.64 积分)

我提到了我们的脚本的第一次运行 - 如果服务不存在,它将会中断。 因此,我们使用一个非常好的 Ansible 功能 - 我们借助于 ignore_errors: yes 忽略错误。 现在,如果为了防止共享冲突错误已经安装了服务,它将被停止,或者如果以前没有安装任何服务,则 win_service  模块会显示一个错误 - 这将被忽略。

现在我们可以下载并提取必要的 Java 运行时环境,或者只需在 chocolatey 的帮助下安装 jre8 软件包即可。 在第三步中,我们将预构建的 Spring Boot 应用程序作为 jar 部署到我们之前创建的目录中。

第 15 段(可获 1.38 积分)

安装并配置 Windows 服务

我们终于可以将我们的 Spring Boot 应用程序安装为 Windows 服务了:

  - name: Install Spring Boot app as Windows service (via nssm), if not already there - but remain stopped to configure Application directory
    win_nssm:
      name: "{{spring_boot_app_name}}"
      application: "{{path_to_java_exe}}"
      app_parameters:
          "-jar": "{{spring_boot_app_path}}\\{{spring_boot_app_name}}.jar"
      state: stopped
 
  - name: Set the Application path for the Spring Boot app to the folder where the needed native libraries reside
    raw: nssm set {{spring_boot_app_name}} AppDirectory {{spring_boot_app_path}}
 
  - name: Fire up Spring Boot app Windows service
    win_service:
      name: "{{spring_boot_app_name}}"
      state: restarted

第一件事是在 win_nssm 模块的帮助下定义 Windows 服务。 我们在应用程序(application 路径(path)选项中填入 java.exe 的安装路径,将 -jar spring-boot-app.jar  作为应用程序参数app_parameters)。 服务状态暂时为停止,因为我们还要配置另一个 nssm 服务选项

如果您的应用程序需要在 jar 文件目录下包含本地库,如 dll 文件,那么 nssm 服务选项 AppDirectory 可能会非常重要。 可以通过nssm edit servicename 手动配置重要的 nssm 选项,输入该命令将会弹出如下内容:

第 16 段(可获 1.49 积分)

nssm_startup_directory

但是我们需要在 Ansible 脚本中更改 Startup Directory 的值。 可惜的是,由于 win_nssm 模块不能提供配置选项,所以我们需要依靠 raw 模块。 在 nssm set servicename AppDirectory path 的帮助下,我们能够实现这一点。

使用 win_service,我们现在可以将 Spring Boot 应用程序作为 Windows服务安全启动了。所以让我们开始实践,并运行我们的 Ansible playbook! 只要确保你的 Windows box 正在运行并且 Ansible 准备就绪:

ansible-playbook -i hostsfile restexample-windows.yml --extra-vars "spring_boot_app_jar=../restexamples/target/restexamples-0.0.1-SNAPSHOT.jar spring_boot_app_name=restexample-springboot host=restexample-windows-dev"

该脚本应该产生如下输出:

running_ansible_playbook_windows

Smoketest

你可能注意到,我们并没有探讨脚本的最后一步。 让我们看看 restexample-windows.yml:

第 17 段(可获 1.46 积分)
  - name: Wait until our Spring Boot app is up & running
    win_uri:
      url: "http://localhost:8080/swagger-ui.html"
      method: GET
    register: result
    until: result.status_code == 200  
    retries: 5
    delay: 5

作为最后一步,检查我们的Spring Boot应用程序是否正常运行是一个很好的做法。这可以通过 win_uri 模块实现。测试只是使用一些我们可以做的有意义的HTTP GET。 因此,小例子应用利用了SpringFox的强大功能,它生成JSON API文档,并提供一个小型Web应用程序,我们可以做一个GET 请求您的http:// localhost:8080 / swagger-ui.html。 所以如果SwaggerFox应用程序启动并运行(并返回一个HTTP Statuscode 200),我们假设我们的Spring Boot应用程序正常运行。

第 18 段(可获 1.36 积分)

无限可能…

现在我们能够在Windows虚拟机(Vagrant)上部署Spring Boot应用,并且在微软机器上运行更复杂的场景。尝试部署一个基于Spring Boot的有历史的优秀SOAP服务,并行部署10次,每次使用一个单独的端口? 或者尝试你想运行的其他运用!

未来有无限可能。我非常希望听到关于你使用Ansible在windows上部署应用的任何消息。

第 19 段(可获 0.94 积分)

文章评论

班纳睿
这篇文章的排版显示出问题了 @CY2@coyee