Ever spent hours debugging an application only to find it works perfectly on your machine but breaks in production? This is a common frustration for developers.
Imagine a developer builds a web application that runs on Python 3.8 and needs specific libraries. In development, the app works perfectly. However, when deployed to a server running Python 3.9, it breaks due to compatibility issues.
So, what's the solution? Enter Docker.
By using Docker, the developer can package the app with Python 3.8 and all necessary libraries in a container. This container can then be deployed anywhere without worrying about compatibility, ensuring it runs smoothly in any environment.
In other words, it solves the "works on my machine" problem by ensuring that the application runs the same regardless of the environment.
What is Docker?
Docker is a platform that allows developers to package applications and their dependencies into lightweight, portable containers. These containers ensure that an application runs the same way, regardless of the environment—whether it's on a developer's laptop, a testing server, or a production server.
Understanding the Basics
Image credit: Senali
Docker Hub
- Docker Hub is a cloud-based repository where you can store and share Docker images, allowing easy access for developers and teams.
Docker Image
- A Docker image is a lightweight, read-only, and executable software package that includes everything needed to run an application: code, runtime, libraries, environment variables, and configuration files.
- Think of an image as a blueprint for creating Docker containers.
- You can have multiple containers running from the same image.
Docker Container
- A Docker container is a running instance of a Docker image. It uses the image's content to execute an application.
- Containers can be stopped, started, or removed without affecting the Docker image.
In simpler terms:
- Image = Blueprint
- Container = Running Application
Dockerfile
A Dockerfile is a script that contains a series of instructions for building a Docker image. It specifies how the application should be packaged and run inside a container.
FROM openjdk:17-jdk-alpine
ARG JAR_FILE=target/*.jar
COPY ${JAR_FILE} app.jar
ENTRYPOINT ["java", "-jar", "/app.jar"]
In this example:
FROM
specifies the base image to use (a base image contains the necessary software, libraries, and files required to run your application or service). Here,openjdk
is used because we are going to run a Java application.ARG
defines a variable to reference the JAR file. Here, the value assigned is the Spring Boot JAR that is built by Maven, located in the target directory.COPY
copies the JAR file into the container.ENTRYPOINT
defines the command to run the application.
Docker Compose
Docker Compose orchestrates multiple containers (for example, a Spring Boot app and MySQL). It defines how each container will be set up, how they communicate, and their environment configurations. The configuration for Docker Compose is specified in a YAML file, typically named docker-compose.yml
.
version: '3'
services:
mysql-db:
image: mysql:8.0
container_name: mysql-db
environment:
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: spring_docker_demo
ports:
- "3306:3306"
networks:
- spring-network
spring-app:
image: spring-docker-demo:latest
container_name: spring-app
build:
context: .
dockerfile: Dockerfile
depends_on:
- mysql-db
ports:
- "8080:8080"
networks:
- spring-network
environment:
SPRING_DATASOURCE_URL: jdbc:mysql://mysql-db:3306/spring_docker_demo
SPRING_DATASOURCE_USERNAME: root
SPRING_DATASOURCE_PASSWORD: root
networks:
spring-network:
driver: bridge
In this example:
version
specifies the Docker Compose version that we are using.services
defines individual containers. In this case,mysql-db
is the first service and the second one isspring-app
.The
networks
section defines a network namedspring-network
. Both the Spring Boot app and MySQL will be on this network, allowing them to communicate with each other.
Image credit: Dhruv Saksena
Brief Overview of Services
1. MySQL (mysql-db
)
image
: Specifies the Docker image to use for this service. In this case, it's the officialmysql:8.0
image.container_name
: This gives a name to the MySQL container, making it easier to reference.-
environment
: Passes environment variables into the container. Here, we’re setting:-
MYSQL_ROOT_PASSWORD
: The root password for MySQL. -
MYSQL_DATABASE
: The name of the initial database to create.
-
ports
: Maps the MySQL container's internal port (3306) to the host machine’s port (3306), allowing access to the database from the host.networks
: Defines the network (spring-network
) that the MySQL container will join.
2. Spring App (spring-app
)
image
: Specifies the Docker image to use for the Spring Boot app. In this case, it’sspring-docker-demo:latest
, which will be built from the Dockerfile in this project.-
build
:-
context
: The directory where the Dockerfile and source code are located (. means the current directory). -
dockerfile
: The name of the Dockerfile to use (in this case, Dockerfile).
-
depends_on
: Specifies that thespring-app
service depends on themysql-db
service, ensuring that MySQL starts before the Spring Boot app.ports
: Maps the Spring Boot container’s internal port (8080) to the host machine’s port (8080), allowing access to the REST API.networks
: Defines the network that the Spring Boot container will join, allowing it to communicate with the MySQL container.environment
: Sets environment variables for the Spring Boot app. These variables override values inapplication.properties
and allow the Spring Boot app to connect to the MySQL container.
Example: Dockerizing a Spring REST API
To understand it better, let me walk you through an example of dockerizing a Spring REST API.
1. Project Structure:
Before diving into the Docker configurations, ensure your project structure looks something like this:
spring-docker-demo/
├── Dockerfile
├── docker-compose.yml
├── src/
│ └── main/
│ └── java/
│ └── com/
│ └── example/
│ └── demo/
│ └── DemoApplication.java
│ └── UserController.java
└── pom.xml
2. Build the Spring Boot Application:
Make sure your Spring Boot application is set up correctly and build it using Maven:
mvn clean package
This command should create a JAR file in the target
directory, which the Dockerfile will reference.
3. Using the Dockerfile:
The Dockerfile
provided will be used to create an image for your Spring REST API, as discussed earlier.
FROM openjdk:17-jdk-alpine
ARG JAR_FILE=target/*.jar
COPY ${JAR_FILE} app.jar
ENTRYPOINT ["java", "-jar", "/app.jar"]
4. Using Docker Compose:
The docker-compose.yml
file will help you orchestrate the application and its database (MySQL). Here’s the configuration:
version: '3'
services:
mysql-db:
image: mysql:8.0
container_name: mysql-db
environment:
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: spring_docker_demo
ports:
- "3306:3306"
networks:
- spring-network
spring-app:
image: spring-docker-demo:latest
container_name: spring-app
build:
context: .
dockerfile: Dockerfile
depends_on:
- mysql-db
ports:
- "8080:8080"
networks:
- spring-network
environment:
SPRING_DATASOURCE_URL: jdbc:mysql://mysql-db:3306/spring_docker_demo
SPRING_DATASOURCE_USERNAME: root
SPRING_DATASOURCE_PASSWORD: root
networks:
spring-network:
driver: bridge
5. Running the Application:
Navigate to your project folder where the docker-compose.yml
file is located and run the following command:
docker-compose up --build
This command builds the Docker images and starts the containers for your application and the database.
6. Accessing the Application:
Once everything is up and running, you can access your Spring REST API at http://localhost:8080
.
Sharing Your Docker Image
Once you've containerized your Spring REST API, sharing the Docker image with others is straightforward.
1. Build the Docker Image
Build your image with the following command:
docker build -t your-username/spring-docker-demo:latest .
Replace your-username
with your Docker Hub username and .
indicates that the Dockerfile is located in the current directory.
2. Push to Docker Hub
Log in to Docker Hub and push your image:
docker login
docker push your-username/spring-docker-demo:latest
Again, replace your-username
with your actual Docker Hub username.
3. Pulling the Image
Others can easily pull and run your image by executing:
docker pull your-username/spring-docker-demo:latest
docker run -d -p 8080:8080 your-username/spring-docker-demo:latest
-
pull
command downloads your Docker image from Docker Hub to their local machine. -
run
command runs a container from the downloaded image.-
-d
: Runs the container in detached mode (in the background). -
-p 8080:8080
: Maps port 8080 of the host machine to port 8080 of the container, allowing access to the application.
-
Wrap Up
Docker is a game-changer for developers, making deployment seamless and ensuring your app runs consistently across environments. Say goodbye to "it works on my machine" frustrations!
Ready to dive into Docker? Share your experiences or questions below!
Happy Coding! 🐳
Top comments (0)