Stockage/calcul distant (on oublie, cf. externalisation)
Virtualisation++
Abstraction du matériel (voire plus)
Accès normalisé par des APIs
Service et facturation à la demande
Flexibilité, élasticité
IaaS : Infrastructure as a Service
PaaS : Platform as a Service
SaaS : Software as a Service
Abstraction des couches basses
On peut tout programmer à son gré (API)
Permet la mise en place d’architectures scalables
Le cloud IaaS repose souvent sur la virtualisation
Ressources compute : virtualisation
Virtualisation complète : KVM, Xen
Virtualisation conteneurs : OpenVZ, LXC, Docker, RKT
L’instance est par définition éphémère
Elle doit être utilisée comme ressource de calcul
Séparer les données des instances
Groupement fonctionnel de ressources : micro services
Infrastructure as Code : Définir toute une infrastructure dans un seul fichier texte de manière déclarative
Scalabilité : passer à l'échelle son infrastructure en fonction de différentes métriques.
Facilitent la mise en place de PaaS
Fonctionnent sur du IaaS ou sur du bare-metal
Simplifient la décomposition d'applications en micro services
Namespaces
Cgroups (control groups)
CGroup: /
|--docker
| |--7a977a50f48f2970b6ede780d687e72c0416d9ab6e0b02030698c1633fdde956
| |--6807 nginx: master process ngin
| | |--6847 nginx: worker proces
Partage du kernel
Un seul processus par conteneur
Le conteneur est encore plus éphémère que l’instance
Le turnover des conteneurs est élevé : orchestration
Permettent d'exécuter des conteneurs sur un système
docker: historique
containerd: implémentation de référence
cri-o: implémentation Open Source développée par RedHat
kata containers: Conteneurs dans des VMs
Fonctionnalités offertes par le Kernel
Les conteneurs engine fournissent des interfaces d'abstraction
Plusieurs types de conteneurs pour différents besoins
Flexibilité et élasticité
Format standard de facto
Instanciation illimitée
Possibilité de construire son image à la main (long et source d'erreurs)
Suivi de version et construction d'images de manière automatisée
Utilisation de Dockerfile afin de garantir l'idempotence des images
Suite d'instruction qui définit une image
Permet de vérifier le contenu d'une image
FROM alpine:3.4
MAINTAINER Particule <admin@particule.io>
RUN apk -U add nginx
EXPOSE 80 443
CMD ["nginx"]
FROM
: baseimage utilisée
RUN
: Commandes effectuées lors du build de l'image
EXPOSE
: Ports exposées lors du run (si -P
est précisé)
ENV
: Variables d'environnement du conteneur à l'instanciation
CMD
: Commande unique lancée par le conteneur
ENTRYPOINT
: "Préfixe" de la commande unique lancée par le conteneur
Bien choisir sa baseimage
Chaque commande Dockerfile génère un nouveau layer
Comptez vos layers !
RUN apk --update add \
git \
tzdata \
python \
unrar \
zip \
libxslt \
py-pip \
RUN rm -rf /var/cache/apk/*
VOLUME /config /downloads
EXPOSE 8081
CMD ["--datadir=/config", "--nolaunch"]
ENTRYPOINT ["/usr/bin/env","python2","/sickrage/SickBeard.py"]
RUN apk --update add \
git \
tzdata \
python \
unrar \
zip \
libxslt \
py-pip \
&& rm -rf /var/cache/apk/*
VOLUME /config /downloads
EXPOSE 8081
CMD ["--datadir=/config", "--nolaunch"]
ENTRYPOINT ["/usr/bin/env","python2","/sickrage/SickBeard.py"]
Build automatisée d'images Docker
Intégration GitHub / DockerHub
Plateforme de stockage et de distribution d'images Docker
docker commit mon-conteneur backup/mon-conteneur
docker run -it backup/mon-conteneur
docker save -o mon-image.tar backup/mon-conteneur
docker import mon-image.tar backup/mon-conteneur
DockerHub n’est qu’au Docker registry ce que GitHub est à git
Pull and Push
Image officielle : registry
docker run
-d
(detach)
-i
(interactive)
-t
(pseudo tty)
-v
/directory/host:/directory/container
-p
portHost:portContainer
-P
-e
“VARIABLE=valeur”
--restart=always
--name=mon-conteneur
--privileged
(Accès à tous les devices)
--pid=host
(Accès aux PID de l’host)
--net=host
(Accès à la stack IP de l’host)
docker exec
docker attach
docker kill (SIGKILL)
docker stop (SIGTERM puis SIGKILL)
docker rm (détruit complètement)
Écosystème de gestion d'images
Construction automatisée d'images
Contrôle au niveau conteneurs
The Foundation’s mission is to create and drive the adoption of a new computing paradigm that is optimized for modern distributed systems environments capable of scaling to tens of thousands of self healing multi-tenant nodes.
La CNCF organise trois KubeCon par an :
Kubernetes n'implémente pas de solution réseau par défaut, mais s'appuie sur des solutions tierces qui implémentent les fonctionnalités suivantes :
apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
Les Pods sont définis en YAML comme les fichiers docker-compose
:
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
app: nginx
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.7.9
ports:
- containerPort: 80
replicas
.fluentd
ou logstash
nvidia-plugin
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: fluentd
spec:
selector:
matchLabels:
name: fluentd
template:
metadata:
labels:
name: fluentd
spec:
containers:
- name: fluentd
image: quay.io/fluentd_elasticsearch/fluentd:v2.5.2
Deployment
Persistent Volume
et un Storage Class
.apiVersion: apps/v1
kind: StatefulSet
metadata:
name: web
spec:
selector:
matchLabels:
app: nginx
serviceName: "nginx"
replicas: 3
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: k8s.gcr.io/nginx-slim:0.8
ports:
- containerPort: 80
name: web
volumeMounts:
- name: www
mountPath: /usr/share/nginx/html
volumeClaimTemplates:
- metadata:
name: www
spec:
accessModes: [ "ReadWriteOnce" ]
storageClassName: "my-storage-class"
resources:
requests:
storage: 1Gi
apiVersion: batch/v1
kind: Job
metadata:
name: pi
spec:
parallelism: 1
completions: 1
template:
metadata:
name: pi
spec:
containers:
- name: pi
image: perl
command: ["perl", "-Mbignum=bpi", "-wle", "print bpi(2000)"]
restartPolicy: OnFailure
Cron
jobTemplate
contient la définition de l'application à lancer comme Job
.apiVersion: batch/v1beta1
kind: CronJob
metadata:
name: batch-job-every-fifteen-minutes
spec:
schedule: "0,15,30,45 * * * *"
jobTemplate:
spec:
template:
metadata:
labels:
app: periodic-batch-job
spec:
restartPolicy: OnFailure
containers:
- name: pi
image: perl
command: ["perl", "-Mbignum=bpi", "-wle", "print bpi(2000)"]
apiVersion: v1
kind: Service
metadata:
name: frontend
spec:
type: ClusterIP
ports:
- port: 80
selector:
app: guestbook
NodePort
: chaque noeud du cluster ouvre un port statique et redirige le trafic vers le port indiqué
LoadBalancer
: expose le Service en externe en utilisant le loadbalancer d'un cloud provider
Il est aussi possible de mapper un Service avec un nom de domaine en spécifiant le paramètre spec.externalName
.
apiVersion: v1
kind: Service
metadata:
name: my-service
namespace: prod
spec:
type: ExternalName
externalName: my.database.example.com
Ingress
permet d'exposer un Service à l'extérieur d'un cluster KubernetesapiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: particule
spec:
rules:
- host: blog.particule.io
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: frontend
port:
number: 80
Pour utiliser un Ingress
, il faut un Ingress Controller. Un Ingress
permet de configurer une règle de reverse proxy sur l'Ingress Controller.
L'augmentation du nombre du nombre de micro services peut provoquer :
Les service mesh déportent la logique de communication au niveau de l'infrastructure et non plus au niveau de l'application. Les service mesh sont en général composés de deux plans:
Aujourd'hui les solutions sont multiples et offrent toutes plus ou moins les même fonctionnalités :
apiVersion: v1
kind: Pod
metadata:
name: redis
spec:
containers:
- name: redis
image: redis
volumeMounts:
- name: redis-persistent-storage
mountPath: /data/redis
volumes:
- name: redis-persistent-storage
emptyDir: {}
Persistent Volumes
pour solliciter un espace de stockage au travers des Persistent Volume Claims
kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
name: slow
provisioner: kubernetes.io/aws-ebs
parameters:
type: io1
zones: us-east-1d, us-east-1c
iopsPerGB: "10"
StatefulSets
pour solliciter du stockage (Utilisation du champ volumeClaimTemplates
)apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: storage-claim
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 5Gi
storageClassName: "slow"
StorageClass
apiVersion: v1
kind: PersistentVolume
metadata:
name: persistent-volume-1
spec:
storageClassName: slow
capacity:
storage: 1Gi
accessModes:
- ReadWriteOnce
hostPath:
path: "/tmp/data"
ConfigMap
peut sollicité par plusieurs pods
apiVersion: v1
data:
username: admin
url: https://api.particule.io
kind: ConfigMap
metadata:
name: web-config
apiVersion: v1
kind: Pod
metadata:
name: configmap-env
spec:
containers:
- name: test-container
image: k8s.gcr.io/busybox
command: [ "/bin/sh", "-c", "env" ]
env:
- name: USERNAME
valueFrom:
configMapKeyRef:
name: web-config
key: username
- name: URL
valueFrom:
configMapKeyRef:
name: web-config
key: url
restartPolicy: Never
apiVersion: v1
data:
redis-config: |
maxmemory 2mb
maxmemory-policy allkeys-lru
kind: ConfigMap
metadata:
name: redis-config
apiVersion: v1
kind: Pod
metadata:
name: configmap-volume
spec:
containers:
- name: test-container
image: k8s.gcr.io/busybox
command: [ "/bin/sh", "-c", "head -v /etc/config/*" ]
volumeMounts:
- name: config-volume
mountPath: /etc/config
volumes:
- name: config-volume
configMap:
name: redis-config
restartPolicy: Never
secret
utilisé pour stocker des informations sensibles comme les mots de passe, les tokens, les clés SSH...ConfigMap
, à la seule différence que le contenu des entrées présentes dans le champ data
sont encodés en base64.Secret
spécifique à l'authentification sur une registry Docker privée.Secret
à partir d'un compte utilisateur et d'un mot de passe.ConfigMap
Generic
: valeurs arbitraire comme dans une ConfigMap
tls
: certificat et clé pour utilisation avec un serveur webdocker-registry
: utilisé en tant que imagePullSecret
par un pod pour pouvoir pull les images d'une registry privéekubectl create secret generic monSuperSecret --from-literal=username='monUser' --from-literal=password='monSuperPassword"
apiVersion: v1
kind: Secret
metadata:
name: mysecret
type: Opaque
data:
username: YWRtaW4=
password: MWYyZDFlMmU2N2Rm
Les valeurs doivent être encodées en base64.
1
: 1 vCPU entier100m
: 0.1 vCPU0.5
: 1/2 vCPUM
: en base 10Mi
: en base 2apiVersion: v1
kind: Pod
metadata:
name: frontend
spec:
containers:
- name: db
image: mysql
env:
- name: MYSQL_ROOT_PASSWORD
value: "password"
resources:
requests:
memory: "64Mi"
cpu: "250m"
limits:
memory: "128Mi"
cpu: "500m"
- name: wp
image: wordpress
resources:
requests:
memory: "64Mi"
cpu: "250m"
limits:
memory: "128Mi"
cpu: "500m"
apiVersion: autoscaling/v2beta2
kind: HorizontalPodAutoscaler
metadata:
name: php-apache
namespace: default
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: php-apache
minReplicas: 1
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 50
LimitRange
permet de définir les valeurs minimales et maximales des ressources utilisées par les containers et les podsLimitRange
s'applique au niveau du namespace
namespace
LimitRange
ne limite pas le nombre total de ressources disponibles dans le namespaceapiVersion: v1
kind: LimitRange
metadata:
name: limit-example
spec:
limits:
- default:
memory: 512Mi
defaultRequest:
memory: 256 Mi
type: Container
ResourceQuota
limite le total des ressources de calcul consommées par les pods ainsi que le total de l'espace de stockage consommé par les PersistentVolumeClaims
dans un namespacepods
, PVC
et autres objets qui peuvent être créés dans un namespace
apiVersion: v1
kind: ResourceQuota
metadata:
name: cpu-and-ram
spec:
hard:
requests.cpu: 400m
requests.memory: 200Mi
limits.cpu: 600m
limits.memory: 500Mi
2 types de règles :
pods/pod-with-node-affinity.yaml
apiVersion: v1
kind: Pod
metadata:
name: with-node-affinity
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/e2e-az-name
operator: In
values:
- e2e-az1
- e2e-az2
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 1
preference:
matchExpressions:
- key: another-node-label-key
operator: In
values:
- another-node-label-value
containers:
- name: with-node-affinity
image: k8s.gcr.io/pause:2.0
apiVersion: v1
kind: Pod
metadata:
name: with-pod-affinity
spec:
affinity:
podAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: security
operator: In
values:
- S1
topologyKey: failure-domain.beta.kubernetes.io/zone
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchExpressions:
- key: security
operator: In
values:
- S2
topologyKey: failure-domain.beta.kubernetes.io/zone
containers:
- name: with-pod-affinity
image: k8s.gcr.io/pause:2.0
kubectl taint nodes node1 key=value:NoSchedule
Aucun pod ne pourra être schedulé sur ce nœud à moins de tolérer la taint:
apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
env: test
spec:
containers:
- name: nginx
image: nginx
imagePullPolicy: IfNotPresent
tolerations:
- key: "key"
operator: "Exists"
effect: "NoSchedule"
apiVersion: v1
kind: Pod
metadata:
name: goproxy
labels:
app: goproxy
spec:
containers:
- name: goproxy
image: k8s.gcr.io/goproxy:0.1
ports:
- containerPort: 8080
readinessProbe:
tcpSocket:
port: 8080
initialDelaySeconds: 5
periodSeconds: 10
livenessProbe:
tcpSocket:
port: 8080
initialDelaySeconds: 15
periodSeconds: 20
~/.kube/config
kubeconfig
peut être passé en paramètre de kubectl avec le flag --kubeconfig
Un seul fichier pour gérer tous ses clusters avec trois informations :
Stocké par défaut dans ~/.kube/config
$ kubectl api-resources
NAME SHORTNAMES APIGROUP NAMESPACED KIND
configmaps cm true ConfigMap
limitranges limits true LimitRange
namespaces ns false Namespace
nodes no false Node
persistentvolumeclaims pvc true PersistentVolumeClaim
persistentvolumes pv false PersistentVolume
pods po true Pod
secrets true Secret
services svc true Service
daemonsets ds apps true DaemonSet
deployments deploy apps true Deployment
replicasets rs apps true ReplicaSet
statefulsets sts apps true StatefulSet
horizontalpodautoscalers hpa autoscaling true HorizontalPodAutoscaler
cronjobs cj batch true CronJob
jobs batch true Job
ingresses ing extensions true Ingress
kubectl get nodes
kubectl get no
kubectl get nodes
kubectl get ns
kubectl get namespaces
default
-n
ou --namespace
kubectl -n kube-system get pods
kubectl get pods
kubectl get pod
default
):kubectl get services
kubectl get svc
kubectl run
, mais limitée aux Deployments
et aux Jobs
kubectl create
:kubectl create -f object.yaml
kubectl create -f https://raw.githubusercontent.com/kubernetes/examples/master/guestbook/frontend-deployment.yaml
kubectl delete -f object.yaml
kubectl replace -f object.yaml
$ kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/master/src/deploy/recommended/kubernetes-dashboard.yaml
$ kubectl proxy
http://localhost:8001/api/v1/namespaces/kube-system/services/https:kubernetes-dashboard:/proxy/
Concept | Description |
---|---|
Chart | Ensemble de ressources permettant de definir une application Kubernetes |
Config | Valeurs permettant de configurer un Chart (values.yaml ) |
Release | Chart deployé avec une Config |
crds/
: Dossier qui recense les CRDstemplates/
: les templates de manifeste Kubernetes en YAMLLe fichier de configuration du Chart dans lequel sont définies ses metadatas.
---
apiVersion: v2
description: Hello World Chart.
name: hello-world-example
sources:
- https://github.com/prometheus-community/helm-charts
version: 1.3.2
appVersion: 0.50.3
dependencies: []
---
### Provide a name in place of kube-prometheus-stack for `app:` labels
##
applicationName: ""
### Override the deployment namespace
##
namespaceOverride: ""
### Apply labels to the resources
##
commonLabels: {}
---
# values-production.yaml
commonLabels:
env: prod
tree
.
├── Chart.yaml
├── templates
│ ├── application.yaml
│ ├── configuration.yaml
│ └── secrets.yaml
├── values-production.yaml
├── values-staging.yaml
└── values.yaml
Helm permet de variabiliser les manifestes Kubernetes, permettant de créer et configurer des ressources dynamiquement. Le langage Go Template est utilisé.
apiVersion: apps/v1
kind: Pod
metadata:
name: {{ .Chart.Name }}
labels:
app.kubernetes.io/managed-by: "Helm"
chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
release: {{ .Release.Name | quote }}
version: 1.0.0
spec:
containers:
- image: "{{ .Values.helloworld.image.name }}:{{ .Values.helloworld.image.tag }}"
name: helloworld
index.yaml
listant les Charts packagés disponibles par version$ helm repo add stable https://charts.helm.sh/stable
"stable" has been added to your repositories
$ helm repo update
$ helm install stable/airflow --generate-name
helm install stable/airflow --generate-name
NAME: airflow-1616524477
NAMESPACE: defaul
...
$ helm upgrade airflow-1616524477 stable/airflow
helm upgrade airflow-1616524477 stable/airflow
Release "airflow-1616524477" has been upgraded. Happy Helming!
$ helm rollback airflow-1616524477
Rollback was a success! Happy Helming!
$ helm uninstall airflow-1616524477
release "airflow-1616524477" uninstalled
Service
se mettent à jour progressivement.Deployment
, DaemonSet
et StatefulSet
support les rolling updates.maxSurge
et maxUnavailabe
définissent le rythme du rolling update.kubectl rollout
permet de suivre les rolling updates effectués.apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
selector:
matchLabels:
app: frontend
replicas: 2
strategy:
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
type: RollingUpdate
template:
metadata:
name: nginx
labels:
app: frontend
spec:
containers:
- image: nginx:1.9.1
name: nginx
$ kubectl create -f nginx.yaml --record
deployment.apps/nginx created
kubectl scale
:kubectl scale --replicas=5 deployment nginx
kubectl set image deployment nginx nginx=nginx:1.15
kubectl run nginx --image=nginx --dry-run
kubectl run nginx --image=nginx \
--command -- <cmd> <arg1> ... <argN>
kubectl run pi --schedule="0/5 * * * ?" --image=perl --restart=OnFailure \
-- perl -Mbignum=bpi -wle 'print bpi(2000)'
kubectl run -it busybox --image=busybox -- sh
kubectl attach my-pod -i
kubectl port-forward my-svc 6000
kubectl
pour diagnostiquer les applications et le cluster kubernetes :kubectl cluster-info
kubectl get events
kubectl describe node <NODE_NAME>
kubectl logs [-f] <POD_NAME>
kubectl get nodes
kubectl describe nodes
kubectl cordon <NODE_NAME>
kubectl drain <NODE_NAME>
kubectl uncordon <NODE_NAME>
Managed - Kops - Kubespray - Kubeadm - Kube-aws - Symplegma
▼
Cluster Deployment
Cluster Lifecycle
IaC : Infrastructure as Code
▼
Terraform - CloudFormation - Cloud Deployment Manager - OpenStack Heat - Azure Resource Manager
▼
Infrastructure déclarée
Infrastructure immuable
Je veux utiliser Kubernetes
Cloud ?
Cloud public ou privé ?
Configuration particulière ?
Multiple cloud providers ?
Homogénéité des outils ?
3 entités sont utilisées :
Users
ou les ServiceAccounts
Deployments
, Pods
, Services
, etc...create, list, get, delete, watch, patch
ServiceAccount
par namespace
ServiceAccount
est formatté ainsi :system:serviceaccount:<namespace>:<service_account_name>
apiVersion: v1
kind: ServiceAccount
metadata:
name: default
namespace: default
Role
est un ensemble de règles permettant de définir quelle opération (ou verbe) peut être effectuée et sur quelle ressourceRole
ne s'applique qu'à un seul namespace
et les ressources liées à ce namespace
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
namespace: default
name: pod-reader
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "watch", "list"]
RoleBinding
va allouer à un User
, ServiceAccount
ou un groupe les permissions dans l'objet Role
associéRoleBinding
doit référencer un Role
dans le même namespace
.roleRef
spécifié dans le RoleBinding
est celui qui crée le liaisonkind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: read-pods
namespace: default
subjects:
- kind: User
name: jane
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: Role
name: pod-reader
apiGroup: rbac.authorization.k8s.io
ClusterRole
est similaire au Role
à la différence qu'il n'est pas limité à un seul namespace
namespace
comme les nodes
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: secret-reader
rules:
- apiGroups: [""]
resources: ["secrets"]
verbs: ["get", "watch", "list"]
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: salme-reads-all-pods
subjects:
- kind: User
name: jsalmeron
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: secret-reader
apiGroup: rbac.authorization.k8s.io
kubectl auth can-i get pods /
--namespace=default /
--as=spesnova@example.com
NetworkPolicy
est une spécification permettant de définir comment un ensemble de pods
communiquent entre eux ou avec d'autres endpointsNetworkPolicy
utilisent les labels pour sélectionner les pods sur lesquels s'appliquent les règles qui définissent le trafic alloué sur les pods sélectionnésNetworkPolicy
est générique et fait partie de l'API Kubernetes. Il est nécessaire que le plugin réseau déployé supporte cette spécificationNetworkPolicy
permettant de blocker le trafic entrant :kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
name: web-deny-all
spec:
podSelector:
matchLabels:
app: web
ingress: []
apiVersion: policy/v1beta1
kind: PodSecurityPolicy
metadata:
name: restricted
spec:
privileged: false
allowPrivilegeEscalation: false
requiredDropCapabilities:
- ALL
hostNetwork: false
hostIPC: false
hostPID: false
runAsUser:
rule: 'MustRunAsNonRoot'
readOnlyRootFilesystem: false
DenyEscalatingExec
ImagePolicyWebhook
NodeRestriction
PodSecurityPolicy
SecurityContextDeny
ServiceAccount