Читать книгу K8s Applications mit MicroK8S auf Raspberry PI - Alfred Sabitzer - Страница 10

Оглавление

Entwicklungsumgebung

Inspiration:

https://pimylifeup.com/ubuntu-install-docker/

https://brjapon.medium.com/setting-up-ubuntu-20-04-arm-64-under-raspberry-pi-4-970654d12696

https://microk8s.io/docs/registry-built-in

https://microk8s.io/docs/registry-private

https://github.com/docker-library/hello-world

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

https://gobyexample.com/hello-world

https://linuxconfig.org/how-to-install-go-on-ubuntu-20-04-focal-fossa-linux

https://forums.docker.com/t/docker-private-registry-how-to-list-all-images/21136/2

https://github.com/fraunhoferfokus/deckschrubber

https://collabnix.github.io/kubetools/

Um das Source-Repository nutzen zu können brauchen wir eine Entwicklungsumgebung. Dafür benutzen wir unseren Entwicklungs-Raspbery PI.

Abbildung 8: Gesamtsystem

Dieser Entwicklungs-Raspberry ist ein Raspberry 4 mit 8GB RAM und einer 120 GB SDRAM Karte. Zusätzlich gibt es noch eine 1TB-USB-Platte für all die Backups.

Auf diesem Rechner ist Docker installiert.

alfred@monitoring:~$ docker version

Client:

Version: 20.10.7

API version: 1.41

Go version: go1.13.8

Git commit: 20.10.7-0ubuntu1~20.04.1

Built: Wed Aug 4 22:53:01 2021

OS/Arch: linux/arm64

Context: default

Experimental: true

Server:

Engine:

Version: 20.10.7

API version: 1.41 (minimum version 1.12)

Go version: go1.13.8

Git commit: 20.10.7-0ubuntu1~20.04.1

Built: Wed Aug 4 19:07:47 2021

OS/Arch: linux/arm64

Experimental: false

containerd:

Version: 1.5.2-0ubuntu1~20.04.2

GitCommit:

runc:

https://github.com/docker-library/hello-world Version: 1.0.0~rc95-0ubuntu1~20.04.2

GitCommit:

docker-init:

Version: 0.19.0

GitCommit:

alfred@monitoring:~$

Es gibt sehr viele Anleitungen, wie man Docker installiert. Ich habe dazu folgendes Skript.

#!/bin/bash

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

# $Date: 2021-11-22 18:47:00 +0100 (Mo, 22. Nov 2021) $

# $Revision: 1252 $

# $Author: alfred $

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

# $Id: portainer.sh 1252 2021-11-22 17:47:00Z alfred $

#

# https://www.digitalocean.com/community/tutorials/how-to-install-and-use-docker-on-ubuntu-20-04-de

#

# Installieren Docker und Portainer

#

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

#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

#

sudo apt update

sudo apt install apt-transport-https ca-certificates curl software-properties-common

curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -

sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu focal stable"

sudo apt update

apt-cache policy docker-ce

sudo apt install docker-ce

sudo usermod -aG docker ${USER}

#

docker volume create portainer_data

docker run -d -p 8000:8000 -p 9443:9443 --name portainer \

--restart=always \

-v /var/run/docker.sock:/var/run/docker.sock \

-v /portainer_data:/data \

portainer/portainer-ce:latest

docker ps

docker run -d -p 9001:9001 --name portainer_agent \

--restart=always \

-v /var/run/docker.sock:/var/run/docker.sock \

-v /var/lib/docker/volumes:/var/lib/docker/volumes \

portainer/agent:latest

Damit gibt es dann auch den Portainer, der recht praktisch ist, um die lokale Dockerinstallation zu steuern.

Abbildung 9: Portainer

Wir müssen das Repository das sich am Kubernetes Cluster befindet in die Konfiguration am Entwicklungsrechner eintragen.

alfred@monitoring:~/go$ cat /etc/hosts

127.0.0.1 localhost

127.0.0.1 monitoring

127.0.0.1 monitoring.slainte.at

192.168.0.213 docker.registry

192.168.0.201 pc1

192.168.0.202 pc2

192.168.0.203 pc3

192.168.0.204 pc4

192.168.0.205 pc5

alfred@monitoring:~/go$ sudo cat /etc/docker/daemon.json

{

"insecure-registries" : ["docker.registry:5000"]

}

Die Registry ist als Loadbalancer-Service ausfallsicher. Die Storage ist in einem persistant volume, somit funktioniert das auch von überall im Cluster.

Nun können wir versuchen ein hello world zu erzeugen.

package main

import "fmt"

func main() {

fmt.Println("hello world")

}

Dieser Programmteil ist in GO geschrieben. Go wird wie folgt installiert.

alfred@monitoring:~$ sudo apt install golang

alfred@monitoring:~$ go version

go version go1.13.8 linux/arm64

alfred@monitoring:~$

Dann kann man das go Programm testen und builden.

alfred@monitoring:~$ mkdir go

alfred@monitoring:~$ cd go

alfred@monitoring:~/go$ nano hello-world.go

alfred@monitoring:~/go$ go run hello-world.go

hello world

alfred@monitoring:~/go$ go build hello-world.go

alfred@monitoring:~/go$ ls -lisa

total 1936

4688691 4 drwxrwxr-x 2 alfred alfred 4096 Sep 30 11:26 .

1140881 4 drwxr-xr-x 21 alfred alfred 4096 Sep 30 11:25 ..

127267 1924 -rwxrwxr-x 1 alfred alfred 2097605 Sep 30 11:26 hello-world

4688693 4 -rw-rw-r-- 1 alfred alfred 75 Sep 30 11:25 hello-world.go

alfred@monitoring:~/go$ ./hello-world

hello world

alfred@monitoring:~/go$

Jetzt haben wir das go-Programm, und müssen es in einen Docker-Container packen.

alfred@monitoring:~/go$ docker rmi $(docker images -q) # Löscht alle vorhandenen Images im lokalen Repository

Um einen Container zu erzeugen, brauchen wir ein dockerfile.

alfred@monitoring:~/dev/hello-world$ cat dockerfile

# syntax=docker/dockerfile:1

# Alpine is chosen for its small footprint

# compared to Ubuntu

FROM golang:1.16-alpine

WORKDIR /app

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

COPY go.mod ./

COPY *.go ./

RUN go build -o /hallo

EXPOSE 80

CMD ["/hallo"]

alfred@monitoring:~/dev/hello-world$

Nun bauen wir den Container.

alfred@monitoring:~/dev/hello-world$ docker build . -t docker.registry:5000/hello-world:20211003

Sending build context to Docker daemon 9.216kB

Step 1/8 : FROM golang:1.16-alpine

1.16-alpine: Pulling from library/golang

be307f383ecc: Already exists

e31131f141ae: Pull complete

7f3ae2225eeb: Pull complete

27b4cf6759f9: Pull complete

05c56ed0aaf5: Pull complete

Digest: sha256:45412fe3f5016509fc448b83faefc34e6f9e9bcc8ca1db1c54505d5528264e16

Status: Downloaded newer image for golang:1.16-alpine

---> bebfc96a903d

Step 2/8 : WORKDIR /app

---> Running in c81df142320d

Removing intermediate container c81df142320d

---> a81936939cb7

Step 3/8 : LABEL maintainer="microk8s.raspberry@slainte.at"

---> Running in 88c7acfdf90e

Removing intermediate container 88c7acfdf90e

---> b023746a02d8

Step 4/8 : COPY go.mod ./

---> 599501f1547a

Step 5/8 : COPY *.go ./

---> 9f60a66c2ac0

Step 6/8 : RUN go build -o /hallo

---> Running in 03fd6b04a839

Removing intermediate container 03fd6b04a839

---> e62606c61d94

Step 7/8 : EXPOSE 80

---> Running in 2b3562abb146

Removing intermediate container 2b3562abb146

---> 121727752180

Step 8/8 : CMD ["hallo"]

---> Running in cfa9e78598dc

Removing intermediate container cfa9e78598dc

---> 52dfdc427a61

Successfully built 52dfdc427a61

Successfully tagged docker.registry:5000/hello-world:20211003

alfred@monitoring:~/dev/hello-world$

Anzeige im lokalen Repository.

alfred@monitoring:~/go$ docker images

REPOSITORY TAG IMAGE ID CREATED SIZE

docker.registry:5000/hello-world 20211003 ebe5a2422dca 24 seconds ago 2.1MB

alfred@monitoring:~/go$

Wir können den Inhalt untersuchen, indem wir den Docker in ein Tar-File exportieren.

alfred@monitoring:~/go$ docker ps -lq

fc63f4826cff

alfred@monitoring:~/go$

alfred@monitoring:~/go$ mkdir test

alfred@monitoring:~/go$ docker export fc63f4826cff > ./test/hello-world.tar

alfred@monitoring:~/go$ cd test/

alfred@monitoring:~/go/test$ tar -xf hello-world.tar

alfred@monitoring:~/go/test$ ll

total 4132

drwxrwxr-x 6 alfred alfred 4096 Oct 3 09:37 ./

drwxrwxr-x 4 alfred alfred 4096 Oct 3 09:37 ../

-rwxr-xr-x 1 alfred alfred 0 Oct 3 09:32 .dockerenv*

drwxr-xr-x 4 alfred alfred 4096 Oct 3 09:32 dev/

drwxr-xr-x 2 alfred alfred 4096 Oct 3 09:32 etc/

-rwxrwxr-x 1 alfred alfred 2097605 Sep 30 11:26 hello-world*

-rw-rw-r-- 1 alfred alfred 2105344 Oct 3 09:37 hello-world.tar

drwxr-xr-x 2 alfred alfred 4096 Oct 3 09:32 proc/

drwxr-xr-x 2 alfred alfred 4096 Oct 3 09:32 sys/

alfred@monitoring:~/go/test$

Wir können das Image auch lokal starten.

alfred@monitoring:~/dev/hello-world$ docker run docker.registry:5000/hello-world:20211003

hello world

alfred@monitoring:~/dev/hello-world$

Pushen in das remote-Repository. In dem Falle gibt es einen darunter liegenden den Layer schon.

alfred@monitoring:~/dev/hello-world$ docker push docker.registry:5000/hello-world:20211003

The push refers to repository [docker.registry:5000/hello-world]

6fa65fc3457a: Pushed

af86841dfdf3: Pushed

001055a1bdf7: Pushed

350991c52258: Pushed

93bd567aa306: Pushed

b48145e02449: Pushed

20211003: digest: sha256:cf16e57415939719367e5e17c09d2f17e36af2c1b84f24208f5750ea2c18b485 size: 1570

alfred@monitoring:~/dev/hello-world$

Anzeige aller vorhandenen Images im Remote Repository

alfred@monitoring:~/go$ curl docker.registry:5000/v2/_catalog

{"repositories":["hello-world"]}

alfred@monitoring:~/go$

alfred@monitoring:~/go$ curl docker.registry:5000/v2/hello-world/tags/list

{"name":"hello-world","tags":["20211003","20211001","20210830","20210930"]}

alfred@monitoring:~/go$

alfred@monitoring:~/go$ curl docker.registry:5000/v2/hello-world/manifests/20211003

{

"schemaVersion": 1,

"name": "hello-world",

"tag": "20211003",

"architecture": "arm64",

"fsLayers": [

{

"blobSum": "sha256:a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4"

},

{

"blobSum": "sha256:34b32ef7cc99133a34d56a284820986ce50c2ff9c1864da8557458489d7428a1"

}

],

"history": [

{

"v1Compatibility": "{\"architecture\":\"arm64\",\"config\":{\"Hostname\":\"\",\"Domainname\":\"\",\"User\":\"\",\"AttachStdin\":false,\"AttachStdout\":false,\"AttachStderr\":false,\"Tty\":false,\"OpenStdin\":false,\"StdinOnce\":false,\"Env\":[\"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\"],\"Cmd\":[\"/hello-world\"],\"Image\":\"sha256:c7642e609037b051e03214a85ddc50434de042a6b08c23bcac16dcb92629ee46\",\"Volumes\":null,\"WorkingDir\":\"\",\"Entrypoint\":null,\"OnBuild\":null,\"Labels\":null},\"container\":\"6d8917fc20a0fcbece354d49781ee260e15cb02df65c35efa5978f583948f9c4\",\"container_config\":{\"Hostname\":\"6d8917fc20a0\",\"Domainname\":\"\",\"User\":\"\",\"AttachStdin\":false,\"AttachStdout\":false,\"AttachStderr\":false,\"Tty\":false,\"OpenStdin\":false,\"StdinOnce\":false,\"Env\":[\"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\"],\"Cmd\":[\"/bin/sh\",\"-c\",\"#(nop) \",\"CMD [\\\"/hello-world\\\"]\"],\"Image\":\"sha256:c7642e609037b051e03214a85ddc50434de042a6b08c23bcac16dcb92629ee46\",\"Volumes\":null,\"WorkingDir\":\"\",\"Entrypoint\":null,\"OnBuild\":null,\"Labels\":{}},\"created\":\"2021-10-03T07:40:42.472956387Z\",\"docker_version\":\"20.10.7\",\"id\":\"031921ba69921f2705920021974bfdc500b6f42530f679aa56481bdbf1543d3e\",\"os\":\"linux\",\"parent\":\"91fdfdcec09b0c57e4f28bd9c1d199796b66e5162c2e0432f8a9dc689952e13c\",\"throwaway\":true,\"variant\":\"v8\"}"

},

{

"v1Compatibility": "{\"id\":\"91fdfdcec09b0c57e4f28bd9c1d199796b66e5162c2e0432f8a9dc689952e13c\",\"created\":\"2021-10-03T07:40:35.230309736Z\",\"container_config\":{\"Cmd\":[\"/bin/sh -c #(nop) COPY file:c46bbf237d2238c6f6241fa3c853f5d4861e4981bd19d09a99fa3f1ef76ed73a in / \"]}}"

}

],

"signatures": [

{

"header": {

"jwk": {

"crv": "P-256",

"kid": "AADV:MDEU:C5BD:UTIA:ME3T:42HB:WJUA:GTV4:DHU6:KPQM:OXBY:RRAS",

"kty": "EC",

"x": "PEw45Fk1zyjGc6iHHYh6_Ydk3mxLC8UE1mvlo_6XY24",

"y": "8e-Ad67SUvJMaYHjlyh05hqv7kcekIm6J-jR8It9unA"

},

"alg": "ES256"

},

"signature": "0iZv8OxENn9Oo_2eTyIQpfxFgBBsIW1z4p0AfkxP-bBxDE-1i5SN76FTwsLdTI9SRHnyY6R0_AoMSB1gWacdeA",

"protected": "eyJmb3JtYXRMZW5ndGgiOjIxMjUsImZvcm1hdFRhaWwiOiJDbjAiLCJ0aW1lIjoiMjAyMS0xMC0wM1QwODoxNjoxM1oifQ"

}

]

alfred@monitoring:~/go$

Somit ist das Image im Repository. Jetzt brauchen wir noch eine Service Definition.

alfred@pc1:/opt/cluster/go$ cat hello-world.yaml

---

apiVersion: apps/v1

kind: Deployment

metadata:

name: hello-world

#namespace: default

spec:

selector:

matchLabels:

app: hello-world

replicas: 1

template:

metadata:

labels:

app: hello-world

annotations:

sidecar.istio.io/inject: "false"

spec:

containers:

- name: hello-world

image: docker.registry:5000/hello-world:20211003

# resource limits

resources:

requests:

memory: "24Mi"

cpu: "500m" # half vcpu

limits:

memory: "64Mi"

cpu: "1000m" # one vcpu

env:

# currently no env vars used for this container

- name: FOO

value: bar

# check for lifetime liveness, restarts if dead

livenessProbe:

exec:

command:

- /hello-world

initialDelaySeconds: 5

periodSeconds: 10

# check for initial readyness

readinessProbe:

exec:

command:

- /hello-world

initialDelaySeconds: 3

periodSeconds: 3

restartPolicy: Always

dnsPolicy: ClusterFirst

---

apiVersion: v1

kind: Service

metadata:

name: hello-world-service

#namespace: default

labels:

app: hello-world

spec:

ports:

# port=available to other containers

- port: 1234

name: hello

# targetPort=exposed from inside container

targetPort: 1234

protocol: TCP

selector:

app: hello-world

---

alfred@pc1:/opt/cluster/go$


Nun installieren wir den Service.

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

deployment.apps/hello-world created

service/hello-world-service created

alfred@pc1:/opt/cluster/go$

Wir kontrollieren ob der Service richtig gestartet wird.

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

Name: hello-world-6bb7844865-4j5bw

Namespace: default

Priority: 0

Node: pc5/192.168.0.205

Start Time: Sun, 03 Oct 2021 20:56:03 +0200

Labels: app=hello-world

pod-template-hash=6bb7844865

Annotations: cni.projectcalico.org/podIP: 10.1.80.118/32

cni.projectcalico.org/podIPs: 10.1.80.118/32

sidecar.istio.io/inject: false

Status: Running

IP: 10.1.80.118

IPs:

IP: 10.1.80.118

Controlled By: ReplicaSet/hello-world-6bb7844865

Containers:

hello-world:

Container ID: containerd://e9d5a90c4ac98c57f9f27bdbe88b0bd5535d4e297ecbb103118a963d554615a9

Image: docker.registry:5000/hello-world:20211003

Image ID: docker.registry:5000/hello-world@sha256:1bb9b5564a34689396c097bb410a837d5e074b61caff822cb43921f425b09a50

Port: <none>

Host Port: <none>

State: Waiting

Reason: CrashLoopBackOff

Last State: Terminated

Reason: Completed

Exit Code: 0

Started: Sun, 03 Oct 2021 20:56:08 +0200

Finished: Sun, 03 Oct 2021 20:56:08 +0200

Ready: False

Restart Count: 1

Limits:

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.

K8s Applications mit MicroK8S auf Raspberry PI

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