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

Yazı tipi:

cpu: 1

memory: 64Mi

Requests:

cpu: 500m

memory: 24Mi

Liveness: exec [/hello-world] delay=5s timeout=1s period=10s #success=1 #failure=3

Readiness: exec [/hello-world] delay=3s timeout=1s period=3s #success=1 #failure=3

Environment:

FOO: bar

Mounts:

/var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-vtwl2 (ro)

Conditions:

Type Status

Initialized True

Ready False

ContainersReady False

PodScheduled True

Volumes:

kube-api-access-vtwl2:

Type: Projected (a volume that contains injected data from multiple sources)

TokenExpirationSeconds: 3607

ConfigMapName: kube-root-ca.crt

ConfigMapOptional: <nil>

DownwardAPI: true

QoS Class: Burstable

Node-Selectors: <none>

Tolerations: node.kubernetes.io/not-ready:NoExecute op=Exists for 300s

node.kubernetes.io/unreachable:NoExecute op=Exists for 300s

Events:

Type Reason Age From Message

---- ------ ---- ---- -------

Normal Scheduled 23s default-scheduler Successfully assigned default/hello-world-6bb7844865-4j5bw to pc5

Warning BackOff 14s (x4 over 19s) kubelet Back-off restarting failed container

Normal Pulled 1s (x3 over 22s) kubelet Container image "docker.registry:5000/hello-world:20211003" already present on machine

Normal Created 1s (x3 over 22s) kubelet Created container hello-world

Normal Started 1s (x3 over 21s) kubelet Started container hello-world

alfred@pc1:/opt/cluster/go$

alfred@pc1:/opt/cluster/go$ kubectl get pod hello-world-6bb7844865-4j5bw

NAME READY STATUS RESTARTS AGE

hello-world-6bb7844865-4j5bw 0/1 CrashLoopBackOff 4 108s

alfred@pc1:/opt/cluster/go$

alfred@pc1:/opt/cluster/go$ kubectl logs hello-world-6bb7844865-4j5bw

hello world

alfred@pc1:/opt/cluster/go$

Das heist, der Service wird ordnungsgemäß installiert, läuft auch einmal und terminiert dann (so ist das Programm). Aus Kubernetes Sicht wird aber über das Deployment versucht den Service wieder herzustellen. Daher wird er permanent restarted. Für das Hello-World Prinzip reicht das. Für einen richtigen Service aber natürlich nicht.

Darum löschen wir den Service auch wieder.

alfred@pc1:/opt/cluster/go$ kubectl delete -f hello-world.yaml

deployment.apps "hello-world" deleted

service "hello-world-service" deleted

alfred@pc1:/opt/cluster/go$

Aber wir haben nun ein funktionierendes Setup. Können auf der Entwicklungsmaschine docker-Container erzeugen, diese in das Repository am Kubernetes Cluster einspielen, und den Service dann auch starten.

Golang IDE

Inspiration:

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

https://github.com/visualfc/liteide

https://linuxize.com/post/how-to-install-atom-text-editor-on-ubuntu-20-04/

https://www.gophercoders.com/install/atom/configure/

https://snapcraft.io/install/liteide-tpaw/ubuntu

https://elearning.wsldp.com/pcmagazine/install-liteide-on-ubuntu/

Um vernünftig Go Programme entwicklen zu können, braucht man eine vernünftige IDE. Neben IntelliJ (leider nicht in der Community-Edition) gibt es noch LiteIDE sowie den beliebten Editor Atom (wahrscheinlich gibt es noch viele andere). Ich verwenden den Atom-Editor.

Abbildung 10: Atom Editor

Nachdem das Plugin eingerichtet ist, kann man das Projekt bereits editieren.

Damit alles funktioniert muß natürlich go selbst vorhanden sein.

Abbildung 11: Atom Konfiguriert

Man kann aber auch LiteIDE benutzen.

Abbildung 12: LiteIDE

Womit man am liebsten arbeitet, muß jeder für sich selbst entscheiden.

Was auch immer man installiert, meine Rat ist die Applikation nicht über snap zu installieren (wegen des Isolation-Levels), sondern direkt. Die Interaktion zwischen den Snaps (setzen von Variablen usw.) funktioniert sonst unter Umständen nicht wie erwartet.

Am Beispiel von LiteIDE. Siehe auch https://elearning.wsldp.com/pcmagazine/install-liteide-on-ubuntu/

Download der richtigen Datei, entpacken nach /usr/local. Danach wird für den bequement Start eine desktop Datei erzeugt.

[Desktop Entry]

Version=1.0

Name=LiteIDE

Comment="IDE for editing and building projects written in the Go programming language"

GenericName=GoIDE

Exec=/usr/local/liteide/bin/liteide

Terminal=false

Type=Application

Icon=/usr/local/liteide/share/liteide/welcome/images/liteide128.xpm

Categories=Development;

StartupNotify=true

Diese Datei wird dann mit dem Statement

alfred@bureau:~$ cd Schreibtisch/

alfred@bureau:~/Schreibtisch$ ll

insgesamt 480

drwx-----T 2 alfred alfred 4096 Okt 10 09:23 ./

drwx-----T 49 alfred alfred 479232 Okt 10 09:24 ../

-rw-r--r-- 1 alfred alfred 361 Okt 10 09:22 LiteIDE.desktop

alfred@bureau:~/Schreibtisch$ sudo desktop-file-install LiteIDE.desktop

alfred@bureau:~/Schreibtisch$

nach

alfred@bureau:~/Schreibtisch$ ll /usr/share/applications/LiteIDE.desktop

-rw-r--r-- 1 root root 361 Okt 10 09:30 /usr/share/applications/LiteIDE.desktop

alfred@bureau:~/Schreibtisch$

kopiert, und leicht modifiziert. Ab dann kann man im Launcher diese Applikation zu den Favoriten hinzufügen.

Abbildung 13: LiteIDE zu Favoriten hinzufügen

Ab jetzt ist der Start leicht.

Abbildung 14: LiteIDE System Environment

Jetzt muß nur noch das Systemenvironment richtig sein, dann steht dem Entwickeln, testen, Debuggen nichts mehr im Wege.

Lens – the Kubernetes IDE

Inspiration:

https://k8slens.dev/

https://kubernetes.io/docs/tasks/tools/install-kubectl-linux/

https://dev.to/anaisintech/getting-started-with-kubernetes-kubectl-and-microk8s-on-ubuntu-pko

https://microk8s.io/docs/services-and-ports

https://microk8s.io/docs/troubleshooting

Lens ist eine recht vernünftige IDE um mit Kubernetes zu arbeiten. Unter Ubuntu kann das direkt aus dem Software-Repository installiert werden.

Abbildung 15: Lens - Installation unter Ubuntu

Damit das Tool funktionieren kann, brauchen wir auf unserem lokalen Rechner kubectl.

alfred@bureau:~$ snap install kubectl --classic

kubectl version --client

kubectl 1.22.4 aus Canonical✓ installiert

Client Version: version.Info{Major:"1", Minor:"22", GitVersion:"v1.22.4", GitCommit:"b695d79d4f967c403a96986f1750a35eb75e75f1", GitTreeState:"clean", BuildDate:"2021-11-18T02:34:11Z", GoVersion:"go1.16.10", Compiler:"gc", Platform:"linux/amd64"}

alfred@bureau:~$ kubectl cluster-info

To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.

The connection to the server localhost:8080 was refused - did you specify the right host or port?

alfred@bureau:~$

Nun fehlt noch die Konfig. Die holen wir uns aus dem existierenden Cluster.

alfred@pc1:~/.kube$ microk8s config > config

alfred@pc1:~/.kube$ cat config

apiVersion: v1

clusters:

- cluster:

certificate-authority-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUREekNDQWZlZ0F3SUJBZ0lVSmdyRlRBbmh6SjBXZThxakdFVFErMDFHYWJRd0RRWUpLb1pJaHZjTkFRRUwKQlFBd0Z6RVZNQk1HQTFVRUF3d01NVEF1TVRVeUxqRTRNeTR4TUI0WERUSXhNVEV5TXpBM016WXpPRm9YRFRNeApNVEV5TVRBM016WXpPRm93RnpFVk1CTUdBMVVFQXd3TU1UQXVNVFV5TGpFNE15NHhNSUlCSWpBTkJna3Foa2lHCjl3MEJBUUVGQUFPQ0FROEFNSUlCQ2dLQ0FRRUExYVQ3Y2hkaHUwRzNwc2EvYjdUZHU3UFRoK3l5ek41TmkyRzMKaDBmbUwweUpqOExHL2FGSm9QdW1RRVBNdWYvRFVWUVQrbmFDdjJrdmtjSjFtdlgzdlhBb1hwMHR1S1FLOEFxawp2a1UwNU8rb1pScERJZFQvUUlSSm1Ba3UraHJwWHJscE1TeHRjdUxWZ3hjc0ZpWGU4ZzVxYXVEOGVSMzZudlN1CnJzK3o2RE1rS1lvVzdlYWp4L0loNDBsNkNNY3VVVDNPVnIyTEh0Sm0vM2NaKzZlVEQ3aTNFUjA3TlVmcVk5Y1oKaXcvUzRlSWtUVC9HRjFwZG5mbUtYdnB4NnFKaWVjWDVPanEzM1l5UitBZ3FPdnlBNzVIOWp5SEtqOTdDekdqdgp5ZGJjcmJtYW5SVU1FditlVWVyVDFMeW13SDNFSDk0OUM5VXhkV2pXZTEydVNZaS9YUUlEQVFBQm8xTXdVVEFkCkJnTlZIUTRFRmdRVTZhZjNUSWc3ZjV6N21kYno3NGtCZ2FHVFRMWXdId1lEVlIwakJCZ3dGb0FVNmFmM1RJZzcKZjV6N21kYno3NGtCZ2FHVFRMWXdEd1lEVlIwVEFRSC9CQVV3QXdFQi96QU5CZ2txaGtpRzl3MEJBUXNGQUFPQwpBUUVBUHppRnhmU29EWjdscGt1TGF0a0VVdy9vUGg0YlIyM2g4bXoyTkpWc0p2NW92bXIvaVA2NXdKa2tKMDVRCnliays0Y0d3TnlFemdQVTBJaFRERnpRVU0vWFRyQlEwZG0zSGFsSHNHVE1iK05Ua3V2REFJQlUzUVhyOWJJYlkKbzVuaUl0SWVRdGR4dVBTbXYwZ2laQ3l6bWpQZTVOcnlRc05ONFQyeFp2UUcrcDhkVnBzWmZhVTd0NERZZlZhbwppTW5KVFJNazdKS3c5M3Y5VDRRcHdsMWthQnlFcjhYUkhWOGxUQUVPa1djOGdlNWx5NlEza1ZGeVAzYUx4djJqCll6K3BxVExncENRQ3JJRlVqcVhpTkdUeUtlQXp1TWlFaWFrclRnODhNZlhaTVdHc0l5NW5GdWt0clpYT0xhL3QKZVo2NEorKzg2SzRrQXRidVdNQUJORjNObEE9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==

server: https://192.168.0.201:16443

name: microk8s-cluster

contexts:

- context:

cluster: microk8s-cluster

user: admin

name: microk8s

current-context: microk8s

kind: Config

preferences: {}

users:

- name: admin

user:

token: WDZKL1VldzE4aFVNVm03amdmVFR5Z1h2UzNZcTZjeWxNUzVud2ZPcWR5WT0K

alfred@pc1:~/.kube$

Wir kopieren die config auf unseren Rechner in den Ordner ${HOME}/.kube.

alfred@bureau:~/.kube$ ls -lisa

insgesamt 480

1706699 4 drwxr-x--- 2 alfred alfred 4096 Nov 26 11:52 .

1311228 472 drwx-----T 52 alfred alfred 479232 Nov 26 11:52 ..

1705911 4 -rw-rw-r-- 1 alfred alfred 1874 Nov 26 11:51 config

alfred@bureau:~/.kube$

alfred@bureau:~/.kube$ kubectl config get-clusters

NAME

microk8s-cluster

alfred@bureau:~/.kube$

alfred@bureau:~/.kube$ kubectl cluster-info

Kubernetes control plane is running at https://192.168.0.201:16443

CoreDNS is running at https://192.168.0.201:16443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy

To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.

alfred@bureau:~/.kube$

Nun funktioniert die Kommand-Line-Version. Wir installieren noch die bash-completion (das spart viel Tipparbeit).

alfred@bureau:~$ sudo apt-get install bash-completion

Paketlisten werden gelesen… Fertig

Abhängigkeitsbaum wird aufgebaut… Fertig

Statusinformationen werden eingelesen… Fertig

bash-completion ist schon die neueste Version (1:2.11-2ubuntu1).

bash-completion wurde als manuell installiert festgelegt.

0 aktualisiert, 0 neu installiert, 0 zu entfernen und 0 nicht aktualisiert.

alfred@bureau:~$

alfred@bureau:~$ echo 'source <(kubectl completion bash)' >>~/.bashrc

alfred@bureau:~$ sudo su -l

root@bureau:~# kubectl completion bash >/etc/bash_completion.d/kubectl

root@bureau:~# exit

Abgemeldet

alfred@bureau:~$ echo 'alias k=kubectl' >>~/.bashrc

echo 'complete -F __start_kubectl k' >>~/.bashrc

alfred@bureau:~$

Nun loggen wir uns neu ein. Somit funktioniert der Alias und der Zugriff auf den Cluster von außen.

alfred@bureau:~$ k get all

NAME READY STATUS RESTARTS AGE

pod/webserver-depl-bff4d4675-8v9nz 1/1 Running 2 (179m ago) 18h

NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE

service/kubernetes ClusterIP 10.152.183.1 <none> 443/TCP 3d3h

service/webserver-svc ClusterIP 10.152.183.121 <none> 443/TCP,80/TCP 38h

NAME READY UP-TO-DATE AVAILABLE AGE

deployment.apps/webserver-depl 1/1 1 1 38h

NAME DESIRED CURRENT READY AGE

replicaset.apps/webserver-depl-cf898f654 0 0 0 38h

replicaset.apps/webserver-depl-98f95758b 0 0 0 38h

replicaset.apps/webserver-depl-646544ddfd 0 0 0 37h

replicaset.apps/webserver-depl-dd8c746d6 0 0 0 37h

replicaset.apps/webserver-depl-86c6d7549f 0 0 0 37h

replicaset.apps/webserver-depl-b485f9695 0 0 0 19h

replicaset.apps/webserver-depl-c8599c9f5 0 0 0 19h

replicaset.apps/webserver-depl-bff4d4675 1 1 1 18h

alfred@bureau:~$

Jetzt können wir den Cluster in der Lens einrichten.

Abbildung 16: Lens - Cluster hinzufügen

Es wird die config aus ${HOME}/.kube/config verwendet.

Abbildung 17: Lens - Cluster Ansicht

Nun ist Lens mit dem Cluster verbunden. Somit kann komfortabel vom eigenen Rechner aus gearbeitet werden.

Alternativ ist natürlich auch das Kubernet Dashboard als Webapplikation vorhanden.

Abbildung 18: Kubernetes Dashboard

Somit kann der Cluster bequem verwaltet und diagnostiziert werden.

Wie sicher das exponieren der API nach aussen ist, weiß ich noch nicht. Im Internet sollten der Cluster durch die Firewall geschützt sein (nur die Ingress-Ports sichtbar).

Generell sollte bei Einsatz im Internet der Firewall große Beachtung zuteil werden. Lokal zu Hause ist die Architektur etwas einfacher.

Abbildung 19: Netzwerk Architektur

Hier ist nur der Ingress nach aussen sichtbar. Alles andere kann von aussen nicht erreicht werden. In Richtung Intranet ist alles erlaubt.

Einfacher WebServer mit Go

Inspiration:

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

https://www.socketloop.com/tutorials/golang-get-hardware-information-such-as-disk-memory-and-cpu-usage

https://www.freecodecamp.org/news/how-to-remove-images-in-docker/

https://docs.docker.com/engine/reference/commandline/image_pull/

Dieses Kapitel beschreibt einen einfachen WebServer mit Go. Das ist ein richtig funktionierender WebService. Dieser Service wird alle Variablen und die Systemzeit des Containers wiedergeben.

Zuerst brauchen wir ein einfaches Programm.

// Ausgabe eines einfachen HTML-Files und ersetzen von Schlüsselwörtern mit konkreten Informationen

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

// https://www.socketloop.com/tutorials/golang-get-hardware-information-such-as-disk-memory-and-cpu-usage

//

// alfred@monitoring:~/GetInfo$ go get github.com/shirou/gopsutil/...

package main

import (

"bufio"

"fmt"

"io/ioutil"

"log"

"net/http"

"os"

"runtime"

"strconv"

"strings"

"time"

"github.com/shirou/gopsutil/disk"

"github.com/shirou/gopsutil/host"

"github.com/shirou/gopsutil/mem"

)

type Page struct {

Title string

Body []byte

}

func loadError(xerr string) (xhtml string) {

var xs string

currentTime := time.Now()

xtext, err := ioutil.ReadFile("error.html")

if err != nil {

log.Fatal("Error File kann nicht geöffnet werden " + err.Error())

}

xs = strings.Replace(string(xtext), "%SYSTIME%", currentTime.Format("2006-01-02 15:04:05 Monday"), -1)

xs = strings.Replace(string(xs), "%SYSTEMFEHLER%", xerr, -1)

return xs

}

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

var xhtml string

var xtmp string

var xenv string

const GB = 1073741824

filename := title + ".html"

log.Println(filename)

xhtml = ""

currentTime := time.Now()

f, err := os.Open(filename)

if err != nil {

log.Println(filename+" kann nicht geöffnet werden: ", err)

xhtml = loadError(err.Error())

} else {

scanner := bufio.NewScanner(f)

for scanner.Scan() {

xtmp = scanner.Text()

if strings.Contains(xtmp, "%SYSTIME%") {

xtmp = strings.Replace(xtmp, "%SYSTIME%", currentTime.Format("2006-01-02 15:04:05 Monday"), -1)

}

if strings.Contains(xtmp, "%OSENVIRONMENT%") {

xenv = ""

for _, pair := range os.Environ() {

variable := strings.Split(pair, "=")

xenv += variable[0] + "=>" + variable[1] + "<br>"

}

xtmp = strings.Replace(xtmp, "%OSENVIRONMENT%", xenv, -1)

}

if strings.Contains(xtmp, "%DISKUSAGE%") {

diskStat, err := disk.Usage("/")

if err != nil {

log.Println(" Plattenbelegung kann nicht gelesen werden: ", err)

}

xenv = "Pfad:" + diskStat.Path +

"<br>FSTYPE:" + diskStat.Fstype +

"<br>Total disk space:" + fmt.Sprintf("%5.1f", float64(diskStat.Total)/GB) +

" GB<br>Free disk space:" + fmt.Sprintf("%5.1f", float64(diskStat.Free)/GB) +

" GB<br>Used disk space:" + fmt.Sprintf("%5.1f", float64(diskStat.Used)/GB) +

" GB<br>Used GB Prozent:" + fmt.Sprintf("%3.1f", diskStat.UsedPercent) +

"<br>Used Inodes:" + strconv.FormatUint(diskStat.InodesUsed, 10) +

"<br>Used Inodes Prozent:" + fmt.Sprintf("%3.1f", diskStat.InodesUsedPercent)

xtmp = strings.Replace(xtmp, "%DISKUSAGE%", xenv, -1)

}

if strings.Contains(xtmp, "%HOSTINFO%") {

// host or machine kernel, uptime, platform Info

hostStat, err := host.Info()

if err != nil {

log.Println(" Hostinformation kann nicht gelesen werden: ", err)

}

xenv = "Hostname: " + hostStat.Hostname +

"<br>OS: " + hostStat.OS +

"<br>Platform: " + hostStat.Platform +

"<br>Host ID(uuid): " + hostStat.HostID +

"<br>Uptime (sec): " + strconv.FormatUint(hostStat.Uptime, 10) +

"<br>Number of processes running: " + strconv.FormatUint(hostStat.Procs, 10)

xtmp = strings.Replace(xtmp, "%HOSTINFO%", xenv, -1)

}

if strings.Contains(xtmp, "%MEMINFO%") {

runtimeOS := runtime.GOOS

vmStat, err := mem.VirtualMemory()

if err != nil {

log.Println(" Memoryinformation kann nicht gelesen werden: ", err)

}

xenv = "OS : " + runtimeOS +

"<br>Total memory: " + fmt.Sprintf("%5.1f", float64(vmStat.Total)/GB) +

" GB<br>Free memory: " + fmt.Sprintf("%5.1f", float64(vmStat.Free)/GB) +

" GB<br>Used memory: " + fmt.Sprintf("%5.1f", float64(vmStat.Used)/GB) +

" GB<br>Percentage used memory: " + strconv.FormatFloat(vmStat.UsedPercent, 'f', 2, 64)

xtmp = strings.Replace(xtmp, "%MEMINFO%", xenv, -1)

}

xhtml += xtmp

}

if err := scanner.Err(); err != nil {

log.Println(filename+" kann nicht gelesen werden: %s\n", err)

xhtml = loadError(err.Error())

}

}

defer f.Close()

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

}

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

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

p, _ := loadPage(title)

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

}

func main() {

log.Println("Main Started")

http.HandleFunc("/view/", viewHandler)

log.Fatal(http.ListenAndServe(":8080", nil))

log.Println("Main End")

}

Um die Abhängigkeiten richtig auflösen zu können, braucht go auch ein module-File. Diese Dateien werden vom SDK LiteIDE selbstständig erzeugt.

alfred@monitoring:~/GetInfo$ cat go.mod

module GetInfo

go 1.16

require (

github.com/StackExchange/wmi v1.2.1 // indirect

github.com/shirou/gopsutil v3.21.9+incompatible // indirect

github.com/tklauser/go-sysconf v0.3.9 // indirect

golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac // indirect

)

alfred@monitoring:~/GetInfo$ cat go.sum

github.com/StackExchange/wmi v1.2.1 h1:VIkavFPXSjcnS+O8yTq7NI32k0R5Aj+v39y29VYDOSA=

github.com/StackExchange/wmi v1.2.1/go.mod h1:rcmrprowKIVzvc+NUiLncP2uuArMWLCbu9SBzvHz7e8=

github.com/go-ole/go-ole v1.2.5 h1:t4MGB5xEDZvXI+0rMjjsfBsD7yAgp/s9ZDkL1JndXwY=

github.com/go-ole/go-ole v1.2.5/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=

github.com/shirou/gopsutil v3.21.9+incompatible h1:LTLpUnfX81MkHeCtSrwNKZwuW5Id6kCa7/P43NdcNn4=

github.com/shirou/gopsutil v3.21.9+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=

github.com/tklauser/go-sysconf v0.3.9 h1:JeUVdAOWhhxVcU6Eqr/ATFHgXk/mmiItdKeJPev3vTo=

github.com/tklauser/go-sysconf v0.3.9/go.mod h1:11DU/5sG7UexIrp/O6g35hrWzu0JxlwQ3LSFUzyeuhs=

github.com/tklauser/numcpus v0.3.0 h1:ILuRUQBtssgnxw0XXIjKUC56fgnOrFoQQ/4+DeU2biQ=

github.com/tklauser/numcpus v0.3.0/go.mod h1:yFGUr7TUHQRAhyqBcEg0Ge34zDBAsIvJJcyE6boqnA8=

golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=

golang.org/x/sys v0.0.0-20210816074244-15123e1e1f71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=

golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac h1:oN6lz7iLW/YC7un8pq+9bOLyXrprv2+DKfkJY+2LJJw=

golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=

alfred@monitoring:~/GetInfo$

Dieses Programm zeigt nach dem Aufruf von <Link:8080/view/filename> das aufgerufene File <filename> an, und ersetzt gewisse Schlüsselwörter durch konkreten Text. In unserem Beispiel habe ich das File hello.html mit OpenOffice vorbereitet.

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

<html>

<head>

<meta http-equiv="content-type" content="text/html; charset=utf-8"/>

<title></title>

<meta name="generator" content="LibreOffice 7.1.6.2 (Linux)"/>

<meta name="author" content="Alfred Sabitzer"/>

<meta name="created" content="2021-10-07T16:33:50.696105947"/>

<meta name="changedby" content="Alfred Sabitzer"/>

<meta name="changed" content="2021-10-07T16:36:08.816466992"/>

<style type="text/css">

@page { size: 21cm 29.7cm; margin: 2cm }

p { margin-bottom: 0.25cm; line-height: 115%; background: transparent }

td p { orphans: 0; widows: 0; background: transparent }

</style>

</head>

<body lang="de-AT" link="#000080" vlink="#800000" dir="ltr"><p style="margin-bottom: 0cm; line-height: 100%">

<p style="margin-bottom: 0cm; line-height: 100%"><br/>

</p>

<table width="100%" cellpadding="4" cellspacing="0">

<col width="64*"/>

<col width="64*"/>

<col width="64*"/>

<col width="64*"/>

<tr valign="top">

<td width="25%" style="border-top: 1px solid #000000; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0.1cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm"><p>

OSENVIRONMENT</p>

</td>

<td width="25%" style="border-top: 1px solid #000000; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0.1cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm"><p>

DISKUSAGE</p>

</td>

<td width="25%" style="border-top: 1px solid #000000; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0.1cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm"><p>

HOSTINFO</p>

</td>

<td width="25%" style="border: 1px solid #000000; padding: 0.1cm"><p>

MEMINFO</p>

</td>

</tr>

<tr valign="top">

<td width="25%" style="border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm"><p>

%OSENVIRONMENT%

</p>

</td>

<td width="25%" style="border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm"><p>

%DISKUSAGE%

</p>

</td>

<td width="25%" style="border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm"><p>

%HOSTINFO%</p>

</td>

<td width="25%" style="border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: 1px solid #000000; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0.1cm"><p>

%MEMINFO%</p>

</td>

</tr>

</table>

<p style="margin-bottom: 0cm; line-height: 100%"><br/>

</p>

<p style="margin-bottom: 0cm; line-height: 100%">Es ist <span style="background: #c0c0c0"><sdfield type=DATETIME sdval="44476,6908896088" sdnum="3079;3079;T. MMMM JJJJ">%SYSTIME%</sdfield></span></p>

</body>

</html>

Nun kompilieren wir das File.

alfred@monitoring:~/GetInfo$ go build GetInfo.go

go: downloading github.com/shirou/gopsutil v3.21.9+incompatible

go: extracting github.com/shirou/gopsutil v3.21.9+incompatible

go: downloading golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac

go: extracting golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac

go: finding github.com/shirou/gopsutil v3.21.9+incompatible

go: finding golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac

alfred@monitoring:~/GetInfo$ ll

total 7716

drwxrwxr-x 2 alfred alfred 4096 Oct 15 20:30 ./

drwxr-xr-x 22 alfred alfred 4096 Oct 11 07:30 ../

-rwxrwxr-x 1 alfred alfred 8009715 Oct 15 20:30 GetInfo*

-rw------- 1 alfred alfred 4473 Oct 10 21:34 GetInfo.go

-rw------- 1 alfred alfred 81 Oct 10 21:48 dockerfile

-rw------- 1 alfred alfred 1434 Oct 10 21:19 error.html

-rw-rw-r-- 1 alfred alfred 0 Oct 11 07:28 getinfo.tar

-rw------- 1 alfred alfred 263 Oct 10 10:04 go.mod

-rw------- 1 alfred alfred 1314 Oct 10 10:04 go.sum

-rw------- 1 alfred alfred 3180 Oct 10 21:32 hello.html

alfred@monitoring:~/GetInfo$ ./GetInfo

Ein kurzer Test auf http://monitoring:8080/view/hello ergibt

Abbildung 20: GetInfo Ausgabe

Das heist das Programm funktioniert. Die Logausgabe sieht aus wie folgt:

alfred@monitoring:~/GetInfo$ ./GetInfo

2021/10/10 21:42:01 Main Started

2021/10/10 21:42:16 hello.html

^C

alfred@monitoring:~/GetInfo$

Jetzt brauchen wir noch ein Docker-File

alfred@monitoring:~/GetInfo$ cat dockerfile

# syntax=docker/dockerfile:1

# Alpine is chosen for its small footprint

# compared to Ubuntu

FROM golang:1.16-alpine

WORKDIR /app

# Download necessary Go modules

COPY go.mod ./

COPY go.sum ./

RUN go mod download

COPY *.go ./

COPY hello.html ./

COPY error.html ./

RUN go build -o /GetInfo

EXPOSE 8080

CMD [ "/GetInfo" ]

alfred@monitoring:~/GetInfo$

um den Container zu bauen.

alfred@monitoring:~/GetInfo$ docker build . -t docker.registry:5000/getinfo:20211015

Sending build context to Docker daemon 16.38kB

Step 1/11 : FROM golang:1.16-alpine

1.16-alpine: Pulling from library/golang

552d1f2373af: Pull complete

eb74239f2a0c: Pull complete

2a8ec004bf6b: Pull complete

12f1fa1a3b20: Pull complete

5c12166b7f9d: Pull complete

Digest: sha256:05df7ff684a2cb06aa207be14a78918cbc3285ed3b965974979e575d59de1c11

Status: Downloaded newer image for golang:1.16-alpine

---> d2f4346f5656

Step 2/11 : WORKDIR /app

---> Running in 9b6c3b098321

Removing intermediate container 9b6c3b098321

---> 738bd59f63db

Step 3/11 : COPY go.mod ./

---> cb6306d5fdf2

Step 4/11 : COPY go.sum ./

---> f7eeef9ebda2

Step 5/11 : RUN go mod download

---> Running in efbe89b22883

Removing intermediate container efbe89b22883

---> cb738e90d4d7

Step 6/11 : COPY *.go ./

---> c5ab2f4e9e5c

Step 7/11 : COPY hello.html ./

---> 8e6738e25799

Step 8/11 : COPY error.html ./

---> 5c9506b2dc3f

Step 9/11 : RUN go build -o /GetInfo.go

---> Running in 3ad675aeb626

Removing intermediate container 3ad675aeb626

---> 0abfe5a9d849

Step 10/11 : EXPOSE 8080

---> Running in 80f728420378

Removing intermediate container 80f728420378

---> b9c5a76c55d2

Step 11/11 : CMD [ "/GetInfo" ]

---> Running in 71d6f27934d2

Removing intermediate container 71d6f27934d2

---> 4fae231152c2

Successfully built 4fae231152c2

Successfully tagged docker.registry:5000/getinfo:20211015

alfred@monitoring:~/GetInfo$

alfred@monitoring:~/GetInfo$ docker images

REPOSITORY TAG IMAGE ID CREATED SIZE

docker.registry:5000/getinfo 20211015 4fae231152c2 39 seconds ago 317MB

golang 1.16-alpine d2f4346f5656 2 days ago 296MB

alfred@monitoring:~/GetInfo$

Nun starten wir den Container im Vordergrund um den Output zu testen.

alfred@monitoring:~/GetInfo$ docker run --publish 8080:8080 docker.registry:5000/getinfo:20211015

2021/10/15 19:22:13 Main Started

2021/10/15 19:22:40 hello.html

Der Output im Browser ist wie folgt:

Abbildung 21: Docker Test Output

Der Container ist am erwarteten Port erreichbar. Die Anzeige der Werte sind jetzt aus Sicht des Containers, wie man an den Variablen und am Environment sehen kann.

Wir überprüfen die Struktur des gebauten docker-files.

alfred@monitoring:~/GetInfo$ docker save docker.registry:5000/getinfo:20211015 > getinfo.tar

alfred@monitoring:~/GetInfo$ tar -tvf getinfo.tar

-rw-r--r-- 0/0 7059 2021-10-15 21:22 0fca605bf404203fe0e1d41e306687bf70b8cdb4392c41363af0f6712ae28959.json

drwxr-xr-x 0/0 0 2021-10-15 21:22 11ada22ca4865de4368da5b2cdea81c34f3fc62b60e62f00329f839e1e51a431/

-rw-r--r-- 0/0 3 2021-10-15 21:22 11ada22ca4865de4368da5b2cdea81c34f3fc62b60e62f00329f839e1e51a431/VERSION

-rw-r--r-- 0/0 406 2021-10-15 21:22 11ada22ca4865de4368da5b2cdea81c34f3fc62b60e62f00329f839e1e51a431/json

-rw-r--r-- 0/0 5605376 2021-10-15 21:22 11ada22ca4865de4368da5b2cdea81c34f3fc62b60e62f00329f839e1e51a431/layer.tar

drwxr-xr-x 0/0 0 2021-10-15 21:22 1a41da37655e1ae130db0ff268801f26989f408ad4e24fee81b18252883fe835/

-rw-r--r-- 0/0 3 2021-10-15 21:22 1a41da37655e1ae130db0ff268801f26989f408ad4e24fee81b18252883fe835/VERSION

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 0, 0 oylamaya göre
Metin
Ortalama puan 4, 1 oylamaya göre
Metin
Ortalama puan 0, 0 oylamaya göre