Containerizing own applications
When orchestrating your application we rely on images either
available on dockerhub or being able to be built locally.
This tutorial will walk you through the design process of containerizing
a web application, using Wordpress as an example.
General
When containerizing apps for the Green Metrics Tool,
the containers must not shut down after starting them.
So you either must have a daemon / process running inside the container
that keeps the container running or use the command
option in the usage_scenario.yml →
file to start a shell that keeps the container running.
This is because our tool sends the commands to the containers after they have
all been orchestrated and does not support one-off container starts with parameters.
Containerizing
Our architecture looks like the following:
We will now containerize the webserver, database, and client inside separate containers.
The reason for this scoping is that the Green Metrics Tool reports on a container level
and we are interested in showing all these metrics separately.
Technically you could also measure the architecture without the client side, but we
believe that the energy consumption of software includes both sides, as well as the
network usage.
Directory structure
We first prepare the directory structure and create the folder /tmp/demo-app
.
This is where our containerized app will be put into.
mkdir /tmp/demo-app
Here you see a list of the final files and directories that we will end up with:
.
├── ./html
├── usage_scenario.yml
├── Dockerfile-wordpress
├── wordpress.conf
├── compose.yml
└── ...
The compose.yml
is technically not needed, but it makes
initial testing and debugging far easier.
We encourage you to always start with setting up a compose.yml
and then migrating the contents of the file to our usage_scenario.yml
file,
adding the flow
and extra attributes you need on top.
We have found this to be the easiest workflow to containerizing your application.
Webserver
We are basing the container off of wordpress:latest
, which includes an
apache webserver as well as a PHP runtime.
In the container we want the webserver to listen on port 9875, therefore we have
to create a new virtual host.
The virtualhost should have a hostname identical to the container.
We set this container name later, so see it as given for the moment.
Setup your wordpress.conf
file as follows:
Listen 9875
<VirtualHost *:9875>
DocumentRoot /var/www/html
ServerName green-coding-wordpress-apache-data-container
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
<Directory /var/www/html>
Options FollowSymLinks
AllowOverride Limit Options FileInfo
DirectoryIndex index.php
Require all granted
</Directory>
<Directory /var/www/html/wp-content>
Options FollowSymLinks
Require all granted
</Directory>
</VirtualHost>
We will now create the Dockerfile Dockerfile-wordpress
as follows:
# Dockerfile-wordpress
FROM wordpress:latest
EXPOSE 9875
COPY ./html /var/www/html
COPY ./wordpress.conf /etc/apache2/sites-enabled/wordpress.conf
By copying the wordpress.conf
to the apache vhost directory we let webserver know
to deliver the website on port 9875
for host green-coding-wordpress-apache-data-container
We will also dump the filesystem of our existing Wordpress app,
so we can ingest it into the container:
cp -R /PATH/TO/WORDPRESS /tmp/demo-app/html
Database
We assume a MariaDB database and will base off their mariadb basic image.
We pull a dump from our database and copy the wordpress filesystem:
mysqldump -u USERNAME -p DATABASE_NAME > /tmp/demo-app/wordpress-dump.sql
We will now create the Dockerfile Dockerfile-mariadb
as follows:
# Dockerfile-mariadb
FROM mariadb:10.6.4-focal
COPY ./wordpress-dump.sql /docker-entrypoint-initdb.d/wordpress-dump.sql
EXPOSE 3306
As you can see we are copying the dump inside the database container.
Thanks to some magic from the folks at MariaDB this container image will automatically
pick up the dump and import it.
Now for the compose.yml
:
services:
db:
build:
context: .
dockerfile: Dockerfile-mariadb
container_name: gcb-wordpress-mariadb
image: gcb_wordpress_mariadb
restart: always
environment:
- MYSQL_ROOT_PASSWORD=somewordpress
- MYSQL_DATABASE=wordpress
- MYSQL_USER=wordpress
- MYSQL_PASSWORD=wordpress
expose:
- 3306
wordpress:
build:
context: .
dockerfile: Dockerfile-wordpress
container_name: gcb-wordpress-apache
image: gcb_wordpress_apache
expose:
- 9875
ports:
- 9875:9875
restart: always
environment:
- WORDPRESS_DB_HOST=db
- WORDPRESS_DB_USER=wordpress
- WORDPRESS_DB_PASSWORD=wordpress
- WORDPRESS_DB_NAME=wordpress
depends_on:
- db
Puppeteer for client side
In order to simulate a client we need a container running a headless browser.
We choose Puppeteer and provide an example container to build here: https://github.com/green-coding-berlin/example-applications/tree/main/puppeteer-firefox-chrome
You can also download the container directly from docker hub here: Docker Hub
Moving to usage_scenario.yml
The next step, after checking that all containers orchestrate correctly
and can talk to each other as expected, would be to move the compose.yml
to our
usage_scenario.yml
format.
The resulting file would look like this:
# We need an explicit networks part, as we do not auto-generate networks for containers
networks:
example-network:
services:
# There is no container_name directive. All services keys act directly as container names
db-container:
# If you build your file with docker compose in the example above this image name should be the one you have now locally
image: demo_app_db
container_name: demo-app-db
environment:
- MYSQL_ROOT_PASSWORD=somewordpress
- MYSQL_DATABASE=wordpress
- MYSQL_USER=wordpress
- MYSQL_PASSWORD=wordpress
# networks must be explicitly stated in each service
networks:
- example-network
wordpress-container:
image: demo_app_wordpress
container_name: demo-app-wordpress
ports:
- 9875:9875
restart: always
environment:
- WORDPRESS_DB_HOST=db
- WORDPRESS_DB_USER=wordpress
- WORDPRESS_DB_PASSWORD=wordpress
- WORDPRESS_DB_NAME=wordpress
networks:
- example-network
flow:
# Is discussed in "Interacting with applications"
...
Finish
You are now done containerizing your web application.
All you need is a flow to interact from the Puppeteer container with the webserver.
Have a look at the tutorial on: Interacting with application →
and from there create your usage_scenario.yml → file based off your compose.yml
file.
Afterwards run the measurements.
An example how to run a measurement locally can be found here: Measuring locally →
To see all final files in an example of what we introduced here go to the Example app
Help / Debugging
If you run into any errors see the Debugging → page.