This commit is contained in:
nutzer26
2022-12-16 12:21:57 +01:00
parent 199a7e11b5
commit 8ee05cb88d
60 changed files with 3516 additions and 2 deletions

View File

@@ -14,3 +14,12 @@ cdebug exec --privileged -it --image nixery.dev/shell/ps/vim/tshark my-distroles
https://github.com/iximiuz/cdebug
https://github.com/donaldzou/WGDashboard#-install
https://learnk8s.io/troubleshooting-deployments
https://artifacthub.io/
https://github.com/kubernetes/git-sync
https://grpc.io/docs/languages/python/basics/

14
git_sync/create_volume Normal file
View File

@@ -0,0 +1,14 @@
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv-git
labels:
app: git
spec:
storageClassName: manual
capacity:
storage: 10Gi
accessModes:
- ReadWriteOnce
hostPath:
path: "/mnt/data"

51
git_sync/deployment Normal file
View File

@@ -0,0 +1,51 @@
apiVersion: apps/v1
kind: Deployment
metadata:
creationTimestamp: null
labels:
app: git-sync
name: git-sync
spec:
replicas: 1
selector:
matchLabels:
app: git-sync
strategy: {}
template:
metadata:
creationTimestamp: null
labels:
app: git-sync
spec:
containers:
- image: nginx:latest
name: nginx
resources: {}
volumeMounts:
- name: workdir
mountPath: /usr/share/nginx/html
initContainers:
- image: registry.k8s.io/git-sync/git-sync:v3.6.2
name: gitsync
args:
- --repo=nutzer26@1:/home/nutzer01/content_repo.git
- --root=/tmp/git/root
- --ssh
- --one-time
volumeMounts:
- name: git-secret
mountPath: /etc/git-secret
- name: workdir
mountPath: "/tmp/git/root"
securityContext:
runAsUser: 65533
volumes:
- name: workdir
emptyDir: {}
- name: claim-pvc2
secret:
secretName: git-creds
defaultMode: 0400
securityContext:
fsGroup: 65533
status: {}

View File

@@ -0,0 +1 @@
ref: refs/heads/master

View File

@@ -0,0 +1,4 @@
[core]
repositoryformatversion = 0
filemode = true
bare = true

View File

@@ -0,0 +1 @@
Unnamed repository; edit this file 'description' to name the repository.

View File

@@ -0,0 +1,15 @@
#!/bin/sh
#
# An example hook script to check the commit log message taken by
# applypatch from an e-mail message.
#
# The hook should exit with non-zero status after issuing an
# appropriate message if it wants to stop the commit. The hook is
# allowed to edit the commit message file.
#
# To enable this hook, rename this file to "applypatch-msg".
. git-sh-setup
commitmsg="$(git rev-parse --git-path hooks/commit-msg)"
test -x "$commitmsg" && exec "$commitmsg" ${1+"$@"}
:

View File

@@ -0,0 +1,24 @@
#!/bin/sh
#
# An example hook script to check the commit log message.
# Called by "git commit" with one argument, the name of the file
# that has the commit message. The hook should exit with non-zero
# status after issuing an appropriate message if it wants to stop the
# commit. The hook is allowed to edit the commit message file.
#
# To enable this hook, rename this file to "commit-msg".
# Uncomment the below to add a Signed-off-by line to the message.
# Doing this in a hook is a bad idea in general, but the prepare-commit-msg
# hook is more suited to it.
#
# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p')
# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1"
# This example catches duplicate Signed-off-by lines.
test "" = "$(grep '^Signed-off-by: ' "$1" |
sort | uniq -c | sed -e '/^[ ]*1[ ]/d')" || {
echo >&2 Duplicate Signed-off-by lines.
exit 1
}

View File

@@ -0,0 +1,109 @@
#!/usr/bin/perl
use strict;
use warnings;
use IPC::Open2;
# An example hook script to integrate Watchman
# (https://facebook.github.io/watchman/) with git to speed up detecting
# new and modified files.
#
# The hook is passed a version (currently 1) and a time in nanoseconds
# formatted as a string and outputs to stdout all files that have been
# modified since the given time. Paths must be relative to the root of
# the working tree and separated by a single NUL.
#
# To enable this hook, rename this file to "query-watchman" and set
# 'git config core.fsmonitor .git/hooks/query-watchman'
#
my ($version, $time) = @ARGV;
# Check the hook interface version
if ($version == 1) {
# convert nanoseconds to seconds
# subtract one second to make sure watchman will return all changes
$time = int ($time / 1000000000) - 1;
} else {
die "Unsupported query-fsmonitor hook version '$version'.\n" .
"Falling back to scanning...\n";
}
my $git_work_tree;
if ($^O =~ 'msys' || $^O =~ 'cygwin') {
$git_work_tree = Win32::GetCwd();
$git_work_tree =~ tr/\\/\//;
} else {
require Cwd;
$git_work_tree = Cwd::cwd();
}
my $retry = 1;
launch_watchman();
sub launch_watchman {
my $pid = open2(\*CHLD_OUT, \*CHLD_IN, 'watchman -j --no-pretty')
or die "open2() failed: $!\n" .
"Falling back to scanning...\n";
# In the query expression below we're asking for names of files that
# changed since $time but were not transient (ie created after
# $time but no longer exist).
#
# To accomplish this, we're using the "since" generator to use the
# recency index to select candidate nodes and "fields" to limit the
# output to file names only.
my $query = <<" END";
["query", "$git_work_tree", {
"since": $time,
"fields": ["name"]
}]
END
print CHLD_IN $query;
close CHLD_IN;
my $response = do {local $/; <CHLD_OUT>};
die "Watchman: command returned no output.\n" .
"Falling back to scanning...\n" if $response eq "";
die "Watchman: command returned invalid output: $response\n" .
"Falling back to scanning...\n" unless $response =~ /^\{/;
my $json_pkg;
eval {
require JSON::XS;
$json_pkg = "JSON::XS";
1;
} or do {
require JSON::PP;
$json_pkg = "JSON::PP";
};
my $o = $json_pkg->new->utf8->decode($response);
if ($retry > 0 and $o->{error} and $o->{error} =~ m/unable to resolve root .* directory (.*) is not watched/) {
print STDERR "Adding '$git_work_tree' to watchman's watch list.\n";
$retry--;
qx/watchman watch "$git_work_tree"/;
die "Failed to make watchman watch '$git_work_tree'.\n" .
"Falling back to scanning...\n" if $? != 0;
# Watchman will always return all files on the first query so
# return the fast "everything is dirty" flag to git and do the
# Watchman query just to get it over with now so we won't pay
# the cost in git to look up each individual file.
print "/\0";
eval { launch_watchman() };
exit 0;
}
die "Watchman: $o->{error}.\n" .
"Falling back to scanning...\n" if $o->{error};
binmode STDOUT, ":utf8";
local $, = "\0";
print @{$o->{files}};
}

View File

@@ -0,0 +1,8 @@
#!/bin/sh
#
# An example hook script to prepare a packed repository for use over
# dumb transports.
#
# To enable this hook, rename this file to "post-update".
exec git update-server-info

View File

@@ -0,0 +1,14 @@
#!/bin/sh
#
# An example hook script to verify what is about to be committed
# by applypatch from an e-mail message.
#
# The hook should exit with non-zero status after issuing an
# appropriate message if it wants to stop the commit.
#
# To enable this hook, rename this file to "pre-applypatch".
. git-sh-setup
precommit="$(git rev-parse --git-path hooks/pre-commit)"
test -x "$precommit" && exec "$precommit" ${1+"$@"}
:

View File

@@ -0,0 +1,49 @@
#!/bin/sh
#
# An example hook script to verify what is about to be committed.
# Called by "git commit" with no arguments. The hook should
# exit with non-zero status after issuing an appropriate message if
# it wants to stop the commit.
#
# To enable this hook, rename this file to "pre-commit".
if git rev-parse --verify HEAD >/dev/null 2>&1
then
against=HEAD
else
# Initial commit: diff against an empty tree object
against=$(git hash-object -t tree /dev/null)
fi
# If you want to allow non-ASCII filenames set this variable to true.
allownonascii=$(git config --bool hooks.allownonascii)
# Redirect output to stderr.
exec 1>&2
# Cross platform projects tend to avoid non-ASCII filenames; prevent
# them from being added to the repository. We exploit the fact that the
# printable range starts at the space character and ends with tilde.
if [ "$allownonascii" != "true" ] &&
# Note that the use of brackets around a tr range is ok here, (it's
# even required, for portability to Solaris 10's /usr/bin/tr), since
# the square bracket bytes happen to fall in the designated range.
test $(git diff --cached --name-only --diff-filter=A -z $against |
LC_ALL=C tr -d '[ -~]\0' | wc -c) != 0
then
cat <<\EOF
Error: Attempt to add a non-ASCII file name.
This can cause problems if you want to work with people on other platforms.
To be portable it is advisable to rename the file.
If you know what you are doing you can disable this check using:
git config hooks.allownonascii true
EOF
exit 1
fi
# If there are whitespace errors, print the offending file names and fail.
exec git diff-index --check --cached $against --

View File

@@ -0,0 +1,13 @@
#!/bin/sh
#
# An example hook script to verify what is about to be committed.
# Called by "git merge" with no arguments. The hook should
# exit with non-zero status after issuing an appropriate message to
# stderr if it wants to stop the merge commit.
#
# To enable this hook, rename this file to "pre-merge-commit".
. git-sh-setup
test -x "$GIT_DIR/hooks/pre-commit" &&
exec "$GIT_DIR/hooks/pre-commit"
:

View File

@@ -0,0 +1,53 @@
#!/bin/sh
# An example hook script to verify what is about to be pushed. Called by "git
# push" after it has checked the remote status, but before anything has been
# pushed. If this script exits with a non-zero status nothing will be pushed.
#
# This hook is called with the following parameters:
#
# $1 -- Name of the remote to which the push is being done
# $2 -- URL to which the push is being done
#
# If pushing without using a named remote those arguments will be equal.
#
# Information about the commits which are being pushed is supplied as lines to
# the standard input in the form:
#
# <local ref> <local sha1> <remote ref> <remote sha1>
#
# This sample shows how to prevent push of commits where the log message starts
# with "WIP" (work in progress).
remote="$1"
url="$2"
z40=0000000000000000000000000000000000000000
while read local_ref local_sha remote_ref remote_sha
do
if [ "$local_sha" = $z40 ]
then
# Handle delete
:
else
if [ "$remote_sha" = $z40 ]
then
# New branch, examine all commits
range="$local_sha"
else
# Update to existing branch, examine new commits
range="$remote_sha..$local_sha"
fi
# Check for WIP commit
commit=`git rev-list -n 1 --grep '^WIP' "$range"`
if [ -n "$commit" ]
then
echo >&2 "Found WIP commit in $local_ref, not pushing"
exit 1
fi
fi
done
exit 0

View File

@@ -0,0 +1,169 @@
#!/bin/sh
#
# Copyright (c) 2006, 2008 Junio C Hamano
#
# The "pre-rebase" hook is run just before "git rebase" starts doing
# its job, and can prevent the command from running by exiting with
# non-zero status.
#
# The hook is called with the following parameters:
#
# $1 -- the upstream the series was forked from.
# $2 -- the branch being rebased (or empty when rebasing the current branch).
#
# This sample shows how to prevent topic branches that are already
# merged to 'next' branch from getting rebased, because allowing it
# would result in rebasing already published history.
publish=next
basebranch="$1"
if test "$#" = 2
then
topic="refs/heads/$2"
else
topic=`git symbolic-ref HEAD` ||
exit 0 ;# we do not interrupt rebasing detached HEAD
fi
case "$topic" in
refs/heads/??/*)
;;
*)
exit 0 ;# we do not interrupt others.
;;
esac
# Now we are dealing with a topic branch being rebased
# on top of master. Is it OK to rebase it?
# Does the topic really exist?
git show-ref -q "$topic" || {
echo >&2 "No such branch $topic"
exit 1
}
# Is topic fully merged to master?
not_in_master=`git rev-list --pretty=oneline ^master "$topic"`
if test -z "$not_in_master"
then
echo >&2 "$topic is fully merged to master; better remove it."
exit 1 ;# we could allow it, but there is no point.
fi
# Is topic ever merged to next? If so you should not be rebasing it.
only_next_1=`git rev-list ^master "^$topic" ${publish} | sort`
only_next_2=`git rev-list ^master ${publish} | sort`
if test "$only_next_1" = "$only_next_2"
then
not_in_topic=`git rev-list "^$topic" master`
if test -z "$not_in_topic"
then
echo >&2 "$topic is already up to date with master"
exit 1 ;# we could allow it, but there is no point.
else
exit 0
fi
else
not_in_next=`git rev-list --pretty=oneline ^${publish} "$topic"`
/usr/bin/perl -e '
my $topic = $ARGV[0];
my $msg = "* $topic has commits already merged to public branch:\n";
my (%not_in_next) = map {
/^([0-9a-f]+) /;
($1 => 1);
} split(/\n/, $ARGV[1]);
for my $elem (map {
/^([0-9a-f]+) (.*)$/;
[$1 => $2];
} split(/\n/, $ARGV[2])) {
if (!exists $not_in_next{$elem->[0]}) {
if ($msg) {
print STDERR $msg;
undef $msg;
}
print STDERR " $elem->[1]\n";
}
}
' "$topic" "$not_in_next" "$not_in_master"
exit 1
fi
<<\DOC_END
This sample hook safeguards topic branches that have been
published from being rewound.
The workflow assumed here is:
* Once a topic branch forks from "master", "master" is never
merged into it again (either directly or indirectly).
* Once a topic branch is fully cooked and merged into "master",
it is deleted. If you need to build on top of it to correct
earlier mistakes, a new topic branch is created by forking at
the tip of the "master". This is not strictly necessary, but
it makes it easier to keep your history simple.
* Whenever you need to test or publish your changes to topic
branches, merge them into "next" branch.
The script, being an example, hardcodes the publish branch name
to be "next", but it is trivial to make it configurable via
$GIT_DIR/config mechanism.
With this workflow, you would want to know:
(1) ... if a topic branch has ever been merged to "next". Young
topic branches can have stupid mistakes you would rather
clean up before publishing, and things that have not been
merged into other branches can be easily rebased without
affecting other people. But once it is published, you would
not want to rewind it.
(2) ... if a topic branch has been fully merged to "master".
Then you can delete it. More importantly, you should not
build on top of it -- other people may already want to
change things related to the topic as patches against your
"master", so if you need further changes, it is better to
fork the topic (perhaps with the same name) afresh from the
tip of "master".
Let's look at this example:
o---o---o---o---o---o---o---o---o---o "next"
/ / / /
/ a---a---b A / /
/ / / /
/ / c---c---c---c B /
/ / / \ /
/ / / b---b C \ /
/ / / / \ /
---o---o---o---o---o---o---o---o---o---o---o "master"
A, B and C are topic branches.
* A has one fix since it was merged up to "next".
* B has finished. It has been fully merged up to "master" and "next",
and is ready to be deleted.
* C has not merged to "next" at all.
We would want to allow C to be rebased, refuse A, and encourage
B to be deleted.
To compute (1):
git rev-list ^master ^topic next
git rev-list ^master next
if these match, topic has not merged in next at all.
To compute (2):
git rev-list master..topic
if this is empty, it is fully merged to "master".
DOC_END

View File

@@ -0,0 +1,24 @@
#!/bin/sh
#
# An example hook script to make use of push options.
# The example simply echoes all push options that start with 'echoback='
# and rejects all pushes when the "reject" push option is used.
#
# To enable this hook, rename this file to "pre-receive".
if test -n "$GIT_PUSH_OPTION_COUNT"
then
i=0
while test "$i" -lt "$GIT_PUSH_OPTION_COUNT"
do
eval "value=\$GIT_PUSH_OPTION_$i"
case "$value" in
echoback=*)
echo "echo from the pre-receive-hook: ${value#*=}" >&2
;;
reject)
exit 1
esac
i=$((i + 1))
done
fi

View File

@@ -0,0 +1,42 @@
#!/bin/sh
#
# An example hook script to prepare the commit log message.
# Called by "git commit" with the name of the file that has the
# commit message, followed by the description of the commit
# message's source. The hook's purpose is to edit the commit
# message file. If the hook fails with a non-zero status,
# the commit is aborted.
#
# To enable this hook, rename this file to "prepare-commit-msg".
# This hook includes three examples. The first one removes the
# "# Please enter the commit message..." help message.
#
# The second includes the output of "git diff --name-status -r"
# into the message, just before the "git status" output. It is
# commented because it doesn't cope with --amend or with squashed
# commits.
#
# The third example adds a Signed-off-by line to the message, that can
# still be edited. This is rarely a good idea.
COMMIT_MSG_FILE=$1
COMMIT_SOURCE=$2
SHA1=$3
/usr/bin/perl -i.bak -ne 'print unless(m/^. Please enter the commit message/..m/^#$/)' "$COMMIT_MSG_FILE"
# case "$COMMIT_SOURCE,$SHA1" in
# ,|template,)
# /usr/bin/perl -i.bak -pe '
# print "\n" . `git diff --cached --name-status -r`
# if /^#/ && $first++ == 0' "$COMMIT_MSG_FILE" ;;
# *) ;;
# esac
# SOB=$(git var GIT_COMMITTER_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p')
# git interpret-trailers --in-place --trailer "$SOB" "$COMMIT_MSG_FILE"
# if test -z "$COMMIT_SOURCE"
# then
# /usr/bin/perl -i.bak -pe 'print "\n" if !$first_line++' "$COMMIT_MSG_FILE"
# fi

View File

@@ -0,0 +1,128 @@
#!/bin/sh
#
# An example hook script to block unannotated tags from entering.
# Called by "git receive-pack" with arguments: refname sha1-old sha1-new
#
# To enable this hook, rename this file to "update".
#
# Config
# ------
# hooks.allowunannotated
# This boolean sets whether unannotated tags will be allowed into the
# repository. By default they won't be.
# hooks.allowdeletetag
# This boolean sets whether deleting tags will be allowed in the
# repository. By default they won't be.
# hooks.allowmodifytag
# This boolean sets whether a tag may be modified after creation. By default
# it won't be.
# hooks.allowdeletebranch
# This boolean sets whether deleting branches will be allowed in the
# repository. By default they won't be.
# hooks.denycreatebranch
# This boolean sets whether remotely creating branches will be denied
# in the repository. By default this is allowed.
#
# --- Command line
refname="$1"
oldrev="$2"
newrev="$3"
# --- Safety check
if [ -z "$GIT_DIR" ]; then
echo "Don't run this script from the command line." >&2
echo " (if you want, you could supply GIT_DIR then run" >&2
echo " $0 <ref> <oldrev> <newrev>)" >&2
exit 1
fi
if [ -z "$refname" -o -z "$oldrev" -o -z "$newrev" ]; then
echo "usage: $0 <ref> <oldrev> <newrev>" >&2
exit 1
fi
# --- Config
allowunannotated=$(git config --bool hooks.allowunannotated)
allowdeletebranch=$(git config --bool hooks.allowdeletebranch)
denycreatebranch=$(git config --bool hooks.denycreatebranch)
allowdeletetag=$(git config --bool hooks.allowdeletetag)
allowmodifytag=$(git config --bool hooks.allowmodifytag)
# check for no description
projectdesc=$(sed -e '1q' "$GIT_DIR/description")
case "$projectdesc" in
"Unnamed repository"* | "")
echo "*** Project description file hasn't been set" >&2
exit 1
;;
esac
# --- Check types
# if $newrev is 0000...0000, it's a commit to delete a ref.
zero="0000000000000000000000000000000000000000"
if [ "$newrev" = "$zero" ]; then
newrev_type=delete
else
newrev_type=$(git cat-file -t $newrev)
fi
case "$refname","$newrev_type" in
refs/tags/*,commit)
# un-annotated tag
short_refname=${refname##refs/tags/}
if [ "$allowunannotated" != "true" ]; then
echo "*** The un-annotated tag, $short_refname, is not allowed in this repository" >&2
echo "*** Use 'git tag [ -a | -s ]' for tags you want to propagate." >&2
exit 1
fi
;;
refs/tags/*,delete)
# delete tag
if [ "$allowdeletetag" != "true" ]; then
echo "*** Deleting a tag is not allowed in this repository" >&2
exit 1
fi
;;
refs/tags/*,tag)
# annotated tag
if [ "$allowmodifytag" != "true" ] && git rev-parse $refname > /dev/null 2>&1
then
echo "*** Tag '$refname' already exists." >&2
echo "*** Modifying a tag is not allowed in this repository." >&2
exit 1
fi
;;
refs/heads/*,commit)
# branch
if [ "$oldrev" = "$zero" -a "$denycreatebranch" = "true" ]; then
echo "*** Creating a branch is not allowed in this repository" >&2
exit 1
fi
;;
refs/heads/*,delete)
# delete branch
if [ "$allowdeletebranch" != "true" ]; then
echo "*** Deleting a branch is not allowed in this repository" >&2
exit 1
fi
;;
refs/remotes/*,commit)
# tracking branch
;;
refs/remotes/*,delete)
# delete tracking branch
if [ "$allowdeletebranch" != "true" ]; then
echo "*** Deleting a tracking branch is not allowed in this repository" >&2
exit 1
fi
;;
*)
# Anything else (is there anything else?)
echo "*** Update hook: unknown type of update to ref $refname of type $newrev_type" >&2
exit 1
;;
esac
# --- Finished
exit 0

View File

@@ -0,0 +1,6 @@
# git ls-files --others --exclude-from=.git/info/exclude
# Lines that start with '#' are comments.
# For a project mostly in C, the following would be a good set of
# exclude patterns (uncomment them if you want to use them):
# *.[oa]
# *~

13
git_sync/pvc Normal file
View File

@@ -0,0 +1,13 @@
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pvc-claim-2
labels:
app: git
spec:
storageClassName: manual
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 3Gi

128
k3d/blue-green/doku Normal file
View File

@@ -0,0 +1,128 @@
Blue Green Deployment
create version 1 and 2 and services
# prepare namespace
mkdir ~/blue-green && cd ~/blue-green
kubectl create namespace blue-green
kubectl config set-context --current --namespace blue-green
# create manifests
cat >nginx-v1.yaml <<EOF
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: web
version: V1.0.0
name: webv1
spec:
replicas: 1
selector:
matchLabels:
app: web
version: V1.0.0
template:
metadata:
labels:
app: web
version: V1.0.0
spec:
containers:
- image: nginx:1.19.3
name: nginx
ports:
- name: http
containerPort: 80
EOF
cat >nginx-v2.yaml <<EOF
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: web
version: V2.0.0
name: webv2
spec:
replicas: 1
selector:
matchLabels:
app: web
version: V2.0.0
template:
metadata:
labels:
app: web
version: V2.0.0
spec:
containers:
- image: nginx:1.19.8
name: nginx
ports:
- name: http
containerPort: 80
EOF
cat >nginx-svc.yaml <<EOF
apiVersion: v1
kind: Service
metadata:
labels:
app: web
name: nginx
spec:
ports:
- port: 80
protocol: TCP
targetPort: 80
selector:
app: web
version: V1.0.0
EOF
Deployment from blue to green
# deploy blue
kubectl apply -f nginx-v1.yaml
kubectl apply -f nginx-svc.yaml
kubectl describe deployment webv1
kubectl describe svc nginx
kubectl get ep nginx
# deploy green
kubectl apply -f nginx-v2.yaml
# traffic shift
kubectl patch service nginx --patch '{"spec":{"selector":{"version":"V2.0.0"}}}'
# Test if the second deployment was successful
kubectl describe deployment webv2
kubectl describe svc nginx
kubectl get ep nginx
# cleanup v1
kubectl delete deploy webv1
WARNING:Traefik shift don't change established connection!!
kubectl run nc -it --rm --image curlimages/curl -- /bin/sh
nc nginx.blue-green.svc.cluster.local 80
GET /index.html HTTP/1.1
Host: localhost
...
# switch at other terminal the load with patch
#kubectl patch service nginx --patch '{"spec":{"selector":{"version":"V1.0.0"}}}'
GET /index.html HTTP/1.1
Host: localhost
# same server/pod answer ...

View File

@@ -0,0 +1,14 @@
apiVersion: v1
kind: Service
metadata:
labels:
app: web
name: nginx
spec:
ports:
- port: 80
protocol: TCP
targetPort: 80
selector:
app: web
version: V1.0.0

View File

@@ -0,0 +1,25 @@
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: web
version: V1.0.0
name: webv1
spec:
replicas: 1
selector:
matchLabels:
app: web
version: V1.0.0
template:
metadata:
labels:
app: web
version: V1.0.0
spec:
containers:
- image: nginx:1.19.3
name: nginx_new
ports:
- name: http
containerPort: 80

View File

@@ -0,0 +1,25 @@
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: web
version: V2.0.0
name: webv2
spec:
replicas: 1
selector:
matchLabels:
app: web
version: V2.0.0
template:
metadata:
labels:
app: web
version: V2.0.0
spec:
containers:
- image: nginx:1.19.8
name: nginx_old
ports:
- name: http
containerPort: 80

View File

@@ -73,4 +73,16 @@ echo "deb https://apt.kubernetes.io/ kubernetes-xenial main" \
sudo apt-get update
sudo apt-get install -y kubectl
source <(kubectl completion bash)
source <(k3d completion bash)
curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3
chmod 700 get_helm.sh
./get_helm.sh
source <(helm completion bash)
default Namespace nächste commands
kubectl config set-context --current --namespace whoami

201
k3d/pod_init/doku Normal file
View File

@@ -0,0 +1,201 @@
Pod init container
https://kubernetes.io/docs/concepts/workloads/pods/init-containers/
A Pod can have multiple containers running apps within it, but it can also have one or more init containers, which are run before the app containers are started.
Init containers are exactly like regular containers, except:
Init containers always run to completion.
Each init container must complete successfully before the next one starts.
If a Pod's init container fails, the kubelet repeatedly restarts that init container until it succeeds. However, if the Pod has a restartPolicy of Never, and an init container fails during startup of that Pod, Kubernetes treats the overall Pod as failed.
kubectl delete service whoami
cat >myapp-pod.yaml <<EOF
apiVersion: v1
kind: Pod
metadata:
name: myapp-pod
labels:
app: myapp
spec:
containers:
- name: myapp-container
image: busybox:1.28
command: ['sh', '-c', 'echo The app is running! && sleep 30']
initContainers:
- name: init-whoami
image: busybox:1.28
command: ['sh', '-c', "until nslookup whoami.\$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local; do echo waiting for whoami; sleep 2; done"]
EOF
kubectl apply -f myapp-pod.yaml
kubectl describe pod myapp-pod
# initContainer not ready
kubectl apply -f service.yaml
kubectl describe pod myapp-pod
https://github.com/groundnuty/k8s-wait-for
cat >myapp-pod-exists.yaml <<EOF
apiVersion: v1
kind: Pod
metadata:
name: myapp-pod-exists
labels:
app: myapp
spec:
containers:
- name: myapp-container
image: busybox:1.28
command: ['sh', '-c', 'echo The app is running! && sleep 30']
initContainers:
- name: init-whoami
image: busybox:1.28
command: ['sh', '-c', "until nslookup whoami.\$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local; do echo waiting for whoami; sleep 2; done"]
- name: wait-for-whoami-pods
image: ghcr.io/groundnuty/k8s-wait-for:v1.7
imagePullPolicy: IfNotPresent
args:
- "pod-wr"
- "-lapp=whoami"
EOF
kubectl scale deployment whoami --replicas=0
kubectl apply -f myapp-pod-exists.yaml
kubectl create role pod-reader \
--verb=get --verb=list --verb=watch \
--resource=pods,services,deployments
kubectl get role pod-reader -o yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
creationTimestamp: "2022-10-27T13:11:32Z"
name: pod-reader
namespace: whoami-1
resourceVersion: "48787"
uid: 2aadcee7-66bc-4ebe-8acc-5f76e2065480
rules:
- apiGroups:
- ""
resources:
- pods
- services
verbs:
- get
- listhttps://artifacthub.io/
- watch
- apiGroups:
- apps
resources:
- deployments
verbs:
- get
- list
- watch
kubectl create rolebinding default-pod-reader \
--role=pod-reader \
--serviceaccount=whoami-1:default \
--namespace=whoami-1
kubectl get rolebindings.rbac.authorization.k8s.io default-pod-reader -o yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
creationTimestamp: "2022-10-27T13:15:02Z"
name: default-pod-reader
namespace: whoami-1
resourceVersion: "48886"https://artifacthub.io/
apiGroup: rbac.authorization.k8s.io
kind: Role
name: pod-reader
subjects:
- kind: ServiceAccount
name: default
namespace: whoami-1
kubectl auth can-i list deployments.apps \
--as system:serviceaccount:whoami-1:default
yes
kubectl auth can-i create deployments.apps \
--as system:serviceaccount:whoami-1:default
no
kubectl scale deployment whoami --replicas=1
kubectl logs myapp-pod-exists -c wait-for-whoami-pods
[2022-10-27 13:34:14] Waiting for pod -lapp=whoami...
[2022-10-27 13:34:16] pod -lapp=whoami is ready.
kubectl get pods
NAME READY STATUS RESTARTS AGE
...
myapp-pod-exists 0/1 Completed 1 (36s ago) 31m
Postgres initContainer
apiVersion: apps/v1beta1
kind: Deployment
metadata:
name: webapp
spec:
template:
metadata:
labels:
app: webapp
spec:
volumes:
- name: config-volume
configMap:
name: app-config
initContainers:
- name: check-db-ready
image: postgres:15
command: ['sh', '-c',
'until pg_isready -h postgres -p 5432;
do echo waiting for database; sleep 2; done;']
Git Sync
https://github.com/kubernetes/git-sync
https://github.com/kubernetes/git-sync/blob/master/docs/ssh.md
https://github.com/kubernetes/git-sync/blob/master/docs/kubernetes.md
https://www.heise.de/tipps-tricks/SSH-Key-erstellen-so-geht-s-4400280.html
Challenges:
Create SSH Key
Create local git repo
Create a secret with SSH Key
Create a pod with git sync initContainer from local repo
Create SSH Key
ssh-keygen -t rsa -b 4096 -f ~/.ssh/id_cnbc-rsa
# without password...
Example to use Git Sync
# make a directory (owned by you) for the volume
export DIR="/tmp/git-data"
mkdir -p $DIR
# run the container (as your own UID)
# run the container
docker container run -d \
-v $DIR:/tmp/git \
-u$(id -u):$(id -g) \
k8s.gcr.io/git-sync/git-sync:v4.0.0 \
--repo=https://github.com/kubernetes/git-sync \
--root=/tmp/git/root \
--period=30s
# run an nginx container to serve the content
docker container run -d \
-p 8080:80 \
-v $DIR:/usr/share/nginx/html \
nginx

View File

@@ -0,0 +1,31 @@
apiVersion: apps/v1
kind: Deployment
metadata:
creationTimestamp: null
labels:
app: web
name: web
spec:
replicas: 1
selector:
matchLabels:
app: web
strategy: {}
template:
metadata:
creationTimestamp: null
labels:
app: web
spec:
containers:
- image: bee42/whoami:2.2.0
name: whoami
ports:
- containerPort: 80
resources:
requests:
memory: "64Mi"
cpu: "250m"
limits:
memory: "128Mi"
cpu: "500m"

274
k3d/stress/doku Normal file
View File

@@ -0,0 +1,274 @@
Deployment with Ressource Constraints
https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/
It's a good practice to assign a CPU request and a CPU limit to a container. Containers cannot use more CPU than the configured limit. Provided the system has CPU time free, a container is guaranteed to be allocated as much CPU as it requests.
mkdir ~/stress && cd ~/stress
kubectl create namespace stress
kubectl config set-context --current --namespace stress
cat >deployment2.yaml <<EOF
apiVersion: apps/v1
kind: Deployment
metadata:
creationTimestamp: null
labels:
app: web
name: web
spec:
replicas: 1
selector:
matchLabels:
app: web
strategy: {}
template:
metadata:
creationTimestamp: null
labels:
app: web
spec:
containers:
- image: bee42/whoami:2.2.0
name: whoami
ports:
- containerPort: 80
resources:
requests:
memory: "64Mi"
cpu: "250m"
limits:
memory: "128Mi"
cpu: "500m"
EOF
kubectl apply -f deployment2.yaml
kubectl get pods
kubectl get all
kubectl describe deployment web
kubectl rollout history deployment web
# set change cause
kubectl annotate deployment web kubernetes.io/change-cause='set cpu limit 500'
kubectl rollout history deployment web
https://kubernetes.io/docs/tasks/configure-pod-container/quality-service-pod/
QoS
https://kubernetes.io/docs/tasks/administer-cluster/manage-resources/quota-pod-namespace/
ResoureQuota
Generate Stress
https://linux.die.net/man/1/stress
create your own stress tool
mkdir -p ~/stress && cd ~/stress
cat >Dockerfile <<EOF
FROM ubuntu
RUN apt-get update && apt-get install -y stress && rm -rf /var/lib/apt/lists/*
ENTRYPOINT ["/usr/bin/stress", "--verbose"]
CMD []
EOF
docker build -t 127.0.0.1:5000/bee42/stress .
docker push 127.0.0.1:5000/bee42/stress
Todo:
apply the pod
check with kubectl top pods
cat >pod.yaml <<EOF
apiVersion: v1
kind: Pod
metadata:
name: cpu-demo
spec:
containers:
- name: cpu
image: cnbc-registry:5000/bee42/stress
resources:
limits:
cpu: "1"
requests:
cpu: "0.5"
args:
- --cpu
- "2"
EOF
kubectl apply -f pod.yaml
kubectl describe pod cpu-demo
# wait a minute
kubectl top pods
NAME CPU(cores) MEMORY(bytes)
cpu-demo 1962m 1Mi
hey 0m 0Mi
load 0m 1Mi
web-7cdc98f947-2n2dp 0m 3Mi
web-7cdc98f947-gn2cg 0m 4Mi
# Consume more cpu the limits set!
# PLEASE KILL this pod
kubectl delete pod cpu-demo --force=true --grace-period=0
stress-deploy.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: cpu-demo
labels:
app: cpu-demo
spec:
replicas: 4
selector:
matchLabels:
app: cpu-demo
template:
metadata:
labels:
app: cpu-demo
spec:
containers:
- name: stress
image: cnbc-registry:5000/bee42/stress
resources:
limits:
cpu: "1"
requests:
cpu: "0.5"
args:
- --cpu
- "2"
nodeName: k3d-cnbc-agent-1
kubectl apply -f stress-deploy.yaml
kubectl top pods
kubectl top nodes
NAME CPU(cores) MEMORY(bytes)
cpu-demo-595664dd8-lschw 1022m 1Mi
cpu-demo-595664dd8-npx4w 975m 1Mi
cpu-demo-595664dd8-p249m 993m 1Mi
cpu-demo-595664dd8-twn84 940m 1Mi
web-588896757f-52gx9 0m 1Mi
kubectl scale deploy cpu-demo --replicas=3
sleep 45
kubectl top nodes
kubectl top pods
NAME CPU(cores) MEMORY(bytes)
cpu-demo-595664dd8-npx4w 1017m 1Mi
cpu-demo-595664dd8-p249m 988m 1Mi
cpu-demo-595664dd8-twn84 980m 1Mi
web-588896757f-52gx9 1m 1Mi
https://kubernetes.io/docs/tasks/administer-cluster/cpu-management-policies/
Kubelet parameter
Tipp:
use imagePullSecerts to auth container registries
https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/
Memory Overload
https://www.cyberciti.biz/faq/stress-test-linux-unix-server-with-stress-ng/
https://sysdig.com/blog/troubleshoot-kubernetes-oom/
k3d node create --cluster cnbc --role agent --memory 2G k3d-cnbc-agent-2
kubectl get nodes
# wait for ready
kubectl apply -f mem-deploy.yaml
kubectl top nodes
# OK!
kubectl scale deploy mem-demo --replicas=4
# Hups...
kubectl scale deploy mem-demo --replicas=5
# wait 60 secs
kubectl get pods -w
NAME READY STATUS RESTARTS AGE
web-588896757f-52gx9 1/1 Running 0 60m
mem-demo-67998d7456-4ntqw 1/1 Running 0 4m20s
mem-demo-67998d7456-htvnn 1/1 Running 0 4m20s
mem-demo-67998d7456-4f2wd 1/1 Running 0 2m2s
mem-demo-67998d7456-kx4xv 1/1 Running 2 (49s ago) 4m20s
mem-demo-67998d7456-d86cs 0/1 OOMKilled 2 (25s ago) 58s
mem-demo-67998d7456-d86cs 0/1 CrashLoopBackOff 2 (12s ago) 65s
mem-demo-67998d7456-d86cs 1/1 Running 3 (28s ago) 81s
mem-demo-67998d7456-4ntqw 0/1 OOMKilled 0 4m44s
mem-demo-67998d7456-4ntqw 1/1 Running 1 (2s ago) 4m45s
mem-demo-67998d7456-4f2wd 0/1 OOMKilled 0 2m29s
mem-demo-67998d7456-4f2wd 1/1 Running 1 (2s ago) 2m30s
mem-demo-67998d7456-d86cs 0/1 OOMKilled 3 (35s ago) 88s
mem-demo-67998d7456-d86cs 0/1 CrashLoopBackOff 3 (12s ago) 99s
# fix: scale down
kubectl scale deploy mem-demo --replicas=4
# cleanup deploy
kubectl delete -f mem-deploy.yaml
# drain node
kubectl drain k3d-k3d-cnbc-agent-2-0
k3d node delete k3d-k3d-cnbc-agent-2-0
kubectl delete node k3d-k3d-cnbc-agent-2-0
mem-deploy.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: mem-demo
labels:
app: mem-demo
spec:
replicas: 3
selector:
matchLabels:
app: mem-demo
template:
metadata:
labels:
app: mem-demo
spec:
containers:
- name: stress
image: cnbc-registry:5000/bee42/stress
resources:
limits:
memory: "500Mi"
requests:
memory: "128Mi"
args:
- "-m"
- "1"
- "--vm-bytes"
- "490M"
nodeName: k3d-k3d-cnbc-agent-2-0
Kubernetes Failures
https://codeberg.org/hjacobs/kubernetes-failure-stories
https://medium.com/omio-engineering/cpu-limits-and-aggressive-throttling-in-kubernetes-c5b20bd8a718
https://home.robusta.dev/blog/stop-using-cpu-limits
Best practices for CPU limits and requests on Kubernetes
Use CPU requests for everything
Make sure they are accurate
Do not use CPU limits.
What about memory limits and requests?
Always use memory limits
Always use memory requests
Always set your memory requests equal to your limits

14
k3d/volumes/pv Normal file
View File

@@ -0,0 +1,14 @@
apiVersion: v1
kind: PersistentVolume
metadata:
name: task-pv-volume
labels:
type: local
spec:
storageClassName: manual
capacity:
storage: 10Gi
accessModes:
- ReadWriteOnce
hostPath:
path: "/mnt/data"

0
k3d/volumes/pvc Normal file
View File

10
k8s/carpool/Dockerfile Normal file
View File

@@ -0,0 +1,10 @@
# syntax=docker/dockerfile:1
FROM python:3.8-slim-buster
WORKDIR /app
COPY requirements.txt requirements.txt
RUN pip3 install --disable-pip-version-check -r requirements.txt
COPY . .
ENV FLASK_APP=python_rest
EXPOSE 5000
STOPSIGNAL SIGINT
CMD [ "python3", "-m" , "flask", "run", "--host=0.0.0.0"]

View File

@@ -0,0 +1,23 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: carpool
labels:
app: carpool
spec:
replicas: 1
selector:
matchLabels:
app: carpool
template:
metadata:
labels:
app: carpool
spec:
containers:
- name: carpool
image: cnbc-registry:5000/bee42/carpool:0.1.0
imagePullPolicy: Always
env:
- name: FLASK_APP
value: python_rest

714
k8s/carpool/doku Normal file
View File

@@ -0,0 +1,714 @@
carpool examples
mkdir ~/carpool && cd ~/carpool
# create app
vi python_rest.py
vi requirements.txt
vi Dockerfile
python_rest.py
python_rest.py
from flask import Flask, request, jsonify
from flask_sqlalchemy import SQLAlchemy
from flask_marshmallow import Marshmallow, fields
from flask_cors import CORS
 
# Init app
app = Flask(__name__)
 
#enable CORS
CORS(app)
# connect to already existing and running Database
app.config['SQLALCHEMY_DATABASE_URI'] = 'postgresql://postgres:cnbc@postgres:5432/esentricar'
 
# not important but otherwise we get a warning every time
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
 
#Init db
db = SQLAlchemy(app)
#Init ma
ma = Marshmallow(app)
 
# Pool Car Class/Model
class Pool_Car(db.Model):
 
#define table, in our case already existing
__tablename__ = 'cars'
car_id = db.Column(db.Integer, primary_key=True)
license_plate = db.Column(db.String(30), unique=True)
car_type = db.Column(db.String(20))
fuel = db.Column(db.String(20))
number_of_seats =db.Column(db.Integer)
 
 
# set class attributes
def __init__(self, license_plate, car_type, fuel, number_of_seats):
self.license_plate = license_plate
self.car_type = car_type
self.fuel = fuel
self.number_of_seats = number_of_seats
 
class Pool_CarSchema(ma.Schema):
class Meta:
fields = ('car_id','license_plate','car_type','fuel','number_of_seats')
 
# Init schema
pool_car_schema = Pool_CarSchema()
pool_cars_schema = Pool_CarSchema(many=True)
 
 
# Create a Pool_Car
@app.route('/car', methods=['POST'])
def add_pool_car():
# Get request data as json
car_entity = request.get_json()
license_plate= car_entity.get('license_plate')
car_type = car_entity.get('car_type')
fuel = car_entity.get('fuel')
number_of_seats = car_entity.get('number_of_seats')
 
new_pool_car = Pool_Car(license_plate, car_type, fuel, number_of_seats)
 
db.session.add(new_pool_car)
db.session.commit()
 
return pool_car_schema.jsonify(new_pool_car)
 
# Get car_id,license_plate,car_type of all products of the table
@app.route('/car', methods=['GET'])
def get_pool_cars():
all_pool_cars = Pool_Car.query.all()
result = pool_cars_schema.dump(all_pool_cars)
car_list= []
for item in result:
car_details = { "car_id":None, "license_plate":None, "car_type":None}
car_details['car_id'] = item['car_id']
car_details['license_plate'] = item['license_plate']
car_details['car_type'] = item['car_type']
car_list.append(car_details)
return jsonify(car_list)
 
# Get Single Products
@app.route('/car/<car_id>', methods=['GET'])
def get_pool_car(car_id):
pool_car = Pool_Car.query.get(car_id)
return pool_car_schema.jsonify(pool_car)
 
# Delete Product
@app.route('/car/<car_id>', methods=['DELETE'])
def delete_pool_car(car_id):
pool_car = Pool_Car.query.get(car_id)
db.session.delete(pool_car)
db.session.commit()
 
return pool_car_schema.jsonify(pool_car)
 
 
if __name__ == '__main__':
app.run(debug=True) #port='5002'
requirements.txt
requirements.txt
Flask==1.1.1
Flask-Cors==3.0.8
flask-marshmallow==0.10.1
Flask-SQLAlchemy==2.4.1
werkzeug==2.0.2
marshmallow==3.2.2
SQLAlchemy==1.3.11
marshmallow-sqlalchemy==0.19.0
psycopg2-binary==2.8.4
itsdangerous==2.0.1
Jinja2==3.0.3
Dockerfile
Dockerfile
# syntax=docker/dockerfile:1
FROM python:3.8-slim-buster
WORKDIR /app
COPY requirements.txt requirements.txt
RUN pip3 install --disable-pip-version-check -r requirements.txt
COPY . .
ENV FLASK_APP=python_rest
EXPOSE 5000
STOPSIGNAL SIGINT
CMD [ "python3", "-m" , "flask", "run", "--host=0.0.0.0"]
Build app
docker build -t bee42/carpool:0.1.0 .
curl http://127.0.0.1:5000/v2/_catalog
{"repositories":[]}
docker tag bee42/carpool:0.1.0 127.0.0.1:5000/bee42/carpool:0.1.0
docker push 127.0.0.1:5000/bee42/carpool:0.1.0
curl http://127.0.0.1:5000/v2/_catalog
{"repositories":["bee42/carpool"]}
curl http://127.0.0.1:5000/v2/bee42/carpool/tags/list
{"name":"bee42/carpool","tags":["0.1.0"]}
CarPool Deploy Postgres
New Kubernetes Manifests:
Persistence Volume
Config Map
mkdir ~/carpool/postgres && cd ~/carpool/postgres
# define kubernetes manifests
postgres-deploy.yaml
postgres-deploy.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: postgres
spec:
replicas: 1
selector:
matchLabels:
app: postgres
template:
metadata:
labels:
app: postgres
spec:
containers:
- name: postgres
image: postgres:10.4
imagePullPolicy: "IfNotPresent"
ports:
- containerPort: 5432
envFrom:
- configMapRef:
name: postgres-config
volumeMounts:
- mountPath: /var/lib/postgresql/data
name: postgredb
- name: config
mountPath: "/docker-entrypoint-initdb.d"
readOnly: true
volumes:
- name: config
configMap:
name: carpool
items:
- key: "esentricar.sql"
path: "esentricar.sql"
- name: postgredb
persistentVolumeClaim:
claimName: postgres-pv-claim
postgres-schema-cm.yaml
postgres-schema-cm.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: carpool
data:
esentricar.sql: |
CREATE DATABASE esentricar;
\c esentricar;
CREATE TABLE cars (
car_id SERIAL PRIMARY KEY,
license_plate varchar(30) NOT NULL,
car_type varchar(30) NOT NULL,
fuel varchar(30) NOT NULL,
number_of_seats integer NOT NULL
);
CREATE UNIQUE INDEX cars_license_plate
ON cars (license_plate);
postgres-config.yaml
postgres-config.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: postgres-config
labels:
app: postgres
data:
POSTGRES_DB: postgresdb
POSTGRES_USER: postgres
POSTGRES_PASSWORD: cnbc
postgres-service.yaml
postgres-service.yaml
apiVersion: v1
kind: Service
metadata:
labels:
app: postgres
name: postgres
spec:
ports:
- name: postgres
port: 5432
protocol: TCP
targetPort: 5432
selector:
app: postgres
type: ClusterIP
postgres-pv-claim.yaml
postgres-pv-claim.yaml
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: postgres-pv-claim
labels:
app: postgres
spec:
storageClassName: local-path
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
Create database
kubectl create namespace carpool
kubectl config set-context --current --namespace=carpool
# apply all manifests
kubectl apply -f .
kubectl get all
kubectl get configmaps
NAME DATA AGE
kube-root-ca.crt 1 21m
postgres-config 3 42s
carpool 1 42s
kubectl get pvc,pv
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
persistentvolumeclaim/postgres-pv-claim Bound pvc-e6e7ba0f-ff3e-4bfa-be1b-4db6629d027e 1Gi RWO local-path 84s
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
persistentvolume/pvc-e6e7ba0f-ff3e-4bfa-be1b-4db6629d027e 1Gi RWO Delete Bound carpool/postgres-pv-claim local-path 79s
kubectl describe pv
Name: pvc-e6e7ba0f-ff3e-4bfa-be1b-4db6629d027e
Labels: <none>
Annotations: pv.kubernetes.io/provisioned-by: rancher.io/local-path
Finalizers: [kubernetes.io/pv-protection]
StorageClass: local-path
Status: Bound
Claim: carpool/postgres-pv-claim
Reclaim Policy: Delete
Access Modes: RWO
VolumeMode: Filesystem
Capacity: 1Gi
Node Affinity:
Required Terms:
Term 0: kubernetes.io/hostname in [k3d-cnbc-agent-1]
Message:
Source:
Type: HostPath (bare host directory volume)
Path: /var/lib/rancher/k3s/storage/pvc-e6e7ba0f-ff3e-4bfa-be1b-4db6629d027e_carpool_postgres-pv-claim
HostPathType: DirectoryOrCreate
Events: <none>
kubectl logs postgres-65974d6d58-72vk5
The files belonging to this database system will be owned by user "postgres".
This user must also own the server process.
The database cluster will be initialized with locale "en_US.utf8".
The default database encoding has accordingly been set to "UTF8".
The default text search configuration will be set to "english".
Data page checksums are disabled.
fixing permissions on existing directory /var/lib/postgresql/data ... ok
creating subdirectories ... ok
selecting default max_connections ... 100
selecting default shared_buffers ... 128MB
selecting dynamic shared memory implementation ... posix
creating configuration files ... ok
running bootstrap script ... ok
performing post-bootstrap initialization ... ok
syncing data to disk ... ok
Success. You can now start the database server using:
pg_ctl -D /var/lib/postgresql/data -l logfile start
WARNING: enabling "trust" authentication for local connections
You can change this by editing pg_hba.conf or using the option -A, or
--auth-local and --auth-host, the next time you run initdb.
waiting for server to start....2022-03-08 12:30:20.872 UTC [42] LOG: listening on Unix socket "/var/run/postgresql/.s.PGSQL.5432"
2022-03-08 12:30:20.901 UTC [43] LOG: database system was shut down at 2022-03-08 12:30:20 UTC
2022-03-08 12:30:20.911 UTC [42] LOG: database system is ready to accept connections
done
server started
CREATE DATABASE
ALTER ROLE
/usr/local/bin/docker-entrypoint.sh: running /docker-entrypoint-initdb.d/esentricar.sql
CREATE DATABASE
You are now connected to database "esentricar" as user "postgres".
CREATE TABLE
CREATE INDEX
2022-03-08 12:30:21.781 UTC [42] LOG: received fast shutdown request
waiting for server to shut down....2022-03-08 12:30:21.783 UTC [42] LOG: aborting any active transactions
2022-03-08 12:30:21.787 UTC [42] LOG: worker process: logical replication launcher (PID 49) exited with exit code 1
2022-03-08 12:30:21.790 UTC [44] LOG: shutting down
2022-03-08 12:30:21.820 UTC [42] LOG: database system is shut down
done
server stopped
PostgreSQL init process complete; ready for start up.
2022-03-08 12:30:21.904 UTC [1] LOG: listening on IPv4 address "0.0.0.0", port 5432
2022-03-08 12:30:21.904 UTC [1] LOG: listening on IPv6 address "::", port 5432
2022-03-08 12:30:21.909 UTC [1] LOG: listening on Unix socket "/var/run/postgresql/.s.PGSQL.5432"
2022-03-08 12:30:21.929 UTC [79] LOG: database system was shut down at 2022-03-08 12:30:21 UTC
2022-03-08 12:30:21.938 UTC [1] LOG: database system is ready to accept connections
Carpool Deploy App
deploy service
create first car
mkdir ~/carpool/app && cd ~/carpool/app
vi deployment.yaml
vi service.yaml
Find name of your local registry cnbc-registry
docker container ls
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
6f83432dbef0 rancher/k3d-proxy:5.3.0 "/bin/sh -c nginx-pr…" 29 hours ago Up 29 hours 0.0.0.0:8580->80/tcp, :::8580->80/tcp, 0.0.0.0:8543->443/tcp, :::8543->443/tcp, 0.0.0.0:8545->6443/tcp k3d-cnbc-serverlb
5f26dbd03241 rancher/k3s:v1.22.6-k3s1 "/bin/k3s agent" 29 hours ago Up 29 hours k3d-cnbc-agent-1
24d5876390bd rancher/k3s:v1.22.6-k3s1 "/bin/k3s agent" 29 hours ago Up 29 hours k3d-cnbc-agent-0
b5a50e960917 rancher/k3s:v1.22.6-k3s1 "/bin/k3s server --t…" 29 hours ago Up 29 hours k3d-cnbc-server-0
8f73928c8294 registry:2 "/entrypoint.sh /etc…" 29 hours ago Up 29 hours 0.0.0.0:5000->5000/tcp cnbc-registry
deployment.yaml
deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: carpool
labels:
app: carpool
spec:
replicas: 1
selector:
matchLabels:
app: carpool
template:
metadata:
labels:
app: carpool
spec:
containers:
- name: carpool
image: cnbc-registry:5000/bee42/carpool:0.1.0
imagePullPolicy: Always
env:
- name: FLASK_APP
value: python_rest
service.yaml
service.yaml
apiVersion: v1
kind: Service
metadata:
labels:
app: carpool
name: carpool
spec:
ports:
- name: http
port: 5000
protocol: TCP
targetPort: 5000
selector:
app: carpool
type: ClusterIP
cd ..
sudo apt install -y tree
tree .
.
├── app
│ ├── deployment.yaml
│ └── service.yaml
├── Dockerfile
├── postgres
│ ├── postgres-config.yaml
│ ├── postgres-deploy.yaml
│ ├── postgres-pv-claim.yaml
│ ├── postgres-schema-cm.yaml
│ └── postgres-service.yaml
├── python_rest.py
└── requirements.txt
Deploy App carpool
# create deployment and service manifests
kubectl apply -f app
kubectl get all
NAME READY STATUS RESTARTS AGE
pod/postgres-65974d6d58-72vk5 1/1 Running 0 26m
pod/carpool-67d9fcf5f4-8cwdg 1/1 Running 0 11s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/postgres ClusterIP 10.43.178.140 <none> 5432/TCP 26m
service/carpool ClusterIP 10.43.223.216 <none> 5000/TCP 11s
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/postgres 1/1 1 1 26m
deployment.apps/carpool 1/1 1 1 11s
NAME DESIRED CURRENT READY AGE
replicaset.apps/postgres-65974d6d58 1 1 1 26m
replicaset.apps/carpool-67d9fcf5f4 1 1 1 11s
Access app
kubectl run curl --tty -i --image curlimages/curl -- /bin/sh
# check registry access
curl cnbc-registry:5000/v2/
curl cnbc-registry:5000/v2/_catalog
curl http://cnbc-registry:5000/v2/bee42/carpool/tags/list
{"repositories":["bee42/carpool"]}
# create data
cd /tmp
cat >car_1.json <<EOF
{
"license_plate": "BO-PR-72",
"car_type": "mini clubman SD",
"fuel": "diesel",
"number_of_seats": "5"
}
EOF
curl -i -X POST http://carpool:5000/car \
-H "Content-Type: application/json" \
--data-binary "@car_1.json"
HTTP/1.0 200 OK
Content-Type: application/json
Content-Length: 105
Access-Control-Allow-Origin: *
Server: Werkzeug/2.0.3 Python/3.8.12
Date: Tue, 08 Mar 2022 12:57:40 GMT
{"car_id":1,"car_type":"mini clubman SD","fuel":"diesel","license_plate":"BO-PR-72","number_of_seats":5}
# access data
curl http://carpool:5000/car
[{"car_id":1,"car_type":"mini clubman SD","license_plate":"BO-PR-72"}]
#check ips nach neustart
kubectl get nodes -o wide
docker network inspect k3d-cnbc
kubectl edit cm -n kube-system coredns
NodeHosts: |
172.19.0.1 host.k3d.internal
172.19.0.6 k3d-cnbc-serverlb
172.19.0.3 k3d-cnbc-agent-0
172.19.0.2 k3d-cnbc-server-0
172.19.0.4 k3d-cnbc-agent-1
172.19.0.5 cnbc-registry
Patch python_rest.py
Add import
get env parameter
concat postgres url with env var parameter
Optimize the App
no static postgres config
define a app configmap
Edit app
vi ~/carpool/python_rest.py
import os
# Init app
app = Flask(__name__)
user = os.environ.get('POSTGRES_USER', 'postgres')
db = os.environ.get('POSTGRES_DB', 'esentricar' )
passwd = os.environ.get('POSTGRES_PASSWORD', 'cnbc')
host = os.environ.get('POSTGRES_HOST', 'postgres')
#enable CORS
CORS(app)
# connect to already existing and running Database
app.config['SQLALCHEMY_DATABASE_URI'] = 'postgresql://' + user + ':' + passwd + '@' + host + ':5432/' + db
or patch:
cat >python_rest.py.patch <<EOF
5a6,7
> import os
>
8a11,14
> user = os.environ.get('POSTGRES_USER', 'postgres')
> db = os.environ.get('POSTGRES_DB', 'esentricar' )
> passwd = os.environ.get('POSTGRES_PASSWORD', 'cnbc')
> host = os.environ.get('POSTGRES_HOST', 'postgres')
12c18
< app.config['SQLALCHEMY_DATABASE_URI'] = 'postgresql://postgres:cnbc@postgres:5432/esentricar'
---
> app.config['SQLALCHEMY_DATABASE_URI'] = 'postgresql://' + user + ':' + passwd + '@' + host + ':5432/' + db
EOF
patch -p0 < python_rest.py.patch python_rest.py
docker build -t bee42/carpool:0.2.0 .
curl http://127.0.0.1:5000/v2/
docker tag bee42/carpool:0.2.0 127.0.0.1:5000/bee42/carpool:0.2.0
docker push 127.0.0.1:5000/bee42/carpool:0.2.0
curl http://127.0.0.1:5000/v2/bee42/carpool/tags/list
{"name":"bee42/carpool","tags":["0.1.0","0.2.0"]}
app/app-config.yaml
app-config.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
labels:
app: carpool
data:
POSTGRES_DB: esentricar
POSTGRES_PASSWORD: cnbc
POSTGRES_USER: postgres
POSTGRES_HOST: postgres
app/deployment.yaml
deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: carpool
labels:
app: carpool
spec:
replicas: 1
selector:
matchLabels:
app: carpool
template:
metadata:
labels:
app: carpool
spec:
containers:
- name: carpool
image: cnbc-registry:5000/bee42/carpool:0.2.0
imagePullPolicy: Always
env:
- name: FLASK_APP
value: python_rest
envFrom:
- configMapRef:
name: app-config
kubectl apply -f app
# later curl exec
kubectl attach -ti curl
curl http://carpool:5000/car
[{"car_id":1,"car_type":"mini clubman SD","license_plate":"BO-PR-72"}]
# remove all
kubectl get pv
# patch pv if you need the data after redeploy :)
PV=$(kubectl get pvc -o json -lapp=postgres | jq -r .items[].spec.volumeName)
kubectl patch pv $PV -p "{\"spec\":{\"persistentVolumeReclaimPolicy\":\"Retain\"}}"
kubectl delete namespace carpool
kubectl create namespace carpool
kubectl apply -f postgres
kubectl apply -f app
# Problem: Auto reassociation of pv does't work
kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pvc-ab3ea061-9180-4e34-95d5-0100a149747d 1Gi RWO Retain Released carpool/postgres-pv-claim local-path 24m
pvc-57cae9ed-3ebe-4181-819a-7a9cfd745606 1Gi RWO Delete Bound carpool/postgres-pv-claim local-path 28s
kubectl delete namespace carpool
kubectl patch pv $PV --type json -p '[{"op": "remove", "path": "/spec/claimRef/uid"}]'
kubectl create namespace carpool
kubectl apply -f postgres
kubectl apply -f app
Options define a node port services
cat ~/carpool/app/node-service.yaml <<EOF
apiVersion: v1
kind: Service
metadata:
creationTimestamp: null
labels:
app: carpool-node
name: carpool-node
spec:
ports:
- name: http
port: 5000
protocol: TCP
targetPort: 5000
selector:
app: carpool
type: NodePort
status:
loadBalancer: {}
EOF
kubectl get nodes -o wide
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
k3d-cnbc-agent-0 Ready worker 30h v1.22.7+k3s1 172.18.0.4 <none> K3s dev 5.4.0-109-generic containerd://1.5.9-k3s1
k3d-cnbc-agent-1 Ready worker 30h v1.22.7+k3s1 172.18.0.3 <none> K3s dev 5.4.0-109-generic containerd://1.5.9-k3s1
k3d-cnbc-server-0 Ready control-plane,master 30h v1.22.7+k3s1 172.18.0.2 <none> K3s dev 5.4.0-109-generic containerd://1.5.9-k3s1
kubectl apply -f ~/carpool/app/node-service.yaml
kubectl get service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
postgres ClusterIP 10.43.173.36 <none> 5432/TCP 5m37s
carpool ClusterIP 10.43.41.38 <none> 5000/TCP 5m11s
carpool-node NodePort 10.43.44.24 <none> 5000:31231/TCP 7s
curl 172.18.0.3:31231/car
[{"car_id":1,"car_type":"mini clubman SD","license_plate":"BO-PR-72"}]

View File

@@ -0,0 +1,11 @@
CREATE DATABASE esentricar;
\c esentricar;
CREATE TABLE cars (
car_id SERIAL PRIMARY KEY,
license_plate varchar(30) NOT NULL,
car_type varchar(30) NOT NULL,
fuel varchar(30) NOT NULL,
number_of_seats integer NOT NULL
);
CREATE UNIQUE INDEX cars_license_plate
ON cars (license_plate);

1
k8s/carpool/index.env Normal file
View File

@@ -0,0 +1 @@
POSTGRES_PASSWORD=postgres

View File

@@ -0,0 +1,10 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: postgres-config
labels:
app: postgres
data:
POSTGRES_DB: postgresdb
POSTGRES_USER: postgres
POSTGRES_PASSWORD: cnbc

View File

@@ -0,0 +1,39 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: postgres
spec:
replicas: 1
selector:
matchLabels:
app: postgres
template:
metadata:
labels:
app: postgres
spec:
containers:
- name: postgres
image: postgres:10.4
imagePullPolicy: "IfNotPresent"
ports:
- containerPort: 5432
envFrom:
- configMapRef:
name: postgres-config
volumeMounts:
- mountPath: /var/lib/postgresql/data
name: postgredb
- name: config
mountPath: "/docker-entrypoint-initdb.d"
readOnly: true
volumes:
- name: config
configMap:
name: carpool
items:
- key: "esentricar.sql"
path: "esentricar.sql"
- name: postgredb
persistentVolumeClaim:
claimName: postgres-pv-claim

View File

@@ -0,0 +1,13 @@
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: postgres-pv-claim
labels:
app: postgres
spec:
storageClassName: local-path
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi

View File

@@ -0,0 +1,17 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: carpool
data:
esentricar.sql: |
CREATE DATABASE esentricar;
\c esentricar;
CREATE TABLE cars (
car_id SERIAL PRIMARY KEY,
license_plate varchar(30) NOT NULL,
car_type varchar(30) NOT NULL,
fuel varchar(30) NOT NULL,
number_of_seats integer NOT NULL
);
CREATE UNIQUE INDEX cars_license_plate
ON cars (license_plate);

View File

@@ -0,0 +1,15 @@
apiVersion: v1
kind: Service
metadata:
labels:
app: postgres
name: postgres
spec:
ports:
- name: postgres
port: 5432
protocol: TCP
targetPort: 5432
selector:
app: postgres
type: ClusterIP

View File

@@ -0,0 +1,98 @@
from flask import Flask, request, jsonify
from flask_sqlalchemy import SQLAlchemy
from flask_marshmallow import Marshmallow, fields
from flask_cors import CORS
# Init app
app = Flask(__name__)
#enable CORS
CORS(app)
# connect to already existing and running Database
app.config['SQLALCHEMY_DATABASE_URI'] = 'postgresql://postgres:cnbc@postgres:5432/esentricar'
# not important but otherwise we get a warning every time
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
#Init db
db = SQLAlchemy(app)
#Init ma
ma = Marshmallow(app)
# Pool Car Class/Model
class Pool_Car(db.Model):
#define table, in our case already existing
__tablename__ = 'cars'
car_id = db.Column(db.Integer, primary_key=True)
license_plate = db.Column(db.String(30), unique=True)
car_type = db.Column(db.String(20))
fuel = db.Column(db.String(20))
number_of_seats =db.Column(db.Integer)
# set class attributes
def __init__(self, license_plate, car_type, fuel, number_of_seats):
self.license_plate = license_plate
self.car_type = car_type
self.fuel = fuel
self.number_of_seats = number_of_seats
class Pool_CarSchema(ma.Schema):
class Meta:
fields = ('car_id','license_plate','car_type','fuel','number_of_seats')
# Init schema
pool_car_schema = Pool_CarSchema()
pool_cars_schema = Pool_CarSchema(many=True)
# Create a Pool_Car
@app.route('/car', methods=['POST'])
def add_pool_car():
# Get request data as json
car_entity = request.get_json()
license_plate= car_entity.get('license_plate')
car_type = car_entity.get('car_type')
fuel = car_entity.get('fuel')
number_of_seats = car_entity.get('number_of_seats')
new_pool_car = Pool_Car(license_plate, car_type, fuel, number_of_seats)
db.session.add(new_pool_car)
db.session.commit()
return pool_car_schema.jsonify(new_pool_car)
# Get car_id,license_plate,car_type of all products of the table
@app.route('/car', methods=['GET'])
def get_pool_cars():
all_pool_cars = Pool_Car.query.all()
result = pool_cars_schema.dump(all_pool_cars)
car_list= []
for item in result:
car_details = { "car_id":None, "license_plate":None, "car_type":None}
car_details['car_id'] = item['car_id']
car_details['license_plate'] = item['license_plate']
car_details['car_type'] = item['car_type']
car_list.append(car_details)
return jsonify(car_list)
# Get Single Products
@app.route('/car/<car_id>', methods=['GET'])
def get_pool_car(car_id):
pool_car = Pool_Car.query.get(car_id)
return pool_car_schema.jsonify(pool_car)
# Delete Product
@app.route('/car/<car_id>', methods=['DELETE'])
def delete_pool_car(car_id):
pool_car = Pool_Car.query.get(car_id)
db.session.delete(pool_car)
db.session.commit()
return pool_car_schema.jsonify(pool_car)
if __name__ == '__main__':
app.run(debug=True) #port='5002'

View File

@@ -0,0 +1,11 @@
Flask==1.1.1
Flask-Cors==3.0.8
flask-marshmallow==0.10.1
Flask-SQLAlchemy==2.4.1
werkzeug==2.0.2
marshmallow==3.2.2
SQLAlchemy==1.3.11
marshmallow-sqlalchemy==0.19.0
psycopg2-binary==2.8.4
itsdangerous==2.0.1
Jinja2==3.0.3

15
k8s/carpool/service.yaml Normal file
View File

@@ -0,0 +1,15 @@
apiVersion: v1
kind: Service
metadata:
labels:
app: carpool
name: carpool
spec:
ports:
- name: http
port: 5000
protocol: TCP
targetPort: 5000
selector:
app: carpool
type: ClusterIP

82
k8s/config_map Normal file
View File

@@ -0,0 +1,82 @@
kubectl create deploy nginx --image nginx --dry-run=client -o yaml >nginx-deploy.yaml
vi nginx-deploy.yaml
# add volume mounts and volumes from configMap
# create config Map
echo Linuxhotel >index.html
kubectl create configmap htdocs --from-file index.html=index.html --dry-run=client -o yaml >htdocs-cm.yaml
kubectl -n nginx apply -f htdocs-cm.yaml
kubectl -n nginx apply -f nginx-deploy.yaml
kubectl -n nginx exec -ti nginx-6fc76484c-q8tmd -- /bin/sh
# more /usr/share/nginx/html/index.html
kubectl edit -n nginx cm htdocs
# change content
apiVersion: v1
data:
index.html: |
Linuxhotel Cloud Native Base Camp
kind: ConfigMap
metadata:
name: htdocs
# See it change at running pods!
kubectl -n nginx exec -ti nginx-6fc76484c-q8tmd -- /bin/sh
# more /usr/share/nginx/html/index.html
Linuxhotel Cloud Native Base Camp
htdocs-cm.yaml
apiVersion: v1
data:
index.html: |
Linuxhotel
kind: ConfigMap
metadata:
creationTimestamp: null
name: htdocs
nginx-deploy.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
creationTimestamp: null
labels:
app: nginx
name: nginx
spec:
replicas: 1
selector:
matchLabels:
app: nginx
strategy: {}
template:
metadata:
creationTimestamp: null
labels:
app: nginx
spec:
containers:
- image: nginx
name: nginx
resources: {}
volumeMounts:
- name: htdocs
mountPath: /usr/share/nginx/html
volumes:
- name: htdocs
configMap:
name: htdocs
status: {}

View File

@@ -68,3 +68,7 @@ kubectl get pods
kubectl get pod <web pod> -o yaml | sed 's/\(image: nginx\):.*$/\1:1.19.3/' | kubectl replace -f -
#kubectl get pod web-548df7676c-v48kv -o yaml | sed 's/\(image: nginx\):.*$/\1:1.19.4/' | kubectl replace -f - web-548df7676c-rzp7v
curl -i -X POST http://carpool:5000/car \
-H "Content-Type: application/json" \
--data-binary "@car_2.json"

93
k8s/pvc Normal file
View File

@@ -0,0 +1,93 @@
Retain static PersistentVolumeClaim
Change Claim to static hostPath volume
cat >~/carpool/postgres/postgres-pv-claim.yaml <<EOF
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: postgres-pv-claim
labels:
app: postgres
spec:
storageClassName: ""
volumeName: postgres-pv
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
EOF
Create static PersistenceVolume
cat >~/carpool/postgres/postgres-pv.yaml <<EOF
apiVersion: v1
kind: PersistentVolume
metadata:
name: postgres-pv
spec:
accessModes:
- ReadWriteOnce
capacity:
storage: 1Gi
claimRef:
name: postgres-pv-claim
namespace: carpool
hostPath:
path: /data
type: DirectoryOrCreate
nodeAffinity:
required:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/hostname
operator: In
values:
- k3d-cnbc-agent-1
persistentVolumeReclaimPolicy: Retain
storageClassName: ""
volumeMode: Filesystem
EOF
Szenario:
kubectl delete namespace carpool
kubectl delete pv <...>
kubectl create namespace carpool
kubectl apply -f postgres
kubectl apply -f app
kubectl run curl -ti --image=curlimages/curl -- /bin/sh
cd /tmp
cat >car_1.json <<EOF
{
"license_plate": "BO-PR-72",
"car_type": "mini clubman SD",
"fuel": "diesel",
"number_of_seats": "5"
}
EOF
curl -i -X POST http://carpool:5000/car \
-H "Content-Type: application/json" \
--data-binary "@car_1.json"
curl http://carpool:5000/car
exit
# delete again and check retaining of pv
kubectl delete namespace carpool
kubectl get pv
# if not edit Postgres pvc and pod pending
kubectl edit pv <...>
# remove claim-ref uid and resource version
kubectl create ns carpool
kubectl apply -f postgres
kubectl apply -f app
kubectl run curl -ti --image=curlimages/curl -- /bin/sh
curl http://carpool:5000/car
# data exists
exit

View File

@@ -9,7 +9,6 @@ services:
- /var/cache/nginx
- /run
read_only: true
 
networks:
default:
driver: bridge

152
traefik/doku Normal file
View File

@@ -0,0 +1,152 @@
mkdir ~/traefik && cd ~/traefik
helm repo add traefik https://helm.traefik.io/traefik
helm repo update
helm pull traefik/traefik --untar
cd traefik
tree .
.
├── Changelog.md
├── Chart.yaml
├── crds
│ ├── ingressroutetcp.yaml
│ ├── ingressrouteudp.yaml
│ ├── ingressroute.yaml
│ ├── middlewarestcp.yaml
│ ├── middlewares.yaml
│ ├── serverstransports.yaml
│ ├── tlsoptions.yaml
│ ├── tlsstores.yaml
│ └── traefikservices.yaml
├── Guidelines.md
├── LICENSE
├── README.md
├── templates
│ ├── daemonset.yaml
│ ├── dashboard-hook-ingressroute.yaml
│ ├── deployment.yaml
│ ├── extra-objects.yaml
│ ├── gatewayclass.yaml
│ ├── gateway.yaml
│ ├── _helpers.tpl
│ ├── hpa.yaml
│ ├── ingressclass.yaml
│ ├── poddisruptionbudget.yaml
│ ├── _podtemplate.tpl
│ ├── pvc.yaml
│ ├── rbac
│ │ ├── clusterrolebinding.yaml
│ │ ├── clusterrole.yaml
│ │ ├── podsecuritypolicy.yaml
│ │ ├── rolebinding.yaml
│ │ ├── role.yaml
│ │ └── serviceaccount.yaml
│ ├── _service.tpl
│ ├── service.yaml
│ ├── tlsoption.yaml
│ └── tlsstore.yaml
└── values.yaml
3 directories, 37 files
# install
kubectl create ns traefik-v2
helm install --namespace=traefik-v2 \
traefik traefik/traefik
kubectl -n traefik-v2 get all
cd ../web/
cat >ingress-values.yaml <<EOF
ingress:
enabled: true
className: ""
annotations:
kubernetes.io/ingress.class: traefik
# kubernetes.io/ingress.class: nginx
# kubernetes.io/tls-acme: "true"
hosts:
- host: web.local
paths:
- path: /
pathType: ImplementationSpecific
tls: []
# - secretName: chart-example-tls
# hosts:
# - chart-example.local
EOF
helm template --values ingress-values.yaml --set image.tag=1.21.3 . |more
helm upgrade web --values ingress-values.yaml --set image.tag=1.21.3 .
curl -H "Host: web.local" http://127.0.0.1:8580
Beispiel Ingress Manifest
# Source: web/templates/ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: release-name-web
labels:
helm.sh/chart: web-0.1.0
app.kubernetes.io/name: web
app.kubernetes.io/instance: release-name
app.kubernetes.io/version: "1.16.0"
app.kubernetes.io/managed-by: Helm
annotations:
kubernetes.io/ingress.class: traefik
spec:
rules:
- host: "web.local"
http:
paths:
- path: /
pathType: ImplementationSpecific
backend:
service:
name: release-name-web
port:
number: 80
cat >~/carpool/app/ingress.yaml <<EOF
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: carpool
labels:
app.kubernetes.io/name: carpool
annotations:
kubernetes.io/ingress.class: traefik
spec:
rules:
- host: "carpool.local"
http:
paths:
- path: /
pathType: ImplementationSpecific
backend:
service:
name: carpool
port:
number: 5000
EOF
kubectl apply -n carpool -f ~/carpool/app/ingress.yaml
curl -H "Host: carpool.local" http://127.0.0.1:8580/car
[{"car_id":1,"car_type":"mini clubman SD","license_plate":"BO-PR-72"}]
TRAEFIK_PODNAME=$(kubectl -n traefik-v2 get pods -l app.kubernetes.io/name=traefik -o jsonpath="{range .items[*]}{@.metadata.name}{end}")
kubectl -n traefik-v2 port-forward $TRAEFIK_PODNAME 9000:9000 &
# open browser http://127.0.0.1:9000/dashboard/
# or
# cloud instance
IP4=$(/sbin/ip -o -4 addr list eth0 | awk '{print $4}' | cut -d/ -f1)
# notebook
IP4=$(/sbin/ip -o -4 addr list br2 | awk '{print $4}' | cut -d/ -f1
kubectl -n traefik-v2 port-forward $TRAEFIK_PODNAME --address $IP4 9000:9000 &
# open browser http://$IP4:9000/dashboard/

331
traefik/get_helm.sh Executable file
View File

@@ -0,0 +1,331 @@
#!/usr/bin/env bash
# Copyright The Helm Authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# The install script is based off of the MIT-licensed script from glide,
# the package manager for Go: https://github.com/Masterminds/glide.sh/blob/master/get
: ${BINARY_NAME:="helm"}
: ${USE_SUDO:="true"}
: ${DEBUG:="false"}
: ${VERIFY_CHECKSUM:="true"}
: ${VERIFY_SIGNATURES:="false"}
: ${HELM_INSTALL_DIR:="/usr/local/bin"}
: ${GPG_PUBRING:="pubring.kbx"}
HAS_CURL="$(type "curl" &> /dev/null && echo true || echo false)"
HAS_WGET="$(type "wget" &> /dev/null && echo true || echo false)"
HAS_OPENSSL="$(type "openssl" &> /dev/null && echo true || echo false)"
HAS_GPG="$(type "gpg" &> /dev/null && echo true || echo false)"
HAS_GIT="$(type "git" &> /dev/null && echo true || echo false)"
# initArch discovers the architecture for this system.
initArch() {
ARCH=$(uname -m)
case $ARCH in
armv5*) ARCH="armv5";;
armv6*) ARCH="armv6";;
armv7*) ARCH="arm";;
aarch64) ARCH="arm64";;
x86) ARCH="386";;
x86_64) ARCH="amd64";;
i686) ARCH="386";;
i386) ARCH="386";;
esac
}
# initOS discovers the operating system for this system.
initOS() {
OS=$(echo `uname`|tr '[:upper:]' '[:lower:]')
case "$OS" in
# Minimalist GNU for Windows
mingw*|cygwin*) OS='windows';;
esac
}
# runs the given command as root (detects if we are root already)
runAsRoot() {
if [ $EUID -ne 0 -a "$USE_SUDO" = "true" ]; then
sudo "${@}"
else
"${@}"
fi
}
# verifySupported checks that the os/arch combination is supported for
# binary builds, as well whether or not necessary tools are present.
verifySupported() {
local supported="darwin-amd64\ndarwin-arm64\nlinux-386\nlinux-amd64\nlinux-arm\nlinux-arm64\nlinux-ppc64le\nlinux-s390x\nwindows-amd64"
if ! echo "${supported}" | grep -q "${OS}-${ARCH}"; then
echo "No prebuilt binary for ${OS}-${ARCH}."
echo "To build from source, go to https://github.com/helm/helm"
exit 1
fi
if [ "${HAS_CURL}" != "true" ] && [ "${HAS_WGET}" != "true" ]; then
echo "Either curl or wget is required"
exit 1
fi
if [ "${VERIFY_CHECKSUM}" == "true" ] && [ "${HAS_OPENSSL}" != "true" ]; then
echo "In order to verify checksum, openssl must first be installed."
echo "Please install openssl or set VERIFY_CHECKSUM=false in your environment."
exit 1
fi
if [ "${VERIFY_SIGNATURES}" == "true" ]; then
if [ "${HAS_GPG}" != "true" ]; then
echo "In order to verify signatures, gpg must first be installed."
echo "Please install gpg or set VERIFY_SIGNATURES=false in your environment."
exit 1
fi
if [ "${OS}" != "linux" ]; then
echo "Signature verification is currently only supported on Linux."
echo "Please set VERIFY_SIGNATURES=false or verify the signatures manually."
exit 1
fi
fi
if [ "${HAS_GIT}" != "true" ]; then
echo "[WARNING] Could not find git. It is required for plugin installation."
fi
}
# checkDesiredVersion checks if the desired version is available.
checkDesiredVersion() {
if [ "x$DESIRED_VERSION" == "x" ]; then
# Get tag from release URL
local latest_release_url="https://github.com/helm/helm/releases"
if [ "${HAS_CURL}" == "true" ]; then
TAG=$(curl -Ls $latest_release_url | grep 'href="/helm/helm/releases/tag/v3.[0-9]*.[0-9]*\"' | sed -E 's/.*\/helm\/helm\/releases\/tag\/(v[0-9\.]+)".*/\1/g' | head -1)
elif [ "${HAS_WGET}" == "true" ]; then
TAG=$(wget $latest_release_url -O - 2>&1 | grep 'href="/helm/helm/releases/tag/v3.[0-9]*.[0-9]*\"' | sed -E 's/.*\/helm\/helm\/releases\/tag\/(v[0-9\.]+)".*/\1/g' | head -1)
fi
else
TAG=$DESIRED_VERSION
fi
}
# checkHelmInstalledVersion checks which version of helm is installed and
# if it needs to be changed.
checkHelmInstalledVersion() {
if [[ -f "${HELM_INSTALL_DIR}/${BINARY_NAME}" ]]; then
local version=$("${HELM_INSTALL_DIR}/${BINARY_NAME}" version --template="{{ .Version }}")
if [[ "$version" == "$TAG" ]]; then
echo "Helm ${version} is already ${DESIRED_VERSION:-latest}"
return 0
else
echo "Helm ${TAG} is available. Changing from version ${version}."
return 1
fi
else
return 1
fi
}
# downloadFile downloads the latest binary package and also the checksum
# for that binary.
downloadFile() {
HELM_DIST="helm-$TAG-$OS-$ARCH.tar.gz"
DOWNLOAD_URL="https://get.helm.sh/$HELM_DIST"
CHECKSUM_URL="$DOWNLOAD_URL.sha256"
HELM_TMP_ROOT="$(mktemp -dt helm-installer-XXXXXX)"
HELM_TMP_FILE="$HELM_TMP_ROOT/$HELM_DIST"
HELM_SUM_FILE="$HELM_TMP_ROOT/$HELM_DIST.sha256"
echo "Downloading $DOWNLOAD_URL"
if [ "${HAS_CURL}" == "true" ]; then
curl -SsL "$CHECKSUM_URL" -o "$HELM_SUM_FILE"
curl -SsL "$DOWNLOAD_URL" -o "$HELM_TMP_FILE"
elif [ "${HAS_WGET}" == "true" ]; then
wget -q -O "$HELM_SUM_FILE" "$CHECKSUM_URL"
wget -q -O "$HELM_TMP_FILE" "$DOWNLOAD_URL"
fi
}
# verifyFile verifies the SHA256 checksum of the binary package
# and the GPG signatures for both the package and checksum file
# (depending on settings in environment).
verifyFile() {
if [ "${VERIFY_CHECKSUM}" == "true" ]; then
verifyChecksum
fi
if [ "${VERIFY_SIGNATURES}" == "true" ]; then
verifySignatures
fi
}
# installFile installs the Helm binary.
installFile() {
HELM_TMP="$HELM_TMP_ROOT/$BINARY_NAME"
mkdir -p "$HELM_TMP"
tar xf "$HELM_TMP_FILE" -C "$HELM_TMP"
HELM_TMP_BIN="$HELM_TMP/$OS-$ARCH/helm"
echo "Preparing to install $BINARY_NAME into ${HELM_INSTALL_DIR}"
runAsRoot cp "$HELM_TMP_BIN" "$HELM_INSTALL_DIR/$BINARY_NAME"
echo "$BINARY_NAME installed into $HELM_INSTALL_DIR/$BINARY_NAME"
}
# verifyChecksum verifies the SHA256 checksum of the binary package.
verifyChecksum() {
printf "Verifying checksum... "
local sum=$(openssl sha1 -sha256 ${HELM_TMP_FILE} | awk '{print $2}')
local expected_sum=$(cat ${HELM_SUM_FILE})
if [ "$sum" != "$expected_sum" ]; then
echo "SHA sum of ${HELM_TMP_FILE} does not match. Aborting."
exit 1
fi
echo "Done."
}
# verifySignatures obtains the latest KEYS file from GitHub main branch
# as well as the signature .asc files from the specific GitHub release,
# then verifies that the release artifacts were signed by a maintainer's key.
verifySignatures() {
printf "Verifying signatures... "
local keys_filename="KEYS"
local github_keys_url="https://raw.githubusercontent.com/helm/helm/main/${keys_filename}"
if [ "${HAS_CURL}" == "true" ]; then
curl -SsL "${github_keys_url}" -o "${HELM_TMP_ROOT}/${keys_filename}"
elif [ "${HAS_WGET}" == "true" ]; then
wget -q -O "${HELM_TMP_ROOT}/${keys_filename}" "${github_keys_url}"
fi
local gpg_keyring="${HELM_TMP_ROOT}/keyring.gpg"
local gpg_homedir="${HELM_TMP_ROOT}/gnupg"
mkdir -p -m 0700 "${gpg_homedir}"
local gpg_stderr_device="/dev/null"
if [ "${DEBUG}" == "true" ]; then
gpg_stderr_device="/dev/stderr"
fi
gpg --batch --quiet --homedir="${gpg_homedir}" --import "${HELM_TMP_ROOT}/${keys_filename}" 2> "${gpg_stderr_device}"
gpg --batch --no-default-keyring --keyring "${gpg_homedir}/${GPG_PUBRING}" --export > "${gpg_keyring}"
local github_release_url="https://github.com/helm/helm/releases/download/${TAG}"
if [ "${HAS_CURL}" == "true" ]; then
curl -SsL "${github_release_url}/helm-${TAG}-${OS}-${ARCH}.tar.gz.sha256.asc" -o "${HELM_TMP_ROOT}/helm-${TAG}-${OS}-${ARCH}.tar.gz.sha256.asc"
curl -SsL "${github_release_url}/helm-${TAG}-${OS}-${ARCH}.tar.gz.asc" -o "${HELM_TMP_ROOT}/helm-${TAG}-${OS}-${ARCH}.tar.gz.asc"
elif [ "${HAS_WGET}" == "true" ]; then
wget -q -O "${HELM_TMP_ROOT}/helm-${TAG}-${OS}-${ARCH}.tar.gz.sha256.asc" "${github_release_url}/helm-${TAG}-${OS}-${ARCH}.tar.gz.sha256.asc"
wget -q -O "${HELM_TMP_ROOT}/helm-${TAG}-${OS}-${ARCH}.tar.gz.asc" "${github_release_url}/helm-${TAG}-${OS}-${ARCH}.tar.gz.asc"
fi
local error_text="If you think this might be a potential security issue,"
error_text="${error_text}\nplease see here: https://github.com/helm/community/blob/master/SECURITY.md"
local num_goodlines_sha=$(gpg --verify --keyring="${gpg_keyring}" --status-fd=1 "${HELM_TMP_ROOT}/helm-${TAG}-${OS}-${ARCH}.tar.gz.sha256.asc" 2> "${gpg_stderr_device}" | grep -c -E '^\[GNUPG:\] (GOODSIG|VALIDSIG)')
if [[ ${num_goodlines_sha} -lt 2 ]]; then
echo "Unable to verify the signature of helm-${TAG}-${OS}-${ARCH}.tar.gz.sha256!"
echo -e "${error_text}"
exit 1
fi
local num_goodlines_tar=$(gpg --verify --keyring="${gpg_keyring}" --status-fd=1 "${HELM_TMP_ROOT}/helm-${TAG}-${OS}-${ARCH}.tar.gz.asc" 2> "${gpg_stderr_device}" | grep -c -E '^\[GNUPG:\] (GOODSIG|VALIDSIG)')
if [[ ${num_goodlines_tar} -lt 2 ]]; then
echo "Unable to verify the signature of helm-${TAG}-${OS}-${ARCH}.tar.gz!"
echo -e "${error_text}"
exit 1
fi
echo "Done."
}
# fail_trap is executed if an error occurs.
fail_trap() {
result=$?
if [ "$result" != "0" ]; then
if [[ -n "$INPUT_ARGUMENTS" ]]; then
echo "Failed to install $BINARY_NAME with the arguments provided: $INPUT_ARGUMENTS"
help
else
echo "Failed to install $BINARY_NAME"
fi
echo -e "\tFor support, go to https://github.com/helm/helm."
fi
cleanup
exit $result
}
# testVersion tests the installed client to make sure it is working.
testVersion() {
set +e
HELM="$(command -v $BINARY_NAME)"
if [ "$?" = "1" ]; then
echo "$BINARY_NAME not found. Is $HELM_INSTALL_DIR on your "'$PATH?'
exit 1
fi
set -e
}
# help provides possible cli installation arguments
help () {
echo "Accepted cli arguments are:"
echo -e "\t[--help|-h ] ->> prints this help"
echo -e "\t[--version|-v <desired_version>] . When not defined it fetches the latest release from GitHub"
echo -e "\te.g. --version v3.0.0 or -v canary"
echo -e "\t[--no-sudo] ->> install without sudo"
}
# cleanup temporary files to avoid https://github.com/helm/helm/issues/2977
cleanup() {
if [[ -d "${HELM_TMP_ROOT:-}" ]]; then
rm -rf "$HELM_TMP_ROOT"
fi
}
# Execution
#Stop execution on any error
trap "fail_trap" EXIT
set -e
# Set debug if desired
if [ "${DEBUG}" == "true" ]; then
set -x
fi
# Parsing input arguments (if any)
export INPUT_ARGUMENTS="${@}"
set -u
while [[ $# -gt 0 ]]; do
case $1 in
'--version'|-v)
shift
if [[ $# -ne 0 ]]; then
export DESIRED_VERSION="${1}"
else
echo -e "Please provide the desired version. e.g. --version v3.0.0 or -v canary"
exit 0
fi
;;
'--no-sudo')
USE_SUDO="false"
;;
'--help'|-h)
help
exit 0
;;
*) exit 1
;;
esac
shift
done
set +u
initArch
initOS
verifySupported
checkDesiredVersion
if ! checkHelmInstalledVersion; then
downloadFile
verifyFile
installFile
fi
testVersion
cleanup

View File

@@ -0,0 +1,23 @@
# Patterns to ignore when building packages.
# This supports shell glob matching, relative path matching, and
# negation (prefixed with !). Only one pattern per line.
.DS_Store
# Common VCS dirs
.git/
.gitignore
.bzr/
.bzrignore
.hg/
.hgignore
.svn/
# Common backup files
*.swp
*.bak
*.tmp
*.orig
*~
# Various IDEs
.project
.idea/
*.tmproj
.vscode/

View File

@@ -0,0 +1,24 @@
apiVersion: v2
name: web-helm
description: A Helm chart for Kubernetes
# A chart can be either an 'application' or a 'library' chart.
#
# Application charts are a collection of templates that can be packaged into versioned archives
# to be deployed.
#
# Library charts provide useful utilities or functions for the chart developer. They're included as
# a dependency of application charts to inject those utilities and functions into the rendering
# pipeline. Library charts do not define any templates and therefore cannot be deployed.
type: application
# This is the chart version. This version number should be incremented each time you make changes
# to the chart and its templates, including the app version.
# Versions are expected to follow Semantic Versioning (https://semver.org/)
version: 0.1.0
# This is the version number of the application being deployed. This version number should be
# incremented each time you make changes to the application. Versions are not expected to
# follow Semantic Versioning. They should reflect the version the application is using.
# It is recommended to use it with quotes.
appVersion: "1.16.0"

View File

@@ -0,0 +1,22 @@
1. Get the application URL by running these commands:
{{- if .Values.ingress.enabled }}
{{- range $host := .Values.ingress.hosts }}
{{- range .paths }}
http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host.host }}{{ .path }}
{{- end }}
{{- end }}
{{- else if contains "NodePort" .Values.service.type }}
export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "web-helm.fullname" . }})
export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}")
echo http://$NODE_IP:$NODE_PORT
{{- else if contains "LoadBalancer" .Values.service.type }}
NOTE: It may take a few minutes for the LoadBalancer IP to be available.
You can watch the status of by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "web-helm.fullname" . }}'
export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "web-helm.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}")
echo http://$SERVICE_IP:{{ .Values.service.port }}
{{- else if contains "ClusterIP" .Values.service.type }}
export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "web-helm.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}")
export CONTAINER_PORT=$(kubectl get pod --namespace {{ .Release.Namespace }} $POD_NAME -o jsonpath="{.spec.containers[0].ports[0].containerPort}")
echo "Visit http://127.0.0.1:8080 to use your application"
kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:$CONTAINER_PORT
{{- end }}

View File

@@ -0,0 +1,62 @@
{{/*
Expand the name of the chart.
*/}}
{{- define "web-helm.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
{{- end }}
{{/*
Create a default fully qualified app name.
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
If release name contains chart name it will be used as a full name.
*/}}
{{- define "web-helm.fullname" -}}
{{- if .Values.fullnameOverride }}
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- $name := default .Chart.Name .Values.nameOverride }}
{{- if contains $name .Release.Name }}
{{- .Release.Name | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
{{- end }}
{{- end }}
{{- end }}
{{/*
Create chart name and version as used by the chart label.
*/}}
{{- define "web-helm.chart" -}}
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
{{- end }}
{{/*
Common labels
*/}}
{{- define "web-helm.labels" -}}
helm.sh/chart: {{ include "web-helm.chart" . }}
{{ include "web-helm.selectorLabels" . }}
{{- if .Chart.AppVersion }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
{{- end }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- end }}
{{/*
Selector labels
*/}}
{{- define "web-helm.selectorLabels" -}}
app.kubernetes.io/name: {{ include "web-helm.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end }}
{{/*
Create the name of the service account to use
*/}}
{{- define "web-helm.serviceAccountName" -}}
{{- if .Values.serviceAccount.create }}
{{- default (include "web-helm.fullname" .) .Values.serviceAccount.name }}
{{- else }}
{{- default "default" .Values.serviceAccount.name }}
{{- end }}
{{- end }}

View File

@@ -0,0 +1,61 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "web-helm.fullname" . }}
labels:
{{- include "web-helm.labels" . | nindent 4 }}
spec:
{{- if not .Values.autoscaling.enabled }}
replicas: {{ .Values.replicaCount }}
{{- end }}
selector:
matchLabels:
{{- include "web-helm.selectorLabels" . | nindent 6 }}
template:
metadata:
{{- with .Values.podAnnotations }}
annotations:
{{- toYaml . | nindent 8 }}
{{- end }}
labels:
{{- include "web-helm.selectorLabels" . | nindent 8 }}
spec:
{{- with .Values.imagePullSecrets }}
imagePullSecrets:
{{- toYaml . | nindent 8 }}
{{- end }}
serviceAccountName: {{ include "web-helm.serviceAccountName" . }}
securityContext:
{{- toYaml .Values.podSecurityContext | nindent 8 }}
containers:
- name: {{ .Chart.Name }}
securityContext:
{{- toYaml .Values.securityContext | nindent 12 }}
image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
ports:
- name: http
containerPort: {{ .Values.service.port }}
protocol: TCP
livenessProbe:
httpGet:
path: /
port: http
readinessProbe:
httpGet:
path: /
port: http
resources:
{{- toYaml .Values.resources | nindent 12 }}
{{- with .Values.nodeSelector }}
nodeSelector:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.affinity }}
affinity:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.tolerations }}
tolerations:
{{- toYaml . | nindent 8 }}
{{- end }}

View File

@@ -0,0 +1,28 @@
{{- if .Values.autoscaling.enabled }}
apiVersion: autoscaling/v2beta1
kind: HorizontalPodAutoscaler
metadata:
name: {{ include "web-helm.fullname" . }}
labels:
{{- include "web-helm.labels" . | nindent 4 }}
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: {{ include "web-helm.fullname" . }}
minReplicas: {{ .Values.autoscaling.minReplicas }}
maxReplicas: {{ .Values.autoscaling.maxReplicas }}
metrics:
{{- if .Values.autoscaling.targetCPUUtilizationPercentage }}
- type: Resource
resource:
name: cpu
targetAverageUtilization: {{ .Values.autoscaling.targetCPUUtilizationPercentage }}
{{- end }}
{{- if .Values.autoscaling.targetMemoryUtilizationPercentage }}
- type: Resource
resource:
name: memory
targetAverageUtilization: {{ .Values.autoscaling.targetMemoryUtilizationPercentage }}
{{- end }}
{{- end }}

View File

@@ -0,0 +1,61 @@
{{- if .Values.ingress.enabled -}}
{{- $fullName := include "web-helm.fullname" . -}}
{{- $svcPort := .Values.service.port -}}
{{- if and .Values.ingress.className (not (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion)) }}
{{- if not (hasKey .Values.ingress.annotations "kubernetes.io/ingress.class") }}
{{- $_ := set .Values.ingress.annotations "kubernetes.io/ingress.class" .Values.ingress.className}}
{{- end }}
{{- end }}
{{- if semverCompare ">=1.19-0" .Capabilities.KubeVersion.GitVersion -}}
apiVersion: networking.k8s.io/v1
{{- else if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}}
apiVersion: networking.k8s.io/v1beta1
{{- else -}}
apiVersion: extensions/v1beta1
{{- end }}
kind: Ingress
metadata:
name: {{ $fullName }}
labels:
{{- include "web-helm.labels" . | nindent 4 }}
{{- with .Values.ingress.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
{{- if and .Values.ingress.className (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion) }}
ingressClassName: {{ .Values.ingress.className }}
{{- end }}
{{- if .Values.ingress.tls }}
tls:
{{- range .Values.ingress.tls }}
- hosts:
{{- range .hosts }}
- {{ . | quote }}
{{- end }}
secretName: {{ .secretName }}
{{- end }}
{{- end }}
rules:
{{- range .Values.ingress.hosts }}
- host: {{ .host | quote }}
http:
paths:
{{- range .paths }}
- path: {{ .path }}
{{- if and .pathType (semverCompare ">=1.18-0" $.Capabilities.KubeVersion.GitVersion) }}
pathType: {{ .pathType }}
{{- end }}
backend:
{{- if semverCompare ">=1.19-0" $.Capabilities.KubeVersion.GitVersion }}
service:
name: {{ $fullName }}
port:
number: {{ $svcPort }}
{{- else }}
serviceName: {{ $fullName }}
servicePort: {{ $svcPort }}
{{- end }}
{{- end }}
{{- end }}
{{- end }}

View File

@@ -0,0 +1,15 @@
apiVersion: v1
kind: Service
metadata:
name: {{ include "web-helm.fullname" . }}
labels:
{{- include "web-helm.labels" . | nindent 4 }}
spec:
type: {{ .Values.service.type }}
ports:
- port: {{ .Values.service.port }}
targetPort: http
protocol: TCP
name: http
selector:
{{- include "web-helm.selectorLabels" . | nindent 4 }}

View File

@@ -0,0 +1,12 @@
{{- if .Values.serviceAccount.create -}}
apiVersion: v1
kind: ServiceAccount
metadata:
name: {{ include "web-helm.serviceAccountName" . }}
labels:
{{- include "web-helm.labels" . | nindent 4 }}
{{- with .Values.serviceAccount.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
{{- end }}

View File

@@ -0,0 +1,15 @@
apiVersion: v1
kind: Pod
metadata:
name: "{{ include "web-helm.fullname" . }}-test-connection"
labels:
{{- include "web-helm.labels" . | nindent 4 }}
annotations:
"helm.sh/hook": test
spec:
containers:
- name: wget
image: busybox
command: ['wget']
args: ['{{ include "web-helm.fullname" . }}:{{ .Values.service.port }}']
restartPolicy: Never

View File

@@ -0,0 +1,82 @@
# Default values for web-helm.
# This is a YAML-formatted file.
# Declare variables to be passed into your templates.
replicaCount: 1
image:
repository: nginx
pullPolicy: IfNotPresent
# Overrides the image tag whose default is the chart appVersion.
tag: ""
imagePullSecrets: []
nameOverride: ""
fullnameOverride: ""
serviceAccount:
# Specifies whether a service account should be created
create: true
# Annotations to add to the service account
annotations: {}
# The name of the service account to use.
# If not set and create is true, a name is generated using the fullname template
name: ""
podAnnotations: {}
podSecurityContext: {}
# fsGroup: 2000
securityContext: {}
# capabilities:
# drop:
# - ALL
# readOnlyRootFilesystem: true
# runAsNonRoot: true
# runAsUser: 1000
service:
type: ClusterIP
port: 80
ingress:
enabled: false
className: ""
annotations: {}
# kubernetes.io/ingress.class: nginx
# kubernetes.io/tls-acme: "true"
hosts:
- host: chart-example.local
paths:
- path: /
pathType: ImplementationSpecific
tls: []
# - secretName: chart-example-tls
# hosts:
# - chart-example.local
resources: {}
# We usually recommend not to specify default resources and to leave this as a conscious
# choice for the user. This also increases chances charts run on environments with little
# resources, such as Minikube. If you do want to specify resources, uncomment the following
# lines, adjust them as necessary, and remove the curly braces after 'resources:'.
# limits:
# cpu: 100m
# memory: 128Mi
# requests:
# cpu: 100m
# memory: 128Mi
autoscaling:
enabled: false
minReplicas: 1
maxReplicas: 100
targetCPUUtilizationPercentage: 80
# targetMemoryUtilizationPercentage: 80
nodeSelector: {}
tolerations: []
affinity: {}