Dockerfile Idioms

Distributing smaller containers is something that should be recommended.

Smaller containers, faster to start, faster to distribute, faster to reuse… . For life, speed is an attitude that means your time is being spent more valuably: saving time is always right.

I actually wanted to write about container reduction a few years ago, but Alpine wasn’t taken seriously at the time, and it was hard to use on its own, so we worked more on reducing the final size on a larger ubuntu.

The good news is that the principles that have been used have always been true, and while the world and the ecology have changed, the principles have not.

There are now plenty of articles and questions and answers about container size reduction.

But I’m going to write one anyway. Writers, for their part, feel that they are writing point by point, point by point, point by point, point by point, point by point, point by point, point by point, point by point, point by point. And so on.

However, this time I’m going to write it casually, not to construct the logic.

Checklist

To reduce the final size of the container, the following Checklist should be considered first:

  • Use a smaller base pack

    • For the most part, Alpine is the pick
    • In extreme cases, you can use distroless, but the result is no shell and no access to the container
    • Sometimes you can use BusyBox
  • Select the most appropriate base pack.

    • For the Golang service,alpine:latestIs the best choice
      • But if you need a Golang build operation, thengolang:alpineProbably right
    • These are good choices for the Java family:
      • anapsix/alpine-java
      • frolvlad/alpine-java
      • openjdk
      • These can also be referenced:
        • Github.com/dockerfile/…
        • Hub.docker.com/r/domblack/…
      • Either way, it’s a hell of a piece of shit.
      • Add SpringCloud and it’s 2B.
      • Java is already the wrong choice.
    • For NodeJS, the Alpine version is the best:node:8-alpine
    • Wait, you can’t enumerate them by language.
  • When using the package installation command, remember to clear the indexes and packages downloaded during the package installation process

    I’ll talk more about this later in usage.

  • Remove the memory swap mechanism, remove the swap partition

  • Do not install tools with NCurse dependencies, such as MCS

  • Do not install a debugger or debugger like Vim or curl. Be sure to use nano and WGET instead

  • Adjust the order of commands to combine the same commands so that fewer layers are generated

  • Use memory to remove packages that will be used during the packaging process, reducing the final container size

    This memory function, mainly refers to alpine APK –virtual function; For APT there is an apt-mark tool.

  • For apt use apt install –no-install-recommends -y

  • Use a multiple build process to reduce the size of the final container by excluding packaging and intermediate content

The following are introduced based on VOXR Vdeps -base.

Check out github.com/hedzr/docke…

Various idioms

The idiom of alpine APk

A more typical approach would be this:

RUN fetchDeps=" \ ca-certificates \ bash less nano iputils bind-tools busybox-extras \ wget lsof unzip \ "; \
    apk update \
    && apk --update add ${fetchDeps} \
    && apk info -vv | sort \
    && apk -v cache clean && rm /var/cache/apk/*
# from https://github.com/hedzr/docker-basics/blob/master/alpine-base/Dockerfile
Copy the code

Apk -v cache clean or rm /var/cache/apk/* is an example.

A more rigorous and accurate way to save space than the above example is:

RUN build-deps="gcc
      freetype-dev \
      musl-dev \
      "; \
    apl add --update --no-cache bash less nano unzip && \
    apk add --no-cache --virtual .build-deps ${buildDeps} && \
    pip install --no-cache-dir requests && \
    apk del .build-deps && \
    rm /var/cache/apk/*
Copy the code

Domestic image server acceleration, more comfortable structure:

# Adapted from Hedzr/Docker-Basics/Golang-Builder
RUN fetchDeps=" \ ca-certificates \ "; \
    buildDeps=" tig "; \
       cp /etc/apk/repositories /etc/apk/repositories.bak; \
       echo "http://mirrors.aliyun.com/alpine/v3.10/main/" > /etc/apk/repositories; \
       apk update \
    && apk add --virtual .build-deps ${buildDeps} \
    && apk add ${fetchDeps} \
    && echo
    && echo "Put your building scripts HERE" \
    && apk del .build-deps \
    && rm /var/cache/apk/* \
Copy the code

Debian apt usage

RUN fetchDeps=" \ ca-certificates \ wget nano vim.tiny net-tools iputils-ping lsof \ dnsutils inetutils-telnet locales \ "; \
       TZ=Etc/UTC; LOCALE=en_US.UTF-8; \
       apt update \
    && DEBIAN_FRONTEND=noninteractive apt install -y --no-install-recommends ${fetchDeps} \
    && locale-gen $LOCALE \
    && cat /etc/default/locale && echo "Original TimeZone is: $(locale -a)" && date +'%z' \
    && ln -s /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ | tee /etc/timezone \
    && echo "Current TimeZone updated: $(locale -a)" && date +'%z' \
    # && apt-get purge -y --auto-remove ${fetchDeps} \
    && rm -rf /var/lib/apt/lists/*
The clock time zone part can be removed
# from https://github.com/hedzr/docker-basics/blob/master/ubuntu-mod/Dockerfile
Copy the code

For scenarios that use Python PIP, you can also:

RUN buildDeps="curl python-pip" && \
    apt-get update && \
    apt-get install -y --no-install-recommends $buildDeps && \
    pip install requests && \
    apt-get purge -y --auto-remove $buildDeps && \
    rm -rf /var/lib/apt/lists/*

Copy the code

Build-essential or GCC can be handled similarly:

RUN buildDeps="curl wget build-essentials flex bison make cmake autoconf automake git libtool" && \
    fetchDeps="nano wget curl"
    apt-get update && \
    apt-get install -y --no-install-recommends $fetchDeps && \
    AUTO_ADDED_PACKAGES=`apt-mark showauto` && \
    apt-get install -y --no-install-recommends $buildDeps && \
    mkdir build && cd build && cmake .. && make && make install && \
    apt-get purge -y --auto-remove $buildDeps $AUTO_ADDED_PACKAGES && \
    rm -rf /var/lib/apt/lists/*
Copy the code

Note that we use AUTO_ADDED_PACKAGES, which is a memory feature of Debian’s package management system that can be used to reduce sizing nicely.

Centos yum is idiomatic

Similar to APT, I won’t repeat it

Many times to build

While package-managed memory is perfect for reducing container size, it is not without its drawbacks:

  1. You have to write the entire script for memorizing and erasing memories in a single sentence. If you split it up into multiple sentences, the OS footprint in the container can still be shrunk, but the size of the container may not be reduced.

  2. If you complete your entire container build script in a single RUN directive, the build development process will be painful because the long sequence of instructions cannot be cached in multiple layers, so every minor change will cause the Docker build to completely rebuild your container.

    Reducing the container size should be done after your container build process has been developed.

Ok, the memory function is a bit imperfect, but multiple builds balance all that out nicely.

Taking the containerization of the Golang application as an example, here is an example of a multiple build:

FROM golang:1.7.3 AS builder
WORKDIR /go/src/github.com/alexellis/href-counter/
RUN go get -d -v golang.org/x/net/html  
COPYapp.go .RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o app .

FROM alpine:latest  
RUN apk --no-cache add ca-certificates
WORKDIR /root/
COPY --from=builder /go/src/github.com/alexellis/href-counter/app .
CMD ["./app"]
# from https://github.com/alexellis/href-counter
Copy the code

Well, my own is much more complex, but I can’t show it yet, and the complex version doesn’t help explain the skeleton structure.

The end of the

I have come to an end here.

So much for reducing size and the conventions for writing dockerfiles. It’s okay to release a little more, but it’s probably not just Docker knowledge that’s involved.

The results are still divided into chapters. Oh, my god