Containerizing a Web Application with Docker

Containerizing a Web Application with Docker

Introduction:

Hello! Recently, I worked on a project to make handling applications easier using something called containerization. I want to share the journey and explain the process in simple terms. Let's dive in!

Why Containerization?

Imagine this: You have a cool application, but it's costing a lot, and making changes feels risky. Sound familiar? That's where containerization helps.

Containers are like straightforward boxes for your applications. They don't need a whole operating system, so they use fewer resources. And guess what? That means saving money!

Real Talk and Numbers:

Before we go further, here are some stats. Turns out, lots of companies are already using containerization. About 50% of them have put half of their applications in these containers. And get this – 29% are using them for real production. It's like the popular trend in the tech world.

Tools I Used:

Now, let's talk tools. I used Docker, the superhero of containerization. Alongside Docker, I had Docker Compose and Docker Hub as helpful sidekicks, making my project much easier.

Containerizing VProfile Project:

The Web Container:

Starting with the web component, I used Nginx as the foundation. The Dockerfile removes the default configuration and adds my custom one, setting the stage for a seamless web experience. This container acts as the face of the project, exposing the web app to the world.

FROM nginx
LABEL "Project"="Vprofile"
LABEL "Author"="Abdul"

RUN rm -rf /etc/nginx/conf.d/default.conf

COPY nginvproapp.conf /etc/nginx/conf.d/vproapp.conf

The Database Container:

Moving on to the database container, which runs on MySQL. The Dockerfile takes care of setting up the environment, including defining the root password and creating the 'accounts' database. To start things off with some data, I included an SQL backup during the initialization process.

FROM mysql:8.0.33
LABEL "Project"="Vprofile"
LABEL "Author"="Abdul"

ENV MYSQL_ROOT_PASSWORD="vprodbpass"
ENV MYSQL_DATABASE="accounts"

ADD db_backup.sql docker-entrypoint-initdb.d/db_backup.sql

The App Container:

Now, let's talk about the app container. I approached this in two steps. First, I used an OpenJDK image to build the application. I installed Maven and Git, cloned the VProfile project, and got everything ready. After that, I moved the war file to a Tomcat image, creating a streamlined container all set to serve the web app.

FROM openjdk:11 AS BUILD_IMAGE
RUN apt update && apt install maven -y 
RUN git clone https://github.com/devopshydclub/vprofile-project.git
RUN cd vprofile-project && git checkout docker && mvn install 

FROM tomcat:9-jre11
LABEL "Project"="Vprofile"
LABEL "Author"="Abdul"
RUN rm -rf /usr/local/tomcat/webapps/*
COPY --from=BUILD_IMAGE vprofile-project/target/vprofile-v2.war /usr/local/tomcat/webapps/ROOT.war

EXPOSE 8080
CMD ["catalina.sh","run"]

Docker Compose:

Now, let's connect all the dots with Docker Compose. This tool orchestrates containers for the database, caching, web, and app components, making deployment a breeze. I also set up volumes for persistent data and specified ports for easy access. It's like the project conductor ensuring everything plays in harmony.

version: "3.8"
services:
  vprodb:
    build:
      context: ./Docker-files/db
    image: immortalabdul/vprofile-db
    container_name: vprodb
    ports:
      - "3306:3306"
    volumes:
      - vprodbdata:/var/lib/mysql
    environment:
      - MYSQL_ROOT_PASSWORD=vprodbpass

  vprocache01:
    image: memcached
    ports:
      - "11211:11211"

  vpromq01:
    image: rabbitmq
    ports:
      - "15672:15672"
    environment:
      - RABBITMQ_DEFAULT_USER=guest
      - RABBITMQ_DEFAULT_PASS=guest

  vproapp:
    build:
      context: ./Docker-files/app
    image: immortalabdul/vprofile-app
    container_name: vproapp
    ports:
      - "8080:8080"
    volumes:
      - vproappdata:/usr/local/tomcat/webapps

  vproweb:
    build:
      context: ./Docker-files/web
    image: immortalabdul/vprofile-web
    container_name: vproweb
    ports:
      - "80:80"
    volumes:
      - vproappdata:/usr/local/tomcat/webapps

volumes:
  vprodbdata: {}
  vproappdata: {}

Once the Dockerfiles and Docker Compose configuration were in place, the practical implementation phase began. To ensure a controlled environment for testing, I opted for a Virtual Machine (VM) using Vagrant, selecting Ubuntu as the OS. Inside this VM, the Docker Engine needed to be installed to facilitate the containerization process.

Setting Up the Virtual Machine:

  1. Installing Docker Engine:

    • The first step was updating the system and installing Docker on the Ubuntu VM.
sudo apt update
sudo apt install docker.io
  1. Building Docker Images:

    • With Docker Engine ready, the next move was to use the docker-compose build command in the directory housing the docker-compose.yaml file. This command initiated the creation of Docker images based on the defined configurations.
docker-compose build
  1. Checking Created Containers:

    • A quick verification of the created containers was done using the docker ps command.
docker ps

docker images and ps

  1. Bringing Up Containers:

    • The containers were brought to life by executing docker-compose up -d, allowing each one to assume its designated role within the setup.
docker-compose up -d
  1. Accessing the App:

    • To ensure everything was working as expected, I determined the VM's IP address using ip addr show and accessed the application through the browser.

Pushing to Docker Hub:

  1. Pushing Images to Docker Hub:

    • With the containers successfully running, it was time to share them on Docker Hub. Logging into Docker Hub using docker login and pushing the images to the public repository ensured accessibility for others.
docker login
docker push immortalabdul/vprofile-app
docker push immortalabdul/vprofile-db
docker push immortalabdul/vprofile-web
  • The public Docker Hub repository is accessible here.

Cleanup:

  1. Bringing Down Containers:

    • Once testing was complete, the containers were gracefully stopped using docker-compose down.
docker-compose down

  1. Cleaning Up Docker System:

    • For a pristine environment, the docker system prune -a command was executed to remove any non-running containers.
docker system prune -a

Wrapping Up:

In conclusion, from setting up the VM to pushing containers and performing post-testing cleanup, every step was executed with precision. The complete project details are available on GitHub here. For a comprehensive experience, be sure to switch to the 'containers' branch.

Did you find this article valuable?

Support DevOps 0 to 1 by becoming a sponsor. Any amount is appreciated!