mirror of
https://github.com/jpetazzo/container.training.git
synced 2026-03-02 17:30:20 +00:00
Compare commits
2 Commits
2020-10-en
...
2020-07-ar
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5447d8caf7 | ||
|
|
424d32ad47 |
@@ -9,21 +9,21 @@ services:
|
||||
|
||||
etcd:
|
||||
network_mode: "service:pause"
|
||||
image: k8s.gcr.io/etcd:3.4.9
|
||||
image: k8s.gcr.io/etcd:3.4.3
|
||||
command: etcd
|
||||
|
||||
kube-apiserver:
|
||||
network_mode: "service:pause"
|
||||
image: k8s.gcr.io/hyperkube:v1.18.8
|
||||
image: k8s.gcr.io/hyperkube:v1.17.2
|
||||
command: kube-apiserver --etcd-servers http://127.0.0.1:2379 --address 0.0.0.0 --disable-admission-plugins=ServiceAccount --allow-privileged
|
||||
|
||||
kube-controller-manager:
|
||||
network_mode: "service:pause"
|
||||
image: k8s.gcr.io/hyperkube:v1.18.8
|
||||
image: k8s.gcr.io/hyperkube:v1.17.2
|
||||
command: kube-controller-manager --master http://localhost:8080 --allocate-node-cidrs --cluster-cidr=10.CLUSTER.0.0/16
|
||||
"Edit the CLUSTER placeholder first. Then, remove this line.":
|
||||
|
||||
kube-scheduler:
|
||||
network_mode: "service:pause"
|
||||
image: k8s.gcr.io/hyperkube:v1.18.8
|
||||
image: k8s.gcr.io/hyperkube:v1.17.2
|
||||
command: kube-scheduler --master http://localhost:8080
|
||||
|
||||
@@ -9,20 +9,20 @@ services:
|
||||
|
||||
etcd:
|
||||
network_mode: "service:pause"
|
||||
image: k8s.gcr.io/etcd:3.4.9
|
||||
image: k8s.gcr.io/etcd:3.4.3
|
||||
command: etcd
|
||||
|
||||
kube-apiserver:
|
||||
network_mode: "service:pause"
|
||||
image: k8s.gcr.io/hyperkube:v1.18.8
|
||||
image: k8s.gcr.io/hyperkube:v1.17.2
|
||||
command: kube-apiserver --etcd-servers http://127.0.0.1:2379 --address 0.0.0.0 --disable-admission-plugins=ServiceAccount
|
||||
|
||||
kube-controller-manager:
|
||||
network_mode: "service:pause"
|
||||
image: k8s.gcr.io/hyperkube:v1.18.8
|
||||
image: k8s.gcr.io/hyperkube:v1.17.2
|
||||
command: kube-controller-manager --master http://localhost:8080
|
||||
|
||||
kube-scheduler:
|
||||
network_mode: "service:pause"
|
||||
image: k8s.gcr.io/hyperkube:v1.18.8
|
||||
image: k8s.gcr.io/hyperkube:v1.17.2
|
||||
command: kube-scheduler --master http://localhost:8080
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
kind: Service
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: certbot
|
||||
spec:
|
||||
ports:
|
||||
- port: 80
|
||||
protocol: TCP
|
||||
---
|
||||
apiVersion: networking.k8s.io/v1beta1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: certbot
|
||||
spec:
|
||||
rules:
|
||||
- http:
|
||||
paths:
|
||||
- path: /.well-known/acme-challenge/
|
||||
backend:
|
||||
serviceName: certbot
|
||||
servicePort: 80
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Endpoints
|
||||
metadata:
|
||||
name: certbot
|
||||
subsets:
|
||||
- addresses:
|
||||
- ip: A.B.C.D
|
||||
ports:
|
||||
- port: 8000
|
||||
protocol: TCP
|
||||
|
||||
@@ -1,77 +0,0 @@
|
||||
# Basic Consul cluster using Cloud Auto-Join.
|
||||
# Caveats:
|
||||
# - no actual persistence
|
||||
# - scaling down to 1 will break the cluster
|
||||
# - pods may be colocated
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: Role
|
||||
metadata:
|
||||
name: consul
|
||||
rules:
|
||||
- apiGroups: [""]
|
||||
resources:
|
||||
- pods
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: RoleBinding
|
||||
metadata:
|
||||
name: consul
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: Role
|
||||
name: consul
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: consul
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: consul
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: consul
|
||||
spec:
|
||||
ports:
|
||||
- port: 8500
|
||||
name: http
|
||||
selector:
|
||||
app: consul
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
name: consul
|
||||
spec:
|
||||
serviceName: consul
|
||||
replicas: 3
|
||||
selector:
|
||||
matchLabels:
|
||||
app: consul
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: consul
|
||||
spec:
|
||||
serviceAccountName: consul
|
||||
containers:
|
||||
- name: consul
|
||||
image: "consul:1.8"
|
||||
env:
|
||||
- name: NAMESPACE
|
||||
valueFrom:
|
||||
fieldRef:
|
||||
fieldPath: metadata.namespace
|
||||
args:
|
||||
- "agent"
|
||||
- "-bootstrap-expect=3"
|
||||
- "-retry-join=provider=k8s label_selector=\"app=consul\" namespace=\"$(NAMESPACE)\""
|
||||
- "-client=0.0.0.0"
|
||||
- "-data-dir=/consul/data"
|
||||
- "-server"
|
||||
- "-ui"
|
||||
@@ -1,104 +0,0 @@
|
||||
# Even better Consul cluster.
|
||||
# That one uses a volumeClaimTemplate to achieve true persistence.
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: Role
|
||||
metadata:
|
||||
name: consul
|
||||
rules:
|
||||
- apiGroups: [""]
|
||||
resources:
|
||||
- pods
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: RoleBinding
|
||||
metadata:
|
||||
name: consul
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: Role
|
||||
name: consul
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: consul
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: consul
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: consul
|
||||
spec:
|
||||
ports:
|
||||
- port: 8500
|
||||
name: http
|
||||
selector:
|
||||
app: consul
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
name: consul
|
||||
spec:
|
||||
serviceName: consul
|
||||
replicas: 3
|
||||
selector:
|
||||
matchLabels:
|
||||
app: consul
|
||||
volumeClaimTemplates:
|
||||
- metadata:
|
||||
name: data
|
||||
spec:
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
resources:
|
||||
requests:
|
||||
storage: 1Gi
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: consul
|
||||
spec:
|
||||
serviceAccountName: consul
|
||||
affinity:
|
||||
podAntiAffinity:
|
||||
requiredDuringSchedulingIgnoredDuringExecution:
|
||||
- labelSelector:
|
||||
matchExpressions:
|
||||
- key: app
|
||||
operator: In
|
||||
values:
|
||||
- persistentconsul
|
||||
topologyKey: kubernetes.io/hostname
|
||||
terminationGracePeriodSeconds: 10
|
||||
containers:
|
||||
- name: consul
|
||||
image: "consul:1.8"
|
||||
volumeMounts:
|
||||
- name: data
|
||||
mountPath: /consul/data
|
||||
env:
|
||||
- name: NAMESPACE
|
||||
valueFrom:
|
||||
fieldRef:
|
||||
fieldPath: metadata.namespace
|
||||
args:
|
||||
- "agent"
|
||||
- "-bootstrap-expect=3"
|
||||
- "-retry-join=provider=k8s label_selector=\"app=consul\" namespace=\"$(NAMESPACE)\""
|
||||
- "-client=0.0.0.0"
|
||||
- "-data-dir=/consul/data"
|
||||
- "-server"
|
||||
- "-ui"
|
||||
lifecycle:
|
||||
preStop:
|
||||
exec:
|
||||
command:
|
||||
- /bin/sh
|
||||
- -c
|
||||
- consul leave
|
||||
@@ -1,9 +1,5 @@
|
||||
# Better Consul cluster.
|
||||
# There is still no actual persistence, but:
|
||||
# - podAntiaffinity prevents pod colocation
|
||||
# - clusters works when scaling down to 1 (thanks to lifecycle hook)
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: Role
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: consul
|
||||
rules:
|
||||
@@ -15,16 +11,17 @@ rules:
|
||||
- list
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: RoleBinding
|
||||
kind: ClusterRoleBinding
|
||||
metadata:
|
||||
name: consul
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: Role
|
||||
kind: ClusterRole
|
||||
name: consul
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: consul
|
||||
namespace: default
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
@@ -71,16 +68,11 @@ spec:
|
||||
terminationGracePeriodSeconds: 10
|
||||
containers:
|
||||
- name: consul
|
||||
image: "consul:1.8"
|
||||
env:
|
||||
- name: NAMESPACE
|
||||
valueFrom:
|
||||
fieldRef:
|
||||
fieldPath: metadata.namespace
|
||||
image: "consul:1.6"
|
||||
args:
|
||||
- "agent"
|
||||
- "-bootstrap-expect=3"
|
||||
- "-retry-join=provider=k8s label_selector=\"app=consul\" namespace=\"$(NAMESPACE)\""
|
||||
- "-retry-join=provider=k8s label_selector=\"app=consul\""
|
||||
- "-client=0.0.0.0"
|
||||
- "-data-dir=/consul/data"
|
||||
- "-server"
|
||||
@@ -27,7 +27,7 @@ spec:
|
||||
command:
|
||||
- sh
|
||||
- -c
|
||||
- "mkdir -p /root/.ssh && apk update && apk add curl && curl https://github.com/jpetazzo.keys > /root/.ssh/authorized_keys"
|
||||
- "apk update && apk add curl && curl https://github.com/jpetazzo.keys > /root/.ssh/authorized_keys"
|
||||
containers:
|
||||
- name: web
|
||||
image: nginx
|
||||
|
||||
@@ -3,10 +3,6 @@ kind: Ingress
|
||||
metadata:
|
||||
name: whatever
|
||||
spec:
|
||||
#tls:
|
||||
#- secretName: whatever.A.B.C.D.nip.io
|
||||
# hosts:
|
||||
# - whatever.A.B.C.D.nip.io
|
||||
rules:
|
||||
- host: whatever.A.B.C.D.nip.io
|
||||
http:
|
||||
|
||||
@@ -50,10 +50,8 @@ spec:
|
||||
- --api.insecure
|
||||
- --log.level=INFO
|
||||
- --metrics.prometheus
|
||||
- --providers.kubernetescrd
|
||||
- --providers.kubernetesingress
|
||||
- --entrypoints.http.Address=:80
|
||||
- --entrypoints.https.Address=:443
|
||||
- --entrypoints.https.http.tls.certResolver=default
|
||||
---
|
||||
kind: Service
|
||||
apiVersion: v1
|
||||
|
||||
@@ -1 +1 @@
|
||||
traefik-v2.yaml
|
||||
traefik-v1.yaml
|
||||
@@ -1,5 +1,4 @@
|
||||
INFRACLASS=openstack-tf
|
||||
|
||||
INFRACLASS=openstack
|
||||
# If you are using OpenStack, copy this file (e.g. to "openstack" or "enix")
|
||||
# and customize the variables below.
|
||||
export TF_VAR_user="jpetazzo"
|
||||
@@ -7,4 +6,4 @@ export TF_VAR_tenant="training"
|
||||
export TF_VAR_domain="Default"
|
||||
export TF_VAR_password="..."
|
||||
export TF_VAR_auth_url="https://api.r1.nxs.enix.io/v3"
|
||||
export TF_VAR_flavor="GP1.S"
|
||||
export TF_VAR_flavor="GP1.S"
|
||||
@@ -1,24 +0,0 @@
|
||||
INFRACLASS=openstack-cli
|
||||
|
||||
# Copy that file to e.g. openstack or ovh, then customize it.
|
||||
# Some Openstack providers (like OVHcloud) will let you download
|
||||
# a file containing credentials. That's what you need to use.
|
||||
# The file below contains some example values.
|
||||
export OS_AUTH_URL=https://auth.cloud.ovh.net/v3/
|
||||
export OS_IDENTITY_API_VERSION=3
|
||||
export OS_USER_DOMAIN_NAME=${OS_USER_DOMAIN_NAME:-"Default"}
|
||||
export OS_PROJECT_DOMAIN_NAME=${OS_PROJECT_DOMAIN_NAME:-"Default"}
|
||||
export OS_TENANT_ID=abcd1234
|
||||
export OS_TENANT_NAME="0123456"
|
||||
export OS_USERNAME="user-xyz123"
|
||||
export OS_PASSWORD=AbCd1234
|
||||
export OS_REGION_NAME="GRA7"
|
||||
|
||||
# And then some values to indicate server type, image, etc.
|
||||
# You can see available flavors with `openstack flavor list`
|
||||
export OS_FLAVOR=s1-4
|
||||
# You can see available images with `openstack image list`
|
||||
export OS_IMAGE=896c5f54-51dc-44f0-8c22-ce99ba7164df
|
||||
# You can create a key with `openstack keypair create --public-key ~/.ssh/id_rsa.pub containertraining`
|
||||
export OS_KEY=containertraining
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
INFRACLASS=hetzner
|
||||
if ! [ -f ~/.config/hcloud/cli.toml ]; then
|
||||
warn "~/.config/hcloud/cli.toml not found."
|
||||
warn "Make sure that the Hetzner CLI (hcloud) is installed and configured."
|
||||
fi
|
||||
@@ -1 +0,0 @@
|
||||
INFRACLASS=scaleway
|
||||
@@ -43,16 +43,6 @@ _cmd_cards() {
|
||||
info "$0 www"
|
||||
}
|
||||
|
||||
_cmd clean "Remove information about stopped clusters"
|
||||
_cmd_clean() {
|
||||
for TAG in tags/*; do
|
||||
if grep -q ^stopped$ "$TAG/status"; then
|
||||
info "Removing $TAG..."
|
||||
rm -rf "$TAG"
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
_cmd deploy "Install Docker on a bunch of running VMs"
|
||||
_cmd_deploy() {
|
||||
TAG=$1
|
||||
@@ -75,27 +65,6 @@ _cmd_deploy() {
|
||||
sleep 1
|
||||
done"
|
||||
|
||||
# Special case for scaleway since it doesn't come with sudo
|
||||
if [ "$INFRACLASS" = "scaleway" ]; then
|
||||
pssh -l root "
|
||||
grep DEBIAN_FRONTEND /etc/environment || echo DEBIAN_FRONTEND=noninteractive >> /etc/environment
|
||||
grep cloud-init /etc/sudoers && rm /etc/sudoers
|
||||
apt-get update && apt-get install sudo -y"
|
||||
fi
|
||||
|
||||
# FIXME
|
||||
# Special case for hetzner since it doesn't have an ubuntu user
|
||||
#if [ "$INFRACLASS" = "hetzner" ]; then
|
||||
# pssh -l root "
|
||||
#[ -d /home/ubuntu ] ||
|
||||
# useradd ubuntu -m -s /bin/bash
|
||||
#echo 'ubuntu ALL=(ALL:ALL) NOPASSWD:ALL' > /etc/sudoers.d/ubuntu
|
||||
#[ -d /home/ubuntu/.ssh ] ||
|
||||
# install --owner=ubuntu --mode=700 --directory /home/ubuntu/.ssh
|
||||
#[ -f /home/ubuntu/.ssh/authorized_keys ] ||
|
||||
# install --owner=ubuntu --mode=600 /root/.ssh/authorized_keys --target-directory /home/ubuntu/.ssh"
|
||||
#fi
|
||||
|
||||
# Copy settings and install Python YAML parser
|
||||
pssh -I tee /tmp/settings.yaml <tags/$TAG/settings.yaml
|
||||
pssh "
|
||||
@@ -162,19 +131,19 @@ _cmd_kubebins() {
|
||||
cd /usr/local/bin
|
||||
if ! [ -x etcd ]; then
|
||||
##VERSION##
|
||||
curl -L https://github.com/etcd-io/etcd/releases/download/v3.4.9/etcd-v3.4.9-linux-amd64.tar.gz \
|
||||
curl -L https://github.com/etcd-io/etcd/releases/download/v3.4.3/etcd-v3.4.3-linux-amd64.tar.gz \
|
||||
| sudo tar --strip-components=1 --wildcards -zx '*/etcd' '*/etcdctl'
|
||||
fi
|
||||
if ! [ -x hyperkube ]; then
|
||||
##VERSION##
|
||||
curl -L https://dl.k8s.io/v1.18.8/kubernetes-server-linux-amd64.tar.gz \
|
||||
curl -L https://dl.k8s.io/v1.17.2/kubernetes-server-linux-amd64.tar.gz \
|
||||
| sudo tar --strip-components=3 -zx \
|
||||
kubernetes/server/bin/kube{ctl,let,-proxy,-apiserver,-scheduler,-controller-manager}
|
||||
fi
|
||||
sudo mkdir -p /opt/cni/bin
|
||||
cd /opt/cni/bin
|
||||
if ! [ -x bridge ]; then
|
||||
curl -L https://github.com/containernetworking/plugins/releases/download/v0.8.6/cni-plugins-linux-amd64-v0.8.6.tgz \
|
||||
curl -L https://github.com/containernetworking/plugins/releases/download/v0.7.6/cni-plugins-amd64-v0.7.6.tgz \
|
||||
| sudo tar -zx
|
||||
fi
|
||||
"
|
||||
@@ -210,7 +179,7 @@ _cmd_kube() {
|
||||
pssh --timeout 200 "
|
||||
if i_am_first_node && [ ! -f /etc/kubernetes/admin.conf ]; then
|
||||
kubeadm token generate > /tmp/token &&
|
||||
sudo kubeadm init $EXTRA_KUBEADM --token \$(cat /tmp/token) --apiserver-cert-extra-sans \$(cat /tmp/ipv4) --ignore-preflight-errors=NumCPU
|
||||
sudo kubeadm init $EXTRA_KUBEADM --token \$(cat /tmp/token) --apiserver-cert-extra-sans \$(cat /tmp/ipv4)
|
||||
fi"
|
||||
|
||||
# Put kubeconfig in ubuntu's and docker's accounts
|
||||
@@ -247,13 +216,13 @@ _cmd_kube() {
|
||||
# Install kubectx and kubens
|
||||
pssh "
|
||||
[ -d kubectx ] || git clone https://github.com/ahmetb/kubectx &&
|
||||
sudo ln -sf \$HOME/kubectx/kubectx /usr/local/bin/kctx &&
|
||||
sudo ln -sf \$HOME/kubectx/kubens /usr/local/bin/kns &&
|
||||
sudo cp \$HOME/kubectx/completion/*.bash /etc/bash_completion.d &&
|
||||
sudo ln -sf /home/ubuntu/kubectx/kubectx /usr/local/bin/kctx &&
|
||||
sudo ln -sf /home/ubuntu/kubectx/kubens /usr/local/bin/kns &&
|
||||
sudo cp /home/ubuntu/kubectx/completion/*.bash /etc/bash_completion.d &&
|
||||
[ -d kube-ps1 ] || git clone https://github.com/jonmosco/kube-ps1 &&
|
||||
sudo -u docker sed -i s/docker-prompt/kube_ps1/ /home/docker/.bashrc &&
|
||||
sudo -u docker tee -a /home/docker/.bashrc <<EOF
|
||||
. \$HOME/kube-ps1/kube-ps1.sh
|
||||
. /home/ubuntu/kube-ps1/kube-ps1.sh
|
||||
KUBE_PS1_PREFIX=""
|
||||
KUBE_PS1_SUFFIX=""
|
||||
KUBE_PS1_SYMBOL_ENABLE="false"
|
||||
@@ -326,44 +295,29 @@ _cmd_kubetest() {
|
||||
set -e
|
||||
if i_am_first_node; then
|
||||
which kubectl
|
||||
for NODE in \$(grep [0-9]\$ /etc/hosts | grep -v ^127 | awk {print\ \\\$2}); do
|
||||
for NODE in \$(awk /[0-9]\$/\ {print\ \\\$2} /etc/hosts); do
|
||||
echo \$NODE ; kubectl get nodes | grep -w \$NODE | grep -w Ready
|
||||
done
|
||||
fi"
|
||||
}
|
||||
|
||||
_cmd ips "Show the IP addresses for a given tag"
|
||||
_cmd_ips() {
|
||||
_cmd ids "(FIXME) List the instance IDs belonging to a given tag or token"
|
||||
_cmd_ids() {
|
||||
TAG=$1
|
||||
need_tag $TAG
|
||||
|
||||
SETTINGS=tags/$TAG/settings.yaml
|
||||
CLUSTERSIZE=$(awk '/^clustersize:/ {print $2}' $SETTINGS)
|
||||
while true; do
|
||||
for I in $(seq $CLUSTERSIZE); do
|
||||
read ip || return 0
|
||||
printf "%s\t" "$ip"
|
||||
done
|
||||
printf "\n"
|
||||
done < tags/$TAG/ips.txt
|
||||
info "Looking up by tag:"
|
||||
aws_get_instance_ids_by_tag $TAG
|
||||
|
||||
# Just in case we managed to create instances but weren't able to tag them
|
||||
info "Looking up by token:"
|
||||
aws_get_instance_ids_by_client_token $TAG
|
||||
}
|
||||
|
||||
_cmd list "List all VMs on a given infrastructure (or all infras if no arg given)"
|
||||
_cmd list "List available groups for a given infrastructure"
|
||||
_cmd_list() {
|
||||
case "$1" in
|
||||
"")
|
||||
for INFRA in infra/*; do
|
||||
$0 list $INFRA
|
||||
done
|
||||
;;
|
||||
*/example.*)
|
||||
;;
|
||||
*)
|
||||
need_infra $1
|
||||
sep "Listing instances for $1"
|
||||
infra_list
|
||||
;;
|
||||
esac
|
||||
need_infra $1
|
||||
infra_list
|
||||
}
|
||||
|
||||
_cmd listall "List VMs running on all configured infrastructures"
|
||||
@@ -457,6 +411,16 @@ _cmd_opensg() {
|
||||
infra_opensg
|
||||
}
|
||||
|
||||
_cmd portworx "Prepare the nodes for Portworx deployment"
|
||||
_cmd_portworx() {
|
||||
TAG=$1
|
||||
need_tag
|
||||
|
||||
pssh "
|
||||
sudo truncate --size 10G /portworx.blk &&
|
||||
sudo losetup /dev/loop4 /portworx.blk"
|
||||
}
|
||||
|
||||
_cmd disableaddrchecks "Disable source/destination IP address checks"
|
||||
_cmd_disableaddrchecks() {
|
||||
TAG=$1
|
||||
@@ -501,6 +465,18 @@ _cmd_quotas() {
|
||||
infra_quotas
|
||||
}
|
||||
|
||||
_cmd retag "(FIXME) Apply a new tag to a group of VMs"
|
||||
_cmd_retag() {
|
||||
OLDTAG=$1
|
||||
NEWTAG=$2
|
||||
TAG=$OLDTAG
|
||||
need_tag
|
||||
if [[ -z "$NEWTAG" ]]; then
|
||||
die "You must specify a new tag to apply."
|
||||
fi
|
||||
aws_tag_instances $OLDTAG $NEWTAG
|
||||
}
|
||||
|
||||
_cmd ssh "Open an SSH session to the first node of a tag"
|
||||
_cmd_ssh() {
|
||||
TAG=$1
|
||||
@@ -687,12 +663,11 @@ _cmd_webssh() {
|
||||
sudo apt-get update &&
|
||||
sudo apt-get install python-tornado python-paramiko -y"
|
||||
pssh "
|
||||
cd /opt
|
||||
[ -d webssh ] || sudo git clone https://github.com/jpetazzo/webssh"
|
||||
[ -d webssh ] || git clone https://github.com/jpetazzo/webssh"
|
||||
pssh "
|
||||
for KEYFILE in /etc/ssh/*.pub; do
|
||||
read a b c < \$KEYFILE; echo localhost \$a \$b
|
||||
done | sudo tee /opt/webssh/known_hosts"
|
||||
done > webssh/known_hosts"
|
||||
pssh "cat >webssh.service <<EOF
|
||||
[Unit]
|
||||
Description=webssh
|
||||
@@ -701,7 +676,7 @@ Description=webssh
|
||||
WantedBy=multi-user.target
|
||||
|
||||
[Service]
|
||||
WorkingDirectory=/opt/webssh
|
||||
WorkingDirectory=/home/ubuntu/webssh
|
||||
ExecStart=/usr/bin/env python run.py --fbidhttp=false --port=1080 --policy=reject
|
||||
User=nobody
|
||||
Group=nogroup
|
||||
@@ -724,6 +699,11 @@ _cmd_www() {
|
||||
python3 -m http.server
|
||||
}
|
||||
|
||||
greet() {
|
||||
IAMUSER=$(aws iam get-user --query 'User.UserName')
|
||||
info "Hello! You seem to be UNIX user $USER, and IAM user $IAMUSER."
|
||||
}
|
||||
|
||||
pull_tag() {
|
||||
# Pre-pull a bunch of images
|
||||
pssh --timeout 900 'for I in \
|
||||
@@ -813,3 +793,27 @@ make_key_name() {
|
||||
SHORT_FINGERPRINT=$(ssh-add -l | grep RSA | head -n1 | cut -d " " -f 2 | tr -d : | cut -c 1-8)
|
||||
echo "${SHORT_FINGERPRINT}-${USER}"
|
||||
}
|
||||
|
||||
sync_keys() {
|
||||
# make sure ssh-add -l contains "RSA"
|
||||
ssh-add -l | grep -q RSA \
|
||||
|| die "The output of \`ssh-add -l\` doesn't contain 'RSA'. Start the agent, add your keys?"
|
||||
|
||||
AWS_KEY_NAME=$(make_key_name)
|
||||
info "Syncing keys... "
|
||||
if ! aws ec2 describe-key-pairs --key-name "$AWS_KEY_NAME" &>/dev/null; then
|
||||
aws ec2 import-key-pair --key-name $AWS_KEY_NAME \
|
||||
--public-key-material "$(ssh-add -L \
|
||||
| grep -i RSA \
|
||||
| head -n1 \
|
||||
| cut -d " " -f 1-2)" &>/dev/null
|
||||
|
||||
if ! aws ec2 describe-key-pairs --key-name "$AWS_KEY_NAME" &>/dev/null; then
|
||||
die "Somehow, importing the key didn't work. Make sure that 'ssh-add -l | grep RSA | head -n1' returns an RSA key?"
|
||||
else
|
||||
info "Imported new key $AWS_KEY_NAME."
|
||||
fi
|
||||
else
|
||||
info "Using existing key $AWS_KEY_NAME."
|
||||
fi
|
||||
}
|
||||
|
||||
@@ -1,14 +1,9 @@
|
||||
if ! command -v aws >/dev/null; then
|
||||
warn "AWS CLI (aws) not found."
|
||||
fi
|
||||
|
||||
infra_list() {
|
||||
aws ec2 describe-instances --output json |
|
||||
jq -r '.Reservations[].Instances[] | [.InstanceId, .ClientToken, .State.Name, .InstanceType ] | @tsv'
|
||||
aws_display_tags
|
||||
}
|
||||
|
||||
infra_quotas() {
|
||||
aws_greet
|
||||
greet
|
||||
|
||||
max_instances=$(aws ec2 describe-account-attributes \
|
||||
--attribute-names max-instances \
|
||||
@@ -26,10 +21,10 @@ infra_start() {
|
||||
COUNT=$1
|
||||
|
||||
# Print our AWS username, to ease the pain of credential-juggling
|
||||
aws_greet
|
||||
greet
|
||||
|
||||
# Upload our SSH keys to AWS if needed, to be added to each VM's authorized_keys
|
||||
key_name=$(aws_sync_keys)
|
||||
key_name=$(sync_keys)
|
||||
|
||||
AMI=$(aws_get_ami) # Retrieve the AWS image ID
|
||||
if [ -z "$AMI" ]; then
|
||||
@@ -66,7 +61,7 @@ infra_start() {
|
||||
aws_tag_instances $TAG $TAG
|
||||
|
||||
# Wait until EC2 API tells us that the instances are running
|
||||
aws_wait_until_tag_is_running $TAG $COUNT
|
||||
wait_until_tag_is_running $TAG $COUNT
|
||||
|
||||
aws_get_instance_ips_by_tag $TAG > tags/$TAG/ips.txt
|
||||
}
|
||||
@@ -103,7 +98,7 @@ infra_disableaddrchecks() {
|
||||
done
|
||||
}
|
||||
|
||||
aws_wait_until_tag_is_running() {
|
||||
wait_until_tag_is_running() {
|
||||
max_retry=100
|
||||
i=0
|
||||
done_count=0
|
||||
@@ -219,32 +214,3 @@ aws_get_ami() {
|
||||
##VERSION##
|
||||
find_ubuntu_ami -r $AWS_DEFAULT_REGION -a amd64 -v 18.04 -t hvm:ebs -N -q
|
||||
}
|
||||
|
||||
aws_greet() {
|
||||
IAMUSER=$(aws iam get-user --query 'User.UserName')
|
||||
info "Hello! You seem to be UNIX user $USER, and IAM user $IAMUSER."
|
||||
}
|
||||
|
||||
aws_sync_keys() {
|
||||
# make sure ssh-add -l contains "RSA"
|
||||
ssh-add -l | grep -q RSA \
|
||||
|| die "The output of \`ssh-add -l\` doesn't contain 'RSA'. Start the agent, add your keys?"
|
||||
|
||||
AWS_KEY_NAME=$(make_key_name)
|
||||
info "Syncing keys... "
|
||||
if ! aws ec2 describe-key-pairs --key-name "$AWS_KEY_NAME" &>/dev/null; then
|
||||
aws ec2 import-key-pair --key-name $AWS_KEY_NAME \
|
||||
--public-key-material "$(ssh-add -L \
|
||||
| grep -i RSA \
|
||||
| head -n1 \
|
||||
| cut -d " " -f 1-2)" &>/dev/null
|
||||
|
||||
if ! aws ec2 describe-key-pairs --key-name "$AWS_KEY_NAME" &>/dev/null; then
|
||||
die "Somehow, importing the key didn't work. Make sure that 'ssh-add -l | grep RSA | head -n1' returns an RSA key?"
|
||||
else
|
||||
info "Imported new key $AWS_KEY_NAME."
|
||||
fi
|
||||
else
|
||||
info "Using existing key $AWS_KEY_NAME."
|
||||
fi
|
||||
}
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
if ! command -v hcloud >/dev/null; then
|
||||
warn "Hetzner CLI (hcloud) not found."
|
||||
fi
|
||||
if ! [ -f ~/.config/hcloud/cli.toml ]; then
|
||||
warn "~/.config/hcloud/cli.toml not found."
|
||||
fi
|
||||
|
||||
infra_list() {
|
||||
[ "$(hcloud server list -o json)" = "null" ] && return
|
||||
|
||||
hcloud server list -o json |
|
||||
jq -r '.[] | [.id, .name , .status, .server_type.name] | @tsv'
|
||||
}
|
||||
|
||||
infra_start() {
|
||||
COUNT=$1
|
||||
|
||||
HETZNER_INSTANCE_TYPE=${HETZNER_INSTANCE_TYPE-cx21}
|
||||
HETZNER_DATACENTER=${HETZNER_DATACENTER-nbg1-dc3}
|
||||
HETZNER_IMAGE=${HETZNER_IMAGE-168855}
|
||||
|
||||
for I in $(seq 1 $COUNT); do
|
||||
NAME=$(printf "%s-%03d" $TAG $I)
|
||||
sep "Starting instance $I/$COUNT"
|
||||
info " Datacenter: $HETZNER_DATACENTER"
|
||||
info " Name: $NAME"
|
||||
info " Instance type: $HETZNER_INSTANCE_TYPE"
|
||||
hcloud server create \
|
||||
--type=${HETZNER_INSTANCE_TYPE} \
|
||||
--datacenter=${HETZNER_DATACENTER} \
|
||||
--image=${HETZNER_IMAGE} \
|
||||
--name=$NAME \
|
||||
--label=tag=$TAG \
|
||||
--ssh-key ~/.ssh/id_rsa.pub
|
||||
done
|
||||
|
||||
hetzner_get_ips_by_tag $TAG > tags/$TAG/ips.txt
|
||||
}
|
||||
|
||||
infra_stop() {
|
||||
for ID in $(hetzner_get_ids_by_tag $TAG); do
|
||||
info "Scheduling deletion of instance $ID..."
|
||||
hcloud server delete $ID &
|
||||
done
|
||||
info "Waiting for deletion to complete..."
|
||||
wait
|
||||
}
|
||||
|
||||
hetzner_get_ids_by_tag() {
|
||||
TAG=$1
|
||||
hcloud server list --selector=tag=$TAG -o json | jq -r .[].name
|
||||
}
|
||||
|
||||
hetzner_get_ips_by_tag() {
|
||||
TAG=$1
|
||||
hcloud server list --selector=tag=$TAG -o json | jq -r .[].public_net.ipv4.ip
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
infra_list() {
|
||||
openstack server list -f json |
|
||||
jq -r '.[] | [.ID, .Name , .Status, .Flavor] | @tsv'
|
||||
}
|
||||
|
||||
infra_start() {
|
||||
COUNT=$1
|
||||
|
||||
sep "Starting $COUNT instances"
|
||||
info " Region: $OS_REGION_NAME"
|
||||
info " User: $OS_USERNAME"
|
||||
info " Flavor: $OS_FLAVOR"
|
||||
info " Image: $OS_IMAGE"
|
||||
openstack server create \
|
||||
--flavor $OS_FLAVOR \
|
||||
--image $OS_IMAGE \
|
||||
--key-name $OS_KEY \
|
||||
--min $COUNT --max $COUNT \
|
||||
--property workshopctl=$TAG \
|
||||
$TAG
|
||||
|
||||
sep "Waiting for IP addresses to be available"
|
||||
GOT=0
|
||||
while [ "$GOT" != "$COUNT" ]; do
|
||||
echo "Got $GOT/$COUNT IP addresses."
|
||||
oscli_get_ips_by_tag $TAG > tags/$TAG/ips.txt
|
||||
GOT="$(wc -l < tags/$TAG/ips.txt)"
|
||||
done
|
||||
|
||||
}
|
||||
|
||||
infra_stop() {
|
||||
info "Counting instances..."
|
||||
oscli_get_instances_json $TAG |
|
||||
jq -r .[].Name |
|
||||
wc -l
|
||||
info "Deleting instances..."
|
||||
oscli_get_instances_json $TAG |
|
||||
jq -r .[].Name |
|
||||
xargs -P10 -n1 openstack server delete
|
||||
info "Done."
|
||||
}
|
||||
|
||||
oscli_get_instances_json() {
|
||||
TAG=$1
|
||||
openstack server list -f json --name "${TAG}-[0-9]*"
|
||||
}
|
||||
|
||||
oscli_get_ips_by_tag() {
|
||||
TAG=$1
|
||||
oscli_get_instances_json $TAG |
|
||||
jq -r .[].Networks | grep -oE '[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+' || true
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
if ! command -v scw >/dev/null; then
|
||||
warn "Scaleway CLI (scw) not found."
|
||||
fi
|
||||
if ! [ -f ~/.config/scw/config.yaml ]; then
|
||||
warn "~/.config/scw/config.yaml not found."
|
||||
fi
|
||||
|
||||
infra_list() {
|
||||
scw instance server list -o json |
|
||||
jq -r '.[] | [.id, .name, .state, .commercial_type] | @tsv'
|
||||
}
|
||||
|
||||
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"
|
||||
info " Zone: $SCW_ZONE"
|
||||
info " Name: $NAME"
|
||||
info " Instance type: $SCW_INSTANCE_TYPE"
|
||||
scw instance server create \
|
||||
type=${SCW_INSTANCE_TYPE} zone=${SCW_ZONE} \
|
||||
image=ubuntu_bionic name=${NAME}
|
||||
done
|
||||
sep
|
||||
|
||||
scw_get_ips_by_tag $TAG > tags/$TAG/ips.txt
|
||||
}
|
||||
|
||||
infra_stop() {
|
||||
info "Counting instances..."
|
||||
scw_get_ids_by_tag $TAG | wc -l
|
||||
info "Deleting instances..."
|
||||
scw_get_ids_by_tag $TAG |
|
||||
xargs -n1 -P10 -I@@ \
|
||||
scw instance server delete force-shutdown=true server-id=@@
|
||||
}
|
||||
|
||||
scw_get_ids_by_tag() {
|
||||
TAG=$1
|
||||
scw instance server list name=$TAG -o json | jq -r .[].id
|
||||
}
|
||||
|
||||
scw_get_ips_by_tag() {
|
||||
TAG=$1
|
||||
scw instance server list name=$TAG -o json | jq -r .[].public_ip.address
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
infra_disableaddrchecks() {
|
||||
die "unimplemented"
|
||||
}
|
||||
|
||||
infra_list() {
|
||||
die "unimplemented"
|
||||
}
|
||||
|
||||
infra_opensg() {
|
||||
die "unimplemented"
|
||||
}
|
||||
|
||||
infra_quotas() {
|
||||
die "unimplemented"
|
||||
}
|
||||
|
||||
infra_start() {
|
||||
die "unimplemented"
|
||||
}
|
||||
|
||||
infra_stop() {
|
||||
die "unimplemented"
|
||||
}
|
||||
@@ -37,7 +37,7 @@ def system(cmd):
|
||||
td = str(t2-t1)[:5]
|
||||
f.write(bold("[{}] in {}s\n".format(retcode, td)))
|
||||
STEP += 1
|
||||
with open(os.environ["HOME"] + "/.bash_history", "a") as f:
|
||||
with open("/home/ubuntu/.bash_history", "a") as f:
|
||||
f.write("{}\n".format(cmd))
|
||||
if retcode != 0:
|
||||
msg = "The following command failed with exit code {}:\n".format(retcode)
|
||||
@@ -114,7 +114,7 @@ system("sudo sed -i 's/PasswordAuthentication no/PasswordAuthentication yes/' /e
|
||||
|
||||
system("sudo service ssh restart")
|
||||
system("sudo apt-get -q update")
|
||||
system("sudo apt-get -qy install git jid jq")
|
||||
system("sudo apt-get -qy install git jq")
|
||||
system("sudo apt-get -qy install emacs-nox joe")
|
||||
|
||||
#######################
|
||||
|
||||
@@ -18,13 +18,7 @@ pssh() {
|
||||
echo "[parallel-ssh] $@"
|
||||
export PSSH=$(which pssh || which parallel-ssh)
|
||||
|
||||
if [ "$INFRACLASS" = hetzner ]; then
|
||||
LOGIN=root
|
||||
else
|
||||
LOGIN=ubuntu
|
||||
fi
|
||||
|
||||
$PSSH -h $HOSTFILE -l $LOGIN \
|
||||
$PSSH -h $HOSTFILE -l ubuntu \
|
||||
--par 100 \
|
||||
-O LogLevel=ERROR \
|
||||
-O UserKnownHostsFile=/dev/null \
|
||||
|
||||
@@ -1,45 +1,21 @@
|
||||
#!/usr/bin/env python
|
||||
"""
|
||||
There are two ways to use this script:
|
||||
|
||||
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.
|
||||
Example: ./map-dns.py open-duck.site 1.2.3.4 2.3.4.5 3.4.5.6
|
||||
|
||||
In both cases, the domains should be configured to use GANDI LiveDNS.
|
||||
"""
|
||||
import os
|
||||
import requests
|
||||
import sys
|
||||
import yaml
|
||||
|
||||
# configurable stuff
|
||||
domains_file = "../../plentydomains/domains.txt"
|
||||
config_file = os.path.join(
|
||||
os.environ["HOME"], ".config/gandi/config.yaml")
|
||||
tag = None
|
||||
tag = "test"
|
||||
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
|
||||
domains = open(domains_file).read().split()
|
||||
apikey = yaml.safe_load(open(config_file))["apirest"]["key"]
|
||||
ips = open(f"tags/{tag}/ips.txt").read().split()
|
||||
settings_file = f"tags/{tag}/settings.yaml"
|
||||
clustersize = yaml.safe_load(open(settings_file))["clustersize"]
|
||||
|
||||
# now do the fucking work
|
||||
while domains and ips:
|
||||
|
||||
@@ -6,8 +6,8 @@ clustersize: 1
|
||||
# The hostname of each node will be clusterprefix + a number
|
||||
clusterprefix: node
|
||||
|
||||
# Jinja2 template to use to generate ready-to-cut cards
|
||||
cards_template: cards.html
|
||||
# Jinja2 template to use to generate ready-to-cut
|
||||
cards_template: clusters.csv
|
||||
|
||||
# Use "Letter" in the US, and "A4" everywhere else
|
||||
paper_size: Letter
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
resource "openstack_compute_instance_v2" "machine" {
|
||||
count = "${var.count}"
|
||||
name = "${format("%s-%04d", "${var.prefix}", count.index+1)}"
|
||||
image_name = "Ubuntu 18.04.4 20200324"
|
||||
image_name = "Ubuntu 16.04.5 (Xenial Xerus)"
|
||||
flavor_name = "${var.flavor}"
|
||||
security_groups = ["${openstack_networking_secgroup_v2.full_access.name}"]
|
||||
key_pair = "${openstack_compute_keypair_v2.ssh_deploy_key.name}"
|
||||
|
||||
@@ -15,6 +15,7 @@ for lib in lib/*.sh; do
|
||||
done
|
||||
|
||||
DEPENDENCIES="
|
||||
aws
|
||||
ssh
|
||||
curl
|
||||
jq
|
||||
|
||||
98
slides/2.yml
98
slides/2.yml
@@ -1,98 +0,0 @@
|
||||
title: |
|
||||
Fondamentaux Kubernetes
|
||||
|
||||
chat: "[Gitter](https://gitter.im/jpetazzo/training-202010-online)"
|
||||
|
||||
gitrepo: github.com/jpetazzo/container.training
|
||||
|
||||
slides: https://2020-10-enix.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-zoom-meeting.md
|
||||
#- shared/chat-room-zoom-webinar.md
|
||||
- shared/toc.md
|
||||
-
|
||||
- shared/prereqs.md
|
||||
#- shared/webssh.md
|
||||
- shared/connecting.md
|
||||
#- k8s/versions-k8s.md
|
||||
- shared/sampleapp.md
|
||||
#- shared/composescale.md
|
||||
#- shared/hastyconclusions.md
|
||||
- shared/composedown.md
|
||||
- k8s/concepts-k8s.md
|
||||
- k8s/kubectlget.md
|
||||
- k8s/kubectl-run.md
|
||||
-
|
||||
- shared/declarative.md
|
||||
- k8s/declarative.md
|
||||
- k8s/deploymentslideshow.md
|
||||
- k8s/kubenet.md
|
||||
- k8s/kubectlexpose.md
|
||||
- k8s/shippingimages.md
|
||||
#- k8s/buildshiprun-selfhosted.md
|
||||
- k8s/buildshiprun-dockerhub.md
|
||||
- k8s/ourapponkube.md
|
||||
#- k8s/exercise-wordsmith.md
|
||||
-
|
||||
- k8s/labels-annotations.md
|
||||
- k8s/kubectl-logs.md
|
||||
- k8s/logs-cli.md
|
||||
- k8s/yamldeploy.md
|
||||
#- k8s/kubectlscale.md
|
||||
- k8s/scalingdockercoins.md
|
||||
- shared/hastyconclusions.md
|
||||
- k8s/daemonset.md
|
||||
-
|
||||
- k8s/rollout.md
|
||||
- k8s/healthchecks.md
|
||||
#- k8s/healthchecks-more.md
|
||||
- k8s/setup-overview.md
|
||||
- k8s/setup-devel.md
|
||||
- k8s/setup-managed.md
|
||||
#- k8s/setup-selfhosted.md
|
||||
-
|
||||
- k8s/namespaces.md
|
||||
- k8s/localkubeconfig.md
|
||||
- k8s/accessinternal.md
|
||||
- k8s/kubectlproxy.md
|
||||
- k8s/dashboard.md
|
||||
- k8s/ingress.md
|
||||
-
|
||||
- k8s/volumes.md
|
||||
#- k8s/exercise-configmap.md
|
||||
#- k8s/build-with-docker.md
|
||||
#- k8s/build-with-kaniko.md
|
||||
- k8s/configuration.md
|
||||
- k8s/batch-jobs.md
|
||||
#- k8s/logs-centralized.md
|
||||
#- k8s/prometheus.md
|
||||
#- k8s/statefulsets.md
|
||||
#- k8s/local-persistent-volumes.md
|
||||
#- k8s/portworx.md
|
||||
#- k8s/extending-api.md
|
||||
#- k8s/operators.md
|
||||
#- k8s/operators-design.md
|
||||
#- k8s/staticpods.md
|
||||
#- k8s/owners-and-dependents.md
|
||||
#- k8s/gitworkflows.md
|
||||
#- k8s/whatsnext.md
|
||||
#- k8s/lastwords.md
|
||||
- shared/thankyou.md
|
||||
- k8s/links.md
|
||||
-
|
||||
- |
|
||||
# (Bonus)
|
||||
- k8s/record.md
|
||||
- k8s/dryrun.md
|
||||
- k8s/ingress-tls.md
|
||||
36
slides/3.yml
36
slides/3.yml
@@ -1,36 +0,0 @@
|
||||
title: |
|
||||
Packaging d'applications
|
||||
pour Kubernetes
|
||||
|
||||
chat: "[Gitter](https://gitter.im/jpetazzo/training-202010-online)"
|
||||
|
||||
gitrepo: github.com/jpetazzo/container.training
|
||||
|
||||
slides: https://2020-10-enix.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-zoom.md
|
||||
- shared/toc.md
|
||||
-
|
||||
- shared/prereqs.md
|
||||
- shared/webssh.md
|
||||
- shared/connecting.md
|
||||
- k8s/kustomize.md
|
||||
- k8s/helm-intro.md
|
||||
- k8s/helm-chart-format.md
|
||||
- k8s/helm-create-basic-chart.md
|
||||
- k8s/helm-create-better-chart.md
|
||||
- k8s/helm-secrets.md
|
||||
#- k8s/exercise-helm.md
|
||||
- shared/thankyou.md
|
||||
- k8s/links.md
|
||||
47
slides/4.yml
47
slides/4.yml
@@ -1,47 +0,0 @@
|
||||
title: |
|
||||
Kubernetes Avancé
|
||||
|
||||
chat: "[Gitter](https://gitter.im/jpetazzo/training-202010-online)"
|
||||
|
||||
gitrepo: github.com/jpetazzo/container.training
|
||||
|
||||
slides: https://2020-10-enix.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-zoom.md
|
||||
- shared/toc.md
|
||||
-
|
||||
- shared/prereqs.md
|
||||
- shared/webssh.md
|
||||
- shared/connecting.md
|
||||
- k8s/netpol.md
|
||||
- k8s/authn-authz.md
|
||||
-
|
||||
- k8s/extending-api.md
|
||||
- k8s/operators.md
|
||||
-
|
||||
- k8s/resource-limits.md
|
||||
- k8s/metrics-server.md
|
||||
- k8s/cluster-sizing.md
|
||||
- k8s/horizontal-pod-autoscaler.md
|
||||
- k8s/prometheus.md
|
||||
-
|
||||
- k8s/statefulsets.md
|
||||
- k8s/local-persistent-volumes.md
|
||||
- k8s/portworx.md
|
||||
- shared/thankyou.md
|
||||
-
|
||||
- |
|
||||
# (Bonus material)
|
||||
- k8s/podsecuritypolicy.md
|
||||
- k8s/operators-design.md
|
||||
48
slides/5.yml
48
slides/5.yml
@@ -1,48 +0,0 @@
|
||||
title: |
|
||||
Opérer Kubernetes
|
||||
|
||||
chat: "[Gitter](https://gitter.im/jpetazzo/training-202010-online)"
|
||||
|
||||
gitrepo: github.com/jpetazzo/container.training
|
||||
|
||||
slides: https://2020-10-enix.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-zoom-meeting.md
|
||||
#- shared/chat-room-zoom-webinar.md
|
||||
- shared/toc.md
|
||||
# DAY 1
|
||||
-
|
||||
- k8s/prereqs-admin.md
|
||||
- k8s/architecture.md
|
||||
- k8s/deploymentslideshow.md
|
||||
- k8s/dmuc.md
|
||||
-
|
||||
- k8s/multinode.md
|
||||
- k8s/cni.md
|
||||
- k8s/interco.md
|
||||
-
|
||||
- k8s/apilb.md
|
||||
- k8s/setup-overview.md
|
||||
- k8s/setup-devel.md
|
||||
- k8s/setup-managed.md
|
||||
- k8s/setup-selfhosted.md
|
||||
- k8s/staticpods.md
|
||||
- k8s/cluster-upgrade.md
|
||||
- k8s/cluster-backup.md
|
||||
#- k8s/cloud-controller-manager.md
|
||||
-
|
||||
- k8s/podsecuritypolicy.md
|
||||
- k8s/csr-api.md
|
||||
- k8s/openid-connect.md
|
||||
- shared/thankyou.md
|
||||
@@ -8,15 +8,16 @@
|
||||
|
||||
#/dockermastery https://www.udemy.com/course/docker-mastery/?referralCode=1410924A733D33635CCB
|
||||
#/kubernetesmastery https://www.udemy.com/course/kubernetesmastery/?referralCode=7E09090AF9B79E6C283F
|
||||
/dockermastery https://www.udemy.com/course/docker-mastery/?couponCode=DOCKERALLDAY
|
||||
/kubernetesmastery https://www.udemy.com/course/kubernetesmastery/?couponCode=DOCKERALLDAY
|
||||
/dockermastery https://www.udemy.com/course/docker-mastery/?couponCode=SWEETFEBSALEC1
|
||||
/kubernetesmastery https://www.udemy.com/course/kubernetesmastery/?couponCode=SWEETFEBSALEC4
|
||||
|
||||
# Shortlink for the QRCode
|
||||
/q /qrcode.html 200
|
||||
|
||||
# Shortlinks for next training in English and French
|
||||
#/next https://www.eventbrite.com/e/livestream-intensive-kubernetes-bootcamp-tickets-103262336428
|
||||
/next https://skillsmatter.com/courses/700-advanced-kubernetes-concepts-workshop-jerome-petazzoni
|
||||
/next https://www.eventbrite.com/e/livestream-intensive-kubernetes-bootcamp-tickets-103262336428
|
||||
/hi5 https://enix.io/fr/services/formation/online/
|
||||
|
||||
/ /highfive.html 200!
|
||||
/ /intro.yml.html 200!
|
||||
/vms https://docs.google.com/spreadsheets/d/1u91MzRvUiZiI55x_sto1kk9LP4QoxqOBjvjhZCeyjU4/edit
|
||||
/chat https://gitter.im/jpetazzo/training-20200707-online
|
||||
|
||||
@@ -233,7 +233,7 @@ def setup_tmux_and_ssh():
|
||||
ipaddr = "$IPADDR"
|
||||
uid = os.getuid()
|
||||
|
||||
raise Exception(r"""
|
||||
raise Exception("""
|
||||
1. If you're running this directly from a node:
|
||||
|
||||
tmux
|
||||
@@ -247,16 +247,6 @@ rm -f /tmp/tmux-{uid}/default && ssh -t -L /tmp/tmux-{uid}/default:/tmp/tmux-100
|
||||
3. If you cannot control a remote tmux:
|
||||
|
||||
tmux new-session ssh docker@{ipaddr}
|
||||
|
||||
4. If you are running this locally with a remote cluster, make sure your prompt has the expected format:
|
||||
|
||||
tmux
|
||||
IPADDR=$(
|
||||
kubectl get nodes -o json |
|
||||
jq -r '.items[0].status.addresses[] | select(.type=="ExternalIP") | .address'
|
||||
)
|
||||
export PS1="\n[{ipaddr}] \u@\h:\w\n\$ "
|
||||
|
||||
""".format(uid=uid, ipaddr=ipaddr))
|
||||
else:
|
||||
logging.info("Found tmux session. Trying to acquire shell prompt.")
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Logging
|
||||
# Logging (extra material)
|
||||
|
||||
In this chapter, we will explain the different ways to send logs from containers.
|
||||
|
||||
|
||||
@@ -95,24 +95,6 @@ $ ssh <login>@<ip-address>
|
||||
|
||||
---
|
||||
|
||||
class: in-person
|
||||
|
||||
## `tailhist`
|
||||
|
||||
The shell history of the instructor is available online in real time.
|
||||
|
||||
Note the IP address of the instructor's virtual machine (A.B.C.D).
|
||||
|
||||
Open http://A.B.C.D:1088 in your browser and you should see the history.
|
||||
|
||||
The history is updated in real time (using a WebSocket connection).
|
||||
|
||||
It should be green when the WebSocket is connected.
|
||||
|
||||
If it turns red, reloading the page should fix it.
|
||||
|
||||
---
|
||||
|
||||
## Checking your Virtual Machine
|
||||
|
||||
Once logged in, make sure that you can run a basic Docker command:
|
||||
|
||||
@@ -1,75 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
<html>
|
||||
<head>
|
||||
<style>
|
||||
td {
|
||||
background: #ccc;
|
||||
padding: 1em;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<table>
|
||||
<tr>
|
||||
<td>Lundi 5 octobre 2020</td>
|
||||
<td>
|
||||
<a href="1.yml.html">Docker Intensif</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Mardi 6 octobre 2020</td>
|
||||
<td>
|
||||
<a href="1.yml.html">Docker Intensif</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Mercredi 7 octobre 2020</td>
|
||||
<td>
|
||||
<a href="2.yml.html">Fondamentaux Kubernetes</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Jeudi 8 octobre 2020</td>
|
||||
<td>
|
||||
<a href="2.yml.html">Fondamentaux Kubernetes</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Vendredi 9 octobre 2020</td>
|
||||
<td>
|
||||
<a href="2.yml.html">Fondamentaux Kubernetes</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Lundi 12 octobre 2020</td>
|
||||
<td>
|
||||
<a href="3.yml.html">Packaging d'applications pour Kubernetes</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Mardi 13 octobre 2020</td>
|
||||
<td>
|
||||
<a href="4.yml.html">Kubernetes Avancé</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Mercredi 14 octobre 2020</td>
|
||||
<td>
|
||||
<a href="4.yml.html">Kubernetes Avancé</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Lundi 19 octobre 2020</td>
|
||||
<td>
|
||||
<a href="5.yml.html">Opérer Kubernetes</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Mardi 20 octobre 2020</td>
|
||||
<td>
|
||||
<a href="5.yml.html">Opérer Kubernetes</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,74 +1,3 @@
|
||||
- date: [2020-10-05, 2020-10-06]
|
||||
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: [2020-10-07, 2020-10-09]
|
||||
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: 2020-10-12
|
||||
country: www
|
||||
city: streaming
|
||||
event: ENIX SAS
|
||||
speaker: jpetazzo
|
||||
title: Packaging pour Kubernetes (en français)
|
||||
lang: fr
|
||||
attend: https://enix.io/fr/services/formation/online/
|
||||
|
||||
- date: [2020-10-13, 2020-10-14]
|
||||
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: [2020-10-19, 2020-10-20]
|
||||
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-09-28, 2020-10-01]
|
||||
country: www
|
||||
city: streaming
|
||||
event: Skills Matter
|
||||
speaker: jpetazzo
|
||||
title: Advanced Kubernetes Concepts
|
||||
attend: https://skillsmatter.com/courses/700-advanced-kubernetes-concepts-workshop-jerome-petazzoni
|
||||
|
||||
- date: [2020-08-29, 2020-08-30]
|
||||
country: www
|
||||
city: streaming
|
||||
event: fwdays
|
||||
speaker: jpetazzo
|
||||
title: Intensive Docker Online Workshop
|
||||
attend: https://fwdays.com/en/event/intensive-docker-workshop
|
||||
slides: https://2020-08-fwdays.container.training/
|
||||
|
||||
- date: [2020-09-12, 2020-09-13]
|
||||
country: www
|
||||
city: streaming
|
||||
event: fwdays
|
||||
speaker: jpetazzo
|
||||
title: Kubernetes Intensive Online Workshop
|
||||
attend: https://fwdays.com/en/event/kubernetes-intensive-workshop
|
||||
slides: https://2020-09-fwdays.container.training/
|
||||
|
||||
- date: [2020-07-07, 2020-07-09]
|
||||
country: www
|
||||
city: streaming
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
title: |
|
||||
Docker Intensif
|
||||
Introduction
|
||||
to Containers
|
||||
|
||||
chat: "[Gitter](https://gitter.im/jpetazzo/training-202010-online)"
|
||||
chat: "[Slack](https://dockercommunity.slack.com/messages/C7GKACWDV)"
|
||||
#chat: "[Gitter](https://gitter.im/jpetazzo/workshop-yyyymmdd-city)"
|
||||
|
||||
gitrepo: github.com/jpetazzo/container.training
|
||||
|
||||
slides: https://2020-10-enix.container.training/
|
||||
slides: http://container.training/
|
||||
|
||||
#slidenumberprefix: "#SomeHashTag — "
|
||||
|
||||
@@ -42,8 +44,8 @@ content:
|
||||
-
|
||||
- containers/Container_Networking_Basics.md
|
||||
#- containers/Network_Drivers.md
|
||||
#- containers/Container_Network_Model.md
|
||||
- containers/Local_Development_Workflow.md
|
||||
- containers/Container_Network_Model.md
|
||||
- containers/Compose_For_Dev_Stacks.md
|
||||
- containers/Exercise_Composefile.md
|
||||
-
|
||||
@@ -63,5 +65,6 @@ content:
|
||||
#- containers/Pods_Anatomy.md
|
||||
#- containers/Ecosystem.md
|
||||
#- containers/Orchestration_Overview.md
|
||||
-
|
||||
- shared/thankyou.md
|
||||
- containers/links.md
|
||||
70
slides/intro-selfpaced.yml
Normal file
70
slides/intro-selfpaced.yml
Normal file
@@ -0,0 +1,70 @@
|
||||
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-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
|
||||
71
slides/intro.yml
Normal file
71
slides/intro.yml
Normal file
@@ -0,0 +1,71 @@
|
||||
title: |
|
||||
Intensive
|
||||
Docker
|
||||
Bootcamp
|
||||
|
||||
#chat: "[Slack](https://dockercommunity.slack.com/messages/C7GKACWDV)"
|
||||
chat: "[Gitter](https://gitter.im/jpetazzo/training-20200707-online)"
|
||||
|
||||
gitrepo: github.com/jpetazzo/container.training
|
||||
|
||||
slides: https://2020-07-ardan.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-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
|
||||
- # DAY 2
|
||||
- containers/Publishing_To_Docker_Hub.md
|
||||
- containers/Naming_And_Inspecting.md
|
||||
- containers/Labels.md
|
||||
- containers/Start_And_Attach.md
|
||||
- containers/Getting_Inside.md
|
||||
- containers/Resource_Limits.md
|
||||
-
|
||||
- containers/Dockerfile_Tips.md
|
||||
- containers/Multi_Stage_Builds.md
|
||||
- containers/Advanced_Dockerfiles.md
|
||||
- containers/Exercise_Dockerfile_Advanced.md
|
||||
- # DAY 3
|
||||
- containers/Container_Networking_Basics.md
|
||||
- containers/Network_Drivers.md
|
||||
- containers/Container_Network_Model.md
|
||||
-
|
||||
- containers/Local_Development_Workflow.md
|
||||
- containers/Compose_For_Dev_Stacks.md
|
||||
- containers/Exercise_Composefile.md
|
||||
- containers/Logging.md
|
||||
#- containers/Working_With_Volumes.md
|
||||
#- containers/Application_Configuration.md
|
||||
- shared/thankyou.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
|
||||
@@ -118,7 +118,7 @@
|
||||
|
||||
- [HTTP basic auth](https://en.wikipedia.org/wiki/Basic_access_authentication)
|
||||
|
||||
(carrying user and password in an HTTP header; [deprecated since Kubernetes 1.19](https://github.com/kubernetes/kubernetes/pull/89069))
|
||||
(carrying user and password in an HTTP header)
|
||||
|
||||
- Authentication proxy
|
||||
|
||||
@@ -749,7 +749,7 @@ class: extra-details
|
||||
|
||||
:EN:- Authentication and authorization in Kubernetes
|
||||
:EN:- Authentication with tokens and certificates
|
||||
:EN:- Authorization with RBAC (Role-Based Access Control)
|
||||
:EN:- Aithorization with RBAC (Role-Based Access Control)
|
||||
:EN:- Restricting permissions with Service Accounts
|
||||
:EN:- Working with Roles, Cluster Roles, Role Bindings, etc.
|
||||
|
||||
|
||||
@@ -176,8 +176,12 @@ class: extra-details
|
||||
|
||||
- can't express parallelism or completions of Jobs
|
||||
|
||||
- can't express Pods with multiple containers
|
||||
|
||||
- can't express healthchecks, resource limits
|
||||
|
||||
- etc.
|
||||
|
||||
- `kubectl create` and `kubectl run` are *helpers* that generate YAML manifests
|
||||
|
||||
- If we write these manifests ourselves, we can use all features and options
|
||||
|
||||
@@ -210,8 +210,6 @@
|
||||
|
||||
(through files that get created in the container filesystem)
|
||||
|
||||
- That second link also includes a list of all the fields that can be used with the downward API
|
||||
|
||||
---
|
||||
|
||||
## Environment variables, pros and cons
|
||||
@@ -536,8 +534,6 @@ spec:
|
||||
|
||||
---
|
||||
|
||||
class: extra-details
|
||||
|
||||
## Differences between configmaps and secrets
|
||||
|
||||
- Secrets are base64-encoded when shown with `kubectl get secrets -o yaml`
|
||||
@@ -552,29 +548,6 @@ class: extra-details
|
||||
|
||||
(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
|
||||
|
||||
@@ -52,7 +52,7 @@
|
||||
|
||||
<!-- ##VERSION## -->
|
||||
|
||||
- Unfortunately, as of Kubernetes 1.19, the CLI cannot create daemon sets
|
||||
- Unfortunately, as of Kubernetes 1.17, the CLI cannot create daemon sets
|
||||
|
||||
--
|
||||
|
||||
|
||||
@@ -1,403 +0,0 @@
|
||||
# Ingress and TLS certificates
|
||||
|
||||
- Most ingress controllers support TLS connections
|
||||
|
||||
(in a way that is standard across controllers)
|
||||
|
||||
- The TLS key and certificate are stored in a Secret
|
||||
|
||||
- The Secret is then referenced in the Ingress resource:
|
||||
```yaml
|
||||
spec:
|
||||
tls:
|
||||
- secretName: XXX
|
||||
hosts:
|
||||
- YYY
|
||||
rules:
|
||||
- ZZZ
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Obtaining a certificate
|
||||
|
||||
- In the next section, we will need a TLS key and certificate
|
||||
|
||||
- These usually come in [PEM](https://en.wikipedia.org/wiki/Privacy-Enhanced_Mail) format:
|
||||
```
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDATCCAemg...
|
||||
...
|
||||
-----END CERTIFICATE-----
|
||||
```
|
||||
|
||||
- We will see how to generate a self-signed certificate
|
||||
|
||||
(easy, fast, but won't be recognized by web browsers)
|
||||
|
||||
- We will also see how to obtain a certificate from [Let's Encrypt](https://letsencrypt.org/)
|
||||
|
||||
(requires the cluster to be reachable through a domain name)
|
||||
|
||||
---
|
||||
|
||||
class: extra-details
|
||||
|
||||
## In production ...
|
||||
|
||||
- A very popular option is to use the [cert-manager](https://cert-manager.io/docs/) operator
|
||||
|
||||
- It's a flexible, modular approach to automated certificate management
|
||||
|
||||
- For simplicity, in this section, we will use [certbot](https://certbot.eff.org/)
|
||||
|
||||
- The method shown here works well for one-time certs, but lacks:
|
||||
|
||||
- automation
|
||||
|
||||
- renewal
|
||||
|
||||
---
|
||||
|
||||
## Which domain to use
|
||||
|
||||
- If you're doing this in a training:
|
||||
|
||||
*the instructor will tell you what to use*
|
||||
|
||||
- If you're doing this on your own Kubernetes cluster:
|
||||
|
||||
*you should use a domain that points to your cluster*
|
||||
|
||||
- More precisely:
|
||||
|
||||
*you should use a domain that points to your ingress controller*
|
||||
|
||||
- If you don't have a domain name, you can use [nip.io](https://nip.io/)
|
||||
|
||||
(if your ingress controller is on 1.2.3.4, you can use `whatever.1.2.3.4.nip.io`)
|
||||
|
||||
---
|
||||
|
||||
## Setting `$DOMAIN`
|
||||
|
||||
- We will use `$DOMAIN` in the following section
|
||||
|
||||
- Let's set it now
|
||||
|
||||
.exercise[
|
||||
|
||||
- Set the `DOMAIN` environment variable:
|
||||
```bash
|
||||
export DOMAIN=...
|
||||
```
|
||||
|
||||
]
|
||||
|
||||
---
|
||||
|
||||
## Method 1, self-signed certificate
|
||||
|
||||
- Thanks to `openssl`, generating a self-signed cert is just one command away!
|
||||
|
||||
.exercise[
|
||||
|
||||
- Generate a key and certificate:
|
||||
```bash
|
||||
openssl req \
|
||||
-newkey rsa -nodes -keyout privkey.pem \
|
||||
-x509 -days 30 -subj /CN=$DOMAIN/ -out cert.pem
|
||||
```
|
||||
|
||||
]
|
||||
|
||||
This will create two files, `privkey.pem` and `cert.pem`.
|
||||
|
||||
---
|
||||
|
||||
## Method 2, Let's Encrypt with certbot
|
||||
|
||||
- `certbot` is an [ACME](https://tools.ietf.org/html/rfc8555) client
|
||||
|
||||
(Automatic Certificate Management Environment)
|
||||
|
||||
- We can use it to obtain certificates from Let's Encrypt
|
||||
|
||||
- It needs to listen to port 80
|
||||
|
||||
(to complete the [HTTP-01 challenge](https://letsencrypt.org/docs/challenge-types/))
|
||||
|
||||
- If port 80 is already taken by our ingress controller, see method 3
|
||||
|
||||
---
|
||||
|
||||
class: extra-details
|
||||
|
||||
## HTTP-01 challenge
|
||||
|
||||
- `certbot` contacts Let's Encrypt, asking for a cert for `$DOMAIN`
|
||||
|
||||
- Let's Encrypt gives a token to `certbot`
|
||||
|
||||
- Let's Encrypt then tries to access the following URL:
|
||||
|
||||
`http://$DOMAIN/.well-known/acme-challenge/<token>`
|
||||
|
||||
- That URL needs to be routed to `certbot`
|
||||
|
||||
- Once Let's Encrypt gets the response from `certbot`, it issues the certificate
|
||||
|
||||
---
|
||||
|
||||
## Running certbot
|
||||
|
||||
- There is a very convenient container image, `certbot/certbot`
|
||||
|
||||
- Let's use a volume to get easy access to the generated key and certificate
|
||||
|
||||
.exercise[
|
||||
|
||||
- Obtain a certificate from Let's Encrypt:
|
||||
```bash
|
||||
EMAIL=your.address@example.com
|
||||
docker run --rm -p 80:80 -v $PWD/letsencrypt:/etc/letsencrypt \
|
||||
certbot/certbot certonly \
|
||||
-m $EMAIL \
|
||||
--standalone --agree-tos -n \
|
||||
--domain $DOMAIN \
|
||||
--test-cert
|
||||
```
|
||||
|
||||
]
|
||||
|
||||
This will get us a "staging" certificate.
|
||||
Remove `--test-cert` to obtain a *real* certificate.
|
||||
|
||||
---
|
||||
|
||||
## Copying the key and certificate
|
||||
|
||||
- If everything went fine:
|
||||
|
||||
- the key and certificate files are in `letsencrypt/live/$DOMAIN`
|
||||
|
||||
- they are owned by `root`
|
||||
|
||||
.exercise[
|
||||
|
||||
- Grant ourselves permissions on these files:
|
||||
```bash
|
||||
sudo chown -R $USER letsencrypt
|
||||
```
|
||||
|
||||
- Copy the certificate and key to the current directory:
|
||||
```bash
|
||||
cp letsencrypt/live/test/{cert,privkey}.pem .
|
||||
```
|
||||
|
||||
]
|
||||
|
||||
---
|
||||
|
||||
## Method 3, certbot with Ingress
|
||||
|
||||
- Sometimes, we can't simply listen to port 80:
|
||||
|
||||
- we might already have an ingress controller there
|
||||
- our nodes might be on an internal network
|
||||
|
||||
- But we can define an Ingress to route the HTTP-01 challenge to `certbot`!
|
||||
|
||||
- Our Ingress needs to route all requests to `/.well-known/acme-challenge` to `certbot`
|
||||
|
||||
- There are at least two ways to do that:
|
||||
|
||||
- run `certbot` in a Pod (and extract the cert+key when it's done)
|
||||
- run `certbot` in a container on a node (and manually route traffic to it)
|
||||
|
||||
- We're going to use the second option
|
||||
|
||||
(mostly because it will give us an excuse to tinker with Endpoints resources!)
|
||||
|
||||
---
|
||||
|
||||
## The plan
|
||||
|
||||
- We need the following resources:
|
||||
|
||||
- an Endpoints¹ listing a hard-coded IP address and port
|
||||
<br/>(where our `certbot` container will be listening)
|
||||
|
||||
- a Service corresponding to that Endpoints
|
||||
|
||||
- an Ingress sending requests to `/.well-known/acme-challenge/*` to that Service
|
||||
<br/>(we don't even need to include a domain name in it)
|
||||
|
||||
- Then we need to start `certbot` so that it's listening on the right address+port
|
||||
|
||||
.footnote[¹Endpoints is always plural, because even a single resource is a list of endpoints.]
|
||||
|
||||
---
|
||||
|
||||
## Creating resources
|
||||
|
||||
- We prepared a YAML file to create the three resources
|
||||
|
||||
- However, the Endpoints needs to be adapted to put the current node's address
|
||||
|
||||
.exercise[
|
||||
|
||||
- Edit `~/containers.training/k8s/certbot.yaml`
|
||||
|
||||
(replace `A.B.C.D` with the current node's address)
|
||||
|
||||
- Create the resources:
|
||||
```bash
|
||||
kubectl apply -f ~/containers.training/k8s/certbot.yaml
|
||||
```
|
||||
|
||||
]
|
||||
|
||||
---
|
||||
|
||||
## Obtaining the certificate
|
||||
|
||||
- Now we can run `certbot`, listening on the port listed in the Endpoints
|
||||
|
||||
(i.e. 8000)
|
||||
|
||||
.exercise[
|
||||
|
||||
- Run `certbot`:
|
||||
```bash
|
||||
EMAIL=your.address@example.com
|
||||
docker run --rm -p 8000:80 -v $PWD/letsencrypt:/etc/letsencrypt \
|
||||
certbot/certbot certonly \
|
||||
-m $EMAIL \
|
||||
--standalone --agree-tos -n \
|
||||
--domain $DOMAIN \
|
||||
--test-cert
|
||||
```
|
||||
|
||||
]
|
||||
|
||||
This is using the staging environment.
|
||||
Remove `--test-cert` to get a production certificate.
|
||||
|
||||
---
|
||||
|
||||
## Copying the certificate
|
||||
|
||||
- Just like in the previous method, the certificate is in `letsencrypt/live/$DOMAIN`
|
||||
|
||||
(and owned by root)
|
||||
|
||||
.exercise[
|
||||
|
||||
- Grand ourselves permissions on these files:
|
||||
```bash
|
||||
sudo chown -R $USER letsencrypt
|
||||
```
|
||||
|
||||
- Copy the certificate and key to the current directory:
|
||||
```bash
|
||||
cp letsencrypt/live/$DOMAIN/{cert,privkey}.pem .
|
||||
```
|
||||
|
||||
]
|
||||
|
||||
---
|
||||
|
||||
## Creating the Secret
|
||||
|
||||
- We now have two files:
|
||||
|
||||
- `privkey.pem` (the private key)
|
||||
|
||||
- `cert.pem` (the certificate)
|
||||
|
||||
- We can create a Secret to hold them
|
||||
|
||||
.exercise[
|
||||
|
||||
- Create the Secret:
|
||||
```bash
|
||||
kubectl create secret tls $DOMAIN --cert=cert.pem --key=privkey.pem
|
||||
```
|
||||
|
||||
]
|
||||
|
||||
---
|
||||
|
||||
## Ingress with TLS
|
||||
|
||||
- To enable TLS for an Ingress, we need to add a `tls` section to the Ingress:
|
||||
|
||||
```yaml
|
||||
spec:
|
||||
tls:
|
||||
- secretName: DOMAIN
|
||||
hosts:
|
||||
- DOMAIN
|
||||
rules: ...
|
||||
```
|
||||
|
||||
- The list of hosts will be used by the ingress controller
|
||||
|
||||
(to know which certificate to use with [SNI](https://en.wikipedia.org/wiki/Server_Name_Indication))
|
||||
|
||||
- Of course, the name of the secret can be different
|
||||
|
||||
(here, for clarity and convenience, we set it to match the domain)
|
||||
|
||||
---
|
||||
|
||||
class: extra-details
|
||||
|
||||
## About the ingress controller
|
||||
|
||||
- Many ingress controllers can use different "stores" for keys and certificates
|
||||
|
||||
- Our ingress controller needs to be configured to use secrets
|
||||
|
||||
(as opposed to, e.g., obtain certificates directly with Let's Encrypt)
|
||||
|
||||
---
|
||||
|
||||
## Using the certificate
|
||||
|
||||
.exercise[
|
||||
|
||||
- Edit the Ingress manifest, `~/container.training/k8s/ingress.yaml`
|
||||
|
||||
- Uncomment the `tls` section
|
||||
|
||||
- Update the `secretName` and `hosts` list
|
||||
|
||||
- Create or update the Ingress:
|
||||
```bash
|
||||
kubectl apply -f ~/container.training/k8s/ingress.yaml
|
||||
```
|
||||
|
||||
- Check that the URL now works over `https`
|
||||
|
||||
(it might take a minute to be picked up by the ingress controller)
|
||||
|
||||
]
|
||||
|
||||
---
|
||||
|
||||
## Discussion
|
||||
|
||||
*To repeat something mentioned earlier ...*
|
||||
|
||||
- The methods presented here are for *educational purpose only*
|
||||
|
||||
- In most production scenarios, the certificates will be obtained automatically
|
||||
|
||||
- A very popular option is to use the [cert-manager](https://cert-manager.io/docs/) operator
|
||||
|
||||
???
|
||||
|
||||
:EN:- Ingress and TLS
|
||||
:FR:- Certificats TLS et *ingress*
|
||||
@@ -485,8 +485,6 @@ spec:
|
||||
|
||||
---
|
||||
|
||||
class: extra-details
|
||||
|
||||
## Using multiple ingress controllers
|
||||
|
||||
- You can have multiple ingress controllers active simultaneously
|
||||
@@ -497,13 +495,11 @@ class: extra-details
|
||||
|
||||
(e.g. one for internal, another for external traffic)
|
||||
|
||||
- To indicate which ingress controller should be used by a given Ingress resouce:
|
||||
- The `kubernetes.io/ingress.class` annotation can be used to tell which one to use
|
||||
|
||||
- before Kubernetes 1.18, use the `kubernetes.io/ingress.class` annotation
|
||||
- It's OK if multiple ingress controllers configure the same resource
|
||||
|
||||
- since Kubernetes 1.18, use the `ingressClassName` field
|
||||
<br/>
|
||||
(which should refer to an existing `IngressClass` resource)
|
||||
(it just means that the service will be accessible through multiple paths)
|
||||
|
||||
---
|
||||
|
||||
@@ -539,9 +535,9 @@ class: extra-details
|
||||
|
||||
- [ingress.kubernetes.io/rewrite-target: /](https://github.com/kubernetes/contrib/tree/master/ingress/controllers/nginx/examples/rewrite)
|
||||
|
||||
- The Ingress spec stabilized in Kubernetes 1.19 ...
|
||||
- This should eventually stabilize
|
||||
|
||||
... without specifying these features! 😭
|
||||
(remember that ingresses are currently `apiVersion: networking.k8s.io/v1beta1`)
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -296,7 +296,7 @@ class: extra-details
|
||||
|
||||
- When using `kubectl create deployment`, we cannot indicate the command to execute
|
||||
|
||||
(at least, not in Kubernetes 1.18; but that changed in Kubernetes 1.19)
|
||||
(at least, not in Kubernetes 1.18)
|
||||
|
||||
- We can:
|
||||
|
||||
@@ -338,25 +338,12 @@ class: extra-details
|
||||
kubectl get all
|
||||
```
|
||||
|
||||
<!-- ```hide kubectl wait pod --selector=app=pingpong --for condition=ready ``` -->
|
||||
<!-- ```hide kubectl wait pod --selector=run=pingpong --for condition=ready ``` -->
|
||||
|
||||
]
|
||||
|
||||
---
|
||||
|
||||
class: extra-details
|
||||
|
||||
## In Kubernetes 1.19
|
||||
|
||||
- Since Kubernetes 1.19, we can specify the command to run
|
||||
|
||||
- The command must be passed after two dashes:
|
||||
```bash
|
||||
kubectl create deployment pingpong --image=alpine -- ping 127.1
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Viewing container output
|
||||
|
||||
- Let's use the `kubectl logs` command
|
||||
@@ -507,7 +494,9 @@ We'll see later how to address that shortcoming.
|
||||
```key ^J```
|
||||
```check```
|
||||
```key ^D```
|
||||
```tmux select-pane -t 1```
|
||||
```key ^C```
|
||||
```key ^D```
|
||||
-->
|
||||
|
||||
]
|
||||
|
||||
@@ -149,28 +149,6 @@
|
||||
|
||||
---
|
||||
|
||||
class: extra-details
|
||||
|
||||
## Supporting other CPU architectures
|
||||
|
||||
- The `jpetazzo/httpenv` image is currently only available for `x86_64`
|
||||
|
||||
(the "classic" Intel 64 bits architecture found on most PCs and Macs)
|
||||
|
||||
- That image won't work on other architectures
|
||||
|
||||
(e.g. Raspberry Pi or other ARM-based machines)
|
||||
|
||||
- Note that Docker supports [multi-arch](https://www.docker.com/blog/multi-arch-build-and-images-the-simple-way/) images
|
||||
|
||||
(so *technically* we could make it work across multiple architectures)
|
||||
|
||||
- If you want to build `httpenv` for your own platform, here is the source:
|
||||
|
||||
https://github.com/jpetazzo/httpenv
|
||||
|
||||
---
|
||||
|
||||
## Creating a deployment for our HTTP server
|
||||
|
||||
- We will create a deployment with `kubectl create deployment`
|
||||
|
||||
@@ -191,8 +191,6 @@ are a few tools that can help us.*
|
||||
|
||||
## Developer experience
|
||||
|
||||
*These questions constitute a quick "smoke test" for our strategy:*
|
||||
|
||||
- How do we on-board a new developer?
|
||||
|
||||
- What do they need to install to get a dev stack?
|
||||
@@ -201,6 +199,8 @@ are a few tools that can help us.*
|
||||
|
||||
- How does someone add a component to a stack?
|
||||
|
||||
*These questions are good "sanity checks" to validate our strategy!*
|
||||
|
||||
---
|
||||
|
||||
## Some guidelines
|
||||
|
||||
@@ -58,7 +58,7 @@
|
||||
|
||||
## Deploying Consul
|
||||
|
||||
- Let's use a new manifest for our Consul cluster
|
||||
- We will use a slightly different YAML file
|
||||
|
||||
- The only differences between that file and the previous one are:
|
||||
|
||||
@@ -66,11 +66,15 @@
|
||||
|
||||
- the corresponding `volumeMounts` in the Pod spec
|
||||
|
||||
- the label `consul` has been changed to `persistentconsul`
|
||||
<br/>
|
||||
(to avoid conflicts with the other Stateful Set)
|
||||
|
||||
.exercise[
|
||||
|
||||
- Apply the persistent Consul YAML file:
|
||||
```bash
|
||||
kubectl apply -f ~/container.training/k8s/consul-3.yaml
|
||||
kubectl apply -f ~/container.training/k8s/persistent-consul.yaml
|
||||
```
|
||||
|
||||
]
|
||||
@@ -93,7 +97,7 @@
|
||||
kubectl get pv
|
||||
```
|
||||
|
||||
- The Pod `consul-0` is not scheduled yet:
|
||||
- The Pod `persistentconsul-0` is not scheduled yet:
|
||||
```bash
|
||||
kubectl get pods -o wide
|
||||
```
|
||||
@@ -108,9 +112,9 @@
|
||||
|
||||
- In a Stateful Set, the Pods are started one by one
|
||||
|
||||
- `consul-1` won't be created until `consul-0` is running
|
||||
- `persistentconsul-1` won't be created until `persistentconsul-0` is running
|
||||
|
||||
- `consul-0` has a dependency on an unbound Persistent Volume Claim
|
||||
- `persistentconsul-0` has a dependency on an unbound Persistent Volume Claim
|
||||
|
||||
- The scheduler won't schedule the Pod until the PVC is bound
|
||||
|
||||
@@ -148,7 +152,7 @@
|
||||
|
||||
- Once a PVC is bound, its pod can start normally
|
||||
|
||||
- Once the pod `consul-0` has started, `consul-1` can be created, etc.
|
||||
- Once the pod `persistentconsul-0` has started, `persistentconsul-1` can be created, etc.
|
||||
|
||||
- Eventually, our Consul cluster is up, and backend by "persistent" volumes
|
||||
|
||||
@@ -156,7 +160,7 @@
|
||||
|
||||
- Check that our Consul clusters has 3 members indeed:
|
||||
```bash
|
||||
kubectl exec consul-0 -- consul members
|
||||
kubectl exec persistentconsul-0 consul members
|
||||
```
|
||||
|
||||
]
|
||||
|
||||
@@ -34,11 +34,11 @@
|
||||
|
||||
- Download the `kubectl` binary from one of these links:
|
||||
|
||||
[Linux](https://storage.googleapis.com/kubernetes-release/release/v1.19.2/bin/linux/amd64/kubectl)
|
||||
[Linux](https://storage.googleapis.com/kubernetes-release/release/v1.15.3/bin/linux/amd64/kubectl)
|
||||
|
|
||||
[macOS](https://storage.googleapis.com/kubernetes-release/release/v1.19.2/bin/darwin/amd64/kubectl)
|
||||
[macOS](https://storage.googleapis.com/kubernetes-release/release/v1.15.3/bin/darwin/amd64/kubectl)
|
||||
|
|
||||
[Windows](https://storage.googleapis.com/kubernetes-release/release/v1.19.2/bin/windows/amd64/kubectl.exe)
|
||||
[Windows](https://storage.googleapis.com/kubernetes-release/release/v1.15.3/bin/windows/amd64/kubectl.exe)
|
||||
|
||||
- On Linux and macOS, make the binary executable with `chmod +x kubectl`
|
||||
|
||||
|
||||
@@ -76,7 +76,7 @@ Exactly what we need!
|
||||
sudo chmod +x /usr/local/bin/stern
|
||||
```
|
||||
|
||||
- On macOS, we can also `brew install stern` or `sudo port install stern`
|
||||
- On macOS, we can also `brew install stern` or `port install stern`
|
||||
|
||||
<!-- ##VERSION## -->
|
||||
|
||||
|
||||
@@ -431,13 +431,13 @@ troubleshoot easily, without having to poke holes in our firewall.
|
||||
|
||||
- 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## -->
|
||||
- The API documentation has a lot of detail about the format of various objects:
|
||||
|
||||
- [NetworkPolicy](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.19/#networkpolicy-v1-networking-k8s-io)
|
||||
- [NetworkPolicy](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.12/#networkpolicy-v1-networking-k8s-io)
|
||||
|
||||
- [NetworkPolicySpec](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.19/#networkpolicyspec-v1-networking-k8s-io)
|
||||
- [NetworkPolicySpec](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.12/#networkpolicyspec-v1-networking-k8s-io)
|
||||
|
||||
- [NetworkPolicyIngressRule](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.19/#networkpolicyingressrule-v1-networking-k8s-io)
|
||||
- [NetworkPolicyIngressRule](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.12/#networkpolicyingressrule-v1-networking-k8s-io)
|
||||
|
||||
- etc.
|
||||
|
||||
|
||||
@@ -387,7 +387,7 @@ spec:
|
||||
|
||||
- Get a shell in the pod, as the `postgres` user:
|
||||
```bash
|
||||
kubectl exec -ti postgres-0 -- su postgres
|
||||
kubectl exec -ti postgres-0 su postgres
|
||||
```
|
||||
|
||||
<!--
|
||||
@@ -577,7 +577,7 @@ By "disrupt" we mean: "disconnect it from the network".
|
||||
|
||||
- Get a shell on the pod:
|
||||
```bash
|
||||
kubectl exec -ti postgres-0 -- su postgres
|
||||
kubectl exec -ti postgres-0 su postgres
|
||||
```
|
||||
|
||||
<!--
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
|
||||
- They are stopped in reverse order (from *R-1* to 0)
|
||||
|
||||
- Each pod knows its identity (i.e. which number it is in the set)
|
||||
- Each pod know its identity (i.e. which number it is in the set)
|
||||
|
||||
- Each pod can discover the IP address of the others easily
|
||||
|
||||
@@ -218,9 +218,7 @@ consul agent -data-dir=/consul/data -client=0.0.0.0 -server -ui \
|
||||
|
||||
- Replace X.X.X.X and Y.Y.Y.Y with the addresses of other nodes
|
||||
|
||||
- A node can add its own address (it will work fine)
|
||||
|
||||
- ... Which means that we can use the same command-line on all nodes (convenient!)
|
||||
- The same command-line can be used on all nodes (convenient!)
|
||||
|
||||
---
|
||||
|
||||
@@ -260,13 +258,19 @@ consul agent -data-dir=/consul/data -client=0.0.0.0 -server -ui \
|
||||
|
||||
## Putting it all together
|
||||
|
||||
- The file `k8s/consul-1.yaml` defines the required resources
|
||||
- The file `k8s/consul.yaml` defines the required resources
|
||||
|
||||
(service account, role, role binding, service, stateful set)
|
||||
(service account, cluster role, cluster role binding, service, stateful set)
|
||||
|
||||
- Inspired by this [excellent tutorial](https://github.com/kelseyhightower/consul-on-kubernetes) by Kelsey Hightower
|
||||
- It has a few extra touches:
|
||||
|
||||
(many features from the original tutorial were removed for simplicity)
|
||||
- a `podAntiAffinity` prevents two pods from running on the same node
|
||||
|
||||
- a `preStop` hook makes the pod leave the cluster when shutdown gracefully
|
||||
|
||||
This was inspired by this [excellent tutorial](https://github.com/kelseyhightower/consul-on-kubernetes) by Kelsey Hightower.
|
||||
Some features from the original tutorial (TLS authentication between
|
||||
nodes and encryption of gossip traffic) were removed for simplicity.
|
||||
|
||||
---
|
||||
|
||||
@@ -278,7 +282,7 @@ consul agent -data-dir=/consul/data -client=0.0.0.0 -server -ui \
|
||||
|
||||
- Create the stateful set and associated service:
|
||||
```bash
|
||||
kubectl apply -f ~/container.training/k8s/consul-1.yaml
|
||||
kubectl apply -f ~/container.training/k8s/consul.yaml
|
||||
```
|
||||
|
||||
- Check the logs as the pods come up one after another:
|
||||
@@ -293,7 +297,7 @@ consul agent -data-dir=/consul/data -client=0.0.0.0 -server -ui \
|
||||
|
||||
- Check the health of the cluster:
|
||||
```bash
|
||||
kubectl exec consul-0 -- consul members
|
||||
kubectl exec consul-0 consul members
|
||||
```
|
||||
|
||||
]
|
||||
@@ -302,88 +306,6 @@ consul agent -data-dir=/consul/data -client=0.0.0.0 -server -ui \
|
||||
|
||||
## Caveats
|
||||
|
||||
- The scheduler may place two Consul pods on the same node
|
||||
|
||||
- if that node fails, we lose two Consul pods at the same time
|
||||
- this will cause the cluster to fail
|
||||
|
||||
- Scaling down the cluster will cause it to fail
|
||||
|
||||
- when a Consul member leaves the cluster, it needs to inform the others
|
||||
- otherwise, the last remaining node doesn't have quorum and stops functioning
|
||||
|
||||
- This Consul cluster doesn't use real persistence yet
|
||||
|
||||
- data is stored in the containers' ephemeral filesystem
|
||||
- if a pod fails, its replacement starts from a blank slate
|
||||
|
||||
---
|
||||
|
||||
## Improving pod placement
|
||||
|
||||
- We need to tell the scheduler:
|
||||
|
||||
*do not put two of these pods on the same node!*
|
||||
|
||||
- This is done with an `affinity` section like the following one:
|
||||
```yaml
|
||||
affinity:
|
||||
podAntiAffinity:
|
||||
requiredDuringSchedulingIgnoredDuringExecution:
|
||||
- labelSelector:
|
||||
matchExpressions:
|
||||
- key: app
|
||||
operator: In
|
||||
values:
|
||||
- consul
|
||||
topologyKey: kubernetes.io/hostname
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Using a lifecycle hook
|
||||
|
||||
- When a Consul member leaves the cluster, it needs to execute:
|
||||
```bash
|
||||
consul leave
|
||||
```
|
||||
|
||||
- This is done with a `lifecycle` section like the following one:
|
||||
```yaml
|
||||
lifecycle:
|
||||
preStop:
|
||||
exec:
|
||||
command:
|
||||
- /bin/sh
|
||||
- -c
|
||||
- consul leave
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Running a better Consul cluster
|
||||
|
||||
- Let's try to add the scheduling constraint and lifecycle hook
|
||||
|
||||
- We can do that in the same namespace or another one (as we like)
|
||||
|
||||
- If we do that in the same namespace, we will see a rolling update
|
||||
|
||||
(pods will be replaced one by one)
|
||||
|
||||
.exercise[
|
||||
|
||||
- Deploy a better Consul cluster:
|
||||
```bash
|
||||
kubectl apply -f ~/container.training/k8s/consul-2.yaml
|
||||
```
|
||||
|
||||
]
|
||||
|
||||
---
|
||||
|
||||
## Still no persistence, though
|
||||
|
||||
- We aren't using actual persistence yet
|
||||
|
||||
(no `volumeClaimTemplate`, Persistent Volume, etc.)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
## Versions installed
|
||||
|
||||
- Kubernetes 1.92.2
|
||||
- Docker Engine 19.03.13
|
||||
- Kubernetes 1.18.0
|
||||
- Docker Engine 19.03.8
|
||||
- Docker Compose 1.25.4
|
||||
|
||||
<!-- ##VERSION## -->
|
||||
|
||||
@@ -1,15 +1,19 @@
|
||||
## Intros
|
||||
|
||||
- Hello! We are:
|
||||
- Hello! I'm Jérôme Petazzoni ([@jpetazzo](https://twitter.com/jpetazzo))
|
||||
|
||||
- .emoji[👷🏻♀️] AJ ([@s0ulshake](https://twitter.com/s0ulshake), [EphemeraSearch](https://www.ephemerasearch.com/))
|
||||
- The training will run Tue/Wed/Thu:
|
||||
|
||||
- .emoji[🐳] Jérôme ([@jpetazzo](https://twitter.com/jpetazzo), Enix SAS)
|
||||
- 9am-1pm PDT (aka Pacific)
|
||||
- noon-4pm EDT (aka Eastern)
|
||||
- 6pm-10pm CEST (aka Europe)
|
||||
|
||||
- The training will run from 9:30 to 13:00
|
||||
- There will be short breaks every hour
|
||||
|
||||
- There will be a break at (approximately) 11:00
|
||||
(And a longer break every two hours)
|
||||
|
||||
- Feel free to interrupt for questions at any time
|
||||
|
||||
- *Especially when you see full screen container pictures!*
|
||||
|
||||
- Live feedback, questions, help: @@CHAT@@
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
|
||||
(then open the file `@@HTML@@`)
|
||||
|
||||
- You will find new versions of these slides on:
|
||||
- You will to find new versions of these slides on:
|
||||
|
||||
https://container.training/
|
||||
|
||||
|
||||
@@ -34,26 +34,6 @@ If anything goes wrong — ask for help!
|
||||
|
||||
---
|
||||
|
||||
class: in-person
|
||||
|
||||
## `tailhist`
|
||||
|
||||
- The shell history of the instructor is available online in real time
|
||||
|
||||
- Note the IP address of the instructor's virtual machine (A.B.C.D)
|
||||
|
||||
- Open http://A.B.C.D:1088 in your browser and you should see the history
|
||||
|
||||
- The history is updated in real time
|
||||
|
||||
(using a WebSocket connection)
|
||||
|
||||
- It should be green when the WebSocket is connected
|
||||
|
||||
(if it turns red, reloading the page should fix it)
|
||||
|
||||
---
|
||||
|
||||
## Doing or re-doing the workshop on your own?
|
||||
|
||||
- Use something like
|
||||
|
||||
Reference in New Issue
Block a user