Common Dockerfiles

On this page we've collected sample Dockerfiles for various programming languages.

We've also included related links for each language, so you can dig deeper and find out the best practises related to each Dockerfile.

You can find simple examples from the internet, but these Dockerfiles have been deliberately designed to accomplish the following goals:

  • App code should run under a non-root user
  • If dependencies need tot be installed, they are installed in a separate layer to speed up build time
  • If dependencies are not needed after compilation, they are deleted from the resulting image to reduce image size

Dockerfiles are provided for the following languages:

Golang

This Dockerfile utilizes a multi-step build…

  • In the first step (build), dependencies are downloaded and the program compiled.
  • In the second step, the compiled program is copied into a barebones alpine image.

Further reading:

  • golang on Docker Hub
  • tini (entrypoint utility for handling signals)

Dockerfile:

FROM golang:1.17-alpine3.15 as build
WORKDIR /build
# Copy files which are needed for downloading dependencies. Do not
# copy source files, because they should not trigger regeneration
# of this layer.
COPY go.mod go.sum ./
RUN go mod download && go mod verify
# Copy the remaining files
COPY . .
# Build
RUN CGO_ENABLED=0 GOOS=linux go build -a -o app .

FROM alpine:3.15
WORKDIR /app
RUN apk add --no-cache tini
# Create and execute the rest as a non-root user
RUN adduser --disabled-password --ingroup myapp --no-create-home myapp
USER myapp
# Copy the previously built program
COPY --from=build /build/app ./
# Define the start-command
ENTRYPOINT [ "/sbin/tini", "--", "app" ]

NodeJS (npm)

This Dockerfile utilizes a multi-step build…

  • In the first step (build), dev dependencies are installed and npm run build executed to build files from source files.
  • In the second step, only non-dev dependencies are installed, and the previously built files are copied into the image.

Further reading:

  • node on Docker Hub
  • Best Practices from the official node image documentation
  • tini (entrypoint utility for handling signals)

Dockerfile:

# Make sure that .dockerignore includes:
# node_modules

FROM node:16-alpine as build
WORKDIR /build
# Copy files which are needed for installing dependencies. Do not
# copy source files, because they should not trigger regeneration
# of this layer.
# Add tsconfig.json after package-lock.json if you are using TypeScript.
COPY package.json package-lock.json ./
# Install all dependencies
RUN npm install
# Copy the remaining files
COPY . .
# Build
RUN npm run build

FROM node:16-alpine
WORKDIR /app
USER node
ENV NODE_ENV production
RUN apk add --no-cache tini
# Again, copy files which are needed for installing dependencies.
# Explanation above.
COPY package.json package-lock.json ./
# Install non-dev dependencies
RUN npm install
# Copy the previously built files
COPY --from=build /build/dist ./dist
# Define the start-command
ENTRYPOINT [ "/sbin/tini", "--", "npm", "start" ]

NodeJS (yarn)

This Dockerfile is otherwise identical to the npm version, but npm commands have been substituted with yarn commands.

See the NodeJS (npm) section for related notes. They also apply to the structure of this Dockerfile.

Dockerfile:

# Make sure that .dockerignore includes:
# node_modules

FROM node:16-alpine as build
WORKDIR /build
# Copy files which are needed for installing dependencies. Do not
# copy source files, because they should not trigger regeneration
# of this layer.
# Add tsconfig.json after yarn.lock if you are using TypeScript.
COPY package.json yarn.lock ./
# Install all dependencies
RUN yarn
# Copy the remaining files
COPY . .
# Build
RUN yarn build

FROM node:16-alpine
WORKDIR /app
USER node
ENV NODE_ENV production
RUN apk add --no-cache tini
# Again, copy files which are needed for installing dependencies.
# Explanation above.
COPY package.json yarn.lock ./
# Install non-dev dependencies
RUN yarn --production
# Copy the previously built files
COPY --from=build /build/dist ./dist
# Define the start-command
ENTRYPOINT [ "/sbin/tini", "--", "yarn", "start" ]

PHP

This Dockerfile runs a single PHP file.

Further reading:

  • php on Docker Hub
  • tini (entrypoint utility for handling signals)

Dockerfile:

FROM php:7.4-cli
WORKDIR /app
# Switch to default production config
RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini"
# Create and execute the rest as a non-root user
RUN adduser --disabled-password --ingroup myapp --no-create-home myapp
USER myapp
# Copy project files
COPY . .
# Define the start-command
ENTRYPOINT [ "/sbin/tini", "--", "php", "start.php" ]

PHP (Apache)

This Dockerfile serves PHP files via an Apache server.

Further reading:

  • php on Docker Hub
  • tini (entrypoint utility for handling signals)

Dockerfile:

FROM php:7.4-apache
# Switch to default production config
RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini"
# Create and execute the rest as a non-root user
RUN adduser --disabled-password --ingroup myapp --no-create-home myapp
USER myapp
# Copy project files to Apache folder
COPY . /var/www/html/

PHP (Composer)

This Dockerfile installs Composer dependencies separately from app code, to reduce the need of regenerating layers.

Further reading:

  • php on Docker Hub
  • tini (entrypoint utility for handling signals)

Dockerfile:

# Make sure that .dockerignore includes:
# vendor

FROM php:7.4-cli
WORKDIR /app
# Switch to default production config
RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini"
# Create and execute the rest as a non-root user
RUN adduser --disabled-password --ingroup myapp --no-create-home myapp
USER myapp
# Install composer
COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer
# Copy files which are needed for installing dependencies. Do not
# copy source files, because they should not trigger regeneration
# of this layer.
COPY composer.json composer-lock.json ./
# Install all dependencies
RUN composer update
# Copy the remaining files
COPY . .
# Define the start-command
ENTRYPOINT [ "/sbin/tini", "--", "php", "artisan", "serve" ]

Python

This Dockerfile installs pip dependencies separately from app code, to reduce the need of regenerating layers.

Further reading:

  • python on Docker Hub
  • tini (entrypoint utility for handling signals)

Dockerfile:

# Can be changed to python:2-alpine, no other changes needed
FROM python:3-alpine
WORKDIR /app
# Create and execute the rest as a non-root user
RUN adduser --disabled-password --ingroup myapp --no-create-home myapp
USER myapp
# Copy files which are needed for installing dependencies. Do not
# copy source files, because they should not trigger regeneration
# of this layer.
COPY requirements.txt ./
# Install all dependencies
RUN pip install --no-cache-dir -r requirements.txt
# Copy the remaining files
COPY . .
# Define the start-command
ENTRYPOINT [ "/sbin/tini", "--", "python", "run.py" ]

Ruby

This Dockerfile installs dependencies separately from app code, to reduce the need of regenerating layers.

Further reading:

  • ruby on Docker Hub
  • tini (entrypoint utility for handling signals)

Dockerfile:

FROM ruby:3
WORKDIR /app
# Create and execute the rest as a non-root user
RUN adduser --disabled-password --ingroup myapp --no-create-home myapp
USER myapp
# Configure to throw if Gemfile does not match Gemfile.lock
RUN bundle config --global frozen 1
# Copy files which are needed for installing dependencies. Do not
# copy source files, because they should not trigger regeneration
# of this layer.
COPY Gemfile Gemfile.lock ./
# Install all dependencies
RUN bundle install
# Copy the remaining files
COPY . .
# Define the start-command
ENTRYPOINT [ "/sbin/tini", "--", "ruby", "run.rb" ]

Rust

This Dockerfile utilizes a multi-step build…

  • In the first step (build), dependencies are downloaded and the program compiled.
  • In the second step, the compiled program is copied into a barebones debian image.

Further reading:

  • rust on Docker Hub
  • tini (entrypoint utility for handling signals)

Dockerfile:

FROM rust:1.40 as build
WORKDIR /build
# Copy project files
COPY . .
# Build
RUN cargo install --path .

FROM debian:buster-slim
WORKDIR /app
RUN apt-get update && \
    apt-get install -y extra-runtime-dependencies tini && \
    rm -rf /var/lib/apt/lists/*
# Create and execute the rest as a non-root user
RUN adduser --disabled-password --ingroup myapp --no-create-home myapp
USER myapp
# Copy the previously built program
COPY --from=build /usr/local/cargo/bin/myapp /usr/local/bin/myapp
# Define the start-command
ENTRYPOINT [ "/sbin/tini", "--", "myapp" ]

Comments?

Did you find an inaccuracy? Should we add a specific language? We’ve compiled this list in good faith, but we could always have made a mistake or could use an improvement. Feedback is appreciated!

Let us know at hi@shipmight.com!

Shipmight

Home

Blog

Docs

Newsletter

Join the mailing list to get notified when a new version or new content on the website is released. Max 1 email per week.

Don’t reinvent the shipCopyright © Fine Productions Oy/Ltd