Best approach to hosting on Azure web service using Azure SQL as the data backend

In attempt to determine the feasibility hosting a Cuba-Platofrm app on Azure and taking advantage of Azure PAAS scalability, I am looking for some guidance on the following:

Can a Cuba-Platform app run under an Azure Web App Service using Azure SQL as the back-end database and if so, what’s the best way to deploy under this scenario.
I created an App Service provisioned with the following:

Java Version: 8
Java Minor version: always use newest
Web container: Newest Tomcat 8.5
Platform 32bit
I have the ability to deploy via simple FTP.

Assuming this can work, are the settings above adequate?
What’s the best way to deploy – FTP with a single WAR file, multiple files, etc…?
Has anyone actually used Azure SQL as the back end database? If so, what considerations should be made for deployment?
My intent is to determine if this can work and attempt to test the deployment process using a basic sample Cuba-Platform app with SQL Azure as the DB. If successful, I would be happy to publish any details required to perform this process.

Thanks

Benjamin

1 Like

Hi Benjamin,

We haven’t tested deployment to Azure Web App Service, but from the information provided by you I assume it should work.

  • Open Deployment settings > WAR in Studio, select Include JDBC driver*, Include Tomcat’s context.xml, generate a custom context.xml, and select *Single WAR with generated custom web.xml. Keep cuba.automaticDatabaseUpdate = true in App properties.

  • Run buildWar Gradle task. Find your WAR file in the build\distributions\war folder.

  • Create an empty database on Azure SQL. I assume it can be accessed by the production Tomcat with the parameters specified in the custom context.xml on the first step.

  • Copy you WAR to the cloud Tomcat, it should deploy and run the app. The database schema will be created from init scripts on first run.

Please share your experience. BTW, we are going to publish a manual on deployment to IBM Bluemix in the near future.

Thanks for the advice.

I was able to generate a single WAR file with your instructions.
I was also able (prior to creating the WAR file) create an Azure WebApp Service with an Azure SQL DB and using the Azure DB connection settings, update my local CUBA Framework project to use the hosted Azure SQL Service.

For my local project, I was simply testing with a brand new CUBA Framework App (no screens other than the default Administration UI). When I launched the local Studio App it was able to create and update the Azure hosted SQL DB service - (this was a good sign)

Then I attempted to copy the WAR file (via FTP) to the Azure Web App VM,

I copied it to the folder:
/site/ wwwroot/webapps

After restarting the VM, I noticed that there was a new folder “App” under “webapps” and within the “App” folder I see folders: idp, META-INV, VAADIN, WEB-INF

However, when I attempt to access the site:
http://MyTestDomain.azurewebsites.net/app

All I got was: HTTP 404 with Apache Tomcat/8.5.6 returning: The requested resource is not available

I’m really not sure if something did not deploy properly from the WAR file or if I need to configure something on the Azure VM side (ie. like a new application virtual).

Anyway, I submitted an Azure request to Microsoft for their side and I thought I would ping you back for any input you may have from the application side.

Lastly, if your interested, I would be happy to provide you with the FTP and SQL credentials for this provisioning on Azure for your own personal testing.

Benjamin

Hi Benjamin,

Could you find and share the Tomcat output log? Looking into logs is the first thing to do when something goes wrong.

Ok, Sorry about taking a couple days to get back to you on this. I had to open a case with Microsoft Azure Support just to understand how to access the App Service Logs for their TomCat Web Container.

Anyway, I’m attaching the web log file. It looks like a problem talking to the database.
This is interesting because I can run the Cuba base Framework app locally on my WS while referring to the Azure SQL database without any issues. I did (however), have to open up the Azure SQL Server firewall to allow my local address for this to work.

My thoughts are…

  1. The Database Connection information is not getting saved with the WAR file and (perhaps), I need to re-define this somewhere else?

  2. Some port on the Azure firewall needs to allow access to the Azure SQL database from the actual web container hosted on the Azure service

  3. There is some software component running locally on my workstation (installed with Studio) that is not getting deployed to Azure with the single WAR file?

Just an FYI…
Microsoft took a copy of the WAR file and deployed it in their test App Service and received the same error in their log file as well.

Any Thoughts?

Thanks (in advance)

Benjamin

localhost.2016-11-30.log (9.2K)

Hi Benjamin,

Thank you for thorough investigation.

Could you check that the generated WAR file has META-INF/context.xml file and there are valid credentials for the database in this file?

Thanks, I checked and the file and connection information was there. However, the password was incorrect. After updating the password, I still cannot get the application to load but I appear to get something different identified in the log files. I’m attaching these files for your review.

Benjamin

localhost.2016-12-01.log (3.7K)

catalina.2016-12-01.log (21.6K)

This error in log:


Caused by: java.lang.AbstractMethodError
    at net.sourceforge.jtds.jdbc.ConnectionJDBC2.isValid(ConnectionJDBC2.java:2589)
    at org.apache.tomcat.dbcp.dbcp2.DelegatingConnection.isValid(DelegatingConnection.java:924)

is caused by some incompatibility between jTDS driver (which we use for connecting to MS SQL) and the latest version of Tomcat’s DB connection pool. It can be easily fixed by adding the following attribute to context.xml:


<Resource driverClassName="net.sourceforge.jtds.jdbc.Driver"
...
              validationQuery="select 1"/>

In fact, this attribute is added automatically for the main context.xml which is used for local deployment - you can find it in modules\core\web\META-INF\context.xml. But when you set up WAR deployment, you generate a separate file - it is called jelastic-context.xml by default and placed in the same folder. And Studio does not add the attribute automatically for MS SQL - this is our fault. So try to add the attribute manually and re-build the WAR file. Then make sure the META-INF/context.xml inside WAR looks like this:


<Context>

    <!-- Database connection -->
    <Resource
      name="jdbc/CubaDS"
      type="javax.sql.DataSource"
      maxTotal="20"
      maxIdle="2"
      maxWaitMillis="5000"
      driverClassName="net.sourceforge.jtds.jdbc.Driver"
      url="..."
      username="..."
      password="..."
      validationQuery="select 1"/>

    <!-- Switch off session serialization -->
    <Manager pathname=""/>

</Context>
1 Like

Thanks…

I think we are in business. I added the missing line, redeployed the single WAR and the app is up and running on Azure with SQL Azure as the DB !!!

I also renamed the WAR file to ROOT so as to deploy to the root folder of the Azure App Service.

I’m sure I’ll have a few more questions as I tinker with various deployment scenarios on Azure but for now - I a very happy !

Thanks.

Benjamin

1 Like

Great! Thank you for sharing your experience!

Hi (again),

As I progress with my Azure PaaS/Azure SQL deployment/scalability project I have a few more questions regarding scalability in the web and middle tiers and I was wondering if you could provide some feedback…

Thus far, (with your support) - it appears that Azure PaaS (which provides an App Service container) can host the Cuba-Framework web or middle tiers. Presently, I’ve been focused on a (simple) single tier/App Service(Server) deployed with a single WAR file (for both web and middle tiers). I’ve even set: cuba.useLocalServiceInvocation=true to optimize local communications.

Today, I had a chat with the Azure support team and confirmed a few things…

Azure PaaS App Service containers can dynamically scale up and out based upon various rules and schedules. When they scale out, they do so by simply spinning up exact copy of the initially deployed App Service Container (or host server). Load balancing is automatically handled with a single DNS name provisioned for the app service. There is no immediate (easy) way to define unique host names or settings in an XML file relative the instance spun up. We can (however), have a middle tier App Service and a separate web tier App Service (each with a single URI)

With this in mind and reference to your documentation on Application Scaling:
https://doc.cuba-platform.com/manual-latest/scaling.html

Could you comment on the following?

  1. With reference to your Stage-3 scalability diagram, if we only use a single middle tier host which can be accessed via a single URL, then I assume, we only need to define a single middle tier url in the cuba.connectionUriList (as described in the Stage-2 reference)? Does this sound right?

  2. For Stage-4, I’m concerned about the requirement for specific settings relative to each new instance of a middle tier host. Since the load balancing for the middle tier can redirect indiscriminately - Do you foresee any problems considering that middle tier servers are spun up as exact copies of each other and there is no immediate way to define specific settings relative to each host server? In other words, there might be no easy way for the middle tier host servers to know who they are in the cluster for inter-server communications. As you mentioned in the Stage-4 description, this might be required to exchange information about user sessions, locks, etc. and provide full fault tolerance of the Middleware is provided. I’m not sure if the middle tier host servers register themselves dynamically in the database but it sounds like these settings need to be defined individually on the host server itself.
    Does this sound like a valid concern?

  3. Assuming #2 (above) is a problem, perhaps a more direct solution would be to simply keep the middle tier and web tier together on single App Service host servers (hosting the web interface) and simply scale out at that level… Of course there could be more load placed on the web server but (at least) they could dynamically scale out as required.
    Thoughts?

Thanks (again) for all your support

Benjamin Siegel

Hi Benjamin,

  1. Exactly. The Stage-3 scenario can be easily implemented because web tier doesn’t require specific settings for spawned nodes or reconfiguration of existing ones.

  2. Yes, this is a valid concern. As you know, the communication in middleware cluster is implemented using JGroups framework. The only reliable way of using JGroups in a cloud is using its TCP-based stack, because multicast communication is usually just disabled. By default TCPPING is used for discovery (see commented section in jgroups.xml provided with the platform), so you need to specify IP addresses of all cluster members on each node. It becomes a problem when you add new nodes automatically on demand. There are other discovery mechanisms, particularly S3_PING that we use when deploying in Amazon cloud. You can try to use other protocols, see http://www.jgroups.org/manual/html/protlist.html#DiscoveryProtocols

  3. If you don’t setup communication on middleware tier, you will not be able to use the following functionality:

  • Entity and Query cache

  • Pessimistic locking

  • Automatic coordination of various configuration caches. So for example if you change a DB-stored app property, you will need to connect to each node and reload configuration on it. The same is for dynamic attributes.

  • Single-Sign-On sessions and Oauth2 REST API tokens will not be replicated.

I think it still can be a reasonable trade-off depending on your application requirements.

In fact, the scalability in clouds is a very interesting topic and we are going to make clustering more cloud-friendly in the near future, perhaps in the first half of 2017.

Thanks for the feedback (again)…

I think a reasonable provisioning tradeoff (in the near term) is to simply pre-deploy a few middle tier App Services (VMs) and setup the provisioning so they all know who they are (no dynamic scaling). Then, create a single web tier App Service (VM) – that can dynamically scale - with the definitions listing all the middle tier VMs (not accessed via a load balancer). As I understand it, the web tier servers will all communicate with a single middle tier server (unless it goes off-line) in which case they will move to the next one. This should give us fault tolerance in the web and middle tier with load distribution in the web tier. However, (unless I miss-understand to docs), the middle tier will not distribute workloads – only share a cache for fault tolerance. All processing will still be on a single middle tier App Service (VM) in (unless it goes offline), then the web tier servers will all redirect to the next server in the list.

Does this sound right?
Just curious if the middle tier servers distribute processing loads among themselves (ie. a task distribution system)

Lastly, when making these provisioning changes (ie. the list of middle-tier servers for the web tier VM to look for) – is this done in a file that would be generated during the WAR file creation that would not impact local development and testing or is this something that should be manually updated on the tiered servers after deployment of the WAR file?

Your assumption about load balancing is right - you can easily achieve it on the web tier but on the middleware all client requests will go to a server which is the first available in cuba.connectionUrlList. The only ability to distribute clients is to turn on the cuba.randomServerPriority app property, but it will work for the whole web server, so if the number of web servers is small, the load will not be evenly distributed.

In fact, CUBA clustering is not well suited for automatic horizontal scaling yet. The usual scenario now is to have 2 or 3 middleware servers in a cluster and manually separate load between user requests and background processes: for example, you specify server1,server2 in cuba.connectionUrlList and opposite order server2,server1 in Permitted Servers field of scheduled tasks.

As I mentioned earlier, we are going to work on this issue in 2017.

As for settings for production deployment - they should be specified in the appProperties parameter of the buildWar task, so they will not affect your development settings and instead will be added to /WEB-INF/local.app.properties inside your WAR file. Please note that you can encounter this bug in the current version of Studio if you specify a real URL in cuba.connectionUrlList. The fix will be available in Studio 6.3.3 next week.

Got it. Thanks for confirming…
Time to deploy a middle tier and run some tests…

Thanks

Benjamin

Oh,
One last thing, you reference a bug (above) with regards to the “cuba.connectionUrlList” but the link goes nowhere. Could you check the link or clarify more about the bug?

Thanks

Benjamin

Are you sure the link doesn’t work for you? It should open the issue in our bugtracker: “STUDIO-3166 If the value of appProperty in CubaWarBuilding task contains colon the project could not be opened in Studio”

Humm, Seems to be working today.

Thanks anyway for the description.

Benjamin