Despite being a primarily .NET Core Azure developer, sometimes we take new challenges. I want to write my process of getting an old Java API from no CI/CD into AWS, in hope that helps devs in a similar situation.
I am aware many things I do in this tutorial can be improved, but being a beginner in AWS and coming from a different tech stack means I will take some decisions which the future me will frown upon, but bear with me ;)
Pre-requisites
- Docker
- IDE that supports Java and Springboot. I used IntelliJ IDEA
- JDK (in my case 1.8)
- Springboot
- A database (in my case MySql)
The original setup
This application had no CI/CD pipeline. We could access only an AWS EC2 instance with the running APIs amd the source code.
The original setup is a Java 1.8 solution with 3 projects:
MyJavaSolution/
├── pom.xml
│
├── admin/
│ │── src/
│ │ ├── main/
│ │ │ ├── java/
│ │ │ ├── resources/
│ │ │ └──── application.yml
│ │ └── pom.xml
│
├── customer/
│ │── src/
│ │ ├── main/
│ │ │ ├── java/
│ │ │ ├── resources/
│ │ │ └──── application.yml
│ │ └── pom.xml
│
├── common/
│ │── src/
│ │ ├── main/
│ │ │ ├── java/
│ │ │ ├── resources/
│ │ │ └──── application.yml
│ │ └── pom.xml
Both the APIs rely on the common
project. And both APIs use a Redis cache (which we will include in the docker-compose
)
The objective
The final objective is having a fully functioning CI/CD pipeline and deployment to a cloud provider.
For this series I will use Azure DevOps for the pipeline and AWS as hosting provider.
Part 1 - Dockerizing the project
The first step I did was dockerizing the application. That allows me to reduce the variability between environments and builds, and to access services such as AWS Elastic Beanstalk.
The APIs
Without changing any of the actual solution, I created the following Docker files:
- Customer.Dockerfile
# Use a base image with Java 8 and Maven for building
FROM maven:3.6.3-jdk-8 AS builder
WORKDIR /app/common
COPY ./common/pom.xml ./pom.xml
COPY ./common/src ./src
WORKDIR /app/admin
COPY ./admin/pom.xml ./pom.xml
COPY ./admin/src ./src
WORKDIR /app/customer
COPY ./customer/pom.xml ./pom.xml
COPY ./customer/src ./src
WORKDIR /app
COPY ./pom.xml ./pom.xml
RUN mvn dependency:go-offline
RUN mvn package
FROM openjdk:8-jdk-alpine AS runner
WORKDIR /app
COPY --from=builder app/common/target/common-0.0.1-SNAPSHOT.jar ./common.jar
COPY --from=builder app/customer/target/customer-0.0.1-SNAPSHOT.jar ./customer.jar
EXPOSE 9001
CMD ["java", "-jar", "customer.jar"]
- Admin.Dockerfile
# Use a base image with Java 8 and Maven for building
FROM maven:3.6.3-jdk-8 AS builder
WORKDIR /app/common
COPY ./common/pom.xml ./pom.xml
COPY ./common/src ./src
WORKDIR /app/admin
COPY ./admin/pom.xml ./pom.xml
COPY ./admin/src ./src
WORKDIR /app/customer
COPY ./customer/pom.xml ./pom.xml
COPY ./customer/src ./src
WORKDIR /app
COPY ./pom.xml ./pom.xml
RUN mvn dependency:go-offline
RUN mvn package
FROM openjdk:8-jdk-alpine AS runner
WORKDIR /app
COPY --from=builder app/common/target/common-0.0.1-SNAPSHOT.jar ./common.jar
COPY --from=builder app/admin/target/admin-0.0.1-SNAPSHOT.jar ./admin.jar
EXPOSE 9002
CMD ["java", "-jar", "admin.jar"]
It might seem a bit strange that I included the customer/
folder in the Admin.Dockerfile and vice-versa but the reason was because the solution pom.xml
relied on both to create the .jar
files and it the refactoring of this issue was not part of the scope.
The docker-compose
After creating the dockerfiles and ensuring they work individually, same as if we running it with Springboot. I then created a docker-compose
to ensure me and my team could run it easily:
version: '3'
services:
local-redis:
image: redis:7.2.1
ports:
- "6379:6379"
test-customer:
build:
context: .
dockerfile: Customer.Dockerfile
depends_on:
- local-redis
ports:
- "9001:9001"
test-admin:
build:
context: .
dockerfile: Admin.Dockerfile
depends_on:
- local-redis
ports:
- "9002:9002"
Redis cache
Having now included the Redis cache as a Docker container running alongside the APIs, I just needed to change it's reference in the application.xml
s.
spring:
application:
name: MyJavaSolution
# The redis cache should have the same host name and port as the one defined in the docker-compose.yml
redis:
host: local-redis
port: 6379
timeout: 5000
And with that we have a fully working, OS-agnostic way of building and running this 2 Java 1.8 APIs.
In the next post of this series I will show how to use Azure DevOps pipelines to build and deploy this.
Top comments (0)