Building and Customizing Docker Images with Dockerfile
A Dockerfile is a script comprising commands and parameters used to assemble a Docker image. The creation workflow involves:
- Writing a Dockerfile.
- Using
docker buildto produce an image. - Running the image via
docker run. - Optionally distributing it with
docker pushto a registry such as DockerHub or Alibaba Cloud.
Most offficial images provide minimal environments; custom images are often required to meet specific application needs.
Build Mechanics
Key principles:
- Instructions are uppercase keywords.
- Execution follows a top-down sequence.
- Lines starting with
#are comments. - Each instruction creates a new image layer that is committed.
A Dockerfile encapsulates all steps needed to produce an image artifact. An image represents a portable, runnable package, while a container is a running instance of that image providing services.
Common Instructions
BASE_IMAGE— Specifies the foundational image for subsequent layers.LABEL_AUTH— Identifies the maintainer with name and email.RUN_CMD— Executes commands during the build phase.COPY_SRC— Copies local files into the image filesystem.ADD_SRC— Similar toCOPY_SRCbut supports automatic extraction of archives and remote URLs.SET_WORKDIR— Defines the working directory for following instructions.MOUNT_VOL— Declares volume mount points.EXPOSE_PORT— Documents ports intended for external access.START_CMD— Sets the default command when the container launches; overridden if another command is passed at runtime.ENTRY_EXEC— Defines an executable entrypoint; additional arguments fromdocker runappend to it.ON_BUILD_TRIG— Registers commands triggered when the image serves as a base for another build.DEF_ENV— Sets environment variables during the build.
Example: Custom CentOS Image
Base images in public registries often derive from scratch. This example extends CentOS with extra tooling.
Dockerfile definition (custom_centos.def):
BASE_IMAGE centos
LABEL_AUTH builder@example.com
DEF_ENV USER_PATH /opt/app
SET_WORKDIR $USER_PATH
RUN_CMD yum -y install vim
RUN_CMD yum -y install net-tools
EXPOSE_PORT 80
START_CMD echo $USER_PATH
START_CMD echo "--complete--"
START_CMD /bin/bash
Build the image:
docker build -f custom_centos.def -t custom_centos:v1 .
Run and verify:
docker run --rm custom_centos:v1
Differentiating START_CMD vs ENTRY_EXEC
START_CMD replaces the entire launch command if arguments are supplied, which can cause failures if those arguments are not valid executables.
Example using START_CMD:
BASE_IMAGE centos
START_CMD ["ls", "-a"]
Build as test_start_cmd_img and run:
docker run test_start_cmd_img -l
# Error: "-l" not found because it replaced the original ls command
docker run test_start_cmd_img ls -l
# Works correctly
ENTRY_EXEC appends runtime arguments to the defined entrypoint, preserving its base behavior.
Example using ENTRY_EXEC:
BASE_IMAGE centos
ENTRY_EXEC ["ls", "-a"]
Build as test_entry_exec_img:
docker run test_entry_exec_img
# Lists directory contents
docker run test_entry_exec_img -l
# Executes `ls -a -l`, demonstrating argument concatenation
Example: Tomcat Service Image
Prepare a JDK tarball and Tomcat archive. Use a Dockerfile named Dockerfile so the builder finds it automatically.
Dockerfile:
BASE_IMAGE centos
LABEL_AUTH builder@example.com
COPY_SRC README.md /opt/app/README.md
ADD_SRC jdk-20_linux-x64_bin.tar.gz /opt/app/
ADD_SRC apache-tomcat-10.1.7.tar.gz /opt/app/
RUN_CMD yum -y install vim
DEF_ENV APP_DIR /opt/app
SET_WORKDIR $APP_DIR
DEF_ENV JAVA_PATH /opt/app/jdk-20.0
DEF_ENV CLASSPATH $JAVA_PATH/lib/dt.jar:$JAVA_PATH/lib/tools.jar
DEF_ENV TOMCAT_HOME /opt/app/apache-tomcat-10.1.7
DEF_ENV TOMCAT_BIN $TOMCAT_HOME/bin
DEF_ENV PATH $PATH:$JAVA_PATH/bin:$TOMCAT_BIN
EXPOSE_PORT 8080
START_CMD $TOMCAT_BIN/startup.sh && tail -F $TOMCAT_HOME/logs/catalina.out
Build and launch:
docker build -t my_tomcat_img .
docker run -d -p 8080:8080 my_tomcat_img
Deploy a sample web app by mounting source code into the container's webapps directory. A minimal web.xml descriptor and a JSP page allow verification of successful deployment.
Publishing Images
To distribute on DockerHub:
- Register at https://hub.docker.com/.
- Authenticate locally:
docker login -u your_username
- Tag the image with your namespace:
docker tag local_image_id your_username/your_repo:tag_version
- Push to the registry:
docker push your_username/your_repo:tag_version
Images are uploaded layer by layer. Registries such as Alibaba Cloud also support hosting private or public images.