Deploy brXM authoring and delivery apps separately with Docker-compose or Kubernetes
Baris Can Vural
2020-02-28
Typically Bloomreach Experience Manager's authoring (cms) and delivery (site) applications are deployed together on the same application server. However there are use cases where deploying the authoring and delivery applications separately on different application servers is preferable. How to achieve this is described in this documentation page.
Starting from version 13.2.x, brXM comes with docker support. There’s a dedicated “docker.build” Maven profile for building a docker image and “docker.run” profile for running the image locally.
What if you want to deploy authoring and delivery applications separately, using docker and Kubernetes? How does one go about creating these separate docker images? In this article I’ll go through the project I prepared for this purpose. The project is at https://github.com/bcanvural/brxm-separate-authoring-delivery
Check out the project. In the main pom.xml, you’ll notice two additional docker profiles called “docker.authoring” and “docker.delivery”. These profiles are meant to be used like the following:
mvn clean install && mvn -Pdocker.build,docker.authoring
mvn clean install && mvn -Pdocker.build,docker.delivery
We activate both the “docker.build” and “docker.authoring” (or docker.delivery) profiles together.
Let’s first check the docker.authoring profile:
<profile> <id>docker.authoring</id> <build> <plugins> <plugin> <groupId>io.fabric8</groupId> <artifactId>docker-maven-plugin</artifactId> <!-- <executions>--> <!-- <execution>--> <!-- <id>Push the docker image</id>--> <!-- <phase>initialize</phase>--> <!-- <goals>--> <!-- <goal>push</goal>--> <!-- </goals>--> <!-- </execution>--> <!-- </executions>--> <configuration> <images combine.children="override"> <image> <name>bcanvural/${project.artifactId}-authoring:${project.version}</name> <alias>${project.artifactId}-authoring</alias> <build> <dockerFileDir>${project.basedir}/src/main/docker</dockerFileDir> <assembly> <mode>dir</mode> <name>maven/</name> <descriptor>${project.basedir}/src/main/docker/assembly/distribution-docker.xml</descriptor> </assembly> </build> </image> </images> </configuration> </plugin> </plugins> </build> </profile>
-
In the <configuration> section we override the default <configuration> coming from the “docker.build” profile (remember we activate two profiles at the same time!)
-
In the build section we specify the dockerfile directory we want to use. Note that for this “docker.authoring” profile we continue to use the default dockerfile and assembly configuration
-
There’s a commented out section in the configuration which, when commented in, pushes the image to a public image registry. I left it there for convenience.
Now let’s take a look at the “docker.delivery” profile which is more interesting:
<profile> <id>docker.delivery</id> <build> <plugins> <plugin> <groupId>io.fabric8</groupId> <artifactId>docker-maven-plugin</artifactId> <!-- <executions>--> <!-- <execution>--> <!-- <id>Push the docker image</id>--> <!-- <phase>initialize</phase>--> <!-- <goals>--> <!-- <goal>push</goal>--> <!-- </goals>--> <!-- </execution>--> <!-- </executions>--> <configuration> <images combine.children="override"> <image> <name>bcanvural/${project.artifactId}-delivery:${project.version}</name> <alias>${project.artifactId}-delivery</alias> <build> <dockerFileDir>${project.basedir}/src/main/docker/separate-deployment</dockerFileDir> <assembly> <mode>dir</mode> <name>maven/</name> <descriptor>${project.basedir}/src/main/docker/assembly/distribution-without-cms.xml</descriptor> </assembly> </build> </image> </images> </configuration> </plugin> </plugins> </build> </profile>
-
Just like the “docker.authoring” profile we override the default <configuration> from the “docker.build” profile (remember we activate two profiles at the same time!)
-
We override the dockerfile directory location. Check that at src/main/docker/separate-deployment there’s a separate dockerfile for delivery deployment.
-
We use a different assembly configuration here. It is at ${project.basedir}/src/main/docker/assembly/distribution-without-cms.xml
Let’s take a look at this assembly file now (distribution-without-cms.xml)
<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd"> <id>distribution-without-cms</id> <formats> <format>tar.gz</format> </formats> <includeBaseDirectory>false</includeBaseDirectory> <componentDescriptors> <componentDescriptor>conf-component.xml</componentDescriptor> <componentDescriptor>webapps-without-cms-component.xml</componentDescriptor> <componentDescriptor>common-lib-component.xml</componentDescriptor> <componentDescriptor>shared-lib-component.xml</componentDescriptor> </componentDescriptors> </assembly>
-
Note that the content is exactly the same as it is described in https://xmdocumentation.bloomreach.com/library/enterprise/installation-and-configuration/create-separate-distributions-for-cms-and-site.html
-
The interesting bit in this file is webapps-without-cms-component.xml, which is sitting next to this xml file.
Now let’s take a look at that file at src/main/assembly/webapps-without-cms-component.xml :
<component xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/component/1.1.2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/component/1.1.2 http://maven.apache.org/xsd/component-1.1.2.xsd"> <files> <file> <source>platform/target/platform.war</source> <outputDirectory>webapps</outputDirectory> <destName>platform.war</destName> </file> <file> <source>site/webapp/target/site.war</source> <outputDirectory>webapps</outputDirectory> <destName>site.war</destName> </file> </files> <dependencySets> <dependencySet> <useProjectArtifact>false</useProjectArtifact> <outputDirectory>webapps</outputDirectory> <outputFileNameMapping>bpm.war</outputFileNameMapping> <scope>provided</scope> <includes> <include>com.onehippo.cms7:hippo-addon-wpm-camunda:war</include> </includes> </dependencySet> </dependencySets> </component>
-
The first two wars in the list are also listed in https://documentation.bloomreach.com/library/enterprise/installation-and-configuration/create-separate-distributions-for-cms-and-site.html . No surprises there
-
The <dependencySets> section is for the projects feature, you can omit it if you don’t need it.
This is all we need to build separate docker images for authoring and delivery apps. Now if we want to run these images we have to pass a series of environment variables to these images. Otherwise they won’t start properly and fail.
Now let’s take a look at the docker-compose.yaml file in docker-compose folder to see how one can use these images. Docker compose configuration looks more compact than kubernetes configuration, which will help us understand easier how to run these docker images.
version: '3.4' services: authoring: image: bcanvural/myproject-authoring:0.1.0-SNAPSHOT ports: - "8081:8080" links: - db environment: profile: postgres POSTGRES_DB_HOST: db POSTGRES_DB_PORT: 5432 POSTGRES_DB_USER: postgres POSTGRES_DB_PASSWORD: mypass POSTGRES_DB_NAME: brxmdb POSTGRES_WPM_DB_NAME: wpmdb POSTGRES_DB_DRIVER: org.postgresql.Driver REPO_WORKSPACE_BUNDLE_CACHE: 256 REPO_VERSIONING_BUNDLE_CACHE: 64 REPO_BOOTSTRAP: "true" depends_on: - db delivery: image: bcanvural/myproject-delivery:0.1.0-SNAPSHOT user: root ports: - "8082:8080" - "5005:5005" links: - db environment: profile: postgres POSTGRES_DB_HOST: db POSTGRES_DB_PORT: 5432 POSTGRES_DB_USER: postgres POSTGRES_DB_PASSWORD: mypass POSTGRES_DB_NAME: brxmdb POSTGRES_WPM_DB_NAME: wpmdb POSTGRES_DB_DRIVER: org.postgresql.Driver REPO_WORKSPACE_BUNDLE_CACHE: 256 REPO_VERSIONING_BUNDLE_CACHE: 64 REPO_BOOTSTRAP: "false" JAVA_ENABLE_DEBUG: "true" volumes: - ./curl_till_200.sh:/brxm/curl_till_200.sh depends_on: - db - authoring entrypoint: ["sh", "-c", "/brxm/curl_till_200.sh && /brxm/bin/docker-entrypoint.sh"] db: image: postgres restart: always ports: - "5432:5432" environment: POSTGRES_PASSWORD: mypass POSTGRES_USER: postgres volumes: - ./brxmdb.sql:/docker-entrypoint-initdb.d/brxmdb.sql - ./wpmdb.sql:/docker-entrypoint-initdb.d/wpmdb.sql
-
One can run this docker compose file with “docker-compose up”
-
There are 3 services deployed together on the same network: “authoring”, “delivery” and “db”
-
The image properties for each service should match the image name we used in respective docker build profiles
-
There are two database init scripts: brxmdb.sql and wpmdb.sql being injected into a specific location in the db image. The creation of databases is a prerequisite for deploying brXM.
-
The delivery image should be deployed after authoring is deployed. This is important! To make sure this happens, there’s a bash script called “curl_till_200.sh” injected into the delivery image which makes sure authoring service is up before the delivery image’s tomcat is started.
-
Inspect the environment variables required for each service. Note that for delivery, the REPO_BOOTSTRAP is false!
-
The authoring is reachable at localhost:8081/cms and delivery is available at localhost:8082/site
-
Remote debugging for delivery is enabled at port 5005. This is not enabled ootb in brxm. Check the relevant part in src/main/docker/scripts/tomcat/setenv.sh to achieve that in your own project
The configuration for Kubernetes is very similar conceptually. The deployment yamls can be found in Kubernetes folder with names authoring-deployment.yaml and delivery-deployment.yaml respectively. Note that before these can be used the db should be set up using the setup_dbs.sh script.
In this article we covered how to:
-
Build separate docker images for authoring and delivery webapps.
-
Pass the right environment variables to each image.