How to parametrize Mule Deployments


In 
previous posts, we’ve seen how to use the Mule Maven Plugin (MMP) to automate the deployment of our Mule apps to the different deployment targets - Standalone, Cloudhub 1.0, Cloudhub 2.0 and Runtime Fabric. 
In all of those examples, we were hard-coding the values for the configuration of the Mule Maven Plugin. This is not how we would do it in a Production scenario.

Why Parametrize Mule Deployments?

But before we see how to do it, why is it important to parametrize the deployments? Here’s a list of good reasons:

Environment-Specific Configuration:

  • Our Mule applications normally will require different settings per environment (like database credentials, URLs, or API keys). Hardcoding these configurations into the application would require manual changes when moving between environments, which is prone to errors and inefficient.
  • It helps us to create a (unique) implementation that does not need to be modified when changing the environment. This ensures that the application is more portable and easier to maintain. 

Automation and Continuous Integration/Continuous Deployment (CI/CD):

  • With parameterization, we can automate the deployment process. The same deployment pipeline can be used for all environments by simply passing different parameters.
  • This is a key practice for CI/CD pipelines, where deployments should be repeatable, reliable, and automated without manual intervention.

Security and Best Practices:

Sensitive data such as API keys, passwords, and credentials should NEVER be hardcoded. Parameterizing these values allows us to externalize sensitive information into configuration files or secure vaults.

Ease of Maintenance:

Parametrization reduces the need to maintain multiple versions of the same application for different environments. Instead, a single version of the app can be deployed with different configurations depending on the target environment.


How to Parametrize the Mule Maven Plugin configuration

Let’s take an example of a Mule Maven Plugin configuration for Cloudhub 2.0 where the values are hardcoded.

<plugin>
<groupId>org.mule.tools.maven</groupId>
<artifactId>mule-maven-plugin</artifactId>
<version>4.3.0</version>
<extensions>true</extensions>
<configuration>
<cloudhub2Deployment>
<uri>https://anypoint.mulesoft.com</uri>
<provider>MC</provider>
<businessGroupId>fc9e3283-a489-4e88-99aa-cceea4aa5ea1</businessGroupId>
<environment>Sandbox</environment>
<target>GON-PS</target>
<muleVersion>4.8.0</muleVersion>
<server>anypoint-exchange-v3</server>
<applicationName>my-mule-app</applicationName>
<replicas>1</replicas>
<vCores>0.1</vCores>
<properties>
<api.manager.autodiscoveryId>12345</api.manager.autodiscoveryId>
</properties>
<secureProperties>
<anypoint.platform.client_id>85956be2d60c94742e4ec6487f50578d</anypoint.platform.client_id>
<anypoint.platform.client_secret>k598u517d2d9te085969c947485287f50</anypoint.platform.client_secret>
</secureProperties>
</cloudhub2Deployment>
</configuration>
</plugin>

Now let’s see different ways of removing those hard-coded values


Reference Maven Properties

Maven properties are often defined in the <properties> section of our pom.xml file. We can define custom properties or override built-in Maven properties.
Once defined, Maven properties can be referenced throughout the pom.xml or in other Maven-related configurations.

We can refer to any property by using the ${propertyName} syntax.
For example, we can define a property for the version of the Mule Maven Plugin and the Mule Runtime version in the POM file and reference those values in the configuration of the plugin:

<project>
...
<properties>
...
<app.runtime>4.8.0</app.runtime>
<mule.maven.plugin.version>4.3.0</mule.maven.plugin.version>
...
</properties>
...
<build>
<plugins>
<plugin>
<groupId>org.mule.tools.maven</groupId>
<artifactId>mule-maven-plugin</artifactId>
<version>${mule.maven.plugin.version}</version>
<extensions>true</extensions>
<configuration>
<cloudhub2Deployment>
...
<muleVersion>${app.runtime}</muleVersion>
...
</cloudhub2Deployment>
</configuration>
</plugin>
</plugins>
</build>
...
</project>


Reference Elements in the POM file

We can also pick up values from other elements in the POM file, not only the ones in the <properties> section. For example, we can use the Maven coordinates of the mule app:
  • The mule application name can be taken from the artifactId
  • The businessGroupId where we’ll deploy the app is something that is also defined in the groupId
This way we can add more parameters:

<project>
<groupId>fc9e3283-a489-4e88-99aa-cceea4aa5ea1</groupId>
<artifactId>deploy-to-ch2</artifactId>
<version>1.0.0</version>
<packaging>mule-application</packaging>

<name>deploy-to-ch2</name>
...
<properties>
...
<app.runtime>4.8.0</app.runtime>
<mule.maven.plugin.version>4.3.0</mule.maven.plugin.version>
...
</properties>
...
<build>
<plugins>
<plugin>
<groupId>org.mule.tools.maven</groupId>
<artifactId>mule-maven-plugin</artifactId>
<version>${mule.maven.plugin.version}</version>
<extensions>true</extensions>
<configuration>
<cloudhub2Deployment>
...
<businessGroupId>${project.groupId}</businessGroupId>
<muleVersion>${app.runtime}</muleVersion>
<applicationName>${project.artifactId}</applicationName>
...
</cloudhub2Deployment>
</configuration>
</plugin>
</plugins>
</build>
...
</project>

Notice that, to reference elements of the POM file we need to provide the hierarchy of tags, e.g. ${project.[ELEMENT]}, whereas references to properties defined within the 
<properties> element don’t need that, e.g. the mule runtime can be reference with the syntax ${app.runtime}, no need to use the whole path of elements like ${project.properties.app.runtime}

Pass Parameters via Command Line

We can define the value of our properties using the Maven CLI with the syntax -Dproperty=value. Property values coming from the command line will override the values defined in the POM.
For example, some values that are good candidates to be set up via Command line are:
  • vcores
  • replicas
So, we could define a property for those two config elements of the plugin like this:

<project>
<groupId>fc9e3283-a489-4e88-99aa-cceea4aa5ea1</groupId>
<artifactId>deploy-to-ch2</artifactId>
<version>1.0.0</version>
<packaging>mule-application</packaging>

<name>deploy-to-ch2</name>
...
<properties>
...
<app.runtime>4.8.0</app.runtime>
<mule.maven.plugin.version>4.3.0</mule.maven.plugin.version>
...
</properties>
...
<build>
<plugins>
<plugin>
<groupId>org.mule.tools.maven</groupId>
<artifactId>mule-maven-plugin</artifactId>
<version>${mule.maven.plugin.version}</version>
<extensions>true</extensions>
<configuration>
<cloudhub2Deployment>
...
<businessGroupId>${project.groupId}</businessGroupId>
<muleVersion>${app.runtime}</muleVersion>
<applicationName>${project.artifactId}</applicationName>
<replicas>${replicas}</replicas>
<vCores>${vcores}</vCores>
...
</cloudhub2Deployment>
</configuration>
</plugin>
</plugins>
</build>
...
</project>

And then pass the values of replicas and vcores via command line like this:

mvn clean deploy -DmuleDeploy -Dreplicas=1 -Dvcores=0.1


Pass Parameters via Environment Variables

Similarly, we can pass the values of properties using Environment variables. For that, we need to use the syntax ${env.property}. 
For example, we could define the value of environment and target using environment variables. This way we can replace the hard-coded values for replicas and vcores like this:


<project>
<groupId>fc9e3283-a489-4e88-99aa-cceea4aa5ea1</groupId>
<artifactId>deploy-to-ch2</artifactId>
<version>1.0.0</version>
<packaging>mule-application</packaging>

<name>deploy-to-ch2</name>
...
<properties>
...
<app.runtime>4.8.0</app.runtime>
<mule.maven.plugin.version>4.3.0</mule.maven.plugin.version>
...
</properties>
...
<build>
<plugins>
<plugin>
<groupId>org.mule.tools.maven</groupId>
<artifactId>mule-maven-plugin</artifactId>
<version>${mule.maven.plugin.version}</version>
<extensions>true</extensions>
<configuration>
<cloudhub2Deployment>
...
<businessGroupId>${project.groupId}</businessGroupId>
<muleVersion>${app.runtime}</muleVersion>
<applicationName>${project.artifactId}</applicationName>
<replicas>${replicas}</replicas>
<vCores>${vcores}</vCores>
<environment>${env.environment}</environment>
<target>${env.target}</target>
...
</cloudhub2Deployment>
</configuration>
</plugin>
</plugins>
</build>
...
</project>

We could prepare a script for deployment where, first, we’d be defining environment variables:

export environment=Sandbox
export target=GON-PS

And then we don’t have to include any flags in the maven commands for environment and target (only for replicas and vcores from the previous step)

mvn clean deploy -DmuleDeploy -Dreplicas=1 -Dvcores=0.1

This way of passing parameters can be used by automation tools like Jenkins or Github actions. It’s a good way for controlling the environment to which we’d deploy. These tools allow us to define environment variables for the workflows or jobs that will be running the maven commands to deploy our mule apps. 

For example, Github Actions will map all the variables and secrets to environment variables in the runner of the GitHub action.


Use a Parent POM

As we’ve seen recently in previous posts, properties can be defined in the POM file of our app but also in a parent POM. When all your applications or a group of them share some common parameters and properties, a parent POM can help us to reduce redundancy in the configuration of our deployments.
So, for example, we could include in the properties section of a parent POM properties for the uri and provider elements of the mule maven plugin. This way our parent POM will be: 

<project>
...
<groupId>[YOUR_ANYPOINT_ORG_ID]</groupId>
<artifactId>parent-pom</artifactId>
<version>1.0.0</version>
...
<properties>
<anypoint.uri>https://anypoint.mulesoft.com</anypoint.uri>
<anypoint.provider>MC</anypoint.provider>
</properties>
...
</project>

I
f necessary, we could also externalize the values of these two properties in the parent POM and pick up their values from the command line or environment variables, like the previous steps.

And then, in the pom file of our app we will include the parent POM and the references to those properties in the plugin configuration

<project>
...
<parent>
<groupId>[YOUR_ANYPOINT_ORG_ID]</groupId>
<artifactId>parent-pom</artifactId>
<version>1.0.0</version>
</parent>
<groupId>fc9e3283-a489-4e88-99aa-cceea4aa5ea1</groupId>
<artifactId>deploy-to-ch2</artifactId>
<version>1.0.0</version>
<packaging>mule-application</packaging>

<name>deploy-to-ch2</name>
...
<properties>
...
<app.runtime>4.8.0</app.runtime>
<mule.maven.plugin.version>4.3.0</mule.maven.plugin.version>
...
</properties>
...
<build>
<plugins>
<plugin>
<groupId>org.mule.tools.maven</groupId>
<artifactId>mule-maven-plugin</artifactId>
<version>${mule.maven.plugin.version}</version>
<extensions>true</extensions>
<configuration>
<cloudhub2Deployment>
...
<uri>${anypoint.uri}</uri>
<provider>${anypoint.provider}</provider>
<businessGroupId>${project.groupId}</businessGroupId>
<muleVersion>${app.runtime}</muleVersion>
<applicationName>${project.artifactId}</applicationName>
<replicas>${replicas}</replicas>
<vCores>${vcores}</vCores>
<environment>${env.environment}</environment>
<target>${env.target}</target>
...
</cloudhub2Deployment>
</configuration>
</plugin>
</plugins>
</build>

</project>

Use the settings.xml file

The configuration file can use the maven properties using the same syntax. Normally, these properties would be global to the user or the machine running the maven commands for deployment. Properties in the settings files are particularly useful for credentials, environment-specific configurations, and user-specific values.

For example, as we saw in previous posts, when using a Connected App for the authentication of the Mule Maven Plugin, the Connected App credentials can be stored in the settings.xml. For that, in the Mule Maven Configuration we use the <server> element

<plugin>
<groupId>org.mule.tools.maven</groupId>
<artifactId>mule-maven-plugin</artifactId>
<version>4.3.0</version>
<extensions>true</extensions>
<configuration>
<cloudhub2Deployment>
...
<uri>${anypoint.uri}</uri>
<provider>${anypoint.provider}</provider>
<businessGroupId>${project.groupId}</businessGroupId>
<muleVersion>${app.runtime}</muleVersion>
<applicationName>${project.artifactId}</applicationName>
<replicas>${replicas}</replicas>
<vCores>${vcores}</vCores>
<environment>${env.environment}</environment>
<target>${env.target}</target>
<server>anypoint-exchange-v3</server>
...
</cloudhub2Deployment>
</configuration>
</plugin>

And then, the settings.xml file contains the client id and secret. We need to make sure the ID of the server element matches the value in the pom file

<settings>

<servers>

<server>
<id>anypoint-exchange-v3</id>
<username>~~~Client~~~</username>
<password>91f732bf23ff4575830b0c86302b9357~?~8090d2CcE1694d03a2b33Ac78339e660</password>
</server>

</servers>

</settings>

With this approach, if the settings.xml file is only accessible by the Automation server (Jenkins, Github actions, Gitlab) we’ll manage to hide those credentials from our developers.


And again, in the settings file we could define maven properties for the credentials, so that, even if the file is not accessible to developers, we don’t put any credentials value in the file. We could rewrite the settings file like this:


<settings>

<servers>

<server>
<id>anypoint-exchange-v3</id>
<username>~~~Client~~~</username>
<password>${env.clientId}~?~${env.clientSecret}</password>
</server>

</servers>

</settings>

The values for clientId and secret will be passed as environment variable, as we’ve seen before.


Use Maven Profiles

Lastly, Maven Profiles can be a very interesting way of defining different sets of properties that would be used based on the environment or deployment target.
For example, we could define two profiles: one for dev and one for prod, and define the same properties with different values in them. For instance, for the parameters required for API Manager we could define something like this:

<profiles>
<profile>
<id>dev</id>
<properties>
<api.manager.autodiscoveryId>12345</api.manager.autodiscoveryId>
<anypoint.platform.client_id>be085956c947426487f50e4ec578d2d6</anypoint.platform.client_id>
<anypoint.platform.client_secret>e4ec517d2d6be085969c947426487f50</anypoint.platform.client_secret>
</properties>
</profile>
<profile>
<id>prod</id>
<properties>
<api.manager.autodiscoveryId>54321</api.manager.autodiscoveryId>
<anypoint.platform.client_id>85956be2d60c94742e4ec6487f50578d</anypoint.platform.client_id>
<anypoint.platform.client_secret>k598u517d2d9te085969c947485287f50</anypoint.platform.client_secret>
</properties>
</profile>
</profiles>

These two profiles can be defined in the POM file, in a parent POM file or in the settings.xml. And again, these values do not have to be hardcoded, they can be passed from environment variables or command line arguments, as we’ve seen before.

In any case, we can make use of these two profiles in this way: First, by referencing these properties in the MMP configuration:

<plugin>
<groupId>org.mule.tools.maven</groupId>
<artifactId>mule-maven-plugin</artifactId>
<version>4.3.0</version>
<extensions>true</extensions>
<configuration>
<cloudhub2Deployment>
<uri>${anypoint.uri}</uri>
<provider>${anypoint.provider}</provider>
<businessGroupId>${project.groupId}</businessGroupId>
<muleVersion>${app.runtime}</muleVersion>
<applicationName>${project.artifactId}</applicationName>
<replicas>${replicas}</replicas>
<vCores>${vcores}</vCores>
<environment>${env.environment}</environment>
<target>${env.target}</target>
<server>anypoint-exchange-v3</server>
<properties>
<api.manager.autodiscoveryId></api.manager.autodiscoveryId>
</properties>
<secureProperties>
<anypoint.platform.client_id>${anypoint.platform.client_id}</anypoint.platform.client_id>
<anypoint.platform.client_secret>${anypoint.platform.client_secret}</anypoint.platform.client_secret>
</secureProperties>
</cloudhub2Deployment>
</configuration>
</plugin>

And secondly, we can activate the corresponding profile from the command line with the -P flag, like this:

mvn clean deploy -DmuleDeploy -Pdev -Dreplicas=1 -Dvcores=0.1

Summary

Parametrizing the deployment of Mule applications using the Mule Maven Plugin is crucial for enabling flexibility, consistency, and automation during the deployment process. This ensures that the same application can be deployed across different environments (such as development, testing, staging, and production) with the appropriate configurations without modifying the code base for each environment.
Previous Post Next Post