Search This Blog

Tuesday, April 29, 2014

Important steps of clustering WSO2 API Manager in hybrid mode or worker manager seperated mode


In this post I'm discussing some important facts about additional transports and port mappings in WSO2 Elastic Load Balancer and WSO2 API Manager product clustering scenarios. To find out a complete guide you have to follow WSO2 Product clustering documentations.

WSO2 API Manager is a descendant of WSO2 ESB. So it uses a few more than one transports which is Servlet and Passthrough

I'm using 101 as ELB and APIM's port offset, so the port mapping will be as following

ELB Port offset 101APIMPort offset 101
http8381http (pt)8381
https8344https (pt)8344
http28382http2 (servlet)9864
https28345https2 (servlet)9544

When fronting an API-M with ELB, you have to open two more transports in ELB to map to the APIM's extra transports. For that you have to add additional transportReceiver and transportSender configurations.  That is done as following.

ELB - axis2.xml

transportRecceiver

   <transportReceiver name="http" class="org.apache.synapse.transport.passthru.PassThroughHttpListener">  
    <parameter name="port">8280</parameter>  
    <parameter name="non-blocking"> true</parameter>  
    <parameter name="httpGetProcessor" locked="false">org.wso2.carbon.transport.nhttp.api.PassThroughNHttpGetProcessor</parameter>  
   </transportReceiver>  
   <transportReceiver name="http2" class="org.apache.synapse.transport.passthru.PassThroughHttpListener">  
    <parameter name="port">8281</parameter>  
    <parameter name="non-blocking"> true</parameter>  
    <parameter name="httpGetProcessor" locked="false">org.wso2.carbon.transport.nhttp.api.PassThroughNHttpGetProcessor</parameter>  
   </transportReceiver>  
   <transportReceiver name="https" class="org.apache.synapse.transport.passthru.PassThroughHttpSSLListener">  
     <parameter name="port" locked="false">8243</parameter>  
     <parameter name="non-blocking" locked="false">true</parameter>  
     <parameter name="httpGetProcessor" locked="false">org.wso2.carbon.transport.nhttp.api.PassThroughNHttpGetProcessor</parameter>  
     <!--parameter name="bind-address" locked="false">hostname or IP address</parameter-->  
     <!--parameter name="WSDLEPRPrefix" locked="false">https://apachehost:port/somepath</parameter-->  
     <parameter name="keystore" locked="false">  
       <KeyStore>  
         <Location>repository/resources/security/wso2carbon.jks</Location>  
         <Type>JKS</Type>  
         <Password>wso2carbon</Password>  
         <KeyPassword>wso2carbon</KeyPassword>  
       </KeyStore>  
     </parameter>  
     <parameter name="truststore" locked="false">  
       <TrustStore>  
         <Location>repository/resources/security/client-truststore.jks</Location>  
         <Type>JKS</Type>  
         <Password>wso2carbon</Password>  
       </TrustStore>  
     </parameter>  
   </transportReceiver>  
   <transportReceiver name="https2" class="org.apache.synapse.transport.passthru.PassThroughHttpSSLListener">  
     <parameter name="port" locked="false">8244</parameter>  
     <parameter name="non-blocking" locked="false">true</parameter>  
     <parameter name="httpGetProcessor" locked="false">org.wso2.carbon.transport.nhttp.api.PassThroughNHttpGetProcessor</parameter>  
     <!--parameter name="bind-address" locked="false">hostname or IP address</parameter-->  
     <!--parameter name="WSDLEPRPrefix" locked="false">https://apachehost:port/somepath</parameter-->  
     <parameter name="keystore" locked="false">  
       <KeyStore>  
         <Location>repository/resources/security/wso2carbon.jks</Location>  
         <Type>JKS</Type>  
         <Password>wso2carbon</Password>  
         <KeyPassword>wso2carbon</KeyPassword>  
       </KeyStore>  
     </parameter>  
     <parameter name="truststore" locked="false">  
       <TrustStore>  
         <Location>repository/resources/security/client-truststore.jks</Location>  
         <Type>JKS</Type>  
         <Password>wso2carbon</Password>  
       </TrustStore>  
     </parameter>  
   </transportReceiver>  

transportSender

   <transportSender name="http" class="org.apache.synapse.transport.passthru.PassThroughHttpSender">  
     <parameter name="non-blocking" locked="false">true</parameter>  
     <parameter name="warnOnHTTP500" locked="false">*</parameter>  
     <!--parameter name="http.proxyHost" locked="false">localhost</parameter>  
     <parameter name="http.proxyPort" locked="false">3128</parameter>  
     <parameter name="http.nonProxyHosts" locked="false">localhost|moon|sun</parameter-->  
   </transportSender>  
   <transportSender name="http2" class="org.apache.synapse.transport.passthru.PassThroughHttpSender">  
     <parameter name="non-blocking" locked="false">true</parameter>  
     <parameter name="warnOnHTTP500" locked="false">*</parameter>  
     <!--parameter name="http.proxyHost" locked="false">localhost</parameter>  
     <parameter name="http.proxyPort" locked="false">3128</parameter>  
     <parameter name="http.nonProxyHosts" locked="false">localhost|moon|sun</parameter-->  
   </transportSender>  
   <transportSender name="https" class="org.apache.synapse.transport.passthru.PassThroughHttpSSLSender">  
     <parameter name="non-blocking" locked="false">true</parameter>  
     <parameter name="keystore" locked="false">  
       <KeyStore>  
         <Location>repository/resources/security/wso2carbon.jks</Location>  
         <Type>JKS</Type>  
         <Password>wso2carbon</Password>  
         <KeyPassword>wso2carbon</KeyPassword>  
       </KeyStore>  
     </parameter>  
     <parameter name="truststore" locked="false">  
       <TrustStore>  
         <Location>repository/resources/security/client-truststore.jks</Location>  
         <Type>JKS</Type>  
         <Password>wso2carbon</Password>  
       </TrustStore>  
     </parameter>  
     <parameter name="HostnameVerifier">AllowAll</parameter>  
    </transportSender>  
   <transportSender name="https2" class="org.apache.synapse.transport.passthru.PassThroughHttpSSLSender">  
     <parameter name="non-blocking" locked="false">true</parameter>  
     <parameter name="keystore" locked="false">  
       <KeyStore>  
         <Location>repository/resources/security/wso2carbon.jks</Location>  
         <Type>JKS</Type>  
         <Password>wso2carbon</Password>  
         <KeyPassword>wso2carbon</KeyPassword>  
       </KeyStore>  
     </parameter>  
     <parameter name="truststore" locked="false">  
       <TrustStore>  
         <Location>repository/resources/security/client-truststore.jks</Location>  
         <Type>JKS</Type>  
         <Password>wso2carbon</Password>  
       </TrustStore>  
     </parameter>  
     <parameter name="HostnameVerifier">AllowAll</parameter>  
       <!--supports Strict|AllowAll|DefaultAndLocalhost or the default if none specified -->  
    </transportSender>  


The loadbalancer.conf of ELB need to have the information of the APIM cluster  such as domains, and hosts. Normally the hosts are separated as manager and worker. But here since, I'm going to use the APIM instance as a hybrid instance the separation of host names as management and worker will be a wrong configuration.

If an APIM node joined the ELB as a management node, even if it's Passthrough transports are mapped into ELB's one transport, the requests will not be served, since ELB doesn't know if APIM node is capable of serving pt requests.

So the loadbalancer.conf configuration specific to the APIM is as following.

   apimanager {  
     # multiple hosts should be separated by a comma.  
     #url_suffix       esb.wso2.com;  
     domains  {  
       wso2.am160.domain {  
         tenant_range  *;  
         group_mgt_port 4050;  
           hosts mgt.am160.gw.com,am160.gw.com;  
       }  
     }  
   }  

if, however, someone need to use seperate management and worker nodes for gateway, then the elb configuraion should be as following. Note the difference.

   apimanager {  
     # multiple hosts should be separated by a comma.  
     #url_suffix       esb.wso2.com;  
     domains  {  
       wso2.am160.domain {  
         tenant_range  *;  
         group_mgt_port 4050;  
         mgt {  
           hosts mgt.am160.gw.com;  
         }  
         worker {  
           hosts am160.gw.com;  
         }  
     }  
   }  


In the APIM side, other than the passthrough transports, I have opened the Servlet transports naming their transport names to match with those in the ELB. This is not mandatory since it is by default open in any wso2 server. But I've done this specifically so that the transport Receiver names matches with the ELB's ones.

   <transportReceiver name="http2"  
             class="org.wso2.carbon.core.transports.http.HttpTransportListener">  
     <!--  
       Uncomment the following if you are deploying this within an application server. You  
       need to specify the HTTP port of the application server  
     -->  
     <parameter name="port">9763</parameter>  
     <!--  
     Uncomment the following to enable Apache2 mod_proxy. The port on the Apache server is 80  
     in this case.  
     -->  
     <!--<parameter name="proxyPort">80</parameter>-->  
   </transportReceiver>  
   <transportReceiver name="https2"  
             class="org.wso2.carbon.core.transports.http.HttpsTransportListener">  
     <!--  
       Uncomment the following if you are deploying this within an application server. You  
       need to specify the HTTPS port of the application server  
     -->  
     <parameter name="port">9443</parameter>  
     <!--  
     Uncomment the following to enable Apache2 mod_proxy. The port on the Apache server is 443  
     in this case.  
     -->  
     <!--<parameter name="proxyPort">443</parameter>-->  
   </transportReceiver>  

The other most important thing is the port mapping.

Those transports we have defined as http and https in ELB and in APIM will be mapped together when the APIM joins the ELB, since those are the default names that is used as transportSender and transportReceiver names.

The other transports in APIM which are the Servlet transports need to be mapped to ELBs, additionally opened transports, so that ELB knows how to server Management requests of the APIM node.  The configuration is as follows.

     <parameter name="properties">  
       <property name="backendServerURL" value="https://${hostName}:${httpsPort}/services/"/>  
       <property name="mgtConsoleURL" value="https://${hostName}:${httpsPort}/"/>  
       <property name="port.mapping.8382" value="9864"/>  
       <property name="port.mapping.8345" value="9544"/>  
       <!--<property name="subDomain" value="mgt"/>-->  
     </parameter>  

See that I have commented out the subDomain property so that the APIM does not specifically say ELB, that it is a management or worker node. So that ELB can serve Passthrough and Servlet requests together.