Co Kubernetes je, jak to funguje, jak to použít
Celou prezentaci a další materiály najdete na https://github.com/che0/kubernetes-workshop
Tvoří image a pouští kontejnery
docker run -ti --rm ubuntu /bin/bashdocker run -ti --rm debian grep ^deb /etc/apt/sources.listdocker run --name databaze --rm mariadbdocker run -ti --rm -v "$(pwd)/php-site:/var/www/html" -p 8000:80 php:7.2-apachedocker run -ti --rm -p 8000:80 pn2d/hello-web:v1docker run -ti --rm -p 8000:8080 gcr.io/google-samples/kubernetes-bootcamp:v1kubectl (dokud na něj chcete sahat)kubectl get nodes mi vypíše seznam nodů
kubectl run hello-web --image pn2d/hello-web:v1 --port=80kubectl get podskubectl describe pod ${pod}kubectl logs ${pod}kubectl port-forward ${pod} 8000:80kubectl exec -ti ${pod} /bin/bashkubectl scale --replicas=3 deploy ${deployment}potřebuju service která web dostane ven
$ kubectl expose deploy hello-web \
--port 80 --target-port 80 --type=LoadBalancer --name=pub-hellominikube service pub-hello --urlkubectl get services, kubectl describe service ${service}
run, expose$ kubectl create -f web.yaml$ kubectl replace -f web.yaml$ kubectl diff -f my-config$ kubectl apply -f my-configNa všechny objekty funguje kubectl get, describe a delete, a jde to i s -f.
apiVersion: apps/v1
kind: Deployment
metadata:
name: hello-web
spec:
replicas: 2
selector:
matchLabels:
app: hello
template:
metadata:
name: hello-web
labels:
app: hello
spec:
containers:
- name: flask
image: pn2d/hello-web:v1
ports:
- name: http
containerPort: 80
kubectl apply -f web.yamlkubectl rollout status -f web.yaml
apiVersion: v1
kind: Service
metadata:
name: hello-loadbalancer
spec:
type: LoadBalancer
selector:
app: hello
ports:
- protocol: TCP
port: 80
targetPort: 80
#loadBalancerIP: "X.X.X.X" # když chcete statickou
Další skvělá komponenta: backend.py
apiVersion: apps/v1
kind: Deployment
metadata:
name: hello-backend
spec:
replicas: 2
selector:
matchLabels:
app: hello
what: backend # nutno označit i front-end, jinak blbne loadbalancer
template:
metadata:
name: hello-backend
labels:
app: hello
what: backend
spec:
containers:
- name: backend
image: pn2d/hello-backend:v1
ports:
- name: http
containerPort: 80
ClusterIP – jedna IP adresa v rámci clusteru
kind: Service
apiVersion: v1
metadata:
name: hello-backend
spec:
type: ClusterIP
selector:
app: hello
what: backend
ports:
- protocol: TCP
port: 80
targetPort: 80
Adresu předáme v env proměnné
spec:
template:
spec:
containers:
- ...
image: pn2d/hello-web:v2
env:
- name: BACKEND_URL
value: "http://hello-backend/backend"
spec:
template:
spec:
containers:
- ...
livenessProbe:
httpGet:
path: /alive
port: 80
initialDelaySeconds: 5
periodSeconds: 1
failureThreshold: 1
readinessProbe:
httpGet:
path: /ready
port: 80
initialDelaySeconds: 5
periodSeconds: 1
failureThreshold: 1
livenessProbe = je to naživu (když není, Kubernetes kontejner restartuje)readinessProbe = reaguje to (když není, Kubernetes na pod nesměruje provoz)httpGet tam je i exec a tcpSocket
kind: StatefulSet
apiVersion: apps/v1
metadata:
name: hello-db
spec:
serviceName: hello-db
replicas: 1
selector:
matchLabels:
app: hello
what: db
template:
metadata:
name: hello-db
labels:
app: hello
what: db
spec:
containers:
- name: mysql
image: percona:5
ports:
- name: mysql
containerPort: 3306
env:
- name: MYSQL_ROOT_PASSWORD
value: "12345"
- name: MYSQL_DATABASE
value: hellodb
- name: MYSQL_USER
value: hello_user
- name: MYSQL_PASSWORD
value: "aaa"
---
kind: Service
apiVersion: v1
metadata:
name: hello-db
spec:
selector:
app: hello
what: db
ports:
- protocol: TCP
port: 3306
targetPort: 3306
clusterIP: None # žádný load balancing, jenom udělá DNS
kind: StatefulSet
spec:
template:
spec:
containers:
- ...
volumeMounts:
- name: hello-db-data
mountPath: "/var/lib/mysql"
volumeClaimTemplates:
- metadata:
name: hello-db-data
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 5Gi
V Google Cloud je každý persistent volume samostatný ext4fs, který má lost+found a vlastníka, což MySQL nemá ráda.
kind: StatefulSet
spec:
template:
spec:
containers:
- ...
args:
- '--datadir=/var/lib/mysql'
- '--ignore-db-dir=lost+found'
initContainers:
- name: chown-datadir
image: busybox
command: ['sh', '-c', 'chown 999:999 /mnt/mysql-data']
volumeMounts:
- name: hello-db-data
mountPath: "/mnt/mysql-data"
spec:
template:
spec:
containers:
- image: pn2d/hello-backend:v2
readinessProbe:
httpGet:
path: /ready
port: 80
initialDelaySeconds: 20
periodSeconds: 10
env:
- name: MYSQL_HOST
value: hello-db
- name: MYSQL_DATABASE
value: hellodb
- name: MYSQL_USER
value: hello_user
- name: MYSQL_PASSWORD
value: "aaa"
Konfigurace se ukládá co ConfigMaps, což jsou vlastně key-value story
ConfigMap se dá vytvářet:
kubectl create configmap foo --from-file=foo.config nebo --from-file=<key>=<path>--from-env-file
--from-literal=<key>=<value>
apiVersion: v1
kind: ConfigMap
metadata:
name: hello-config
data:
backend.url: "http://hello-backend/backend"
db.host: hello-db
db.database: hellodb
spec:
template:
spec:
containers:
- ...
env:
- name: BACKEND_URL
valueFrom:
configMapKeyRef:
name: hello-config
key: backend.url
envFrom:
- configMapRef:
name: hello-config
prefix: FROM_FULL_CONFIGMAP_
spec:
template:
spec:
containers:
- ...
volumeMounts:
- name: config-volume
mountPath: /etc/config
volumes:
- name: config-volume
configMap:
name: hello-config
Secrets jsou jako ConfigMapy, ale tajné
apiVersion: v1
kind: Secret
metadata:
name: hello-db-root-password
data:
password: MTIzNDU=
apiVersion: v1
kind: Secret
metadata:
name: hello-db-passwords
data:
username: aGVsbG9fdXNlcg==
password: YWFh
spec:
template:
spec:
containers:
- ...
env:
- name: MYSQL_USER
valueFrom:
secretKeyRef:
name: hello-db-passwords
key: username
- ...
Analogicky jdou doplnit do envFrom přes secretRef a jako volumes typu secret.
Webserver rozdělíme na nginx proxy a uwsgi
spec:
template:
spec:
containers:
- name: web
image: pn2d/hello-web:v3-web
env:
- name: BACKEND_URL
valueFrom: ...
- name: proxy
image: pn2d/hello-web:v3-proxy
ports:
- name: http
containerPort: 80
spec:
template:
spec:
containers:
- ...
livenessProbe:
exec:
command:
- uwping
- uwsgi://localhost:9090/alive
initialDelaySeconds: 10
periodSeconds: 10
readinessProbe:
exec:
command:
- uwping
- uwsgi://localhost:9090/ready
initialDelaySeconds: 20
periodSeconds: 10
Nová verze backendu umí resetovat počítadlo
apiVersion: batch/v1beta1
kind: CronJob
metadata:
name: reset-counter
spec:
schedule: "*/3 * * * *"
jobTemplate:
spec:
template:
spec:
restartPolicy: OnFailure
containers:
- name: reset-counter
image: pn2d/hello-backend:v3
command: ["python3", "/app/reset.py"]
env:
- name: MYSQL_HOST
valueFrom:
configMapKeyRef:
name: hello-config
key: db.host
- name: MYSQL_DATABASE
valueFrom:
configMapKeyRef:
name: hello-config
key: db.database
- name: MYSQL_USER
valueFrom:
secretKeyRef:
name: hello-db-passwords
key: username
- name: MYSQL_PASSWORD
valueFrom:
secretKeyRef:
name: hello-db-passwords
key: password
web v4 umí vytáhnout info o posledním resetu
kubectl rollout status deployment ${deployment}
apiVersion: v1
kind: Service
metadata:
name: hello-nodeport
spec:
type: NodePort
selector:
app: hello
what: frontend
ports:
- protocol: TCP
port: 80
nodePort: 31000
Ingress spravuje externí přístup do clusteru. Typicky terminuje a load balancuje HTTP/HTTPS.
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: hello-ingress
annotations:
#kubernetes.io/ingress.global-static-ip-name: my-static-address
# ^ anotace vidí a mohou použít další procesy v clusteru
spec:
rules:
- http:
paths:
- path: /*
backend:
serviceName: hello-nodeport
servicePort: 80
Potřebujet do clusteru nainstalovat rozšíření cert-manager
apiVersion: certmanager.k8s.io/v1alpha1
kind: ClusterIssuer
metadata:
name: letsencrypt-staging
spec:
acme:
email: seznam-workshop@example.com
server: https://acme-staging-v02.api.letsencrypt.org/directory
# production server: https://acme-v01.api.letsencrypt.org/directory
privateKeySecretRef:
name: letsencrypt-staging-account-key
http01: {}
kind: Ingress
spec:
tls:
- secretName: www-example-com-tls
---
apiVersion: certmanager.k8s.io/v1alpha1
kind: Certificate
metadata:
name: www-example-com
spec:
secretName: www-example-com-tls
issuerRef:
name: letsencrypt-staging
kind: ClusterIssuer
commonName: www.example.com
acme:
config:
- http01:
ingress: hello-ingress
domains:
- www.example.com
spec:
template:
spec:
containers:
- name: forum
image: pn2d/phpbb2-k8s
env:
- name: PHPBB_DB_HOST
valueFrom:
configMapKeyRef:
name: hello-config
key: db.host
- name: PHPBB_DB_NAME
valueFrom:
configMapKeyRef:
name: hello-config
key: db.database
- name: PHPBB_DB_USER
valueFrom:
secretKeyRef:
name: hello-db-passwords
key: username
- name: PHPBB_DB_PASSWORD
valueFrom:
secretKeyRef:
name: hello-db-passwords
key: password
- name: PHPBB_SERVER_NAME
value: forum.example.com
- name: PHPBB_SERVER_PORT
value: "80"
- name: PHPBB_USE_HTTPS
value: "0"