mirror of
https://github.com/jpetazzo/container.training.git
synced 2026-02-28 16:30:21 +00:00
Compare commits
8 Commits
2021-04-di
...
2020-11-nr
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3797fc6f9f | ||
|
|
242a3d9ddf | ||
|
|
a14f5e81ce | ||
|
|
109f6503e4 | ||
|
|
337be57182 | ||
|
|
63d88236b2 | ||
|
|
799aa21302 | ||
|
|
95247d6d39 |
@@ -1,49 +0,0 @@
|
||||
k8s_yaml(blob('''
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
labels:
|
||||
app: registry
|
||||
name: registry
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
app: registry
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: registry
|
||||
spec:
|
||||
containers:
|
||||
- image: registry
|
||||
name: registry
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
labels:
|
||||
app: registry
|
||||
name: registry
|
||||
spec:
|
||||
ports:
|
||||
- port: 5000
|
||||
protocol: TCP
|
||||
targetPort: 5000
|
||||
nodePort: 30555
|
||||
selector:
|
||||
app: registry
|
||||
type: NodePort
|
||||
'''))
|
||||
default_registry('localhost:30555')
|
||||
docker_build('dockercoins/hasher', 'hasher')
|
||||
docker_build('dockercoins/rng', 'rng')
|
||||
docker_build('dockercoins/webui', 'webui')
|
||||
docker_build('dockercoins/worker', 'worker')
|
||||
k8s_yaml('../k8s/dockercoins.yaml')
|
||||
|
||||
# Uncomment the following line to let tilt run with the default kubeadm cluster-admin context.
|
||||
#allow_k8s_contexts('kubernetes-admin@kubernetes')
|
||||
|
||||
# While we're here: if you're controlling a remote cluster, uncomment that line.
|
||||
# It will create a port forward so that you can access the remote registry.
|
||||
#k8s_resource(workload='registry', port_forwards='30555:5000')
|
||||
@@ -1,13 +0,0 @@
|
||||
#!/bin/sh
|
||||
# Create an EKS cluster.
|
||||
# This is not idempotent (each time you run it, it creates a new cluster).
|
||||
|
||||
eksctl create cluster \
|
||||
--node-type=t3.large \
|
||||
--nodes-max=10 \
|
||||
--alb-ingress-access \
|
||||
--asg-access \
|
||||
--ssh-access \
|
||||
--with-oidc \
|
||||
#
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
#!/bin/sh
|
||||
# For each user listed in "users.txt", create an IAM user.
|
||||
# Also create AWS API access keys, and store them in "users.keys".
|
||||
# This is idempotent (you can run it multiple times, it will only
|
||||
# create the missing users). However, it will not remove users.
|
||||
# Note that you can remove users from "users.keys" (or even wipe
|
||||
# that file out entirely) and then this script will delete their
|
||||
# keys and generate new keys for them (and add the new keys to
|
||||
# "users.keys".)
|
||||
|
||||
echo "Getting list of existing users ..."
|
||||
aws iam list-users --output json | jq -r .Users[].UserName > users.tmp
|
||||
|
||||
for U in $(cat users.txt); do
|
||||
if ! grep -qw $U users.tmp; then
|
||||
echo "Creating user $U..."
|
||||
aws iam create-user --user-name=$U \
|
||||
--tags=Key=container.training,Value=1
|
||||
fi
|
||||
if ! grep -qw $U users.keys; then
|
||||
echo "Listing keys for user $U..."
|
||||
KEYS=$(aws iam list-access-keys --user=$U | jq -r .AccessKeyMetadata[].AccessKeyId)
|
||||
for KEY in $KEYS; do
|
||||
echo "Deleting key $KEY for user $U..."
|
||||
aws iam delete-access-key --user=$U --access-key-id=$KEY
|
||||
done
|
||||
echo "Creating access key for user $U..."
|
||||
aws iam create-access-key --user=$U --output json \
|
||||
| jq -r '.AccessKey | [ .UserName, .AccessKeyId, .SecretAccessKey ] | @tsv' \
|
||||
>> users.keys
|
||||
fi
|
||||
done
|
||||
@@ -1,51 +0,0 @@
|
||||
#!/bin/sh
|
||||
# Create an IAM policy to authorize users to do "aws eks update-kubeconfig".
|
||||
# This is idempotent, which allows to update the policy document below if
|
||||
# you want the users to do other things as well.
|
||||
# Note that each time you run this script, it will actually create a new
|
||||
# version of the policy, set that version as the default version, and
|
||||
# remove all non-default versions. (Because you can only have up to
|
||||
# 5 versions of a given policy, so you need to clean them up.)
|
||||
# After running that script, you will want to attach the policy to our
|
||||
# users (check the other scripts in that directory).
|
||||
|
||||
POLICY_NAME=user.container.training
|
||||
POLICY_DOC='{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Action": [
|
||||
"eks:DescribeCluster"
|
||||
],
|
||||
"Resource": "arn:aws:eks:*",
|
||||
"Effect": "Allow"
|
||||
}
|
||||
]
|
||||
}'
|
||||
|
||||
ACCOUNT=$(aws sts get-caller-identity | jq -r .Account)
|
||||
|
||||
aws iam create-policy-version \
|
||||
--policy-arn arn:aws:iam::$ACCOUNT:policy/$POLICY_NAME \
|
||||
--policy-document "$POLICY_DOC" \
|
||||
--set-as-default
|
||||
|
||||
# For reference, the command below creates a policy without versioning:
|
||||
#aws iam create-policy \
|
||||
#--policy-name user.container.training \
|
||||
#--policy-document "$JSON"
|
||||
|
||||
for VERSION in $(
|
||||
aws iam list-policy-versions \
|
||||
--policy-arn arn:aws:iam::$ACCOUNT:policy/$POLICY_NAME \
|
||||
--query 'Versions[?!IsDefaultVersion].VersionId' \
|
||||
--output text)
|
||||
do
|
||||
aws iam delete-policy-version \
|
||||
--policy-arn arn:aws:iam::$ACCOUNT:policy/$POLICY_NAME \
|
||||
--version-id "$VERSION"
|
||||
done
|
||||
|
||||
# For reference, the command below shows all users using the policy:
|
||||
#aws iam list-entities-for-policy \
|
||||
#--policy-arn arn:aws:iam::$ACCOUNT:policy/$POLICY_NAME
|
||||
@@ -1,14 +0,0 @@
|
||||
#!/bin/sh
|
||||
# Attach our user policy to all the users defined in "users.txt".
|
||||
# This should be idempotent, because attaching the same policy
|
||||
# to the same user multiple times doesn't do anything.
|
||||
|
||||
ACCOUNT=$(aws sts get-caller-identity | jq -r .Account)
|
||||
POLICY_NAME=user.container.training
|
||||
|
||||
for U in $(cat users.txt); do
|
||||
echo "Attaching policy to user $U ..."
|
||||
aws iam attach-user-policy \
|
||||
--user-name $U \
|
||||
--policy-arn arn:aws:iam::$ACCOUNT:policy/$POLICY_NAME
|
||||
done
|
||||
@@ -1,24 +0,0 @@
|
||||
#!/bin/sh
|
||||
# Update the aws-auth ConfigMap to map our IAM users to Kubernetes users.
|
||||
# Each user defined in "users.txt" will be mapped to a Kubernetes user
|
||||
# with the same name, and put in the "container.training" group, too.
|
||||
# This is idempotent.
|
||||
# WARNING: this will wipe out the mapUsers component of the aws-auth
|
||||
# ConfigMap, removing all users that aren't in "users.txt".
|
||||
# It won't touch mapRoles, so it shouldn't break the role mappings
|
||||
# put in place by EKS.
|
||||
|
||||
ACCOUNT=$(aws sts get-caller-identity | jq -r .Account)
|
||||
|
||||
rm -f users.map
|
||||
for U in $(cat users.txt); do
|
||||
echo "\
|
||||
- userarn: arn:aws:iam::$ACCOUNT:user/$U
|
||||
username: $U
|
||||
groups: [ container.training ]\
|
||||
" >> users.map
|
||||
done
|
||||
|
||||
kubectl create --namespace=kube-system configmap aws-auth \
|
||||
--dry-run=client --from-file=mapUsers=users.map -o yaml \
|
||||
| kubectl apply -f-
|
||||
@@ -1,65 +0,0 @@
|
||||
#!/bin/sh
|
||||
# Create a shared Kubernetes Namespace ("container-training") as well as
|
||||
# individual namespaces for every user in "users.txt", and set up a bunch
|
||||
# of permissions.
|
||||
# Specifically:
|
||||
# - each user gets "view" permissions in the "default" Namespace
|
||||
# - each user gets "edit" permissions in the "container-training" Namespace
|
||||
# - each user gets permissions to list Nodes and Namespaces
|
||||
# - each user gets "admin" permissions in their personal Namespace
|
||||
# Note that since Kubernetes Namespaces can't have dots in their names,
|
||||
# if a user has dots, dots will be mapped to dashes.
|
||||
# So user "ada.lovelace" will get namespace "ada-lovelace".
|
||||
# This is kind of idempotent (but will raise a bunch of errors for objects
|
||||
# that already exist).
|
||||
# TODO: if this needs to evolve, replace all the "create" operations by
|
||||
# "apply" operations. But this is good enough for now.
|
||||
|
||||
kubectl create rolebinding --namespace default container.training \
|
||||
--group=container.training --clusterrole=view
|
||||
|
||||
kubectl create clusterrole view-nodes \
|
||||
--verb=get,list,watch --resource=node
|
||||
kubectl create clusterrolebinding view-nodes \
|
||||
--group=container.training --clusterrole=view-nodes
|
||||
|
||||
kubectl create clusterrole view-namespaces \
|
||||
--verb=get,list,watch --resource=namespace
|
||||
kubectl create clusterrolebinding view-namespaces \
|
||||
--group=container.training --clusterrole=view-namespaces
|
||||
|
||||
kubectl create namespace container-training
|
||||
kubectl create rolebinding --namespace container-training edit \
|
||||
--group=container.training --clusterrole=edit
|
||||
|
||||
# Note: API calls to EKS tend to be fairly slow. To optimize things a bit,
|
||||
# instead of running "kubectl" N times, we generate a bunch of YAML and
|
||||
# apply it. It will still generate a lot of API calls but it's much faster
|
||||
# than calling "kubectl" N times. It might be possible to make this even
|
||||
# faster by generating a "kind: List" (I don't know if this would issue
|
||||
# a single API calls or multiple ones; TBD!)
|
||||
for U in $(cat users.txt); do
|
||||
NS=$(echo $U | tr . -)
|
||||
cat <<EOF
|
||||
---
|
||||
kind: Namespace
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: $NS
|
||||
---
|
||||
kind: RoleBinding
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
metadata:
|
||||
name: admin
|
||||
namespace: $NS
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: ClusterRole
|
||||
name: admin
|
||||
subjects:
|
||||
- apiGroup: rbac.authorization.k8s.io
|
||||
kind: User
|
||||
name: $U
|
||||
EOF
|
||||
done | kubectl create -f-
|
||||
|
||||
@@ -1,76 +0,0 @@
|
||||
#!/bin/sh
|
||||
# Create an IAM role to be used by a Kubernetes ServiceAccount.
|
||||
# The role isn't given any permissions yet (this has to be done by
|
||||
# another script in this series), but a properly configured Pod
|
||||
# should still be able to execute "aws sts get-caller-identity"
|
||||
# and confirm that it's using that role.
|
||||
# This requires the cluster to have an attached OIDC provider.
|
||||
# This should be the case if the cluster has been created with
|
||||
# the scripts in this directory; otherwise, this can be done with
|
||||
# the subsequent command, which is idempotent:
|
||||
# eksctl utils associate-iam-oidc-provider --cluster cluster-name-12341234 --approve
|
||||
# The policy document used below will authorize all ServiceAccounts
|
||||
# in the "container-training" Namespace to use that role.
|
||||
# This script will also annotate the container-training:default
|
||||
# ServiceAccount so that it can use that role.
|
||||
# This script is not quite idempotent: if you want to use a new
|
||||
# trust policy, some work will be required. (You can delete the role,
|
||||
# but that requires detaching the associated policies. There might also
|
||||
# be a way to update the trust policy directly; we didn't investigate this
|
||||
# further at this point.)
|
||||
|
||||
if [ "$1" ]; then
|
||||
CLUSTER="$1"
|
||||
else
|
||||
echo "Please indicate cluster to use. Available clusters:"
|
||||
aws eks list-clusters --output table
|
||||
exit 1
|
||||
fi
|
||||
|
||||
ACCOUNT=$(aws sts get-caller-identity | jq -r .Account)
|
||||
OIDC=$(aws eks describe-cluster --name $CLUSTER --query cluster.identity.oidc.issuer --output text | cut -d/ -f3-)
|
||||
ROLE_NAME=s3-reader-container-training
|
||||
TRUST_POLICY=$(envsubst <<EOF
|
||||
{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Effect": "Allow",
|
||||
"Principal": {
|
||||
"Federated": "arn:aws:iam::${ACCOUNT}:oidc-provider/${OIDC}"
|
||||
},
|
||||
"Action": "sts:AssumeRoleWithWebIdentity",
|
||||
"Condition": {
|
||||
"StringLike": {
|
||||
"${OIDC}:sub": ["system:serviceaccount:container-training:*"]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
EOF
|
||||
)
|
||||
|
||||
aws iam create-role \
|
||||
--role-name "$ROLE_NAME" \
|
||||
--assume-role-policy-document "$TRUST_POLICY"
|
||||
|
||||
kubectl annotate serviceaccounts \
|
||||
--namespace container-training default \
|
||||
"eks.amazonaws.com/role-arn=arn:aws:iam::$ACCOUNT:role/$ROLE_NAME" \
|
||||
--overwrite
|
||||
|
||||
exit
|
||||
|
||||
# Here are commands to delete the role:
|
||||
for POLICY_ARN in $(aws iam list-attached-role-policies --role-name $ROLE_NAME --query 'AttachedPolicies[*].PolicyArn' --output text); do aws iam detach-role-policy --role-name $ROLE_NAME --policy-arn $POLICY_ARN; done
|
||||
aws iam delete-role --role-name $ROLE_NAME
|
||||
|
||||
# Merging the policy with the existing policies:
|
||||
{
|
||||
aws iam get-role --role-name s3-reader-container-training | jq -r .Role.AssumeRolePolicyDocument.Statement[]
|
||||
echo "$TRUST_POLICY" | jq -r .Statement[]
|
||||
} | jq -s '{"Version": "2012-10-17", "Statement": .}' > /tmp/policy.json
|
||||
aws iam update-assume-role-policy \
|
||||
--role-name $ROLE_NAME \
|
||||
--policy-document file:///tmp/policy.json
|
||||
@@ -1,54 +0,0 @@
|
||||
#!/bin/sh
|
||||
# Create an S3 bucket with two objects in it:
|
||||
# - public.txt (world-readable)
|
||||
# - private.txt (private)
|
||||
# Also create an IAM policy granting read-only access to the bucket
|
||||
# (and therefore, to the private object).
|
||||
# Finally, attach the policy to an IAM role (for instance, the role
|
||||
# created by another script in this directory).
|
||||
# This isn't idempotent, but it can be made idempotent by replacing the
|
||||
# "aws iam create-policy" call with "aws iam create-policy-version" and
|
||||
# a bit of extra elbow grease. (See other scripts in this directory for
|
||||
# an example).
|
||||
|
||||
ACCOUNT=$(aws sts get-caller-identity | jq -r .Account)
|
||||
BUCKET=container.training
|
||||
ROLE_NAME=s3-reader-container-training
|
||||
POLICY_NAME=s3-reader-container-training
|
||||
POLICY_DOC=$(envsubst <<EOF
|
||||
{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Effect": "Allow",
|
||||
"Action": [
|
||||
"s3:ListBucket",
|
||||
"s3:GetObject*"
|
||||
],
|
||||
"Resource": [
|
||||
"arn:aws:s3:::$BUCKET",
|
||||
"arn:aws:s3:::$BUCKET/*"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
EOF
|
||||
)
|
||||
|
||||
aws iam create-policy \
|
||||
--policy-name $POLICY_NAME \
|
||||
--policy-doc "$POLICY_DOC"
|
||||
|
||||
aws s3 mb s3://container.training
|
||||
|
||||
echo "this is a public object" \
|
||||
| aws s3 cp - s3://container.training/public.txt \
|
||||
--acl public-read
|
||||
|
||||
echo "this is a private object" \
|
||||
| aws s3 cp - s3://container.training/private.txt \
|
||||
--acl private
|
||||
|
||||
aws iam attach-role-policy \
|
||||
--role-name "$ROLE_NAME" \
|
||||
--policy-arn arn:aws:iam::$ACCOUNT:policy/$POLICY_NAME
|
||||
@@ -1,50 +0,0 @@
|
||||
ada.lovelace
|
||||
adele.goldstine
|
||||
amanda.jones
|
||||
anita.borg
|
||||
ann.kiessling
|
||||
barbara.mcclintock
|
||||
beatrice.worsley
|
||||
bessie.blount
|
||||
betty.holberton
|
||||
beulah.henry
|
||||
carleen.hutchins
|
||||
caroline.herschel
|
||||
dona.bailey
|
||||
dorothy.hodgkin
|
||||
ellen.ochoa
|
||||
edith.clarke
|
||||
elisha.collier
|
||||
elizabeth.feinler
|
||||
emily.davenport
|
||||
erna.hoover
|
||||
frances.spence
|
||||
gertrude.blanch
|
||||
grace.hopper
|
||||
grete.hermann
|
||||
giuliana.tesoro
|
||||
harriet.tubman
|
||||
hedy.lamarr
|
||||
irma.wyman
|
||||
jane.goodall
|
||||
jean.bartik
|
||||
joy.mangano
|
||||
josephine.cochrane
|
||||
katherine.blodgett
|
||||
kathleen.antonelli
|
||||
lynn.conway
|
||||
margaret.hamilton
|
||||
maria.beasley
|
||||
marie.curie
|
||||
marjorie.joyner
|
||||
marlyn.meltzer
|
||||
mary.kies
|
||||
melitta.bentz
|
||||
milly.koss
|
||||
radia.perlman
|
||||
rosalind.franklin
|
||||
ruth.teitelbaum
|
||||
sarah.mather
|
||||
sophie.wilson
|
||||
stephanie.kwolek
|
||||
yvonne.brill
|
||||
@@ -1,3 +1 @@
|
||||
INFRACLASS=scaleway
|
||||
#SCW_INSTANCE_TYPE=DEV1-L
|
||||
#SCW_ZONE=fr-par-2
|
||||
|
||||
@@ -69,14 +69,11 @@ _cmd_deploy() {
|
||||
echo deploying > tags/$TAG/status
|
||||
sep "Deploying tag $TAG"
|
||||
|
||||
# If this VM image is using cloud-init,
|
||||
# wait for cloud-init to be done
|
||||
# Wait for cloudinit to be done
|
||||
pssh "
|
||||
if [ -d /var/lib/cloud ]; then
|
||||
while [ ! -f /var/lib/cloud/instance/boot-finished ]; do
|
||||
sleep 1
|
||||
done
|
||||
fi"
|
||||
while [ ! -f /var/lib/cloud/instance/boot-finished ]; do
|
||||
sleep 1
|
||||
done"
|
||||
|
||||
# Special case for scaleway since it doesn't come with sudo
|
||||
if [ "$INFRACLASS" = "scaleway" ]; then
|
||||
@@ -105,12 +102,6 @@ _cmd_deploy() {
|
||||
sudo apt-get update &&
|
||||
sudo apt-get install -y python-yaml"
|
||||
|
||||
# If there is no "python" binary, symlink to python3
|
||||
#pssh "
|
||||
#if ! which python; then
|
||||
# ln -s $(which python3) /usr/local/bin/python
|
||||
#fi"
|
||||
|
||||
# Copy postprep.py to the remote machines, and execute it, feeding it the list of IP addresses
|
||||
pssh -I tee /tmp/postprep.py <lib/postprep.py
|
||||
pssh --timeout 900 --send-input "python /tmp/postprep.py >>/tmp/pp.out 2>>/tmp/pp.err" <tags/$TAG/ips.txt
|
||||
@@ -217,14 +208,7 @@ _cmd_kube() {
|
||||
echo 'alias k=kubectl' | sudo tee /etc/bash_completion.d/k &&
|
||||
echo 'complete -F __start_kubectl k' | sudo tee -a /etc/bash_completion.d/k"
|
||||
|
||||
# Disable swap
|
||||
# (note that this won't survive across node reboots!)
|
||||
if [ "$INFRACLASS" = "linode" ]; then
|
||||
pssh "
|
||||
sudo swapoff -a"
|
||||
fi
|
||||
|
||||
# Initialize kube control plane
|
||||
# Initialize kube master
|
||||
pssh --timeout 200 "
|
||||
if i_am_first_node && [ ! -f /etc/kubernetes/admin.conf ]; then
|
||||
kubeadm token generate > /tmp/token &&
|
||||
@@ -737,7 +721,7 @@ _cmd_helmprom() {
|
||||
need_tag
|
||||
pssh "
|
||||
if i_am_first_node; then
|
||||
sudo -u docker -H helm repo add prometheus-community https://prometheus-community.github.io/helm-charts/
|
||||
sudo -u docker -H helm helm repo add prometheus-community https://prometheus-community.github.io/helm-charts/
|
||||
sudo -u docker -H helm install prometheus prometheus-community/prometheus \
|
||||
--namespace kube-system \
|
||||
--set server.service.type=NodePort \
|
||||
|
||||
@@ -1,58 +0,0 @@
|
||||
if ! command -v linode-cli >/dev/null; then
|
||||
warn "Linode CLI (linode-cli) not found."
|
||||
fi
|
||||
if ! [ -f ~/.config/linode-cli ]; then
|
||||
warn "~/.config/linode-cli not found."
|
||||
fi
|
||||
|
||||
# To view available regions: "linode-cli regions list"
|
||||
LINODE_REGION=${LINODE_REGION-us-west}
|
||||
|
||||
# To view available types: "linode-cli linodes types"
|
||||
LINODE_TYPE=${LINODE_TYPE-g6-standard-2}
|
||||
|
||||
infra_list() {
|
||||
linode-cli linodes list --json |
|
||||
jq -r '.[] | [.id, .label, .status, .type] | @tsv'
|
||||
}
|
||||
|
||||
infra_start() {
|
||||
COUNT=$1
|
||||
|
||||
for I in $(seq 1 $COUNT); do
|
||||
NAME=$(printf "%s-%03d" $TAG $I)
|
||||
sep "Starting instance $I/$COUNT"
|
||||
info " Zone: $LINODE_REGION"
|
||||
info " Name: $NAME"
|
||||
info " Instance type: $LINODE_TYPE"
|
||||
ROOT_PASS="$(base64 /dev/urandom | cut -c1-20 | head -n 1)"
|
||||
linode-cli linodes create \
|
||||
--type=${LINODE_TYPE} --region=${LINODE_REGION} \
|
||||
--image=linode/ubuntu18.04 \
|
||||
--authorized_keys="${LINODE_SSHKEY}" \
|
||||
--root_pass="${ROOT_PASS}" \
|
||||
--tags=${TAG} --label=${NAME}
|
||||
done
|
||||
sep
|
||||
|
||||
linode_get_ips_by_tag $TAG > tags/$TAG/ips.txt
|
||||
}
|
||||
|
||||
infra_stop() {
|
||||
info "Counting instances..."
|
||||
linode_get_ids_by_tag $TAG | wc -l
|
||||
info "Deleting instances..."
|
||||
linode_get_ids_by_tag $TAG |
|
||||
xargs -n1 -P10 \
|
||||
linode-cli linodes delete
|
||||
}
|
||||
|
||||
linode_get_ids_by_tag() {
|
||||
TAG=$1
|
||||
linode-cli linodes list --tags $TAG --json | jq -r ".[].id"
|
||||
}
|
||||
|
||||
linode_get_ips_by_tag() {
|
||||
TAG=$1
|
||||
linode-cli linodes list --tags $TAG --json | jq -r ".[].ipv4[0]"
|
||||
}
|
||||
@@ -5,9 +5,6 @@ if ! [ -f ~/.config/scw/config.yaml ]; then
|
||||
warn "~/.config/scw/config.yaml not found."
|
||||
fi
|
||||
|
||||
SCW_INSTANCE_TYPE=${SCW_INSTANCE_TYPE-DEV1-M}
|
||||
SCW_ZONE=${SCW_ZONE-fr-par-1}
|
||||
|
||||
infra_list() {
|
||||
scw instance server list -o json |
|
||||
jq -r '.[] | [.id, .name, .state, .commercial_type] | @tsv'
|
||||
@@ -16,6 +13,9 @@ infra_list() {
|
||||
infra_start() {
|
||||
COUNT=$1
|
||||
|
||||
SCW_INSTANCE_TYPE=${SCW_INSTANCE_TYPE-DEV1-M}
|
||||
SCW_ZONE=${SCW_ZONE-fr-par-1}
|
||||
|
||||
for I in $(seq 1 $COUNT); do
|
||||
NAME=$(printf "%s-%03d" $TAG $I)
|
||||
sep "Starting instance $I/$COUNT"
|
||||
@@ -36,16 +36,16 @@ infra_stop() {
|
||||
scw_get_ids_by_tag $TAG | wc -l
|
||||
info "Deleting instances..."
|
||||
scw_get_ids_by_tag $TAG |
|
||||
xargs -n1 -P10 \
|
||||
scw instance server delete zone=${SCW_ZONE} force-shutdown=true with-ip=true
|
||||
xargs -n1 -P10 -I@@ \
|
||||
scw instance server delete force-shutdown=true server-id=@@
|
||||
}
|
||||
|
||||
scw_get_ids_by_tag() {
|
||||
TAG=$1
|
||||
scw instance server list zone=${SCW_ZONE} name=$TAG -o json | jq -r .[].id
|
||||
scw instance server list name=$TAG -o json | jq -r .[].id
|
||||
}
|
||||
|
||||
scw_get_ips_by_tag() {
|
||||
TAG=$1
|
||||
scw instance server list zone=${SCW_ZONE} name=$TAG -o json | jq -r .[].public_ip.address
|
||||
scw instance server list name=$TAG -o json | jq -r .[].public_ip.address
|
||||
}
|
||||
|
||||
@@ -18,11 +18,11 @@ pssh() {
|
||||
echo "[parallel-ssh] $@"
|
||||
export PSSH=$(which pssh || which parallel-ssh)
|
||||
|
||||
case "$INFRACLASS" in
|
||||
hetzner) LOGIN=root ;;
|
||||
linode) LOGIN=root ;;
|
||||
*) LOGIN=ubuntu ;;
|
||||
esac
|
||||
if [ "$INFRACLASS" = hetzner ]; then
|
||||
LOGIN=root
|
||||
else
|
||||
LOGIN=ubuntu
|
||||
fi
|
||||
|
||||
$PSSH -h $HOSTFILE -l $LOGIN \
|
||||
--par 100 \
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
"""
|
||||
There are two ways to use this script:
|
||||
|
||||
1. Pass a file name and a tag name as a single argument.
|
||||
It will load a list of domains from the given file (one per line),
|
||||
and assign them to the clusters corresponding to that tag.
|
||||
There should be more domains than clusters.
|
||||
Example: ./map-dns.py domains.txt 2020-08-15-jp
|
||||
1. Pass a tag name as a single argument.
|
||||
It will then take the clusters corresponding to that tag, and assign one
|
||||
domain name per cluster. Currently it gets the domains from a hard-coded
|
||||
path. There should be more domains than clusters.
|
||||
Example: ./map-dns.py 2020-08-15-jp
|
||||
|
||||
2. Pass a domain as the 1st argument, and IP addresses then.
|
||||
It will configure the domain with the listed IP addresses.
|
||||
@@ -19,53 +19,55 @@ import requests
|
||||
import sys
|
||||
import yaml
|
||||
|
||||
# This can be tweaked if necessary.
|
||||
# configurable stuff
|
||||
domains_file = "../../plentydomains/domains.txt"
|
||||
config_file = os.path.join(
|
||||
os.environ["HOME"], ".config/gandi/config.yaml")
|
||||
os.environ["HOME"], ".config/gandi/config.yaml")
|
||||
tag = None
|
||||
apiurl = "https://dns.api.gandi.net/api/v5/domains"
|
||||
|
||||
if len(sys.argv) == 2:
|
||||
tag = sys.argv[1]
|
||||
domains = open(domains_file).read().split()
|
||||
domains = [ d for d in domains if not d.startswith('#') ]
|
||||
ips = open(f"tags/{tag}/ips.txt").read().split()
|
||||
settings_file = f"tags/{tag}/settings.yaml"
|
||||
clustersize = yaml.safe_load(open(settings_file))["clustersize"]
|
||||
else:
|
||||
domains = [sys.argv[1]]
|
||||
ips = sys.argv[2:]
|
||||
clustersize = len(ips)
|
||||
|
||||
# inferred stuff
|
||||
apikey = yaml.safe_load(open(config_file))["apirest"]["key"]
|
||||
|
||||
# Figure out if we're called for a bunch of domains, or just one.
|
||||
domain_or_domain_file = sys.argv[1]
|
||||
if os.path.isfile(domain_or_domain_file):
|
||||
domains = open(domain_or_domain_file).read().split()
|
||||
domains = [ d for d in domains if not d.startswith('#') ]
|
||||
tag = sys.argv[2]
|
||||
ips = open(f"tags/{tag}/ips.txt").read().split()
|
||||
settings_file = f"tags/{tag}/settings.yaml"
|
||||
clustersize = yaml.safe_load(open(settings_file))["clustersize"]
|
||||
else:
|
||||
domains = [domain_or_domain_file]
|
||||
ips = sys.argv[2:]
|
||||
clustersize = len(ips)
|
||||
|
||||
# Now, do the work.
|
||||
# now do the fucking work
|
||||
while domains and ips:
|
||||
domain = domains[0]
|
||||
domains = domains[1:]
|
||||
cluster = ips[:clustersize]
|
||||
ips = ips[clustersize:]
|
||||
print(f"{domain} => {cluster}")
|
||||
zone = ""
|
||||
node = 0
|
||||
for ip in cluster:
|
||||
node += 1
|
||||
zone += f"@ 300 IN A {ip}\n"
|
||||
zone += f"* 300 IN A {ip}\n"
|
||||
zone += f"node{node} 300 IN A {ip}\n"
|
||||
r = requests.put(
|
||||
f"{apiurl}/{domain}/records",
|
||||
headers={"x-api-key": apikey},
|
||||
data=zone)
|
||||
print(r.text)
|
||||
domain = domains[0]
|
||||
domains = domains[1:]
|
||||
cluster = ips[:clustersize]
|
||||
ips = ips[clustersize:]
|
||||
print(f"{domain} => {cluster}")
|
||||
zone = ""
|
||||
node = 0
|
||||
for ip in cluster:
|
||||
node += 1
|
||||
zone += f"@ 300 IN A {ip}\n"
|
||||
zone += f"* 300 IN A {ip}\n"
|
||||
zone += f"node{node} 300 IN A {ip}\n"
|
||||
r = requests.put(
|
||||
f"{apiurl}/{domain}/records",
|
||||
headers={"x-api-key": apikey},
|
||||
data=zone)
|
||||
print(r.text)
|
||||
|
||||
#r = requests.get(
|
||||
# f"{apiurl}/{domain}/records",
|
||||
# headers={"x-api-key": apikey},
|
||||
# )
|
||||
#r = requests.get(
|
||||
# f"{apiurl}/{domain}/records",
|
||||
# headers={"x-api-key": apikey},
|
||||
# )
|
||||
|
||||
if domains:
|
||||
print(f"Good, we have {len(domains)} domains left.")
|
||||
print(f"Good, we have {len(domains)} domains left.")
|
||||
|
||||
if ips:
|
||||
print(f"Crap, we have {len(ips)} IP addresses left.")
|
||||
print(f"Crap, we have {len(ips)} IP addresses left.")
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#/ /kube-halfday.yml.html 200!
|
||||
#/ /kube-fullday.yml.html 200!
|
||||
#/ /kube-twodays.yml.html 200!
|
||||
/ /kube-adv.yml.html 200!
|
||||
|
||||
# And this allows to do "git clone https://container.training".
|
||||
/info/refs service=git-upload-pack https://github.com/jpetazzo/container.training/info/refs?service=git-upload-pack
|
||||
@@ -21,5 +22,3 @@
|
||||
|
||||
# Survey form
|
||||
/please https://docs.google.com/forms/d/e/1FAIpQLSfIYSgrV7tpfBNm1hOaprjnBHgWKn5n-k5vtNXYJkOX1sRxng/viewform
|
||||
|
||||
/ /helm.yml.html 200!
|
||||
|
||||
298
slides/autopilot/package-lock.json
generated
298
slides/autopilot/package-lock.json
generated
@@ -24,9 +24,14 @@
|
||||
"integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI="
|
||||
},
|
||||
"arraybuffer.slice": {
|
||||
"version": "0.0.7",
|
||||
"resolved": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz",
|
||||
"integrity": "sha512-wGUIVQXuehL5TCqQun8OW81jGzAWycqzFF8lFp+GOM5BXLYj3bKNsYC4daB7n6XjCqxQA/qgTJ+8ANR3acjrog=="
|
||||
"version": "0.0.6",
|
||||
"resolved": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.6.tgz",
|
||||
"integrity": "sha1-8zshWfBTKj8xB6JywMz70a0peco="
|
||||
},
|
||||
"async-limiter": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz",
|
||||
"integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg=="
|
||||
},
|
||||
"backo2": {
|
||||
"version": "1.0.2",
|
||||
@@ -34,19 +39,27 @@
|
||||
"integrity": "sha1-MasayLEpNjRj41s+u2n038+6eUc="
|
||||
},
|
||||
"base64-arraybuffer": {
|
||||
"version": "0.1.4",
|
||||
"resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.4.tgz",
|
||||
"integrity": "sha1-mBjHngWbE1X5fgQooBfIOOkLqBI="
|
||||
"version": "0.1.5",
|
||||
"resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz",
|
||||
"integrity": "sha1-c5JncZI7Whl0etZmqlzUv5xunOg="
|
||||
},
|
||||
"base64id": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz",
|
||||
"integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog=="
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/base64id/-/base64id-1.0.0.tgz",
|
||||
"integrity": "sha1-R2iMuZu2gE8OBtPnY7HDLlfY5rY="
|
||||
},
|
||||
"better-assert": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/better-assert/-/better-assert-1.0.2.tgz",
|
||||
"integrity": "sha1-QIZrnhueC1W0gYlDEeaPr/rrxSI=",
|
||||
"requires": {
|
||||
"callsite": "1.0.0"
|
||||
}
|
||||
},
|
||||
"blob": {
|
||||
"version": "0.0.5",
|
||||
"resolved": "https://registry.npmjs.org/blob/-/blob-0.0.5.tgz",
|
||||
"integrity": "sha512-gaqbzQPqOoamawKg0LGVd7SzLgXS+JH61oWprSLH+P+abTczqJbhTR8CmJ2u9/bUYNmHTGJx/UEmn6doAvvuig=="
|
||||
"version": "0.0.4",
|
||||
"resolved": "https://registry.npmjs.org/blob/-/blob-0.0.4.tgz",
|
||||
"integrity": "sha1-vPEwUspURj8w+fx+lbmkdjCpSSE="
|
||||
},
|
||||
"body-parser": {
|
||||
"version": "1.18.2",
|
||||
@@ -70,15 +83,20 @@
|
||||
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz",
|
||||
"integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg="
|
||||
},
|
||||
"callsite": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz",
|
||||
"integrity": "sha1-KAOY5dZkvXQDi28JBRU+borxvCA="
|
||||
},
|
||||
"component-bind": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/component-bind/-/component-bind-1.0.0.tgz",
|
||||
"integrity": "sha1-AMYIq33Nk4l8AAllGx06jh5zu9E="
|
||||
},
|
||||
"component-emitter": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz",
|
||||
"integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg=="
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz",
|
||||
"integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY="
|
||||
},
|
||||
"component-inherit": {
|
||||
"version": "0.0.3",
|
||||
@@ -134,76 +152,58 @@
|
||||
"integrity": "sha1-eePVhlU0aQn+bw9Fpd5oEDspTSA="
|
||||
},
|
||||
"engine.io": {
|
||||
"version": "3.5.0",
|
||||
"resolved": "https://registry.npmjs.org/engine.io/-/engine.io-3.5.0.tgz",
|
||||
"integrity": "sha512-21HlvPUKaitDGE4GXNtQ7PLP0Sz4aWLddMPw2VTyFz1FVZqu/kZsJUO8WNpKuE/OCL7nkfRaOui2ZCJloGznGA==",
|
||||
"version": "3.1.4",
|
||||
"resolved": "https://registry.npmjs.org/engine.io/-/engine.io-3.1.4.tgz",
|
||||
"integrity": "sha1-PQIRtwpVLOhB/8fahiezAamkFi4=",
|
||||
"requires": {
|
||||
"accepts": "~1.3.4",
|
||||
"base64id": "2.0.0",
|
||||
"cookie": "~0.4.1",
|
||||
"debug": "~4.1.0",
|
||||
"engine.io-parser": "~2.2.0",
|
||||
"ws": "~7.4.2"
|
||||
"accepts": "1.3.3",
|
||||
"base64id": "1.0.0",
|
||||
"cookie": "0.3.1",
|
||||
"debug": "2.6.9",
|
||||
"engine.io-parser": "2.1.1",
|
||||
"uws": "0.14.5",
|
||||
"ws": "3.3.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"cookie": {
|
||||
"version": "0.4.1",
|
||||
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz",
|
||||
"integrity": "sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA=="
|
||||
},
|
||||
"debug": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
|
||||
"integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
|
||||
"accepts": {
|
||||
"version": "1.3.3",
|
||||
"resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.3.tgz",
|
||||
"integrity": "sha1-w8p0NJOGSMPg2cHjKN1otiLChMo=",
|
||||
"requires": {
|
||||
"ms": "^2.1.1"
|
||||
"mime-types": "2.1.17",
|
||||
"negotiator": "0.6.1"
|
||||
}
|
||||
},
|
||||
"ms": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
||||
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"engine.io-client": {
|
||||
"version": "3.5.0",
|
||||
"resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-3.5.0.tgz",
|
||||
"integrity": "sha512-12wPRfMrugVw/DNyJk34GQ5vIVArEcVMXWugQGGuw2XxUSztFNmJggZmv8IZlLyEdnpO1QB9LkcjeWewO2vxtA==",
|
||||
"version": "3.1.4",
|
||||
"resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-3.1.4.tgz",
|
||||
"integrity": "sha1-T88TcLRxY70s6b4nM5ckMDUNTqE=",
|
||||
"requires": {
|
||||
"component-emitter": "~1.3.0",
|
||||
"component-emitter": "1.2.1",
|
||||
"component-inherit": "0.0.3",
|
||||
"debug": "~3.1.0",
|
||||
"engine.io-parser": "~2.2.0",
|
||||
"debug": "2.6.9",
|
||||
"engine.io-parser": "2.1.1",
|
||||
"has-cors": "1.1.0",
|
||||
"indexof": "0.0.1",
|
||||
"parseqs": "0.0.6",
|
||||
"parseuri": "0.0.6",
|
||||
"ws": "~7.4.2",
|
||||
"xmlhttprequest-ssl": "~1.5.4",
|
||||
"parseqs": "0.0.5",
|
||||
"parseuri": "0.0.5",
|
||||
"ws": "3.3.3",
|
||||
"xmlhttprequest-ssl": "1.5.4",
|
||||
"yeast": "0.1.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"debug": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
|
||||
"integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
|
||||
"requires": {
|
||||
"ms": "2.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"engine.io-parser": {
|
||||
"version": "2.2.1",
|
||||
"resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-2.2.1.tgz",
|
||||
"integrity": "sha512-x+dN/fBH8Ro8TFwJ+rkB2AmuVw9Yu2mockR/p3W8f8YtExwFgDvBDi0GWyb4ZLkpahtDGZgtr3zLovanJghPqg==",
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-2.1.1.tgz",
|
||||
"integrity": "sha1-4Ps/DgRi9/WLt3waUun1p+JuRmg=",
|
||||
"requires": {
|
||||
"after": "0.8.2",
|
||||
"arraybuffer.slice": "~0.0.7",
|
||||
"base64-arraybuffer": "0.1.4",
|
||||
"blob": "0.0.5",
|
||||
"has-binary2": "~1.0.2"
|
||||
"arraybuffer.slice": "0.0.6",
|
||||
"base64-arraybuffer": "0.1.5",
|
||||
"blob": "0.0.4",
|
||||
"has-binary2": "1.0.2"
|
||||
}
|
||||
},
|
||||
"escape-html": {
|
||||
@@ -278,9 +278,9 @@
|
||||
"integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac="
|
||||
},
|
||||
"has-binary2": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/has-binary2/-/has-binary2-1.0.3.tgz",
|
||||
"integrity": "sha512-G1LWKhDSvhGeAQ8mPVQlqNcOB2sJdwATtZKl2pDKKHfpf/rYj24lkinxf69blJbnsvtqqNU+L3SL50vzZhXOnw==",
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/has-binary2/-/has-binary2-1.0.2.tgz",
|
||||
"integrity": "sha1-6D26SfC5vk0CbSc2U1DZ8D9Uvpg=",
|
||||
"requires": {
|
||||
"isarray": "2.0.1"
|
||||
}
|
||||
@@ -376,6 +376,11 @@
|
||||
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz",
|
||||
"integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk="
|
||||
},
|
||||
"object-component": {
|
||||
"version": "0.0.3",
|
||||
"resolved": "https://registry.npmjs.org/object-component/-/object-component-0.0.3.tgz",
|
||||
"integrity": "sha1-8MaapQ78lbhmwYb0AKM3acsvEpE="
|
||||
},
|
||||
"on-finished": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
|
||||
@@ -385,14 +390,20 @@
|
||||
}
|
||||
},
|
||||
"parseqs": {
|
||||
"version": "0.0.6",
|
||||
"resolved": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.6.tgz",
|
||||
"integrity": "sha512-jeAGzMDbfSHHA091hr0r31eYfTig+29g3GKKE/PPbEQ65X0lmMwlEoqmhzu0iztID5uJpZsFlUPDP8ThPL7M8w=="
|
||||
"version": "0.0.5",
|
||||
"resolved": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.5.tgz",
|
||||
"integrity": "sha1-1SCKNzjkZ2bikbouoXNoSSGouJ0=",
|
||||
"requires": {
|
||||
"better-assert": "1.0.2"
|
||||
}
|
||||
},
|
||||
"parseuri": {
|
||||
"version": "0.0.6",
|
||||
"resolved": "https://registry.npmjs.org/parseuri/-/parseuri-0.0.6.tgz",
|
||||
"integrity": "sha512-AUjen8sAkGgao7UyCX6Ahv0gIK2fABKmYjvP4xmy5JaKvcbTRueIqIPHLAfq30xJddqSE033IOMUSOMCcK3Sow=="
|
||||
"version": "0.0.5",
|
||||
"resolved": "https://registry.npmjs.org/parseuri/-/parseuri-0.0.5.tgz",
|
||||
"integrity": "sha1-gCBKUNTbt3m/3G6+J3jZDkvOMgo=",
|
||||
"requires": {
|
||||
"better-assert": "1.0.2"
|
||||
}
|
||||
},
|
||||
"parseurl": {
|
||||
"version": "1.3.2",
|
||||
@@ -476,104 +487,51 @@
|
||||
"integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ=="
|
||||
},
|
||||
"socket.io": {
|
||||
"version": "2.4.0",
|
||||
"resolved": "https://registry.npmjs.org/socket.io/-/socket.io-2.4.0.tgz",
|
||||
"integrity": "sha512-9UPJ1UTvKayuQfVv2IQ3k7tCQC/fboDyIK62i99dAQIyHKaBsNdTpwHLgKJ6guRWxRtC9H+138UwpaGuQO9uWQ==",
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/socket.io/-/socket.io-2.0.4.tgz",
|
||||
"integrity": "sha1-waRZDO/4fs8TxyZS8Eb3FrKeYBQ=",
|
||||
"requires": {
|
||||
"debug": "~4.1.0",
|
||||
"engine.io": "~3.5.0",
|
||||
"has-binary2": "~1.0.2",
|
||||
"socket.io-adapter": "~1.1.0",
|
||||
"socket.io-client": "2.4.0",
|
||||
"socket.io-parser": "~3.4.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"debug": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
|
||||
"integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
|
||||
"requires": {
|
||||
"ms": "^2.1.1"
|
||||
}
|
||||
},
|
||||
"ms": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
||||
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
|
||||
}
|
||||
"debug": "2.6.9",
|
||||
"engine.io": "3.1.4",
|
||||
"socket.io-adapter": "1.1.1",
|
||||
"socket.io-client": "2.0.4",
|
||||
"socket.io-parser": "3.1.2"
|
||||
}
|
||||
},
|
||||
"socket.io-adapter": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-1.1.2.tgz",
|
||||
"integrity": "sha512-WzZRUj1kUjrTIrUKpZLEzFZ1OLj5FwLlAFQs9kuZJzJi5DKdU7FsWc36SNmA8iDOtwBQyT8FkrriRM8vXLYz8g=="
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-1.1.1.tgz",
|
||||
"integrity": "sha1-KoBeihTWNyEk3ZFZrUUC+MsH8Gs="
|
||||
},
|
||||
"socket.io-client": {
|
||||
"version": "2.4.0",
|
||||
"resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-2.4.0.tgz",
|
||||
"integrity": "sha512-M6xhnKQHuuZd4Ba9vltCLT9oa+YvTsP8j9NcEiLElfIg8KeYPyhWOes6x4t+LTAC8enQbE/995AdTem2uNyKKQ==",
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-2.0.4.tgz",
|
||||
"integrity": "sha1-CRilUkBtxeVAs4Dc2Xr8SmQzL44=",
|
||||
"requires": {
|
||||
"backo2": "1.0.2",
|
||||
"base64-arraybuffer": "0.1.5",
|
||||
"component-bind": "1.0.0",
|
||||
"component-emitter": "~1.3.0",
|
||||
"debug": "~3.1.0",
|
||||
"engine.io-client": "~3.5.0",
|
||||
"has-binary2": "~1.0.2",
|
||||
"component-emitter": "1.2.1",
|
||||
"debug": "2.6.9",
|
||||
"engine.io-client": "3.1.4",
|
||||
"has-cors": "1.1.0",
|
||||
"indexof": "0.0.1",
|
||||
"parseqs": "0.0.6",
|
||||
"parseuri": "0.0.6",
|
||||
"socket.io-parser": "~3.3.0",
|
||||
"object-component": "0.0.3",
|
||||
"parseqs": "0.0.5",
|
||||
"parseuri": "0.0.5",
|
||||
"socket.io-parser": "3.1.2",
|
||||
"to-array": "0.1.4"
|
||||
},
|
||||
"dependencies": {
|
||||
"debug": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
|
||||
"integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
|
||||
"requires": {
|
||||
"ms": "2.0.0"
|
||||
}
|
||||
},
|
||||
"socket.io-parser": {
|
||||
"version": "3.3.2",
|
||||
"resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.3.2.tgz",
|
||||
"integrity": "sha512-FJvDBuOALxdCI9qwRrO/Rfp9yfndRtc1jSgVgV8FDraihmSP/MLGD5PEuJrNfjALvcQ+vMDM/33AWOYP/JSjDg==",
|
||||
"requires": {
|
||||
"component-emitter": "~1.3.0",
|
||||
"debug": "~3.1.0",
|
||||
"isarray": "2.0.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"socket.io-parser": {
|
||||
"version": "3.4.1",
|
||||
"resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.4.1.tgz",
|
||||
"integrity": "sha512-11hMgzL+WCLWf1uFtHSNvliI++tcRUWdoeYuwIl+Axvwy9z2gQM+7nJyN3STj1tLj5JyIUH8/gpDGxzAlDdi0A==",
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.1.2.tgz",
|
||||
"integrity": "sha1-28IoIVH8T6675Aru3Ady66YZ9/I=",
|
||||
"requires": {
|
||||
"component-emitter": "1.2.1",
|
||||
"debug": "~4.1.0",
|
||||
"debug": "2.6.9",
|
||||
"has-binary2": "1.0.2",
|
||||
"isarray": "2.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"component-emitter": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz",
|
||||
"integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY="
|
||||
},
|
||||
"debug": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
|
||||
"integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
|
||||
"requires": {
|
||||
"ms": "^2.1.1"
|
||||
}
|
||||
},
|
||||
"ms": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
||||
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"statuses": {
|
||||
@@ -595,6 +553,11 @@
|
||||
"mime-types": "2.1.17"
|
||||
}
|
||||
},
|
||||
"ultron": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/ultron/-/ultron-1.1.1.tgz",
|
||||
"integrity": "sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og=="
|
||||
},
|
||||
"unpipe": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
|
||||
@@ -605,20 +568,31 @@
|
||||
"resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
|
||||
"integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM="
|
||||
},
|
||||
"uws": {
|
||||
"version": "0.14.5",
|
||||
"resolved": "https://registry.npmjs.org/uws/-/uws-0.14.5.tgz",
|
||||
"integrity": "sha1-Z6rzPEaypYel9mZtAPdpEyjxSdw=",
|
||||
"optional": true
|
||||
},
|
||||
"vary": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
|
||||
"integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw="
|
||||
},
|
||||
"ws": {
|
||||
"version": "7.4.2",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-7.4.2.tgz",
|
||||
"integrity": "sha512-T4tewALS3+qsrpGI/8dqNMLIVdq/g/85U98HPMa6F0m6xTbvhXU6RCQLqPH3+SlomNV/LdY6RXEbBpMH6EOJnA=="
|
||||
"version": "3.3.3",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-3.3.3.tgz",
|
||||
"integrity": "sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==",
|
||||
"requires": {
|
||||
"async-limiter": "1.0.0",
|
||||
"safe-buffer": "5.1.1",
|
||||
"ultron": "1.1.1"
|
||||
}
|
||||
},
|
||||
"xmlhttprequest-ssl": {
|
||||
"version": "1.5.5",
|
||||
"resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz",
|
||||
"integrity": "sha1-wodrBhaKrcQOV9l+gRkayPQ5iz4="
|
||||
"version": "1.5.4",
|
||||
"resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.4.tgz",
|
||||
"integrity": "sha1-BPVgkVcks4kIhxXMDteBPpZ3v1c="
|
||||
},
|
||||
"yeast": {
|
||||
"version": "0.1.2",
|
||||
|
||||
@@ -3,6 +3,6 @@
|
||||
"version": "0.0.1",
|
||||
"dependencies": {
|
||||
"express": "^4.16.2",
|
||||
"socket.io": "^2.4.0"
|
||||
"socket.io": "^2.0.4"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -329,4 +329,4 @@ This is ideal to debug regressions, do side-by-side comparisons, etc.
|
||||
:EN:- Connecting services together with a *Compose file*
|
||||
|
||||
:FR:- Utiliser Compose pour décrire son environnement
|
||||
:FR:- Écrire un *Compose file* pour connecter les services entre eux
|
||||
:FR:- Écrire un *Compose file* pour connecter les services entre eux
|
||||
@@ -742,15 +742,3 @@ class: extra-details
|
||||
* This may be used to access an internal package repository.
|
||||
|
||||
(But try to use a multi-stage build instead, if possible!)
|
||||
|
||||
???
|
||||
|
||||
:EN:Container networking essentials
|
||||
:EN:- The Container Network Model
|
||||
:EN:- Container isolation
|
||||
:EN:- Service discovery
|
||||
|
||||
:FR:Mettre ses conteneurs en réseau
|
||||
:FR:- Le "Container Network Model"
|
||||
:FR:- Isolation des conteneurs
|
||||
:FR:- *Service discovery*
|
||||
|
||||
@@ -229,5 +229,10 @@ containers together without exposing their ports.
|
||||
|
||||
???
|
||||
|
||||
:EN:- Exposing single containers
|
||||
:FR:- Exposer un conteneur isolé
|
||||
:EN:Connecting containers
|
||||
:EN:- Container networking basics
|
||||
:EN:- Exposing a container
|
||||
|
||||
:FR:Connecter les conteneurs
|
||||
:FR:- Description du modèle réseau des conteneurs
|
||||
:FR:- Exposer un conteneur
|
||||
|
||||
@@ -101,5 +101,5 @@ Success!
|
||||
|
||||
???
|
||||
|
||||
:EN:- Leveraging the build cache for faster builds
|
||||
:EN:- The build cache
|
||||
:FR:- Tirer parti du cache afin d'optimiser la vitesse de *build*
|
||||
|
||||
@@ -424,7 +424,7 @@ services:
|
||||
|
||||
- In this chapter, we showed many ways to write Dockerfiles.
|
||||
|
||||
- These Dockerfiles use sometimes diametrically opposed techniques.
|
||||
- These Dockerfiles use sometimes diametrally opposed techniques.
|
||||
|
||||
- Yet, they were the "right" ones *for a specific situation.*
|
||||
|
||||
@@ -434,12 +434,5 @@ services:
|
||||
|
||||
???
|
||||
|
||||
:EN:Optimizing images
|
||||
:EN:- Dockerfile tips, tricks, and best practices
|
||||
:EN:- Reducing build time
|
||||
:EN:- Reducing image size
|
||||
|
||||
:FR:Optimiser ses images
|
||||
:FR:- Bonnes pratiques, trucs et astuces
|
||||
:FR:- Réduire le temps de build
|
||||
:FR:- Réduire la taille des images
|
||||
:FR:- Bonnes pratiques pour la construction des images
|
||||
|
||||
@@ -82,12 +82,3 @@ Use cases:
|
||||
* Those containers can communicate over their `lo` interface.
|
||||
<br/>(i.e. one can bind to 127.0.0.1 and the others can connect to it.)
|
||||
|
||||
???
|
||||
|
||||
:EN:Advanced container networking
|
||||
:EN:- Transparent network access with the "host" driver
|
||||
:EN:- Sharing is caring with the "container" driver
|
||||
|
||||
:FR:Paramétrage réseau avancé
|
||||
:FR:- Accès transparent au réseau avec le mode "host"
|
||||
:FR:- Partage de la pile réseau avece le mode "container"
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
title: |
|
||||
Packaging d'applications
|
||||
et CI/CD pour Kubernetes
|
||||
|
||||
#chat: "[Gitter](https://gitter.im/jpetazzo/training-202102-online)"
|
||||
|
||||
gitrepo: github.com/jpetazzo/container.training
|
||||
|
||||
slides: https://2021-04-dijon.container.training/
|
||||
|
||||
#slidenumberprefix: "#SomeHashTag — "
|
||||
|
||||
exclude:
|
||||
- self-paced
|
||||
|
||||
content:
|
||||
- shared/title.md
|
||||
#- logistics.md
|
||||
- k8s/intro.md
|
||||
- shared/about-slides.md
|
||||
- shared/prereqs.md
|
||||
- shared/webssh.md
|
||||
- shared/connecting.md
|
||||
#- shared/chat-room-im.md
|
||||
#- shared/chat-room-zoom.md
|
||||
- shared/toc.md
|
||||
-
|
||||
- shared/sampleapp.md
|
||||
- k8s/helm-intro.md
|
||||
- k8s/helm-chart-format.md
|
||||
- k8s/helm-create-basic-chart.md
|
||||
-
|
||||
- k8s/helm-create-better-chart.md
|
||||
- k8s/helm-dependencies.md
|
||||
- k8s/helm-values-schema-validation.md
|
||||
- k8s/helm-secrets.md
|
||||
-
|
||||
- k8s/cert-manager.md
|
||||
- k8s/gitlab.md
|
||||
- |
|
||||
# (Extra content)
|
||||
- k8s/prometheus.md
|
||||
|
||||
File diff suppressed because one or more lines are too long
|
Before Width: | Height: | Size: 99 KiB |
@@ -1,519 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
version="1.1"
|
||||
viewBox="16 32 880 495"
|
||||
fill="none"
|
||||
stroke="none"
|
||||
stroke-linecap="square"
|
||||
stroke-miterlimit="10"
|
||||
id="svg464"
|
||||
sodipodi:docname="k8s-net-1-pod-to-pod.svg"
|
||||
width="1600"
|
||||
height="900"
|
||||
inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07, custom)">
|
||||
<metadata
|
||||
id="metadata470">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<defs
|
||||
id="defs468" />
|
||||
<sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="476"
|
||||
inkscape:window-height="1032"
|
||||
id="namedview466"
|
||||
showgrid="false"
|
||||
inkscape:zoom="1.0208333"
|
||||
inkscape:cx="480"
|
||||
inkscape:cy="360"
|
||||
inkscape:window-x="480"
|
||||
inkscape:window-y="18"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="svg464" />
|
||||
<clipPath
|
||||
id="p.0">
|
||||
<path
|
||||
d="M 0,0 H 960 V 720 H 0 Z"
|
||||
clip-rule="nonzero"
|
||||
id="path317" />
|
||||
</clipPath>
|
||||
<g
|
||||
clip-path="url(#p.0)"
|
||||
id="g462">
|
||||
<path
|
||||
fill="#000000"
|
||||
fill-opacity="0"
|
||||
d="M 0,0 H 960 V 720 H 0 Z"
|
||||
fill-rule="evenodd"
|
||||
id="path320" />
|
||||
<path
|
||||
fill="#d9d9d9"
|
||||
d="m 66.944885,154.29968 v 0 c 0,-13.08115 10.604363,-23.68552 23.685509,-23.68552 H 296.55071 c 6.28177,0 12.30628,2.49544 16.74817,6.93734 4.4419,4.44189 6.93732,10.4664 6.93732,16.74818 v 94.73921 c 0,13.08116 -10.60434,23.6855 -23.68549,23.6855 H 90.630394 c -13.081146,0 -23.685509,-10.60434 -23.685509,-23.6855 z"
|
||||
fill-rule="evenodd"
|
||||
id="path322" />
|
||||
<path
|
||||
stroke="#434343"
|
||||
stroke-width="2"
|
||||
stroke-linejoin="round"
|
||||
stroke-linecap="butt"
|
||||
d="m 66.944885,154.29968 v 0 c 0,-13.08115 10.604363,-23.68552 23.685509,-23.68552 H 296.55071 c 6.28177,0 12.30628,2.49544 16.74817,6.93734 4.4419,4.44189 6.93732,10.4664 6.93732,16.74818 v 94.73921 c 0,13.08116 -10.60434,23.6855 -23.68549,23.6855 H 90.630394 c -13.081146,0 -23.685509,-10.60434 -23.685509,-23.6855 z"
|
||||
fill-rule="evenodd"
|
||||
id="path324" />
|
||||
<path
|
||||
fill="#000000"
|
||||
d="m 85.75713,154.61205 0.04687,1.23437 q 1.125,-1.40625 2.953125,-1.40625 3.125,0 3.15625,3.51563 v 6.51562 h -1.6875 v -6.51562 q -0.01563,-1.07813 -0.5,-1.57813 -0.46875,-0.51562 -1.484375,-0.51562 -0.8125,0 -1.4375,0.4375 -0.609375,0.4375 -0.96875,1.15625 v 7.01562 h -1.67187 v -9.85937 z m 8.246857,4.84375 q 0,-1.45313 0.5625,-2.60938 0.578125,-1.15625 1.59375,-1.78125 1.015625,-0.625 2.3125,-0.625 2.015623,0 3.250003,1.39063 1.25,1.39062 1.25,3.70312 v 0.125 q 0,1.4375 -0.54688,2.57813 -0.54687,1.14062 -1.57812,1.78125 -1.015628,0.64062 -2.359378,0.64062 -2,0 -3.25,-1.39062 -1.234375,-1.40625 -1.234375,-3.70313 z m 1.6875,0.20312 q 0,1.64063 0.765625,2.64063 0.765625,0.98437 2.03125,0.98437 1.296875,0 2.046878,-1 0.75,-1.01562 0.75,-2.82812 0,-1.625 -0.76563,-2.625 -0.765623,-1.01563 -2.046873,-1.01563 -1.25,0 -2.015625,1 -0.765625,0.98438 -0.765625,2.84375 z m 8.983643,-0.20312 q 0,-2.26563 1.07813,-3.64063 1.07812,-1.375 2.8125,-1.375 1.73437,0 2.75,1.17188 v -5.14063 h 1.6875 v 14 h -1.54688 l -0.0937,-1.0625 q -1,1.25 -2.8125,1.25 -1.70312,0 -2.79687,-1.40625 -1.07813,-1.40625 -1.07813,-3.65625 z m 1.6875,0.20312 q 0,1.67188 0.6875,2.625 0.70313,0.9375 1.92188,0.9375 1.60937,0 2.34375,-1.4375 v -4.53125 q -0.76563,-1.39062 -2.32813,-1.39062 -1.23437,0 -1.9375,0.95312 -0.6875,0.95313 -0.6875,2.84375 z m 13.33397,5 q -2,0 -3.26563,-1.3125 -1.25,-1.32812 -1.25,-3.53125 v -0.3125 q 0,-1.46875 0.5625,-2.60937 0.5625,-1.15625 1.5625,-1.79688 1.01563,-0.65625 2.1875,-0.65625 1.92188,0 2.98438,1.26563 1.0625,1.26562 1.0625,3.625 v 0.6875 h -6.67188 q 0.0312,1.46875 0.84375,2.375 0.82813,0.89062 2.07813,0.89062 0.89062,0 1.51562,-0.35937 0.625,-0.375 1.07813,-0.96875 l 1.03125,0.79687 q -1.23438,1.90625 -3.71875,1.90625 z m -0.20313,-8.84375 q -1.01562,0 -1.71875,0.75 -0.6875,0.73438 -0.84375,2.07813 h 4.9375 v -0.125 q -0.0781,-1.28125 -0.70312,-1.98438 -0.60938,-0.71875 -1.67188,-0.71875 z"
|
||||
fill-rule="nonzero"
|
||||
id="path326" />
|
||||
<path
|
||||
fill="#000000"
|
||||
fill-opacity="0"
|
||||
d="M 741.52496,67.91863 H 819.2572"
|
||||
fill-rule="evenodd"
|
||||
id="path328" />
|
||||
<path
|
||||
stroke="#0000ff"
|
||||
stroke-width="4"
|
||||
stroke-linejoin="round"
|
||||
stroke-linecap="butt"
|
||||
d="M 741.52496,67.91863 H 819.2572"
|
||||
fill-rule="evenodd"
|
||||
id="path330" />
|
||||
<path
|
||||
fill="#000000"
|
||||
fill-opacity="0"
|
||||
d="M 692.19946,70.157394 H 868.57745 V 116.01565 H 692.19946 Z"
|
||||
fill-rule="evenodd"
|
||||
id="path332" />
|
||||
<path
|
||||
fill="#000000"
|
||||
d="m 747.46643,91.32864 q 0,2.078125 -0.96875,3.359375 -0.95313,1.28125 -2.57813,1.28125 -1.67187,0 -2.625,-1.0625 v 4.40625 h -1.5625 V 86.64114 h 1.42188 l 0.0781,1.015625 q 0.95313,-1.1875 2.65625,-1.1875 1.65625,0 2.60938,1.25 0.96875,1.234375 0.96875,3.453125 z m -1.5625,-0.1875 q 0,-1.546875 -0.67188,-2.4375 -0.65625,-0.90625 -1.8125,-0.90625 -1.42187,0 -2.125,1.265625 v 4.375 q 0.70313,1.25 2.15625,1.25 1.125,0 1.78125,-0.890625 0.67188,-0.890625 0.67188,-2.65625 z m 3.12799,0 q 0,-1.34375 0.53125,-2.421875 0.53125,-1.078125 1.46875,-1.65625 0.95313,-0.59375 2.15625,-0.59375 1.875,0 3.03125,1.296875 1.15625,1.296875 1.15625,3.453125 v 0.109375 q 0,1.328125 -0.51562,2.390625 -0.51563,1.0625 -1.46875,1.65625 -0.95313,0.59375 -2.1875,0.59375 -1.85938,0 -3.01563,-1.296875 -1.15625,-1.296875 -1.15625,-3.421875 z m 1.57813,0.1875 q 0,1.515625 0.70312,2.4375 0.70313,0.921875 1.89063,0.921875 1.20312,0 1.89062,-0.9375 0.70313,-0.9375 0.70313,-2.609375 0,-1.515625 -0.71875,-2.4375 -0.70313,-0.9375 -1.89063,-0.9375 -1.15625,0 -1.875,0.921875 -0.70312,0.921875 -0.70312,2.640625 z m 8.33557,-0.1875 q 0,-2.109375 1,-3.390625 1,-1.28125 2.625,-1.28125 1.60937,0 2.54687,1.109375 v -4.78125 h 1.5625 v 13 h -1.4375 l -0.0781,-0.984375 q -0.9375,1.15625 -2.60938,1.15625 -1.59375,0 -2.60937,-1.296875 -1,-1.3125 -1,-3.40625 z m 1.57812,0.1875 q 0,1.546875 0.64063,2.4375 0.64062,0.875 1.76562,0.875 1.5,0 2.1875,-1.34375 v -4.203125 q -0.70312,-1.296875 -2.15625,-1.296875 -1.15625,0 -1.79687,0.890625 -0.64063,0.890625 -0.64063,2.640625 z m 11.83496,-0.125 h -4.125 v -1.28125 h 4.125 z m 3.65546,-6.78125 v 2.21875 h 1.70312 v 1.21875 h -1.70312 v 5.671875 q 0,0.546875 0.21875,0.828125 0.23437,0.265625 0.78125,0.265625 0.26562,0 0.75,-0.09375 v 1.265625 q -0.625,0.171875 -1.20313,0.171875 -1.04687,0 -1.57812,-0.625 -0.53125,-0.640625 -0.53125,-1.8125 V 87.85989 h -1.67188 v -1.21875 h 1.67188 v -2.21875 z m 2.94427,6.71875 q 0,-1.34375 0.53125,-2.421875 0.53125,-1.078125 1.46875,-1.65625 0.95313,-0.59375 2.15625,-0.59375 1.875,0 3.03125,1.296875 1.15625,1.296875 1.15625,3.453125 v 0.109375 q 0,1.328125 -0.51562,2.390625 -0.51563,1.0625 -1.46875,1.65625 -0.95313,0.59375 -2.1875,0.59375 -1.85938,0 -3.01563,-1.296875 -1.15625,-1.296875 -1.15625,-3.421875 z m 1.57813,0.1875 q 0,1.515625 0.70312,2.4375 0.70313,0.921875 1.89063,0.921875 1.20312,0 1.89062,-0.9375 0.70313,-0.9375 0.70313,-2.609375 0,-1.515625 -0.71875,-2.4375 -0.70313,-0.9375 -1.89063,-0.9375 -1.15625,0 -1.875,0.921875 -0.70312,0.921875 -0.70312,2.640625 z m 11.9762,-0.125 h -4.125 v -1.28125 h 4.125 z m 9.26483,0.125 q 0,2.078125 -0.96875,3.359375 -0.95313,1.28125 -2.57813,1.28125 -1.67187,0 -2.625,-1.0625 v 4.40625 h -1.5625 V 86.64114 h 1.42188 l 0.0781,1.015625 q 0.95313,-1.1875 2.65625,-1.1875 1.65625,0 2.60938,1.25 0.96875,1.234375 0.96875,3.453125 z m -1.5625,-0.1875 q 0,-1.546875 -0.67188,-2.4375 -0.65625,-0.90625 -1.8125,-0.90625 -1.42187,0 -2.125,1.265625 v 4.375 q 0.70313,1.25 2.15625,1.25 1.125,0 1.78125,-0.890625 0.67188,-0.890625 0.67188,-2.65625 z m 3.12793,0 q 0,-1.34375 0.53125,-2.421875 0.53125,-1.078125 1.46875,-1.65625 0.95312,-0.59375 2.15625,-0.59375 1.875,0 3.03125,1.296875 1.15625,1.296875 1.15625,3.453125 v 0.109375 q 0,1.328125 -0.51563,2.390625 -0.51562,1.0625 -1.46875,1.65625 -0.95312,0.59375 -2.1875,0.59375 -1.85937,0 -3.01562,-1.296875 -1.15625,-1.296875 -1.15625,-3.421875 z m 1.57812,0.1875 q 0,1.515625 0.70313,2.4375 0.70312,0.921875 1.89062,0.921875 1.20313,0 1.89063,-0.9375 0.70312,-0.9375 0.70312,-2.609375 0,-1.515625 -0.71875,-2.4375 -0.70312,-0.9375 -1.89062,-0.9375 -1.15625,0 -1.875,0.921875 -0.70313,0.921875 -0.70313,2.640625 z m 8.33557,-0.1875 q 0,-2.109375 1,-3.390625 1,-1.28125 2.625,-1.28125 1.60938,0 2.54688,1.109375 v -4.78125 h 1.5625 v 13 h -1.4375 l -0.0781,-0.984375 q -0.9375,1.15625 -2.60937,1.15625 -1.59375,0 -2.60938,-1.296875 -1,-1.3125 -1,-3.40625 z m 1.57813,0.1875 q 0,1.546875 0.64062,2.4375 0.64063,0.875 1.76563,0.875 1.5,0 2.1875,-1.34375 v -4.203125 q -0.70313,-1.296875 -2.15625,-1.296875 -1.15625,0 -1.79688,0.890625 -0.64062,0.890625 -0.64062,2.640625 z"
|
||||
fill-rule="nonzero"
|
||||
id="path334" />
|
||||
<path
|
||||
fill="#f4cccc"
|
||||
d="m 228.27559,151.61942 h 63.53264 l 8.34137,8.34138 v 41.70587 h -71.87401 z"
|
||||
fill-rule="evenodd"
|
||||
id="path336" />
|
||||
<path
|
||||
stroke="#434343"
|
||||
stroke-width="1"
|
||||
stroke-linejoin="round"
|
||||
stroke-linecap="butt"
|
||||
d="m 228.27559,151.61942 h 63.53264 l 8.34137,8.34138 v 41.70587 h -71.87401 z"
|
||||
fill-rule="evenodd"
|
||||
id="path338" />
|
||||
<path
|
||||
fill="#000000"
|
||||
d="m 246.86934,177.89761 q 0,2.25 -1.03125,3.625 -1.01563,1.375 -2.78125,1.375 -1.79688,0 -2.82813,-1.14063 v 4.75 h -1.67187 v -13.65625 h 1.53125 l 0.0781,1.09375 q 1.03125,-1.26562 2.85938,-1.26562 1.78125,0 2.8125,1.34375 1.03125,1.32812 1.03125,3.71875 z m -1.67188,-0.20313 q 0,-1.65625 -0.71875,-2.625 -0.70312,-0.96875 -1.95312,-0.96875 -1.53125,0 -2.29688,1.35938 v 4.70312 q 0.76563,1.35938 2.32813,1.35938 1.20312,0 1.92187,-0.95313 0.71875,-0.96875 0.71875,-2.875 z m 3.37307,0 q 0,-1.45312 0.5625,-2.60937 0.57812,-1.15625 1.59375,-1.78125 1.01562,-0.625 2.3125,-0.625 2.01562,0 3.25,1.39062 1.25,1.39063 1.25,3.70313 v 0.125 q 0,1.4375 -0.54688,2.57812 -0.54687,1.14063 -1.57812,1.78125 -1.01563,0.64063 -2.35938,0.64063 -2,0 -3.25,-1.39063 -1.23437,-1.40625 -1.23437,-3.70312 z m 1.6875,0.20313 q 0,1.64062 0.76562,2.64062 0.76563,0.98438 2.03125,0.98438 1.29688,0 2.04688,-1 0.75,-1.01563 0.75,-2.82813 0,-1.625 -0.76563,-2.625 -0.76562,-1.01562 -2.04687,-1.01562 -1.25,0 -2.01563,1 -0.76562,0.98437 -0.76562,2.84375 z m 8.98364,-0.20313 q 0,-2.26562 1.07813,-3.64062 1.07812,-1.375 2.8125,-1.375 1.73437,0 2.75,1.17187 v -5.14062 h 1.6875 v 14 h -1.54688 l -0.0937,-1.0625 q -1,1.25 -2.8125,1.25 -1.70312,0 -2.79687,-1.40625 -1.07813,-1.40625 -1.07813,-3.65625 z m 1.6875,0.20313 q 0,1.67187 0.6875,2.625 0.70313,0.9375 1.92188,0.9375 1.60937,0 2.34375,-1.4375 v -4.53125 q -0.76563,-1.39063 -2.32813,-1.39063 -1.23437,0 -1.9375,0.95313 -0.6875,0.95312 -0.6875,2.84375 z"
|
||||
fill-rule="nonzero"
|
||||
id="path340" />
|
||||
<path
|
||||
fill="#f4cccc"
|
||||
d="m 180.86351,212.08398 h 63.53265 l 8.34137,8.34138 v 41.70586 h -71.87402 z"
|
||||
fill-rule="evenodd"
|
||||
id="path342" />
|
||||
<path
|
||||
stroke="#434343"
|
||||
stroke-width="1"
|
||||
stroke-linejoin="round"
|
||||
stroke-linecap="butt"
|
||||
d="m 180.86351,212.08398 h 63.53265 l 8.34137,8.34138 v 41.70586 h -71.87402 z"
|
||||
fill-rule="evenodd"
|
||||
id="path344" />
|
||||
<path
|
||||
fill="#000000"
|
||||
d="m 199.45726,238.36217 q 0,2.25 -1.03125,3.625 -1.01563,1.375 -2.78125,1.375 -1.79688,0 -2.82813,-1.14063 v 4.75 h -1.67187 v -13.65625 h 1.53125 l 0.0781,1.09375 q 1.03125,-1.26562 2.85938,-1.26562 1.78125,0 2.8125,1.34375 1.03125,1.32812 1.03125,3.71875 z m -1.67188,-0.20313 q 0,-1.65625 -0.71875,-2.625 -0.70312,-0.96875 -1.95312,-0.96875 -1.53125,0 -2.29688,1.35938 v 4.70312 q 0.76563,1.35938 2.32813,1.35938 1.20312,0 1.92187,-0.95313 0.71875,-0.96875 0.71875,-2.875 z m 3.37307,0 q 0,-1.45312 0.5625,-2.60937 0.57812,-1.15625 1.59375,-1.78125 1.01562,-0.625 2.3125,-0.625 2.01562,0 3.25,1.39062 1.25,1.39063 1.25,3.70313 v 0.125 q 0,1.4375 -0.54688,2.57812 -0.54687,1.14063 -1.57812,1.78125 -1.01563,0.64063 -2.35938,0.64063 -2,0 -3.25,-1.39063 -1.23437,-1.40625 -1.23437,-3.70312 z m 1.6875,0.20313 q 0,1.64062 0.76562,2.64062 0.76563,0.98438 2.03125,0.98438 1.29688,0 2.04688,-1 0.75,-1.01563 0.75,-2.82813 0,-1.625 -0.76563,-2.625 -0.76562,-1.01562 -2.04687,-1.01562 -1.25,0 -2.01563,1 -0.76562,0.98437 -0.76562,2.84375 z m 8.98364,-0.20313 q 0,-2.26562 1.07813,-3.64062 1.07812,-1.375 2.8125,-1.375 1.73437,0 2.75,1.17187 v -5.14062 h 1.6875 v 14 h -1.54688 l -0.0937,-1.0625 q -1,1.25 -2.8125,1.25 -1.70312,0 -2.79687,-1.40625 -1.07813,-1.40625 -1.07813,-3.65625 z m 1.6875,0.20313 q 0,1.67187 0.6875,2.625 0.70313,0.9375 1.92188,0.9375 1.60937,0 2.34375,-1.4375 v -4.53125 q -0.76563,-1.39063 -2.32813,-1.39063 -1.23437,0 -1.9375,0.95313 -0.6875,0.95312 -0.6875,2.84375 z"
|
||||
fill-rule="nonzero"
|
||||
id="path346" />
|
||||
<path
|
||||
fill="#d9d9d9"
|
||||
d="m 398.08398,209.82724 v 0 c 0,-13.08115 10.60437,-23.6855 23.68552,-23.6855 h 205.92032 c 6.2818,0 12.30627,2.49542 16.74817,6.93732 4.44189,4.44189 6.93731,10.4664 6.93731,16.74818 v 94.73923 c 0,13.08115 -10.60437,23.68552 -23.68548,23.68552 H 421.7695 c -13.08115,0 -23.68552,-10.60437 -23.68552,-23.68552 z"
|
||||
fill-rule="evenodd"
|
||||
id="path348" />
|
||||
<path
|
||||
stroke="#434343"
|
||||
stroke-width="2"
|
||||
stroke-linejoin="round"
|
||||
stroke-linecap="butt"
|
||||
d="m 398.08398,209.82724 v 0 c 0,-13.08115 10.60437,-23.6855 23.68552,-23.6855 h 205.92032 c 6.2818,0 12.30627,2.49542 16.74817,6.93732 4.44189,4.44189 6.93731,10.4664 6.93731,16.74818 v 94.73923 c 0,13.08115 -10.60437,23.68552 -23.68548,23.68552 H 421.7695 c -13.08115,0 -23.68552,-10.60437 -23.68552,-23.68552 z"
|
||||
fill-rule="evenodd"
|
||||
id="path350" />
|
||||
<path
|
||||
fill="#000000"
|
||||
d="m 416.89624,210.1396 0.0469,1.23437 q 1.125,-1.40625 2.95313,-1.40625 3.125,0 3.15625,3.51563 v 6.51562 h -1.6875 v -6.51562 q -0.0156,-1.07813 -0.5,-1.57813 -0.46875,-0.51562 -1.48438,-0.51562 -0.8125,0 -1.4375,0.4375 -0.60937,0.4375 -0.96875,1.15625 v 7.01562 h -1.67187 v -9.85937 z m 8.24686,4.84375 q 0,-1.45313 0.5625,-2.60938 0.57812,-1.15625 1.59375,-1.78125 1.01562,-0.625 2.3125,-0.625 2.01562,0 3.25,1.39063 1.25,1.39062 1.25,3.70312 v 0.125 q 0,1.4375 -0.54688,2.57813 -0.54687,1.14062 -1.57812,1.78125 -1.01563,0.64062 -2.35938,0.64062 -2,0 -3.25,-1.39062 -1.23437,-1.40625 -1.23437,-3.70313 z m 1.6875,0.20312 q 0,1.64063 0.76562,2.64063 0.76563,0.98437 2.03125,0.98437 1.29688,0 2.04688,-1 0.75,-1.01562 0.75,-2.82812 0,-1.625 -0.76563,-2.625 -0.76562,-1.01563 -2.04687,-1.01563 -1.25,0 -2.01563,1 -0.76562,0.98438 -0.76562,2.84375 z m 8.98364,-0.20312 q 0,-2.26563 1.07812,-3.64063 1.07813,-1.375 2.8125,-1.375 1.73438,0 2.75,1.17188 v -5.14063 h 1.6875 v 14 h -1.54687 l -0.0937,-1.0625 q -1,1.25 -2.8125,1.25 -1.70313,0 -2.79688,-1.40625 -1.07812,-1.40625 -1.07812,-3.65625 z m 1.6875,0.20312 q 0,1.67188 0.6875,2.625 0.70312,0.9375 1.92187,0.9375 1.60938,0 2.34375,-1.4375 v -4.53125 q -0.76562,-1.39062 -2.32812,-1.39062 -1.23438,0 -1.9375,0.95312 -0.6875,0.95313 -0.6875,2.84375 z m 13.33395,5 q -2,0 -3.26562,-1.3125 -1.25,-1.32812 -1.25,-3.53125 v -0.3125 q 0,-1.46875 0.5625,-2.60937 0.5625,-1.15625 1.5625,-1.79688 1.01562,-0.65625 2.1875,-0.65625 1.92187,0 2.98437,1.26563 1.0625,1.26562 1.0625,3.625 v 0.6875 h -6.67187 q 0.0312,1.46875 0.84375,2.375 0.82812,0.89062 2.07812,0.89062 0.89063,0 1.51563,-0.35937 0.625,-0.375 1.07812,-0.96875 l 1.03125,0.79687 q -1.23437,1.90625 -3.71875,1.90625 z m -0.20312,-8.84375 q -1.01563,0 -1.71875,0.75 -0.6875,0.73438 -0.84375,2.07813 h 4.9375 v -0.125 q -0.0781,-1.28125 -0.70313,-1.98438 -0.60937,-0.71875 -1.67187,-0.71875 z"
|
||||
fill-rule="nonzero"
|
||||
id="path352" />
|
||||
<path
|
||||
fill="#f4cccc"
|
||||
d="m 436.5315,244.97638 h 63.53265 l 8.34137,8.34137 v 41.70587 H 436.5315 Z"
|
||||
fill-rule="evenodd"
|
||||
id="path354" />
|
||||
<path
|
||||
stroke="#434343"
|
||||
stroke-width="1"
|
||||
stroke-linejoin="round"
|
||||
stroke-linecap="butt"
|
||||
d="m 436.5315,244.97638 h 63.53265 l 8.34137,8.34137 v 41.70587 H 436.5315 Z"
|
||||
fill-rule="evenodd"
|
||||
id="path356" />
|
||||
<path
|
||||
fill="#000000"
|
||||
d="m 455.12524,271.25458 q 0,2.25 -1.03125,3.625 -1.01562,1.375 -2.78125,1.375 -1.79687,0 -2.82812,-1.14063 v 4.75 h -1.67188 V 266.2077 h 1.53125 l 0.0781,1.09375 q 1.03125,-1.26562 2.85937,-1.26562 1.78125,0 2.8125,1.34375 1.03125,1.32812 1.03125,3.71875 z m -1.67187,-0.20313 q 0,-1.65625 -0.71875,-2.625 -0.70313,-0.96875 -1.95313,-0.96875 -1.53125,0 -2.29687,1.35938 v 4.70312 q 0.76562,1.35938 2.32812,1.35938 1.20313,0 1.92188,-0.95313 0.71875,-0.96875 0.71875,-2.875 z m 3.37307,0 q 0,-1.45312 0.5625,-2.60937 0.57813,-1.15625 1.59375,-1.78125 1.01563,-0.625 2.3125,-0.625 2.01563,0 3.25,1.39062 1.25,1.39063 1.25,3.70313 v 0.125 q 0,1.4375 -0.54687,2.57812 -0.54688,1.14063 -1.57813,1.78125 -1.01562,0.64063 -2.35937,0.64063 -2,0 -3.25,-1.39063 -1.23438,-1.40625 -1.23438,-3.70312 z m 1.6875,0.20313 q 0,1.64062 0.76563,2.64062 0.76562,0.98438 2.03125,0.98438 1.29687,0 2.04687,-1 0.75,-1.01563 0.75,-2.82813 0,-1.625 -0.76562,-2.625 -0.76563,-1.01562 -2.04688,-1.01562 -1.25,0 -2.01562,1 -0.76563,0.98437 -0.76563,2.84375 z m 8.98365,-0.20313 q 0,-2.26562 1.07812,-3.64062 1.07813,-1.375 2.8125,-1.375 1.73438,0 2.75,1.17187 v -5.14062 h 1.6875 v 14 h -1.54687 l -0.0937,-1.0625 q -1,1.25 -2.8125,1.25 -1.70313,0 -2.79688,-1.40625 -1.07812,-1.40625 -1.07812,-3.65625 z m 1.6875,0.20313 q 0,1.67187 0.6875,2.625 0.70312,0.9375 1.92187,0.9375 1.60938,0 2.34375,-1.4375 v -4.53125 q -0.76562,-1.39063 -2.32812,-1.39063 -1.23438,0 -1.9375,0.95313 -0.6875,0.95312 -0.6875,2.84375 z"
|
||||
fill-rule="nonzero"
|
||||
id="path358" />
|
||||
<path
|
||||
fill="#d9d9d9"
|
||||
d="m 95.60105,380.54904 v 0 c 0,-13.08115 10.60436,-23.68552 23.68551,-23.68552 h 205.92032 c 6.2818,0 12.30627,2.49543 16.74817,6.93732 4.44192,4.4419 6.93735,10.4664 6.93735,16.7482 v 94.7392 c 0,13.08115 -10.60437,23.68552 -23.68552,23.68552 H 119.28656 c -13.08115,0 -23.68551,-10.60437 -23.68551,-23.68552 z"
|
||||
fill-rule="evenodd"
|
||||
id="path360" />
|
||||
<path
|
||||
stroke="#434343"
|
||||
stroke-width="2"
|
||||
stroke-linejoin="round"
|
||||
stroke-linecap="butt"
|
||||
d="m 95.60105,380.54904 v 0 c 0,-13.08115 10.60436,-23.68552 23.68551,-23.68552 h 205.92032 c 6.2818,0 12.30627,2.49543 16.74817,6.93732 4.44192,4.4419 6.93735,10.4664 6.93735,16.7482 v 94.7392 c 0,13.08115 -10.60437,23.68552 -23.68552,23.68552 H 119.28656 c -13.08115,0 -23.68551,-10.60437 -23.68551,-23.68552 z"
|
||||
fill-rule="evenodd"
|
||||
id="path362" />
|
||||
<path
|
||||
fill="#000000"
|
||||
d="m 114.4133,380.8614 0.0469,1.23437 q 1.125,-1.40625 2.95312,-1.40625 3.125,0 3.15625,3.51563 v 6.51562 h -1.6875 v -6.51562 q -0.0156,-1.07813 -0.5,-1.57813 -0.46875,-0.51562 -1.48437,-0.51562 -0.8125,0 -1.4375,0.4375 -0.60938,0.4375 -0.96875,1.15625 v 7.01562 h -1.67188 v -9.85937 z m 8.24686,4.84375 q 0,-1.45313 0.5625,-2.60938 0.57812,-1.15625 1.59375,-1.78125 1.01562,-0.625 2.3125,-0.625 2.01562,0 3.25,1.39063 1.25,1.39062 1.25,3.70312 v 0.125 q 0,1.4375 -0.54688,2.57813 -0.54687,1.14062 -1.57812,1.78125 -1.01563,0.64062 -2.35938,0.64062 -2,0 -3.25,-1.39062 -1.23437,-1.40625 -1.23437,-3.70313 z m 1.6875,0.20312 q 0,1.64063 0.76562,2.64063 0.76563,0.98437 2.03125,0.98437 1.29688,0 2.04688,-1 0.75,-1.01562 0.75,-2.82812 0,-1.625 -0.76563,-2.625 -0.76562,-1.01563 -2.04687,-1.01563 -1.25,0 -2.01563,1 -0.76562,0.98438 -0.76562,2.84375 z m 8.98364,-0.20312 q 0,-2.26563 1.07812,-3.64063 1.07813,-1.375 2.8125,-1.375 1.73438,0 2.75,1.17188 v -5.14063 h 1.6875 v 14 h -1.54687 l -0.0937,-1.0625 q -1,1.25 -2.8125,1.25 -1.70313,0 -2.79688,-1.40625 -1.07812,-1.40625 -1.07812,-3.65625 z m 1.6875,0.20312 q 0,1.67188 0.6875,2.625 0.70312,0.9375 1.92187,0.9375 1.60938,0 2.34375,-1.4375 v -4.53125 q -0.76562,-1.39062 -2.32812,-1.39062 -1.23438,0 -1.9375,0.95312 -0.6875,0.95313 -0.6875,2.84375 z m 13.33397,5 q -2,0 -3.26563,-1.3125 -1.25,-1.32812 -1.25,-3.53125 v -0.3125 q 0,-1.46875 0.5625,-2.60937 0.5625,-1.15625 1.5625,-1.79688 1.01563,-0.65625 2.1875,-0.65625 1.92188,0 2.98438,1.26563 1.0625,1.26562 1.0625,3.625 v 0.6875 h -6.67188 q 0.0312,1.46875 0.84375,2.375 0.82813,0.89062 2.07813,0.89062 0.89062,0 1.51562,-0.35937 0.625,-0.375 1.07813,-0.96875 l 1.03125,0.79687 q -1.23438,1.90625 -3.71875,1.90625 z m -0.20313,-8.84375 q -1.01562,0 -1.71875,0.75 -0.6875,0.73438 -0.84375,2.07813 h 4.9375 v -0.125 q -0.0781,-1.28125 -0.70312,-1.98438 -0.60938,-0.71875 -1.67188,-0.71875 z"
|
||||
fill-rule="nonzero"
|
||||
id="path364" />
|
||||
<path
|
||||
fill="#f4cccc"
|
||||
d="m 200.92651,377.43307 h 63.53262 l 8.3414,8.34137 v 41.70587 h -71.87402 z"
|
||||
fill-rule="evenodd"
|
||||
id="path366" />
|
||||
<path
|
||||
stroke="#434343"
|
||||
stroke-width="1"
|
||||
stroke-linejoin="round"
|
||||
stroke-linecap="butt"
|
||||
d="m 200.92651,377.43307 h 63.53262 l 8.3414,8.34137 v 41.70587 h -71.87402 z"
|
||||
fill-rule="evenodd"
|
||||
id="path368" />
|
||||
<path
|
||||
fill="#000000"
|
||||
d="m 219.52026,403.71124 q 0,2.25 -1.03125,3.625 -1.01563,1.375 -2.78125,1.375 -1.79688,0 -2.82813,-1.14063 v 4.75 h -1.67187 v -13.65625 h 1.53125 l 0.0781,1.09375 q 1.03125,-1.26562 2.85938,-1.26562 1.78125,0 2.8125,1.34375 1.03125,1.32812 1.03125,3.71875 z m -1.67188,-0.20313 q 0,-1.65625 -0.71875,-2.625 -0.70312,-0.96875 -1.95312,-0.96875 -1.53125,0 -2.29688,1.35938 v 4.70312 q 0.76563,1.35938 2.32813,1.35938 1.20312,0 1.92187,-0.95313 0.71875,-0.96875 0.71875,-2.875 z m 3.37307,0 q 0,-1.45312 0.5625,-2.60937 0.57812,-1.15625 1.59375,-1.78125 1.01562,-0.625 2.3125,-0.625 2.01562,0 3.25,1.39062 1.25,1.39063 1.25,3.70313 v 0.125 q 0,1.4375 -0.54688,2.57812 -0.54687,1.14063 -1.57812,1.78125 -1.01563,0.64063 -2.35938,0.64063 -2,0 -3.25,-1.39063 -1.23437,-1.40625 -1.23437,-3.70312 z m 1.6875,0.20313 q 0,1.64062 0.76562,2.64062 0.76563,0.98438 2.03125,0.98438 1.29688,0 2.04688,-1 0.75,-1.01563 0.75,-2.82813 0,-1.625 -0.76563,-2.625 -0.76562,-1.01562 -2.04687,-1.01562 -1.25,0 -2.01563,1 -0.76562,0.98437 -0.76562,2.84375 z m 8.98364,-0.20313 q 0,-2.26562 1.07813,-3.64062 1.07812,-1.375 2.8125,-1.375 1.73437,0 2.75,1.17187 v -5.14062 h 1.6875 v 14 h -1.54688 l -0.0937,-1.0625 q -1,1.25 -2.8125,1.25 -1.70312,0 -2.79687,-1.40625 -1.07813,-1.40625 -1.07813,-3.65625 z m 1.6875,0.20313 q 0,1.67187 0.6875,2.625 0.70313,0.9375 1.92188,0.9375 1.60937,0 2.34375,-1.4375 v -4.53125 q -0.76563,-1.39063 -2.32813,-1.39063 -1.23437,0 -1.9375,0.95313 -0.6875,0.95312 -0.6875,2.84375 z"
|
||||
fill-rule="nonzero"
|
||||
id="path370" />
|
||||
<path
|
||||
fill="#000000"
|
||||
fill-opacity="0"
|
||||
d="m 145.48819,305.3176 v 0 c 0,-108.95232 87.37144,-197.2756 195.1496,-197.2756 v 0 c 51.7569,0 101.39395,20.78433 137.99161,57.78069 36.59766,36.99635 57.15802,87.17416 57.15802,139.49492 v 0 c 0,108.9523 -87.37146,197.27557 -195.14963,197.27557 v 0 c -107.77815,0 -195.1496,-88.32327 -195.1496,-197.27557 z"
|
||||
fill-rule="evenodd"
|
||||
id="path372" />
|
||||
<path
|
||||
stroke="#0000ff"
|
||||
stroke-width="4"
|
||||
stroke-linejoin="round"
|
||||
stroke-linecap="butt"
|
||||
d="m 145.48819,305.3176 v 0 c 0,-108.95232 87.37144,-197.2756 195.1496,-197.2756 v 0 c 51.7569,0 101.39395,20.78433 137.99161,57.78069 36.59766,36.99635 57.15802,87.17416 57.15802,139.49492 v 0 c 0,108.9523 -87.37146,197.27557 -195.14963,197.27557 v 0 c -107.77815,0 -195.1496,-88.32327 -195.1496,-197.27557 z"
|
||||
fill-rule="evenodd"
|
||||
id="path374" />
|
||||
<path
|
||||
fill="#f4cccc"
|
||||
d="m 108.9895,417.0105 h 63.53264 l 8.34137,8.34137 v 41.70587 H 108.9895 Z"
|
||||
fill-rule="evenodd"
|
||||
id="path376" />
|
||||
<path
|
||||
stroke="#434343"
|
||||
stroke-width="1"
|
||||
stroke-linejoin="round"
|
||||
stroke-linecap="butt"
|
||||
d="m 108.9895,417.0105 h 63.53264 l 8.34137,8.34137 v 41.70587 H 108.9895 Z"
|
||||
fill-rule="evenodd"
|
||||
id="path378" />
|
||||
<path
|
||||
fill="#000000"
|
||||
d="m 127.58325,443.2887 q 0,2.25 -1.03125,3.625 -1.01562,1.375 -2.78125,1.375 -1.79687,0 -2.82812,-1.14063 v 4.75 h -1.67188 v -13.65625 h 1.53125 l 0.0781,1.09375 q 1.03125,-1.26562 2.85937,-1.26562 1.78125,0 2.8125,1.34375 1.03125,1.32812 1.03125,3.71875 z m -1.67187,-0.20313 q 0,-1.65625 -0.71875,-2.625 -0.70313,-0.96875 -1.95313,-0.96875 -1.53125,0 -2.29687,1.35938 v 4.70312 q 0.76562,1.35938 2.32812,1.35938 1.20313,0 1.92188,-0.95313 0.71875,-0.96875 0.71875,-2.875 z m 3.37306,0 q 0,-1.45312 0.5625,-2.60937 0.57812,-1.15625 1.59375,-1.78125 1.01562,-0.625 2.3125,-0.625 2.01562,0 3.25,1.39062 1.25,1.39063 1.25,3.70313 v 0.125 q 0,1.4375 -0.54688,2.57812 -0.54687,1.14063 -1.57812,1.78125 -1.01563,0.64063 -2.35938,0.64063 -2,0 -3.25,-1.39063 -1.23437,-1.40625 -1.23437,-3.70312 z m 1.6875,0.20313 q 0,1.64062 0.76562,2.64062 0.76563,0.98438 2.03125,0.98438 1.29688,0 2.04688,-1 0.75,-1.01563 0.75,-2.82813 0,-1.625 -0.76563,-2.625 -0.76562,-1.01562 -2.04687,-1.01562 -1.25,0 -2.01563,1 -0.76562,0.98437 -0.76562,2.84375 z m 8.98364,-0.20313 q 0,-2.26562 1.07813,-3.64062 1.07812,-1.375 2.8125,-1.375 1.73437,0 2.75,1.17187 v -5.14062 h 1.6875 v 14 h -1.54688 l -0.0937,-1.0625 q -1,1.25 -2.8125,1.25 -1.70312,0 -2.79687,-1.40625 -1.07813,-1.40625 -1.07813,-3.65625 z m 1.6875,0.20313 q 0,1.67187 0.6875,2.625 0.70313,0.9375 1.92188,0.9375 1.60937,0 2.34375,-1.4375 v -4.53125 q -0.76563,-1.39063 -2.32813,-1.39063 -1.23437,0 -1.9375,0.95313 -0.6875,0.95312 -0.6875,2.84375 z"
|
||||
fill-rule="nonzero"
|
||||
id="path380" />
|
||||
<path
|
||||
fill="#f4cccc"
|
||||
d="m 87.96063,209.9895 h 63.53264 l 8.34137,8.34137 v 41.70587 H 87.96063 Z"
|
||||
fill-rule="evenodd"
|
||||
id="path382" />
|
||||
<path
|
||||
stroke="#434343"
|
||||
stroke-width="1"
|
||||
stroke-linejoin="round"
|
||||
stroke-linecap="butt"
|
||||
d="m 87.96063,209.9895 h 63.53264 l 8.34137,8.34137 v 41.70587 H 87.96063 Z"
|
||||
fill-rule="evenodd"
|
||||
id="path384" />
|
||||
<path
|
||||
fill="#000000"
|
||||
d="m 106.55438,236.26768 q 0,2.25 -1.03125,3.625 -1.01563,1.375 -2.78125,1.375 -1.79688,0 -2.828125,-1.14062 v 4.75 H 98.24188 v -13.65625 h 1.53125 l 0.07813,1.09375 q 1.03124,-1.26563 2.85937,-1.26563 1.78125,0 2.8125,1.34375 1.03125,1.32813 1.03125,3.71875 z m -1.67188,-0.20312 q 0,-1.65625 -0.71875,-2.625 -0.70312,-0.96875 -1.95312,-0.96875 -1.53125,0 -2.296875,1.35937 v 4.70313 q 0.765625,1.35937 2.328125,1.35937 1.20312,0 1.92187,-0.95312 0.71875,-0.96875 0.71875,-2.875 z m 3.37307,0 q 0,-1.45313 0.5625,-2.60938 0.57812,-1.15625 1.59375,-1.78125 1.01562,-0.625 2.3125,-0.625 2.01562,0 3.25,1.39063 1.25,1.39062 1.25,3.70312 v 0.125 q 0,1.4375 -0.54688,2.57813 -0.54687,1.14062 -1.57812,1.78125 -1.01563,0.64062 -2.35938,0.64062 -2,0 -3.25,-1.39062 -1.23437,-1.40625 -1.23437,-3.70313 z m 1.6875,0.20312 q 0,1.64063 0.76562,2.64063 0.76563,0.98437 2.03125,0.98437 1.29688,0 2.04688,-1 0.75,-1.01562 0.75,-2.82812 0,-1.625 -0.76563,-2.625 -0.76562,-1.01563 -2.04687,-1.01563 -1.25,0 -2.01563,1 -0.76562,0.98438 -0.76562,2.84375 z m 8.98364,-0.20312 q 0,-2.26563 1.07813,-3.64063 1.07812,-1.375 2.8125,-1.375 1.73437,0 2.75,1.17188 v -5.14063 h 1.6875 v 14 h -1.54688 l -0.0937,-1.0625 q -1,1.25 -2.8125,1.25 -1.70312,0 -2.79687,-1.40625 -1.07813,-1.40625 -1.07813,-3.65625 z m 1.6875,0.20312 q 0,1.67188 0.6875,2.625 0.70313,0.9375 1.92188,0.9375 1.60937,0 2.34375,-1.4375 v -4.53125 q -0.76563,-1.39062 -2.32813,-1.39062 -1.23437,0 -1.9375,0.95312 -0.6875,0.95313 -0.6875,2.84375 z"
|
||||
fill-rule="nonzero"
|
||||
id="path386" />
|
||||
<path
|
||||
fill="#000000"
|
||||
fill-opacity="0"
|
||||
d="m 204.99213,171.03674 -81.10236,38.96063"
|
||||
fill-rule="evenodd"
|
||||
id="path388" />
|
||||
<path
|
||||
stroke="#0000ff"
|
||||
stroke-width="4"
|
||||
stroke-linejoin="round"
|
||||
stroke-linecap="butt"
|
||||
d="m 204.99213,171.03674 -81.10236,38.96063"
|
||||
fill-rule="evenodd"
|
||||
id="path390" />
|
||||
<path
|
||||
fill="#000000"
|
||||
fill-opacity="0"
|
||||
d="m 185.52843,162.97461 31.27559,49.10237"
|
||||
fill-rule="evenodd"
|
||||
id="path392" />
|
||||
<path
|
||||
stroke="#0000ff"
|
||||
stroke-width="4"
|
||||
stroke-linejoin="round"
|
||||
stroke-linecap="butt"
|
||||
d="m 185.52843,162.97461 31.27559,49.10237"
|
||||
fill-rule="evenodd"
|
||||
id="path394" />
|
||||
<path
|
||||
fill="#000000"
|
||||
fill-opacity="0"
|
||||
d="m 182.18898,171.03674 46.07873,5.60631"
|
||||
fill-rule="evenodd"
|
||||
id="path396" />
|
||||
<path
|
||||
stroke="#0000ff"
|
||||
stroke-width="4"
|
||||
stroke-linejoin="round"
|
||||
stroke-linecap="butt"
|
||||
d="m 182.18898,171.03674 46.07873,5.60631"
|
||||
fill-rule="evenodd"
|
||||
id="path398" />
|
||||
<path
|
||||
fill="#000000"
|
||||
fill-opacity="0"
|
||||
d="m 180.86351,442.03412 44,27.2756"
|
||||
fill-rule="evenodd"
|
||||
id="path400" />
|
||||
<path
|
||||
stroke="#0000ff"
|
||||
stroke-width="4"
|
||||
stroke-linejoin="round"
|
||||
stroke-linecap="butt"
|
||||
d="m 180.86351,442.03412 44,27.2756"
|
||||
fill-rule="evenodd"
|
||||
id="path402" />
|
||||
<path
|
||||
fill="#000000"
|
||||
fill-opacity="0"
|
||||
d="M 236.86351,427.48032 208.73753,469.3386"
|
||||
fill-rule="evenodd"
|
||||
id="path404" />
|
||||
<path
|
||||
stroke="#0000ff"
|
||||
stroke-width="4"
|
||||
stroke-linejoin="round"
|
||||
stroke-linecap="butt"
|
||||
d="M 236.86351,427.48032 208.73753,469.3386"
|
||||
fill-rule="evenodd"
|
||||
id="path406" />
|
||||
<path
|
||||
fill="#000000"
|
||||
fill-opacity="0"
|
||||
d="m 228.2021,461.26248 h 24.53543"
|
||||
fill-rule="evenodd"
|
||||
id="path408" />
|
||||
<path
|
||||
stroke="#0000ff"
|
||||
stroke-width="4"
|
||||
stroke-linejoin="round"
|
||||
stroke-linecap="butt"
|
||||
d="m 228.2021,461.26248 h 24.53543"
|
||||
fill-rule="evenodd"
|
||||
id="path410" />
|
||||
<path
|
||||
fill="#000000"
|
||||
fill-opacity="0"
|
||||
d="m 521.6842,219.98076 35.21259,20.59843"
|
||||
fill-rule="evenodd"
|
||||
id="path412" />
|
||||
<path
|
||||
stroke="#0000ff"
|
||||
stroke-width="4"
|
||||
stroke-linejoin="round"
|
||||
stroke-linecap="butt"
|
||||
d="m 521.6842,219.98076 35.21259,20.59843"
|
||||
fill-rule="evenodd"
|
||||
id="path414" />
|
||||
<path
|
||||
fill="#000000"
|
||||
fill-opacity="0"
|
||||
d="m 505.5599,219.98076 -33.10236,25.00789"
|
||||
fill-rule="evenodd"
|
||||
id="path416" />
|
||||
<path
|
||||
stroke="#0000ff"
|
||||
stroke-width="4"
|
||||
stroke-linejoin="round"
|
||||
stroke-linecap="butt"
|
||||
d="m 505.5599,219.98076 -33.10236,25.00789"
|
||||
fill-rule="evenodd"
|
||||
id="path418" />
|
||||
<path
|
||||
fill="#0000ff"
|
||||
d="m 205.39896,461.26248 v 0 c 0,-6.29694 5.10466,-11.40158 11.40157,-11.40158 v 0 c 3.02389,0 5.92392,1.20123 8.06213,3.33945 2.13821,2.13818 3.33945,5.03823 3.33945,8.06213 v 0 c 0,6.29691 -5.10466,11.40155 -11.40158,11.40155 v 0 c -6.29691,0 -11.40157,-5.10465 -11.40157,-11.40155 z"
|
||||
fill-rule="evenodd"
|
||||
id="path420" />
|
||||
<path
|
||||
fill="#000000"
|
||||
fill-opacity="0"
|
||||
d="m 208.73839,453.20035 16.12427,16.12424 m 0,-16.12424 -16.12427,16.12424"
|
||||
fill-rule="evenodd"
|
||||
id="path422" />
|
||||
<path
|
||||
fill="#000000"
|
||||
fill-opacity="0"
|
||||
d="m 205.39896,461.26248 v 0 c 0,-6.29694 5.10466,-11.40158 11.40157,-11.40158 v 0 c 3.02389,0 5.92392,1.20123 8.06213,3.33945 2.13821,2.13818 3.33945,5.03823 3.33945,8.06213 v 0 c 0,6.29691 -5.10466,11.40155 -11.40158,11.40155 v 0 c -6.29691,0 -11.40157,-5.10465 -11.40157,-11.40155 z"
|
||||
fill-rule="evenodd"
|
||||
id="path424" />
|
||||
<path
|
||||
stroke="#ffffff"
|
||||
stroke-width="1"
|
||||
stroke-linejoin="round"
|
||||
stroke-linecap="butt"
|
||||
d="m 208.73839,453.20035 16.12427,16.12424 m 0,-16.12424 -16.12427,16.12424"
|
||||
fill-rule="evenodd"
|
||||
id="path426" />
|
||||
<path
|
||||
stroke="#ffffff"
|
||||
stroke-width="1"
|
||||
stroke-linejoin="round"
|
||||
stroke-linecap="butt"
|
||||
d="m 205.39896,461.26248 v 0 c 0,-6.29694 5.10466,-11.40158 11.40157,-11.40158 v 0 c 3.02389,0 5.92392,1.20123 8.06213,3.33945 2.13821,2.13818 3.33945,5.03823 3.33945,8.06213 v 0 c 0,6.29691 -5.10466,11.40155 -11.40158,11.40155 v 0 c -6.29691,0 -11.40157,-5.10465 -11.40157,-11.40155 z"
|
||||
fill-rule="evenodd"
|
||||
id="path428" />
|
||||
<path
|
||||
fill="#0000ff"
|
||||
d="m 182.18898,171.03674 v 0 c 0,-6.29692 5.10466,-11.40157 11.40157,-11.40157 v 0 c 3.02389,0 5.92392,1.20124 8.06213,3.33944 2.13821,2.13821 3.33945,5.03825 3.33945,8.06213 v 0 c 0,6.29692 -5.10466,11.40158 -11.40158,11.40158 v 0 c -6.29691,0 -11.40157,-5.10466 -11.40157,-11.40158 z"
|
||||
fill-rule="evenodd"
|
||||
id="path430" />
|
||||
<path
|
||||
fill="#000000"
|
||||
fill-opacity="0"
|
||||
d="m 185.52843,162.97461 16.12425,16.12427 m 0,-16.12427 -16.12425,16.12427"
|
||||
fill-rule="evenodd"
|
||||
id="path432" />
|
||||
<path
|
||||
fill="#000000"
|
||||
fill-opacity="0"
|
||||
d="m 182.18898,171.03674 v 0 c 0,-6.29692 5.10466,-11.40157 11.40157,-11.40157 v 0 c 3.02389,0 5.92392,1.20124 8.06213,3.33944 2.13821,2.13821 3.33945,5.03825 3.33945,8.06213 v 0 c 0,6.29692 -5.10466,11.40158 -11.40158,11.40158 v 0 c -6.29691,0 -11.40157,-5.10466 -11.40157,-11.40158 z"
|
||||
fill-rule="evenodd"
|
||||
id="path434" />
|
||||
<path
|
||||
stroke="#ffffff"
|
||||
stroke-width="1"
|
||||
stroke-linejoin="round"
|
||||
stroke-linecap="butt"
|
||||
d="m 185.52843,162.97461 16.12425,16.12427 m 0,-16.12427 -16.12425,16.12427"
|
||||
fill-rule="evenodd"
|
||||
id="path436" />
|
||||
<path
|
||||
stroke="#ffffff"
|
||||
stroke-width="1"
|
||||
stroke-linejoin="round"
|
||||
stroke-linecap="butt"
|
||||
d="m 182.18898,171.03674 v 0 c 0,-6.29692 5.10466,-11.40157 11.40157,-11.40157 v 0 c 3.02389,0 5.92392,1.20124 8.06213,3.33944 2.13821,2.13821 3.33945,5.03825 3.33945,8.06213 v 0 c 0,6.29692 -5.10466,11.40158 -11.40158,11.40158 v 0 c -6.29691,0 -11.40157,-5.10466 -11.40157,-11.40158 z"
|
||||
fill-rule="evenodd"
|
||||
id="path438" />
|
||||
<path
|
||||
fill="#0000ff"
|
||||
d="m 502.22046,211.91864 v 0 c 0,-6.29692 5.10468,-11.40158 11.40161,-11.40158 v 0 c 3.02387,0 5.92389,1.20123 8.06214,3.33945 2.13818,2.13821 3.33941,5.03823 3.33941,8.06213 v 0 c 0,6.29691 -5.10467,11.40157 -11.40155,11.40157 v 0 c -6.29693,0 -11.40161,-5.10466 -11.40161,-11.40157 z"
|
||||
fill-rule="evenodd"
|
||||
id="path440" />
|
||||
<path
|
||||
fill="#000000"
|
||||
fill-opacity="0"
|
||||
d="m 505.5599,203.8565 16.1243,16.12425 m 0,-16.12425 -16.1243,16.12425"
|
||||
fill-rule="evenodd"
|
||||
id="path442" />
|
||||
<path
|
||||
fill="#000000"
|
||||
fill-opacity="0"
|
||||
d="m 502.22046,211.91864 v 0 c 0,-6.29692 5.10468,-11.40158 11.40161,-11.40158 v 0 c 3.02387,0 5.92389,1.20123 8.06214,3.33945 2.13818,2.13821 3.33941,5.03823 3.33941,8.06213 v 0 c 0,6.29691 -5.10467,11.40157 -11.40155,11.40157 v 0 c -6.29693,0 -11.40161,-5.10466 -11.40161,-11.40157 z"
|
||||
fill-rule="evenodd"
|
||||
id="path444" />
|
||||
<path
|
||||
stroke="#ffffff"
|
||||
stroke-width="1"
|
||||
stroke-linejoin="round"
|
||||
stroke-linecap="butt"
|
||||
d="m 505.5599,203.8565 16.1243,16.12425 m 0,-16.12425 -16.1243,16.12425"
|
||||
fill-rule="evenodd"
|
||||
id="path446" />
|
||||
<path
|
||||
stroke="#ffffff"
|
||||
stroke-width="1"
|
||||
stroke-linejoin="round"
|
||||
stroke-linecap="butt"
|
||||
d="m 502.22046,211.91864 v 0 c 0,-6.29692 5.10468,-11.40158 11.40161,-11.40158 v 0 c 3.02387,0 5.92389,1.20123 8.06214,3.33945 2.13818,2.13821 3.33941,5.03823 3.33941,8.06213 v 0 c 0,6.29691 -5.10467,11.40157 -11.40155,11.40157 v 0 c -6.29693,0 -11.40161,-5.10466 -11.40161,-11.40157 z"
|
||||
fill-rule="evenodd"
|
||||
id="path448" />
|
||||
<path
|
||||
fill="#f4cccc"
|
||||
d="m 520.96063,240.58267 h 63.53265 l 8.34137,8.34138 v 41.70586 h -71.87402 z"
|
||||
fill-rule="evenodd"
|
||||
id="path450" />
|
||||
<path
|
||||
stroke="#434343"
|
||||
stroke-width="1"
|
||||
stroke-linejoin="round"
|
||||
stroke-linecap="butt"
|
||||
d="m 520.96063,240.58267 h 63.53265 l 8.34137,8.34138 v 41.70586 h -71.87402 z"
|
||||
fill-rule="evenodd"
|
||||
id="path452" />
|
||||
<path
|
||||
fill="#000000"
|
||||
d="m 539.5544,266.86087 q 0,2.25 -1.03125,3.625 -1.01563,1.375 -2.78125,1.375 -1.79688,0 -2.82813,-1.14063 v 4.75 h -1.67187 v -13.65625 h 1.53125 l 0.0781,1.09375 q 1.03125,-1.26562 2.85938,-1.26562 1.78125,0 2.8125,1.34375 1.03125,1.32812 1.03125,3.71875 z m -1.67188,-0.20313 q 0,-1.65625 -0.71875,-2.625 -0.70312,-0.96875 -1.95312,-0.96875 -1.53125,0 -2.29688,1.35938 v 4.70312 q 0.76563,1.35938 2.32813,1.35938 1.20312,0 1.92187,-0.95313 0.71875,-0.96875 0.71875,-2.875 z m 3.37305,0 q 0,-1.45312 0.5625,-2.60937 0.57813,-1.15625 1.59375,-1.78125 1.01563,-0.625 2.3125,-0.625 2.01563,0 3.25,1.39062 1.25,1.39063 1.25,3.70313 v 0.125 q 0,1.4375 -0.54687,2.57812 -0.54688,1.14063 -1.57813,1.78125 -1.01562,0.64063 -2.35937,0.64063 -2,0 -3.25,-1.39063 -1.23438,-1.40625 -1.23438,-3.70312 z m 1.6875,0.20313 q 0,1.64062 0.76563,2.64062 0.76562,0.98438 2.03125,0.98438 1.29687,0 2.04687,-1 0.75,-1.01563 0.75,-2.82813 0,-1.625 -0.76562,-2.625 -0.76563,-1.01562 -2.04688,-1.01562 -1.25,0 -2.01562,1 -0.76563,0.98437 -0.76563,2.84375 z m 8.98364,-0.20313 q 0,-2.26562 1.07813,-3.64062 1.07812,-1.375 2.8125,-1.375 1.73437,0 2.75,1.17187 v -5.14062 h 1.6875 v 14 h -1.54688 l -0.0937,-1.0625 q -1,1.25 -2.8125,1.25 -1.70312,0 -2.79687,-1.40625 -1.07813,-1.40625 -1.07813,-3.65625 z m 1.6875,0.20313 q 0,1.67187 0.6875,2.625 0.70313,0.9375 1.92188,0.9375 1.60937,0 2.34375,-1.4375 v -4.53125 q -0.76563,-1.39063 -2.32813,-1.39063 -1.23437,0 -1.9375,0.95313 -0.6875,0.95312 -0.6875,2.84375 z"
|
||||
fill-rule="nonzero"
|
||||
id="path454" />
|
||||
<path
|
||||
fill="#f4cccc"
|
||||
d="m 252.73753,436.23883 h 63.53264 l 8.34137,8.3414 v 41.70587 h -71.87401 z"
|
||||
fill-rule="evenodd"
|
||||
id="path456" />
|
||||
<path
|
||||
stroke="#434343"
|
||||
stroke-width="1"
|
||||
stroke-linejoin="round"
|
||||
stroke-linecap="butt"
|
||||
d="m 252.73753,436.23883 h 63.53264 l 8.34137,8.3414 v 41.70587 h -71.87401 z"
|
||||
fill-rule="evenodd"
|
||||
id="path458" />
|
||||
<path
|
||||
fill="#000000"
|
||||
d="m 271.33127,462.51703 q 0,2.25 -1.03125,3.625 -1.01562,1.375 -2.78125,1.375 -1.79687,0 -2.82812,-1.14063 v 4.75 h -1.67188 v -13.65625 h 1.53125 l 0.0781,1.09375 q 1.03125,-1.26562 2.85937,-1.26562 1.78125,0 2.8125,1.34375 1.03125,1.32812 1.03125,3.71875 z m -1.67187,-0.20313 q 0,-1.65625 -0.71875,-2.625 -0.70313,-0.96875 -1.95313,-0.96875 -1.53125,0 -2.29687,1.35938 v 4.70312 q 0.76562,1.35938 2.32812,1.35938 1.20313,0 1.92188,-0.95313 0.71875,-0.96875 0.71875,-2.875 z m 3.37307,0 q 0,-1.45312 0.5625,-2.60937 0.57813,-1.15625 1.59375,-1.78125 1.01563,-0.625 2.3125,-0.625 2.01563,0 3.25,1.39062 1.25,1.39063 1.25,3.70313 v 0.125 q 0,1.4375 -0.54687,2.57812 -0.54688,1.14063 -1.57813,1.78125 -1.01562,0.64063 -2.35937,0.64063 -2,0 -3.25,-1.39063 -1.23438,-1.40625 -1.23438,-3.70312 z m 1.6875,0.20313 q 0,1.64062 0.76563,2.64062 0.76562,0.98438 2.03125,0.98438 1.29687,0 2.04687,-1 0.75,-1.01563 0.75,-2.82813 0,-1.625 -0.76562,-2.625 -0.76563,-1.01562 -2.04688,-1.01562 -1.25,0 -2.01562,1 -0.76563,0.98437 -0.76563,2.84375 z m 8.98365,-0.20313 q 0,-2.26562 1.07812,-3.64062 1.07813,-1.375 2.8125,-1.375 1.73438,0 2.75,1.17187 v -5.14062 h 1.6875 v 14 h -1.54687 l -0.0937,-1.0625 q -1,1.25 -2.8125,1.25 -1.70313,0 -2.79688,-1.40625 -1.07812,-1.40625 -1.07812,-3.65625 z m 1.6875,0.20313 q 0,1.67187 0.6875,2.625 0.70312,0.9375 1.92187,0.9375 1.60938,0 2.34375,-1.4375 v -4.53125 q -0.76562,-1.39063 -2.32812,-1.39063 -1.23438,0 -1.9375,0.95313 -0.6875,0.95312 -0.6875,2.84375 z"
|
||||
fill-rule="nonzero"
|
||||
id="path460" />
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 39 KiB |
File diff suppressed because one or more lines are too long
|
Before Width: | Height: | Size: 57 KiB |
File diff suppressed because one or more lines are too long
|
Before Width: | Height: | Size: 55 KiB |
File diff suppressed because one or more lines are too long
|
Before Width: | Height: | Size: 110 KiB |
@@ -1,48 +1,3 @@
|
||||
- date: [2021-02-08, 2021-02-10]
|
||||
country: www
|
||||
city: streaming
|
||||
event: ENIX SAS
|
||||
speaker: jpetazzo
|
||||
title: Docker intensif (en français)
|
||||
lang: fr
|
||||
attend: https://enix.io/fr/services/formation/online/
|
||||
|
||||
- date: [2021-02-15, 2021-02-18]
|
||||
country: www
|
||||
city: streaming
|
||||
event: ENIX SAS
|
||||
speaker: jpetazzo
|
||||
title: Fondamentaux Kubernetes (en français)
|
||||
lang: fr
|
||||
attend: https://enix.io/fr/services/formation/online/
|
||||
|
||||
- date: [2021-02-22, 2021-02-23]
|
||||
country: www
|
||||
city: streaming
|
||||
event: ENIX SAS
|
||||
speaker: jpetazzo
|
||||
title: Packaging et CI/CD pour Kubernetes (en français)
|
||||
lang: fr
|
||||
attend: https://enix.io/fr/services/formation/online/
|
||||
|
||||
- date: [2021-02-24, 2021-02-26]
|
||||
country: www
|
||||
city: streaming
|
||||
event: ENIX SAS
|
||||
speaker: jpetazzo
|
||||
title: Kubernetes avancé (en français)
|
||||
lang: fr
|
||||
attend: https://enix.io/fr/services/formation/online/
|
||||
|
||||
- date: [2021-03-01, 2021-03-02]
|
||||
country: www
|
||||
city: streaming
|
||||
event: ENIX SAS
|
||||
speaker: jpetazzo
|
||||
title: Opérer Kubernetes (en français)
|
||||
lang: fr
|
||||
attend: https://enix.io/fr/services/formation/online/
|
||||
|
||||
- date: [2020-10-05, 2020-10-06]
|
||||
country: www
|
||||
city: streaming
|
||||
|
||||
@@ -1,70 +0,0 @@
|
||||
title: |
|
||||
Introduction
|
||||
to Containers
|
||||
|
||||
chat: "[Slack](https://dockercommunity.slack.com/messages/C7GKACWDV)"
|
||||
#chat: "[Gitter](https://gitter.im/jpetazzo/workshop-yyyymmdd-city)"
|
||||
|
||||
gitrepo: github.com/jpetazzo/container.training
|
||||
|
||||
slides: http://container.training/
|
||||
|
||||
#slidenumberprefix: "#SomeHashTag — "
|
||||
|
||||
exclude:
|
||||
- self-paced
|
||||
|
||||
content:
|
||||
- shared/title.md
|
||||
- logistics.md
|
||||
- containers/intro.md
|
||||
- shared/about-slides.md
|
||||
- shared/chat-room-im.md
|
||||
#- shared/chat-room-slack.md
|
||||
#- shared/chat-room-zoom-meeting.md
|
||||
#- shared/chat-room-zoom-webinar.md
|
||||
- shared/toc.md
|
||||
-
|
||||
#- containers/Docker_Overview.md
|
||||
#- containers/Docker_History.md
|
||||
- containers/Training_Environment.md
|
||||
#- containers/Installing_Docker.md
|
||||
- containers/First_Containers.md
|
||||
- containers/Background_Containers.md
|
||||
#- containers/Start_And_Attach.md
|
||||
- containers/Naming_And_Inspecting.md
|
||||
#- containers/Labels.md
|
||||
- containers/Getting_Inside.md
|
||||
- containers/Initial_Images.md
|
||||
-
|
||||
- containers/Building_Images_Interactively.md
|
||||
- containers/Building_Images_With_Dockerfiles.md
|
||||
- containers/Cmd_And_Entrypoint.md
|
||||
- containers/Copying_Files_During_Build.md
|
||||
- containers/Exercise_Dockerfile_Basic.md
|
||||
-
|
||||
- containers/Container_Networking_Basics.md
|
||||
#- containers/Network_Drivers.md
|
||||
- containers/Local_Development_Workflow.md
|
||||
- containers/Container_Network_Model.md
|
||||
- containers/Compose_For_Dev_Stacks.md
|
||||
- containers/Exercise_Composefile.md
|
||||
-
|
||||
- containers/Multi_Stage_Builds.md
|
||||
#- containers/Publishing_To_Docker_Hub.md
|
||||
- containers/Dockerfile_Tips.md
|
||||
- containers/Exercise_Dockerfile_Advanced.md
|
||||
#- containers/Docker_Machine.md
|
||||
#- containers/Advanced_Dockerfiles.md
|
||||
#- containers/Init_Systems.md
|
||||
#- containers/Application_Configuration.md
|
||||
#- containers/Logging.md
|
||||
#- containers/Namespaces_Cgroups.md
|
||||
#- containers/Copy_On_Write.md
|
||||
#- containers/Containers_From_Scratch.md
|
||||
#- containers/Container_Engines.md
|
||||
#- containers/Pods_Anatomy.md
|
||||
#- containers/Ecosystem.md
|
||||
#- containers/Orchestration_Overview.md
|
||||
- shared/thankyou.md
|
||||
- containers/links.md
|
||||
@@ -1,71 +0,0 @@
|
||||
title: |
|
||||
Introduction
|
||||
to Containers
|
||||
|
||||
chat: "[Slack](https://dockercommunity.slack.com/messages/C7GKACWDV)"
|
||||
#chat: "[Gitter](https://gitter.im/jpetazzo/workshop-yyyymmdd-city)"
|
||||
|
||||
gitrepo: github.com/jpetazzo/container.training
|
||||
|
||||
slides: http://container.training/
|
||||
|
||||
#slidenumberprefix: "#SomeHashTag — "
|
||||
|
||||
exclude:
|
||||
- in-person
|
||||
|
||||
content:
|
||||
- shared/title.md
|
||||
# - shared/logistics.md
|
||||
- containers/intro.md
|
||||
- shared/about-slides.md
|
||||
#- shared/chat-room-im.md
|
||||
#- shared/chat-room-slack.md
|
||||
#- shared/chat-room-zoom-meeting.md
|
||||
#- shared/chat-room-zoom-webinar.md
|
||||
- shared/toc.md
|
||||
- - containers/Docker_Overview.md
|
||||
- containers/Docker_History.md
|
||||
- containers/Training_Environment.md
|
||||
- containers/Installing_Docker.md
|
||||
- containers/First_Containers.md
|
||||
- containers/Background_Containers.md
|
||||
- containers/Start_And_Attach.md
|
||||
- - containers/Initial_Images.md
|
||||
- containers/Building_Images_Interactively.md
|
||||
- containers/Building_Images_With_Dockerfiles.md
|
||||
- containers/Cmd_And_Entrypoint.md
|
||||
- containers/Copying_Files_During_Build.md
|
||||
- containers/Exercise_Dockerfile_Basic.md
|
||||
- - containers/Multi_Stage_Builds.md
|
||||
- containers/Publishing_To_Docker_Hub.md
|
||||
- containers/Dockerfile_Tips.md
|
||||
- containers/Exercise_Dockerfile_Advanced.md
|
||||
- - containers/Naming_And_Inspecting.md
|
||||
- containers/Labels.md
|
||||
- containers/Getting_Inside.md
|
||||
- - containers/Container_Networking_Basics.md
|
||||
- containers/Network_Drivers.md
|
||||
- containers/Container_Network_Model.md
|
||||
#- containers/Connecting_Containers_With_Links.md
|
||||
- containers/Ambassadors.md
|
||||
- - containers/Local_Development_Workflow.md
|
||||
- containers/Windows_Containers.md
|
||||
- containers/Working_With_Volumes.md
|
||||
- containers/Compose_For_Dev_Stacks.md
|
||||
- containers/Exercise_Composefile.md
|
||||
- containers/Docker_Machine.md
|
||||
- - containers/Advanced_Dockerfiles.md
|
||||
- containers/Init_Systems.md
|
||||
- containers/Application_Configuration.md
|
||||
- containers/Logging.md
|
||||
- containers/Resource_Limits.md
|
||||
- - containers/Namespaces_Cgroups.md
|
||||
- containers/Copy_On_Write.md
|
||||
#- containers/Containers_From_Scratch.md
|
||||
- - containers/Container_Engines.md
|
||||
- containers/Pods_Anatomy.md
|
||||
- containers/Ecosystem.md
|
||||
- containers/Orchestration_Overview.md
|
||||
- shared/thankyou.md
|
||||
- containers/links.md
|
||||
@@ -1,79 +0,0 @@
|
||||
title: |
|
||||
Introduction
|
||||
to Containers
|
||||
|
||||
chat: "[Slack](https://dockercommunity.slack.com/messages/C7GKACWDV)"
|
||||
#chat: "[Gitter](https://gitter.im/jpetazzo/workshop-yyyymmdd-city)"
|
||||
|
||||
gitrepo: github.com/jpetazzo/container.training
|
||||
|
||||
slides: http://container.training/
|
||||
|
||||
#slidenumberprefix: "#SomeHashTag — "
|
||||
|
||||
exclude:
|
||||
- self-paced
|
||||
|
||||
content:
|
||||
- shared/title.md
|
||||
- logistics.md
|
||||
- containers/intro.md
|
||||
- shared/about-slides.md
|
||||
- shared/chat-room-im.md
|
||||
#- shared/chat-room-slack.md
|
||||
#- shared/chat-room-zoom-meeting.md
|
||||
#- shared/chat-room-zoom-webinar.md
|
||||
- shared/toc.md
|
||||
- # DAY 1
|
||||
- containers/Docker_Overview.md
|
||||
#- containers/Docker_History.md
|
||||
- containers/Training_Environment.md
|
||||
- containers/First_Containers.md
|
||||
- containers/Background_Containers.md
|
||||
- containers/Initial_Images.md
|
||||
-
|
||||
- containers/Building_Images_Interactively.md
|
||||
- containers/Building_Images_With_Dockerfiles.md
|
||||
- containers/Cmd_And_Entrypoint.md
|
||||
- containers/Copying_Files_During_Build.md
|
||||
- containers/Exercise_Dockerfile_Basic.md
|
||||
-
|
||||
- containers/Dockerfile_Tips.md
|
||||
- containers/Multi_Stage_Builds.md
|
||||
- containers/Publishing_To_Docker_Hub.md
|
||||
- containers/Exercise_Dockerfile_Advanced.md
|
||||
-
|
||||
- containers/Naming_And_Inspecting.md
|
||||
- containers/Labels.md
|
||||
- containers/Start_And_Attach.md
|
||||
- containers/Getting_Inside.md
|
||||
- containers/Resource_Limits.md
|
||||
- # DAY 2
|
||||
- containers/Container_Networking_Basics.md
|
||||
- containers/Network_Drivers.md
|
||||
- containers/Container_Network_Model.md
|
||||
-
|
||||
- containers/Local_Development_Workflow.md
|
||||
- containers/Working_With_Volumes.md
|
||||
- containers/Compose_For_Dev_Stacks.md
|
||||
- containers/Exercise_Composefile.md
|
||||
-
|
||||
- containers/Installing_Docker.md
|
||||
- containers/Container_Engines.md
|
||||
- containers/Init_Systems.md
|
||||
- containers/Advanced_Dockerfiles.md
|
||||
-
|
||||
- containers/Application_Configuration.md
|
||||
- containers/Logging.md
|
||||
- containers/Orchestration_Overview.md
|
||||
-
|
||||
- shared/thankyou.md
|
||||
- containers/links.md
|
||||
#-
|
||||
#- containers/Docker_Machine.md
|
||||
#- containers/Ambassadors.md
|
||||
#- containers/Namespaces_Cgroups.md
|
||||
#- containers/Copy_On_Write.md
|
||||
#- containers/Containers_From_Scratch.md
|
||||
#- containers/Pods_Anatomy.md
|
||||
#- containers/Ecosystem.md
|
||||
@@ -1,104 +0,0 @@
|
||||
## Accessing our EKS cluster
|
||||
|
||||
- We also have a shared EKS cluster
|
||||
|
||||
- With individual IAM users
|
||||
|
||||
- Let's connect to this cluster!
|
||||
|
||||
---
|
||||
|
||||
## What we need
|
||||
|
||||
- `kubectl` (obviously!)
|
||||
|
||||
- `aws` CLI (recent-ish version)
|
||||
|
||||
(or `aws` CLI + `aws-iam-authenticator` plugin)
|
||||
|
||||
- AWS API access key and secret access key
|
||||
|
||||
- AWS region
|
||||
|
||||
- EKS cluster name
|
||||
|
||||
---
|
||||
|
||||
## Setting up AWS credentials
|
||||
|
||||
- There are many ways to do this
|
||||
|
||||
- We're going to use environment variables
|
||||
|
||||
- You're welcome to use whatever you like (e.g. AWS profiles)
|
||||
|
||||
.exercise[
|
||||
|
||||
- Set the AWS region, API access key, and secret key:
|
||||
```bash
|
||||
export AWS_DEFAULT_REGION=`us-east-2`
|
||||
export AWS_ACCESS_KEY_ID=`AKI...`
|
||||
export AWS_SECRET_ACCESS_KEY=`xyz123...`
|
||||
```
|
||||
|
||||
- Check that the AWS API recognizes us:
|
||||
```bash
|
||||
aws sts get-caller-identity
|
||||
```
|
||||
|
||||
]
|
||||
|
||||
---
|
||||
|
||||
## Updating our kubeconfig file
|
||||
|
||||
- Now we can use the AWS CLI to:
|
||||
|
||||
- obtain the Kubernetes API address
|
||||
|
||||
- register it in our kubeconfig file
|
||||
|
||||
.exercise[
|
||||
|
||||
- Update our kubeconfig file:
|
||||
```bash
|
||||
aws eks update-kubeconfig --name `fancy-clustername-1234`
|
||||
```
|
||||
|
||||
- Run some harmless command:
|
||||
```bash
|
||||
kubectl version
|
||||
```
|
||||
|
||||
]
|
||||
|
||||
---
|
||||
|
||||
## Our resources
|
||||
|
||||
- We have the following permissions:
|
||||
|
||||
- `view` in the `default` namespace
|
||||
|
||||
- `edit` in the `container-training` namespace
|
||||
|
||||
- `admin` in our personal namespace
|
||||
|
||||
- Our personal namespace is our IAM user name
|
||||
|
||||
(but with dots replaced with dashes)
|
||||
|
||||
- For instance, user `ada.lovelace` has namespace `ada-lovelace`
|
||||
|
||||
---
|
||||
|
||||
## Deploying things
|
||||
|
||||
- Let's deploy DockerCoins in our personal namespace!
|
||||
|
||||
- Expose the Web UI with a `LoadBalancer` service
|
||||
|
||||
???
|
||||
|
||||
:EN:- Working with an EKS cluster
|
||||
:FR:- Travailler avec un cluster EKS
|
||||
@@ -134,17 +134,3 @@ installed and set up `kubectl` to communicate with your cluster.
|
||||
|
||||
:EN:- Securely accessing internal services
|
||||
:FR:- Accès sécurisé aux services internes
|
||||
|
||||
:T: Accessing internal services from our local machine
|
||||
|
||||
:Q: What's the advantage of "kubectl port-forward" compared to a NodePort?
|
||||
:A: It can forward arbitrary protocols
|
||||
:A: It doesn't require Kubernetes API credentials
|
||||
:A: It offers deterministic load balancing (instead of random)
|
||||
:A: ✔️It doesn't expose the service to the public
|
||||
|
||||
:Q: What's the security concept behind "kubectl port-forward"?
|
||||
:A: ✔️We authenticate with the Kubernetes API, and it forwards connections on our behalf
|
||||
:A: It detects our source IP address, and only allows connections coming from it
|
||||
:A: It uses end-to-end mTLS (mutual TLS) to authenticate our connections
|
||||
:A: There is no security (as long as it's running, anyone can connect from anywhere)
|
||||
|
||||
@@ -58,24 +58,27 @@
|
||||
|
||||
*probably aggregation layer*
|
||||
|
||||
|
||||
---
|
||||
|
||||
## How are resources organized?
|
||||
|
||||
- Let's have a look at the Kubernetes API hierarchical structure
|
||||
|
||||
- We'll ask `kubectl` to show us the exacts requests that it's making
|
||||
- Useful: `.metadata.selfLink` contains the URI of a resource
|
||||
|
||||
.exercise[
|
||||
|
||||
- Check the URI for a cluster-scope, "core" resource, e.g. a Node:
|
||||
- Check the `apiVersion` and URI of a "core" resource, e.g. a Node:
|
||||
```bash
|
||||
kubectl -v6 get node node1
|
||||
kubectl get nodes -o json | jq .items[0].apiVersion
|
||||
kubectl get nodes -o json | jq .items[0].metadata.selfLink
|
||||
```
|
||||
|
||||
- Check the URI for a cluster-scope, "non-core" resource, e.g. a ClusterRole:
|
||||
- Get the `apiVersion` and URI for a "non-core" resource, e.g. a ClusterRole:
|
||||
```bash
|
||||
kubectl -v6 get clusterrole view
|
||||
kubectl get clusterrole view -o json | jq .apiVersion
|
||||
kubectl get clusterrole view -o json | jq .metadata.selfLink
|
||||
```
|
||||
|
||||
]
|
||||
@@ -120,17 +123,6 @@ class: extra-details
|
||||
|
||||
## Namespaced resources
|
||||
|
||||
- What about namespaced resources?
|
||||
|
||||
.exercise[
|
||||
|
||||
- Check the URI for a namespaced, "core" resource, e.g. a Service:
|
||||
```bash
|
||||
kubectl -v6 get service kubernetes --namespace default
|
||||
```
|
||||
|
||||
]
|
||||
|
||||
- Here are what namespaced resources URIs look like:
|
||||
|
||||
```
|
||||
@@ -176,7 +168,7 @@ class: extra-details
|
||||
kubectl get pods --namespace=kube-system --selector=k8s-app=kube-proxy
|
||||
PODNAME=$(
|
||||
kubectl get pods --namespace=kube-system --selector=k8s-app=kube-proxy \
|
||||
-o json | jq -r .items[0].metadata.name)
|
||||
-o json | jq .items[0].metadata.name)
|
||||
```
|
||||
|
||||
- Execute a command in a pod, showing the API requests:
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
- Jobs are great for "long" background work
|
||||
|
||||
("long" being at least minutes or hours)
|
||||
("long" being at least minutes our hours)
|
||||
|
||||
- CronJobs are great to schedule Jobs at regular intervals
|
||||
|
||||
|
||||
@@ -242,5 +242,3 @@ class: extra-details
|
||||
|
||||
:EN:- Obtaining certificates with cert-manager
|
||||
:FR:- Obtenir des certificats avec cert-manager
|
||||
|
||||
:T: Obtaining TLS certificates with cert-manager
|
||||
|
||||
@@ -338,9 +338,9 @@ docker run --rm --net host -v $PWD:/vol \
|
||||
|
||||
(e.g. [Portworx](https://docs.portworx.com/portworx-install-with-kubernetes/storage-operations/create-snapshots/) can [create snapshots through annotations](https://docs.portworx.com/portworx-install-with-kubernetes/storage-operations/create-snapshots/snaps-annotations/#taking-periodic-snapshots-on-a-running-pod))
|
||||
|
||||
- Option 3: [snapshots through Kubernetes API](https://kubernetes.io/docs/concepts/storage/volume-snapshots/)
|
||||
- Option 3: [snapshots through Kubernetes API](https://kubernetes.io/blog/2018/10/09/introducing-volume-snapshot-alpha-for-kubernetes/)
|
||||
|
||||
(Generally available since Kuberentes 1.20 for a number of [CSI](https://kubernetes.io/blog/2019/01/15/container-storage-interface-ga/) volume plugins : GCE, OpenSDS, Ceph, Portworx, etc)
|
||||
(now in alpha for a few storage providers: GCE, OpenSDS, Ceph, Portworx)
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -60,41 +60,21 @@
|
||||
|
||||
## Command-line arguments
|
||||
|
||||
- Indicate what should run in the container
|
||||
- Pass options to `args` array in the container specification
|
||||
|
||||
- Pass `command` and/or `args` in the container options in a Pod's template
|
||||
|
||||
- Both `command` and `args` are arrays
|
||||
|
||||
- Example ([source](https://github.com/jpetazzo/container.training/blob/main/k8s/consul-1.yaml#L70)):
|
||||
- Example ([source](https://github.com/coreos/pods/blob/master/kubernetes.yaml#L29)):
|
||||
```yaml
|
||||
args:
|
||||
- "agent"
|
||||
- "-bootstrap-expect=3"
|
||||
- "-retry-join=provider=k8s label_selector=\"app=consul\" namespace=\"$(NS)\""
|
||||
- "-client=0.0.0.0"
|
||||
- "-data-dir=/consul/data"
|
||||
- "-server"
|
||||
- "-ui"
|
||||
args:
|
||||
- "--data-dir=/var/lib/etcd"
|
||||
- "--advertise-client-urls=http://127.0.0.1:2379"
|
||||
- "--listen-client-urls=http://127.0.0.1:2379"
|
||||
- "--listen-peer-urls=http://127.0.0.1:2380"
|
||||
- "--name=etcd"
|
||||
```
|
||||
|
||||
---
|
||||
- The options can be passed directly to the program that we run ...
|
||||
|
||||
## `args` or `command`?
|
||||
|
||||
- Use `command` to override the `ENTRYPOINT` defined in the image
|
||||
|
||||
- Use `args` to keep the `ENTRYPOINT` defined in the image
|
||||
|
||||
(the parameters specified in `args` are added to the `ENTRYPOINT`)
|
||||
|
||||
- In doubt, use `command`
|
||||
|
||||
- It is also possible to use *both* `command` and `args`
|
||||
|
||||
(they will be strung together, just like `ENTRYPOINT` and `CMD`)
|
||||
|
||||
- See the [docs](https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#notes) to see how they interact together
|
||||
... or to a wrapper script that will use them to e.g. generate a config file
|
||||
|
||||
---
|
||||
|
||||
@@ -534,12 +514,73 @@ spec:
|
||||
|
||||
]
|
||||
|
||||
---
|
||||
|
||||
## Passwords, tokens, sensitive information
|
||||
|
||||
- For sensitive information, there is another special resource: *Secrets*
|
||||
|
||||
- Secrets and Configmaps work almost the same way
|
||||
|
||||
(we'll expose the differences on the next slide)
|
||||
|
||||
- The *intent* is different, though:
|
||||
|
||||
*"You should use secrets for things which are actually secret like API keys,
|
||||
credentials, etc., and use config map for not-secret configuration data."*
|
||||
|
||||
*"In the future there will likely be some differentiators for secrets like rotation or support for backing the secret API w/ HSMs, etc."*
|
||||
|
||||
(Source: [the author of both features](https://stackoverflow.com/a/36925553/580281
|
||||
))
|
||||
|
||||
---
|
||||
|
||||
class: extra-details
|
||||
|
||||
## Differences between configmaps and secrets
|
||||
|
||||
- Secrets are base64-encoded when shown with `kubectl get secrets -o yaml`
|
||||
|
||||
- keep in mind that this is just *encoding*, not *encryption*
|
||||
|
||||
- it is very easy to [automatically extract and decode secrets](https://medium.com/@mveritym/decoding-kubernetes-secrets-60deed7a96a3)
|
||||
|
||||
- [Secrets can be encrypted at rest](https://kubernetes.io/docs/tasks/administer-cluster/encrypt-data/)
|
||||
|
||||
- With RBAC, we can authorize a user to access configmaps, but not secrets
|
||||
|
||||
(since they are two different kinds of resources)
|
||||
|
||||
---
|
||||
|
||||
class: extra-details
|
||||
|
||||
## Immutable ConfigMaps and Secrets
|
||||
|
||||
- Since Kubernetes 1.19, it is possible to mark a ConfigMap or Secret as *immutable*
|
||||
|
||||
```bash
|
||||
kubectl patch configmap xyz --patch='{"immutable": true}'
|
||||
```
|
||||
|
||||
- This brings performance improvements when using lots of ConfigMaps and Secrets
|
||||
|
||||
(lots = tens of thousands)
|
||||
|
||||
- Once a ConfigMap or Secret has been marked as immutable:
|
||||
|
||||
- its content cannot be changed anymore
|
||||
- the `immutable` field can't be changed back either
|
||||
- the only way to change it is to delete and re-create it
|
||||
- Pods using it will have to be re-created as well
|
||||
|
||||
???
|
||||
|
||||
:EN:- Managing application configuration
|
||||
:EN:- Exposing configuration with the downward API
|
||||
:EN:- Exposing configuration with Config Maps
|
||||
:EN:- Exposing configuration with Config Maps and Secrets
|
||||
|
||||
:FR:- Gérer la configuration des applications
|
||||
:FR:- Configuration au travers de la *downward API*
|
||||
:FR:- Configurer les applications avec des *Config Maps*
|
||||
:FR:- Configuration via les *Config Maps* et *Secrets*
|
||||
|
||||
@@ -92,29 +92,6 @@
|
||||
|
||||
---
|
||||
|
||||
## etcd authorization
|
||||
|
||||
- etcd supports RBAC, but Kubernetes doesn't use it by default
|
||||
|
||||
(note: etcd RBAC is completely different from Kubernetes RBAC!)
|
||||
|
||||
- By default, etcd access is "all or nothing"
|
||||
|
||||
(if you have a valid certificate, you get in)
|
||||
|
||||
- Be very careful if you use the same root CA for etcd and other things
|
||||
|
||||
(if etcd trusts the root CA, then anyone with a valid cert gets full etcd access)
|
||||
|
||||
- For more details, check the following resources:
|
||||
|
||||
- [etcd documentation on authentication](https://etcd.io/docs/current/op-guide/authentication/)
|
||||
|
||||
- [PKI The Wrong Way](https://www.youtube.com/watch?v=gcOLDEzsVHI) at KubeCon NA 2020
|
||||
|
||||
---
|
||||
|
||||
|
||||
## API server clients
|
||||
|
||||
- The API server has a sophisticated authentication and authorization system
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Authoring YAML
|
||||
|
||||
- We have already generated YAML implicitly, with e.g.:
|
||||
- There are various ways to generate YAML with Kubernetes, e.g.:
|
||||
|
||||
- `kubectl run`
|
||||
|
||||
@@ -32,63 +32,26 @@
|
||||
|
||||
---
|
||||
|
||||
## Various ways to write YAML
|
||||
## We don't have to start from scratch
|
||||
|
||||
- Completely from scratch with our favorite editor
|
||||
- Create a resource (e.g. Deployment)
|
||||
|
||||
(yeah, right)
|
||||
- Dump its YAML with `kubectl get -o yaml ...`
|
||||
|
||||
- Dump an existing resource with `kubectl get -o yaml ...`
|
||||
- Edit the YAML
|
||||
|
||||
(it is recommended to clean up the result)
|
||||
- Use `kubectl apply -f ...` with the YAML file to:
|
||||
|
||||
- Ask `kubectl` to generate the YAML
|
||||
- update the resource (if it's the same kind)
|
||||
|
||||
(with a `kubectl create --dry-run -o yaml`)
|
||||
- create a new resource (if it's a different kind)
|
||||
|
||||
- Use The Docs, Luke
|
||||
- Or: Use The Docs, Luke
|
||||
|
||||
(the documentation almost always has YAML examples)
|
||||
|
||||
---
|
||||
|
||||
## Generating YAML from scratch
|
||||
|
||||
- Start with a namespace:
|
||||
```yaml
|
||||
kind: Namespace
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: hello
|
||||
```
|
||||
|
||||
- We can use `kubectl explain` to see resource definitions:
|
||||
```bash
|
||||
kubectl explain -r pod.spec
|
||||
```
|
||||
|
||||
- Not the easiest option!
|
||||
|
||||
---
|
||||
|
||||
## Dump the YAML for an existing resource
|
||||
|
||||
- `kubectl get -o yaml` works!
|
||||
|
||||
- A lot of fields in `metadata` are not necessary
|
||||
|
||||
(`managedFields`, `resourceVersion`, `uid`, `creationTimestamp` ...)
|
||||
|
||||
- Most objects will have a `status` field that is not necessary
|
||||
|
||||
- Default or empty values can also be removed for clarity
|
||||
|
||||
- This can be done manually or with the `kubectl-neat` plugin
|
||||
|
||||
`kubectl get -o yaml ... | kubectl neat`
|
||||
|
||||
---
|
||||
|
||||
## Generating YAML without creating resources
|
||||
|
||||
- We can use the `--dry-run` option
|
||||
@@ -100,18 +63,14 @@
|
||||
kubectl create deployment web --image nginx --dry-run
|
||||
```
|
||||
|
||||
- Optionally clean it up with `kubectl neat`, too
|
||||
|
||||
]
|
||||
|
||||
Note: in recent versions of Kubernetes, we should use `--dry-run=client`
|
||||
- We can clean up that YAML even more if we want
|
||||
|
||||
(Or `--dry-run=server`; more on that later!)
|
||||
(for instance, we can remove the `creationTimestamp` and empty dicts)
|
||||
|
||||
---
|
||||
|
||||
class: extra-details
|
||||
|
||||
## Using `--dry-run` with `kubectl apply`
|
||||
|
||||
- The `--dry-run` option can also be used with `kubectl apply`
|
||||
@@ -128,8 +87,6 @@ class: extra-details
|
||||
|
||||
---
|
||||
|
||||
class: extra-details
|
||||
|
||||
## The limits of `kubectl apply --dry-run`
|
||||
|
||||
.exercise[
|
||||
@@ -155,8 +112,6 @@ The resulting YAML doesn't represent a valid DaemonSet.
|
||||
|
||||
---
|
||||
|
||||
class: extra-details
|
||||
|
||||
## Server-side dry run
|
||||
|
||||
- Since Kubernetes 1.13, we can use [server-side dry run and diffs](https://kubernetes.io/blog/2019/01/14/apiserver-dry-run-and-kubectl-diff/)
|
||||
@@ -180,8 +135,6 @@ Instead, it has the fields expected in a DaemonSet.
|
||||
|
||||
---
|
||||
|
||||
class: extra-details
|
||||
|
||||
## Advantages of server-side dry run
|
||||
|
||||
- The YAML is verified much more extensively
|
||||
@@ -196,8 +149,6 @@ class: extra-details
|
||||
|
||||
---
|
||||
|
||||
class: extra-details
|
||||
|
||||
## `kubectl diff`
|
||||
|
||||
- Kubernetes 1.13 also introduced `kubectl diff`
|
||||
@@ -258,8 +209,3 @@ Note: we don't need to specify `--validate=false` here.
|
||||
- check that it still works!
|
||||
|
||||
- That YAML will be useful later when using e.g. Kustomize or Helm
|
||||
|
||||
???
|
||||
|
||||
:EN:- Techniques to write YAML manifests
|
||||
:FR:- Comment écrire des *manifests* YAML
|
||||
@@ -10,7 +10,7 @@ Level 2: make it so that the number of replicas can be set with `--set replicas=
|
||||
|
||||
Level 3: change the colors of the lego bricks.
|
||||
|
||||
(For level 3, you'll have to build/push your own images.)
|
||||
(For level 3, fork the repository and use ctr.run to build images.)
|
||||
|
||||
See next slide if you need hints!
|
||||
|
||||
@@ -44,12 +44,20 @@ Also add `replicas: 5` to `values.yaml` to provide a default value.
|
||||
|
||||
## Changing the color
|
||||
|
||||
- Create an account on e.g. Docker Hub (e.g. `janedoe`)
|
||||
- Fork the repository
|
||||
|
||||
- Create an image repository (e.g. `janedoe/web`)
|
||||
- Make sure that your fork has valid Dockerfiles
|
||||
|
||||
(or identify a branch that has valid Dockerfiles)
|
||||
|
||||
- Use the following images:
|
||||
|
||||
ctr.run/yourgithubusername/wordsmith/db:branchname
|
||||
|
||||
(replace db with web and words for the other components)
|
||||
|
||||
- Change the images and/or CSS in `web/static`
|
||||
|
||||
- Build and push
|
||||
- Commit, push, trigger a rolling update
|
||||
|
||||
- Trigger a rolling update using the image you just pushed
|
||||
(`imagePullPolicy` should be `Always`, which is the default)
|
||||
|
||||
@@ -1,447 +0,0 @@
|
||||
# CI/CD with GitLab
|
||||
|
||||
- In this section, we will see how to set up a CI/CD pipeline with GitLab
|
||||
|
||||
(using a "self-hosted" GitLab; i.e. running on our Kubernetes cluster)
|
||||
|
||||
- The big picture:
|
||||
|
||||
- each time we push code to GitLab, it will be deployed in a staging environment
|
||||
|
||||
- each time we push the `production` tag, it will be deployed in production
|
||||
|
||||
---
|
||||
|
||||
## Disclaimers
|
||||
|
||||
- We'll use GitLab here as an exemple, but there are many other options
|
||||
|
||||
(e.g. some combination of Argo, Harbor, Tekton ...)
|
||||
|
||||
- There are also hosted options
|
||||
|
||||
(e.g. GitHub Actions and many others)
|
||||
|
||||
- We'll use a specific pipeline and workflow, but it's purely arbitrary
|
||||
|
||||
(treat it as a source of inspiration, not a model to be copied!)
|
||||
|
||||
---
|
||||
|
||||
## Workflow overview
|
||||
|
||||
- Push code to GitLab's git server
|
||||
|
||||
- GitLab notices the `.gitlab-ci.yml` file, which defines our pipeline
|
||||
|
||||
- Our pipeline can have multiple *stages* executed sequentially
|
||||
|
||||
(e.g. lint, build, test, deploy ...)
|
||||
|
||||
- Each stage can have multiple *jobs* executed in parallel
|
||||
|
||||
(e.g. build images in parallel)
|
||||
|
||||
- Each job will be executed in an independent *runner* pod
|
||||
|
||||
---
|
||||
|
||||
## Pipeline overview
|
||||
|
||||
- Our repository holds source code, Dockerfiles, and a Helm chart
|
||||
|
||||
- *Lint* stage will check the Helm chart validity
|
||||
|
||||
- *Build* stage will build container images
|
||||
|
||||
(and push them to GitLab's integrated registry)
|
||||
|
||||
- *Deploy* stage will deploy the Helm chart, using these images
|
||||
|
||||
- Pushes to `production` will deploy to "the" production namespace
|
||||
|
||||
- Pushes to other tags/branches will deploy to a namespace created on the fly
|
||||
|
||||
- We will discuss shortcomings and alternatives and the end of this chapter!
|
||||
|
||||
---
|
||||
|
||||
## Lots of requirements
|
||||
|
||||
- We need *a lot* of components to pull this off:
|
||||
|
||||
- a domain name
|
||||
|
||||
- a storage class
|
||||
|
||||
- a TLS-capable ingress controller
|
||||
|
||||
- the cert-manager operator
|
||||
|
||||
- GitLab itself
|
||||
|
||||
- the GitLab pipeline
|
||||
|
||||
- Wow, why?!?
|
||||
|
||||
---
|
||||
|
||||
## I find your lack of TLS disturbing
|
||||
|
||||
- We need a container registry (obviously!)
|
||||
|
||||
- Docker (and other container engines) *require* TLS on the registry
|
||||
|
||||
(with valid certificates)
|
||||
|
||||
- A few options:
|
||||
|
||||
- use a "real" TLS certificate (e.g. obtained with Let's Encrypt)
|
||||
|
||||
- use a self-signed TLS certificate
|
||||
|
||||
- communicate with the registry over localhost (TLS isn't required then)
|
||||
|
||||
---
|
||||
|
||||
class: extra-details
|
||||
|
||||
## Why not self-signed certs?
|
||||
|
||||
- When using self-signed certs, we need to either:
|
||||
|
||||
- add the cert (or CA) to trusted certs
|
||||
|
||||
- disable cert validation
|
||||
|
||||
- This needs to be done on *every client* connecting to the registry:
|
||||
|
||||
- CI/CD pipeline (building and pushing images)
|
||||
|
||||
- container engine (deploying the images)
|
||||
|
||||
- other tools (e.g. container security scanner)
|
||||
|
||||
- It's doable, but it's a lot of hacks (especially when adding more tools!)
|
||||
|
||||
---
|
||||
|
||||
class: extra-details
|
||||
|
||||
## Why not localhost?
|
||||
|
||||
- TLS is usually not required when the registry is on localhost
|
||||
|
||||
- We could expose the registry e.g. on a `NodePort`
|
||||
|
||||
- ... And then tweak the CI/CD pipeline to use that instead
|
||||
|
||||
- This is great when obtaining valid certs is difficult:
|
||||
|
||||
- air-gapped or internal environments (that can't use Let's Encrypt)
|
||||
|
||||
- no domain name available
|
||||
|
||||
- Downside: the registry isn't easily or safely available from outside
|
||||
|
||||
(the `NodePort` essentially defeats TLS)
|
||||
|
||||
---
|
||||
|
||||
class: extra-details
|
||||
|
||||
## Can we use `nip.io`?
|
||||
|
||||
- We will use Let's Encrypt
|
||||
|
||||
- Let's Encrypt has a quota of certificates per domain
|
||||
|
||||
(in 2020, that was [50 certificates per week per domain](https://letsencrypt.org/docs/rate-limits/))
|
||||
|
||||
- So if we all use `nip.io`, we will probably run into that limit
|
||||
|
||||
- But you can try and see if it works!
|
||||
|
||||
---
|
||||
|
||||
## Ingress
|
||||
|
||||
- We will assume that we have a domain name pointing to our cluster
|
||||
|
||||
(i.e. with a wildcard record pointing to at least one node of the cluster)
|
||||
|
||||
- We will get traffic in the cluster by leveraging `ExternalIPs` services
|
||||
|
||||
(but it would be easy to use `LoadBalancer` services instead)
|
||||
|
||||
- We will use Traefik as the ingress controller
|
||||
|
||||
(but any other one should work too)
|
||||
|
||||
- We will use cert-manager to obtain certificates with Let's Encrypt
|
||||
|
||||
---
|
||||
|
||||
## Other details
|
||||
|
||||
- We will deploy GitLab with its official Helm chart
|
||||
|
||||
- It will still require a bunch of parameters and customization
|
||||
|
||||
- We also need a Storage Class
|
||||
|
||||
(unless our cluster already has one, of course)
|
||||
|
||||
- We suggest the [Rancher local path provisioner](https://github.com/rancher/local-path-provisioner)
|
||||
|
||||
---
|
||||
|
||||
## Setting everything up
|
||||
|
||||
1. `git clone https://github.com/jpetazzo/kubecoin`
|
||||
|
||||
2. `export EMAIL=xxx@example.com DOMAIN=awesome-kube-ci.io`
|
||||
|
||||
(we need a real email address and a domain pointing to the cluster!)
|
||||
|
||||
3. `. setup-gitlab-on-k8s.rc`
|
||||
|
||||
(this doesn't do anything, but defines a number of helper functions)
|
||||
|
||||
4. Execute each helper function, one after another
|
||||
|
||||
(try `do_[TAB]` to see these functions)
|
||||
|
||||
---
|
||||
|
||||
## Local Storage
|
||||
|
||||
`do_1_localstorage`
|
||||
|
||||
Applies the YAML directly from Rancher's repository.
|
||||
|
||||
Annotate the Storage Class so that it becomes the default one.
|
||||
|
||||
---
|
||||
|
||||
## Traefik
|
||||
|
||||
`do_2_traefik_with_externalips`
|
||||
|
||||
Install the official Traefik Helm chart.
|
||||
|
||||
Instead of a `LoadBalancer` service, use a `ClusterIP` with `ExternalIPs`.
|
||||
|
||||
Automatically infer the `ExternalIPs` from `kubectl get nodes`.
|
||||
|
||||
Enable TLS.
|
||||
|
||||
---
|
||||
|
||||
## cert-manager
|
||||
|
||||
`do_3_certmanager`
|
||||
|
||||
Install cert-manager using their official YAML.
|
||||
|
||||
Easy-peasy.
|
||||
|
||||
---
|
||||
|
||||
## Certificate issuers
|
||||
|
||||
`do_4_issuers`
|
||||
|
||||
Create a couple of `ClusterIssuer` resources for cert-manager.
|
||||
|
||||
(One for the staging Let's Encrypt environment, one for production.)
|
||||
|
||||
Note: this requires to specify a valid `$EMAIL` address!
|
||||
|
||||
Note: if this fails, wait a bit and try again (cert-manager needs to be up).
|
||||
|
||||
---
|
||||
|
||||
## GitLab
|
||||
|
||||
`do_5_gitlab`
|
||||
|
||||
Deploy GitLab using their official Helm chart.
|
||||
|
||||
We pass a lot of parameters to this chart:
|
||||
- the domain name to use
|
||||
- disable GitLab's own ingress and cert-manager
|
||||
- annotate the ingress resources so that cert-manager kicks in
|
||||
- bind the shell service (git over SSH) to port 222 to avoid conflict
|
||||
- use ExternalIPs for that shell service
|
||||
|
||||
Note: on modest cloud instances, it can take 10 minutes for GitLab to come up.
|
||||
|
||||
We can check the status with `kubectl get pods --namespace=gitlab`
|
||||
|
||||
---
|
||||
|
||||
## Log into GitLab and configure it
|
||||
|
||||
`do_6_showlogin`
|
||||
|
||||
This will get the GitLab root password (stored in a Secret).
|
||||
|
||||
Then we need to:
|
||||
- log into GitLab
|
||||
- add our SSH key (top-right user menu → settings, then SSH keys on the left)
|
||||
- create a project (using the + menu next to the search bar on top)
|
||||
- go to project configuration (on the left, settings → CI/CD)
|
||||
- add a `KUBECONFIG` file variable with the content of our `.kube/config` file
|
||||
- go to settings → access tokens to create a read-only registry token
|
||||
- add variables `REGISTRY_USER` and `REGISTRY_PASSWORD` with that token
|
||||
- push our repo (`git remote add gitlab ...` then `git push gitlab ...`)
|
||||
|
||||
---
|
||||
|
||||
## Monitoring progress and troubleshooting
|
||||
|
||||
- Click on "CI/CD" in the left bar to view pipelines
|
||||
|
||||
- If you see a permission issue mentioning `system:serviceaccount:gitlab:...`:
|
||||
|
||||
*make sure you did set `KUBECONFIG` correctly!*
|
||||
|
||||
- GitLab will create namespaces named `gl-<user>-<project>`
|
||||
|
||||
- At the end of the deployment, the web UI will be available on some unique URL
|
||||
|
||||
(`http://<user>-<project>-<githash>-gitlab.<domain>`)
|
||||
|
||||
---
|
||||
|
||||
## Production
|
||||
|
||||
- `git tag -f production && git push -f --tags`
|
||||
|
||||
- Our CI/CD pipeline will deploy on the production URL
|
||||
|
||||
(`http://<user>-<project>-gitlab.<domain>`)
|
||||
|
||||
- It will do it *only* if that same git commit was pushed to staging first
|
||||
|
||||
(look in the pipeline configuration file to see how it's done!)
|
||||
|
||||
---
|
||||
|
||||
## Let's talk about build
|
||||
|
||||
- There are many ways to build container images on Kubernetes
|
||||
|
||||
- ~~And they all suck~~ Many of them have inconveniencing issues
|
||||
|
||||
- Let's do a quick review!
|
||||
|
||||
---
|
||||
|
||||
## Docker-based approaches
|
||||
|
||||
- Bind-mount the Docker socket
|
||||
|
||||
- very easy, but requires Docker Engine
|
||||
- build resource usage "evades" Kubernetes scheduler
|
||||
- insecure
|
||||
|
||||
- Docker-in-Docker in a pod
|
||||
|
||||
- requires privileged pod
|
||||
- insecure
|
||||
- approaches like rootless or sysbox might help in the future
|
||||
|
||||
- External build host
|
||||
|
||||
- more secure
|
||||
- requires resources outside of the Kubernetes cluster
|
||||
|
||||
---
|
||||
|
||||
## Non-privileged builders
|
||||
|
||||
- Kaniko
|
||||
|
||||
- each build runs in its own containers or pod
|
||||
- no caching by default
|
||||
- registry-based caching is possible
|
||||
|
||||
- BuildKit / `docker buildx`
|
||||
|
||||
- can leverage Docker Engine or long-running Kubernetes worker pod
|
||||
- supports distributed, multi-arch build farms
|
||||
- basic caching out of the box
|
||||
- can also leverage registry-based caching
|
||||
|
||||
---
|
||||
|
||||
## Other approaches
|
||||
|
||||
- Ditch the Dockerfile!
|
||||
|
||||
- bazel
|
||||
|
||||
- jib
|
||||
|
||||
- ko
|
||||
|
||||
- etc.
|
||||
|
||||
---
|
||||
|
||||
## Discussion
|
||||
|
||||
- Our CI/CD workflow is just *one* of the many possibilities
|
||||
|
||||
- It would be nice to add some actual unit or e2e tests
|
||||
|
||||
- Map the production namespace to a "real" domain name
|
||||
|
||||
- Automatically remove older staging environments
|
||||
|
||||
(see e.g. [kube-janitor](https://codeberg.org/hjacobs/kube-janitor))
|
||||
|
||||
- Deploy production to a separate cluster
|
||||
|
||||
- Better segregate permissions
|
||||
|
||||
(don't give `cluster-admin` to the GitLab pipeline)
|
||||
|
||||
---
|
||||
|
||||
## Pros
|
||||
|
||||
- GitLab is an amazing, open source, all-in-one platform
|
||||
|
||||
- Available as hosted, community, or enterprise editions
|
||||
|
||||
- Rich ecosystem, very customizable
|
||||
|
||||
- Can run on Kubernetes, or somewhere else
|
||||
|
||||
---
|
||||
|
||||
## Cons
|
||||
|
||||
- It can be difficult to use components separately
|
||||
|
||||
(e.g. use a different registry, or a different job runner)
|
||||
|
||||
- More than one way to configure it
|
||||
|
||||
(it's not an opinionated platform)
|
||||
|
||||
- Not "Kubernetes-native"
|
||||
|
||||
(for instance, jobs are not Kubernetes jobs)
|
||||
|
||||
- Job latency could be improved
|
||||
|
||||
*Note: most of these drawbacks are the flip side of the "pros" on the previous slide!*
|
||||
|
||||
???
|
||||
|
||||
:EN:- CI/CD with GitLab
|
||||
:FR:- CI/CD avec GitLab
|
||||
@@ -1,338 +0,0 @@
|
||||
# Charts using other charts
|
||||
|
||||
- Helm charts can have *dependencies* on other charts
|
||||
|
||||
- These dependencies will help us to share or reuse components
|
||||
|
||||
(so that we write and maintain less manifests, less templates, less code!)
|
||||
|
||||
- As an example, we will use a community chart for Redis
|
||||
|
||||
- This will help people who write charts, and people who use them
|
||||
|
||||
- ... And potentially remove a lot of code! ✌️
|
||||
|
||||
---
|
||||
|
||||
## Redis in DockerCoins
|
||||
|
||||
- In the DockerCoins demo app, we have 5 components:
|
||||
|
||||
- 2 internal webservices
|
||||
- 1 worker
|
||||
- 1 public web UI
|
||||
- 1 Redis data store
|
||||
|
||||
- Every component is running some custom code, except Redis
|
||||
|
||||
- Every component is using a custom image, except Redis
|
||||
|
||||
(which is using the official `redis` image)
|
||||
|
||||
- Could we use a standard chart for Redis?
|
||||
|
||||
- Yes! Dependencies to the rescue!
|
||||
|
||||
---
|
||||
|
||||
## Adding our dependency
|
||||
|
||||
- First, we will add the dependency to the `Chart.yaml` file
|
||||
|
||||
- Then, we will ask Helm to download that dependency
|
||||
|
||||
- We will also *lock* the dependency
|
||||
|
||||
(lock it to a specific version, to ensure reproducibility)
|
||||
|
||||
---
|
||||
|
||||
## Declaring the dependency
|
||||
|
||||
- First, let's edit `Chart.yaml`
|
||||
|
||||
.exercise[
|
||||
|
||||
- In `Chart.yaml`, fill the `dependencies` section:
|
||||
```yaml
|
||||
dependencies:
|
||||
- name: redis
|
||||
version: 11.0.5
|
||||
repository: https://charts.bitnami.com/bitnami
|
||||
condition: redis.enabled
|
||||
```
|
||||
|
||||
]
|
||||
|
||||
Where do that `repository` and `version` come from?
|
||||
|
||||
We're assuming here that we did our reserach,
|
||||
or that our resident Helm expert advised us to
|
||||
use Bitnami's Redis chart.
|
||||
|
||||
---
|
||||
|
||||
## Conditions
|
||||
|
||||
- The `condition` field gives us a way to enable/disable the dependency:
|
||||
```yaml
|
||||
conditions: redis.enabled
|
||||
```
|
||||
|
||||
- Here, we can disable Redis with the Helm flag `--set redis.enabled=false`
|
||||
|
||||
(or set that value in a `values.yaml` file)
|
||||
|
||||
- Of course, this is mostly useful for *optional* dependencies
|
||||
|
||||
(otherwise, the app ends up being broken since it'll miss a component)
|
||||
|
||||
---
|
||||
|
||||
## Lock & Load!
|
||||
|
||||
- After adding the dependency, we ask Helm to pin an download it
|
||||
|
||||
.exercise[
|
||||
|
||||
- Ask Helm:
|
||||
```bash
|
||||
helm dependency update
|
||||
```
|
||||
|
||||
(Or `helm dep up`)
|
||||
|
||||
]
|
||||
|
||||
- This wil create `Chart.lock` and fetch the dependency
|
||||
|
||||
---
|
||||
|
||||
## What's `Chart.lock`?
|
||||
|
||||
- This is a common pattern with dependencies
|
||||
|
||||
(see also: `Gemfile.lock`, `package.json.lock`, and many others)
|
||||
|
||||
- This lets us define loose dependencies in `Chart.yaml`
|
||||
|
||||
(e.g. "version 11.whatever, but below 12")
|
||||
|
||||
- But have the exact version used in `Chart.lock`
|
||||
|
||||
- This ensures reproducible deployments
|
||||
|
||||
- `Chart.lock` can (should!) be added to our source tree
|
||||
|
||||
- `Chart.lock` can (should!) regularly be updated
|
||||
|
||||
---
|
||||
|
||||
## Loose dependencies
|
||||
|
||||
- Here is an example of loose version requirement:
|
||||
```yaml
|
||||
dependencies:
|
||||
- name: redis
|
||||
version: ">=11 <12"
|
||||
repository: https://charts.bitnami.com/bitnami
|
||||
```
|
||||
|
||||
- This makes sure that we have the most recent version in the 11.x train
|
||||
|
||||
- ... But without upgrading to version 12.x
|
||||
|
||||
(because it might be incompatible)
|
||||
|
||||
---
|
||||
|
||||
## `build` vs `update`
|
||||
|
||||
- Helm actually offers two commands to manage dependencies:
|
||||
|
||||
`helm dependency build` = fetch dependencies listed in `Chart.lock`
|
||||
|
||||
`helm dependency update` = update `Chart.lock` (and run `build`)
|
||||
|
||||
- When the dependency gets updated, we can/should:
|
||||
|
||||
- `helm dep up` (update `Chart.lock` and fetch new chart)
|
||||
|
||||
- test!
|
||||
|
||||
- if everything is fine, `git add Chart.lock` and commit
|
||||
|
||||
---
|
||||
|
||||
## Where are my dependencies?
|
||||
|
||||
- Dependencies are downloaded to the `charts/` subdirectory
|
||||
|
||||
- When they're downloaded, they stay in compressed format (`.tgz`)
|
||||
|
||||
- Should we commit them to our code repository?
|
||||
|
||||
- Pros:
|
||||
|
||||
- more resilient to internet/mirror failures/decomissioning
|
||||
|
||||
- Cons:
|
||||
|
||||
- can add a lot of weight to the repo if charts are big or change often
|
||||
|
||||
- this can be solved by extra tools like git-lfs
|
||||
|
||||
---
|
||||
|
||||
## Dependency tuning
|
||||
|
||||
- DockerCoins expects the `redis` Service to be named `redis`
|
||||
|
||||
- Our Redis chart uses a different Service name by default
|
||||
|
||||
- Service name is `{{ template "redis.fullname" . }}-master`
|
||||
|
||||
- `redis.fullname` looks like this:
|
||||
```
|
||||
{{- define "redis.fullname" -}}
|
||||
{{- if .Values.fullnameOverride -}}
|
||||
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}}
|
||||
{{- else -}}
|
||||
[...]
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
```
|
||||
|
||||
- How do we fix this?
|
||||
|
||||
---
|
||||
|
||||
## Setting dependency variables
|
||||
|
||||
- If we set `fullnameOverride` to `redis`:
|
||||
|
||||
- the `{{ template ... }}` block will output `redis`
|
||||
|
||||
- the Service name will be `redis-master`
|
||||
|
||||
- A parent chart can set values for its dependencies
|
||||
|
||||
- For example, in the parent's `values.yaml`:
|
||||
|
||||
```yaml
|
||||
redis: # Name of the dependency
|
||||
fullnameOverride: redis # Value passed to redis
|
||||
cluster: # Other values passed to redis
|
||||
enabled: false
|
||||
```
|
||||
|
||||
- User can also set variables with `--set=` or with `--values=`
|
||||
|
||||
---
|
||||
|
||||
class: extra-details
|
||||
|
||||
## Passing templates
|
||||
|
||||
- We can even pass template `{{ include "template.name" }}`, but warning:
|
||||
|
||||
- need to be evaluated with the `tpl` function, on the child side
|
||||
|
||||
- evaluated in the context of the child, with no access to parent variables
|
||||
|
||||
<!-- FIXME this probably deserves an example, but I can't imagine one right now 😅 -->
|
||||
|
||||
---
|
||||
|
||||
## Getting rid of the `-master`
|
||||
|
||||
- Even if we set that `fullnameOverride`, the Service name will be `redis-master`
|
||||
|
||||
- To remove the `-master` suffix, we need to edit the chart itself
|
||||
|
||||
- To edit the Redis chart, we need to *embed* it in our own chart
|
||||
|
||||
- We need to:
|
||||
|
||||
- decompress the chart
|
||||
|
||||
- adjust `Chart.yaml` accordingly
|
||||
|
||||
---
|
||||
|
||||
## Embedding a dependency
|
||||
|
||||
.exercise[
|
||||
|
||||
- Decompress the chart:
|
||||
```yaml
|
||||
cd charts
|
||||
tar zxf redis-*.tgz
|
||||
cd ..
|
||||
```
|
||||
|
||||
- Edit `Chart.yaml` and update the `dependencies` section:
|
||||
```yaml
|
||||
dependencies:
|
||||
- name: redis
|
||||
version: '*' # No need to constraint version, from local files
|
||||
```
|
||||
|
||||
- Run `helm dep update`
|
||||
|
||||
]
|
||||
|
||||
---
|
||||
|
||||
## Updating the dependency
|
||||
|
||||
- Now we can edit the Service name
|
||||
|
||||
(it should be in `charts/redis/templates/redis-master-svc.yaml`)
|
||||
|
||||
- Then try to deploy the whole chart!
|
||||
|
||||
---
|
||||
|
||||
## Embedding a dependency multiple times
|
||||
|
||||
- What if we need multiple copies of the same subchart?
|
||||
|
||||
(for instance, if we need two completely different Redis servers)
|
||||
|
||||
- We can declare a dependency multiple times, and specify an `alias`:
|
||||
```yaml
|
||||
dependencies:
|
||||
- name: redis
|
||||
version: '*'
|
||||
alias: querycache
|
||||
- name: redis
|
||||
version: '*'
|
||||
alias: celeryqueue
|
||||
```
|
||||
|
||||
- `.Chart.Name` will be set to the `alias`
|
||||
|
||||
---
|
||||
|
||||
class: extra-details
|
||||
|
||||
## Compatibility with Helm 2
|
||||
|
||||
- Chart `apiVersion: v1` is the only version supported by Helm 2
|
||||
|
||||
- Chart v1 is also supported by Helm 3
|
||||
|
||||
- Use v1 if you want to be compatible with Helm 2
|
||||
|
||||
- Instead of `Chart.yaml`, dependencies are defined in `requirements.yaml`
|
||||
|
||||
(and we should commit `requirements.lock` instead of `Chart.lock`)
|
||||
|
||||
???
|
||||
|
||||
:EN:- Depending on other charts
|
||||
:EN:- Charts within charts
|
||||
|
||||
:FR:- Dépendances entre charts
|
||||
:FR:- Un chart peut en cacher un autre
|
||||
@@ -244,7 +244,7 @@ fine for personal and development clusters.)
|
||||
|
||||
- Add the `stable` repo:
|
||||
```bash
|
||||
helm repo add stable https://charts.helm.sh/stable
|
||||
helm repo add stable https://kubernetes-charts.storage.googleapis.com/
|
||||
```
|
||||
|
||||
]
|
||||
@@ -255,22 +255,6 @@ It's OK to add a repo that already exists (it will merely update it).
|
||||
|
||||
---
|
||||
|
||||
class: extra-details
|
||||
|
||||
## Deprecation warning
|
||||
|
||||
- That "stable" is being deprecated, in favor of a more decentralized approach
|
||||
|
||||
(each community / company / group / project hosting their own repository)
|
||||
|
||||
- We're going to use it here for educational purposes
|
||||
|
||||
- But if you're looking for production-grade charts, look elsewhere!
|
||||
|
||||
(namely, on the Helm Hub)
|
||||
|
||||
---
|
||||
|
||||
## Search available charts
|
||||
|
||||
- We can search available charts with `helm search`
|
||||
@@ -462,17 +446,3 @@ All unspecified values will take the default values defined in the chart.
|
||||
:FR:- Fonctionnement général de Helm
|
||||
:FR:- Installer des composants via Helm
|
||||
:FR:- Helm 2, Helm 3, et le *Helm Hub*
|
||||
|
||||
:T: Getting started with Helm and its concepts
|
||||
|
||||
:Q: Which comparison is the most adequate?
|
||||
:A: Helm is a firewall, charts are access lists
|
||||
:A: ✔️Helm is a package manager, charts are packages
|
||||
:A: Helm is an artefact repository, charts are artefacts
|
||||
:A: Helm is a CI/CD platform, charts are CI/CD pipelines
|
||||
|
||||
:Q: What's required to distribute a Helm chart?
|
||||
:A: A Helm commercial license
|
||||
:A: A Docker registry
|
||||
:A: An account on the Helm Hub
|
||||
:A: ✔️An HTTP server
|
||||
|
||||
@@ -1,191 +0,0 @@
|
||||
# Helm and invalid values
|
||||
|
||||
- A lot of Helm charts let us specify an image tag like this:
|
||||
```bash
|
||||
helm install ... --set image.tag=v1.0
|
||||
```
|
||||
|
||||
- What happens if we make a small mistake, like this:
|
||||
```bash
|
||||
helm install ... --set imagetag=v1.0
|
||||
```
|
||||
|
||||
- Or even, like this:
|
||||
```bash
|
||||
helm install ... --set image=v1.0
|
||||
```
|
||||
|
||||
🤔
|
||||
|
||||
---
|
||||
|
||||
## Making mistakes
|
||||
|
||||
- In the first case:
|
||||
|
||||
- we set `imagetag=v1.0` instead of `image.tag=v1.0`
|
||||
|
||||
- Helm will ignore that value (if it's not used anywhere in templates)
|
||||
|
||||
- the chart is deployed with the default value instead
|
||||
|
||||
- In the second case:
|
||||
|
||||
- we set `image=v1.0` instead of `image.tag=v1.0`
|
||||
|
||||
- `image` will be a string instead of an object
|
||||
|
||||
- Helm will *probably* fail when trying to evaluate `image.tag`
|
||||
|
||||
---
|
||||
|
||||
## Preventing mistakes
|
||||
|
||||
- To prevent the first mistake, we need to tell Helm:
|
||||
|
||||
*"let me know if any additional (unknonw) value was set!"*
|
||||
|
||||
- To prevent the second mistake, we need to tell Helm:
|
||||
|
||||
*"`image` should be an object, and `image.tag` should be a string!"*
|
||||
|
||||
- We can do this with *values schema validation*
|
||||
|
||||
---
|
||||
|
||||
## Helm values schema validation
|
||||
|
||||
- We can write a spec representing the possible values accepted by the chart
|
||||
|
||||
- Helm will check the validity of the values before trying to install/upgrade
|
||||
|
||||
- If it finds problems, it will stop immediately
|
||||
|
||||
- The spec uses [JSON Schema](https://json-schema.org/):
|
||||
|
||||
*JSON Schema is a vocabulary that allows you to annotate and validate JSON documents.*
|
||||
|
||||
- JSON Schema is designed for JSON, but can easily work with YAML too
|
||||
|
||||
(or any language with `map|dict|associativearray` and `list|array|sequence|tuple`)
|
||||
|
||||
---
|
||||
|
||||
## In practice
|
||||
|
||||
- We need to put the JSON Schema spec in a file called `values.schema.json`
|
||||
|
||||
(at the root of our chart; right next to `values.yaml` etc.)
|
||||
|
||||
- The file is optional
|
||||
|
||||
- We don't need to register or declare it in `Chart.yaml` or anywhere
|
||||
|
||||
- Let's write a schema that will verify that ...
|
||||
|
||||
- `image.repository` is an official image (string without slashes or dots)
|
||||
|
||||
- `image.pullPolicy` can only be `Always`, `Never`, `IfNotPresent`
|
||||
|
||||
---
|
||||
|
||||
## `values.schema.json`
|
||||
|
||||
```json
|
||||
{
|
||||
"$schema": "http://json-schema.org/schema#",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"image": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"repository": {
|
||||
"type": "string",
|
||||
"pattern": "^[a-z0-9-_]+$"
|
||||
},
|
||||
"pullPolicy": {
|
||||
"type": "string",
|
||||
"pattern": "^(Always|Never|IfNotPresent)$"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Testing our schema
|
||||
|
||||
- Let's try to install a couple releases with that schema!
|
||||
|
||||
.exercise[
|
||||
|
||||
- Try an invalid `pullPolicy`:
|
||||
```bash
|
||||
helm install broken --set image.pullPolicy=ShallNotPass
|
||||
```
|
||||
|
||||
- Try an invalid value:
|
||||
```bash
|
||||
helm install should-break --set ImAgeTAg=toto
|
||||
```
|
||||
|
||||
]
|
||||
|
||||
- The first one fails, but the second one still passes ...
|
||||
|
||||
- Why?
|
||||
|
||||
---
|
||||
|
||||
## Bailing out on unkown properties
|
||||
|
||||
- We told Helm what properties (values) were valid
|
||||
|
||||
- We didn't say what to do about additional (unknown) properties!
|
||||
|
||||
- We can fix that with `"additionalProperties": false`
|
||||
|
||||
.exercise[
|
||||
|
||||
- Edit `values.schema.json` to add `"additionalProperties": false`
|
||||
```json
|
||||
{
|
||||
"$schema": "http://json-schema.org/schema#",
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
...
|
||||
```
|
||||
|
||||
]
|
||||
|
||||
---
|
||||
|
||||
## Testing with unknown properties
|
||||
|
||||
.exercise[
|
||||
|
||||
- Try to pass an extra property:
|
||||
```bash
|
||||
helm install should-break --set ImAgeTAg=toto
|
||||
```
|
||||
|
||||
- Try to pass an extra nested property:
|
||||
```bash
|
||||
helm install does-it-work --set image.hello=world
|
||||
```
|
||||
|
||||
]
|
||||
|
||||
The first command should break.
|
||||
|
||||
The second will not.
|
||||
|
||||
`"additionalProperties": false` needs to be specified at each level.
|
||||
|
||||
???
|
||||
|
||||
:EN:- Helm schema validation
|
||||
:FR:- Validation de schema Helm
|
||||
@@ -72,7 +72,7 @@
|
||||
|
||||
- Deploy DockerCoins, and scale up the `worker` Deployment:
|
||||
```bash
|
||||
kubectl apply -f ~/container.training/k8s/dockercoins.yaml
|
||||
kubectl apply -f ~/container.training/k8/dockercoins.yaml
|
||||
kubectl scale deployment worker --replicas=10
|
||||
```
|
||||
|
||||
@@ -118,7 +118,7 @@
|
||||
|
||||
- Deploy `httplat`:
|
||||
```bash
|
||||
kubectl create deployment httplat --image=jpetazzo/httplat -- httplat http://rng/
|
||||
kubectl create deployment httplat -- httplat http://rng/
|
||||
```
|
||||
|
||||
- Expose it:
|
||||
@@ -512,20 +512,20 @@ no custom metrics API (custom.metrics.k8s.io) registered
|
||||
Here is the rule that we need to add to the configuration:
|
||||
|
||||
```yaml
|
||||
- seriesQuery: |
|
||||
httplat_latency_seconds_sum{kubernetes_namespace!="",kubernetes_name!=""}
|
||||
resources:
|
||||
overrides:
|
||||
kubernetes_namespace:
|
||||
resource: namespace
|
||||
kubernetes_name:
|
||||
resource: service
|
||||
name:
|
||||
matches: "httplat_latency_seconds_sum"
|
||||
as: "httplat_latency_seconds"
|
||||
metricsQuery: |
|
||||
rate(httplat_latency_seconds_sum{<<.LabelMatchers>>}[2m])
|
||||
/rate(httplat_latency_seconds_count{<<.LabelMatchers>>}[2m])
|
||||
- seriesQuery: |
|
||||
httplat_latency_seconds_sum{kubernetes_namespace!="",kubernetes_name!=""}
|
||||
resources:
|
||||
overrides:
|
||||
kubernetes_namespace:
|
||||
resource: namespace
|
||||
kubernetes_name:
|
||||
resource: service
|
||||
name:
|
||||
matches: "httplat_latency_seconds_sum"
|
||||
as: "httplat_latency_seconds"
|
||||
metricsQuery: |
|
||||
rate(httplat_latency_seconds_sum{<<.LabelMatchers>>}[2m])
|
||||
/rate(httplat_latency_seconds_count{<<.LabelMatchers>>}[2m])
|
||||
```
|
||||
|
||||
(I built it following the [walkthrough](https://github.com/DirectXMan12/k8s-prometheus-adapter/blob/master/docs/config-walkthrough.md
|
||||
@@ -636,7 +636,7 @@ kubectl get --raw /apis/custom.metrics.k8s.io/v1beta1
|
||||
Check that our `httplat` metrics are available:
|
||||
```bash
|
||||
kubectl get --raw /apis/custom.metrics.k8s.io/v1beta1\
|
||||
/namespaces/customscaling/services/httplat/httplat_latency_seconds
|
||||
/namespaces/coins/services/httplat/httplat_latency_seconds
|
||||
```
|
||||
|
||||
Also check the logs of the `prometheus-adapter` and the `kube-controller-manager`.
|
||||
|
||||
@@ -1,151 +0,0 @@
|
||||
# Kubernetes Internal APIs
|
||||
|
||||
- Almost every Kubernetes component has some kind of internal API
|
||||
|
||||
(some components even have multiple APIs on different ports!)
|
||||
|
||||
- At the very least, these can be used for healthchecks
|
||||
|
||||
(you *should* leverage this if you are deploying and operating Kubernetes yourself!)
|
||||
|
||||
- Sometimes, they are used internally by Kubernetes
|
||||
|
||||
(e.g. when the API server retrieves logs from kubelet)
|
||||
|
||||
- Let's review some of these APIs!
|
||||
|
||||
---
|
||||
|
||||
## API hunting guide
|
||||
|
||||
This is how we found and investigated these APIs:
|
||||
|
||||
- look for open ports on Kubernetes nodes
|
||||
|
||||
(worker nodes or control plane nodes)
|
||||
|
||||
- check which process owns that port
|
||||
|
||||
- probe the port (with `curl` or other tools)
|
||||
|
||||
- read the source code of that process
|
||||
|
||||
(in particular when looking for API routes)
|
||||
|
||||
OK, now let's see the results!
|
||||
|
||||
---
|
||||
|
||||
## etcd
|
||||
|
||||
- 2379/tcp → etcd clients
|
||||
|
||||
- should be HTTPS and require mTLS authentication
|
||||
|
||||
- 2380/tcp → etcd peers
|
||||
|
||||
- should be HTTPS and require mTLS authentication
|
||||
|
||||
- 2381/tcp → etcd healthcheck
|
||||
|
||||
- HTTP without authentication
|
||||
|
||||
- exposes two API routes: `/health` and `/metrics`
|
||||
|
||||
---
|
||||
|
||||
## kubelet
|
||||
|
||||
- 10248/tcp → healthcheck
|
||||
|
||||
- HTTP without authentication
|
||||
|
||||
- exposes a single API route, `/healthz`, that just returns `ok`
|
||||
|
||||
- 10250/tcp → internal API
|
||||
|
||||
- should be HTTPS and require mTLS authentication
|
||||
|
||||
- used by the API server to obtain logs, `kubectl exec`, etc.
|
||||
|
||||
---
|
||||
|
||||
class: extra-details
|
||||
|
||||
## kubelet API
|
||||
|
||||
- We can authenticate with e.g. our TLS admin certificate
|
||||
|
||||
- The following routes should be available:
|
||||
|
||||
- `/healthz`
|
||||
- `/configz` (serves kubelet configuration)
|
||||
- `/metrics`
|
||||
- `/pods` (returns *desired state*)
|
||||
- `/runningpods` (returns *current state* from the container runtime)
|
||||
- `/logs` (serves files from `/var/log`)
|
||||
- `/containerLogs/<namespace>/<podname>/<containername>` (can add e.g. `?tail=10`)
|
||||
- `/run`, `/exec`, `/attach`, `/portForward`
|
||||
|
||||
- See [kubelet source code](https://github.com/kubernetes/kubernetes/blob/master/pkg/kubelet/server/server.go) for details!
|
||||
|
||||
---
|
||||
|
||||
class: extra-details
|
||||
|
||||
## Trying the kubelet API
|
||||
|
||||
The following example should work on a cluster deployed with `kubeadm`.
|
||||
|
||||
1. Obtain the key and certificate for the `cluster-admin` user.
|
||||
|
||||
2. Log into a node.
|
||||
|
||||
3. Copy the key and certificate on the node.
|
||||
|
||||
4. Find out the name of the `kube-proxy` pod running on that node.
|
||||
|
||||
5. Run the following command, updating the pod name:
|
||||
```bash
|
||||
curl -d cmd=ls -k --cert admin.crt --key admin.key \
|
||||
https://localhost:10250/run/kube-system/`kube-proxy-xy123`/kube-proxy
|
||||
```
|
||||
|
||||
... This should show the content of the root directory in the pod.
|
||||
|
||||
---
|
||||
|
||||
## kube-proxy
|
||||
|
||||
- 10249/tcp → healthcheck
|
||||
|
||||
- HTTP, without authentication
|
||||
|
||||
- exposes a few API routes: `/healthz` (just returns `ok`), `/configz`, `/metrics`
|
||||
|
||||
- 10256/tcp → another healthcheck
|
||||
|
||||
- HTTP, without authentication
|
||||
|
||||
- also exposes a `/healthz` API route (but this one shows a timestamp)
|
||||
|
||||
---
|
||||
|
||||
## kube-controller and kube-scheduler
|
||||
|
||||
- 10257/tcp → kube-controller
|
||||
|
||||
- HTTPS, with optional mTLS authentication
|
||||
|
||||
- `/healthz` doesn't require authentication
|
||||
|
||||
- ... but `/configz` and `/metrics` do (use e.g. admin key and certificate)
|
||||
|
||||
- 10259/tcp → kube-scheduler
|
||||
|
||||
- similar to kube-controller, with the same routes
|
||||
|
||||
???
|
||||
|
||||
:EN:- Kubernetes internal APIs
|
||||
:FR:- Les APIs internes de Kubernetes
|
||||
@@ -1,141 +0,0 @@
|
||||
# k9s
|
||||
|
||||
- Somewhere in between CLI and GUI (or web UI), we can find the magic land of TUI
|
||||
|
||||
- [Text-based user interfaces](https://en.wikipedia.org/wiki/Text-based_user_interface)
|
||||
|
||||
- often using libraries like [curses](https://en.wikipedia.org/wiki/Curses_%28programming_library%29) and its successors
|
||||
|
||||
- Some folks love them, some folks hate them, some are indifferent ...
|
||||
|
||||
- But it's nice to have different options!
|
||||
|
||||
- Let's see one particular TUI for Kubernetes: [k9s](https://k9scli.io/)
|
||||
|
||||
---
|
||||
|
||||
## Installing k9s
|
||||
|
||||
- If you are using a training cluster or the [shpod](https://github.com/jpetazzo/shpod) image, k9s is pre-installed
|
||||
|
||||
- Otherwise, it can be installed easily:
|
||||
|
||||
- with [various package managers](https://k9scli.io/topics/install/)
|
||||
|
||||
- or by fetching a [binary release](https://github.com/derailed/k9s/releases)
|
||||
|
||||
- We don't need to set up or configure anything
|
||||
|
||||
(it will use the same configuration as `kubectl` and other well-behaved clients)
|
||||
|
||||
- Just run `k9s` to fire it up!
|
||||
|
||||
---
|
||||
|
||||
## What kind to we want to see?
|
||||
|
||||
- Press `:` to change the type of resource to view
|
||||
|
||||
- Then type, for instance, `ns` or `namespace` or `nam[TAB]`, then `[ENTER]`
|
||||
|
||||
- Use the arrows to move down to e.g. `kube-system`, and press `[ENTER]`
|
||||
|
||||
- Or, type `/kub` or `/sys` to filter the output, and press `[ENTER]` twice
|
||||
|
||||
(once to exit the filter, once to enter the namespace)
|
||||
|
||||
- We now see the pods in `kube-system`!
|
||||
|
||||
---
|
||||
|
||||
## Interacting with pods
|
||||
|
||||
- `l` to view logs
|
||||
|
||||
- `d` to describe
|
||||
|
||||
- `s` to get a shell (won't work if `sh` isn't available in the container image)
|
||||
|
||||
- `e` to edit
|
||||
|
||||
- `shift-f` to define port forwarding
|
||||
|
||||
- `ctrl-k` to kill
|
||||
|
||||
- `[ESC]` to get out or get back
|
||||
|
||||
---
|
||||
|
||||
## Quick navigation between namespaces
|
||||
|
||||
- On top of the screen, we should see shortcuts like this:
|
||||
```
|
||||
<0> all
|
||||
<1> kube-system
|
||||
<2> default
|
||||
```
|
||||
|
||||
- Pressing the corresponding number switches to that namespace
|
||||
|
||||
(or shows resources across all namespaces with `0`)
|
||||
|
||||
- Locate a namespace with a copy of DockerCoins, and go there!
|
||||
|
||||
---
|
||||
|
||||
## Interacting with Deployments
|
||||
|
||||
- View Deployments (type `:` `deploy` `[ENTER]`)
|
||||
|
||||
- Select e.g. `worker`
|
||||
|
||||
- Scale it with `s`
|
||||
|
||||
- View its aggregated logs with `l`
|
||||
|
||||
---
|
||||
|
||||
## Exit
|
||||
|
||||
- Exit at any time with `Ctrl-C`
|
||||
|
||||
- k9s will "remember" where you were
|
||||
|
||||
(and go back there next time you run it)
|
||||
|
||||
---
|
||||
|
||||
## Pros
|
||||
|
||||
- Very convenient to navigate through resources
|
||||
|
||||
(hopping from a deployment, to its pod, to another namespace, etc.)
|
||||
|
||||
- Very convenient to quickly view logs of e.g. init containers
|
||||
|
||||
- Very convenient to get a (quasi) realtime view of resources
|
||||
|
||||
(if we use `watch kubectl get` a lot, we will probably like k9s)
|
||||
|
||||
---
|
||||
|
||||
## Cons
|
||||
|
||||
- Doesn't promote automation / scripting
|
||||
|
||||
(if you repeat the same things over and over, there is a scripting opportunity)
|
||||
|
||||
- Not all features are available
|
||||
|
||||
(e.g. executing arbitrary commands in containers)
|
||||
|
||||
---
|
||||
|
||||
## Conclusion
|
||||
|
||||
Try it out, and see if it makes you more productive!
|
||||
|
||||
???
|
||||
|
||||
:EN:- The k9s TUI
|
||||
:FR:- L'interface texte k9s
|
||||
@@ -52,7 +52,7 @@
|
||||
|
||||
- There are literally dozens of implementations out there
|
||||
|
||||
(https://github.com/containernetworking/cni/ lists more than 25 plugins)
|
||||
(15 are listed in the Kubernetes documentation)
|
||||
|
||||
- Pods have level 3 (IP) connectivity, but *services* are level 4 (TCP or UDP)
|
||||
|
||||
@@ -128,36 +128,6 @@ class: extra-details
|
||||
|
||||
---
|
||||
|
||||
class: pic
|
||||
|
||||

|
||||
|
||||
---
|
||||
|
||||
class: pic
|
||||
|
||||

|
||||
|
||||
---
|
||||
|
||||
class: pic
|
||||
|
||||

|
||||
|
||||
---
|
||||
|
||||
class: pic
|
||||
|
||||

|
||||
|
||||
---
|
||||
|
||||
class: pic
|
||||
|
||||

|
||||
|
||||
---
|
||||
|
||||
class: extra-details
|
||||
|
||||
## Even more moving parts
|
||||
|
||||
@@ -321,9 +321,9 @@ class: extra-details
|
||||
|
||||
- Try to apply a few color labels:
|
||||
```bash
|
||||
kubectl label pod test-color-2 color=purple
|
||||
kubectl label pod test-color-2 color=red
|
||||
kubectl label pod test-color-2 color=blue --overwrite
|
||||
kubectl label test-color-2 color=purple
|
||||
kubectl label test-color-2 color=red
|
||||
kubectl label test-color-2 color=blue --overwrite
|
||||
```
|
||||
|
||||
]
|
||||
@@ -432,9 +432,9 @@ class: extra-details
|
||||
|
||||
- Try to apply a few color labels:
|
||||
```bash
|
||||
kubectl label pod test-color-3 color=purple
|
||||
kubectl label pod test-color-3 color=red
|
||||
kubectl label pod test-color-3 color-
|
||||
kubectl label test-color-3 color=purple
|
||||
kubectl label test-color-3 color=red
|
||||
kubectl label test-color-3 color-
|
||||
```
|
||||
|
||||
]
|
||||
|
||||
@@ -427,34 +427,26 @@ troubleshoot easily, without having to poke holes in our firewall.
|
||||
|
||||
---
|
||||
|
||||
## Tools and resources
|
||||
|
||||
- [Cilium Network Policy Editor](https://editor.cilium.io/)
|
||||
|
||||
- [Tufin Network Policy Viewer](https://orca.tufin.io/netpol/)
|
||||
|
||||
- Two resources by [Ahmet Alp Balkan](https://ahmet.im/):
|
||||
|
||||
- a [very good talk about network policies](https://www.youtube.com/watch?list=PLj6h78yzYM2P-3-xqvmWaZbbI1sW-ulZb&v=3gGpMmYeEO8) at KubeCon North America 2017
|
||||
|
||||
- a repository of [ready-to-use recipes](https://github.com/ahmetb/kubernetes-network-policy-recipes) for network policies
|
||||
|
||||
---
|
||||
|
||||
## Documentation
|
||||
## Further resources
|
||||
|
||||
- As always, the [Kubernetes documentation](https://kubernetes.io/docs/concepts/services-networking/network-policies/) is a good starting point
|
||||
|
||||
- The API documentation has a lot of detail about the format of various objects: <!-- ##VERSION## -->
|
||||
|
||||
- [NetworkPolicy](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.20/#networkpolicy-v1-networking-k8s-io)
|
||||
- [NetworkPolicy](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.19/#networkpolicy-v1-networking-k8s-io)
|
||||
|
||||
- [NetworkPolicySpec](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.20/#networkpolicyspec-v1-networking-k8s-io)
|
||||
- [NetworkPolicySpec](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.19/#networkpolicyspec-v1-networking-k8s-io)
|
||||
|
||||
- [NetworkPolicyIngressRule](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.20/#networkpolicyingressrule-v1-networking-k8s-io)
|
||||
- [NetworkPolicyIngressRule](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.19/#networkpolicyingressrule-v1-networking-k8s-io)
|
||||
|
||||
- etc.
|
||||
|
||||
- And two resources by [Ahmet Alp Balkan](https://ahmet.im/):
|
||||
|
||||
- a [very good talk about network policies](https://www.youtube.com/watch?list=PLj6h78yzYM2P-3-xqvmWaZbbI1sW-ulZb&v=3gGpMmYeEO8) at KubeCon North America 2017
|
||||
|
||||
- a repository of [ready-to-use recipes](https://github.com/ahmetb/kubernetes-network-policy-recipes) for network policies
|
||||
|
||||
???
|
||||
|
||||
:EN:- Isolating workloads with Network Policies
|
||||
|
||||
@@ -40,112 +40,6 @@
|
||||
|
||||
---
|
||||
|
||||
class: extra-details
|
||||
|
||||
## CPU limits implementation details
|
||||
|
||||
- A container with a CPU limit will be "rationed" by the kernel
|
||||
|
||||
- Every `cfs_period_us`, it will receive a CPU quota, like an "allowance"
|
||||
|
||||
(that interval defaults to 100ms)
|
||||
|
||||
- Once it has used its quota, it will be stalled until the next period
|
||||
|
||||
- This can easily result in throttling for bursty workloads
|
||||
|
||||
(see details on next slide)
|
||||
|
||||
---
|
||||
|
||||
class: extra-details
|
||||
|
||||
## A bursty example
|
||||
|
||||
- Web service receives one request per minute
|
||||
|
||||
- Each request takes 1 second of CPU
|
||||
|
||||
- Average load: 0.16%
|
||||
|
||||
- Let's say we set a CPU limit of 10%
|
||||
|
||||
- This means CPU quotas of 10ms every 100ms
|
||||
|
||||
- Obtaining the quota for 1 second of CPU will take 10 seconds
|
||||
|
||||
- Observed latency will be 10 seconds (... actually 9.9s) instead of 1 second
|
||||
|
||||
(real-life scenarios will of course be less extreme, but they do happen!)
|
||||
|
||||
---
|
||||
|
||||
class: extra-details
|
||||
|
||||
## Multi-core scheduling details
|
||||
|
||||
- Each core gets a small share of the container's CPU quota
|
||||
|
||||
(this avoids locking and contention on the "global" quota for the container)
|
||||
|
||||
- By default, the kernel distributes that quota to CPUs in 5ms increments
|
||||
|
||||
(tunable with `kernel.sched_cfs_bandwidth_slice_us`)
|
||||
|
||||
- If a containerized process (or thread) uses up its local CPU quota:
|
||||
|
||||
*it gets more from the "global" container quota (if there's some left)*
|
||||
|
||||
- If it "yields" (e.g. sleeps for I/O) before using its local CPU quota:
|
||||
|
||||
*the quota is **soon** returned to the "global" container quota, **minus** 1ms*
|
||||
|
||||
---
|
||||
|
||||
class: extra-details
|
||||
|
||||
## Low quotas on machines with many cores
|
||||
|
||||
- The local CPU quota is not immediately returned to the global quota
|
||||
|
||||
- this reduces locking and contention on the global quota
|
||||
|
||||
- but this can cause starvation when many threads/processes become runnable
|
||||
|
||||
- That 1ms that "stays" on the local CPU quota is often useful
|
||||
|
||||
- if the thread/process becomes runnable, it can be scheduled immediately
|
||||
|
||||
- again, this reduces locking and contention on the global quota
|
||||
|
||||
- but if the thread/process doesn't become runnable, it is wasted!
|
||||
|
||||
- this can become a huge problem on machines with many cores
|
||||
|
||||
---
|
||||
|
||||
class: extra-details
|
||||
|
||||
## CPU limits in a nutshell
|
||||
|
||||
- Beware if you run small bursty workloads on machines with many cores!
|
||||
|
||||
("highly-threaded, user-interactive, non-cpu bound applications")
|
||||
|
||||
- Check the `nr_throttled` and `throttled_time` metrics in `cpu.stat`
|
||||
|
||||
- Possible solutions/workarounds:
|
||||
|
||||
- be generous with the limits
|
||||
|
||||
- make sure your kernel has the [appropriate patch](https://lkml.org/lkml/2019/5/17/581)
|
||||
|
||||
- use [static CPU manager policy](https://kubernetes.io/docs/tasks/administer-cluster/cpu-management-policies/#static-policy)
|
||||
|
||||
For more details, check [this blog post](https://erickhun.com/posts/kubernetes-faster-services-no-cpu-limits/) or these ones ([part 1](https://engineering.indeedblog.com/blog/2019/12/unthrottled-fixing-cpu-limits-in-the-cloud/), [part 2](https://engineering.indeedblog.com/blog/2019/12/cpu-throttling-regression-fix/)).
|
||||
|
||||
---
|
||||
|
||||
## Exceeding memory limits
|
||||
|
||||
- Memory needs to be swapped out before being reclaimed
|
||||
|
||||
@@ -1,289 +0,0 @@
|
||||
# Managing secrets
|
||||
|
||||
- Sometimes our code needs sensitive information:
|
||||
|
||||
- passwords
|
||||
|
||||
- API tokens
|
||||
|
||||
- TLS keys
|
||||
|
||||
- ...
|
||||
|
||||
- *Secrets* can be used for that purpose
|
||||
|
||||
- Secrets and ConfigMaps are very similar
|
||||
|
||||
---
|
||||
|
||||
## Similarities between ConfigMap and Secrets
|
||||
|
||||
- ConfigMap and Secrets are key-value maps
|
||||
|
||||
(a Secret can contain zero, one, or many key-value pairs)
|
||||
|
||||
- They can both be exposed with the downward API or volumes
|
||||
|
||||
- They can both be created with YAML or with a CLI command
|
||||
|
||||
(`kubectl create configmap` / `kubectl create secret`)
|
||||
|
||||
---
|
||||
|
||||
## ConfigMap and Secrets are different resources
|
||||
|
||||
- They can have different RBAC permissions
|
||||
|
||||
(e.g. the default `view` role can read ConfigMaps but not Secrets)
|
||||
|
||||
- They indicate a different *intent*:
|
||||
|
||||
*"You should use secrets for things which are actually secret like API keys,
|
||||
credentials, etc., and use config map for not-secret configuration data."*
|
||||
|
||||
*"In the future there will likely be some differentiators for secrets like rotation or support for backing the secret API w/ HSMs, etc."*
|
||||
|
||||
(Source: [the author of both features](https://stackoverflow.com/a/36925553/580281
|
||||
))
|
||||
|
||||
---
|
||||
|
||||
## Secrets have an optional *type*
|
||||
|
||||
- The type indicates which keys must exist in the secrets, for instance:
|
||||
|
||||
`kubernetes.io/tls` requires `tls.crt` and `tls.key`
|
||||
|
||||
`kubernetes.io/basic-auth` requires `username` and `password`
|
||||
|
||||
`kubernetes.io/ssh-auth` requires `ssh-privatekey`
|
||||
|
||||
`kubernetes.io/dockerconfigjson` requires `.dockerconfigjson`
|
||||
|
||||
`kubernetes.io/service-account-token` requires `token`, `namespace`, `ca.crt`
|
||||
|
||||
(the whole list is in [the documentation](https://kubernetes.io/docs/concepts/configuration/secret/#secret-types))
|
||||
|
||||
- This is merely for our (human) convenience:
|
||||
|
||||
“Ah yes, this secret is a ...”
|
||||
|
||||
---
|
||||
|
||||
## Accessing private repositories
|
||||
|
||||
- Let's see how to access an image on private registry!
|
||||
|
||||
- These images are protected by a username + password
|
||||
|
||||
(on some registries, it's token + password, but it's the same thing)
|
||||
|
||||
- To access a private image, we need to:
|
||||
|
||||
- create a secret
|
||||
|
||||
- reference that secret in a Pod template
|
||||
|
||||
- or reference that secret in a ServiceAccount used by a Pod
|
||||
|
||||
---
|
||||
|
||||
## In practice
|
||||
|
||||
- Let's try to access an image on a private registry!
|
||||
|
||||
- image = docker-registry.enix.io/jpetazzo/private:latest
|
||||
- user = reader
|
||||
- password = VmQvqdtXFwXfyy4Jb5DR
|
||||
|
||||
.exercise[
|
||||
|
||||
- Create a Deployment using that image:
|
||||
```bash
|
||||
kubectl create deployment priv \
|
||||
--image=docker-registry.enix.io/jpetazzo/private
|
||||
```
|
||||
|
||||
- Check that the Pod won't start:
|
||||
```bash
|
||||
kubectl get pods --selector=app=priv
|
||||
```
|
||||
|
||||
]
|
||||
|
||||
---
|
||||
|
||||
## Creating a secret
|
||||
|
||||
- Let's create a secret with the information provided earlier
|
||||
|
||||
.exercise[
|
||||
|
||||
- Create the registry secret:
|
||||
```bash
|
||||
kubectl create secret docker-registry enix \
|
||||
--docker-server=docker-registry.enix.io \
|
||||
--docker-username=reader \
|
||||
--docker-password=VmQvqdtXFwXfyy4Jb5DR
|
||||
```
|
||||
|
||||
]
|
||||
|
||||
Why do we have to specify the registry address?
|
||||
|
||||
If we use multiple sets of credentials for different registries, it prevents leaking the credentials of one registry to *another* registry.
|
||||
|
||||
---
|
||||
|
||||
## Using the secret
|
||||
|
||||
- The first way to use a secret is to add it to `imagePullSecrets`
|
||||
|
||||
(in the `spec` section of a Pod template)
|
||||
|
||||
.exercise[
|
||||
|
||||
- Patch the `priv` Deployment that we created earlier:
|
||||
```bash
|
||||
kubectl patch deploy priv --patch='
|
||||
spec:
|
||||
template:
|
||||
spec:
|
||||
imagePullSecrets:
|
||||
- name: enix
|
||||
'
|
||||
```
|
||||
|
||||
]
|
||||
|
||||
---
|
||||
|
||||
## Checking the results
|
||||
|
||||
.exercise[
|
||||
|
||||
- Confirm that our Pod can now start correctly:
|
||||
```bash
|
||||
kubectl get pods --selector=app=priv
|
||||
```
|
||||
|
||||
]
|
||||
|
||||
---
|
||||
|
||||
## Another way to use the secret
|
||||
|
||||
- We can add the secret to the ServiceAccount
|
||||
|
||||
- This is convenient to automatically use credentials for *all* pods
|
||||
|
||||
(as long as they're using a specific ServiceAccount, of course)
|
||||
|
||||
.exercise[
|
||||
|
||||
- Add the secret to the ServiceAccount:
|
||||
```bash
|
||||
kubectl patch serviceaccount default --patch='
|
||||
imagePullSecrets:
|
||||
- name: enix
|
||||
'
|
||||
```
|
||||
|
||||
]
|
||||
|
||||
---
|
||||
|
||||
## Secrets are displayed with base64 encoding
|
||||
|
||||
- When shown with e.g. `kubectl get secrets -o yaml`, secrets are base64-encoded
|
||||
|
||||
- Likewise, when defining it with YAML, `data` values are base64-encoded
|
||||
|
||||
- Example:
|
||||
```yaml
|
||||
kind: Secret
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: pin-codes
|
||||
data:
|
||||
onetwothreefour: MTIzNA==
|
||||
zerozerozerozero: MDAwMA==
|
||||
```
|
||||
|
||||
- Keep in mind that this is just *encoding*, not *encryption*
|
||||
|
||||
- It is very easy to [automatically extract and decode secrets](https://medium.com/@mveritym/decoding-kubernetes-secrets-60deed7a96a3)
|
||||
|
||||
---
|
||||
|
||||
class: extra-details
|
||||
|
||||
## Using `stringData`
|
||||
|
||||
- When creating a Secret, it is possible to bypass base64
|
||||
|
||||
- Just use `stringData` instead of `data`:
|
||||
```yaml
|
||||
kind: Secret
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: pin-codes
|
||||
stringData:
|
||||
onetwothreefour: 1234
|
||||
zerozerozerozero: 0000
|
||||
```
|
||||
|
||||
- It will show up as base64 if you `kubectl get -o yaml`
|
||||
|
||||
- No `type` was specified, so it defaults to `Opaque`
|
||||
|
||||
---
|
||||
|
||||
class: extra-details
|
||||
|
||||
## Encryption at rest
|
||||
|
||||
- It is possible to [encrypted secrets at rest](https://kubernetes.io/docs/tasks/administer-cluster/encrypt-data/)
|
||||
|
||||
- This means that secrets will be safe if someone ...
|
||||
|
||||
- steals our etcd servers
|
||||
|
||||
- steals our backups
|
||||
|
||||
- snoops the e.g. iSCSI link between our etcd servers and SAN
|
||||
|
||||
- However, starting the API server will now require human intervention
|
||||
|
||||
(to provide the decryption keys)
|
||||
|
||||
- This is only for extremely regulated environments (military, nation states...)
|
||||
|
||||
---
|
||||
|
||||
class: extra-details
|
||||
|
||||
## Immutable ConfigMaps and Secrets
|
||||
|
||||
- Since Kubernetes 1.19, it is possible to mark a ConfigMap or Secret as *immutable*
|
||||
|
||||
```bash
|
||||
kubectl patch configmap xyz --patch='{"immutable": true}'
|
||||
```
|
||||
|
||||
- This brings performance improvements when using lots of ConfigMaps and Secrets
|
||||
|
||||
(lots = tens of thousands)
|
||||
|
||||
- Once a ConfigMap or Secret has been marked as immutable:
|
||||
|
||||
- its content cannot be changed anymore
|
||||
- the `immutable` field can't be changed back either
|
||||
- the only way to change it is to delete and re-create it
|
||||
- Pods using it will have to be re-created as well
|
||||
|
||||
???
|
||||
|
||||
:EN:- Handling passwords and tokens safely
|
||||
|
||||
:FR:- Manipulation de mots de passe, clés API etc.
|
||||
@@ -63,7 +63,6 @@
|
||||
```bash
|
||||
k3d cluster create groscluster \
|
||||
--image rancher/k3s:v1.18.9-k3s1 --servers 3 --agents 5
|
||||
```
|
||||
|
||||
(3 nodes for the control plane + 5 worker nodes)
|
||||
|
||||
|
||||
@@ -94,20 +94,28 @@
|
||||
|
||||
## Building on the fly
|
||||
|
||||
- Conceptually, it is possible to build images on the fly from a repository
|
||||
- Some services can build images on the fly from a repository
|
||||
|
||||
- Example: [ctr.run](https://ctr.run/)
|
||||
|
||||
(deprecated in August 2020, after being aquired by Datadog)
|
||||
.exercise[
|
||||
|
||||
- It did allow something like this:
|
||||
- Use ctr.run to automatically build a container image and run it:
|
||||
```bash
|
||||
docker run ctr.run/github.com/jpetazzo/container.training/dockercoins/hasher
|
||||
```
|
||||
|
||||
- No alternative yet
|
||||
<!--
|
||||
```longwait Sinatra```
|
||||
```key ^C```
|
||||
-->
|
||||
|
||||
(free startup idea, anyone?)
|
||||
]
|
||||
|
||||
There might be a long pause before the first layer is pulled,
|
||||
because the API behind `docker pull` doesn't allow to stream build logs, and there is no feedback during the build.
|
||||
|
||||
It is possible to view the build logs by setting up an account on [ctr.run](https://ctr.run/).
|
||||
|
||||
???
|
||||
|
||||
|
||||
@@ -1,302 +0,0 @@
|
||||
# Tilt
|
||||
|
||||
- What does a development workflow look like?
|
||||
|
||||
- make changes
|
||||
|
||||
- test / see these changes
|
||||
|
||||
- repeat!
|
||||
|
||||
- What does it look like, with containers?
|
||||
|
||||
🤔
|
||||
|
||||
---
|
||||
|
||||
## Basic Docker workflow
|
||||
|
||||
- Preparation
|
||||
|
||||
- write Dockerfiles
|
||||
|
||||
- Iteration
|
||||
|
||||
- edit code
|
||||
- `docker build`
|
||||
- `docker run`
|
||||
- test
|
||||
- `docker stop`
|
||||
|
||||
Straightforward when we have a single container.
|
||||
|
||||
---
|
||||
|
||||
## Docker workflow with volumes
|
||||
|
||||
- Preparation
|
||||
|
||||
- write Dockerfiles
|
||||
- `docker build` + `docker run`
|
||||
|
||||
- Iteration
|
||||
|
||||
- edit code
|
||||
- test
|
||||
|
||||
Note: only works with interpreted languages.
|
||||
<br/>
|
||||
(Compiled languages require extra work.)
|
||||
|
||||
---
|
||||
|
||||
## Docker workflow with Compose
|
||||
|
||||
- Preparation
|
||||
|
||||
- write Dockerfiles + Compose file
|
||||
- `docker-compose up`
|
||||
|
||||
- Iteration
|
||||
|
||||
- edit code
|
||||
- test
|
||||
- `docker-compose up` (as needed)
|
||||
|
||||
Simplifies complex scenarios (multiple containers).
|
||||
<br/>
|
||||
Facilitates updating images.
|
||||
|
||||
---
|
||||
|
||||
## Basic Kubernetes workflow
|
||||
|
||||
- Preparation
|
||||
|
||||
- write Dockerfiles
|
||||
- write Kubernetes YAML
|
||||
- set up container registry
|
||||
|
||||
- Iteration
|
||||
|
||||
- edit code
|
||||
- build images
|
||||
- push images
|
||||
- update Kubernetes resources
|
||||
|
||||
Seems simple enough, right?
|
||||
|
||||
---
|
||||
|
||||
## Basic Kubernetes workflow
|
||||
|
||||
- Preparation
|
||||
|
||||
- write Dockerfiles
|
||||
- write Kubernetes YAML
|
||||
- **set up container registry**
|
||||
|
||||
- Iteration
|
||||
|
||||
- edit code
|
||||
- build images
|
||||
- **push images**
|
||||
- update Kubernetes resources
|
||||
|
||||
Ah, right ...
|
||||
|
||||
---
|
||||
|
||||
## We need a registry
|
||||
|
||||
- Remember "build, ship, and run"
|
||||
|
||||
- Registries are involved in the "ship" phase
|
||||
|
||||
- With Docker, we were building and running on the same node
|
||||
|
||||
- We didn't need a registry!
|
||||
|
||||
- With Kubernetes, though ...
|
||||
|
||||
---
|
||||
|
||||
## Special case of single node clusters
|
||||
|
||||
- If our Kubernetes has only one node ...
|
||||
|
||||
- ... We can build directly on that node ...
|
||||
|
||||
- ... We don't need to push images ...
|
||||
|
||||
- ... We don't need to run a registry!
|
||||
|
||||
- Examples: Docker Desktop, Minikube ...
|
||||
|
||||
---
|
||||
|
||||
## When we have more than one node
|
||||
|
||||
- Which registry should we use?
|
||||
|
||||
(Docker Hub, Quay, cloud-based, self-hosted ...)
|
||||
|
||||
- Should we use a single registry, or one per cluster or environment?
|
||||
|
||||
- Which tags and credentials should we use?
|
||||
|
||||
(in particular when using a shared registry!)
|
||||
|
||||
- How do we provision that registry and its users?
|
||||
|
||||
- How do we adjust our Kubernetes YAML manifests?
|
||||
|
||||
(e.g. to inject image names and tags)
|
||||
|
||||
---
|
||||
|
||||
## More questions
|
||||
|
||||
- The whole cycle (build+push+update) is expensive
|
||||
|
||||
- If we have many services, how do we update only the ones we need?
|
||||
|
||||
- Can we take shortcuts?
|
||||
|
||||
(e.g. synchronized files without going through a whole build+push+update cycle)
|
||||
|
||||
---
|
||||
|
||||
## Tilt
|
||||
|
||||
- Tilt is a tool to address all these questions
|
||||
|
||||
- There are other similar tools (e.g. Skaffold)
|
||||
|
||||
- We arbitrarily decided to focus on that one
|
||||
|
||||
---
|
||||
|
||||
## Tilt in practice
|
||||
|
||||
- The `dockercoins` directory in our repository has a `Tiltfile`
|
||||
|
||||
- Go to that directory and try `tilt up`
|
||||
|
||||
- Tilt should refuse to start, but it will explain why
|
||||
|
||||
- Edit the `Tiltfile` accordingly and try again
|
||||
|
||||
- Open the Tilt web UI
|
||||
|
||||
(if running Tilt on a remote machine, you will need `tilt up --host 0.0.0.0`)
|
||||
|
||||
- Watch as the Dockercoins app is built, pushed, started
|
||||
|
||||
---
|
||||
|
||||
## What's in our Tiltfile?
|
||||
|
||||
- Kubernetes manifests for a local registry
|
||||
|
||||
- Kubernetes manifests for DockerCoins
|
||||
|
||||
- Instructions indicating how to build DockerCoins' images
|
||||
|
||||
- A tiny bit of sugar
|
||||
|
||||
(telling Tilt which registry to use)
|
||||
|
||||
---
|
||||
|
||||
|
||||
## How does it work?
|
||||
|
||||
- Tilt keeps track of dependencies between files and resources
|
||||
|
||||
(a bit like a `make` that would run continuously)
|
||||
|
||||
- It automatically alters some resources
|
||||
|
||||
(for instance, it updates the images used in our Kubernetes manifests)
|
||||
|
||||
- That's it!
|
||||
|
||||
(And of course, it provides a great web UI, lots of libraries, etc.)
|
||||
|
||||
---
|
||||
|
||||
## What happens when we edit a file (1/2)
|
||||
|
||||
- Let's change e.g. `worker/worker.py`
|
||||
|
||||
- Thanks to this line,
|
||||
```python
|
||||
docker_build('dockercoins/worker', 'worker')
|
||||
```
|
||||
... Tilt watches the `worker` directory and uses it to build `dockercoins/worker`
|
||||
|
||||
- Thanks to this line,
|
||||
```python
|
||||
default_registry('localhost:30555')
|
||||
```
|
||||
... Tilt actually renames `dockercoins/worker` to `localhost:30555/dockercoins_worker`
|
||||
|
||||
- Tilt will tag the image with something like `tilt-xxxxxxxxxx`
|
||||
|
||||
---
|
||||
|
||||
## What happens when we edit a file (2/2)
|
||||
|
||||
- Thanks to this line,
|
||||
```python
|
||||
k8s_yaml('../k8s/dockercoins.yaml')
|
||||
```
|
||||
... Tilt is aware of our Kubernetes resources
|
||||
|
||||
- The `worker` Deployment uses `dockercoins/worker`, so it must be updated
|
||||
|
||||
- `dockercoins/worker` becomes `localhost:30555/dockercoins_worker:tilt-xxx`
|
||||
|
||||
- The `worker` Deployment gets updated on the Kubernetes cluster
|
||||
|
||||
- All these operations (and their log output) are visible in the Tilt UI
|
||||
|
||||
---
|
||||
|
||||
## Configuration file format
|
||||
|
||||
- The Tiltfile is written in [Starlark](https://github.com/bazelbuild/starlark)
|
||||
|
||||
(essentially a subset of Python)
|
||||
|
||||
- Tilt monitors the Tiltfile too
|
||||
|
||||
(so it reloads it immediately when we change it)
|
||||
|
||||
---
|
||||
|
||||
## Tilt "killer features"
|
||||
|
||||
- Dependency engine
|
||||
|
||||
(build or run only what's necessary)
|
||||
|
||||
- Ability to watch resources
|
||||
|
||||
(execute actions immediately, without explicitly running a command)
|
||||
|
||||
- Rich library of function and helpers
|
||||
|
||||
(build container images, manipulate YAML manifests...)
|
||||
|
||||
- Convenient UI (web; TUI also available)
|
||||
|
||||
(provides immediate feedback and logs)
|
||||
|
||||
- Extensibility!
|
||||
|
||||
???
|
||||
|
||||
:EN:- Development workflow with Tilt
|
||||
:FR:- Développer avec Tilt
|
||||
@@ -1,60 +0,0 @@
|
||||
title: |
|
||||
Kubernetes
|
||||
for Admins and Ops
|
||||
|
||||
#chat: "[Slack](https://dockercommunity.slack.com/messages/C7GKACWDV)"
|
||||
#chat: "[Gitter](https://gitter.im/jpetazzo/workshop-yyyymmdd-city)"
|
||||
chat: "In person!"
|
||||
|
||||
gitrepo: github.com/jpetazzo/container.training
|
||||
|
||||
slides: http://container.training/
|
||||
|
||||
#slidenumberprefix: "#SomeHashTag — "
|
||||
|
||||
exclude:
|
||||
- self-paced
|
||||
- static-pods-exercise
|
||||
|
||||
content:
|
||||
- shared/title.md
|
||||
- logistics.md
|
||||
- k8s/intro.md
|
||||
- shared/about-slides.md
|
||||
- shared/chat-room-im.md
|
||||
#- shared/chat-room-slack.md
|
||||
#- shared/chat-room-zoom-meeting.md
|
||||
#- shared/chat-room-zoom-webinar.md
|
||||
- shared/toc.md
|
||||
-
|
||||
- k8s/prereqs-admin.md
|
||||
- k8s/architecture.md
|
||||
#- k8s/internal-apis.md
|
||||
- k8s/deploymentslideshow.md
|
||||
- k8s/dmuc.md
|
||||
-
|
||||
- k8s/multinode.md
|
||||
- k8s/cni.md
|
||||
- k8s/cni-internals.md
|
||||
- k8s/interco.md
|
||||
-
|
||||
- k8s/apilb.md
|
||||
#- k8s/setup-overview.md
|
||||
#- k8s/setup-devel.md
|
||||
#- k8s/setup-managed.md
|
||||
#- k8s/setup-selfhosted.md
|
||||
- k8s/cluster-upgrade.md
|
||||
- k8s/cluster-backup.md
|
||||
- k8s/staticpods.md
|
||||
-
|
||||
#- k8s/cloud-controller-manager.md
|
||||
#- k8s/bootstrap.md
|
||||
- k8s/control-plane-auth.md
|
||||
- k8s/podsecuritypolicy.md
|
||||
- k8s/user-cert.md
|
||||
- k8s/csr-api.md
|
||||
- k8s/openid-connect.md
|
||||
-
|
||||
#- k8s/lastwords-admin.md
|
||||
- k8s/links.md
|
||||
- shared/thankyou.md
|
||||
@@ -1,84 +0,0 @@
|
||||
title: |
|
||||
Kubernetes
|
||||
for administrators
|
||||
and operators
|
||||
|
||||
#chat: "[Slack](https://dockercommunity.slack.com/messages/C7GKACWDV)"
|
||||
#chat: "[Gitter](https://gitter.im/jpetazzo/workshop-yyyymmdd-city)"
|
||||
chat: "In person!"
|
||||
|
||||
gitrepo: github.com/jpetazzo/container.training
|
||||
|
||||
slides: http://container.training/
|
||||
|
||||
#slidenumberprefix: "#SomeHashTag — "
|
||||
|
||||
exclude:
|
||||
- self-paced
|
||||
|
||||
content:
|
||||
- shared/title.md
|
||||
- logistics.md
|
||||
- k8s/intro.md
|
||||
- shared/about-slides.md
|
||||
- shared/chat-room-im.md
|
||||
#- shared/chat-room-slack.md
|
||||
#- shared/chat-room-zoom-meeting.md
|
||||
#- shared/chat-room-zoom-webinar.md
|
||||
- shared/toc.md
|
||||
# DAY 1
|
||||
- - k8s/prereqs-admin.md
|
||||
- k8s/architecture.md
|
||||
- k8s/internal-apis.md
|
||||
- k8s/deploymentslideshow.md
|
||||
- k8s/dmuc.md
|
||||
- - k8s/multinode.md
|
||||
- k8s/cni.md
|
||||
- k8s/cni-internals.md
|
||||
- k8s/interco.md
|
||||
- - k8s/apilb.md
|
||||
- k8s/setup-overview.md
|
||||
#- k8s/setup-devel.md
|
||||
- k8s/setup-managed.md
|
||||
- k8s/setup-selfhosted.md
|
||||
- k8s/cluster-upgrade.md
|
||||
- k8s/staticpods.md
|
||||
- - k8s/cluster-backup.md
|
||||
- k8s/cloud-controller-manager.md
|
||||
- k8s/healthchecks.md
|
||||
- k8s/healthchecks-more.md
|
||||
# DAY 2
|
||||
- - k8s/kubercoins.md
|
||||
- k8s/logs-cli.md
|
||||
- k8s/logs-centralized.md
|
||||
- k8s/authn-authz.md
|
||||
- k8s/user-cert.md
|
||||
- k8s/csr-api.md
|
||||
- - k8s/openid-connect.md
|
||||
- k8s/control-plane-auth.md
|
||||
###- k8s/bootstrap.md
|
||||
- k8s/netpol.md
|
||||
- k8s/podsecuritypolicy.md
|
||||
- - k8s/resource-limits.md
|
||||
- k8s/metrics-server.md
|
||||
- k8s/cluster-sizing.md
|
||||
- k8s/horizontal-pod-autoscaler.md
|
||||
- - k8s/prometheus.md
|
||||
- k8s/extending-api.md
|
||||
- k8s/crd.md
|
||||
- k8s/operators.md
|
||||
- k8s/eck.md
|
||||
###- k8s/operators-design.md
|
||||
# CONCLUSION
|
||||
- - k8s/lastwords.md
|
||||
- k8s/links.md
|
||||
- shared/thankyou.md
|
||||
- |
|
||||
# (All content after this slide is bonus material)
|
||||
# EXTRA
|
||||
- - k8s/volumes.md
|
||||
- k8s/configuration.md
|
||||
- k8s/secrets.md
|
||||
- k8s/statefulsets.md
|
||||
- k8s/local-persistent-volumes.md
|
||||
- k8s/portworx.md
|
||||
@@ -2,12 +2,12 @@ title: |
|
||||
Advanced
|
||||
Kubernetes
|
||||
|
||||
chat: "[Slack](https://dockercommunity.slack.com/messages/C7GKACWDV)"
|
||||
chat: "`#kubernetes-training-november-30-december-4`"
|
||||
#chat: "[Gitter](https://gitter.im/jpetazzo/workshop-yyyymmdd-city)"
|
||||
|
||||
gitrepo: github.com/jpetazzo/container.training
|
||||
|
||||
slides: https://container.training/
|
||||
slides: https://2020-11-nr.container.training/
|
||||
|
||||
#slidenumberprefix: "#SomeHashTag — "
|
||||
|
||||
@@ -20,14 +20,12 @@ content:
|
||||
- k8s/intro.md
|
||||
- shared/about-slides.md
|
||||
#- shared/chat-room-im.md
|
||||
#- shared/chat-room-slack.md
|
||||
#- shared/chat-room-zoom-meeting.md
|
||||
#- shared/chat-room-zoom-webinar.md
|
||||
- shared/toc.md
|
||||
- #1
|
||||
- k8s/prereqs-admin.md
|
||||
- k8s/architecture.md
|
||||
- k8s/internal-apis.md
|
||||
- k8s/deploymentslideshow.md
|
||||
- k8s/dmuc.md
|
||||
- #2
|
||||
|
||||
@@ -21,7 +21,6 @@ content:
|
||||
- k8s/intro.md
|
||||
- shared/about-slides.md
|
||||
- shared/chat-room-im.md
|
||||
#- shared/chat-room-slack.md
|
||||
#- shared/chat-room-zoom-meeting.md
|
||||
#- shared/chat-room-zoom-webinar.md
|
||||
- shared/toc.md
|
||||
@@ -59,16 +58,13 @@ content:
|
||||
#- k8s/setup-managed.md
|
||||
#- k8s/setup-selfhosted.md
|
||||
#- k8s/dashboard.md
|
||||
#- k8s/k9s.md
|
||||
#- k8s/tilt.md
|
||||
#- k8s/kubectlscale.md
|
||||
- k8s/scalingdockercoins.md
|
||||
- shared/hastyconclusions.md
|
||||
- k8s/daemonset.md
|
||||
#- k8s/authoring-yaml.md
|
||||
#- k8s/dryrun.md
|
||||
#- k8s/exercise-yaml.md
|
||||
#- k8s/localkubeconfig.md
|
||||
#- k8s/access-eks-cluster.md
|
||||
#- k8s/accessinternal.md
|
||||
#- k8s/kubectlproxy.md
|
||||
- k8s/rollout.md
|
||||
@@ -86,7 +82,6 @@ content:
|
||||
#- k8s/helm-create-better-chart.md
|
||||
#- k8s/helm-secrets.md
|
||||
#- k8s/exercise-helm.md
|
||||
#- k8s/gitlab.md
|
||||
#- k8s/create-chart.md
|
||||
#- k8s/create-more-charts.md
|
||||
#- k8s/netpol.md
|
||||
@@ -100,7 +95,6 @@ content:
|
||||
#- k8s/build-with-docker.md
|
||||
#- k8s/build-with-kaniko.md
|
||||
- k8s/configuration.md
|
||||
- k8s/secrets.md
|
||||
#- k8s/logs-centralized.md
|
||||
#- k8s/prometheus.md
|
||||
#- k8s/statefulsets.md
|
||||
|
||||
@@ -23,7 +23,6 @@ content:
|
||||
- k8s/intro.md
|
||||
- shared/about-slides.md
|
||||
- shared/chat-room-im.md
|
||||
#- shared/chat-room-slack.md
|
||||
#- shared/chat-room-zoom-meeting.md
|
||||
#- shared/chat-room-zoom-webinar.md
|
||||
- shared/toc.md
|
||||
@@ -56,12 +55,9 @@ content:
|
||||
- k8s/buildshiprun-dockerhub.md
|
||||
- k8s/ourapponkube.md
|
||||
#- k8s/localkubeconfig.md
|
||||
#- k8s/access-eks-cluster.md
|
||||
#- k8s/accessinternal.md
|
||||
#- k8s/kubectlproxy.md
|
||||
- - k8s/dashboard.md
|
||||
#- k8s/k9s.md
|
||||
#- k8s/tilt.md
|
||||
#- k8s/kubectlscale.md
|
||||
- k8s/scalingdockercoins.md
|
||||
- shared/hastyconclusions.md
|
||||
|
||||
@@ -21,7 +21,6 @@ content:
|
||||
- k8s/intro.md
|
||||
- shared/about-slides.md
|
||||
#- shared/chat-room-im.md
|
||||
#- shared/chat-room-slack.md
|
||||
#- shared/chat-room-zoom-meeting.md
|
||||
#- shared/chat-room-zoom-webinar.md
|
||||
- shared/toc.md
|
||||
@@ -60,13 +59,11 @@ content:
|
||||
- k8s/setup-managed.md
|
||||
- k8s/setup-selfhosted.md
|
||||
- k8s/dashboard.md
|
||||
- k8s/k9s.md
|
||||
- k8s/tilt.md
|
||||
#- k8s/kubectlscale.md
|
||||
- k8s/scalingdockercoins.md
|
||||
- shared/hastyconclusions.md
|
||||
- k8s/daemonset.md
|
||||
- k8s/authoring-yaml.md
|
||||
- k8s/dryrun.md
|
||||
#- k8s/exercise-yaml.md
|
||||
-
|
||||
- k8s/rollout.md
|
||||
@@ -76,7 +73,6 @@ content:
|
||||
-
|
||||
- k8s/namespaces.md
|
||||
- k8s/localkubeconfig.md
|
||||
#- k8s/access-eks-cluster.md
|
||||
- k8s/accessinternal.md
|
||||
- k8s/kubectlproxy.md
|
||||
-
|
||||
@@ -90,7 +86,6 @@ content:
|
||||
- k8s/helm-create-better-chart.md
|
||||
- k8s/helm-secrets.md
|
||||
#- k8s/exercise-helm.md
|
||||
- k8s/gitlab.md
|
||||
-
|
||||
- k8s/netpol.md
|
||||
- k8s/authn-authz.md
|
||||
@@ -106,7 +101,6 @@ content:
|
||||
- k8s/build-with-kaniko.md
|
||||
-
|
||||
- k8s/configuration.md
|
||||
- k8s/secrets.md
|
||||
- k8s/statefulsets.md
|
||||
- k8s/local-persistent-volumes.md
|
||||
- k8s/portworx.md
|
||||
|
||||
@@ -21,7 +21,6 @@ content:
|
||||
- k8s/intro.md
|
||||
- shared/about-slides.md
|
||||
- shared/chat-room-im.md
|
||||
#- shared/chat-room-slack.md
|
||||
#- shared/chat-room-zoom-meeting.md
|
||||
#- shared/chat-room-zoom-webinar.md
|
||||
- shared/toc.md
|
||||
@@ -59,17 +58,14 @@ content:
|
||||
#- k8s/setup-managed.md
|
||||
#- k8s/setup-selfhosted.md
|
||||
- k8s/dashboard.md
|
||||
- k8s/k9s.md
|
||||
#- k8s/tilt.md
|
||||
#- k8s/kubectlscale.md
|
||||
- k8s/scalingdockercoins.md
|
||||
- shared/hastyconclusions.md
|
||||
- k8s/daemonset.md
|
||||
- k8s/authoring-yaml.md
|
||||
- k8s/dryrun.md
|
||||
#- k8s/exercise-yaml.md
|
||||
-
|
||||
- k8s/localkubeconfig.md
|
||||
#- k8s/access-eks-cluster.md
|
||||
- k8s/accessinternal.md
|
||||
#- k8s/kubectlproxy.md
|
||||
- k8s/rollout.md
|
||||
@@ -87,7 +83,6 @@ content:
|
||||
- k8s/helm-create-better-chart.md
|
||||
- k8s/helm-secrets.md
|
||||
#- k8s/exercise-helm.md
|
||||
- k8s/gitlab.md
|
||||
-
|
||||
- k8s/netpol.md
|
||||
- k8s/authn-authz.md
|
||||
@@ -100,7 +95,6 @@ content:
|
||||
#- k8s/build-with-docker.md
|
||||
#- k8s/build-with-kaniko.md
|
||||
- k8s/configuration.md
|
||||
- k8s/secrets.md
|
||||
- k8s/logs-centralized.md
|
||||
- k8s/prometheus.md
|
||||
-
|
||||
|
||||
@@ -1,35 +1,59 @@
|
||||
## Intros
|
||||
## Intros & disclaimers
|
||||
|
||||
- This slide should be customized by the tutorial instructor(s).
|
||||
- Hello! I'm Jérôme Petazzoni ([@jpetazzo](https://twitter.com/jpetazzo))
|
||||
|
||||
- Hello! We are:
|
||||
- I have ...
|
||||
|
||||
- .emoji[👩🏻🏫] Ann O'Nymous ([@...](https://twitter.com/...), Megacorp Inc)
|
||||
- extensive experience running *containers* in production
|
||||
- limited experience running *Kubernetes* in production
|
||||
|
||||
- .emoji[👨🏾🎓] Stu Dent ([@...](https://twitter.com/...), University of Wakanda)
|
||||
- taught Docker and Kubernetes many times, to large audiences
|
||||
- less frequently taught operators and API internals
|
||||
|
||||
<!-- .dummy[
|
||||
- written a lot of Python code during my career; but much less Go
|
||||
|
||||
- .emoji[👷🏻♀️] AJ ([@s0ulshake](https://twitter.com/s0ulshake), Travis CI)
|
||||
- learned way more than I expected just by writing some chapters of this course (!)
|
||||
|
||||
- .emoji[🚁] Alexandre ([@alexbuisine](https://twitter.com/alexbuisine), Enix SAS)
|
||||
---
|
||||
|
||||
- .emoji[🐳] Jérôme ([@jpetazzo](https://twitter.com/jpetazzo), Enix SAS)
|
||||
## Logistics
|
||||
|
||||
- .emoji[⛵] Jérémy ([@jeremygarrouste](twitter.com/jeremygarrouste), Inpiwee)
|
||||
- The training will from 8am to noon PST, Monday to Friday
|
||||
|
||||
- .emoji[🎧] Romain ([@rdegez](https://twitter.com/rdegez), Enix SAS)
|
||||
|
||||
] -->
|
||||
|
||||
- The workshop will run from ...
|
||||
|
||||
- There will be a lunch break at ...
|
||||
|
||||
(And coffee breaks!)
|
||||
- There will be short breaks every hour, and a longer break in the middle
|
||||
|
||||
- Feel free to interrupt for questions at any time
|
||||
|
||||
- *Especially when you see full screen container pictures!*
|
||||
|
||||
(I will watch them in silence while I wait for your questions)
|
||||
|
||||
- Live feedback, questions, help: @@CHAT@@
|
||||
|
||||
---
|
||||
|
||||
## Course structure
|
||||
|
||||
Three axis:
|
||||
|
||||
1. Fundamental concepts, "under the hood" components
|
||||
|
||||
(think: data structures, algorithms, assembly language ...)
|
||||
|
||||
2. Analyzing state-of-the-art implementations
|
||||
|
||||
(think: design patterns ...)
|
||||
|
||||
3. High-level abstractions, highly effective frameworks
|
||||
|
||||
(think: Django, Ruby ...)
|
||||
|
||||
---
|
||||
|
||||
## The power of repetition ...
|
||||
|
||||
- You will notice some repetition in the beginning of some chapters
|
||||
|
||||
- This is to let you review some chapters in isolation, just in case
|
||||
|
||||
- Also, supposedly, repetition yields better learning results? 🤷🏻
|
||||
|
||||
@@ -213,7 +213,6 @@ def processcontent(content, filename):
|
||||
return (content, titles)
|
||||
if os.path.isfile(content):
|
||||
return processcontent(open(content).read(), content)
|
||||
logging.warning("Content spans only one line (it's probably a file name) but no file found: {}".format(content))
|
||||
if isinstance(content, list):
|
||||
subparts = [processcontent(c, filename) for c in content]
|
||||
markdown = "\n---\n".join(c[0] for c in subparts)
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
## Chat room
|
||||
|
||||
- A Slack room has been set up for the duration of the training
|
||||
|
||||
- We'll use it to ask questions, get help, share feedback ...
|
||||
|
||||
(let's keep an eye on it during the training!)
|
||||
|
||||
- Reminder, the room is @@CHAT@@
|
||||
|
||||
- Say hi in the chat room!
|
||||
|
||||
@@ -1,71 +0,0 @@
|
||||
title: |
|
||||
Container Orchestration
|
||||
with Docker and Swarm
|
||||
|
||||
chat: "[Slack](https://dockercommunity.slack.com/messages/C7GKACWDV)"
|
||||
#chat: "[Gitter](https://gitter.im/jpetazzo/workshop-yyyymmdd-city)"
|
||||
|
||||
gitrepo: github.com/jpetazzo/container.training
|
||||
|
||||
slides: http://container.training/
|
||||
|
||||
#slidenumberprefix: "#SomeHashTag — "
|
||||
|
||||
exclude:
|
||||
- self-paced
|
||||
- snap
|
||||
- btp-auto
|
||||
- benchmarking
|
||||
- elk-manual
|
||||
- prom-manual
|
||||
|
||||
content:
|
||||
- shared/title.md
|
||||
- logistics.md
|
||||
- swarm/intro.md
|
||||
- shared/about-slides.md
|
||||
- shared/chat-room-im.md
|
||||
#- shared/chat-room-slack.md
|
||||
#- shared/chat-room-zoom-meeting.md
|
||||
#- shared/chat-room-zoom-webinar.md
|
||||
- shared/toc.md
|
||||
- - shared/prereqs.md
|
||||
- shared/connecting.md
|
||||
- swarm/versions.md
|
||||
- shared/sampleapp.md
|
||||
- shared/composescale.md
|
||||
- shared/hastyconclusions.md
|
||||
- shared/composedown.md
|
||||
- swarm/swarmkit.md
|
||||
- shared/declarative.md
|
||||
- swarm/swarmmode.md
|
||||
- swarm/creatingswarm.md
|
||||
#- swarm/machine.md
|
||||
- swarm/morenodes.md
|
||||
- - swarm/firstservice.md
|
||||
- swarm/ourapponswarm.md
|
||||
- swarm/hostingregistry.md
|
||||
- swarm/testingregistry.md
|
||||
- swarm/btp-manual.md
|
||||
- swarm/swarmready.md
|
||||
- swarm/stacks.md
|
||||
- swarm/cicd.md
|
||||
- swarm/updatingservices.md
|
||||
- swarm/rollingupdates.md
|
||||
- swarm/healthchecks.md
|
||||
- - swarm/operatingswarm.md
|
||||
- swarm/netshoot.md
|
||||
- swarm/ipsec.md
|
||||
- swarm/swarmtools.md
|
||||
- swarm/security.md
|
||||
- swarm/secrets.md
|
||||
- swarm/encryptionatrest.md
|
||||
- swarm/leastprivilege.md
|
||||
- swarm/apiscope.md
|
||||
- - swarm/logging.md
|
||||
- swarm/metrics.md
|
||||
- swarm/gui.md
|
||||
- swarm/stateful.md
|
||||
- swarm/extratips.md
|
||||
- shared/thankyou.md
|
||||
- swarm/links.md
|
||||
@@ -1,70 +0,0 @@
|
||||
title: |
|
||||
Container Orchestration
|
||||
with Docker and Swarm
|
||||
|
||||
chat: "[Slack](https://dockercommunity.slack.com/messages/C7GKACWDV)"
|
||||
#chat: "[Gitter](https://gitter.im/jpetazzo/workshop-yyyymmdd-city)"
|
||||
|
||||
gitrepo: github.com/jpetazzo/container.training
|
||||
|
||||
slides: http://container.training/
|
||||
|
||||
#slidenumberprefix: "#SomeHashTag — "
|
||||
|
||||
exclude:
|
||||
- self-paced
|
||||
- snap
|
||||
- btp-manual
|
||||
- benchmarking
|
||||
- elk-manual
|
||||
- prom-manual
|
||||
|
||||
content:
|
||||
- shared/title.md
|
||||
- logistics.md
|
||||
- swarm/intro.md
|
||||
- shared/about-slides.md
|
||||
- shared/chat-room-im.md
|
||||
#- shared/chat-room-slack.md
|
||||
#- shared/chat-room-zoom-meeting.md
|
||||
#- shared/chat-room-zoom-webinar.md
|
||||
- shared/toc.md
|
||||
- - shared/prereqs.md
|
||||
- shared/connecting.md
|
||||
- swarm/versions.md
|
||||
- shared/sampleapp.md
|
||||
- shared/composescale.md
|
||||
- shared/hastyconclusions.md
|
||||
- shared/composedown.md
|
||||
- swarm/swarmkit.md
|
||||
- shared/declarative.md
|
||||
- swarm/swarmmode.md
|
||||
- swarm/creatingswarm.md
|
||||
#- swarm/machine.md
|
||||
- swarm/morenodes.md
|
||||
- - swarm/firstservice.md
|
||||
- swarm/ourapponswarm.md
|
||||
#- swarm/hostingregistry.md
|
||||
#- swarm/testingregistry.md
|
||||
#- swarm/btp-manual.md
|
||||
#- swarm/swarmready.md
|
||||
- swarm/stacks.md
|
||||
- swarm/cicd.md
|
||||
- swarm/updatingservices.md
|
||||
#- swarm/rollingupdates.md
|
||||
#- swarm/healthchecks.md
|
||||
- - swarm/operatingswarm.md
|
||||
#- swarm/netshoot.md
|
||||
#- swarm/ipsec.md
|
||||
#- swarm/swarmtools.md
|
||||
- swarm/security.md
|
||||
#- swarm/secrets.md
|
||||
#- swarm/encryptionatrest.md
|
||||
- swarm/leastprivilege.md
|
||||
- swarm/apiscope.md
|
||||
- swarm/logging.md
|
||||
- swarm/metrics.md
|
||||
#- swarm/stateful.md
|
||||
#- swarm/extratips.md
|
||||
- shared/thankyou.md
|
||||
- swarm/links.md
|
||||
@@ -1,79 +0,0 @@
|
||||
title: |
|
||||
Container Orchestration
|
||||
with Docker and Swarm
|
||||
|
||||
chat: "[Slack](https://dockercommunity.slack.com/messages/C7GKACWDV)"
|
||||
|
||||
gitrepo: github.com/jpetazzo/container.training
|
||||
|
||||
slides: http://container.training/
|
||||
|
||||
#slidenumberprefix: "#SomeHashTag — "
|
||||
|
||||
exclude:
|
||||
- in-person
|
||||
- btp-auto
|
||||
|
||||
content:
|
||||
- shared/title.md
|
||||
#- shared/logistics.md
|
||||
- swarm/intro.md
|
||||
- shared/about-slides.md
|
||||
#- shared/chat-room-im.md
|
||||
#- shared/chat-room-slack.md
|
||||
#- shared/chat-room-zoom-meeting.md
|
||||
#- shared/chat-room-zoom-webinar.md
|
||||
- shared/toc.md
|
||||
- - shared/prereqs.md
|
||||
- shared/connecting.md
|
||||
- swarm/versions.md
|
||||
- |
|
||||
name: part-1
|
||||
|
||||
class: title, self-paced
|
||||
|
||||
Part 1
|
||||
- shared/sampleapp.md
|
||||
- shared/composescale.md
|
||||
- shared/hastyconclusions.md
|
||||
- shared/composedown.md
|
||||
- swarm/swarmkit.md
|
||||
- shared/declarative.md
|
||||
- swarm/swarmmode.md
|
||||
- swarm/creatingswarm.md
|
||||
#- swarm/machine.md
|
||||
- swarm/morenodes.md
|
||||
- - swarm/firstservice.md
|
||||
- swarm/ourapponswarm.md
|
||||
- swarm/hostingregistry.md
|
||||
- swarm/testingregistry.md
|
||||
- swarm/btp-manual.md
|
||||
- swarm/swarmready.md
|
||||
- swarm/stacks.md
|
||||
- swarm/cicd.md
|
||||
- |
|
||||
name: part-2
|
||||
|
||||
class: title, self-paced
|
||||
|
||||
Part 2
|
||||
- - swarm/operatingswarm.md
|
||||
- swarm/netshoot.md
|
||||
- swarm/swarmnbt.md
|
||||
- swarm/ipsec.md
|
||||
- swarm/updatingservices.md
|
||||
- swarm/rollingupdates.md
|
||||
- swarm/healthchecks.md
|
||||
- swarm/nodeinfo.md
|
||||
- swarm/swarmtools.md
|
||||
- - swarm/security.md
|
||||
- swarm/secrets.md
|
||||
- swarm/encryptionatrest.md
|
||||
- swarm/leastprivilege.md
|
||||
- swarm/apiscope.md
|
||||
- swarm/logging.md
|
||||
- swarm/metrics.md
|
||||
- swarm/stateful.md
|
||||
- swarm/extratips.md
|
||||
- shared/thankyou.md
|
||||
- swarm/links.md
|
||||
@@ -1,74 +0,0 @@
|
||||
title: |
|
||||
Container Orchestration
|
||||
with Docker and Swarm
|
||||
|
||||
chat: "[Slack](https://dockercommunity.slack.com/messages/C7GKACWDV)"
|
||||
|
||||
gitrepo: github.com/jpetazzo/container.training
|
||||
|
||||
slides: http://container.training/
|
||||
|
||||
#slidenumberprefix: "#SomeHashTag — "
|
||||
|
||||
exclude:
|
||||
- in-person
|
||||
- btp-auto
|
||||
|
||||
content:
|
||||
- shared/title.md
|
||||
#- shared/logistics.md
|
||||
- swarm/intro.md
|
||||
- shared/about-slides.md
|
||||
- shared/toc.md
|
||||
- - shared/prereqs.md
|
||||
- shared/connecting.md
|
||||
- swarm/versions.md
|
||||
- |
|
||||
name: part-1
|
||||
|
||||
class: title, self-paced
|
||||
|
||||
Part 1
|
||||
- shared/sampleapp.md
|
||||
- shared/composescale.md
|
||||
- shared/hastyconclusions.md
|
||||
- shared/composedown.md
|
||||
- swarm/swarmkit.md
|
||||
- shared/declarative.md
|
||||
- swarm/swarmmode.md
|
||||
- swarm/creatingswarm.md
|
||||
#- swarm/machine.md
|
||||
- swarm/morenodes.md
|
||||
- - swarm/firstservice.md
|
||||
- swarm/ourapponswarm.md
|
||||
- swarm/hostingregistry.md
|
||||
- swarm/testingregistry.md
|
||||
- swarm/btp-manual.md
|
||||
- swarm/swarmready.md
|
||||
- swarm/stacks.md
|
||||
- |
|
||||
name: part-2
|
||||
|
||||
class: title, self-paced
|
||||
|
||||
Part 2
|
||||
- - swarm/operatingswarm.md
|
||||
#- swarm/netshoot.md
|
||||
#- swarm/swarmnbt.md
|
||||
- swarm/ipsec.md
|
||||
- swarm/updatingservices.md
|
||||
- swarm/rollingupdates.md
|
||||
#- swarm/healthchecks.md
|
||||
- swarm/nodeinfo.md
|
||||
- swarm/swarmtools.md
|
||||
- - swarm/security.md
|
||||
- swarm/secrets.md
|
||||
- swarm/encryptionatrest.md
|
||||
- swarm/leastprivilege.md
|
||||
- swarm/apiscope.md
|
||||
#- swarm/logging.md
|
||||
#- swarm/metrics.md
|
||||
- swarm/stateful.md
|
||||
- swarm/extratips.md
|
||||
- shared/thankyou.md
|
||||
- swarm/links.md
|
||||
Reference in New Issue
Block a user