K8s gestion des ressources (opérations de base)

_ Bar _촯 2021-09-15 06:23:57
k8s gestion des ressources op


1. Base

Cet article est basé surk8s 1.22.1

# Vous pouvez voir l'allocation des ressources
kubectl describe node
# Vue d'ensemble de l'état des ressources
kubectl api-resources

1.1 apply

apply La commande peut créer une ressource en utilisant le profil

  • -f UtiliseryamlOujsonCréer une ressource, C'est aussi la façon la plus courante de
kubectl apply -f ./my1.yaml # Créer une ressource
kubectl apply -f ./my1.yaml -f ./my2.yaml # Création avec plusieurs fichiers
kubectl apply -f ./dir # Créer une ressource basée sur tous les fichiers du manifeste dans le répertoire
kubectl apply -f https://git.io/vPieo # De URL Créer une ressource dans

Créer à partir d'un flux de sortie standard

# Créer plusieursPod
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
name: busybox-sleep
spec:
containers:
- name: busybox
image: busybox
args:
- sleep
- "1000000"
---
apiVersion: v1
kind: Pod
metadata:
name: busybox-sleep-less
spec:
containers:
- name: busybox
image: busybox
args:
- sleep
- "1000"
EOF
# Créer plusieurs key De Secret
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Secret
metadata:
name: mysecret
type: Opaque
data:
password: $(echo -n "s33msi4" | base64 -w0)
username: $(echo -n "jane" | base64 -w0)
EOF

1.2 get

Liste une ou plusieurs ressources

Type Description
pods, pod, po ListepodInformation
replicationcontroller, rc Liste des contrôleurs de répliques
services, svc Liste des services
ds Liste des assemblages de démons
Paramètres Par défaut Description
-A, --all-namespace false Renvoie les ressources de tous les espaces de noms , Même si-n Ça ne marche pas non plus.
--chunk-size 500 Renvoie une grande liste sous forme de bloc , Au lieu de retourner toutes les listes à la fois .Passer0Pour désactiver.
--ignore-not-found false true: Ne pas signaler d'erreur lorsque la ressource n'est pas trouvée
-o, --output '' json,yaml,name,go-template,go-template-file,template,templatefile,jsonpath,jsonpath-as-json,jsonpath-file,custom-columns-file,custom-columns,wide

yaml: Paryaml Configuration détaillée de la sortie du format
wide: Exporter des informations plus détaillées dans une liste
name: Imprimer uniquement le nom de la ressource
json: Parjson Format détails de sortie
--server-print true Imprimer les informations de colonne spécifiques reçues du serveur , Par exemple,: STATUS(État de fonctionnement), RESTARTS(Nombre de redémarrages)
--show-labels false Afficher les étiquettes pour les paramètres de ressources correspondants
--sort-by '' Accepté jsonpath Expression, Par exemple, trié par nom podListe kubectl get pods --sort-by=.metadata.name
--template ''
-w, --watch false Surveiller les changements dans les ressources, Démarrer une mission permanente , Disponible enpod name Surveillance individuelle pod
-n, --namespace Espace de noms

1.3 describe

Afficher l'état détaillé d'une ou de plusieurs ressources , Inclure les ressources non initialisées par défaut .

2. Dépendance

2.1 Espace de noms namespace

  • namespacePour écrire: namespaces, namespace, ns

Catégoriser les ressources, Les services connexes sont placés dans le même espace de noms pour une gestion facile

# Créer un espace de noms
kubectl create namespace
# Espace de noms de requête
kubectl get ns
# Supprimer un espace de noms
kubectl delete namespace NAME
# yaml Configuration
apiVersion: v1
kind: Namespace
metadata:
name: repo-nexus
labels:
name: repo-nexus

k8s Le Cluster possède par défaut les éléments suivants: namespace

NAME STATUS AGE
default Active 2d3h
kube-node-lease Active 2d3h
kube-public Active 2d3h
kube-system Active 2d3h
  • Tous lesNAMESPACEDRessources, Doit être spécifié lors de la création namespace,Si non spécifié,La valeur par défaut seradefaultSous l'espace de noms

  • Même chose.namespace La ressource similaire sous ne peut pas être renommée , Différents types de ressources peuvent être renommés

  • C'est différent.namespace Les ressources similaires sous peuvent être renommées

  • Habituellement, lorsque le projet est utilisé , Nous créerons un sens commercial namespace Pour une intégration logique

2.2 apiVersion

apiVersion Sens
alpha EntréeK8s Versions candidates antérieures de la fonctionnalité ,Peut contenirBug, Finalement, pas nécessairement. K8s
beta Version testée ,Qui finiront par entrerK8s, Mais la fonction 、 La définition de l'objet peut changer .
stable Version stable pour une utilisation sûre
v1 stable Première version après la version , Contient plus d'objets de base
apps/v1 La version la plus utilisée ,CommeDeployment、ReplicaSets Tous sont entrés dans cette version

Types de ressources et apiVersionTableau comparatif( Les versions sont différentes. , Sous réserve des documents officiels )

Kind apiVersion
ClusterRoleBinding rbac.authorization.k8s.io/v1
ClusterRole rbac.authorization.k8s.io/v1
ConfigMap v1
CronJob batch/v1beta1
DaemonSet extensions/v1beta1
Node v1
Namespace v1
Secret v1
PersistentVolume v1
PersistentVolumeClaim v1
Pod v1
Deployment v1、apps/v1、apps/v1beta1、apps/v1beta2
Service v1
Ingress extensions/v1beta1
ReplicaSet apps/v1、apps/v1beta2
Job batch/v1
StatefulSet apps/v1、apps/v1beta1、apps/v1beta2

Accès rapide aux ressources et aux versions

kubectl explain pod
kubectl explain Pod.apiVersion

2.3 Clusternode label

# Requêtenode Informations existantes sur l'étiquette
kubectl get nodes --show-labels
# Étiquetage des noeuds
kubectl label node k8s-n-1 component=mysql

2.4 configmap

Les variables de profil ou d'environnement couramment utilisées pour gérer les applications , Mettre des informations qui ne sont pas particulièrement sensibles

apiVersion: v1
kind: ConfigMap
metadata:
name: xxxx
namespace: default
data:
# Configuration key: value
MYSQL_HOST: "172.168.23.11"
MYSQL_PORT: "3306"
kubectl create -f configmap.yaml

Création à l'aide d'un fichier texte

MYSQL_HOST=172.168.23.11
MYSQL_PORT=3306
kubectl create configmap xxx --form-env-file=xxx.txt -n default

2.5 secret

Gérer les informations sensibles , Par défautbase64 Stockage codé , Il existe trois types

  • Service Account: Pour accéder àKubernetes API, Oui.KubernetesCréation automatique, Et sera automatiquement monté sur PodDe/run/secrets/kubernetes.io/serviceaccountDans la table des matières; CréationServiceAccountAprès, podSpécifié dansserviceAccountAprès, Créer automatiquement ceci ServiceAccountCorrespondantsecret
  • Opaque: base64CodageSecret, Utilisé pour stocker les mots de passe , Clé, etc.;
  • kubernetes.io/dockerconfigjson: Pour le stockage privé docker registry Informations de certification pour
apiVersion: v1
kind: Secret
metadata:
name: xxxx
namespace: default
type: Opaque
data:
# Configuration key: base64(value)
MYSQL_USER: cm9vdA==
MYSQL_PASSWD: MTIzNDU2
kubectl create -f configmap.yaml

Création à l'aide d'un fichier texte , Non requisbase64Codage

MYSQL_USER=rootMYSQL_PASSWD=123456
kubectl create secret generic xxx --form-env-file=xxx.txt -n default

3. Pod

  • pod Styles pris en charge : pods, pod, po

docker Les conteneurs sont programmés ,Ink8sEn grappes, La plus petite Unit é de programmation est Pod

  • Découplage du moteur du conteneur Docker、Rkt. Découplage de la conception de la plate - forme et de la réalisation concrète du moteur
  • Réseau de partage de conteneurs multiples |Stockage|Processus Espace, Les scénarios d'affaires pris en charge sont plus flexibles
# yamlapiVersion: v1kind: Pod # Type de ressourcemetadata: # Configuration de base name: POD_NAME namespace: MY_NS labels: # Voilà.podÉTIQUETAGE, Gestion facile, À l'arrière, il y a une présentation. component: POD_NAMEspec: containers: # Configuration du conteneur - name: NAME1 # Nom du conteneur image: IMAGE # Adresse de l'entrepôt miroir env: # Variables d'environnement - name: MYSQL_HOST # Désignationroot Nom d'utilisateur de l'utilisateur value: "127.0.0.1" - name: MYSQL_PASSWD value: "123456" ports: # Port de fuite du conteneur - containerPort: 8002 - name: mysql # Unpod Peut avoir plusieurs conteneurs image: mysql ports: - containerPort: 3306 env: - name: MYSQL_ROOT_PASSWORD value: "123456" - name: MYSQL_DATABASE value: "myblog"
# Créationpodkubectl create -f pod.yamlkubectl apply -f pod.yamlkubectl run --image=IMAGE POD_NAME # Pluskubectl run Référence d'utilisation kubeclt run -h# Les bases peuvent être obtenues par la mise en service yamlDocumentationkubectl run --image=nginx --dry-run -o yaml nginx# Mise à jour de la version de service kubectl apply -f pod.yaml# Voirpod, -n Spécifier un espace de noms , -o wide Afficher plus d'informations ( Vous pouvez voir le noeud de programmation )kubectl get pods -o wide -n xxx# Voirpod Détails et événements pour kubectl describe pods -n xxx POD_NAME# VoirpodCompletyamlkubectl get pods -o yaml -n xxx POD_NAME# VoirPod Journal du contenu , Afficher les journaux de sortie standard ou d'erreur kubectl logs -n xxx -f POD_NAME -c CONTAINER_NAME# --tail Nombre limité de lignes , Similaire àdockerLes ordres docker logs --tail=10 -f xxxxxkubectl -n default logs -f --tail=10 nginx -c nginx# Supprimer le conteneurkubectl delete -f pod.yamlkubectl delete pod -n xxx POD_NAME# Dans le récipient, -c Indique quel conteneur entrer kubectl -n xxx exec -it POD_NAME -c NAME1 bash# Utiliser -o wide Nous pouvons voirpod Où est la machine? , Donc le conteneur correspondant est dans cette machine # Nous pouvons exécuter sur la machine correspondante docker ps Voir les informations du conteneurdocker ps -a | grep NAME1# pod Le format de nommage du conteneur dans est : k8s_<container_name>_<pod_name>_<pod_uuid>

3.1 Sélecteur de noeuds

  • nodeSelector Sélecteur de noeuds , Peut êtrepod Envoyé à quelqu'un labelDenodeAllez., SinodeN'existe pas, pod Ne sera pas créé correctement , Jusqu'ànode Est marqué en conséquence label Sera déployé automatiquement , Sans recréer
spec: nodeSelector: # En utilisant le sélecteur de noeud Pod Envoyer à la spécification labelNode of component: mysql # Spécifie que la sélection a mysqlÉtiquettenode

3.2 Persistance des données

Similaire àdocker Montage des données pour , Mais nous avons déjà monté tout seul. , Maintenant, nous l'utilisons dans le cluster volumes Le montage n'est également monté que sur pod Sur la machine , Quand nous serons de nouveau en ligne pod Il y a toujours un problème de données non trouvées lorsqu'elles sont envoyées à d'autres machines. , Ici, nous utilisonsnodeSelectorRésolution, Bien sûr, cette méthode n'est généralement pas utilisée dans la production.

...spec: volumes: - name: mysql-data hostPath: path: /opt/mysql/data nodeSelector: component: mysql containers: - name: mysql image: mysql ... volumeMounts: - name: mysql-data mountPath: /var/lib/mysql

UtiliserPV+PVC Connexion à une solution de stockage distribuée

  • ceph
  • glusterfs
  • nfs

3.3 Service health check

Deux sondes

  • LivenessProbeSonde: Détection active , Utilisé pour déterminer si le contenant est vivant , C'est - à - dire:PodOui NonrunningStatut, SiLivenessProbeLa sonde a détecté un contenant malsain, EtkubeletOui.kill Chute du récipient , Et redémarrer selon la politique de redémarrage du conteneur , Si l'un ne contient pas LivenessProbeSonde, EtKubelet Considered container LivenessProbe La valeur de retour de la sonde est toujours réussie
  • ReadinessProbeSonde: Détection de la disponibilité , Utilisé pour détecter si le conteneur fournit correctement le Service , C'est - à - dire le conteneur ReadyOui NonTrue, Si la demande peut être reçue , SiReadinessProbeÉchec de la détection, Du conteneur ReadySeraFalse, Endpoint Controller Le Contrôleur va PodDeEndpointÀ partir deserviceEndpointSupprimer de la Liste, Ne plus envoyer de demandes à ce PodAllez., Jusqu'à ce que la prochaine sonde réussisse . ( Supprimer ceci Pod Ne pas participer à la réception des demandes ne transmet pas le trafic à cet endroit Pod)

Trois types

  • exec: Exécuter une commande, La valeur de l'état de retour est 0 Indique la santé du conteneur

  • httpGet: Envoyer unhttpDemande, Retour200-399 Indique la santé du conteneur

  • tcpSocket: Par conteneur IPEtPortMise en œuvreTCPVérifiez, Si une connexion peut être établie , Indique la santé du conteneur

Paramètres et implications

  • initialDelaySeconds: Combien de secondes faut - il attendre pour effectuer la première sonde après le démarrage?
  • perioSeconds: Fréquence de détection . Par défaut10Secondes, Minimum1Secondes
  • timeoutSeconds: Délai de détection . Par défaut1Secondes, Minimum1Secondes
  • successThreshold: Après défaillance de la sonde , Combien de fois au moins la détection continue est - elle réussie? . Par défaut1
  • failureThreshold: Après détection réussie , Combien de fois la détection continue a - t - elle échoué au moins pour être considérée comme un échec? . Par défaut3, Minimum1
spec: containers: - image: xxx name: xxx livenessProbe: # Spécifier la sonde , Peut également être spécifié ici readinessProbe # UtiliserhttpDemande, Conteneur de demande80 Port pour déterminer si le conteneur est vivant httpGet: path: /blog/index port: 80 scheme: HTTP initialDelaySeconds: 10 # Combien de secondes faut - il attendre pour effectuer la première sonde après le démarrage du conteneur? perioSeconds: 10 # Fréquence de détection timeoutSeconds: 2 # Délai de détection

3.4 Politique de redémarrage

PodPolitique de redémarrage pour(RestartPolicy)Appliquer àPod Tous les conteneurs à l'intérieur , Et seulement PodOùNodeParkubelet Jugement et redémarrage . Lorsqu'un contenant sort anormalement ou qu'un contrôle de santé échoue , kubeletSera basé surRestartPolicy Pour effectuer les opérations correspondantes . Pod Les politiques de redémarrage pour :Always、OnFailureEtNever,La valeur par défaut estAlways

  • Always: En cas de défaillance du conteneur ( Sortie normale ou non ),ParkubeletRedémarrer automatiquement le conteneur.
  • OnFailure: Lorsque le conteneur cesse de fonctionner et que le Code de sortie n'est pas 0Heure,ParkubeletRedémarrer automatiquement le conteneur.
  • Never: Quel que soit l'état de fonctionnement du conteneur ,kubelet Ne redémarrera pas le conteneur .
spec: restartPolicy: Always containers: - name: xxx image: xxx args: # Sortie anormale analogique , Paramètres du conteneur - /bin/sh - -c - sleep 10 && exit 1

3.5 Politique de retrait du miroir

spec: containers: - name: xxx image: xxx imagePullPolicy: IfNotPresent

Politique de retrait du miroir: Par défautIfNotPresent

  • Always: Toujours tirer le miroir , Même s'il y en a un localement, tirez - le de l'entrepôt.
  • IfNotPresent: Priorité locale , S'il n'y en a pas, allez à l'entrepôt.
  • Never: Utiliser uniquement le miroir local, Aucune erreur locale

3.6 PodRessources limitées

Attention!: Si l'utilisation de la mémoire dépasse la limite , Ça va déclencher le système. OOMMécanismes,CauseCPU Est une ressource compressible , Ne déclenchera pas Pod Sortie ou reconstruction

spec:
containers:
- name: xxx
image: xxx
resources:
requests:
memory: 100Mi
cpu: 50m
limits:
memory: 100Mi
cpu: 50m

requests:

  • Exigences minimales en matière de ressources pour l'utilisation des conteneurs , Rôle etschedulePhase, Dépendance à l'égard du jugement de l'allocation des ressources lors de l'ordonnancement des conteneurs
  • Seulement si la quantité de ressources disponibles pour l'allocation sur le noeud >=request Autoriser l'envoi du conteneur à ce noeud
  • request Le paramètre ne limite pas la ressource maximale disponible pour le conteneur
  • requests.cpu A été transformé en dockerDe--cpu-sharesParamètres, Aveccgroup cpu.sharesMême fonction( Peu importe le nombre d'hôtes cpuOu le noyau, --cpu-shares Les options sont réparties proportionnellement cpuRessources)
  • requests.memoryIl n'y a pas de correspondancedockerParamètres, Uniquement en tant que k8s Base de répartition

limits:

  • Le conteneur peut utiliser le plus de ressources
  • Set to0 Indique qu'il n'y a pas de limite aux ressources utilisées , Illimité
  • QuandpodMémoire supérieure àlimitHeure, Seraoom
  • QuandcpuPlus quelimitHeure, Ne sera paskill, Mais il est limité à limitValeur
  • limits.cpuSera transformé endockerDe-cpu-qiotaParamètres. Aveccgroup cpu.cfs_quota_usMême fonction
  • limits.memory Sera transformé en dockerDe-memoryParamètres. Utilisé pour limiter la mémoire maximale du conteneur

3.7 Réseau

Si dansPODUtilisé dans"hostNetwork: true"Configurer le réseau,pod L'application en cours d'exécution peut voir directement l'interface réseau de l'hôte , L'application et le port sont accessibles à toutes les interfaces réseau du réseau local où se trouve l'hôte. .Déclarationpod Le mode réseau pour hostMode, Même effet docker run --net=host

spec: hostNetwork: true

3.8 Configuration de référence

3.8.1 Référencesconfigmap

spec: containers: - name: xxx image: xxx env: - name: MYSQL_HOST valueFrom: configMapKeyRef: name: xxx key: MYSQL_HOST - name: MYSQL_PORT valueFrom: configMapKeyRef: name: xxx key: MYSQL_PORT - name: MYSQL_DATABASE value: "xxx"

3.8.2 Référencessecret

spec: containers: - name: xxx image: xxx env: - name: MYSQL_USER valueFrom: secretKeyRef: name: xxx key: MYSQL_USER - name: MYSQL_ROOT_PASSWORD valueFrom: secretKeyRef: name: xxx key: MYSQL_PASSWD - name: MYSQL_DATABASE value: "xxx"

3.9 pod Cycle de vie

Pod Description de la valeur de l'état

  • Pending: API Server Créé Pod, En attente de l'ordonnancement .
  • ContainerCreating: Tirer dans le conteneur de démarrage du miroir
  • Runnung: Pod Tous les conteneurs à l'intérieur ont été créés , Et au moins un conteneur fonctionne 、 État de démarrage ou état de redémarrage .
  • Succeeded| Completed: Pod Sortie après que tous les conteneurs à l'intérieur ont été exécutés avec succès , Et ne redémarrera pas .
  • Failed | Error: Pod Tous les conteneurs à l'intérieur sont sortis , Mais au moins un conteneur a quitté l'état défaillant .
  • CrashLoopBackOff: Pod Impossible de démarrer le conteneur à l'intérieur , Par exemple, la perte de profil entraîne l'échec du démarrage du processus principal
  • Unknown: Impossible d'obtenir ceci pour une raison quelconque PodÉtat de, Peut être causé par une mauvaise communication réseau .

Initialiser le conteneur(init)

  • Vérifier que tous les composants dépendants de l'application commerciale ont commencé
  • Modifier les permissions du Répertoire
  • Ajuster les paramètres du système

ValidationPodCycle de vie

apiVersion: v1
kind: Pod
metadata:
name: nginx
namespace: default
labels:
component: nginx
spec:
# En affairespod Démarrage avant démarrage , Peut être utilisé pour traiter certaines affaires pod Quelques travaux avant le démarrage
initContainers:
- name: nginx1
image: nginx
# Écrire l'heure et l'étiquette du fichier après le démarrage du conteneur
command: ['sh', '-c', 'echo $(date +%s): INIT >> /loap/timing']
volumeMounts:
- mountPath: /loap
name: timing
containers:
- name: nginx2
image: nginx
command: ['sh', '-c', 'echo $(date +%s): START >> /loap/timing; sleep 10; echo $(date +%s): END >> /loap/timing;']
volumeMounts:
- mountPath: /loap
name: timing
livenessProbe: # Sonde de détection active
exec:
command: ['sh', '-c', 'echo $(date +%s): LIVENESS >> /loap/timing']
readinessProbe: # Sonde de disponibilité
exec:
command: ['sh', '-c', 'echo $(date +%s): READINESS >> /loap/timing']
lifecycle: # Cycle de vie
postStart: # Déclenché lorsque le conteneur démarre
exec:
command: ['sh', '-c', 'echo $(date +%s): POST-START >> /loap/timing']
# Il faut le tuer. Pod Pour déclencher pre-stop hook,Si oui Pod Moi - même. Down Laisse tomber.,Ne sera pas exécuté pre-stop hook
preStop:
exec:
command: ['sh', '-c', 'echo $(date +%s): PRE-STOP >> /loap/timing']
volumes:
- name: timing
hostPath:
path: /tmp/loap
kubectl apply -f nginx.yaml# Voirpod Machine kubectl get pod -o wide# Inpod Afficher les fichiers sur la machine cat /tmp/loap/timing
1630456396: INIT1630456398: START1630456398: POST-START1630456398: READINESS1630456406: LIVENESS1630456406: READINESS1630456408: END
# Supprimer le testpod, Sinon, il n'y a pas de processus de résidence , pod Il va continuer à redémarrer. kubectl delete -f nginx.yaml

4. Controller

Les contrôleurs, également appelés charges de travail, sont utilisés pour mettre en œuvre la gestion pod Couche intermédiaire ,Assurez - vous quepod Ressources dans l'état prévu ,pod En cas de défaillance des ressources ,Je vais essayer. Redémarrer , Lorsque la politique de redémarrage est invalide , Sera créé à nouveau podRessources.

  • ReplicaSet: Créer un nombre spécifié de podNombre d'exemplaires,Assurez - vous quepod Nombre d'exemplaires conformes à l'état prévu , Et prend en charge les fonctions d'expansion et de réduction automatiques de la capacité de roulement
  • Deployment:Travailler dansReplicaSetAu - dessus de, Pour gérer les applications apatrides , Le meilleur Contrôleur pour le moment . Prise en charge des mises à jour et des retours en arrière , Fournir une configuration déclarative
  • DaemonSet: Utilisé pour s'assurer que chaque noeud du cluster n'exécute qu'un podCopie, Généralement utilisé pour effectuer des tâches de fond au niveau du système .Par exemple,EFKServices
  • Job: Quittez dès que vous avez terminé , Pas besoin de redémarrer ou de reconstruire
  • Cronjob: Contrôle périodique des tâches , Aucune opération de fond soutenue n'est nécessaire
  • StatefulSet: Gérer les applications stateful

4.1 Deployment

Deployment Styles pris en charge : deployment, deploy

apiVersion: apps/v1kind: Deploymentmetadata: name: nginx namespace: defaultspec: replicas: 1 # DésignationPodNombre de copies selector: # DésignationPodSélecteur pour matchLabels: app: nginx template: # temlate Contenu et création podEssentiellement cohérent metadata: labels: # Voilà.PodFrappe!label app: nginx spec: containers: - image: nginx name: nginx resources: {} dnsPolicy: ClusterFirst restartPolicy: Always
# CréationDeploymentkubectl create -f nginx.yaml kubectl create deploy --image=nginx nginx# Base obtenue par mise en service yamlkubectl create deploy --image=nginx nginx --dry-run -o yaml# VoirDeployment, -n Ajouter un espace de noms kubectl get deploy# Sera créé automatiquementreplicaSet, Vous pouvez voirkubectl get replicaset(rs) # Supprimer avec créer un fichier Deploymentkubectl delete -f nginx.yaml # Mise à jour-- Exécuter après modification du profil applykubectl apply -f nginx.yaml# Mise à jour en ligne , Similaire àvimÉditeur, Mise à jour automatique après enregistrement kubectl edit deploy nginx# Mise à jour avec commande directe kubectl set image deploy nginx nginx=nginx:1.21.1 --record

4.2 Nombre de copies

controller(Controller)Détection en temps réelpodStatut, Et s'assurer que le nombre d'exemplaires est toujours à la valeur attendue

spec: replicas: 1 # DésignationPodNombre de copies
# Nombre de copies modifiées kubectl scale deploy nginx --replicas=2# De préférence en modifiant le fichier de configuration replicas Parameter re apply Pour modifier le nombre de copies ( Maintenir le profil en ligne avec la santé réelle )# On en supprime un. pod, Le Contrôleur recréera un kubectl delete pod nginx-6799fc88d8-7rppv
[[email protected] ~]# kubectl get podNAME READY STATUS RESTARTS AGEnginx-6799fc88d8-7rppv 1/1 Running 0 9m5snginx-6799fc88d8-fnwqr 1/1 Running 0 56s[[email protected] ~]# kubectl delete pod nginx-6799fc88d8-7rppvpod "nginx-6799fc88d8-7rppv" deleted[[email protected] ~]# kubectl get podNAME READY STATUS RESTARTS AGEnginx-6799fc88d8-fnwqr 1/1 Running 0 97snginx-6799fc88d8-grxfs 0/1 ContainerCreating 0 2s

4.3 PodStratégies d'expulsion

K8S Il y a une fonction spéciale appelée pod eviction, Dans certaines scènes, comme les noeuds NotReady, Ou lorsque les ressources sont insuffisantes ,Prends ça. pod Expulsion vers un autre noeud , C'est une question de protection des entreprises.

4.4 Mettre à jour la politique

spec: replicas: 2 # DésignationPodNombre de copies selector: # DésignationPodSélecteur pour matchLabels: app: myblog strategy: rollingUpdate: maxSurge: 25% maxUnavailable: 25% type: RollingUpdate # Spécifier la méthode de mise à jour comme mise à jour progressive ,Politique par défaut,Adoptionkubectl get deploy -o yamlVoir

Contrôle des politiques :

  • maxSurge: Augmentation maximale , Se réfère au processus de mise à jour , Peut être comparé àreplicas Dépassement de la valeur de préréglage podNombre, Peut être une valeur fixe ou un pourcentage ,Par défautdesired PodsCompter25%. Arrondi vers le Haut lors du calcul (Par exemple,3.4,Prends - le.4), Jusqu'à replicas + maxSurge- Oui.pod
  • maxUnavailable: Se réfère au processus de mise à jour , Quelques - uns au plus pod Dans un état de non - service , Peut être une valeur fixe ou un pourcentage ,Par défautdesired PodsCompter25%. Arrondi vers le bas lors du calcul (Par exemple,3.6,Prends - le.3)
# On va le modifier.nginxVersion miroirkubectl set image deploy nginx nginx=nginx:1.21.1 --record# Afficher les événements de mise à jour de défilement kubectl describe deploy nginx
Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal ScalingReplicaSet 35s deployment-controller Scaled up replica set nginx-54f48578cf to 1 Normal ScalingReplicaSet 32s (x2 over 5m5s) deployment-controller Scaled down replica set nginx-6799fc88d8 to 2 Normal ScalingReplicaSet 32s deployment-controller Scaled up replica set nginx-54f48578cf to 2 Normal ScalingReplicaSet 29s deployment-controller Scaled down replica set nginx-6799fc88d8 to 1 Normal ScalingReplicaSet 29s deployment-controller Scaled up replica set nginx-54f48578cf to 3 Normal ScalingReplicaSet 27s deployment-controller Scaled down replica set nginx-6799fc88d8 to 0
  • Nous avons trois noeuds , Donc vous pouvez augmenter au maximum 1- Oui.pod, Jusqu'à0- Oui.pod Dans un état de non - service ( C'est - à - dire au moins trois podEn cours d'exécution)
  • 3 old pod, Augmentation du déclenchement de la politique augmentation réussie d'un pod, Échec du déclenchement de la politique réduite
  • 3 old pod + 1 new pod, Échec du déclenchement de la politique ajoutée , Réduction de la stratégie déclenchée avec succès , Réduire d'un ancien pod
  • 2 old pod + 1 new pod, Ajouter1Diminution0
  • 2 old pod + 2 new pod, Ajouter0Diminution1
  • 1 old pod + 2 new pod, Ajouter1Diminution0
  • 1 old pod + 3 new pod, Nouveaupod Nombre de demandes satisfaites , Vieux.podDiminution1
  • 3 new pod Mise à jour terminée

4.5 Service rollback

Les politiques de mise à niveau peuvent être mises à niveau en douceur en faisant défiler les mises à niveau Deployment, En cas de problème de mise à niveau , Nécessite le moyen le plus rapide et le plus efficace de revenir à la dernière version disponible pour un bon fonctionnement .À cette fin,K8S Fournit un mécanisme de rollback

revision: Lors de la mise à jour de l'application ,K8S Enregistre le numéro de version actuel ,C'est - à - dire:revision, En cas de problème de mise à niveau , Peut être retourné à un revision,Configuration par défaut,K8S Seuls les plus récents seront conservés. revision,Peut passerDeploymentDans le profilspec.revisionHistoryLimit Augmentation des attributs revisionNombre,Par défaut10.

# Voir la version actuelle et l'historique de la version , Si oui<none> Parce qu'il n'a pas été créé et mis à jour --record kubectl rollout history deploy nginx# Enlevons le service et reconstruisons - le. kubectl delete -f nginx.yamlkubectl apply -f nginx.yaml --record# Et le modifier kubectl set image deploy nginx nginx=nginx:1.21.1 --record# Revoir la version historique kubectl rollout history deploy nginx
[[email protected] ~]# kubectl rollout history deploy nginxdeployment.apps/nginx REVISION CHANGE-CAUSE1 kubectl apply --filename=nginx.yaml --record=true2 kubectl set image deploy nginx nginx=nginx:1.21.1 --record=true
# Retour à la version spécifique kubectl rollout undo deploy nginx --to-revision=1
[[email protected] ~]# kubectl rollout undo deploy nginx --to-revision=1deployment.apps/nginx rolled back[[email protected] ~]# kubectl rollout history deploy nginxdeployment.apps/nginx REVISION CHANGE-CAUSE2 kubectl set image deploy nginx nginx=nginx:1.21.1 --record=true3 kubectl apply --filename=nginx.yaml --record=true

Nous avons vu que l'histoire qui aurait dû ajouter un autre enregistrement n'en avait que deux. , Parce que1Et3 C'est la même version. , Un seul.

5. Service

serviceAlias: services, service, svc

Par dessus,Capable de passer à traversDeployment Pour créer un groupe Pod Pour fournir des services hautement disponibles . Bien que chaque Pod Un seul sera attribué Pod IP, Mais il y a deux problèmes: :

  • Pod IP Seulement les virtuels visibles dans le cluster IP, Impossible d'accéder à l'extérieur
  • Pod IPVa suivrePod Et disparaît ,QuandReplicaSetC'est exact.Pod Lors de l'expansion dynamique ,Pod IP Ça peut changer n'importe quand, n'importe où. , Cela rend difficile l'accès au service

5.1 ServiceÉquilibrer la chargeCluster IP

serviceC'est un groupe.pod Résumé du service pour , équivalent à un groupe podDeLB, Responsable de la distribution des demandes aux homologues pod.service Pour ça. LBFournir unIP,Généralement appelécluster IP .UtiliserServiceObjet,Adoptionselector Sélection des étiquettes ,Trouver la correspondancePod

apiVersion: v1kind: Servicemetadata: name: nginx namespace: defaultspec: ports: - port: 80 protocol: TCP targetPort: 80 selector: app: nginx type: ClusterIP
# Création
kubectl apply -f svc-nginx.yaml
kubectl expose deployment nginx --port=80 --type=ClusterIP
# Voirsvc
kubectl get svc
# Supprimer
kubectl delete svc nginx
# VoirsvcDétails
kubectl describe svc nginx
[[email protected] ~]# kubectl describe svc nginx
Name: nginx
Namespace: default
Labels: <none>
Annotations: <none>
Selector: app=nginx # D'après çalabel Filtrer ses manipulations pod
Type: ClusterIP
IP Family Policy: SingleStack
IP Families: IPv4
IP: 10.1.156.133
IPs: 10.1.156.133
Port: <unset> 80/TCP
TargetPort: 80/TCP
Endpoints: 10.2.1.12:80,10.2.2.7:80
Session Affinity: None
Events: <none>

Nous pouvons maintenant l'utiliser à l'intérieur du cluster 10.1.156.133 Pour accéder au service

5.1.1 Endpoint

service Pendant que l'objet est créé , Le même nom sera créé endpointsObjet, Si le service est configuré readinessProbe, QuandreadinessProbe En cas d'échec de la détection ,endpoints Les correspondances seront supprimées de la Liste pod_ip, De cette façon, le trafic ne sera pas distribué aux tests de santé échoués PodMoyenne

# Voirendpoint, AvecserviceDansEndpointsContenu cohérentkubectl get endpoints nginx

5.1.2 Problèmes existants

Actuellement utiliséhostNetworkDéploiement, Doit passer par l'hôte hôte ip+portAccès à, Les questions suivantes se posent:

  • Utilisation du servicehostNetwork, Provoque une fuite massive du port de l'hôte hôte ,Danger potentiel pour la sécurité
  • Risque de conflit de port

Tous les services appartiennent à k8sCluster,Utilisez autant que possiblek8s Accès au réseau pour , Il est donc possible myblogAccès àmysql Pour transformer :

  • Pourmysql Créer une ancre clusterIpDeService,Prends ça.clusterIpConfiguré dansmyblog Dans les variables d'environnement
  • Tirer parti de la découverte de services groupés , Passage entre les composants service namePour visiter

5.2 Découverte de services

Ink8sEn grappes, Les composants peuvent être définis Service Nom implémenter la communication

Bien quepodipEtclusterip Pas fixé. ,Maisservice nameC'est fixe., Et une portabilité complète entre les grappes , Donc, en même temps que les appels entre les composants ,C'est parfait.service name Pour communiquer , Cela évite beaucoup ipFrais d'entretien, Rendre le Service yaml Les modèles sont plus simples .

# Un autre service , Pour vérifier kubectl create deployment tomcat --image=tomcatkubectl expose deployment tomcat --port=8080 --type=ClusterIP# Encore.tomcat Demande dans le conteneur nginxServiceskubectl exec -it tomcat-7d987c7694-qgfxv -- bash# Peut être utilisé directementsvc nameServices d'accèscurl nginx# Voirpod Résoudre la configuration cat /etc/resolv.conf
[email protected]:~# cat /etc/resolv.confnameserver 10.1.0.10search default.svc.cluster.local svc.cluster.local cluster.localoptions ndots:5
# Au - dessus10.1.0.10- Oui.dnsDeip[[email protected] ~]# kubectl get svc -n kube-systemNAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGEkube-dns ClusterIP 10.1.0.10 <none> 53/UDP,53/TCP,9153/TCP 10d

DémarragepodQuand,Il vakube-dnsServicescluster-ip Adresse injectée dans podDeresolve Résoudre la configuration , Ajouter le namespaceDesearchDomaine. Donc à travers namespaceAdoptionservice name Si vous visitez ,Besoin d'ajouter unnamespaceNom

# Selonresolv.confConfiguration de, Les adresses suivantes sont disponibles sur demande nginxServicescurl nginxcurl nginx.default # Permet la communication entre les espaces de noms curl nginx.default.svccurl nginx.default.svc.cluster.local

5.3 ServiceÉquilibrer la chargeNodePort

cluster-ip Est une adresse virtuelle ,Seulement dansk8s Accès interne au cluster , Cluster externe si vous accédez aux services internes , Une façon de le faire est d'utiliser NodePortComment.NodePort Par défaut à 30000-32767 , Non spécifié utilise l'un d'eux au hasard

apiVersion: v1kind: Servicemetadata: name: nginx namespace: defaultspec: ports: - port: 80 protocol: TCP targetPort: 80 selector: app: nginx type: NodePort
# Créationkubectl apply -f svc-nginx.yamlkubectl expose deployment nginx2 --port=80 --type=NodePort
# Machine disponible après le démarrage ip(ArbitrairenodeTout va bien.)+portAccès ànginxService renducurl 192.169.8.1:31429curl 192.169.8.2:31429curl 192.169.8.3:31429

Nous pouvons également accéder à nginxServices

5.4 kube-proxy

Exécuter sur chaque noeud ,Écouter API Server Changements dans les objets de service , Ensuite, la transmission du réseau peut être réalisée en créant des règles de routage du trafic. .Documents officiels

Il y a trois modes:

  • User space, Jean Kube-Proxy Écouter un port dans l'espace Utilisateur ,Tous les Service Tous transmis à ce port ,Et puis Kube-Proxy Il est transmis au niveau interne de l'application , Tous les messages passent par l'utilisateur , Faible performance ,k8s v1.2 Jeter après la version
  • Iptables, Mode par défaut actuel ,Entièrement IPtables Pour réaliser, Par le biais de nodeSur le noeudiptables Règles à appliquer serviceÉquilibrage de la charge,Mais avecservice Augmentation de la quantité ,iptables Motif en raison de la correspondance de recherche linéaire 、 Mise à jour complète et autres caractéristiques , Les performances diminuent considérablement
  • IPVS, AveciptablesEncore une fois, sur la baseNetfilter, Mais adopté hashTableau,Donc quandservice Lorsque la quantité atteint une certaine échelle ,hash L'avantage de vitesse de la table de recherche apparaîtra ,Pour améliorerservice Performance du service pour . k8s 1.8 Début de l'introduction de la version ,1.11 La version commence à se stabiliser , Besoin d'activer l'hôte ipvsModule

iptables Schéma du mode :

[[email protected] ~]# iptables-save | grep "default/nginx"
-A KUBE-NODEPORTS -p tcp -m comment --comment "default/nginx" -m tcp --dport 31429 -j KUBE-SVC-2CMXP7HKUVJN7L6M
-A KUBE-SEP-QEWF37NALXUNKCQB -s 10.2.1.13/32 -m comment --comment "default/nginx" -j KUBE-MARK-MASQ
-A KUBE-SEP-QEWF37NALXUNKCQB -p tcp -m comment --comment "default/nginx" -m tcp -j DNAT --to-destination 10.2.1.13:80
-A KUBE-SEP-THS5ZWJX3A5H6VN4 -s 10.2.1.12/32 -m comment --comment "default/nginx" -j KUBE-MARK-MASQ
-A KUBE-SEP-THS5ZWJX3A5H6VN4 -p tcp -m comment --comment "default/nginx" -m tcp -j DNAT --to-destination 10.2.1.12:80
-A KUBE-SERVICES -d 10.1.162.20/32 -p tcp -m comment --comment "default/nginx cluster IP" -m tcp --dport 80 -j KUBE-SVC-2CMXP7HKUVJN7L6M
-A KUBE-SVC-2CMXP7HKUVJN7L6M ! -s 10.2.0.0/16 -d 10.1.162.20/32 -p tcp -m comment --comment "default/nginx cluster IP" -m tcp --dport 80 -j KUBE-MARK-MASQ
-A KUBE-SVC-2CMXP7HKUVJN7L6M -p tcp -m comment --comment "default/nginx" -m tcp --dport 31429 -j KUBE-MARK-MASQ
-A KUBE-SVC-2CMXP7HKUVJN7L6M -m comment --comment "default/nginx" -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-THS5ZWJX3A5H6VN4
-A KUBE-SVC-2CMXP7HKUVJN7L6M -m comment --comment "default/nginx" -j KUBE-SEP-QEWF37NALXUNKCQB

6. Kubernetes Accès au service Ingress

PourKubernetesDeService,Que ce soitCluster-IpEtNodePort Sont des charges à quatre niveaux , Comment réaliser l'équilibrage de la charge à sept niveaux pour les services dans le cluster , Cela nécessite l'aide Ingress,Ingress Il existe de nombreuses façons d'implémenter un contrôleur ,Par exemple,nginx, Contour, Haproxy, trafik, Istio.

Ingress-nginx- Oui.7 Équilibreur de charge pour les couches , Responsable de la gestion unifiée des paires externes k8s clusterMoyenneServiceDemandes.Comprend principalement::

  • ingress-nginx-controller: Écrit par l'utilisateur ingressLes règles(CrééingressDeyamlDocumentation), Changement dynamique nginxProfil du service,Etreload Surcharger pour qu'il prenne effet (Est automatisé,AdoptionluaScript pour implémenter);
  • IngressObjet de la ressource:Oui.Nginx La configuration de IngressObjet

Logique de mise en œuvre

  • ingress controllerAdoption etkubernetes apiInteraction, Dans un Cluster dynamique de désensibilisation ingress Modification des règles

  • Et lisezingressLes règles( La règle est de dire quel nom de domaine correspond à lequel service), Selon des règles personnalisées , Générer un segment nginxConfiguration

  • Écris encore. nginx-ingress-controllerDepod- Oui.,C'estIngress controllerDepod Il y en a un. NginxServices, Le Contrôleur a généré nginx Configurer l'écriture /etc/nginx/nginx.confDans le document

  • Et puisreload Pour que la configuration prenne effet . Le problème de la configuration et de la mise à jour dynamique des noms de domaine est atteint.

6.1 Installation

Documents officiels

# En général, il peut être téléchargé plusieurs fois.
wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.0.0/deploy/static/provider/baremetal/deploy.yaml
sed -i "s#k8s.gcr.io/ingress-nginx/controller:v1.0.0.*#registry.cn-hangzhou.aliyuncs.com/google_containers/nginx-ingress-controller:v1.0.0#" deploy.yaml
sed -i "s#k8s.gcr.io/ingress-nginx/kube-webhook-certgen:v1.0.*#hzde0128/kube-webhook-certgen:v1.0#g" deploy.yaml
kubectl apply -f deploy.yaml
kubectl get pod -n ingress-nginx -owide
kubectl describe pod -n ingress-nginx
# Voirwebhook
kubectl get validatingwebhookconfigurations
# Supprimeringress-nginx-admission
kubectl delete -A ValidatingWebhookConfiguration ingress-nginx-admission

6.2 Utiliser

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
# Peut passerkubectl get ingressclass VoiringressClassName
ingressClassName: nginx
rules:
- host: nginx.openstudy.space
http:
paths:
- path: /
pathType: Prefix
backend:
service:
# Servicesservice name
name: nginx
port:
# Ports ouverts au service
number: 80
kubectl apply -f ingress.yaml
# Aucun nom de domaine à ajouter hostsTests, Changez - vous enip
vi /etc/hosts
# 192.169.8.1 nginx.openstudy.space
yum -y install
ifconfig cni0 down
ifconfig flannel.1 down
ifconfig del flannel.1
ifconfig del cni0
ip link del flannel.1
ip link del cni0
yum -y install bridge-utils
brctl delbr flannel.1
kubectl delete -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
ip link del flannel.1
ip link del cni0
rm -rf /var/lib/cni/
rm -f /etc/cni/net.d/*
systemctl restart kubelet
kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
版权声明
本文为[_ Bar _촯]所创,转载请带上原文链接,感谢
https://javamana.com/2021/09/20210914170658015m.html

  1. Vous apprendrez à construire un serveur d'applet Wechat (https) à la main
  2. 作为一名程序员我不忘初心,Java最新实习面试经验总结,
  3. 作为一名Java面试者你应该知道的,2021最新Java常用开源库总结,
  4. 作为一个程序员,你觉得最大的悲哀是什么,2021年大厂Java岗面试必问,
  5. Configuration de l'environnement Java du système win10
  6. 作為一個程序員,你覺得最大的悲哀是什麼,2021年大廠Java崗面試必問,
  7. En tant que programmeur, quelle est la plus grande tristesse que vous ressentez? L'entrevue d'emploi Java de 2021 dans une grande usine vous demandera:
  8. Comme vous devriez le savoir en tant qu'intervieweur Java, 2021 dernier résumé des bibliothèques open source couramment utilisées pour Java,
  9. En tant que programmeur, je n'oublie pas le dernier résumé de mon expérience d'entrevue de stage en Java.
  10. 作為一名Java面試者你應該知道的,2021最新Java常用開源庫總結,
  11. New feature of Java 8. Stream (). Map (general programming method: collect. Groupingby)
  12. Computer graduation project java + SSM hospital registration system
  13. 作為一名程序員我不忘初心,Java最新實習面試經驗總結,
  14. 使用Docker部署Spring-Boot项目,论程序员成长的正确姿势,
  15. Conseils pour améliorer l'efficacité du Code Java mille fois
  16. 全网首发,我在华为做Java外包的真实经历!
  17. 全套Java视频百度云,终于找到一个看得懂的JVM内存模型了,
  18. 入职3个月的Java程序员面临转正,字节跳动 京东 360 网易面试题整理,
  19. Docker tutorial series (I) introduction to docker tutorial spring cloud mybatis distributed microservice Cloud Architecture
  20. 全網首發,我在華為做Java外包的真實經曆!
  21. Lancement de l'ensemble du réseau, je fais l'expérience réelle de l'externalisation Java à Huawei!
  22. Run around with money? Li Weijia fell into the storm of endorsement! In the face of collective hot discussion, personal attitude has become the focus of attention
  23. 全套Java視頻百度雲,終於找到一個看得懂的JVM內存模型了,
  24. Un ensemble complet de vidéos Java Baidu Cloud a finalement trouvé un modèle de mémoire JVM compréhensible.
  25. Déployez le projet Spring Boot avec docker, et parlez de la bonne posture pour que les programmeurs grandissent.
  26. 关于网络优化你必须要知道的重点,GC 堆排 Tomcat 算法题,
  27. 关于电商秒杀系统中防超卖处理方案简述,Java开发热门前沿知识,
  28. Les programmeurs Java qui sont entrés dans l'entreprise pendant trois mois ont dû faire face à une correction d'échelle, et les octets ont sauté dans le traitement des questions d'entrevue de JD 360 Netease.
  29. What is the new syntax of XX ≠ null in Java?
  30. Spring scheduled task cron expression (@ scheduled)
  31. Une brève description du plan de traitement anti - surproduction dans le système d'arrêt du commerce électronique et les connaissances de pointe du développement Java.
  32. Ce que vous devez savoir sur l'optimisation du réseau, c'est que le problème de l'algorithme Tomcat de gerbage GC,
  33. 凭借这份Java面试题集,成体系化的神级Java进阶笔记,
  34. 凭借这份Java面试题集,BAT大厂面试基础题集合,
  35. Docker Knowledge point collation
  36. Redis sur la réalisation élégante des tâches retardées
  37. 憑借這份Java面試題集,BAT大廠面試基礎題集合,
  38. Avec cet ensemble de questions d'entrevue Java, l'ensemble de questions de base d'entrevue de bat,
  39. Avec cet ensemble de questions d'entrevue Java, les notes avancées Java de niveau divin sont systématisées,
  40. Opérateurs arithmétiques et opérateurs de comparaison pour JavaScript, Introduction classique au développement web
  41. MySQL + +: slow query log analysis (I)
  42. Android Architect path 21 Responsive Programming RX Java thread transformation Principles
  43. Explorer le cadre open source Android - 1. Okhttp Source Analysis
  44. 分布式宝典:限流 缓存 通讯,Java开发中常见的一些问题面试专题,
  45. 分享面试经历的网站,腾讯大牛教你自己写Java框架!
  46. Expliquer les six principes de base du modèle de conception par des exemples réels
  47. Site Web pour partager vos expériences d'entrevue, Tencent Bull vous apprend à écrire votre propre cadre Java!
  48. Dictionnaire distribué: communication de cache limitée par le courant, sujets d'entrevue pour certaines questions courantes dans le développement Java,
  49. Another uncle circle man is angry! The high-quality acting skills make people admire and achieve the highlight of the ending of spring in Jade House
  50. 10. MySQL database import, export and authorization
  51. 9. MySQL data query
  52. 8. MySQL data operation DML
  53. 7. MySQL database table engine and character set
  54. 分享面試經曆的網站,騰訊大牛教你自己寫Java框架!
  55. Les points de connaissance de Java Real - time Video Download, Byte Jumping Java R & D post ont été divulgués à l'intérieur.
  56. Introduction au JavaScript chapitre 15 (objets, clairvoyance)
  57. 前方高能,Java程序员最大的悲哀是什么?
  58. Tencent private cloud MySQL solution tdsql
  59. 前方高能,Java程序員最大的悲哀是什麼?
  60. Quelle est la plus grande tristesse des programmeurs Java à l'avenir?