Ce tutoriel décrit comment personnaliser les nœuds d'un cluster Google Kubernetes Engine (GKE) à l'aide de DaemonSets. Un DaemonSet permet de garantir que tous les nœuds (ou les nœuds sélectionnés) exécutent une copie d'un pod. Lorsque de nouveaux nœuds sont ajoutés à un cluster, ils exécutent également un pod du DaemonSet.
Si les outils et systèmes avec lesquels vous initialisez vos clusters sont différents de ceux avec lesquels vous exécutez vos charges de travail, l'effort nécessaire à la gestion de votre environnement augmente. Par exemple, si vous initialisez les nœuds de cluster à l'aide d'un outil de gestion des configurations, vous vous appuyez sur une procédure située en dehors de l'environnement d'exécution accueillant le reste de vos charges de travail. L'utilisation d'un DaemonSet vous permet d'utiliser les mêmes outils pour orchestrer vos charges de travail que ceux que vous utilisez pour modifier vos nœuds GKE.
L'objectif de ce tutoriel est d'aider les administrateurs système, les ingénieurs système et les opérateurs d'infrastructure à simplifier l'initialisation des clusters Kubernetes.
Avant de lire cette page, assurez-vous de connaître les éléments suivants :
Dans ce tutoriel, vous allez apprendre à utiliser les rejets et tolérances Kubernetes pour vous assurer que les nœuds sont configurés par un DaemonSet avant que les charges de travail d'application puissent y être planifiées.
Objectifs
Dans ce tutoriel, vous allez effectuer les opérations suivantes :
- Provisionner un cluster GKE
- Appliquez un taint à un pool de nœuds pour empêcher la planification des charges de travail avant d'appliquer la configuration des nœuds.
- Déployez un DaemonSet qui configure les nœuds et supprime la contamination.
- Vérifiez que les nœuds du cluster sont configurés et que la contamination est supprimée.
Coûts
Dans ce document, vous utilisez les composants facturables suivants de Google Cloud :
Pour obtenir une estimation des coûts en fonction de votre utilisation prévue,
utilisez le simulateur de coût.
Une fois que vous avez terminé les tâches décrites dans ce document, supprimez les ressources que vous avez créées pour éviter que des frais vous soient facturés. Pour en savoir plus, consultez la section Effectuer un nettoyage.
Avant de commencer
- Connectez-vous à votre compte Google Cloud . Si vous débutez sur Google Cloud, créez un compte pour évaluer les performances de nos produits en conditions réelles. Les nouveaux clients bénéficient également de 300 $ de crédits sans frais pour exécuter, tester et déployer des charges de travail.
-
In the Google Cloud console, on the project selector page, select or create a Google Cloud project.
Roles required to select or create a project
- Select a project: Selecting a project doesn't require a specific IAM role—you can select any project that you've been granted a role on.
-
Create a project: To create a project, you need the Project Creator role
(
roles/resourcemanager.projectCreator), which contains theresourcemanager.projects.createpermission. Learn how to grant roles.
-
Verify that billing is enabled for your Google Cloud project.
-
In the Google Cloud console, on the project selector page, select or create a Google Cloud project.
Roles required to select or create a project
- Select a project: Selecting a project doesn't require a specific IAM role—you can select any project that you've been granted a role on.
-
Create a project: To create a project, you need the Project Creator role
(
roles/resourcemanager.projectCreator), which contains theresourcemanager.projects.createpermission. Learn how to grant roles.
-
Verify that billing is enabled for your Google Cloud project.
Implications en termes de sécurité des DaemonSet privilégiés
L'utilisation du paramètre securityContext: privileged: true dans un DaemonSet (ou n'importe quel pod) est puissante, mais elle a des implications importantes en termes de sécurité, car elle désactive la plupart des limites d'isolation des conteneurs pour ce pod. Vous devez connaître les restrictions de sécurité et les risques suivants qu'elle introduit :
- Échappement de conteneur ou compromission de l'hôte : une faille dans l'application ou l'image du conteneur privilégié peut directement entraîner un accès racine sur le nœud hôte.
- Violation du principe du moindre privilège : le mode privilégié accorde toutes les fonctionnalités, probablement bien plus que nécessaire pour une tâche spécifique. Cet accès étendu augmente les dommages potentiels si le conteneur est compromis.
- Déstabilisation des nœuds : des commandes accidentelles ou malveillantes peuvent s'exécuter dans le conteneur privilégié, par exemple des valeurs
sysctlincorrectes ou des commandes telles querm -rf /host/boot. Ces types de commandes peuvent planter ou corrompre le système d'exploitation du nœud hôte. - Déplacement latéral : compromettre un nœud via un DaemonSet privilégié donne à un pirate informatique un point d'ancrage solide pour attaquer d'autres nœuds, le plan de contrôle Kubernetes ou les systèmes connectés.
- Exposition des données : un accès illimité au système de fichiers hôte (
/) peut exposer des données sensibles stockées sur le nœud, y compris des identifiants, des clés ou des données appartenant à d'autres pods s'ils utilisent des volumes hostPath. - Surface d'attaque accrue : le mode privilégié expose davantage d'appels système et de fonctionnalités du noyau hôte à des exploits potentiels depuis le conteneur.
Pour éviter les risques de sécurité, vous devez connaître les bonnes pratiques et les mesures d'atténuation suivantes :
- Évitez d'utiliser le mode privilégié : l'approche la plus sécurisée consiste à éviter complètement le paramètre
privileged: true. - Utiliser les fonctionnalités Linux : si des droits élevés sont nécessaires, vous pouvez accorder des fonctionnalités Linux spécifiques telles que
NET_ADMIN,SYS_ADMINetSYS_MODULEdans le champsecurityContext.capabilities.addau lieu d'un accès complet. Cette approche suit le principe du moindre privilège, que nous recommandons plutôt que d'accorder des autorisations étendues. - Limitez le champ d'application : exécutez des DaemonSets privilégiés uniquement sur des pools de nœuds dédiés, éventuellement contaminés, pour limiter l'impact potentiel si un conteneur est compromis.
- Appliquez des règles : utilisez des outils tels que Policy Controller ou Gatekeeper pour créer des règles qui limitent, auditent ou exigent une justification pour le déploiement de conteneurs privilégiés.
- Analysez et utilisez des images de confiance : utilisez l'autorisation binaire et une analyse rigoureuse des images pour vous assurer que seules les images de conteneurs approuvées et fiables sont exécutées avec des droits d'accès élevés.
- Réduisez les installations d'hôte : n'installez que les chemins d'hôte spécifiques nécessaires et utilisez
readOnly: truechaque fois que possible. Évitez d'installer l'intégralité du système de fichiers racine (/). - Effectuez des audits réguliers : examinez régulièrement toutes les charges de travail exécutées avec le paramètre
privileged: true.
Amorcer l'environnement
Dans cette section, vous allez exécuter les opérations suivantes :
- Activer les API Cloud nécessaires
- Provisionner un compte de service ayant des droits limités sur les nœuds du cluster GKE
- Préparer le cluster GKE
- Accorder à l'utilisateur des droits d'administrateur sur le cluster
Activer API Cloud
Ouvrez Cloud Shell.
Sélectionnez le projet Google Cloud :
gcloud config set project project-id
Remplacez
project-idpar l'ID du projetGoogle Cloud que vous avez créé ou sélectionné pour ce tutoriel.Activez l'API Kubernetes Engine :
gcloud services enable container.googleapis.com
Provisionner un compte de service pour gérer les clusters GKE
Dans cette section, vous allez créer un compte de service associé aux nœuds du cluster. Dans ce tutoriel, les nœuds GKE utilisent ce compte de service au lieu du compte de service par défaut. Nous vous recommandons de n'accorder au compte de service que les rôles et autorisations d'accès nécessaires pour exécuter l'application.
Les rôles requis pour le compte de service sont les suivants :
- Rôle Lecteur Monitoring (
roles/monitoring.viewer) : ce rôle donne un accès en lecture seule aux données de surveillance. - Rédacteur de métriques de surveillance (
roles/monitoring.metricWriter). Ce rôle permet d'écrire des données de surveillance. - Rôle Rédacteur de journaux (
roles/logging.logWriter) : ce rôle permet d'écrire des journaux.
Pour provisionner un compte de service, procédez comme suit :
Dans Cloud Shell, initialisez une variable d'environnement qui stocke le nom du compte de service :
GKE_SERVICE_ACCOUNT_NAME=ds-init-tutorial-gkeCréez un compte de service :
gcloud iam service-accounts create "$GKE_SERVICE_ACCOUNT_NAME" \ --display-name="$GKE_SERVICE_ACCOUNT_NAME"Initialisez une variable d'environnement qui stocke le nom du compte de messagerie du compte de service :
GKE_SERVICE_ACCOUNT_EMAIL="$(gcloud iam service-accounts list \ --format='value(email)' \ --filter=displayName:"$GKE_SERVICE_ACCOUNT_NAME")"Associez les rôles de gestion de l'authentification et des accès (IAM) au compte de service :
gcloud projects add-iam-policy-binding \ "$(gcloud config get-value project 2> /dev/null)" \ --member serviceAccount:"$GKE_SERVICE_ACCOUNT_EMAIL" \ --role roles/monitoring.viewer gcloud projects add-iam-policy-binding \ "$(gcloud config get-value project 2> /dev/null)" \ --member serviceAccount:"$GKE_SERVICE_ACCOUNT_EMAIL" \ --role roles/monitoring.metricWriter gcloud projects add-iam-policy-binding \ "$(gcloud config get-value project 2> /dev/null)" \ --member serviceAccount:"$GKE_SERVICE_ACCOUNT_EMAIL" \ --role roles/logging.logWriter
Préparer le cluster GKE
Dans cette section, vous allez lancer le cluster GKE, accorder des autorisations et terminer la configuration du cluster.
Ici, un cluster doté d'un nombre relativement faible de petits nœuds à usage général suffit à démontrer le concept de ce tutoriel. Vous allez tout d'abord créer un cluster avec un seul pool de nœuds (le pool par défaut),
Dans Cloud Shell, créez et lancez un cluster GKE régional :
gcloud container clusters create ds-init-tutorial \ --enable-ip-alias \ --machine-type=n1-standard-2 \ --metadata disable-legacy-endpoints=true \ --node-labels=app=default-init \ --node-locations us-central1-a,us-central1-b,us-central1-c \ --no-enable-basic-auth \ --no-issue-client-certificate \ --num-nodes=1 \ --location us-central1 \ --service-account="$GKE_SERVICE_ACCOUNT_EMAIL"
Appliquer des configurations de nœud à l'aide d'un DaemonSet
Dans cette section, vous allez empêcher l'exécution des charges de travail sur les nœuds avant la fin de la configuration en appliquant un rejet au pool de nœuds. Vous déployez ensuite un DaemonSet qui effectue les opérations suivantes :
- Planifie les pods sur les nœuds rejetés en utilisant une tolérance pour le rejet.
- Exécute un conteneur init privilégié qui applique d'abord la configuration du nœud à l'aide de
sysctl, puis supprime le taint du nœud à l'aide dekubectl. La suppression du rejet permet de planifier des charges de travail sur le nœud. - Il programme et exécute un conteneur de pause qui reste inactif et ne consomme aucune ressource pour empêcher le DaemonSet de reprogrammer le pod utilisé pour la configuration.
Ce tutoriel applique le paramètre de noyau vm.max_map_count=262144 comme exemple de configuration.
Appliquez un rejet au pool de nœuds par défaut :
gcloud container node-pools update default-pool \ --cluster=ds-init-tutorial \ --node-taints=node.config.status/stage=configuring:NoSchedule \ --region=us-central1Avec ce rejet, seuls les pods qui le tolèrent, comme le pod DaemonSet, peuvent être programmés dans ce pool de nœuds.
Vérifiez que la contamination est appliquée :
kubectl describe nodes -l cloud.google.com/gke-nodepool=default-pool | grep TaintsL'état du nœud doit être
node.config.status/stage=configuring:NoSchedule.Enregistrez le manifeste suivant sous le nom
auto-untaint-daemonset.yaml:# WARNING: This DaemonSet runs as privileged, which has significant # security implications. Only use this on clusters where you have # strict controls over what is deployed. --- apiVersion: v1 kind: ServiceAccount metadata: name: node-config-sa namespace: default --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: node-patcher-role rules: - apiGroups: [""] resources: ["nodes"] # Permissions needed to read and remove a taint from the node. verbs: ["get", "patch", "update"] --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: node-config-binding subjects: - kind: ServiceAccount name: node-config-sa namespace: default roleRef: kind: ClusterRole name: node-patcher-role apiGroup: rbac.authorization.k8s.io --- apiVersion: apps/v1 kind: DaemonSet metadata: name: auto-untaint-daemonset labels: app: auto-untaint-configurator spec: selector: matchLabels: app: auto-untaint-configurator updateStrategy: type: RollingUpdate template: metadata: labels: app: auto-untaint-configurator spec: serviceAccountName: node-config-sa hostPID: true # Toleration now matches the taint on your node. tolerations: - key: "node.config.status/stage" operator: "Equal" value: "configuring" effect: "NoSchedule" volumes: - name: host-root-fs hostPath: path: / initContainers: - name: configure-and-untaint image: ubuntu:22.04 # Using a standard container image. securityContext: privileged: true # Required for chroot and sysctl. env: - name: NODE_NAME valueFrom: fieldRef: fieldPath: spec.nodeName volumeMounts: - name: host-root-fs mountPath: /host command: ["/bin/bash", "-c"] args: - | # Using explicit error checking for each critical command. # Define the configuration and taint details. SYSCTL_PARAM="vm.max_map_count" SYSCTL_VALUE="262144" TAINT_KEY="node.config.status/stage" echo "Running configuration on node: ${NODE_NAME}" # 1. APPLY CONFIGURATION echo "--> Applying ${SYSCTL_PARAM}=${SYSCTL_VALUE}..." if ! chroot /host sysctl -w "${SYSCTL_PARAM}=${SYSCTL_VALUE}"; then echo "ERROR: Failed to apply sysctl parameter." >&2 exit 1 fi echo "--> Configuration applied successfully." # 2. UNTAINT THE NODE # This command removes the taint from the node this Pod is running on. echo "--> Untainting node ${NODE_NAME} by removing taint ${TAINT_KEY}..." if ! /host/home/kubernetes/bin/kubectl taint node "${NODE_NAME}" "${TAINT_KEY}:NoSchedule-"; then echo "ERROR: Failed to untaint the node." >&2 exit 1 fi echo "--> Node has been untainted and is now schedulable." # The main container is minimal; it just keeps the Pod running. containers: - name: pause-container image: registry.k8s.io/pause:3.9Ce fichier manifeste crée un ServiceAccount, un ClusterRole et un ClusterRoleBinding pour accorder au DaemonSet l'autorisation de supprimer les rejets des nœuds. Le DaemonSet déploie un pod sur chaque nœud qui tolère le taint
configuring:NoSchedule. Ce pod exécute un conteneur d'initialisation privilégié qui applique la configurationsysctl(vm.max_map_count=262144) et supprime le rejet de nœud, ce qui rend le nœud planifiable. Un conteneur de pause démarre alors pour maintenir le pod en cours d'exécution.Le conteneur init s'exécute en mode privilégié, ce qui a des implications en termes de sécurité. Pour en savoir plus, consultez Compromis et restrictions de sécurité liés aux DaemonSets privilégiés.
Appliquez le fichier manifeste :
kubectl apply -f auto-untaint-daemonset.yamlVérifiez que les pods DaemonSet sont créés et attendez qu'ils atteignent l'état
Running:kubectl get pods -l app=auto-untaint-configurator -o wideL'état
Runningindique que le conteneur d'initialisation s'est terminé correctement. Notez le nom du pod pour pouvoir l'utiliser afin de vérifier l'initialisation dans la section suivante.
Valider et vérifier la procédure d'initialisation
Une fois la configuration des nœuds terminée, vous pouvez vérifier les résultats en consultant les journaux.
Consultez les journaux du conteneur init de l'un des pods pour afficher sa sortie :
kubectl logs POD_NAME -c configure-and-untaintRemplacez
POD_NAMEpar le nom de votre pod.Le résultat qui s'affiche doit indiquer que la configuration a bien été effectuée et que le nœud a été non contaminé.
Vérifiez que la contamination a été supprimée :
kubectl describe nodes -l cloud.google.com/gke-nodepool=default-pool | grep TaintsL'état du nœud doit indiquer
Taints: <none>ou afficher des rejets dont la clé estnode.config.status/stage.
Effectuer un nettoyage
Pour éviter que les ressources utilisées dans ce tutoriel soient facturées sur votre compte Google Cloud , vous pouvez supprimer le projet que vous avez créé pour ce tutoriel. Si vous avez créé un projet dédié à ce tutoriel, vous pouvez le supprimer entièrement. Si vous avez utilisé un projet existant, mais que vous ne souhaitez pas le supprimer, suivez les étapes ci-dessous pour nettoyer le projet.
Nettoyer le projet
Pour nettoyer un projet sans le supprimer, vous devez supprimer les ressources que vous avez créées dans le cadre de ce tutoriel.
Dans Cloud Shell, supprimez le cluster GKE :
gcloud container clusters delete ds-init-tutorial --quiet --region us-central1Supprimez le compte de service :
gcloud iam service-accounts delete "$GKE_SERVICE_ACCOUNT_EMAIL" --quiet
Supprimer le projet
Le moyen le plus simple d'empêcher la facturation est de supprimer le projet que vous avez créé pour ce tutoriel.
- Dans la console Google Cloud , accédez à la page Gérer les ressources.
- Dans la liste des projets, sélectionnez le projet que vous souhaitez supprimer, puis cliquez sur Supprimer.
- Dans la boîte de dialogue, saisissez l'ID du projet, puis cliquez sur Arrêter pour supprimer le projet.
Étapes suivantes
- Apprenez-en plus sur GKE.
- Mettez en œuvre une chaîne d'approvisionnement logicielle sécurisée.
- Découvrez comment renforcer la sécurité de votre cluster GKE.
- Découvrez des architectures de référence, des schémas et des bonnes pratiques concernant Google Cloud. Consultez notre Cloud Architecture Center.