Pull to refresh

Публикуем веб приложения Ruby, Python, Node.js, Perl и Java в Azure Cloud Services

Reading time 35 min
Views 14K
image В этой статье мы рассмотрим способ разворачивания веб приложений, написанных с использованием различных технологий, в облаке Azure Cloud Services. А именно это будет Ruby, Python, Node.js, Perl и с некоторыми оговорками также Java и Railo (ColdFusion). В качестве примера Ruby приложения будем использовать Redmine, работающий на Ruby on Rails, в Python пойдет Lightning Fast Shop, работающий на Django, в Node.js будем использовать небольшой проект с использованием express.js, на Perl будем ставить пустой проект Mojolicious. Целью данной статьи не является экскурс по всем этим веб технологиям, а лишь показать удобный и универсальный способ публикации в облаке Azure. Так что кода на Ruby, Python или Perl в ней не будет. Зато будет много скриншотов, shell-скриптов и инструкций по упаковке и развертыванию приложений.


Итак, что же такое Azure Cloud Services и с чем его едят:

К сожалению, обилие маркетинговых материалов в сети плохо раскрывает эту тему и создает много шума. А мы попробуем обсудить этот вопрос человеческим языком, понятным для простых веб разработчиков. Во первых, что важно понимать разработчику, который хочет узнать как пользоваться Azure Cloud Services, это то что данная услуга фактически представляет собой фабрику виртуальных машин. Как это реализовано технически не так важно, главное, что нам интересно это то, что инфраструктура Azure может достаточно быстро и автоматически предоставить нам некоторое количество идентичных виртуальных машин с некоторым количеством ресурсов, на которых может работать наш веб сайт или другое приложение.

В системе Azure все эти виртуальные машины примерно одинаковые и могут быть Windows Server 2008, 2008 R2 и 2012. Видимо, это сделано потому что создание таких виртуальных машин обходится системе достаточно дешево и сами эти машины потребляют не много ресурсов плюс одинаковыми виртуалками легко управлять. Хотя лично мне не известно внутреннее устройство Azure Cloud Services и это лишь предположение. Главное отличие от VPS-хостинга в том что нам не нужно настраивать эти виртуальные машины. Система Azure сама развернет виртуальную машину и сама установит на нее наше приложение, когда это будет нужно. Это позволяет динамически создавать и удалять виртуальные машины по мере необходимости, автоматически и без нашего участия. Для того чтобы реализовать эту технологию наше приложение должно быть особым образом написано и упаковано, чтобы система знала как его устанавливать.

Зачем это выгодно нам: В первую очередь это экономия ресурсов, а значит и наших денег (зависит, конечно, от цены услуги). Сайтам не все время нужно максимальное количество ресурсов. Если покупая VPS или Dedicated хостинг мы вынуждены брать максимальную конфигурацию, которая нам может потребоваться, то в случае с Azure Cloud Services мы можем платить только за те виртуальные машины, которые нам нужны в данный момент. Когда нагрузка на ресурс будет возрастать, система Azure будет автоматически выделять новые виртуальные машины для обслуживания нашего сайта. Когда нагрузка упадет, виртуальные машины вернуться системе и мы не будем за них платить.

Зачем это нужно хостеру (в данном случае Microsoft): Причина та же – экономия ресурсов. Обычно разным сайтам и сервисам максимальное количество ресурсов нужно не одновременно. Значит, это позволяет провайдеру захостить больше веб сайтов на меньшем количестве физических ресурсов. Та же экономия, как и в случае с shared hosting – не всем нужна пиковая нагрузка одновременно. Поэтому shared hosting обычно и стоит дешевле.

А теперь неприятный момент – это усложняет разработку приложения и привязывает нас к платформе. Вернее не усложняет, а немного меняет подход, делает его не столь привычным. Ведь обычно разработчики привыкли, что есть некоторый сервер, к которому можно открыть SSH сессию или RDP, где выполнить различные команды по конфигурации нужной им среды. Несмотря на то, что теоретически в системе Azure Cloud Services тоже можно открыть RDP к виртуальной машине, толку от этого чуть, разьве что в отладочных целях. Ведь через 5 минут система может наплодить еще десяток таких «серверов» которые не будут сконфигурированы вами вручную. А потом и вовсе удалить ваш настроенный сервер без предупреждения.

Решить проблему конфигурации серверов достаточно просто – нужно упаковать наше приложение перед публикацией так, чтобы система сама знала как его настраивать, какие действия нужно выполнить на сервере чтобы наше приложение заработало. В этот пакет кроме самого приложения должны входить также все его зависимости, которые могут понадобиться на сервере для его запуска и настройки. А самое главное там должны быть скрипты, которые смогут сконфигурировать чистую новую виртуальную машину под наше приложение. Система Azure будет разворачивать этот пакет и выполнять скрипты каждый раз, когда новая виртуальная машина входит в строй.

В этой статье мы будем использовать такое решение, чтобы сохранить максимальную независимость от платформы. Ведь платформозависимость и невозможность затем переехать на другой сервис – один из главных факторов тормозящих переход на облачные сервисы на данный момент. Не случайно мы выбрали общеизвестные приложения для примеров и технологии с открытым кодом – способы настройки этих приложений на других платформах общеизвестны. А значит при необходимости можно переносить приложение с одной платформы на другую. Итак, достаточно теории, перейдем к практике. Сейчас будем рассматривать пример использования по каждой технологии по очереди. Так как для каждой технологии будет много одинаковых действий, чтобы сократить статью я не буду повторяться, поэтому я советую читать весь текст подряд, даже если данную конкретную технологию вы использовать не собираетесь.

Ruby


Начнем с Ruby и рассмотрим на ее примере все основные положения, так что эта глава будет самой длинной. Если вы с Ruby не работали – ничего страшного. Мы практически не будем использовать специфических команд, а действия по настройке всех платформ однотипны. Во первых нам понадобится рабочая станция Windows. Мы будем использовать Helicon Zoo для запуска Ruby приложений на IIS как на рабочей станции, так и в системе Azure. Мало того что так будет легче конфигурировать среду выполнения для нашего приложения, такая конфигурация в Azure создаст значительно лучшее и более надежное с точки зрения производительности решение, чем запуск Ruby процесса с встроенным сервером на 80-м порту, как это часто делают в других инструкциях. Плюс запуск приложения в IIS еще и позволит нам включить в приложение другие технологии и возможности самого IIS, добавить к сайту секции на ASP.NET и других языках перечисленных в этой статье, сконфигурировать SSL и URL Rewriting, полноценно использовать многоядерные машины, отгружать статические данные средствами самого IIS что также значительно сэкономит ресурсы, и многое другое.

Если вы уже работали с Ruby, то возможно на вашей рабочей станции уже есть установленная и сконфигурированная версия Ruby, с установленными gem-ами и т.д. Это все хорошо, но как ее перенести в Azure Cloud Services? Используя же пакеты Helicon Zoo, мы сможем упаковать все зависимости приложения в один архив, что позволит нам легко переносить его на другие сервера и в Azure Cloud Services в том числе. Так что для верности мы будем устанавливать свежую версию Ruby из репозитория Helicon Zoo, независимо от наличия другого Ruby на вашей машине.

Итак, пройдем по ссылке и установим Microsoft Web Platform Installer. Запустим его и нажмем Options и в открывшемся окне добавим Helicon Zoo feed: http://www.helicontech.com/zoo/feed.xml

На рабочей станции советую также выбирать IIS Express в качестве сервера, т.к. с ним будет проще работать для тестов и потребуется меньше настроек.



Далее нужно установить Windows Azure SDK и легче всего это сделать, воспользовавшись все тем же Web Platform Installer. Введите в поиске «Azure SDK 2.1» или просто нажмите на эту ссылку. Если на момент прочтения статьи версия SDK устареет и ссылка не будет работать, просто найдите более новую в списке:



В Azure SDK входит набор утилит по созданию и тестированию пакетов для Windows Azure Cloud Services, который нам и понадобится. Мы будем использовать утилиты командной строки и не будем использовать Visual Studio и другие инструменты по автоматической публикации сайтов, так как я старался минимизировать количество «магии» в статье. Тем более раз мы публикуем приложение на Ruby, то сомнительно, что именно Visual Studio будет вашим инструментом разработки. Поэтому я предлагаю ставить именно базовый Azure SDK, а не Azure SDK for Ruby. В последний уже входит некоторый дистрибутив Ruby и набор конфигураций, которые возможно и не плохи, но определенно не те, которые будут использованы в этой статье. Если вы все же привыкли использовать Visual Studio для создания пакетов Azure, то для вас не составит труда создать нужный пакет вручную, пользуясь этой статьей.

Теперь давайте создадим Ruby приложение на нашей рабочей станции. Если у вас уже есть готовое Ruby Rack приложение, то вам нужно запустить Web Platform Installer, и установить «Ruby project» из секции Zoo -> Templates. Далее следуйте инструкциям на пригласительной странице получившегося шаблонного сайта.



Однако всем уже, похоже, надоела установка «Hello World» приложений, а написание более продвинутого кода выходит за рамки этой статьи, поэтому мы просто будем ставить Redmine, как достаточно сложное и известное Ruby on Rails приложение с открытым кодом. Для этого откройте все тот же Web Platform Installer, зайдите в Zoo -> Applications и установите Redmine. По завершении установки запустится процесс развертывания приложения, который просто автоматически выполняет шаги, описанные в этой статье(англ.) в разделе Manual installation.



При этом никакой предварительной установки Ruby, Dev Kit, gem-ов и даже самого IIS Express не требуется – обо всем позаботится Web Platform Installer и Helicon Zoo. Все требуемые пакеты будут загружены из интернет и установлены на вашу рабочую станцию. После окончания установки всех компонентов вы должны увидеть первую страницу Redmine. Конечно, по-хорошему еще нужно сконфигурировать правильную базу данных, но для нашего теста уже вполне достаточно используемой по умолчанию SQLite.

Обратите внимание на структуру файлов получившегося сайта (может понадобится нажать F5 в WebMatrix чтобы обновить вид папок):



В папке GEM_HOME собраны все gem-ы, от которых зависит наше приложение. Именно оттуда они и будут загружаться во время работы. Файл deploy_done.rb – это скрипт deploy.rb, выполнение которого мы наблюдали на предыдущем шаге, на странице с сообщением «Application deployment in progress». По завершении его выполнения Helicon Zoo переименовал этот файл в deploy_done.rb, чтобы исключить повторный запуск без надобности. Если вам понадобится запустить процесс по-новой, просто переименуйте этот файл обратно в deploy.rb и со следующего запроса к серверу скрипт будет запущен снова. В этом скрипте содержатся стандартные команды нахождения и установки недостающих зависимостей, создания при необходимости и миграций базы данных и т.п. Это один из способов как выполнять команды в контексте приложения подробнее о котором можно прочитать в документации Helicon Zoo(англ.). Другой способ – это запустить Helicon Zoo Manager (for IIS Express) из Start -> Programs -> Helicon –> Zoo, а там, выбрав наше приложение, можно нажать на Start Web console или Start IDE.



Web console позволяет выполнять команды в контексте приложения и от лица пользователя этого приложения (Application pool user в случае IIS и интерактивного пользователя в случае IIS Express), как на локальной машине, так и на удаленном сервере. Кнопка Start IDE позволяет запустить программу (по умолчанию это будет командная строка cmd.exe) в предварительно сконфигурированной среде из переменных и путей для выбранного веб приложения. Это также позволит выполнять команды, которые будут применены к нашему приложению, а не глобально к системе. Большинство современных IDE, таких как Aptana или PyCharm, имеют встроенную командную строку, корректно распознают эти переменные и позволяют работать с локальными папками приложения более-менее изолированно и выполнять команды прямо из среды. Так что я рекомендую сконфигурировать запуск вашего любимого IDE по кнопке Start IDE и выполнять все команды оттуда. Еще можно экспортировать переменные окружения в .cmd-файл нажав на Tools -> Export application environment. Этот файл затем можно вызывать перед выполнением других скриптовых команд предназначенных для приложения и он установит требуемые пути и переменные среды. Это удобно если например вам нужно применить команды к приложению по таймеру из Windows Scheduler.

Почему так важно использовать именно эти инструменты? Потому что они позволяют упаковать все зависимости внутрь приложения. Ведь наше приложение будет отправлено для работы на Azure Cloud Services и нам нужно иметь при себе все необходимые зависимости. Разумеется, мы могли бы выполнять Ruby команду 'bundle install' чтобы скачать из интернета и установить все зависимости каждый раз, когда новый узел Cloud Services входит в строй. Однако тогда наше приложение будет зависеть еще и от работы сервиса rubygems.org и других интернет ресурсов, 100% доступность которых под вопросом. К тому же всегда есть вероятность, что мы забудем указать точную версию какого ни будь gem-а из вторичных зависимостей и наше приложение вдруг перестанет работать с выходом новой, несовместимой версии gem-а, хотя мы вроде бы ничего и не меняли. Помножите все эти вероятности, и вы получите не такой уж и привлекательный аптайм. Значит, нам нужно минимизировать число внешних зависимостей, чтобы по возможности при установке из интернета не качалось ничего – тогда все новые виртуальные машины будут точными копиями друг друга.

И тут есть один тонкий момент – привычка. Если например программисты на Java привыкли что все зависимости должны быть упакованы с приложением как само собой разумеющееся, то программисты на Ruby больше привыкли конфигурировать сервер руками и на свое усмотрение. Так что работа с Helicon Zoo потребует некоторой дисциплины, а именно: нельзя запускать консоль или IDE для работы с приложением, даже на вашей рабочей станции, предварительно не сконфигурировав пути к приложению. Сделать это можно либо запустив консоль и IDE из Helicon Zoo Manager, либо выполнив экспортированный из приложения environment.cmd файл перед запуском других команд. Отсюда также следует, что нельзя устанавливать gem-ы и другие модули глобально. Пользуясь этими правилами можно получить легко портируемое приложение, которое удобно переносить с одного сервера на другой.

Так как мы устанавливали Redmine прямо из репозитория Helicon Zoo, то все зависимости были установлены в приложение автоматически. Теперь, чтобы перенести наш Redmine на другой сервер, нам понадобится лишь установить Helicon Zoo -> Ruby Hosting Package на этом сервере и перенести саму папку с сайтом. В пакет Ruby Hosting Package уже входит Ruby разных версий, Dev kit, Helicon Zoo Module и все другие зависимости что могут пригодится на сервере. Вместо установки Ruby Hosting Package можно в принципе установить только требуемые пакеты из репозитория Helicon Zoo отдельно, чтобы сэкономить место. Однако тут повышается вероятность что-то пропустить, да и места дистрибутивы Ruby занимают не так много чтобы экономить.

На сервере мы не будем качать пакеты Ruby и Helicon Zoo из интернета чтобы не зависить от доступности дистрибутивов и серверов. Для этого также существует способ упаковать все один раз, чтобы потом устанавливать из архива. Мы используем Web Platform Installer и утилиту командной строки WebpiCMD.exe. Найти ее можно обычно в папке установки Web Platform Installer: C:\Program Files\Microsoft\Web Platform Installer. Эта утилита может упаковывать продукты из Web Platform Installer для их последующей установки без подключения к интернет.

Для начала запустите консоль с административными правами, кликнув на ней правой кнопкой и выбрав пункт 'Run as administrator':



Это нужно чтобы не открывалось новое окно консоли при запуске WebpiCMD.exe, иначе читать вывод команды будет затруднительно. Сохранять установочные пакеты будем в самой директории сайта с Redmine в папку 'offline-package'. Т.к. я устанавливал Redmine под IIS Express, то мой сайт находится в папке 'C:\Users\Slov\Documents\My Web Sites\redmine222'. В вашем случае имя папки будет другим, так что исправьте это в следующей команде и выполните в консоли:

mkdir "C:\Users\Slov\Documents\My Web Sites\redmine222\offline-package"

WebpiCmd.exe /offline /Products:RubyHostingPackage /Path:"C:\Users\Slov\Documents\My Web Sites\redmine222\offline-package" /Feeds:http://www.helicontech.com/zoo/feed.xml


Как видно из команды мы указываем продукт, который должен быть сохранен для offline-установки. При этом WebpiCmd.exe сохранит все его возможные зависимости, битности и т.п. В команду пеердается путь к папке куда сохранять пакеты и URL репозитория Helicon Zoo, откуда все эти пакеты и берутся. Весь процесс может занять некоторое время. Помните, что многие shell-команды не любят пробелы в пути, так что не забываем кавычки. Эта команда сохранит продукт RubyHostingPackage и все его возможные зависимости в папку 'offline-package' внутри нашего веб сайта. Затем содержимое этой папки можно будет использовать, чтобы установить пакет Ruby Hosting Package на другой машине. На момент написания статьи в Helicon Zoo входит семь хостинг пакетов и имена у них следующие:

CFMLHostingPackage    CFML Hosting Package
JavaHostingPackage    Java Hosting Package
RubyHostingPackage    Ruby Hosting Package
NodejsHostingPackage  Node.js Hosting Package
PerlHostingPackage    Perl Hosting Package
PHPHostingPackage     PHP Hosting Package
PythonHostingPackage  Python Hosting Package

Более подробно про оффлайн установку можно почитать на английском по этой ссылке. Посмотреть внутренние имена всех доступных продуктов можно воспользовавшись ключем /List команды WebpiCmd.exe. Оригинальная английская документация к утилите WebpiCMD.exe находится здесь.

Если вы посмотрите на структуру получившейся папки 'offline-package', то в папке bin увидите что WebpiCMD.exe очень кстати уже включил рабочую копию самого себя в пакет. Именно его мы будем вызывать на виртуальной машине Azure Cloud Services, чтобы установить нужные зависимости обратно из пакета.



Прежде чем упаковать наш сайт для Azure, нужно добавить к нему скрипт, который будет устанавливать все зависимости на виртуальной машине. По правилам Azure этот скрипт должен находиться в директории bin под корнем самого сайта. Назовем этот файл startup.cmd. Вот его содержимое:

[bin\startup.cmd]
echo Starting installation...

rem Дать права на чтение и запись папке куда распаковано приложение
icacls "%RoleRoot%\approot" /grant "Everyone":F /T

rem Локальная папка AppData с правами на запись нужна для работы Web Platform Installer
rem Создадим эту папку и ключ реестра на нее указывающий
md "%RoleRoot%\appdata"
reg add "hku\.default\software\microsoft\windows\currentversion\explorer\user shell folders" ^
    /v "Local AppData" /t REG_EXPAND_SZ /d "%RoleRoot%\appdata" /f

rem Перейдем в папку с WebpiCmd.exe
pushd "%RoleRoot%\approot\offline-package\bin"

rem Вызов команды WebpiCmd.exe для установки продукта из папки offline-package
rem Обратите внимание на имя продукта - RubyHostingPackage, а также логи в install.txt и install-error.txt
WebpiCmd.exe /install /Products:RubyHostingPackage /XML:%RoleRoot%\approot\offline-package\feeds\latest\webproductlist.xml ^
             /Feeds:%RoleRoot%\approot\offline-package\feeds\latest\supplementalfeeds\feed.xml ^
			 /AcceptEula >%RoleRoot%\approot\public\install.txt 2>%RoleRoot%\approot\public\install-error.txt

popd

rem Вернуть старое значение ключу реестра с AppData
reg add "hku\.default\software\microsoft\windows\currentversion\explorer\user shell folders" ^
    /v "Local AppData" /t REG_EXPAND_SZ /d %%USERPROFILE%%\AppData\Local /f


rem Тут можно выполнить другие действия, например удалить временные файлы.

echo Completed installation.

Переменная %RoleRoot% будет указывать куда устанавливается наша роль, а папка %RoleRoot%\approot соответственно будет корневой папкой сайта. Главной строкой в этом файле является вызов WebpiCmd.exe. Обратите внимание на перенаправление вывода логов установки в файл install.txt, а вывод STDERR будет в файле install-error.txt – оба в папку public корня получившегося сайта. Можно будет потом запросить эти файлы по URL чтобы прочитать возможные ошибки установки, если опыт не удастся с первого раза. Первой строкой устанавливаются права на запись в папку с сайтом – эти права нужны самому Redmine для работы, т.к. Ruby приложения часто пишут в папку с приложением.

Теперь настало время упаковать сайт для Azure Cloud Services. Сайт у меня находится в папке «C:\Users\Slov\Documents\My Web Sites\redmine222». Перейдем консолью в папку выше нашего сайта – у меня это будет папка «C:\Users\Slov\Documents\My Web Sites\». Здесь нам понадобится создать три файла: файл конфигурации сервиса *.cscfg, файл с параметрами для создания пакета *.csdef и файл cmd скрипта которым будет удобно все это упаковать. Вот эти файлы с некоторыми комментариями:

[remine222.csdef]
<?xml version="1.0" encoding="utf-8"?>
<ServiceDefinition name="WindowsAzure2" xmlns="http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceDefinition" schemaVersion="2013-03.2.0">
  <WebRole name="redmine222" vmsize="Small">
    <Sites>
      <Site name="Web"  physicalDirectory="./redmine222">
        <Bindings>
          <Binding name="Endpoint1" endpointName="Endpoint1" />
        </Bindings>
      </Site>
    </Sites>
    <Endpoints>
      <InputEndpoint name="Endpoint1" protocol="http" port="80" />
    </Endpoints>
    <Startup>
      <Task commandLine="startup.cmd" executionContext="elevated" taskType="simple" >
      </Task>
    </Startup>
  </WebRole>
</ServiceDefinition>

Имя роли и имя папки, где она находится, почему-то должны совпадать.

[redmine222.cloud.cscfg]
<?xml version="1.0" encoding="utf-8"?>
<ServiceConfiguration serviceName="WindowsAzure2" xmlns="http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceConfiguration" osFamily="2" osVersion="*" schemaVersion="2013-03.2.0">
  <Role name="redmine222">
    <Instances count="1" />
    <ConfigurationSettings>
    </ConfigurationSettings>
  </Role>
</ServiceConfiguration>

Описания и форматы этих файлов можно найти в интернете и в самой документации к Windows Azure, так что опустим подробности.

[redmine222.pack.cmd]
@echo off

set WINDOWS_AZURE_SDK_PATH="C:\Program Files\Microsoft SDKs\Windows Azure\.NET SDK\v2.1"

call %WINDOWS_AZURE_SDK_PATH%\bin\setenv.cmd

pushd %~dp0

if "%ServiceHostingSDKInstallPath%" == "" (
    echo Can't see the ServiceHostingSDKInstallPath environment variable. Please run from a Windows Azure SDK command-line (run Program Files\Windows Azure SDK\^<version^>\bin\setenv.cmd^).
    GOTO :eof
)

rem Тут можно удалить временные файлы, остановить IIS и т.п.
rem iisreset /stop

rem Переименовать deploy_done.rb в deploy.rb чтобы запустить процесс деплоя по новой
ren redmine222\deploy_done.rb deploy.rb

rem Эта команда создает пакет для Windows Azure
cspack redmine222.csdef /out:redmine222.cspkg

popd

Обратите внимание на строчку
ren redmine222\deploy_done.rb deploy.rb

Эта команда переименовывает файл deploy_done.rb в deploy.rb, что приведет к повторному запуску деплой-скрипта в Helicon Zoo при первом запросе к развернувшемуся приложению. Если мы правильно упаковали все модули и нам не нужно мигрировать базу данных, то этот шаг не обязателен и может сэкономить время. Однако вероятность того что с первого раза все будет правильно упаковано не очень высока, поэтому для первых попыток я рекомендую оставить эту строчку.

Еще одной рекомендацией будет отредактировать файл web.config корня сайта и добавить такую строчку в секцию <system.webServer>:
<httpErrors existingResponse="PassThrough" />

Эта строчка включает выдачу подробных сообщений о 500-й ошибке при внешних запросах к IIS. Без этой строчки если что-то сломается в приложении, то текста ошибки вы не увидите, а только сухое сообщение 'Server error'. Для работы в production режиме эту строку лучше убрать, но для первого запуска она может пригодиться.

По этой ссылке вы можете найти примеры описанных выше файлов в соответствии со структурой папок проекта – чтобы было понятнее что куда ложить.

Все, файлы готовы. Теперь перед вызовом redmine222.pack.cmd нужно остановить IIS или IIS Express на рабочей станции, чтобы разблокировать файлы приложения. Затем вызвать redmine222.pack.cmd из нашей консоли с административными правами. Процесс упаковки займет какое-то время и в результате у нас получится файл redmine222.cspkg, который фактически представляет собой ZIP архив со всеми необходимыми пакетами. Размер этого файла у меня получился 138 мегабайт, что немало, т.к. в него включены версии Ruby 1.8, 1.9, две версии Ruby DevKit, Helicon Zoo Module, Microsoft URL Rewrite, сам Redmine и все требуемые для его работы gem-ы. Зато этот архив включает в себя все зависимости и нам не придется ничего качать из интернета, а сам же архив будет передан внутри сети Azure, что, смею надеяться, значительно быстрее.

Теперь перейдем в портал управления Windows Azure. Нужно создать новый Cloud Service и выбрать ему URL:



Затем нужно выбрать «New staging deployment»:



Выбрать наши файлы с Redmine из локальной папки. Нужно указать флаг «Deploy even if role contain a single instance», потому что в файле redmine222.csdef мы указали использовать один экземпляр роли, чего достаточно для тестов, хотя в реальных условиях вам, скорее всего, понадобится увеличить это число.



После чего начнется процесс загрузки пакета в Azure, создания новой виртуальной машины, разворачивания нашего пакета с приложением на этой виртуальной машине и выполнение установочных скриптов. Процесс довольно длительный, у меня он занимает минут 20 – не меньше. Когда все процессы установки будут завершены, нажмите на ссылку Site URL.



Вы должны увидеть страницу Applcation deployment из Helicon Zoo, которая затем обновится на домашнюю страницу Redmine:



Чтобы затем ваш веб сайт стал виден пользователям под более приемлемым доменным именем, вам нужно в настройках вашего домена у регистратора указать либо CNAME запись на доменное имя внутри .cloudapp.net (предпочтительно) или указать 'A'-record вашего домена на публичный IP адрес вашего Azure-приложения. Сам же Microsoft не занимается предоставлением услуг по регистрации доменов.

Python



В этой главе мы рассмотрим, как установить вручную приложение, которое не входит в репозиторий Helicon Zoo. Для этого мы будем использовать приложение Lightning Fast Shop (LFS) с открытым исходным кодом, написанное на Python с использование Django. Шаги по публикации приложения в Azure Cloud Service будут практически идентичны с прошлой главой, а вот шаги по развертыванию приложения на рабочей станции будут другими.

Итак, ставим Microsoft Web Platform Installer, Helicon Zoo feed и Windows Azure SDK, как в прошлой главе, если еще что-то из этого не установлено. Запускаем Web Platform Installer и устанавливаем Zoo -> Templates -> Python project на IIS Express.



Запустится WebMatrix и откроется новый сайт:



Мы только что установили шаблонный проект для Python. В этом проекте уже сконфигурирован virtualenv, который и будет использован для установки всех модулей и зависимостей внутрь сайта. Для запуска своего проекта на Python можно идти дальше по инструкции на пригласительной странице Python project. Только не забывайте запускать консоль или IDE (например PyCharm ) используя Helicon Zoo Manager, чтобы консоль запускалась с предварительно сконфигурированным virtualenv, иначе команды не найдут путей к нашему приложению.

Lightning Fast Shop достаточно большая и капризная в установке программа, поэтому я прошу вас шаг за шагом повторить следующую инструкцию по его ручной установке на IIS и Helicon Zoo. Я не буду давать слишком подробных объяснений, что происходит, потому что происходящее имеет отношение к особенностям проекта LFS, а не к Helicon Zoo или Azure. Настройка другого проекта может идти по другому сценарию. В случае неудачи попробуйте начать с более мелких и простых проектов, следуя инструкциям из Python project. Проект LFS я выбрал просто для того чтобы показать что не только «Hello World» можно запускать на Azure Cloud Services.
  1. Скачайте диструбутив LFS с официального сайта. Я выбрал версию 0.7.7. Нужно скачать обязательно installer-версию, у которой имя файла вроде django-lfs-installer-0.7.7.tar.gz.
    В архиве будет папка 'lfs-installer' – распакуйте её содержимое в корень сайта с нашим Python project (в моем случае это папка C:\Users\Slov\Documents\My Web Sites\ZooPythonProject2).
    Запустите Helicon Zoo Manager, выберете нужный сайт с проектом и нажмите на Start IDE, чтобы запустить сконфигурированную консоль.
    В консоли введите:
    python bootstrap.py
    Затем
    bin\buildout –v
    Затем отредактируйте файл lfs_project\settings.py и замените секцию DATABASES следующим текстом, для использования в проекте SQLite:
    DATABASES = {
        'default': {
            'ENGINE': 'django.db.backends.sqlite3', # Add 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'.
            'NAME': os.path.join(DIRNAME, 'sqlite3.bd'),                      # Or path to database file if using sqlite3.
            'USER': '',                      # Not used with sqlite3.
            'PASSWORD': '',                  # Not used with sqlite3.
            'HOST': '',                      # Set to empty string for localhost. Not used with sqlite3.
            'PORT': '',                      # Set to empty string for default. Not used with sqlite3.
        }
    }
    Затем введите в консоли последовательно такие команды:
    bin\django syncdb
    bin\django lfs_init
    bin\django collectstatic
    Если все выполнилось без ошибок, то теперь можно запустить тестовый сервер Django, чтобы проверить работу проекта LFS отдельно от веб сервера IIS. Выполните в консоли:
    bin/django runserver
    И затем откройте в браузере http://localhost:8080/

    Теперь, чтобы запустить проект на IIS через Helicon Zoo, нужно задать PYTHONPATH в файле web.config. У LFS он длинный и включает в себя множество egg-пакетов. Найти его можно в файле bin\django_script.py:
    #!"C:\Users\Slov\Documents\My Web Sites\ZooPythonProject2\venv\Scripts\python.exe"
    
    import sys
    sys.path[0:0] = [
      'c:\\users\\slov\\docume~1\\mywebs~1\\zoopyt~1\\eggs\\django_lfs-0.7.6-py2.7.egg',
      'c:\\users\\slov\\docume~1\\mywebs~1\\zoopyt~1\\eggs\\gunicorn-18.0-py2.7.egg',
      'c:\\users\\slov\\docume~1\\mywebs~1\\zoopyt~1\\eggs\\djangorecipe-1.1.2-py2.7.egg',
      'c:\\users\\slov\\docume~1\\mywebs~1\\zoopyt~1\\eggs\\django-1.3.1-py2.7.egg',
      'c:\\users\\slov\\docume~1\\mywebs~1\\zoopyt~1\\eggs\\zc.recipe.egg-2.0.1-py2.7.egg',
      'c:\\users\\slov\\docume~1\\mywebs~1\\zoopyt~1\\eggs\\zc.buildout-2.2.1-py2.7.egg',
      'c:\\users\\slov\\docume~1\\mywebs~1\\zoopyt~1\\eggs\\south-0.7.3-py2.7.egg',
      'c:\\users\\slov\\docume~1\\mywebs~1\\zoopyt~1\\eggs\\pillow-1.7.5-py2.7-win32.egg',
      'c:\\users\\slov\\docume~1\\mywebs~1\\zoopyt~1\\eggs\\lfs_order_numbers-1.0b1-py2.7.egg',
      'c:\\users\\slov\\docume~1\\mywebs~1\\zoopyt~1\\eggs\\lfs_contact-1.0-py2.7.egg',
      'c:\\users\\slov\\docume~1\\mywebs~1\\zoopyt~1\\eggs\\django_tagging-0.3.1-py2.7.egg',
      'c:\\users\\slov\\docume~1\\mywebs~1\\zoopyt~1\\eggs\\django_reviews-0.2.1-py2.7.egg',
      'c:\\users\\slov\\docume~1\\mywebs~1\\zoopyt~1\\eggs\\django_postal-0.9-py2.7.egg',
      'c:\\users\\slov\\docume~1\\mywebs~1\\zoopyt~1\\eggs\\django_portlets-1.1.1-py2.7.egg',
      'c:\\users\\slov\\docume~1\\mywebs~1\\zoopyt~1\\eggs\\django_paypal-0.1.2-py2.7.egg',
      'c:\\users\\slov\\docume~1\\mywebs~1\\zoopyt~1\\eggs\\django_pagination-1.0.7-py2.7.egg',
      'c:\\users\\slov\\docume~1\\mywebs~1\\zoopyt~1\\eggs\\django_lfstheme-0.7.3-py2.7.egg',
      'c:\\users\\slov\\docume~1\\mywebs~1\\zoopyt~1\\eggs\\django_compressor-1.1.1-py2.7.egg',
      'c:\\users\\slov\\documents\\my web sites\\zoopythonproject2\\venv\\lib\\site-packages',
      'c:\\users\\slov\\docume~1\\mywebs~1\\zoopyt~1\\eggs\\django_piston-0.2.3-py2.7.egg',
      'c:\\users\\slov\\docume~1\\mywebs~1\\zoopyt~1\\eggs\\django_countries-1.5-py2.7.egg',
      'c:\\users\\slov\\docume~1\\mywebs~1\\zoopyt~1\\eggs\\django_appconf-0.6-py2.7.egg',
      'c:\\users\\slov\\docume~1\\mywebs~1\\zoopyt~1\\eggs\\six-1.4.1-py2.7.egg',
      'c:\\users\\slov\\docume~1\\mywebs~1\\zoopyt~1\\parts\\django',
      'c:\\users\\slov\\docume~1\\mywebs~1\\zoopyt~1',
      'c:\\users\\slov\\docume~1\\mywebs~1\\zoopyt~1\\parts',
      'c:\\users\\slov\\docume~1\\mywebs~1\\zoopyt~1\\lfs_project',
      ]
    
    import djangorecipe.manage
    
    if __name__ == '__main__':
        sys.exit(djangorecipe.manage.main('lfs_project.settings'))

    Как видно там абсолютные пути, что нам не подходит, ведь проект будет переносится в Azure. Для задания PYTHONPATH через web.config эти пути нужно переделать в такой, немного странный формат. Вот фрагмент моего web.config:
    <?xml version="1.0" encoding="UTF-8"?> 
    <configuration> 
     <system.webServer>
      <heliconZoo>
       <application name="python.project">
        <environmentVariables>
            <add name="VIRTUAL_ENV" value="%APPL_PHYSICAL_PATH%\venv" />
            <add name="PATH" value="%APPL_PHYSICAL_PATH%\venv\Scripts;%PATH%" />
            <add name="PYTHONPATH" value=".\eggs\django_lfs-0.7.6-py2.7.egg
            ;.\eggs\gunicorn-18.0-py2.7.egg
            ;.\eggs\djangorecipe-1.1.2-py2.7.egg
            ;.\eggs\django-1.3.1-py2.7.egg
            ;.\eggs\zc.recipe.egg-2.0.1-py2.7.egg
            ;.\eggs\zc.buildout-2.2.1-py2.7.egg
            ;.\eggs\south-0.7.3-py2.7.egg
            ;.\eggs\pillow-1.7.5-py2.7-win32.egg
            ;.\eggs\lfs_order_numbers-1.0b1-py2.7.egg
            ;.\eggs\lfs_contact-1.0-py2.7.egg
            ;.\eggs\django_tagging-0.3.1-py2.7.egg
            ;.\eggs\django_reviews-0.2.1-py2.7.egg
            ;.\eggs\django_postal-0.9-py2.7.egg
            ;.\eggs\django_portlets-1.1.1-py2.7.egg
            ;.\eggs\django_paypal-0.1.2-py2.7.egg
            ;.\eggs\django_pagination-1.0.7-py2.7.egg
            ;.\eggs\django_lfstheme-0.7.3-py2.7.egg
            ;.\eggs\django_compressor-1.1.1-py2.7.egg
            ;.\venv\lib\site-packages
            ;.\eggs\django_piston-0.2.3-py2.7.egg
            ;.\eggs\django_countries-1.5-py2.7.egg
            ;.\eggs\django_appconf-0.6-py2.7.egg
            ;.\eggs\six-1.4.1-py2.7.egg
            ;.\parts\django
            ;%APPL_PHYSICAL_PATH%
            ;.\parts
            ;.\lfs_project" />
            <add name="WSGI_APP" value="welcome.application" />
            <add name="CONSOLE_URL" value="console" />
            <add name="DEPLOY_FILE" value="deploy.py" />
            <add name="ERROR_LOG_DIR" value="log" />
            <add name="IDE" value="C:\Windows\system32\cmd.exe" />

    Можете скопировать к себе в web.config, однако если вы настраиваете версию отличную от 0.7.7, то ваш PYTHONPATH может отличаться.

    Также установим переменную DJANGO_SETTINGS_MODULE в web.config:
    <!-- django project -->
    <add name="DJANGO_SETTINGS_MODULE" value="lfs_project.settings" />

    Теперь содержимое папки '\lfs_project\sitestatic' нужно перенести в папку '\static' в корне сайта.

    Все, проект готов к запуску на IIS. Нажмите на ссылку в WebMatrix и вы должны увидеть домашнюю страницу LFS.

    Структура папок в результате вышла следующая:



    Дальше подготовим пакет для Azure Cloud Services. Запустите Helicon Zoo Manager, выберете нужный сайт и нажмите Start IDE для запуска консоли. Web console тут не подойдет, т.к. у нее будет недостаточно прав. Выполните там следующие команды:

    mkdir offline-package
    
    WebpiCmd.exe /offline /Products:PythonHostingPackage /Path:"offline-package" /Feeds:http://www.helicontech.com/zoo/feed.xml

    Это сохранит Python Hosting Package в директории offline-package внутри сайта.

    Затем создайте три файла для Azure Cloud Services в папке 'My Documents\My Web Sites', как в предыдущей главе. Я выделил жирным те строчки, которые в этих файлах отличаются от предыдущих:

    [LFS.Cloud.cscfg]
    <?xml version="1.0" encoding="utf-8"?>
    <ServiceConfiguration serviceName="WindowsAzure2" xmlns="http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceConfiguration" osFamily="2" osVersion="*" schemaVersion="2013-03.2.0">
      <Role name="ZooPythonProject2">
        <Instances count="1" />
        <ConfigurationSettings>
        </ConfigurationSettings>
      </Role>
    </ServiceConfiguration>


    [LFS.csdef]
    <?xml version="1.0" encoding="utf-8"?>
    <ServiceDefinition name="WindowsAzure2" xmlns="http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceDefinition" schemaVersion="2013-03.2.0">
      <WebRole name="ZooPythonProject2" vmsize="Small">
        <Sites>
          <Site name="Web"  physicalDirectory="./ZooPythonProject2">
            <Bindings>
              <Binding name="Endpoint1" endpointName="Endpoint1" />
            </Bindings>
          </Site>
        </Sites>
        <Endpoints>
          <InputEndpoint name="Endpoint1" protocol="http" port="80" />
        </Endpoints>
        <Startup>
          <Task commandLine="startup.cmd" executionContext="elevated" taskType="simple" >
          </Task>
        </Startup>
      </WebRole>
    </ServiceDefinition>


    [LFS.pack.cmd]
    @echo off
    
    set WINDOWS_AZURE_SDK_PATH="C:\Program Files\Microsoft SDKs\Windows Azure\.NET SDK\v2.1"
    
    call %WINDOWS_AZURE_SDK_PATH%\bin\setenv.cmd
    
    pushd %~dp0
    
    if "%ServiceHostingSDKInstallPath%" == "" (
        echo Can't see the ServiceHostingSDKInstallPath environment variable. Please run from a Windows Azure SDK command-line (run Program Files\Windows Azure SDK\^<version^>\bin\setenv.cmd^).
        GOTO :eof
    )
    
    rem Тут можно удалить временные файлы, остановить IIS и т.п.
    rem iisreset /stop
    <b>del /s /q *.log *.pyc *.pyo</b>
    
    
    rem Эта команда создает пакет для Windows Azure
    cspack lfs.csdef /out:lfs.cspkg
    
    popd

    И осталось создать файл \bin\startup.cmd в корне сайта:
    echo Starting installation...
    
    rem Дать права на чтение и запись папке куда распаковано приложение
    icacls "%RoleRoot%\approot" /grant "Everyone":F /T
    
    rem Локальная папка AppData с правами на запись нужна для работы Web Platform Installer
    rem Создадим эту папку и ключ реестра на нее указывающий
    md "%RoleRoot%\appdata"
    reg add "hku\.default\software\microsoft\windows\currentversion\explorer\user shell folders" ^
        /v "Local AppData" /t REG_EXPAND_SZ /d "%RoleRoot%\appdata" /f
    
    rem Перейдем в папку с WebpiCmd.exe
    pushd "%RoleRoot%\approot\offline-package\bin"
    
    rem Вызов команды WebpiCmd.exe для установки продукта из папки offline-package
    rem Обратите внимание на имя продукта - <b>PythonHostingPackage</b>, а также логи в install.txt и install-error.txt
    WebpiCmd.exe /install /Products:PythonHostingPackage /XML:%RoleRoot%\approot\offline-package\feeds\latest\webproductlist.xml ^
                 /Feeds:%RoleRoot%\approot\offline-package\feeds\latest\supplementalfeeds\feed.xml /AcceptEula  ^
                 >%RoleRoot%\approot\static\install.txt 2>%RoleRoot%\approot\static\install-error.txt
    
    popd
    
    rem Вернуть старое значение ключу реестра с AppData
    reg add "hku\.default\software\microsoft\windows\currentversion\explorer\user shell folders" ^
        /v "Local AppData" /t REG_EXPAND_SZ /d %%USERPROFILE%%\AppData\Local /f
    
    
    rem Тут можно выполнить другие действия, например удалить временные файлы.
    
    echo Completed installation.
    

    В этом архиве вы найдете пример описанных выше файлов.

    Выполните LFS.pack.cmd. Получившийся файл LFS.cspkg у меня занимает 70мб.

    Удалим старый Staging Environment из Azure Portal и создадим новый. Передадим файлы как в предыдущей главе и ожидаем запуска.



    Когда строчка «Not all instances are ready» пропадет, можно открывать ссылку, где мы должны увидеть работающий Lightning Fast Shop в Azure Cloud Services.



    Node.js


    Теперь на очереди Node.js. Итак, запускаем Microsoft Web Platform Installer и устанавливаем Zoo -> Templates -> Node.js project. Все зависимости будут установлены автоматически.



    После запуска проект развернется во вполне готовое Model-View-Route приложение, построенное на базе express.js, sqlite3, persist.js и Twitter Bootstrap. В этом шаблоне для примера уже будет простенький блог и административная панель к нему. Такое приложение может быть хорошей отправной точкой для создания собственного сайта. Если же у вас уже есть готовый Node.js веб сайт, то вы, очевидно, знаете назначение всех прописанных в шаблонном проекте файлов. Просто перезапишите свои файлы поверх, оставляя web.config нетронутым, и ваше приложение должно заработать.



    Этот простенький блог мы и будем устанавливать на Azure Cloud Services. Как и в предыдущих главах – запустим Helicon Zoo Manager и нажмем Start IDE или Start web console. В консоли наберем:

    mkdir offline-package
    
    WebpiCmd.exe /offline /Products:NodejsHostingPackage /Path:"offline-package" /Feeds:http://www.helicontech.com/zoo/feed.xml

    Дальше создадим файл bin\startup.cmd:

    [bin\startup.cmd]
    echo Starting installation...
    
    rem Дать права на чтение и запись папке куда распаковано приложение
    icacls "%RoleRoot%\approot" /grant "Everyone":F /T
    
    rem Локальная папка AppData с правами на запись нужна для работы Web Platform Installer
    rem Создадим эту папку и ключ реестра на нее указывающий
    md "%RoleRoot%\appdata"
    reg add "hku\.default\software\microsoft\windows\currentversion\explorer\user shell folders" ^
        /v "Local AppData" /t REG_EXPAND_SZ /d "%RoleRoot%\appdata" /f
    
    rem Перейдем в папку с WebpiCmd.exe
    pushd "%RoleRoot%\approot\offline-package\bin"
    
    rem Вызов команды WebpiCmd.exe для установки продукта из папки offline-package
    rem Обратите внимание на имя продукта – NodejsHostingPackage, а также логи в install.txt и install-error.txt
    WebpiCmd.exe /install /Products:NodejsHostingPackage /XML:%RoleRoot%\approot\offline-package\feeds\latest\webproductlist.xml ^
                 /Feeds:%RoleRoot%\approot\offline-package\feeds\latest\supplementalfeeds\feed.xml ^
                 /AcceptEula  >%RoleRoot%\approot\public\install.txt 2>%RoleRoot%\approot\public\install-error.txt
    
    popd
    
    rem Вернуть старое значение ключу реестра с AppData
    reg add "hku\.default\software\microsoft\windows\currentversion\explorer\user shell folders" ^
        /v "Local AppData" /t REG_EXPAND_SZ /d %%USERPROFILE%%\AppData\Local /f
    
    
    rem Тут можно выполнить другие действия, например удалить временные файлы.
    
    echo Completed installation.

    И затем три файла в директории «My Web Sites»:

    [Node.js.Cloud.cscfg]
    <?xml version="1.0" encoding="utf-8"?>
    <ServiceConfiguration serviceName="WindowsAzure2" xmlns="http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceConfiguration" osFamily="2" osVersion="*" schemaVersion="2013-03.2.0">
      <Role name="Node.js project">
        <Instances count="1" />
        <ConfigurationSettings>
        </ConfigurationSettings>
      </Role>
    </ServiceConfiguration>


    [Node.js.csdef]
    <?xml version="1.0" encoding="utf-8"?>
    <ServiceDefinition name="WindowsAzure2" xmlns="http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceDefinition" schemaVersion="2013-03.2.0">
      <WebRole name="Node.js project" vmsize="Small">
        <Sites>
          <Site name="Web"  physicalDirectory="./Node.js project">
            <Bindings>
              <Binding name="Endpoint1" endpointName="Endpoint1" />
            </Bindings>
          </Site>
        </Sites>
        <Endpoints>
          <InputEndpoint name="Endpoint1" protocol="http" port="80" />
        </Endpoints>
        <Startup>
          <Task commandLine="startup.cmd" executionContext="elevated" taskType="simple" >
          </Task>
        </Startup>
      </WebRole>
    </ServiceDefinition>


    [Node.js.pack.cmd]
    @echo off
    
    set WINDOWS_AZURE_SDK_PATH="C:\Program Files\Microsoft SDKs\Windows Azure\.NET SDK\v2.1"
    
    call %WINDOWS_AZURE_SDK_PATH%\bin\setenv.cmd
    
    pushd %~dp0
    
    if "%ServiceHostingSDKInstallPath%" == "" (
        echo Can't see the ServiceHostingSDKInstallPath environment variable. Please run from a Windows Azure SDK command-line (run Program Files\Windows Azure SDK\^<version^>\bin\setenv.cmd^).
        GOTO :eof
    )
    
    rem Тут можно удалить временные файлы, остановить IIS и т.п.
    rem iisreset /stop
    
    rem Эта команда создает пакет для Windows Azure
    cspack Node.js.csdef /out:Node.js.cspkg
    
    popd

    Как и раньше различия выделены жирным.

    Выполним Node.js.pack.cmd, в результате получим файл Node.js.cspkg размером примерно 41мб. Вот ссылка на архив с примерами файлов выше: https://dl.dropboxusercontent.com/u/7840290/habrahabr/Node.js.zip

    Теперь опубликуем пакеты в Azure Cloud Services как и в предыдущих главах. Весь процесс занимает минут 5-10, что значительно быстрее, чем, например, в случае с Ruby.

    Perl


    На этот раз все же будем ставить «Hello World» проект на Mojolitious. К сожалению ничего более зрелищного для Perl у меня под рукой не нашлось. Запустим Microsoft Web Platform Installer и установим Zoo -> Templates -> Perl project.



    После установки откроется страница «Welcome to universal Perl template powered by Helicon Zoo», нажмите на этой странице на ссылку «open web console» и наберите там следующую команду:
    cpanm Mojolicious

    Теперь создайте файл app.pl такого содержания:

    [app.pl]
    use Mojolicious::Lite;
    get '/' => sub { shift->render(text => 'Hello from Mojolicious!') };
    app->start;

    Нажав «обновить» в браузере увидим сообщение «Hello from Mojolicious!». Не ахти как красиво, но концепцию доказывает.

    Теперь, как и в предыдущих главах выполняем из консоли:

    mkdir offline-package
    
    WebpiCmd.exe /offline /Products:PerlHostingPackage /Path:"offline-package" /Feeds:http://www.helicontech.com/zoo/feed.xml

    Добавим скрипт bin\startup.cmd:

    [bin\startup.cmd]
    echo Starting installation...
    
    rem Дать права на чтение и запись папке куда распаковано приложение
    icacls "%RoleRoot%\approot" /grant "Everyone":F /T
    
    rem Локальная папка AppData с правами на запись нужна для работы Web Platform Installer
    rem Создадим эту папку и ключ реестра на нее указывающий
    md "%RoleRoot%\appdata"
    reg add "hku\.default\software\microsoft\windows\currentversion\explorer\user shell folders" ^
        /v "Local AppData" /t REG_EXPAND_SZ /d "%RoleRoot%\appdata" /f
    
    rem Перейдем в папку с WebpiCmd.exe
    pushd "%RoleRoot%\approot\offline-package\bin"
    
    rem Вызов команды WebpiCmd.exe для установки продукта из папки offline-package
    rem Обратите внимание на имя продукта – PerlHostingPackage, а также логи в install.txt и install-error.txt
    WebpiCmd.exe /install /Products:PerlHostingPackage /XML:%RoleRoot%\approot\offline-package\feeds\latest\webproductlist.xml ^
                 /Feeds:%RoleRoot%\approot\offline-package\feeds\latest\supplementalfeeds\feed.xml ^
                 /AcceptEula  >%RoleRoot%\approot\public\install.txt 2>%RoleRoot%\approot\public\install-error.txt
    
    popd
    
    rem Вернуть старое значение ключу реестра с AppData
    reg add "hku\.default\software\microsoft\windows\currentversion\explorer\user shell folders" ^
        /v "Local AppData" /t REG_EXPAND_SZ /d %%USERPROFILE%%\AppData\Local /f
    
    
    rem Тут можно выполнить другие действия, например удалить временные файлы.
    
    echo Completed installation.

    И создадим файлы в папке «My Web Sites» (предполагается что сайт находится в папке «My Web Sites\Perl project»):

    [Perl.Cloud.cscfg]
    <?xml version="1.0" encoding="utf-8"?>
    <ServiceConfiguration serviceName="WindowsAzure2" xmlns="http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceConfiguration" osFamily="2" osVersion="*" schemaVersion="2013-03.2.0">
      <Role name="Perl project">
        <Instances count="1" />
        <ConfigurationSettings>
        </ConfigurationSettings>
      </Role>
    </ServiceConfiguration>


    [Perl.csdef]
    <?xml version="1.0" encoding="utf-8"?>
    <ServiceDefinition name="WindowsAzure2" xmlns="http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceDefinition" schemaVersion="2013-03.2.0">
      <WebRole name="Perl project" vmsize="Small">
        <Sites>
          <Site name="Web"  physicalDirectory="./Perl project">
            <Bindings>
              <Binding name="Endpoint1" endpointName="Endpoint1" />
            </Bindings>
          </Site>
        </Sites>
        <Endpoints>
          <InputEndpoint name="Endpoint1" protocol="http" port="80" />
        </Endpoints>
        <Startup>
          <Task commandLine="startup.cmd" executionContext="elevated" taskType="simple" >
          </Task>
        </Startup>
      </WebRole>
    </ServiceDefinition>


    [Perl.pack.cmd]
    @echo off
    
    set WINDOWS_AZURE_SDK_PATH="C:\Program Files\Microsoft SDKs\Windows Azure\.NET SDK\v2.1"
    
    call %WINDOWS_AZURE_SDK_PATH%\bin\setenv.cmd
    
    pushd %~dp0
    
    if "%ServiceHostingSDKInstallPath%" == "" (
        echo Can't see the ServiceHostingSDKInstallPath environment variable. Please run from a Windows Azure SDK command-line (run Program Files\Windows Azure SDK\^<version^>\bin\setenv.cmd^).
        GOTO :eof
    )
    
    rem Тут можно удалить временные файлы, остановить IIS и т.п.
    rem iisreset /stop
    
    rem Эта команда создает пакет для Windows Azure
    cspack Perl.csdef /out:Perl.cspkg
    
    popd

    Ссылка на архив с примерами файлов: https://dl.dropboxusercontent.com/u/7840290/habrahabr/Perl.zip

    Запустим Perl.pack.cmd. Получится файл Perl.cspkg размером 92мб. Выложим файлы на Azure Cloud Services и убедимся что программа на Mojolicious работает корректно, открыв ссылку по завершении всей установки.



    Java и ColdFusion (Railo)



    На последок остались Java и ColdFusion. В качестве альтернативы ColdFusion в Helicon Zoo на данный момент используется бесплатный Railo с открытым исходным кодом. Сразу же оговорюсь – установить Java или Railo на Azure Cloud Services мне не удалось, и причина тому весьма тривиальна – ограничение на размер пакетов Azure. По крайней мере в моем аккаунте нельзя выкладывать пакеты более 200 мб размером. При этом для работы Railo и большинства других серверных технологий на Java требуется Oracle JDK, размер дистрибутива которого 125 мб, что вместе с другими компонентами легко переваливает за 200. Однако я все же опишу, как должны были бы запускаться Java программы, если бы не это ограничение. Возможно, ограничение будет снято в будущем и глава станет актуальна. Тем более что в целом запуск Java программ достаточно прост и удобен. Java разработчикам не нужно приучаться упаковывать компоненты внутрь программ – для них это стандартное поведение. Сайты, программы и сервисы на Java, как правило, имеют минимум внешних зависимостей и не нуждаются в сложной настройке среды.

    Главной внешней зависимостью для Java-программ является Oracle JDK, и, к сожалению, его нельзя установить из репозитория Helicon Zoo. Oracle запрещает встраивание своего JDK в другие продукты и репозитории и любые поставки их дистрибутивов в обход самого сайта Oracle. Поэтому вам нужно скачать JDK-7 самостоятельно, воспользовавшись этой ссылкой: http://www.oracle.com/technetwork/java/javase/downloads/jdk7-downloads-1880260.html Для Azure Cloud Services вам понадобится версия Windows-64 bit. На вашу рабочую станцию ставьте версию в соответствии с битностью машины. После того как JDK-7 установлен, можно устанавливать Java-программы из репозитория Helicon Zoo. Для примера вы можете установить Zoo -> Applications -> SCM Manager – небольшой менеджер и сервис репозиториев Git, Mercurial и SVN написанный на Java. Или поставить Zoo -> Applications -> Mura CMS – красивая CMS написанная на ColdFusion. Обе программы устанавливаются прямо из репозитория без дополнительных действий.



    В моем случае я установил Mura CMS в папку «My Web Sites\Mura CMS1». Дальше как и раньше – создаем папку offline-package куда пакуем Java Hosting Package или CFML Hosting Package из репозитория Helicon Zoo, в зависимости от того какая технология используется:
    mkdir offline-package
    
    WebpiCmd.exe /offline /Products:CFMLHostingPackage /Path:"offline-package" /Feeds:http://www.helicontech.com/zoo/feed.xml


    Добавим в директорию offline-package\bin еще и скачанный ранее дистрибутив с JDK-7. 
    Скрипт bin\startup.cmd будет отличатся дополнительным вызовом установщика JDK-7:

    [bin\startup.cmd]
    echo Starting installation...
    
    rem Дать права на чтение и запись папке куда распаковано приложение
    icacls "%RoleRoot%\approot" /grant "Everyone":F /T
    
    rem Локальная папка AppData с правами на запись нужна для работы Web Platform Installer
    rem Создадим эту папку и ключ реестра на нее указывающий
    md "%RoleRoot%\appdata"
    reg add "hku\.default\software\microsoft\windows\currentversion\explorer\user shell folders" ^
        /v "Local AppData" /t REG_EXPAND_SZ /d "%RoleRoot%\appdata" /f
    
    rem Перейдем в папку с WebpiCmd.exe
    pushd "%RoleRoot%\approot\offline-package\bin"
    
    rem Устанавливаем JDK-7
    jdk-7u45-windows-x64.exe /s
    
    rem Вызов команды WebpiCmd.exe для установки продукта из папки offline-package
    rem Обратите внимание на имя продукта – PerlHostingPackage, а также логи в install.txt и install-error.txt
    WebpiCmd.exe /install /Products:CFMLHostingPackage /XML:%RoleRoot%\approot\offline-package\feeds\latest\webproductlist.xml ^
                 /Feeds:%RoleRoot%\approot\offline-package\feeds\latest\supplementalfeeds\feed.xml ^
                 /AcceptEula  >%RoleRoot%\approot\install.txt 2>%RoleRoot%\approot\install-error.txt
    
    popd
    
    rem Вернуть старое значение ключу реестра с AppData
    reg add "hku\.default\software\microsoft\windows\currentversion\explorer\user shell folders" ^
        /v "Local AppData" /t REG_EXPAND_SZ /d %%USERPROFILE%%\AppData\Local /f
    
    
    rem Тут можно выполнить другие действия, например удалить временные файлы.
    
    echo Completed installation.

    Создадим файлы пакета:

    [Mura.Cloud.cscfg]
    <?xml version="1.0" encoding="utf-8"?>
    <ServiceConfiguration serviceName="WindowsAzure2" xmlns="http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceConfiguration" osFamily="2" osVersion="*" schemaVersion="2013-03.2.0">
      <Role name="Mura CMS1">
        <Instances count="1" />
        <ConfigurationSettings>
        </ConfigurationSettings>
      </Role>
    </ServiceConfiguration>


    [Mura.csdef]
    <?xml version="1.0" encoding="utf-8"?>
    <ServiceDefinition name="WindowsAzure2" xmlns="http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceDefinition" schemaVersion="2013-03.2.0">
      <WebRole name="Mura CMS1" vmsize="Small">
        <Sites>
          <Site name="Web"  physicalDirectory="./Mura CMS1">
            <Bindings>
              <Binding name="Endpoint1" endpointName="Endpoint1" />
            </Bindings>
          </Site>
        </Sites>
        <Endpoints>
          <InputEndpoint name="Endpoint1" protocol="http" port="80" />
        </Endpoints>
        <Startup>
          <Task commandLine="startup.cmd" executionContext="elevated" taskType="simple" >
          </Task>
        </Startup>
      </WebRole>
    </ServiceDefinition>


    [Mura.pack.cmd]
    @echo off
    
    set WINDOWS_AZURE_SDK_PATH="C:\Program Files\Microsoft SDKs\Windows Azure\.NET SDK\v2.1"
    
    call %WINDOWS_AZURE_SDK_PATH%\bin\setenv.cmd
    
    pushd %~dp0
    
    if "%ServiceHostingSDKInstallPath%" == "" (
        echo Can't see the ServiceHostingSDKInstallPath environment variable. Please run from a Windows Azure SDK command-line (run Program Files\Windows Azure SDK\^<version^>\bin\setenv.cmd^).
        GOTO :eof
    )
    
    rem Тут можно удалить временные файлы, остановить IIS и т.п.
    rem iisreset /stop
    
    rem Эта команда создает пакет для Windows Azure
    cspack Mura.csdef /out:Mura.cspkg
    
    popd

    И запустим Mura.pack.cmd. Получится файл Mura.cspkg размером 275 мб. Что можно сказать: Java требует много ресурсов. Хотя и 300 мб для передачи по локальной сети по современным меркам не так уж и много.

    Ну и теперь, если бы Azure Cloud Services принимал пакеты такого размера, нам нужно было бы просто загрузить ему эти файлы. Пока же наш эксперимент чисто теоретический.

    Заключение



    Несмотря на кажущуюся сложность показанного решения, не все так страшно. За одну статью мы управились сразу с большинством популярных технологий веб разработки. Разумеется, остались еще PHP и ASP.NET, которые и так неплохо описаны в инструкциях к Windows Azure. В репозитории Helicon Zoo есть еще PHP Hosting Package, которым удобно воспользоваться вместо стандартного решения от Microsoft в том случае если вы собираетесь смешивать несколько версий PHP или другие веб технологии в рамках одного сайта, так как в Zoo неплохо реализована изоляция технологий.

    Главное достоинство представленного решения, помимо относительной простоты и хорошей производительности – это достаточно легкая миграция приложений между серверами и сервисами. Пользуясь таким решением, вы оставляете для себя теоретическую возможность в будущем «спрыгнуть» с сервисов Azure, если условия не будут вас удовлетворять. Все приложения, приведенные в данной статье, могут быть аналогично запущены практически на любом сервере Windows и Linux. Разумеется, инфраструктура Azure предоставляет еще массу других, полезных, сервисов, таких как Media Services, Mobile Services, SQL Databases или очереди сообщений. Если ваше приложение будет активно использовать эти сервисы, то привязка к платформе будет более жесткой.
Tags:
Hubs:
+12
Comments 4
Comments Comments 4

Articles