Share:

Craig Bowers, développeur principal de systèmes Cloud, poursuit sa série Kubernetes 101 avec un article consacré aux ressources de base et aux contrôleurs par défaut.

Dans le deuxième volet de la série Kubernetes 101, je vais vous faire plonger plus profondément dans les ressources k8s qui vivent dans l’environnement. Il s’agit de la suite du premier article, donc si vous ne l’avez pas encore lu, vous pouvez le consulter ici

Bien qu’il existe de nombreux types de ressources pouvant être déployés dans un cluster k8s, je me concentrerai aujourd’hui sur les principaux. Au programme : namespaces, RBAC, configmaps, comptes de service, pods, services et contrôleurs par défaut.

Namespaces

Les namespaces sont un concept fondamental dans k8s et l’une des premières choses créées lorsque vous avez un nouveau cluster. Un namespace permet de regrouper des ressources ou peut être considéré comme une barrière. Nous pouvons y penser comme suit : disons que j’ai une application appelée « foo ». Je crée un namespace appelé foo dans le cluster k8s. Lorsque je déploie mon application, je peux spécifier de la déployer dans le namespace foo. Si je sais qu’une autre application appelée « bar » est déployée dans le même cluster, je pourrais essayer de consulter les ressources du namespace bar, mais je recevrais une erreur car j’ai uniquement accès au namespace foo. Si vous ne spécifiez pas de namespace, un namespace par défaut appelé default sera utilisé. Les namespacess constituent la base de l’autorisation au sein d’un cluster, car la plupart des rôles et des autorisations y sont liés.

Contrôle d’accès basé sur les rôles

Le contrôle d’accès basé sur les rôles, ou RBAC, est la façon dont k8s (version 1.8+) applique l’autorisation. Il s’agit de règles implémentées sous forme de rôle qui indiquent à k8s qui peut faire quoi au sein d’un cluster. Tout comme IAM au sein d’une plateforme Cloud, vous devez utiliser le modèle du moindre privilège lors de la définition des rôles. Il existe deux types de rôles : les rôles à l’échelle du cluster et les rôles à l’échelle du nom. Les rôles à l’échelle du cluster sont utiles pour définir des politiques globales, puis vous pouvez lier le rôle à des espaces de noms et des comptes de service spécifiques. Les rôles du namespace n’existent que dans ce namespace et ne peuvent pas être utilisés en dehors. La politique au sein du rôle est exactement la même dans les deux cas, c’est juste une question d’étendue ou d’étroitesse de leur champ d’application. Dans la politique, vous spécifiez la ressource et les actions qui peuvent être prises sur la ressource. Une ressource est toute ressource k8s comme les pods et les namespaces dont nous avons déjà parlé. Les actions peuvent être les suivantes : créer, lister, regarder, supprimer, etc…

La création d’un rôle ne fait rien tant qu’il n’est pas lié à une entité comme un utilisateur ou un compte de service. Un utilisateur dans k8s est une identité qui est externe au cluster, peut-être un compte IAM de votre fournisseur de services Cloud, ou même un compte AD si vous hébergez le cluster sur site. Les comptes de service sont internes au cluster et donnent une identité aux processus s’exécutant dans le pod. Lier le compte d’utilisateur ou de service à un rôle est la façon dont vous contrôlez l’autorisation aux ressources de k8s.

Je crée un rôle de cluster appelé « foo-role ». Ce rôle peut obtenir, répertorier, surveiller, créer et supprimer des pods.

kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: foo-role
rules:
  - apiGroups: ['*']
    resources: ['pods']
    verbs:     ['get','list','watch','create','delete']

 

Maintenant, je vais lier ce rôle à mon compte de service dans le namespace foo.

kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: foo-role-binding
  namespace: foo
roleRef:
  kind: Role
  name: foo-role
  apiGroup: rbac.authorization.k8s.io
subjects:
- kind: ServiceAccount
  name: craig
  namespace: foo

Je peux vérifier mon accès en utilisant la commande « kubectl auth can-i ».

kubectl auth can-i get pods --namespace foo --as=system:serviceaccount:foo:craig
yes

kubectl auth can-i create pods --namespace foo --as=system:serviceaccount:foo:craig
yes

J’essaie de créer un compte de service et une ressource de rôle dans le namespace foo.

kubectl auth can-i create serviceaccount --namespace foo --as=system:serviceaccount:foo:craig
no

kubectl auth can-i create role --namespace foo --as=system:serviceaccount:foo:craig
no

Comme je m’y attendais, je n’ai pas d’autorisation sur d’autres ressources que les pods.

Le test final consiste à voir si je peux obtenir ou créer des pods dans le namespace bar.

kubectl auth can-i get pods --namespace bar --as=system:serviceaccount:foo:craig
no

kubectl auth can-i create pods --namespace bar --as=system:serviceaccount:foo:craig
no

Parfait ! D’après l’accès que l’administrateur k8s m’a accordé, je ne peux prendre des mesures que sur les pods du namespace foo.

ConfigMaps

Les ConfigMaps sont un moyen d’extraire des données configurables de votre conteneur d’application et de s’y lier au moment de l’exécution. Comme la plupart des ressources, la configmap doit être déployée dans le même namespace que le pod. Une pratique courante consiste à définir votre configmap comme un magasin clé/valeur. Ensuite, dans la spécification du pod, vous pouvez faire référence aux données à partir du nom de la configmap et du nom de la clé dans la configmap. Vous pouvez même déployer un fichier de configuration existant en tant que configmap. Où le nom du fichier devient le nom de la clé dans la configmap, et le contenu du fichier est la valeur de la clé. Vous pouvez ensuite monter ce fichier dans le pod et y accéder comme vous le feriez normalement sur le système de fichiers directement.

Un exemple de données d’application dans ConfigMap :

apiVersion: v1
kind: ConfigMap
metadata:
  name: foo-key
  namespace: foo
data:
  foo.properties: |
    env=dev
    database=dev.database.endpoint:3306
  general.properties: |
    key1=value1
    key2=value2

Je vais ensuite monter la ConfigMap à l’intérieur du pod. Je spécifie le paramètre volumes qui fait référence à la ConfigMap. Ensuite, dans le paramètre du conteneur, je spécifie un volumeMounts qui correspond à la spécification du volume et je fournis le chemin pour le monter dans le conteneur.

spec:
  serviceAccountName: craig
  volumes:
  - name: application-config
    configMap:
      name: foo-key
  containers:
  - name: busybox-container
    image: gcr.io/google_containers/busybox
    command:
    - "sleep"
    - "3600"
    imagePullPolicy: IfNotPresent
    volumeMounts:
    - name: application-config
      mountPath: /var/secrets/foo

Après l’exécution du conteneur, vous pouvez voir que la ConfigMap est représentée comme un fichier dans le conteneur.

/ # ls -l /var/secrets/foo/
lrwxrwxrwx    1 root     root            21 May 21 17:41 foo.properties -> ..data/foo.properties
lrwxrwxrwx    1 root     root            25 May 21 17:41 general.properties -> ..data/general.properties

/ # cat /var/secrets/foo/foo.properties
env=dev
database=dev.database.endpoint:3306

Si vous avez des données sensibles, vous pouvez les stocker dans un « secret » qui est une autre ressource dans k8s et il peut être monté de la même manière qu’une config map. Les secrets ne sont codés qu’en base64 et ne sont donc pas entièrement sécurisés. Lors de la création d’un secret à partir d’un fichier, seul le nom du fichier est exposé dans le secret. Vous pouvez accéder aux données encodées à l’intérieur du fichier si vous avez les autorisations RBAC pour le faire, mais un simple get ou une description du secret ne suffit pas.

Retour aux Pods

Pour en revenir aux pods, j’ai dit dans le premier article de les considérer comme des conteneurs. Les pods sont en fait un regroupement de conteneurs. Vous pouvez donc avoir plusieurs conteneurs en cours d’exécution par pod. Toutefois, il est recommandé de déployer un seul conteneur par pod. Un exemple d’exécution de plusieurs conteneurs dans un pod est celui de la journalisation, où vous déployez un deuxième pod, appelé sidecar, qui contient un agent de journalisation. Le réseau Pod est un autre réseau au sein de l’écosystème k8s. Chaque pod se voit attribuer une seule IP à partir de la gamme de réseaux de pods et tous les conteneurs d’un pod se verront attribuer la même IP. Pour plusieurs conteneurs dans un seul pod, ils peuvent communiquer via localhost et le port. Les pods contiennent de nombreux attributs de métadonnées qui permettent d’identifier le pod. Il s’agit notamment des étiquettes. Les étiquettes sont importantes car elles donnent une identité au pod et sont utilisées par d’autres ressources pour contrôler les pods avec lesquels elles interagissent.  Comme je l’ai mentionné dans mon premier article, il existe plusieurs réseaux superposés, dont le réseau de services. Vous pouvez vous référer à cet article pour mieux comprendre la différence entre les deux.

Services

J’ai déjà parlé du réseau de services plusieurs fois, mais vous vous demandez peut-être encore en quoi cela consiste exactement ? Vous pouvez considérer la ressource de service comme un moyen d’équilibrer la charge entre les pods. Lorsque vous avez plusieurs pods fonctionnant sur plusieurs serveurs de nœuds, comment le réseau sait-il vers quel pod se diriger ? C’est ce que fait le service. Lorsque vous créez un service pour un ensemble de pods dans un espace de nom particulier, il est capable d’obtenir toutes les IP des pods qui correspondent aux critères, généralement des étiquettes. Le service lui-même se voit attribuer une IP de la gamme de réseaux de service. Un autre pod peut appeler le nom du service et être acheminé vers l’un des pods derrière le service. Il existe trois types de services que vous pouvez déployer, 1) ClusterIP, NodePort et LoadBalancer. Avec ClusterIP, le service se voit attribuer une IP qui n’est adressable qu’au sein du cluster. Bonne option pour les services dorsaux qui doivent communiquer entre eux. Avec NodePort, le service se voit attribuer un port aléatoire dans une plage spécifiée sur le nœud de travail lui-même. Le service est accessible via l’IP du nœud et le port qui lui a été attribué. Cela permet d’établir une connexion depuis l’extérieur du cluster. Le port sera réservé sur tous les nœuds de travail, vous pouvez donc utiliser n’importe quelle IP de nœud de travail pour établir la connexion. Avec le type LoadBalancer, cela créera un équilibreur de charge sur la plateforme Cloud sous-jacente que vous utilisez et n’est pris en charge que sur les plateformes Cloud.

Contrôleurs

Nous terminons cette série par une plongée plus profonde dans les contrôleurs par défaut des nœuds maîtres. Pour résumer, les contrôleurs remplissent des fonctions spécifiques dans l’environnement k8s. Les quatre contrôleurs par défaut qui sortent de l’emballage sont les points de terminaison, les nœuds, la réplication et les contrôleurs de jetons de compte de service (SA). Le contrôleur de point de terminaison joint les services aux pods. Je viens de parler de la création de services et nous pouvons maintenant voir une partie de la magie qui se produit sous le capot. Lorsqu’un service est créé, le contrôleur de point de terminaison crée un objet de point de terminaison pour le service. L’objet du point de terminaison contient une liste de toutes les IP de pod qui sont dans le service. Le service vérifie constamment l’objet d’extrémité et si une IP change, il la met à jour afin de toujours acheminer le trafic vers un pod sain. Le contrôleur de nœuds est chargé de lancer de nouveaux nœuds et de vérifier l’état de santé de tous les nœuds. K8s lui-même ne peut pas vraiment lancer de nouveaux nœuds. Pour que cela fonctionne, il faut une configuration de mise à l’échelle automatique sur la plateforme de votre fournisseur Cloud. Le contrôleur de réplication est responsable du maintien du nombre correct de pods dans le cluster. Le contrôleur SA et Token assure la génération d’un compte de service et d’un jeton API par défaut pour chaque namespace. Lorsque vous créez un compte de service, ce contrôleur génère également un jeton API pour ce compte. Le jeton API permet au compte de s’authentifier auprès du serveur API, mais nous y reviendrons dans une série ultérieure. Il existe de nombreux autres types de contrôleurs avec lesquels vous vous familiariserez à mesure que vous continuerez à travailler avec Kubernetes.

Restez à l’écoute pour les prochaines séries où je parlerai de la façon dont vous, en tant qu’utilisateur final, pouvez interagir avec le cluster pour créer et modifier toutes ces ressources que j’ai approfondies, ainsi que des ressources supplémentaires autour des déploiements de pods.

 

Références :

https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/

https://kubernetes.io/docs/reference/access-authn-authz/rbac/

https://kubernetes.io/docs/tasks/configure-pod-container/configure-pod-configmap/

https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/

https://kubernetes.io/docs/concepts/workloads/pods/pod-overview/

https://kubernetes.io/docs/tutorials/kubernetes-basics/expose/expose-intro/

https://kubernetes.io/docs/reference/command-line-tools-reference/kube-controller-manager/