AEM (Adobe Experience Manager) is a Content Management System that is widely used in large organizations. WordPress, Drupal, and much other Content Management Systems are good enough for developing and serving the Web content. But AEM is leading with Comprehensive and Robust Content Management System. However, the application runtime platform of AEM is very huge and complex to set up every time compared to other CMS Platforms. Therefore, just like any other application platform, containerization of this application will make provisioning and Infrastructure deployment process easier. So, in this article, we will discuss How to Create AEM instance in Docker with Docker Compose.
Table of Contents
Plan of action
Before starting, lets see our plan of action. We are going to create the following components.
- AEM Instances
- Author – Runs on Port 4502
- Publisher – Runs on Port 4503
- Dispatcher – Runs on Port 80
- Separate folder for all the three instances with AEM binary and License files.
- Each folder will act as separate Docker Images
docker-compose.yml
file to compose the Images to run together as containers
Setting Up Folder Structures required files.
As per our plan of action, we are going to create three different AEM instances, Author, Publisher, Dispatcher respectively. For the same, we will create four folders namely, aem-base_image
, aem-author
, aem-publisher
, aem-dispatcher
.
$ tree aem-in-docker/ aem-in-docker/ ├── aem-author ├── aem-base_image ├── aem-dispacher └── aem-publisher
Creating Base Image
In this, “aem-base_image
” folder will have the Dockerfile
and AEM binary including licenses file to create base AEM Docker image with your own license. So do the following steps.
# Using 'ubuntu' as the base image here FROM ubuntu # setting the working directory WORKDIR /opt/aem # Copy the license file COPY license.properties . # Copy Quickstart jar file COPY cq-quickstart-6.5.0.jar cq-quickstart.jar # Install Java RUN apt-get update && \ apt-get install -y curl && \ apt-get install -y software-properties-common && \ add-apt-repository ppa:openjdk-r/ppa && \ apt-get update && \ apt-get install -y openjdk-8-jdk # Unack the Jar file RUN java -jar cq-quickstart.jar -unpack
$ docker build -t aem-base-image .
Now, If you see the list of docker images, you can see the created docker image aem-base-image
.
$ sudo docker images REPOSITORY TAG IMAGE ID CREATED SIZE aem-base-image latest 86ca799058b5 56 seconds ago 5.57MB alpine latest a24bb4013296 2 months ago 5.57MB
So, now you can either push it to your docker registry or keep it in local.
Dockerfile for AEM Author
Now, Inside the aem-author
folder, create a Dockerfile
and put the following line of code.
# Use the previously created aem-base-image FROM aem-base-image # Expose AEM author in port 4502 EXPOSE 4502 # Make the container start always in Author mode with Port 4502 ENTRYPOINT ["java", "-jar", "cq-quickstart.jar", "-Dsling.run.modes=author", "-p", "4502"]
IMPORTANT NOTE:
To Run the AEM Instance, You need Minimum 2GB Memory and 5GB Disk Space. However, This tutorial may ask you to create 3 or more containers running parallelly which demand a minimum of 8GB RAM configuration If you are trying in your Personal Computer.
If you want to run the only the Author, You can stop here and build this Dockerfile to create author docker image and run the container out of it. For the same, Do the following steps.
$ docker build -t aem-author .
$ docker run -p 4502:4502 aem-author
Now, Your AEM Author will be running on http://localhost:4502
NOTE:
Learn Docker Port forwarding here (https://docs.docker.com/config/containers/container-networking/)]
If you want to Setup Publisher too, Continue the Steps.
Dockerfile for AEM Publisher.
Creating Docker Image and container for the AEM publisher is as same as AEM Author. So Just do all the steps except exposing the port number 4503 instead of Port 4502. So, the complete code of Dockerfile
is below.
# Use the previously created aem-base-image FROM aem-base-image # Expose AEM Publisher in port 4503 EXPOSE 4503 # Make the container start always in Publisher mode with Port 4503 ENTRYPOINT ["java", "-jar", "cq-quickstart.jar", "-Dsling.run.modes=publisher", "-p", "4503"]
Then, you can build and run using the following command.
$ docker build -t aem-publisher .
$ docker run -p 4503:4503 aem-publisher
Now, If you want to stop with creating Author and Publisher, you can stop here and access you publisher in http://localhost:4503.
Dockerfile for AEM Dispacher
So, Our plan is to run the Dispatcher is with the Apache application server. So, We can start with the Apache configuration file. Hence, we will create a file called httpd.conf
and the following content inside this
ServerRoot "/usr/local/apache2" Listen 80 LoadModule mpm_event_module modules/mod_mpm_event.so LoadModule authn_file_module modules/mod_authn_file.so LoadModule authn_core_module modules/mod_authn_core.so LoadModule authz_host_module modules/mod_authz_host.so LoadModule authz_groupfile_module modules/mod_authz_groupfile.so LoadModule authz_user_module modules/mod_authz_user.so LoadModule authz_core_module modules/mod_authz_core.so LoadModule access_compat_module modules/mod_access_compat.so LoadModule auth_basic_module modules/mod_auth_basic.so LoadModule reqtimeout_module modules/mod_reqtimeout.so LoadModule filter_module modules/mod_filter.so LoadModule mime_module modules/mod_mime.so LoadModule log_config_module modules/mod_log_config.so LoadModule env_module modules/mod_env.so LoadModule headers_module modules/mod_headers.so LoadModule setenvif_module modules/mod_setenvif.so LoadModule version_module modules/mod_version.so LoadModule unixd_module modules/mod_unixd.so LoadModule status_module modules/mod_status.so LoadModule autoindex_module modules/mod_autoindex.so <IfModule !mpm_prefork_module> </IfModule> <IfModule mpm_prefork_module> </IfModule> LoadModule dir_module modules/mod_dir.so LoadModule alias_module modules/mod_alias.so LoadModule dispatcher_module modules/mod_dispatcher.so <IfModule disp_apache2.c> DispatcherConfig conf/dispatcher.any DispatcherLog logs/dispatcher.log DispatcherLogLevel warn DispatcherNoServerHeader Off DispatcherDeclineRoot Off DispatcherUseProcessedURL Off DispatcherPassError 0 </IfModule> <IfModule unixd_module> User daemon Group daemon </IfModule> ServerAdmin you@example.com <Directory /> AllowOverride none Require all denied </Directory> DocumentRoot "/usr/local/apache2/htdocs" <Directory /> <IfModule disp_apache2.c> ModMimeUsePathInfo On SetHandler dispatcher-handler </IfModule> Options FollowSymLinks AllowOverride None </Directory> <Directory "/usr/local/apache2/htdocs"> Options Indexes FollowSymLinks AllowOverride None Require all granted </Directory> <IfModule dir_module> DirectoryIndex index.html </IfModule> <Files ".ht*"> Require all denied </Files> ErrorLog /proc/self/fd/2 LogLevel warn <IfModule log_config_module> LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined LogFormat "%h %l %u %t \"%r\" %>s %b" common <IfModule logio_module> LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" %I %O" combinedio </IfModule> CustomLog /proc/self/fd/1 common </IfModule> <IfModule alias_module> ScriptAlias /cgi-bin/ "/usr/local/apache2/cgi-bin/" </IfModule> <IfModule cgid_module> </IfModule> <Directory "/usr/local/apache2/cgi-bin"> AllowOverride None Options None Require all granted </Directory> <IfModule headers_module> RequestHeader unset Proxy early </IfModule> <IfModule mime_module> TypesConfig conf/mime.types AddType application/x-compress .Z AddType application/x-gzip .gz .tgz </IfModule> <IfModule proxy_html_module> Include conf/extra/proxy-html.conf </IfModule> <IfModule ssl_module> SSLRandomSeed startup builtin SSLRandomSeed connect builtin </IfModule>
Then, add the dispatcher.any
file and copy the following lines of code.
/farms { /website { /clientheaders { "*" } /virtualhosts { "*" } /renders { /rend01 { /hostname "aem-publish" /port "4503" } } /filter { /0001 { /type "deny" /glob "*" } /0041 { /type "allow" /extension '(clientlibs|css|gif|ico|js|png|swf|jpe?g|woff2?)' } /0081 { /type "deny" /selectors '((sys|doc)view|query|[0-9-]+)' /extension '(json|xml)' } /0082 { /type "deny" /path "/content" /selectors '(feed|rss|pages|languages|blueprint|infinity|tidy)' /extension '(json|xml|html)' } } /cache { /docroot "/usr/local/apache2/htdocs" /rules { /0000 { /glob "*" /type "allow" } } /invalidate { /0000 { /glob "*" /type "deny" } /0001 { /glob "*.html" /type "allow" } /0002 { /glob "/etc/segmentation.segment.js" /type "allow" } /0003 { /glob "*/analytics.sitecatalyst.js" /type "allow" } } /allowedClients { } } /statistics { /categories { /html { /glob "*.html" } /others { /glob "*" } } } } }
Now, Create the Dockerfile
in the same directory and add the following lines of code on in.
# Using the apache base Image FROM httpd:2.4 # Setting the current working directory WORKDIR /usr/src/app # Get the dispacher tar file and keepit inside 'dispacher' folder ADD https://www.adobeaemcloud.com/content/companies/public/adobe/dispatcher/dispatcher/_jcr_content/top/download_8/file.res/dispatcher-apache2.4-linux-x86-64-4.2.3.tar.gz ./dispatcher/ # Extract the tar file and move it to Apache Modules folder with name mod_dispacher.so RUN tar -xzvf ./dispatcher/dispatcher-apache2.4-linux-x86-64-4.2.3.tar.gz -C ./dispatcher && \ cp ./dispatcher/dispatcher-apache2.4-4.2.3.so /usr/local/apache2/modules/mod_dispatcher.so # Copy the dispacher.any file in to the Image in the below path COPY dispatcher.any /usr/local/apache2/conf/dispatcher.any # Copy the apache configuration file in the Image and paste it into the apache configuration path as mentioned below COPY httpd.conf /usr/local/apache2/conf/httpd.conf
Now, Run the docker command to create the AEM dispatcher image and Container out of it.
$ docker build -t aem-dispatcher .
$ docker run -p 80:80 aem-dispatcher
So, now you will be able to see the dispatcher in http://localhost.
Running all together with Docker Compose.
Sometimes, Starting and Running the AEM Instances one by one is Pain. So, we can have Docker compose file to create the AEM instance altogether. To do so, create the file called docker-compose.yml
and put the following content inside it.
version: '3' services: author: image: aem-author build: ./aem-author ports: - "4502:4502" publish: image: aem-publish build: ./aem-publish ports: - "4503:4503" dispatcher: image: aem-dispatcher build: ./aem-dispatcher ports: - "80:80" depends_on: - "aem-publish"
Once Added, Just run the following command to create all the Instance together.
$ docker-compose up
Check out this Github to get the entire Source code of this tutorial by clicking here.
Conclusion
Developers are the most affected people in terms of setting up the AEM instance in the local machine with a proper set of repositories and binaries. So, This containerization of AEM instances will help developers to set up the AEM environment in their local, instantly. Also, Enterprise is moving its architectural design from Monolithic to Microservices and in this big digital transformation, this AEM Containerization will be the first step to push forward and hence, learn how to Create AEM instance in Docker with Docker Compose. Stay tuned and subscribe DigitalVarys for more articles and study materials on DevOps, Agile, DevSecOps, and App Development.
Certified Cloud Automation Architect and DevSecOps expert, skilled in optimizing IT workflows with Six Sigma and Value Stream Management. Proficient in both technical and leadership roles, I deliver robust solutions and lead teams to success.
This was very helpful for me. Thanks a lot.
PS. there is an error: for the publish instance Dockerfile, the parameter -Dsling.run.modes is not equal to “publisher” but only to “publish”. Now it works!
what is the actual size of base image after building. because quickstart-crx.jar file itself aroung 500 to 600+MB size. and after building your image showing 5.57mb