Monday, January 16, 2023

Dockerizing Previously Built WebApp and Pushing it to DockerHub, Then Try it out on an Ec2 Instance

Dockerizing Previously Built WebApp and Pushing it to DockerHub, Then Try it out on an Ec2 Instance 


Requirements

  • A maven project to be dockerized for deployment. In this tutorial, We will be Using the projects we have in class
  • GitHub repository
  • Docker Hub repository
  • Linux machine where your container images will be Tested 


The GitHub workflow

Triggering GitHub actions for our project is as simple as having the correct configuration files in the correct place. Create two new YAML configuration files in the root of your project in the /.github/workflows folder. The first file will be used for the master branch and will run some tests to make sure every push is OK. The second one will be applied to release branches only and will not only test the new version but also create a docker image for it and trigger a redeploy.

The master workflow

name: Master - Testing

on:
push:
branches:
- 'main'

jobs:

artifact:

name: Test master branch - GitHub Packages
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v1
- name: Set up JDK 11
uses: actions/setup-java@v1
with:
java-version: 11.0.4
- name: Maven Package
run: mvn -B clean package -DskipTests
- name: Maven Verify
run: mvn -B clean verify

This simple file is easily readable, it triggers the packaging and verifying phases of the maven build lifecycle in a Java 11 environment. I strongly suggest taking a look at the official documentation on workflows to understand these configuration files work. Now let’s take a look at the one we just created, step by step:

name: Master - Testing

on:
push:
branches:
- 'main'

This workflow will be triggered only when the master branch gets pushed. The name you give your workflow will be visible when checking your actions history on the GitHub page, as well as when you receive email notifications regarding failed tests, so always choose a meaningful one.

jobs:

test:

name: Build
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v1
- name: Set up JDK 11
uses: actions/setup-java@v3
with:
java-version: '11'
- name: Build With Maven
run: mvn -B package --file pom.xml
- name: Run the Maven Verify Phase
run: mvn --batch-mode --update-snapshots verify

We have only one job in this workflow. We define the type of machine in which the job will be running on, you can find a list of the possible values here.

A job always consists of steps. In this case, we set up a java environment with the desired version, and once it is ready we can run whatever maven commands we want. In this case, we package our app and then verify it.

Now that we have the master workflow ready, let’s turn our attention to the star of the show. Our release workflow should build and publish a docker image to our Docker Hub repository


Preparing the server

For this lab, we will use using a simple AWS EC2 Instance running Ubuntu 18.04. 

Install docker

Since our application will be turned into a container image, our server will need to have docker installed to always pull and run the latest version. You can find detailed information on how to install the latest version of docker here, but this simple list of commands will do the trick in most cases:

sudo apt-get update
sudo apt-get remove docker docker-engine docker.io
sudo apt install docker.io
sudo systemctl start docker
sudo systemctl enable docker

You can then check if the installation was successful:

docker --version

Create Dockerfile

In order to turn our application into a container image, we need a configuration file describing the steps necessary to make it. Create the following file under the name of Dockerfile in the root directory of your project.

# Use an official maven runtime as a parent image FROM maven:3.8.3-jdk-11 AS build # Set the working directory to /app WORKDIR /app # Copy the pom.xml and source code to the container COPY pom.xml . COPY webapp/ ./src/ # Build the application RUN mvn clean package # Use an official Nginx image as a parent image for the final stage FROM nginx:1.21.3-alpine # Copy the built WAR file from the previous stage to the Nginx webapps directory COPY webapp /usr/share/nginx/html # Expose port 80 for Nginx EXPOSE 80 # Start the Nginx web server CMD ["nginx", "-g", "daemon off;"]


This will create a workspace containing the pom file and the source code of your maven project. It will then package it and expose the generated jar file as the entry point of your container.



…and back to the workflow

Let’s get back to business. Our release workflow needs to do this things  automatically, and here’s how it is done.

Create your secrets

Store the following variables as secrets in GitHub so that the workflow is able to access your docker account.

  • DOCKER_USER - your username
  • DOCKER_TOKEN - your password




Create your workflow file

Just like we did for the master branch, create another YAML file at “/.github/workflows ” for the master branch.



name: Docker Workflow on: push: branches: [main] jobs: build-and-publish: runs-on: ubuntu-latest steps: - name: Checkout code uses: actions/checkout@v2 - name: Login to Docker Hub uses: docker/login-action@v1 with: username: ${{ secrets.DOCKER_USER }} password: ${{ secrets.DOCKER_TOKEN }} - name: Build and tag Docker image run: | IMAGE_NAME=$(echo "${{ github.repository }}" | tr '[:upper:]' '[:lower:]') IMAGE_TAG="${IMAGE_NAME}:latest" docker build -t "${IMAGE_TAG}" . - name: Push Docker image run: | IMAGE_NAME=$(echo "${{ github.repository }}" | tr '[:upper:]' '[:lower:]') IMAGE_TAG="${IMAGE_NAME}:latest" docker push "${IMAGE_TAG}"


Copy this command to your github work flow and name is whatever you want to name the build. This will build the application with maven, use the Docker file to run a docker image and push it to the docker hub.

After this is done. Go over to your Ec2 Instance and run this command to pull the image from your dockerhub to your instance

                              docker pull (username/reponame:latest)


This will pull down the image from your dockerhub into your Ec2 and then you can run 

                         docker run -d -p 8080:80 (username/reponame:latest)


The -d option, causes Docker to detach the container and have it run in the background. The -p argument establishes a port mapping, which defines that port 80 of the docker container (as specified in dockerfile), should be exposed to port 8080 of our host machine.

To check the details of our running container, type in the following command:

docker ps
view rawgistfile1.txt hosted with ❤ by GitHub

Output:

CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
12d6293d6e19 devopsclass/appname:latest "/docker-entrypoint.…" 16 seconds ago Up 14 seconds 0.0.0.0:8080->80/tcp keen_khayyam
view rawgistfile1.txt hosted with ❤ by GitHub

As per the above output, we see that the container is up and running. If we now head to ipaddress:8080/ we can see the web application is successfully dockerized.

No comments:

Post a Comment

Jenkins Scripted Pipeline - Create Jenkins Pipeline for Automating Builds, Code quality checks, Deployments to Tomcat - How to build, deploy WARs using Jenkins Pipeline - Build pipelines integrate with github, Sonarqube, Slack, JaCoCo, Nexus, Tomcat

  Jenkins Scripted Pipeline - Create Jenkins Pipeline for Automating Builds, Code quality checks, Deployments to Tomcat - How to build, depl...