Dockerfile structure
This article refers to Platform v3.1.0. The current Platform version is v3.2.0.
Overview
A Dockerfile is a sequence of instructions Docker reads top-to-bottom to build an image. Knowing which instruction to use — and when — keeps your images small, reproducible, and cacheable. This article is a reference of every Dockerfile instruction you are likely to need, followed by a Node.js example that ties them together.
Watch this step on YouTube: Dockerfile Structure.
Reference of Dockerfile instructions
FROM
Specifies the base image. Usually the first instruction in the file.
FROM ubuntu:20.04
LABEL
Attaches metadata to the image — author, version, description. Read by tooling and registries.
LABEL maintainer="developer@example.com" \
version="1.0" \
description="A sample Dockerfile for demonstration."
RUN
Executes a command during the build. Each RUN adds a layer to the image, which is good for caching but bad if you create many small layers — combine commands when it helps.
RUN apt-get update && apt-get install -y curl
WORKDIR
Sets the working directory for subsequent RUN, COPY, CMD, and ENTRYPOINT instructions.
WORKDIR /app
COPY and ADD
Both copy files from the build context into the image:
COPY— straightforward copy. Prefer this.ADD— likeCOPY, plus URL fetching and automatic extraction oftar.gzarchives. Use only when you actually need those extras.
COPY . /app
ADD https://example.com/file.tar.gz /app
ENV
Sets environment variables inside the container, readable at runtime by the application.
ENV APP_ENV=production
EXPOSE
Documents the ports the container will listen on. Does not publish them — you still need -p or --publish at runtime, or ports: in Compose.
EXPOSE 8080
CMD
The default command when a container starts. Only one CMD per Dockerfile. If both CMD and ENTRYPOINT are set, CMD provides default arguments to ENTRYPOINT.
CMD ["node", "app.js"]
ENTRYPOINT
Like CMD, but the container always runs this command — extra docker run arguments are appended to it.
ENTRYPOINT ["/bin/bash", "-c"]
VOLUME
Declares a mount point for persistent storage outside the container's writable layer.
VOLUME ["/data"]
ARG
Build-time variable that can be overridden with --build-arg on docker build.
ARG VERSION=1.0
ONBUILD
A deferred instruction — runs when this image is used as a base in another Dockerfile.
ONBUILD RUN apt-get update
HEALTHCHECK
A command Docker runs to check whether the container is healthy.
HEALTHCHECK --interval=30s --timeout=5s CMD curl -f http://localhost/ || exit 1
Practice — Node.js image
Build an image that exposes a tiny Node.js HTTP server, using several of the instructions above.
1. Create the project
mkdir 02_01_docker-practice
cd 02_01_docker-practice
2. Write the application files
app.js:
const http = require('http');
const server = http.createServer((req, res) => {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end('Hello, Dockerfile World!\n');
});
server.listen(8080, () => {
console.log('Server running on http://localhost:8080');
});
package.json:
{
"name": "docker-practice",
"version": "1.0.0",
"main": "app.js",
"dependencies": {
"http": "^0.0.1-security"
}
}
3. Write the Dockerfile
# 1. Base image
FROM node:14
# 2. Metadata
LABEL maintainer="developer@example.com" \
version="1.0" \
description="Node.js application example."
# 3. Working directory
WORKDIR /app
# 4. Application files
COPY package*.json ./
COPY app.js ./
# 5. Dependencies
RUN npm install
# 6. Port
EXPOSE 8080
# 7. Default command
CMD ["node", "app.js"]
4. Build the image
docker build -t node-app:1.0 .
5. Run the container
docker run -p 8080:8080 node-app:1.0
6. Verify
Open http://localhost:8080 in your browser. You should see:
Hello, Dockerfile World!
Summary
Each Dockerfile instruction has a focused role — FROM for the base image, RUN for build-time commands, COPY for files, ENV for runtime environment, CMD / ENTRYPOINT for the default command. Master the small set above and you can build any image you will need for the rest of this tutorial.