All,

Thanks for your replies, very good information.


Christopher,

Let me share additional information about my environment: 

1) All my servers, production and non-production, are hosted at two data 
centers (different locations) with a third-party company (A)
-Server specs: Mac mini, 16 GB memory and 1 TB HD

2)There is one Tomcat instance per server and all Tomcats are in a cluster, 
having HTTPD in front
-on HTTPD, mod_jk is used
-one cluster per each location, multicast is used - I do recall a presentation 
where not using multicast was mentioned - I need to check my notes 

3) The application is developed by a third-party company (B) and uploaded to 
one of my non-production servers

4) When an application needs to be deployed, I connect (ssh) to the target 
server(s) and from there, I use scp to get the war file from the non-production 
server and place the war file into a particular directory; then, I have a 
script that moves the war file to $CATALINA_BASE and do some additional 
validations
-Autodeploy and Parallel deployment are used
-I explored the FarmWebDeployer option years ago but had the war file removed 
from the cluster when the master node was down… maybe I had a wrong 
configuration then.. so I will need to check this option again and experiment

5) As per the JAVA_OPTS…
-I use it for “-server -Dfile.encoding=UTF-8”
-It seems that I can add “-server -Dfile.encoding=UTF-8” to CATALINA_OPTS; I 
will change and test it.



I have an additional question:

1) Would there be any recommendations for not having one Tomcat instance per 
physical server?

____________
Israel Timoteo

> On May 19, 2017, at 2:06 PM, Mark Eggers <its_toas...@yahoo.com.INVALID> 
> wrote:
> 
> Folks,
> 
> Beware, the following is extremely ugly Groovy. I've changed the names
> to protect the guilty (I think).
> 
> Also, the *_SVR and *_URL values are environment values stored centrally
> in Jenkins. That way they can be changed easily. They also show up in
> the job logs, which means with a little scripting effort I can get a
> history of what versions were deployed to what server when.
> 
> Please review and laugh . . . or better yet, proffer improvements :-).
> 
> On 5/19/2017 10:10 AM, Decker, Richard M wrote:
>> Mark,
>> 
>>> -----Original Message-----
>>> From: Mark Eggers [mailto:its_toas...@yahoo.com.INVALID]
>>> Sent: Friday, May 19, 2017 10:44 AM
>>> To: Tomcat Users List <users@tomcat.apache.org>
>>> Subject: Re: Tomcat on macOS
>>> 
>>> Chris,
>>> 
>>> On 5/19/2017 7:33 AM, Christopher Schultz wrote:
>>>> Israel,
>>>> 
>>>> On 5/18/17 10:52 AM, Israel Timoteo wrote:
>>>>> Any comments from the community for ...
>>>> 
>>>>> 1) What tools is the community using for simultaneous applications
>>>>> deployment on several servers, let’s say more than 20?
>>>> 
>>>> I am using neither of these strategies, but...
>>>> 
>>>> a. FarmWebDeployer [1]
>>> 
>>> Doesn't this require a cluster (and therefore multicast)? That becomes
>>> challenging in a cloud environment where there's no multicast easily
>>> available.
>>> 
>>>> b. Auto-deploy + scp
>>> 
>>> This would be nice with a little scripting.
>>> 
>>>> 
>>>> Why in the world are you deploying a web application to 20+
>>>> macos-based servers? Or do you have a Macos client and 20+
>>>> non-macos-based servers?
>>>> 
>>>>> 4) Is JAVA_OPTS required?
>>>> 
>>>> JAVA_OPTS is only required if you require any java opts. Do you
>>>> require such options? Usually, when people set JAVA_OPTS they really
>>>> want to set CATALINA_OPTS instead.
>>>> 
>>>> Hope that helps,
>>>> -chris
>>>> 
>>>> [1]
>>>> http://tomcat.apache.org/tomcat-8.0-doc/config/cluster-deployer.html
>>> 
>>> What I do is use Jenkins, Maven, Nexus, and a little Groovy scripting.
>>> 
>>> 1. Maven with the Tomcat Maven Plugin [1]
>>> 
>>> The WAR file is customized (context.xml) based on the target environment.
>>> 
>>> 2. Jenkins
>>> 
>>> The build is run by Jenkins, and the build number (with a little 0 padding 
>>> via a
>>> Groovy script) is tacked onto the WAR name as app##0000nn.war.
>> 
>> I don't mean to hijack the thread, but could you expand on this? Could you 
>> please provide examples of your Groovy scripts?
>> 
>>> 
>>> This allows the parallel deploy feature to be used [2].
>>> 
>>> 3. Nexus
>>> 
>>> This is where all of the base artifacts are stored. Nexus 2 is used 
>>> currently
>>> since Nexus 3 doesn't have the REST API needed to cleanly interact with the
>>> Jenkins job via a Groovy script. Maybe I should learn how to write a Nexus
>>> plugin to get lists of artifact versions via REST . . .
>>> 
>>> 4. Groovy scripting
>>> 
>>> Groovy is used in Jenkins to do the following:
>>> 
>>> a. Query Nexus to get a list of artifact versions b. Prevent non-production
>>> artifacts from landing on production platforms c. Create the final number 
>>> for
>>> parallel deployment
>>> 
>>> To expand this to multiple machines, a set of pipeline jobs could be 
>>> created.
>>> 
>>> a. Build the customized WAR for the target environment b. Multiple jobs
>>> deploy to the servers in the target environment c. Multiple jobs validate 
>>> the
>>> deployment d. Final job sends mail to interested parties with success / 
>>> failure
>>> 
>>> I know that's a lot of infrastructure. There are certainly things that 
>>> could be
>>> done differently. Ant (with Ivy), or gradle could be used for the builds. A
>>> different repository manager could be used (other than Nexus). A different
>>> CI / CD system could be used (other than Jenkins).
>>> 
>>> Anything that meets at least the following requirements could be strung
>>> together.
>>> 
>>> a. Reliable place to get the WAR file you need to deploy b. Reliable build
>>> system that can be automated c. Build system that can deploy to Tomcat d.
>>> Testing that the deployment actually worked e. Notification
>>> 
>>> The end result is that some authorized person can log into Jenkins, select a
>>> version of an application to deploy, deploy it to the target environment,
>>> know that it's been successful (or not), and have notifications 
>>> automatically
>>> sent out.
>>> 
>>> [1] http://tomcat.apache.org/maven-plugin.html
>>> [2]
>>> https://tomcat.apache.org/tomcat-8.0-
>>> doc/config/context.html#Parallel_deployment
>>> 
>>> . . . just my (rather lengthy) 2 cents
>>> /mde/
> 
> // talks to Nexus 2 servers - NOT Nexus 3
> // Gets list of versions for a particular groupId and artifactId
> // review and use at your own risk
>  def prod =
> "http://my.nexus.server.com/nexus/service/local/repositories/releases/content";
>  def snap =
> "http://my.nexus.server.com/nexus/service/local/repositories/snapshots/content";
> 
>  def groupId = ARTIFACT_GROUP
>  def artifactId = ARTIFACT_ID
>  def target = ARTIFACT_TARGET
> 
>  def versions = []
> 
>  def locationp = prod + "/" + groupId.replaceAll("\\.","/") + "/" +
> artifactId
>  def locations = snap + "/" + groupId.replaceAll("\\.","/") + "/" +
> artifactId
> 
>  // get all available SNAPSHOT versions
>  try {
>         def scontent = new XmlParser().parseText(new 
> URL(locations).getText());
>         for (contentNode in scontent.data.'content-item') {
>                 if (contentNode.leaf.text() != "true") {
>                         versions.add(contentNode.text.text())
>                 }
>         }
>  } catch (FileNotFoundException e) {
>  }
> 
>  // get all available released versions
>  try {
>         def pcontent = new XmlParser().parseText(new 
> URL(locationp).getText());
>         for (contentNode in pcontent.data.'content-item') {
>                 if (contentNode.leaf.text() != "true") {
>                         versions.add(contentNode.text.text())
>                 }
>         }
>  } catch (FileNotFoundException e) {
>  }
> 
>  // no artifacts in Nexus repository
>  if ( versions.isEmpty() ) {
>         versions.add("NO-VERSION")
>         return versions
>  }
> 
>  switch (target) {
>         // production servers cannot host SNAPSHOT releases
>         case ["PROD","PROD02","PROD01","PROD03","PROD04","PROD05"]:
>                 def pversions = []
>             for (version in versions) {
>                 if (!version.endsWith("SNAPSHOT")) {
>                         pversions.add(version)
>                 }
>             }
>             versions = pversions
>             // no releases in Nexus repository
>             if (versions.isEmpty()) {
>                 versions.add("NO-VERSION")
>             }
>         break
>         default:
>         break
>  }
> 
>  sversions = versions.sort().reverse()
>  return sversions
> 
> // takes artifact versions and creates appropriate Maven parameters
> // popcorn needed - scotch recommended - review and use at your own risk
> def tname = ''
> def url = ''
> def svr = ''
> def bn = ''
> def host = ''
> def vurl = ''
> def ddate = new Date()
> 
> // target server
> if (binding.variables.containsKey('ARTIFACT_TARGET')) {
>    tname = binding.variables.get('ARTIFACT_TARGET')
>    switch (tname) {
>       // production - prod01.server.com
>       case "PROD01":
>               if (binding.variables.containsKey('PROD01_URL')) {
>                       url = binding.variables.get('PROD01_URL')
>                       host = url - ~/:\d{4}\/manager\/text/
>                       vurl ="https://prod01.server.com"; + '/' +
> binding.variables.get('ARTIFACT_ID')
>               }
>               if (binding.variables.containsKey('PROD01_SVR')) {
>                       svr = binding.variables.get('PROD01_SVR')
>               }
>       break
>       // production - prod02.server.com
>       case "PROD02":
>               if (binding.variables.containsKey('PROD02_URL')) {
>                       url = binding.variables.get('PROD02_URL')
>                       host = url - ~/:\d{4}\/manager\/text/
>                       vurl = "http://prod02.server.com"; + '/' +
> binding.variables.get('ARTIFACT_ID')
>               }
>               if (binding.variables.containsKey('PROD02_SVR')) {
>                       svr = binding.variables.get('PROD02_SVR')
>               }
>       break
>       // production - PROD03.server.com
>       case "PROD03":
>               if (binding.variables.containsKey('PROD03_URL')) {
>                       url = binding.variables.get('PROD03_URL')
>                       host = url - ~/:\d{4}\/manager\/text/
>                       vurl = "http://prod03.server.com"; + '/' +
> binding.variables.get('ARTIFACT_ID')
>               }
>               if (binding.variables.containsKey('PROD03_SVR')) {
>                       svr = binding.variables.get('PROD03_SVR')
>               }
>       break
>       // production - prod04.server.com
>       case "PROD04":
>               if (binding.variables.containsKey('PROD04_URL')) {
>                       url = binding.variables.get('PROD04_URL')
>                       host = url - ~/:\d{4}\/manager\/text/
>                       vurl = "prod04.server.com" + '/' +
> binding.variables.get('ARTIFACT_ID')
>               }
>               if (binding.variables.containsKey('PROD04_SVR')) {
>                       svr = binding.variables.get('PROD04_SVR')
>               }
>       break
>       // production - prod05.server.com
>       case "PROD05":
>               if (binding.variables.containsKey('PROD05_URL')) {
>                       url = binding.variables.get('PROD05_URL')
>                       host = url - ~/:\d{4}\/manager\/text/
>                       vurl = "http://prod05.server.com"; + '/' +
> binding.variables.get('ARTIFACT_ID')
>               }
>               if (binding.variables.containsKey('PROD05_SVR')) {
>                       svr = binding.variables.get('PROD05_SVR')
>               }
>       break
>       // user acceptance test - uattest.server.com
>       case "UATTEST":
>               if (binding.variables.containsKey('UATTEST_URL')) {
>                       url = binding.variables.get('UATTEST_URL')
>                       host = url - ~/:\d{4}\/manager\/text/
>                       vurl = "http://uattest.server.com"; + '/' +
> binding.variables.get('ARTIFACT_ID')
>               }
>               if (binding.variables.containsKey('UATTEST_SVR')) {
>                       svr = binding.variables.get('UATTEST_SVR')
>               }
>       break
>       // internal test - itest.server.com
>       case "ITEST":
>               if (binding.variables.containsKey('ITEST_URL')) {
>                       url = binding.variables.get('ITEST_URL')
>                       host = url - ~/:\d{4}\/manager\/text/
>                       vurl = host + '/' + binding.variables.get('ARTIFACT_ID')
>               }
>               if (binding.variables.containsKey('ITEST_SVR')) {
>                       svr = binding.variables.get('ITEST_SVR')
>               }
>       break
>       // default is to deploy to internal test
>       default:
>               if (binding.variables.containsKey('ITEST_URL')) {
>                       url = binding.variables.get('ITEST_URL')
>                       host = url - ~/:\d{4}\/manager\/text/
>                       vurl = host + '/' + binding.variables.get('ARTIFACT_ID')
>               }
>               if (binding.variables.containsKey('ITEST_SVR')) {
>                       svr = binding.variables.get('ITEST_SVR')
>               }
>       break
>    }
> }
> 
> // build number with proper zero padding
> if (binding.variables.containsKey('BUILD_NUMBER')) {
>    bns = binding.variables.get('BUILD_NUMBER')
>    bni = bns.toInteger()
>    if (bni < 10) {
>        bn = '0000' + bni.toString()
>    } else if (bni < 100) {
>        bn = '000' + bni.toString()
>    } else if (bni < 1000) {
>        bn = '00' + bni.toString()
>    } else if (bni < 10000) {
>        bn = '0' + bni.toString()
>    } else {
>        bn = bn.toString()
>    }
> } else {
>    bn = '00001'
> }
> 
> return [ TARGET_URL:url, TARGET_SERVER:svr, BN:bn, ARTIFACT_URL:vurl,
> DEPLOY_DATE:ddate ]
> 
> The second script creates appropriate environment variables for the
> following Maven command:
> 
> mvn -U clean package tomcat7:deploy -Dbuild.number=${BN}
> -Dversion.number=${ARTIFACT_VERSION} -Ddeploy.url=${TARGET_URL}
> -Ddeploy.server=${TARGET_SERVER}
> 
> The DEPLOY_DATE is used in the email notification, as is the BUILD_USER
> Jenkins variable. That way, everyone knows who did bad things to a
> server when.
> 
> Sorry for the line wrap.
> 
> . . . just my (ugly scripting) two cents
> /mde/
> 

Reply via email to