Читать книгу Kubernetes - Kelsey Hightower - Страница 30

2.3Multistage Image Build

Оглавление

Große Images entstehen sehr oft unabsichtlich, wenn das Kompilieren des Programms Teil der Konstruktion des Anwendungs-Container-Image ist. Es scheint logisch zu sein, den Code als Teil des Image-Builds zu kompilieren, und es ist der einfachste Weg, ein Container-Image aus Ihrem Programm zu erstellen. Das Problem ist aber, dass damit alle unnötigen Entwicklungstools verbleiben, die meist ziemlich groß sind. Sie liegen dann in Ihrem Image herum und verlangsamen Ihre Deployments.

Um dieses Problem zu lösen, hat Docker Multistage Builds entwickelt. Dabei wird aus einem Dockerfile nicht einfach ein einzelnes Image erstellt, sondern mehrere. Jedes Image wird als Stage angesehen und Artefakte können aus den vorigen Stages in den aktuellen Stage kopiert werden.

Machen wir das an einem Beispiel deutlich und schauen uns an, wie wir unsere Beispielanwendung kuard bauen. Das ist eine halbwegs komplizierte Anwendung, zu der ein React.js-Frontend gehört (mit seinem eigenen Build-Prozess), das wiederum in ein Go-Programm eingebunden wird. Das Go-Programm führt einen Backend-API-Server aus, mit dem das React.js-Frontend interagiert.

Ein einfaches Dockerfile könnte so aussehen:

FROM golang:1.11-alpine

# Node uand NPM installieren

RUN apk update && apk upgrade && apk add --no-cache git nodejs bash npm

# Abhängigkeiten für Go-Teil des Build holen

RUN go get -u github.com/jteeuwen/go-bindata/...

RUN go get github.com/tools/godep

WORKDIR /go/src/github.com/kubernetes-up-and-running/kuard

# Sourcen kopieren

COPY . .

# Variablen, die das Build-Skript erwartet

ENV VERBOSE=0

ENV PKG=github.com/kubernetes-up-and-running/kuard

ENV ARCH=amd64

ENV VERSION=test

# Build ausführen. Dieses Skript ist Teil der Sourcen.

RUN build/build.sh

CMD [ "/go/bin/kuard" ]

Dieses Dockerfile erstellt ein Container-Image mit einem statischen Executable, aber es enthält auch alle Go-Entwicklungstools, die Tools zum Bauen des React.js-Frontends und den Quellcode für die Anwendung, was beides von der eigentlichen Anwendung nicht benötigt wird. Das Image wird so – addiert man alle Layer auf – über 500MB groß.

Wie gehen wir nun bei Multistage Builds vor? Schauen wir uns dieses Multistage-Dockerfile an:

# STAGE 1: Build

FROM golang:1.11-alpine AS build

# Node und NPM installieren

RUN apk update && apk upgrade && apk add --no-cache git nodejs bash npm

# Abhängigkeiten für Go-Teil des Builds holen

RUN go get -u github.com/jteeuwen/go-bindata/...

RUN go get github.com/tools/godep

WORKDIR /go/src/github.com/kubernetes-up-and-running/kuard

# Sourcen kopieren

COPY . .

# Variablen, die das Build-Skript erwartet

ENV VERBOSE=0

ENV PKG=github.com/kubernetes-up-and-running/kuard

ENV ARCH=amd64

ENV VERSION=test

# Build ausführen. Dieses Skript ist Teil der Sourcen.

RUN build/build.sh

# STAGE 2: Deployment

FROM alpine

USER nobody:nobody

COPY --from=build /go/bin/kuard /kuard

CMD [ "/kuard" ]

Dieses Dockerfile erzeugt zwei Images. Das erste ist das build-Image mit dem Go-Compiler, der React.js-Toolchain und dem Quellcode für das Programm. Das zweite ist das deployment-Image, das einfach nur das kompilierte Binary enthält. Wenn Sie ein Container-Image über Multistage Builds bauen, können Sie die Größe des eigentlich benötigten Container-Image um Hunderte von Megabytes verkleinern und damit Ihre Deployment-Zeiten drastisch verkürzen, da die Deployment-Latenz im Allgemeinen vor allem von der Netzwerk-Performance abhängt. Das aus diesem Dockerfile erzeugte Image ist nun nur noch ungefähr 20MB groß.

Sie können dieses Image mit den folgenden Befehlen bauen:

$ docker build -t kuard .

$ docker run --rm -p 8080:8080 kuard

Kubernetes

Подняться наверх