Kitabı oku: «K8s Applications mit MicroK8S auf Raspberry PI», sayfa 5

Yazı tipi:

Kleinster möglicher statischer Webserver

Inspiration:

https://chemidy.medium.com/create-the-smallest-and-secured-golang-docker-image-based-on-scratch-4752223b7324

https://github.com/PierreZ/goStatic

https://hub.docker.com/r/tobilg/mini-webserver

https://devopsdirective.com/posts/2021/04/tiny-container-image/

https://lipanski.com/posts/smallest-docker-image-static-website

https://ashishb.net/tech/docker-101-a-basic-web-server-displaying-hello-world/

Um einen Fallback Backend-Server zu haben (für den Fall dass im Service irgendwo was schief geht) bauen wir uns einen "Under Construction" Service. Dieser Service ist statisch, zeigt ein wenig Information und dient als defaultBackend für alle anderen Services.

Die Projektstruktur ist wie folgt:

.

├── default_ingress.yaml

├── default_latest_container.tar.gz

├── default_svc.yaml

├── default.yaml

├── dockerfile

├── do.sh

├── env.sh

├── html

│ ├── android-chrome-192x192.png

│ ├── android-chrome-512x512.png

│ ├── apple-touch-icon.png

│ ├── favicon-16x16.png

│ ├── favicon-32x32.png

│ ├── favicon.ico

│ ├── healthz

│ ├── index.html

│ ├── site.webmanifest

│ ├── Slainte.jpeg

│ └── website_under_construction.jpg

├── src

│ └── main.go

└── test

└── test.sh

Das env.sh legt die Variablen fest.

#!/bin/bash

############################################################################################

# $Date: 2021-11-27 00:08:17 +0100 (Sa, 27. Nov 2021) $

# $Revision: 1370 $

# $Author: alfred $

# $HeadURL: https://monitoring.slainte.at/svn/slainte/trunk/k8s/k8s_app/default/env.sh $

# $Id: env.sh 1370 2021-11-26 23:08:17Z alfred $

#

# Bauen und deployen

#

############################################################################################

#shopt -o -s errexit #—Terminates the shell script if a command returns an error code.

shopt -o -s xtrace #—Displays each command before it’s executed.

shopt -o -s nounset #-No Variables without definition

export image="default"

export namespace="default slainte"

#Namespacespezifisch

. ../namespace/${namespace}_env.sh

#

Dieser Webserver (es ist das Default-Backend für alle) wird sowohl in den Namespace "default" als auch in den Namespace "slainte" ausgerollt.

ARG BUILDER_IMAGE=golang:alpine

############################

# STEP 1 build executable binary

############################

FROM ${BUILDER_IMAGE} as builder

# timezone support

ENV TZ=Europe/Vienna

# Timezone support

RUN apk add git \

tzdata && \

cp /usr/share/zoneinfo/${TZ} /etc/localtime &&\

echo $TZ > /etc/timezone

# Create appuser

ENV USER=appuser

ENV UID=10001

# See https://stackoverflow.com/a/55757473/12429735

RUN adduser \

--disabled-password \

--gecos "" \

--home "/nonexistent" \

--shell "/sbin/nologin" \

--no-create-home \

--uid "${UID}" \

"${USER}"

WORKDIR $GOPATH/src

# Copy the code

COPY src/ /go/src/

# Fetch dependencies.

RUN go mod init main

RUN go mod tidy

RUN go get -d -v

# Build the binary

RUN CGO_ENABLED=0 go build \

-ldflags='-w -s -extldflags "-static"' -a \

-o /go/bin/main .

############################

# STEP 2 build a small image

############################

FROM scratch

#FROM alpine:latest -> Zum testen ist das ganz praktisch

LABEL maintainer="microk8s.raspberry@slainte.at"

LABEL Description="Kleiner statischer Webserver"

# Import from builder.

#COPY --from=builder /usr/share/zoneinfo /usr/share/zoneinfo

COPY --from=builder /etc/localtime /etc/localtime

COPY --from=builder /etc/timezone /etc/timezone

COPY --from=builder /etc/passwd /etc/passwd

COPY --from=builder /etc/group /etc/group

# Copy html

COPY --chown=appuser:appuser html/ /html/

# Copy our static executable

COPY --from=builder /go/bin/main /main

EXPOSE 8080

# Use an unprivileged user.

USER appuser:appuser

WORKDIR /html/

# Run the hello binary.

ENTRYPOINT ["/main"]

Das dockerfile ist ein jetzt ein Multistage-Build. Im ersten Schritt wird das go-Programm compiliert und ein paar notwendig Programme installiert. Im zweiten Schritt werden die notwendigen Dateien aus der Stufe 1 sowie die Web-Dateien kopiert.

#!/bin/bash

############################################################################################

# $Date: 2021-11-26 23:02:04 +0100 (Fr, 26. Nov 2021) $

# $Revision: 1361 $

# $Author: alfred $

# $HeadURL: https://monitoring.slainte.at/svn/slainte/trunk/k8s/k8s_app/default/do.sh $

# $Id: do.sh 1361 2021-11-26 22:02:04Z alfred $

#

# Bauen und deployen

#

############################################################################################

#shopt -o -s errexit #—Terminates the shell script if a command returns an error code.

shopt -o -s xtrace #—Displays each command before it’s executed.

shopt -o -s nounset #-No Variables without definition

svn update

source env.sh

docker build --no-cache --force-rm . -t ${image}:latest

#docker save ${image}:latest | gzip > ${image}_latest.tar.gz

docker kill $(docker ps | grep -i ${image}:latest | awk '{print $1 }')

docker container rm -f $(docker container ls -a | grep -i ${image}_latest | awk '{print $1 }')

docker run -d --name ${image}_latest -p 8080:8080 ${image}:latest

sleep 10

docker ps

docker export $(docker ps | grep -i ${image}:latest | awk '{print $1 }') | gzip > ${image}_latest_container.tar.gz

echo "docker exec -u 0 -it ${image}_latest /bin/sh"

#docker exec -u 0 -it ${image}_latest /bin/sh

#docker kill $(docker ps | grep -i ${image}:latest | awk '{print $1 }')

#docker container rm $(docker container ls -a | awk '{print $1 }')

#docker run -it --name ${image}_latest ${image}:latest /bin/bash

#

Das do.sh dient zum lokalen Testen mit docker. Hier wird ein Image erzeugt, und man kann testen, wie sich der Container verhält. Dieses Skript exportier den fertigen Container auch in ein tar-File. Das ist recht praktisch um in Ruhe nachzusehen, welche Dateinen wo gelandet sind.

---

apiVersion: apps/v1

kind: Deployment

metadata:

name: ${image}-depl

namespace: ${namespace}

spec:

replicas: 1

selector:

matchLabels:

app: ${image}-app

minReadySeconds: 60

strategy:

type: Recreate

template:

metadata:

labels:

app: ${image}-app

annotations:

sidecar.istio.io/inject: "false"

spec:

# Verhalten, wenn mehrere Replicas notwendig sind

affinity:

podAntiAffinity:

requiredDuringSchedulingIgnoredDuringExecution:

- labelSelector:

matchExpressions:

- key: app

operator: In

values:

- ${image}-app

topologyKey: "kubernetes.io/hostname"

# Container Spec

containers:

- name: ${image}

image: ${docker_registry}/${image}:${tag}

imagePullPolicy: Always

env:

- name: image

value: "${image}"

- name: tag

value: "${tag}"

ports:

- containerPort: 8080

name: http

# check for lifetime liveness, restarts if dead

livenessProbe:

httpGet:

path: /healthz

port: 8080

scheme: HTTP

initialDelaySeconds: 60

timeoutSeconds: 5

periodSeconds: 30

successThreshold: 1

failureThreshold: 3

# check for initial readiness

readinessProbe:

httpGet:

path: /healthz

port: 8080

scheme: HTTP

initialDelaySeconds: 60

timeoutSeconds: 5

periodSeconds: 30

successThreshold: 1

failureThreshold: 3

securityContext:

capabilities:

drop:

- all

add:

- NET_BIND_SERVICE

allowPrivilegeEscalation: false

# Verhalten, beim Beenden

terminationGracePeriodSeconds: 60

restartPolicy: Always

dnsPolicy: ClusterFirst

---

Das default-yaml beschreibt die Verhaltensweise des Services. Nach 60 Sekunden wird geprüft ob der Service bereit und gesund ist (ist in diesem Fall dieselbe Prüfung). Diese Prüfung geschieht alle 30 Sekunden. Weiters werden die Rechte richtig gesetzt. Einerseits hat der User im Container keine Rechte (ist unprivilegiert), so wird nur auch der Pod selbst Rechtemäßig richtig gesetzt (darf nichts, ausser eine Port binden).

---

# Yaml für ${image}:${tag}

---

apiVersion: v1

kind: Service

metadata:

name: ${image}-svc

namespace: ${namespace}

labels:

app: ${image}-app

spec:

ports:

- port: 80

name: http

targetPort: 8080

protocol: TCP

selector:

app: ${image}-app

type: ClusterIP

---

Hier wird der Service beschrieben. Der Service ist nach aussen auf Port 80 erreichbar. Der Pod läuft aber auf Port 8080.

---

# Yaml für ${image}:${tag}

apiVersion: networking.k8s.io/v1

kind: Ingress

metadata:

name: ${image}-routes

namespace: ${namespace}

annotations:

kubernetes.io/ingress.class: public

cert-manager.io/cluster-issuer: "${cluster_issuer}"

# https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/annotations/

# nginx.ingress.kubernetes.io/rewrite-target: /$2

nginx.ingress.kubernetes.io/ssl-redirect: "true"

nginx.ingress.kubernetes.io/ssl-passthrough: "true"

nginx.ingress.kubernetes.io/force-ssl-redirect: "true"

nginx.ingress.kubernetes.io/ssl-temporary-redirect: "false"

nginx.ingress.kubernetes.io/secure-backends: "true"

nginx.ingress.kubernetes.io/ssl-proxy-headers: "X-Forwarded-Proto: https"

nginx.ingress.kubernetes.io/proxy-body-size: 0m

nginx.ingress.kubernetes.io/proxy-buffering: "off"

# https://github.com/nginxinc/kubernetes-ingress/tree/v1.12.0/examples/ssl-services

# nginx.ingress.kubernetes.io/ssl-services: "default-svc"

# nginx.ingress.kubernetes.io/backend-protocol: "HTTPS"

spec:

tls:

- hosts:

- ${host}

secretName: ${secretName}

rules:

- host: ${host}

http:

paths: # https://github.com/google/re2/wiki/Syntax, https://www.regular-expressions.info/refcapture.html

- path: /${image}(/|$)(.*)

pathType: Prefix

backend:

service:

name: ${image}-svc

port:

number: 80

defaultBackend:

service:

name: ${image}-svc

port:

number: 80

---

Hier wird der Ingress beschrieben. Bis zum Ingress-Controller muß der Verkehr gesichert über https gesichert sein. Der Service dahinter kann aber kein https, somit wird das Protokoll am Controller aufgebrochen, und dahinter wird über http kommuniziert. Rewrite führt in der Regel zu Verwirrungen. Siehe auch die Erklärungen in https://kubernetes.github.io/ingress-nginx/examples/rewrite/

Starting in Version 0.22.0, ingress definitions using the annotation nginx.ingress.kubernetes.io/rewrite-target are not backwards compatible with previous versions. In Version 0.22.0 and beyond, any substrings within the request URI that need to be passed to the rewritten path must explicitly be defined in a capture group.

Und nun kommt der Haupteil. Das Go-Programm um eine einfache Webserver-Funktionalität abzubilden.

// Ausgabe eines einfachen HTML-Files

// Inspiration https://golang.org/doc/articles/wiki/

package main

import (

"fmt"

"strings"

"io/ioutil"

"log"

"net/http"

"net/http/httputil"

)

type Page struct {

Title string

Body []byte

}

func loadPage(title string) (*Page, error) {

var xhtml []byte

var err error

title = strings.Replace(title, "default/", "", -1)

title = strings.Replace(title, "default", "", -1)

xhtml, err = ioutil.ReadFile(title)

if err != nil { // wenn was schiefgeht (warum auch immer) wird das index.html gezeigt

log.Println("GET /index.html: " + title )

xhtml, err = ioutil.ReadFile("index.html")

}

//log.Println("RESULT " + title )

return &Page{Title: title, Body: []byte(xhtml)}, err

}

func viewHandler(w http.ResponseWriter, r *http.Request) {

title := r.URL.Path[len("/"):]

//log.Println("URL " + title + "\n")

p, _ := loadPage(title)

fmt.Fprintf(w, "%s", p.Body)

}

func logRequest(handler http.Handler) http.Handler {

return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {

x, err := httputil.DumpRequest(r, true)

if err != nil {

http.Error(w, fmt.Sprint(err), http.StatusInternalServerError)

return

}

title := r.URL.Path[len("/"):]

title = strings.Replace(title, "default/", "", -1)

title = strings.Replace(title, "default", "", -1)

if title != "healthz" { // Nicht das Log zumüllen.

log.Println(fmt.Sprintf("%q", x))

}

handler.ServeHTTP(w, r)

})

}

func main() {

log.Println("Main Started")

http.HandleFunc("/", viewHandler)

log.Fatal(http.ListenAndServe(":8080", logRequest(http.DefaultServeMux)))

log.Println("Main End")

}

Die Source selbst ist ein einfaches go-Programm. Das Programm zeigt nur die angegebene Datei her. Mehr nicht. Der Aufruf von "/healthz" passiert alle 30 Sekunden. Um das Log nicht vollzumüllen wird dieser Aufruf nicht im Log ausgegeben (alles andere schon).

Wenn ein Aufruf nicht funktioniert (z.b. es gibt die gesuchte Datei nicht), dann wird das "/index.html" hergezeigt. Durch die verschiedenartigen Aufrufe des nginx-Controllers (mal mit dem fixen Teil des Ingress, mal ohne, jenachdem ob man das von aussen aufruft oder ob das ein Nachladen aus dem html ist, zb. das favicon) wird hier hardcoded der default und default/ weggelöscht. Damit ist das Programm nicht mehr wirklich portabel. Vielleicht gibt es in der Zukunft eine bessere Lösung.

Das index.html sieh aus wie folgt:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"

"http://www.w3.org/TR/html4/transitional.dtd">

<html>

<head>

<meta HTTP-EQUIV=CONTENT-TYPE CONTENT="text/html; charset=utf-8">

<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png">

<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png">

<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png">

<link rel="manifest" href="/site.webmanifest">

<title>K8's Default-Seite</title>

</head>

<body>

<center>

<img src="http://litres.ru/website_under_construction.jpg" alt="">

<p><br/><p>

<p>Bitte verständigen Sie den Siteadmin<br/><p>

</center>

</body>

</html>

Es wird nicht gecached (soweit die Theorie, die Browser und alle Schichten dazwischen halten sich nicht immer daran). Es wird das "website_under_construction.jpg" Bild hergezeigt und ein statischer Text ausgegeben.

Nun testen wir das Ganze am lokalen Rechner.

alfred@bureau:~/svn/trunk/k8s/k8s_app/default$ ./do.sh

+ shopt -o -s nounset

+ svn update

Aktualisiere ».«:

Revision 1377.

+ source env.sh

++ shopt -o -s xtrace

++ shopt -o -s nounset

++ export image=default

++ image=default

++ export 'namespace=default slainte'

++ namespace='default slainte'

++ . ../namespace/default slainte_env.sh

env.sh: Zeile 18: ../namespace/default: Datei oder Verzeichnis nicht gefunden

+ docker build --no-cache --force-rm . -t default:latest

Sending build context to Docker daemon 3.174MB

Step 1/27 : ARG BUILDER_IMAGE=golang:alpine

Step 2/27 : FROM ${BUILDER_IMAGE} as builder

---> 3a38ce03c951

Step 3/27 : ENV TZ=Europe/Vienna

---> Running in 782165bd1a8b

Removing intermediate container 782165bd1a8b

---> 2e2c7a4ea026

Step 4/27 : RUN apk add git tzdata && cp /usr/share/zoneinfo/${TZ} /etc/localtime && echo $TZ > /etc/timezone

---> Running in 85b32bb185c8

fetch https://dl-cdn.alpinelinux.org/alpine/v3.14/main/x86_64/APKINDEX.tar.gz

fetch https://dl-cdn.alpinelinux.org/alpine/v3.14/community/x86_64/APKINDEX.tar.gz

(1/7) Installing brotli-libs (1.0.9-r5)

(2/7) Installing nghttp2-libs (1.43.0-r0)

(3/7) Installing libcurl (7.79.1-r0)

(4/7) Installing expat (2.4.1-r0)

(5/7) Installing pcre2 (10.36-r0)

(6/7) Installing git (2.32.0-r0)

(7/7) Installing tzdata (2021e-r0)

Executing busybox-1.33.1-r6.trigger

OK: 22 MiB in 22 packages

Removing intermediate container 85b32bb185c8

---> 3240adcab128

Step 5/27 : ENV USER=appuser

---> Running in 8b8f2c8d3d3b

Removing intermediate container 8b8f2c8d3d3b

---> f2b4866b21ab

Step 6/27 : ENV UID=10001

---> Running in f6feab446106

Removing intermediate container f6feab446106

---> 54a02a4ae4f9

Step 7/27 : RUN adduser --disabled-password --gecos "" --home "/nonexistent" --shell "/sbin/nologin" --no-create-home --uid "${UID}" "${USER}"

---> Running in 05036e634b0c

Removing intermediate container 05036e634b0c

---> e0aa6d53860c

Step 8/27 : WORKDIR $GOPATH/src

---> Running in 962513e1a258

Removing intermediate container 962513e1a258

---> e9c7f169382f

Step 9/27 : COPY src/ /go/src/

---> 383d35179658

Step 10/27 : RUN go mod init main

---> Running in 7de29b1330ae

go: creating new go.mod: module main

go: to add module requirements and sums:

go mod tidy

Removing intermediate container 7de29b1330ae

---> 447d5859e95f

Step 11/27 : RUN go mod tidy

---> Running in ff31b9185dcc

Removing intermediate container ff31b9185dcc

---> d070533a2f6f

Step 12/27 : RUN go get -d -v

---> Running in 1076e9742df7

Removing intermediate container 1076e9742df7

---> cee66da4930a

Step 13/27 : RUN CGO_ENABLED=0 go build -ldflags='-w -s -extldflags "-static"' -a -o /go/bin/main .

---> Running in fda0bfe51009

Removing intermediate container fda0bfe51009

---> 886781406af3

Step 14/27 : FROM scratch

--->

Step 15/27 : LABEL maintainer="microk8s.raspberry@slainte.at"

---> Running in 37be2d43c280

Removing intermediate container 37be2d43c280

---> 74d5145b8a4a

Step 16/27 : LABEL Description="Kleiner statischer Webserver"

---> Running in bea56ecac8d6

Removing intermediate container bea56ecac8d6

---> 8882ec04a7a4

Step 17/27 : COPY --from=builder /usr/share/zoneinfo /usr/share/zoneinfo

---> fc930e8c71cc

Step 18/27 : COPY --from=builder /etc/localtime /etc/localtime

---> 72ab47f2ab4d

Step 19/27 : COPY --from=builder /etc/timezone /etc/timezone

---> 8b6cf086ecc9

Step 20/27 : COPY --from=builder /etc/passwd /etc/passwd

---> a7f34db7d163

Step 21/27 : COPY --from=builder /etc/group /etc/group

---> f5311faa6ef2

Step 22/27 : COPY --chown=appuser:appuser html/ /html/

---> 177ec4c642f2

Step 23/27 : COPY --from=builder /go/bin/main /main

---> 885e4ce994c7

Step 24/27 : EXPOSE 8080

---> Running in b1b0e6258ac8

Removing intermediate container b1b0e6258ac8

---> 5d1baee2add9

Step 25/27 : USER appuser:appuser

---> Running in 3e7a7ed9c791

Removing intermediate container 3e7a7ed9c791

---> 3477baadb6c6

Step 26/27 : WORKDIR /html/

---> Running in fb38b3ed44f9

Removing intermediate container fb38b3ed44f9

---> 99161e3f43d9

Step 27/27 : ENTRYPOINT ["/main"]

---> Running in 60665f656ce7

Removing intermediate container 60665f656ce7

---> f041835dcff7

Successfully built f041835dcff7

Successfully tagged default:latest

++ docker ps

++ grep -i default:latest

++ awk '{print $1 }'

+ docker kill

"docker kill" requires at least 1 argument.

See 'docker kill --help'.

Usage: docker kill [OPTIONS] CONTAINER [CONTAINER...]

Kill one or more running containers

++ docker container ls -a

++ awk '{print $1 }'

++ grep -i default_latest

+ docker container rm -f 51a36a4f7ed5

51a36a4f7ed5

+ docker run -d --name default_latest -p 8080:8080 default:latest

ac883b89517387a7a674426ea96b82dd59fcf7e2ce513ef18f21890934627f19

+ sleep 10

+ docker ps

CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES

ac883b895173 default:latest "/main" 10 seconds ago Up 10 seconds 0.0.0.0:8080->8080/tcp, :::8080->8080/tcp default_latest

041d5fd2b67a portainer/agent:latest "./agent" 5 days ago Up 4 hours 0.0.0.0:9001->9001/tcp, :::9001->9001/tcp portainer_agent

ebb513933fe0 portainer/portainer-ce:latest "/portainer" 5 days ago Up 4 hours 0.0.0.0:8000->8000/tcp, :::8000->8000/tcp, 0.0.0.0:9443->9443/tcp, :::9443->9443/tcp, 9000/tcp portainer

+ gzip

++ docker ps

++ grep -i default:latest

++ awk '{print $1 }'

+ docker export ac883b895173

+ echo 'docker exec -u 0 -it default_latest /bin/sh'

docker exec -u 0 -it default_latest /bin/sh

alfred@bureau:~/svn/trunk/k8s/k8s_app/default$

Das Image wird gebaut, und kann im Portainer betrachtet werden.

Abbildung 25: Portainer - Default-Service Container

Der Container startet problemlos.

Abbildung 26: Portainer - Default Service Image Größe

Das Image selbst ist jetzt mit 4,8 MB auch sehr schlank geworden.

Abbildung 27: Portainer - Default Service Image-Layer Größen

Die Zeitzone braucht ca. 2,5KB, was sehr schlank ist.

Die html-Dateien und Bildchen brauchen 528KB.

Die kompilierte go-Datei braucht 4,3MB. Das finde ich recht beachtlich. Denke diesen einfachen Service könnte man mit zb. C einfacher hinbekommen (mehr als GET kann dieser Service ja eh nicht). Wenn mal viel Zeit vorhanden ist, kann man sich das weiter ansehen.

Abbildung 28: Default Webservice

Und wenn man dann diesen Service aufruft, dann sieht das so aus.

Jetzt werden wir den Service am "Entwicklungsrechner" builden, und deployen.

alfred@monitoring:~/dev/default$ mk

+ shopt -o -s nounset

+ namespace=default

+ docker_registry=docker.registry:5000

+ . ./env.sh

++ shopt -o -s xtrace

++ shopt -o -s nounset

++ export image=default

++ image=default

++ export 'namespace=default slainte'

++ namespace='default slainte'

++ . ../namespace/default slainte_env.sh

./env.sh: line 18: ../namespace/default: No such file or directory

+ datum=(`date '+%Y%m%d'`)

++ date +%Y%m%d

++ svn info

++ grep Revision

++ awk '{print $2}'

+ revision=1376

+ tag=20211127-1376

+ svn update

Updating '.':

U do.sh

U src/main.go

Updated to revision 1377.

+ docker build --no-cache . -t docker.registry:5000/default:20211127-1376

Sending build context to Docker daemon 557.1kB

Step 1/27 : ARG BUILDER_IMAGE=golang:alpine

Step 2/27 : FROM ${BUILDER_IMAGE} as builder

---> 975a291cf170

Step 3/27 : ENV TZ=Europe/Vienna

---> Running in 3f12caec82d6

Removing intermediate container 3f12caec82d6

---> d768166f363c

Step 4/27 : RUN apk add git tzdata && cp /usr/share/zoneinfo/${TZ} /etc/localtime && echo $TZ > /etc/timezone

---> Running in 97dc8787993d

fetch https://dl-cdn.alpinelinux.org/alpine/v3.14/main/aarch64/APKINDEX.tar.gz

fetch https://dl-cdn.alpinelinux.org/alpine/v3.14/community/aarch64/APKINDEX.tar.gz

(1/7) Installing brotli-libs (1.0.9-r5)

(2/7) Installing nghttp2-libs (1.43.0-r0)

(3/7) Installing libcurl (7.79.1-r0)

(4/7) Installing expat (2.4.1-r0)

(5/7) Installing pcre2 (10.36-r0)

(6/7) Installing git (2.32.0-r0)

(7/7) Installing tzdata (2021e-r0)

Executing busybox-1.33.1-r6.trigger

OK: 22 MiB in 22 packages

Removing intermediate container 97dc8787993d

---> e373bea9d5ac

Step 5/27 : ENV USER=appuser

---> Running in e09441fbcbf5

Removing intermediate container e09441fbcbf5

---> 782881df7fad

Step 6/27 : ENV UID=10001

---> Running in 51e56a86b293

Removing intermediate container 51e56a86b293

---> a49c317f4d3d

Step 7/27 : RUN adduser --disabled-password --gecos "" --home "/nonexistent" --shell "/sbin/nologin" --no-create-home --uid "${UID}" "${USER}"

---> Running in ecdd977ac68f

Removing intermediate container ecdd977ac68f

---> dbc27ad53f47

Step 8/27 : WORKDIR $GOPATH/src

---> Running in 4192b680ffe3

Removing intermediate container 4192b680ffe3

---> 85b3ccb5bdc9

Step 9/27 : COPY src/ /go/src/

---> 42f076c95522

Step 10/27 : RUN go mod init main

---> Running in c315c3253dd4

go: creating new go.mod: module main

go: to add module requirements and sums:

go mod tidy

Removing intermediate container c315c3253dd4

---> e89ddadaf202

Step 11/27 : RUN go mod tidy

---> Running in 46d037445181

Removing intermediate container 46d037445181

---> ae12bb619e5c

Step 12/27 : RUN go get -d -v

---> Running in 07742fd47a31

Removing intermediate container 07742fd47a31

---> 7a84a944fb38

Step 13/27 : RUN CGO_ENABLED=0 go build -ldflags='-w -s -extldflags "-static"' -a -o /go/bin/main .

---> Running in 5be03523c796

Removing intermediate container 5be03523c796

---> 3b4526214505

Step 14/27 : FROM scratch

--->

Step 15/27 : LABEL maintainer="microk8s.raspberry@slainte.at"

---> Running in b85cc7d56c35

Removing intermediate container b85cc7d56c35

---> 18819bc782dc

Step 16/27 : LABEL Description="Kleiner statischer Webserver"

---> Running in bd9e30ad837d

Removing intermediate container bd9e30ad837d

---> 76989ca004c9

Step 17/27 : COPY --from=builder /usr/share/zoneinfo /usr/share/zoneinfo

---> bf390ed23d43

Step 18/27 : COPY --from=builder /etc/localtime /etc/localtime

---> 12a477258813

Step 19/27 : COPY --from=builder /etc/timezone /etc/timezone

---> fe6ff43916ae

Step 20/27 : COPY --from=builder /etc/passwd /etc/passwd

---> df8e003c5608

Step 21/27 : COPY --from=builder /etc/group /etc/group

---> e137cf1f65b3

Step 22/27 : COPY --chown=appuser:appuser html/ /html/

---> 988dcd53ed26

Step 23/27 : COPY --from=builder /go/bin/main /main

---> 7f2287a4e3e8

Step 24/27 : EXPOSE 8080

---> Running in 7667c76d041b

Removing intermediate container 7667c76d041b

---> 23244506a748

Step 25/27 : USER appuser:appuser

---> Running in 966ba5bdda48

Removing intermediate container 966ba5bdda48

---> 2c46e9cc4ae6

Step 26/27 : WORKDIR /html/

---> Running in d183fe447e3c

Removing intermediate container d183fe447e3c

---> 126d56f90f82

Step 27/27 : ENTRYPOINT ["/main"]

---> Running in 065facb8bf39

Removing intermediate container 065facb8bf39

---> be32ef870cef

Successfully built be32ef870cef

Successfully tagged docker.registry:5000/default:20211127-1376

+ docker push docker.registry:5000/default:20211127-1376

The push refers to repository [docker.registry:5000/default]

dac4a02d94a9: Pushed

b1283fda34d3: Pushed

90937b03a9ab: Pushed

400c6d30c005: Pushed

948ebb21a773: Pushed

9cd5dadbfe87: Pushed

a35817905619: Pushed

20211127-1376: digest: sha256:b740a40b5afb5fd3d5b116f26f0c5e9c8beeed224507a8d89722aa164d47e210 size: 1777

+ docker build . -t docker.registry:5000/default:latest

Sending build context to Docker daemon 557.1kB

Step 1/27 : ARG BUILDER_IMAGE=golang:alpine

Step 2/27 : FROM ${BUILDER_IMAGE} as builder

---> 975a291cf170

Step 3/27 : ENV TZ=Europe/Vienna

---> Using cache

---> d768166f363c

Step 4/27 : RUN apk add git tzdata && cp /usr/share/zoneinfo/${TZ} /etc/localtime && echo $TZ > /etc/timezone

---> Using cache

---> e373bea9d5ac

Step 5/27 : ENV USER=appuser

---> Using cache

---> 782881df7fad

Step 6/27 : ENV UID=10001

---> Using cache

---> a49c317f4d3d

Step 7/27 : RUN adduser --disabled-password --gecos "" --home "/nonexistent" --shell "/sbin/nologin" --no-create-home --uid "${UID}" "${USER}"

---> Using cache

---> dbc27ad53f47

Step 8/27 : WORKDIR $GOPATH/src

---> Using cache

---> 85b3ccb5bdc9

Step 9/27 : COPY src/ /go/src/

---> Using cache

---> 42f076c95522

Step 10/27 : RUN go mod init main

---> Using cache

---> e89ddadaf202

Step 11/27 : RUN go mod tidy

---> Using cache

---> ae12bb619e5c

Step 12/27 : RUN go get -d -v

---> Using cache

---> 7a84a944fb38

Step 13/27 : RUN CGO_ENABLED=0 go build -ldflags='-w -s -extldflags "-static"' -a -o /go/bin/main .

---> Using cache

---> 3b4526214505

Step 14/27 : FROM scratch

--->

Step 15/27 : LABEL maintainer="microk8s.raspberry@slainte.at"

---> Using cache

---> 18819bc782dc

Step 16/27 : LABEL Description="Kleiner statischer Webserver"

---> Using cache

---> 76989ca004c9

Step 17/27 : COPY --from=builder /usr/share/zoneinfo /usr/share/zoneinfo

---> Using cache

---> bf390ed23d43

Step 18/27 : COPY --from=builder /etc/localtime /etc/localtime

---> Using cache

---> 12a477258813

Step 19/27 : COPY --from=builder /etc/timezone /etc/timezone

---> Using cache

---> fe6ff43916ae

Step 20/27 : COPY --from=builder /etc/passwd /etc/passwd

---> Using cache

---> df8e003c5608

Step 21/27 : COPY --from=builder /etc/group /etc/group

---> Using cache

---> e137cf1f65b3

Türler ve etiketler

Yaş sınırı:
0+
Hacim:
515 s. 126 illüstrasyon
ISBN:
9783742770134
Yayıncı:
Telif hakkı:
Bookwire
İndirme biçimi:
Metin
Ortalama puan 4, 1 oylamaya göre
Metin
Ortalama puan 0, 0 oylamaya göre
Metin
Ortalama puan 0, 0 oylamaya göre