Dockerfile Best Practices have appeared in the official documentation, address is Best Practices for Writing Dockerfiles. Writing a list of best practices would be a bit of a sword in front of the gate. Therefore, this article is a translation, understanding, extension and sample supplement to the official documentation

  • Dockerfile best practices
  • Series of articles: Personal server operation and maintenance guide

If this article helps you, please click a star on shfshanyue/op-note for me

Containers should be ephemeral

The container started by an image built from a Dockerfile should be as ephemeral as possible. Ephemeral means it can start and stop quickly

Use.dockerignore to rule out building irrelevant files

The.dockerignore syntax is consistent with the.gitignore syntax. Use it to exclude building irrelevant files and directories, such as node_modules

Use multi-phase builds

Multi-stage builds can effectively reduce image size, especially for compiled languages, and the build process for an application is often as follows

  1. Installing the Compilation tool
  2. Install third-party library dependencies
  3. Build the application

There is a lot of mirror volume redundancy in the first two steps, which can be avoided by using a multi-stage build

This is an example of building a Go application

FROM golang:1.11-alpine AS build

# Install tools required for project
# Run `docker build --no-cache .` to update dependencies
RUN apk add --no-cache git
RUN go get github.com/golang/dep/cmd/dep

# List project dependencies with Gopkg.toml and Gopkg.lock
# These layers are only re-built when Gopkg files are updated
COPY Gopkg.lock Gopkg.toml /go/src/project/
WORKDIR /go/src/project/
# Install library dependencies
RUN dep ensure -vendor-only

# Copy the entire project and build it
# This layer is rebuilt when a file changes in the project directory
COPY . /go/src/project/
RUN go build -o /bin/project

# This results in a single layer image
FROM scratch
COPY --from=build /bin/project /bin/project
ENTRYPOINT ["/bin/project"]
CMD ["--help"]
Copy the code

This is an example of building a front-end application. See how to deploy a front-end application efficiently with Docker

FROM node:10-alpine as builder

ENV PROJECT_ENV production
ENV NODE_ENV production

# http-server can also take advantage of caching without changing
WORKDIR /code

ADD package.json /code
RUN npm install --production

ADD . /code
RUN npm run build

# Select a smaller volume base image
FROM nginx:10-alpine
COPY --from=builder /code/public /usr/share/nginx/html
Copy the code

Avoid installing unnecessary packages

Reduce volume and build time. For example, the front-end application uses NPM install –production to only install packages that the production environment depends on.

A container does one thing

For example, a Web application will contain three parts, Web service, database and cache. Decouple them into multiple containers for horizontal scaling. If you need network communication, you can put them under one network.

For example, IN my personal server, I use Traefik for load balancing and service discovery. All applications and databases are in traefik_default network. For details, see Traefik for load balancing and service discovery

version: '3'

services:
  This image will expose its own 'header' information
  whoami:
    image: containous/whoami
    restart: always
    labels:
      Set Host to whoami.docker. Localhost for domain access
      - "traefik.http.routers.whoami.rule=Host(`whoami.docker.localhost`)"

# Use the existing traefik network
networks:
  default:
    external:
      name: traefik_default
Copy the code

Reduce the number of mirror layers

  • onlyRUN.COPY.ADDCreates the number of layers. Other instructions do not increase the size of the mirror
  • Use multi-phase builds whenever possible

Use the following method to install dependencies

RUN yum install -y node python go
Copy the code

Wrong way to install dependencies, which will increase the number of mirror layers

RUN yum install -y node
RUN yum install -y python
RUN yum install -y go
Copy the code

Sort multiple rows of arguments

Easy readability and careful repacking

RUNapt-get update && apt-get install -y \ bzr \ cvs \ git \ mercurial \ subversionCopy the code

Take full advantage of the build cache

During the construction process of the image, Docker will traverse all instructions in the Dockerfile file and execute them in sequence. For each instruction, Docker looks in the cache to see if a reusable image already exists, or creates a new one

We can skip the cache using docker build –no-cache

  • ADDCOPYThe file will be computedchecksumWhether to change to determine whether to take advantage of the cache
  • RUNJust see if the command string hits the cache, as inRUN apt-get -y updateThere could be problems

For example, a Node application can copy package.json for dependency installation and then add the entire directory to make full use of the cache.

FROM node:10-alpine as builder

WORKDIR /code

ADD package.json /code
# This step will take full advantage of the node_modules cache
RUN npm install --production

ADD . /code

RUN npm run build 
Copy the code

I am Shanyue94, you can add my wechat shanyue94 to communicate with me