DockerFile

Sagar Kulkarni
5 min readApr 26, 2024

--

A Dockerfile is a script that contains instructions for building a customized docker image. Each instruction in a Dockerfile creates a new layer in the image, and the final image is composed of all the layers stacked on top of each other.

It includes instructions for installing dependencies, copying files, setting environment variables, and configuring the container.

The Dockerfile supports the following instructions

Different between ADD and COPY

In a Dockerfile, both the ADD and COPY instructions are used to copy files and directories from the host machine into the Docker image, but they have some differences in behavior:

COPY:

  • COPY is the preferred instruction for copying files and directories from the host to the Docker image.
  • It is a straightforward and simple command that copies files or directories from the host machine to the destination in the Docker image.
  • It supports copying local files/directories as well as remote URLs.

ADD

  • ADD has the same functionality as COPY, but with some additional features.
  • In addition to copying files and directories, ADD also supports automatically extracting compressed files (e.g., .tar, .tar.gz, .tar.bz2, .tar.xz, .zip) into the destination directory.
  • However, because of this additional functionality, ADD is more complex and less predictable than COPY.
# Copy a file from the host into the image
COPY ./file.txt /app/
# Add a file from the host into the image and automatically extract it (if it's a compressed file)
ADD ./archive.tar.gz /app/

Different between ENTRYPOINT and CMD

In a Dockerfile, both the ENTRYPOINT and CMD instructions are used to specify the command that will be executed when a container based on the image is run. However, they serve slightly different purposes:

CMD

  • The CMD instruction specifies the default command to run when a container is started from the Docker image.
  • It can be overridden by passing arguments to the docker run command.
  • If a Dockerfile has multiple CMD instructions, only the last one will take effect.

ENTRYPOINT

  • The ENTRYPOINT instruction sets the primary command that will be run when the container is started.
  • It can be combined with CMD to provide default arguments to the primary command.
  • Unlike CMD, the ENTRYPOINT command and its arguments are not overridden by arguments passed to docker run.
  • If a Dockerfile has multiple ENTRYPOINT instructions, only the last one will take effect.
FROM ubuntu:latest
ENTRYPOINT ["echo"]
CMD ["Hello, World!"]

Output will be when you run a container from the image created by the Dockerfile
with ENTRYPOINT and CMD as shown,
the command executed will be echo Hello, World!.
Create entrypoint.sh
#!/bin/sh
echo "Executing entrypoint script..."
echo "$GREETING"
exec "$@"

*********************
***************Dockerfile
# Use an alpine Linux base image
FROM alpine

# Set an environment variable
ENV GREETING "Hello, World!"

# Create a directory for the entrypoint script
WORKDIR /app

# Copy the entrypoint script into the container
COPY entrypoint.sh .

# Make the entrypoint script executable
RUN chmod +x entrypoint.sh

# Specify the entrypoint script
ENTRYPOINT ["./entrypoint.sh"]

# Provide a default command
CMD ["echo", "No command specified. Use 'docker run <image> <command>' to run a command."]

*********************************
docker build -t myalpine .
docker run myalpine
docker run <image_ID> echo 'first'
# Need to create on sample index.html on local machine
# Use the official Nginx image as the base image
FROM nginx

# Set a default value for the HTML file path using ARG
ARG HTML_FILE=index.html

# Copy the HTML file from the local machine to the default Nginx HTML directory
COPY ${HTML_FILE} /usr/share/nginx/html

# Expose port 80 to allow external access to the Nginx server
EXPOSE 80
LABEL maintainer="sagar"

docker run -d -p 8080:80 19f4a347c16d

simple Dockerfile that sets up a container with a basic web server:

vi Dockerfile

# Use a base image, Alpine images are lightweight and include a minimal Linux distribution.
FROM nginx:alpine

# Copy a simple HTML file to serve
COPY index.html /usr/share/nginx/html/

# Expose port 80 to allow external access
EXPOSE 80

*******************
docker build –t <image_name> .
docker build –t learningDocker .

( -t = use for tag and .(dot) Use the current directory to build a Docker image using the Dockerfile located in the current directory)

# to run a container from image
docker run -d -p 8080:80 <Container_ID>
#Access web page - http://<Public_ip>:8080
# push images to Dockerhub 
docker tag your_image_name your_dockerhub_username/your_repository_name
docker tag c9186af07e21 gita/testing

#Log in to Docker Hub #provide username and password
docker login

#Push Your Image to Docker Hub
docker push your_dockerhub_username/your_repository_name
docker push gita/testing

#Edit container and create a new images
docker pull nginx
docker run --name myimage -d -p 8081:80 <image_ID>
docker exec -it <container_id> /bin/bash # in container
apt-get update
apt-get install vim
vim /usr/share/nginx/html/index.html #update some content
docker commit <existing containername> <newimagename>
docker commit myimage mynewimage
docker run --name mynewimage -d -p 8081:80 <image_ID>

Multi-stage Docker file

A multi-stage Dockerfile allows you to create smaller and more efficient Docker images by using multiple build stages. Each stage in the Dockerfile can produce an intermediate image, and the final image contains only the artifacts and dependencies needed for the application to run. This is particularly useful for compiled languages like Go, Java, or C++, where you need build tools and dependencies during the build process but not in the final runtime environment.

Smaller Image Size:

  • Multi-stage builds allow you to separate the build environment from the runtime environment. This means you can include only the necessary dependencies and artifacts in the final image, resulting in smaller image sizes.

Simplified Build Process:

  • Multi-stage builds allow you to encapsulate complex build processes within the Dockerfile, making it easier to maintain and reproduce builds.
git clone https://github.com/kishancs2020/webAppExample.git
cd webAppExample
#try to build code manually using
mvn clean install
#if code is failed with plugin error then update pom.xml as per below


*********************pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.javarticles.webapp</groupId>
<artifactId>webappExample</artifactId>
<packaging>war</packaging>
<version>0.0.1-SNAPSHOT</version>
<name>webappExample Maven Webapp</name>
<url>http://maven.apache.org</url>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
</dependencies>

<build>
<finalName>webappExample</finalName>

<plugins>
<!-- Maven Plugin for Tomcat -->
<plugin>
<groupId>org.codehaus.cargo</groupId>
<artifactId>cargo-maven2-plugin</artifactId>
<version>1.7.6</version>
<configuration>
<container>
<containerId>tomcat9x</containerId>
<type>embedded</type>
</container>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>3.3.1</version>
</plugin>
</plugins>
</build>
</project>

********************************
then try manual build

#add below content into Dockerfile
vim Dockerfile
# Stage 1: Build stage
FROM maven:3.8.4-openjdk-11 AS builder

# Set the working directory inside the container
WORKDIR /app

# Copy the Maven project files
COPY pom.xml ./
COPY src ./src/

# Build the application
RUN mvn clean package

# Stage 2: Final stage
FROM tomcat:latest

# Set the working directory inside the container
WORKDIR /usr/local/tomcat/webapps

# Copy the WAR file from the builder stage to Tomcat's webapps directory
COPY --from=builder /app/target/webappExample.war .

# Expose port 8080
EXPOSE 8080

# Command to run Tomcat when the container starts
CMD ["catalina.sh", "run"]
docker build -t mytest .
docker run -d -p 8080:8080 <image_ID>
docker exec -it <Container_ID>/bin/bash

open browser and acccess URL <IP_address>:8080

--

--