PROBLEM
Typically, when using ZipDeploy to push a WAR file (ex: my-app.war
) to an Azure instance, we need to:-
- Rename
my-app.war
toROOT.war
. - Place
ROOT.war
underwebapps/
. - Zip up
webapps/
. - Use ZipDeploy to push the zip file to an Azure instance.
This zip file will automatically be unzipped under site/wwwroot
:-
D:\home\site\wwwroot └── webapps └── ROOT.war
Tomcat detects ROOT.war
and will try to unpack the WAR file under ROOT/
:-
D:\home\site\wwwroot └── webapps ├── ROOT │ ├── META-INF │ │ └── ... │ └── WEB-INF │ └── ... └── ROOT.war
The problem is sometimes Tomcat is unable to fully unpack ROOT.war
because some files may be locked by some running processes. As a result, the web page fails to load and shows 404 error.
SOLUTION
A better and more stable solution is to use WarDeploy to push WAR file to an Azure instance because:-
- It simplifies the deployment process because we don’t need to create a zip file with
webapps/
containing a WAR file namedROOT.war
. - Instead of relying on Tomcat to unpack the WAR file, WarDeploy will do the unpacking step elsewhere before copying to
site/wwwroot/webapps/
.
To use WarDeploy, you can use curl
command or PowerShell script to do so.
Here’s an example of the PowerShell script:-
Param( [string]$filePath, [string]$apiUrl, [string]$username, [string]$password ) $base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $username, $password))) Invoke-RestMethod -Uri $apiUrl -Headers @{ Authorization = ("Basic {0}" -f $base64AuthInfo) } -Method POST -InFile $filePath -ContentType "multipart/form-data"
If the PowerShell script above is called deploy.ps1
, to push my-app.war
to my-app
Azure instance:-
deploy.ps1 -filePath D:\my-app.war -apiUrl https://my-app.scm.azurewebsites.net/api/wardeploy -username [USER] -password [PASSWORD]
Depending on the size of the WAR file, you may get “The operation has timed out” error after 100 seconds:-
Invoke-RestMethod : The operation has timed out At D:\agent\_work\2ea6e947a\my-app\deploy.ps1:18 char:1 + Invoke-RestMethod -Uri $apiUrl -Headers @{Authorization=("Basic {0}" ... + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-RestMethod], WebException + FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeRestMethodCommand
This will most likely to occur if the WAR file is too big (80MB+).
To fix this, increase the time out duration by adding -TimeoutSec
option to Invoke-RestMethod
statement:-
Invoke-RestMethod [OTHER_OPTIONS...] -TimeoutSec 300