在Java/Tomcat on Windows Azure一文中介紹了如何將Web Project打包後送上Windows Azure平台的方法,這個方法基本上是正確的,
也是官方文件所建議使用的。但仔細想想,每次的打包動作都必須包含兩樣東西: JDK與Tomcat,至少需要近40MB的大小,上傳不僅耗時
Tomcat/Java in Azure – Deployment tips
文/黃忠成
問題在哪?
在Java/Tomcat on Windows Azure一文中介紹了如何將Web Project打包後送上Windows Azure平台的方法,這個方法基本上是正確的,
也是官方文件所建議使用的。但仔細想想,每次的打包動作都必須包含兩樣東西: JDK與Tomcat,至少需要近40MB的大小,上傳挺耗時的,
這兩樣東西不會經常變動,理論上只需要上傳一次就夠了不是嗎?有沒有更快速的方法呢?
使用Blob來儲存Runtime
在Using Windwos Azure Storage Services with Java一文中,我介紹了如何在Java中使用Table、Blob及Queue,其中的Blob就很適合拿來儲存
JDK與Tomcat這兩個Runtime,手法很簡單,下面是大概的流程。
- 上傳JDK與Tomcat到Blob Service
- 撰寫一個命令列應用程式(BlobDownload),由Blob將這兩個檔案下載到Worker Role
- 將BlobDownload.exe封裝到Web Project的War中
- 修改Azure Project中的startup.cmd,令其執行BlobDownload.exe來下載JDK與Tomcat
看起來不難是吧?下面的程式就是BlobDownload的原始程式碼,這個程式是使用C#寫的。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.WindowsAzure;
using Microsoft.WindowsAzure.StorageClient;
using System.Configuration;
using Microsoft.WindowsAzure.ServiceRuntime;
namespace BlobDownload
{
class Program
{
private static CloudBlobClient _client = null;
private static CloudBlobContainer _container = null;
static void InitizlieBlob()
{
CloudStorageAccount.SetConfigurationSettingPublisher((configName, configSetter) =>
{
// Provide the configSetter with the initial value
configSetter(RoleEnvironment.GetConfigurationSettingValue(configName));
RoleEnvironment.Changed += (sender, arg) =>
{
if (arg.Changes.OfType().Any((change) =>
(change.ConfigurationSettingName == configName)))
{
// The corresponding configuration setting has changed, so propagate the value
if (!configSetter(RoleEnvironment.GetConfigurationSettingValue(configName)))
{
// In this case, the change to the storage account credentials in the
// service configuration is significant enough that the role needs to be
// recycled in order to use the latest settings (for example, the
// endpoint may have changed)
RoleEnvironment.RequestRecycle();
}
}
};
}
);
var storageAccount = CloudStorageAccount.Parse(ConfigurationManager.AppSettings["DataConnectionString"]);
_client = storageAccount.CreateCloudBlobClient();
// Get and create the container
_container = _client.GetContainerReference(ConfigurationManager.AppSettings["blobName"]);
}
static void Main(string[] args)
{
InitizlieBlob();
CloudBlob blob = _container.GetBlobReference(args[0]);
if (args.Length > 1)
blob.DownloadToFile(args[1]);
else
blob.DownloadToFile(blob.Name);
}
}
}
嗯,為何不使用Java呢?很簡單,因為JDK還沒下載到…….,有了這個程式後,接下來先透過Storage Explorer來上傳JDK與Tomcat到Blob Service。
圖1
圖2
按下OK後,Eclipse會跳出一個日期時間格式的錯誤訊息,不需要理他,Blob Container還是建立成功了,只要重新按下Open按鈕即可看到。預設BlobDownload使用runtime作為Blob Container名稱,你可以修改BlobDownload.exe.config來改變這個名稱。
<?xml version="1.0"?>
<configuration>
<appSettings>
<add key="DataConnectionString" value="DefaultEndpointsProtocol=http;AccountName=<your account>;AccountKey=<your account key>"/>
<add key="blobName" value="runtime"/>
</appSettings>
<startup><supportedRuntime version="v2.0.50727"/></startup></configuration>
分別將JDK與tomcat上傳到Blob。
圖3
圖4
圖5
接著刪除Azure Project\WorkerRole1\approot下的JDK及Tomcat兩個ZIP檔,然後複製BlobDownload.exe及BlobDownload.exe.config到此目錄下,整個專案結構如圖6。
圖6
最後修改startup.cmd,加入BlobDownload的部分。
:: *** Sample startup script containing the steps for starting ApacheTomcat and deploying a WAR file. :: *** (Last tested with Apache Tomcat 7.0.22)
:: To use the sample, follow these steps: :: 1) Copy all this content into approot/startup.cmd in the role folder, close this file, and edit the copy :: 2) Place a JDK distribution as jdk.zip under approot :: 3) Place an Apache Tomcat 7.x distribution as tomcat7.zip under approot in your project :: 3.1) If you want to download the server into Azure directly from a URL instead, then :: uncomment the next line and modify the URL as appropriate: :: cscript /NoLogo "util\download.vbs" "http://archive.apache.org/dist/tomcat/tomcat-7/v7.0.22/bin/apache-tomcat-7.0.22.zip" "tomcat7.zip"
:: 4) Update SERVER_DIR_NAME below as appropriate: :: (IMPORTANT: There must be no trailing nor leading whitespace around the setting)
SET SERVER_DIR_NAME=apache-tomcat-7.0.27
:: 5) To deploy your own WAR file, place it in approot and update WAR_NAME below: :: (IMPORTANT: There must be no trailing nor leading whitespace around the setting)
SET WAR_NAME=UsingStorage.war
:: ***************************************************************** :: *** Deployment and startup logic :: *** (Do not make changes below unless you know what you're doing.
rd"\%ROLENAME%" mklink/D "\%ROLENAME%" "%ROLEROOT%\approot" cd/d "\%ROLENAME%" BlobDownload.exe JDK.ZIP BlobDownload.exe apache-tomcat-7.0.27-windows-x64.zip cscript/NoLogo util\unzip.vbs jdk.zip "%CD%" cscript/NoLogo util\unzip.vbs apache-tomcat-7.0.27-windows-x64.zip "%CD%" copy %WAR_NAME% "%SERVER_DIR_NAME%\webapps\%WAR_NAME%" cd"%SERVER_DIR_NAME%\bin" set JAVA_HOME=\%ROLENAME%\jdk set PATH=%PATH%;%JAVA_HOME%\bin cmd/c startup.bat
@ECHO OFF if %ERRORLEVEL%==0 exit %ERRORLEVEL% choice /d y /t 5 /c Y /N /M "*** Windows Azure startup failed - exiting..." exit %ERRORLEVEL% |
完成後調整Azure Project的Deploy模式為Deployment to cloud,然後點選Build All,再次查看產生的.cspkg大小,由原來的80MB降到了12MB。
圖7
這種手法還可以更精煉化,例如將Web Project所引用的Library分離出來,於startup.cmd中設定classpath,將.WAR縮得更小。
BlobDownload程式下載
http://www.code6421.com/BlogPics/Azure_Java4/BlobDownload.zip