Blog de dada

DevOps, bidouilleur et routard plein de logiciels libres

Debian

Rook pour gérer le système de fichiers

Rédigé par dada / 08 novembre 2018 / 4 commentaires


Un cluster k8s, c'est presque "out-of-the-box" quand on veut s'en servir pour lancer des conteneurs qui n'amènent avec eux qu'un traitement. En gros, votre conteneur contient un script python qui va afficher 42 fois le message "toto" et mourir. C'est un exemple idiot, mais ce n'est pas un détail.
Dans le cadre de ce tuto qui me sert à préparer la migration de ce blog dans un cluster k8s, j'ai besoin de pouvoir stocker le contenu de mes billets quelque part. Le mettre dans un conteneur est une aberration et sera synonyme de perte de données quand celui-ci mourra.

Pour m'en sortir, on m'a parlé de Rook.io, un système de cluster Ceph intégré à Kubernetes. On va voir comment s'en servir maintenant.

Installer Rook

Installer les dépendances

Il va falloir installer des paquets sur vos membres du cluster. À l'exception du Master.
apt-get install ceph-fs-common ceph-common

Récupérer le binaire RBD

cd /bin  
sudo curl -O https://raw.githubusercontent.com/ceph/ceph-docker/master/examples/kubernetes-coreos/rbd 
sudo chmod +x /bin/rbd 
rbd #Command to download ceph images
On va partir sur la version beta de l'outil. C'est la plus stable.

Ajouter le dépôt Rook dans Helm

dada@k8smaster:~$ helm repo add rook-beta https://charts.rook.io/beta
"rook-beta" has been added to your repositories

Récupérer Rook

À la manière de APT :
dada@k8smaster:~$ helm install --namespace rook-ceph-system rook-beta/rook-ceph
NAME:   torrid-dragonfly
LAST DEPLOYED: Sun Nov  4 11:22:24 2018
NAMESPACE: rook-ceph-system
STATUS: DEPLOYED
Le message est bien plus long. Je vous invite à prendre le temps de le décortiquer pour y repérer les infos intéressantes.

On peut y récupérer la commande pour valider la présence du pod Operator :
dada@k8smaster:~$ kubectl --namespace rook-ceph-system get pods -l "app=rook-ceph-operator"
NAME                                 READY   STATUS    RESTARTS   AGE
rook-ceph-operator-f4cd7f8d5-zt7f4   1/1     Running   0          2m25
On y trouve aussi les pods nécessaires au cluster dans nos différents nodes :
dada@k8smaster:~$ kubectl get pods --all-namespaces -o wide | grep rook
rook-ceph-system   rook-ceph-agent-pb62s                   1/1     Running   0          4m10s   192.168.0.30   k8snode1    <none
rook-ceph-system   rook-ceph-agent-vccpt                   1/1     Running   0          4m10s   192.168.0.18   k8snode2    <none>
rook-ceph-system   rook-ceph-operator-f4cd7f8d5-zt7f4      1/1     Running   0          4m24s   10.244.2.62    k8snode2    <none>
rook-ceph-system   rook-discover-589mf                     1/1     Running   0          4m10s   10.244.2.63    k8snode2    <none>
rook-ceph-system   rook-discover-qhv9q                     1/1     Running   0          4m10s   10.244.1.232   k8snode1    <none>
On a la base ! Vous devriez avoir un agent et un discover par node. L'operator, lui, reste tout seul.

Création du cluster

Maintenant que Rook tourne, il lui faut lui faire comprendre que nous voulons un cluster qui va bien pour nos volumes.

Je reprends ci-dessous l'exemple de la documentation : ça marche bien comme ça.
#################################################################################
# This example first defines some necessary namespace and RBAC security objects.
# The actual Ceph Cluster CRD example can be found at the bottom of this example.
#################################################################################
apiVersion: v1
kind: Namespace
metadata:
  name: rook-ceph
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: rook-ceph-cluster
  namespace: rook-ceph
---
kind: Role
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
  name: rook-ceph-cluster
  namespace: rook-ceph
rules:
- apiGroups: [""]
  resources: ["configmaps"]
  verbs: [ "get", "list", "watch", "create", "update", "delete" ]
---
# Allow the operator to create resources in this cluster's namespace
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
  name: rook-ceph-cluster-mgmt
  namespace: rook-ceph
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: rook-ceph-cluster-mgmt
subjects:
- kind: ServiceAccount
  name: rook-ceph-system
  namespace: rook-ceph-system
---
# Allow the pods in this namespace to work with configmaps
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
  name: rook-ceph-cluster
  namespace: rook-ceph
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: rook-ceph-cluster
subjects:
- kind: ServiceAccount
  name: rook-ceph-cluster
  namespace: rook-ceph
---
#################################################################################
# The Ceph Cluster CRD example
#################################################################################
apiVersion: ceph.rook.io/v1beta1
kind: Cluster
metadata:
  name: rook-ceph
  namespace: rook-ceph
spec:
  cephVersion:
    # For the latest ceph images, see https://hub.docker.com/r/ceph/ceph/tags
    image: ceph/ceph:v13.2.2-20181023
  dataDirHostPath: /var/lib/rook
  dashboard:
    enabled: true
  storage:
    useAllNodes: true
    useAllDevices: false
    config:
      databaseSizeMB: "1024"
      journalSizeMB: "1024"
On apply tout ça :
kubectl create -f cluster.yaml
Si tout s'est bien passé et que vous avez patienté quelques minutes, voici ce que vous devriez avoir maintenant :
dada@k8smaster:~/rook$ kubectl get pods -n rook-ceph -o wide 
NAME                                   READY   STATUS      RESTARTS   AGE     IP             NODE       NOMINATED NODE
rook-ceph-mgr-a-5f6dd98574-tm9md       1/1     Running     0          3m3s    10.244.2.126   k8snode2   <none>
rook-ceph-mon0-sk798                   1/1     Running     0          4m36s   10.244.1.42    k8snode1   <none>
rook-ceph-mon1-bxgjt                   1/1     Running     0          4m16s   10.244.2.125   k8snode2   <none>
rook-ceph-mon2-snznb                   1/1     Running     0          3m48s   10.244.1.43    k8snode1   <none>
rook-ceph-osd-id-0-54c856d49d-77hfr    1/1     Running     0          2m27s   10.244.1.45    k8snode1   <none>
rook-ceph-osd-id-1-7d98bf85b5-rt4jw    1/1     Running     0          2m26s   10.244.2.128   k8snode2   <none>
rook-ceph-osd-prepare-k8snode1-dzd5v   0/1     Completed   0          2m41s   10.244.1.44    k8snode1   <none>
rook-ceph-osd-prepare-k8snode2-2jgvg   0/1     Completed   0          2m41s   10.244.2.127   k8snode2   <none>

Créer le système de fichiers

Le cluster est en place, mais rien ne nous permet de l'utiliser. On va remédier à ça en lui assignant un système de fichiers. Pour l'exemple, j'ai choisi la méthode dite Block Storage. Elle permet de mettre en place des Persistent Volumes (PV) qui pourront être utilisés par un seul pod à la fois. S'il vous faut plusieurs pods accédant à un PV, dirigez-vous vers le Shared File System.

Pour que ça marche, créez la configuration de la StorageClass :
apiVersion: ceph.rook.io/v1beta1
kind: Pool
metadata:
  name: replicapool
  namespace: rook-ceph
spec:
  replicated:
    size: 3
---
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
   name: rook-ceph-block
provisioner: ceph.rook.io/bloc
parameters:
  pool: replicapool
  clusterNamespace: rook-ceph
On l'applique :
kubectl create -f storageclass.yaml
On est bon pour le système de fichiers !
On ne va pas créer de pod s'en servant pour le moment. Si vous y allez, vous ne pourrez rien en tirer puisque vous ne pouvez pas encore accéder à votre cluster depuis l'extérieur. C'est la prochaine étape.

Le Dashboard Ceph

Si vous avez pris le temps de lire la configuration du cluster proposée un peu plus haut, vous devriez avoir vu que le Dashboard est activé dans le yaml. Comme pour Kubernetes, Rook intègre un dashboard pour y voir un peu plus clair.

Il est "enable", mais pas activé. Corrigeons ça à l'aide en créant le fichier dashboard-external.yaml :
dada@k8smaster:~/rook$ cat dashboard-external.yaml 
apiVersion: v1
kind: Service
metadata:
  name: rook-ceph-mgr-dashboard-external
  namespace: rook-ceph
  labels:
    app: rook-ceph-mgr
    rook_cluster: rook-ceph
spec:
  ports:
  - name: dashboard
    port: 7000
    protocol: TCP
    targetPort: 7000
  selector:
    app: rook-ceph-mgr
    rook_cluster: rook-ceph
  sessionAffinity: None
  type: NodePort
Récupérez le port exposé :
dada@k8smaster:~/rook$ kubectl -n rook-ceph get service | grep Node
rook-ceph-mgr-dashboard-external   NodePort    10.99.88.135     <none>        7000:31165/TCP   3m41s
Et vous devriez pouvoir joindre le dashboard en utilisant l'IP du master et le port qui va bien : 31165 dans mon cas.

Si tout va bien, vous devriez pouvoir vous promener dans une page web qui ressemble à ça :

Considérations

La gestion du système de fichiers que je vous propose n'est pas sans risque. Les volumes que vous allez créer doivent être configurés sérieusement. Les exemples que vous aller trouver par-ci par-là vous permettront d'avoir un stockage dans votre cluster k8s, certes, mais rendront sans doute vos volumes dépendants de vos pods. Si vous décidez de supprimer le pod pour lequel vous avec un PVC, le PV disparaîtra, et vos données avec.

Prenez le temps de bien réfléchir et de bien plus étudier la question que ce que je vous propose dans mes billets avant de vous lancer dans une installation en production.

La suite ?


Se faciliter la vie avec Helm

Rédigé par dada / 06 novembre 2018 / Aucun commentaire

Perdu ? Retrouvez les épisodes précédents :

Helm ? Rien à voir avec le Gouffre du même nom. Il s'agit ici de passer par un outil permettant à l'utilisateur de k8s d'installer des pods en passant par son dépôt officiel. C'est une sorte de gestionnaire de paquet, un peu comme APT pour Debian. Ça nous facilite la vie et ça nous permet d'utiliser toute la puissance de l'orchestrateur sans se prendre la tête.

Installer Helm

Récupérer les binaires

Helm a besoin de son exécutable pour fonctionner. Allez le récupérer et déposez-le sur votre master :
dada@k8smaster:~$ mkdir helm
dada@k8smaster:~$ cd helm
dada@k8smaster:~/helm$ wget https://storage.googleapis.com/kubernetes-helm/helm-v2.11.0-linux-amd64.tar.gz
dada@k8smaster:~/helm$ tar -zxvf helm-v2.11.0-linux-amd64.tar.gz
Rendez-le utilisable
root@k8smaster:/home/dada/helm# mv linux-amd64/helm  /usr/local/bin/
Vous devriez maintenant pouvoir vous en servir avec votre utilisateur normal (pas root !)
helm version
Client: &version.Version{SemVer:"v2.11.0", GitCommit:"2e55dbe1fdb5fdb96b75ff144a339489417b146b", GitTreeState:"clean"}

Initialiser Helm

Tout simplement avec la commande helm init :
dada@k8smaster:~$ helm init
$HELM_HOME has been configured at /home/dada/.helm.

Tiller (the Helm server-side component) has been installed into your Kubernetes Cluster.

Please note: by default, Tiller is deployed with an insecure 'allow unauthenticated users' policy.
To prevent this, run `helm init` with the --tiller-tls-verify flag.
For more information on securing your installation see: https://docs.helm.sh/using_helm/#securing-your-helm-installation
Happy Helming!
Happy Helming, comme ils disent !

Si vous avez bien tapé la commande "helm version" donnée quelques lignes plus haut, vous devriez avoir remarqué l'erreur suivante :
Error: could not find tiller
Cachée volontairement jusque là, elle attendait l'initialisation pour disparaître !
dada@k8smaster:~$ helm version
Client: &version.Version{SemVer:"v2.11.0", GitCommit:"2e55dbe1fdb5fdb96b75ff144a339489417b146b", GitTreeState:"clean"}
Server: &version.Version{SemVer:"v2.11.0", GitCommit:"2e55dbe1fdb5fdb96b75ff144a339489417b146b", GitTreeState:"clean"}
Un nouveau pod est maintenant apparu : tiller !
dada@k8smaster:~$ kubectl get pods --all-namespaces -o wide | grep tiller
kube-system   tiller-deploy-845cffcd48-268tr          1/1     Running   0          4m22s   10.244.2.61    k8snode2    <none>

Configurer les permissions

Je vais rappeler que nous sommes dans le cadre d'un cluster de test. C'est un détail important parce que je ne vais pas m'étendre avec les jeux de permission de Kubernetes. Pour aller plus vite, et pour permettre à Helm d'accéder à l'API à travers laquelle tout transite, je vais vous donner les commandes pour lui donner des droits d'admin. Ce n'est pas à faire en production !

Donner les droits admin à Helm

dada@k8smaster:~$ kubectl create serviceaccount --namespace kube-system tiller
dada@k8smaster:~$ kubectl create clusterrolebinding tiller-cluster-rule --clusterrole=cluster-admin --serviceaccount=kube-system:tiller
dada@k8smaster:~$ kubectl patch deploy --namespace kube-system tiller-deploy -p '{"spec":{"template":{"spec":{"serviceAccount":"tiller"}}}}'

Mettre à jour la configuration

dada@k8smaster:~$ helm init --service-account tiller --upgrade
$HELM_HOME has been configured at /home/dada/.helm.

Tiller (the Helm server-side component) has been upgraded to the current version.
Happy Helming
Helm devrait maintenant pouvoir s'amuser !

La suite ?

Installer Rook pour prendre en charge nos volumes persistants.

Le dashboard de Kubernetes

Rédigé par dada / 04 novembre 2018 / 1 commentaire


Perdu ? Retrouvez les épisodes précédents :

À la fin de la deuxième partie de ce tuto, je dis que les couleurs, c'est quand même mieux. Enfin, c'est surtout assez fatiguant de lutter avec un grand nombre de terminaux pour vérifier le bon comportement du cluster. Pour nous sauver, il y a un Dashboard.

Installer le Dashboard

Pour installer le Dashboard, placez-vous sur votre master et tapez la commande suivante :
kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/master/src/deploy/recommended/kubernetes-dashboard.yaml
Kubernetes va aller chercher la configuration nécessaire la mise à en place du Dashboard directement depuis son dépôt Github et le faire apparaître dans la liste des pods de votre cluster.
dada@k8smaster:~$  kubectl get pods --all-namespaces -o wide | grep dashb
kube-system   kubernetes-dashboard-77fd78f978-f8p9l   1/1     Running   0          60s     10.244.1.230   k8snode1    <none>
Il est  "Running", ça veut dire qu'il est disponible, mais pas encore accessible.

Créez un compte utilisateur

Créez un fichier admin-user.yaml avec ce qui suit dedans :
apiVersion: v1
kind: ServiceAccount
metadata:
  name: admin-user
  namespace: kube-system
Puis créez le rôle qui lui sera attaché : admin-role.yaml
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
  name: admin-user
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: cluster-admin
subjects:
- kind: ServiceAccount
  name: admin-user
  namespace: kube-system
Chargez ces configurations dans le cluster :
kubectl apply -f admin-user.yaml
kubectl apply -f admin-role.yaml

Récupérer le token de connexion

Pour vous connecter au Dashboard, en plus d'avoir le pod et un utilisateur, il vous faut le token qui va bien. Pour le récupérer :
dada@k8smaster:~$ kubectl -n kube-system describe secret $(kubectl -n kube-system get secret | grep admin-user | awk '{print $1}')
Name:         admin-user-token-b8qmq
Namespace:    kube-system
Labels:       <none>
Annotations:  kubernetes.io/service-account.name: admin-user
              kubernetes.io/service-account.uid: a8a600b1-e010-11e8-96ec-0800273c4560

Type:  kubernetes.io/service-account-token

Data
====
ca.crt:     1025 bytes
namespace:  11 bytes
token:      eyJhbGciOiJSUzI1NiIsImtpZCI6IiJ9.eyJpc3MiOiJrdWJl.........
J'ai tronqué l'affichage du token. Il est d'une longueur dingue. Copiez-le dans un coin maintenant que vous l'avez.

Accéder au Dashboard

Le Dashboard n'est par défaut pas accessible en dehors du cluster. On peut cependant tricher en passant par un proxy et un tunnel SSH.

Le proxy

Ouvrez un nouveau terminal branché sur votre master et tapez la commande suivante :
dada@k8smaster:~$ kubectl proxy
Starting to serve on 127.0.0.1:8001

Le tunnel SSH

Depuis votre PC hôte, lancez le tunnel :
dada@dada-laptop:~$ ssh -L 8001:127.0.0.1:8001 dada@IP_DU_MASTER

Affichez le fameux tant attendu

Si tout s'est bien passé jusqu'ici, vous deviez pouvoir accéder au Dashboard via cette url :


Et voir ceci : 


Vous voici avec une belle interface pour admirer le comportement de votre cluster k8s. Foncez cliquer absolument partout et chercher le pourquoi du comment de telles options à tel endroit !

La suite ?

Démarrer notre cluster kubernetes

Rédigé par dada / 01 novembre 2018 / 4 commentaires



Vous ne comprenez pas d'où vient ce billet ? Retrouvez sa première partie !

Configurez le master

Le master, c'est la machine qui va gérer le cluster. Pour ce tutoriel, nous n'allons utiliser qu'un seul master. Pas la peine de s'ennuyer à aller plus loin pour le moment. Sachez tout de même que c'est une mauvaise pratique : s'il se casse la figure, vous êtes dans la mouise.

Initialisation

Pour initialiser le master (k8smaster), pour faire comprendre à la VM que c'est elle la cheffe, tapez la commande suivante :
kubeadm init --pod-network-cidr=10.244.0.0/16
Elle va initialiser le cluster et lui assigner une plage d'IP privée.

Si vous avez bien suivi la première partie de ce tuto, vous devriez voir afficher les choses (tronquées) suivantes :
root@k8smaster:/home/dada# kubeadm init --pod-network-cidr=10.244.0.0/16
[init] using Kubernetes version: v1.12.2
[preflight] running pre-flight checks
[preflight/images] Pulling images required for setting up a Kubernetes cluster
[preflight/images] This might take a minute or two, depending on the speed of your internet connection
[preflight/images] You can also perform this action in beforehand using 'kubeadm config images pull'
[..]
[addons] Applied essential addon: CoreDNS
[addons] Applied essential addon: kube-proxy

Your Kubernetes master has initialized successfully!
Le message affirmant que le master est bien initialisé parle de lui-même : on est bon ! Ou presque. Il faut faire ce que la suite du message vous demande.

Configurez l'utilisateur qui aura le droit de jouer avec k8s

Notez que jongler entre k8s et docker peut-être épuisant : certaines commandes se jouent en root et d'autres en simple utilisateur. Pensez à changer d'utilisateur si rien ne se passe ou si le terminal vous insulte.

On enchaîne donc avec :
To start using your cluster, you need to run the following as a regular user:

  mkdir -p $HOME/.kube
  sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
  sudo chown $(id -u):$(id -g) $HOME/.kube/config

Je vous laisse placer le fichier de configuration du cluster dans la home de votre utilisateur classique.

Configurer le réseau du cluster

La suite du message d'initialisation :
You should now deploy a pod network to the cluster.
Run "kubectl apply -f [podnetwork].yaml" with one of the options listed at:
  https://kubernetes.io/docs/concepts/cluster-administration/addons/
k8s se sert d'un pod pour gérer son réseau. Il en existe plusieurs et celui que j'ai réussi à faire marcher du premier coup s'appelle Flannel.

Pour l'installer :
dada@k8smaster:~$ kubectl apply -f https://github.com/coreos/flannel/raw/master/Documentation/kube-flannel.yml
Et le retour qui confirme que tout va bien :
clusterrole.rbac.authorization.k8s.io/flannel created
clusterrolebinding.rbac.authorization.k8s.io/flannel created
serviceaccount/flannel created
configmap/kube-flannel-cfg created
daemonset.extensions/kube-flannel-ds-amd64 created
daemonset.extensions/kube-flannel-ds-arm64 created
daemonset.extensions/kube-flannel-ds-arm created
daemonset.extensions/kube-flannel-ds-ppc64le created
daemonset.extensions/kube-flannel-ds-s390x created
Il est temps de vous montrer une première commande k8s que vous allez passer votre vie à utiliser :
kubectl get pods --all-namespaces -o wide
Elle vous afficher le namespace, le nom, la quantité, le statut, l'âge, le node hôte, etc, des pods de votre cluster. Exemple :
dada@k8smaster:~$ kubectl get pods --all-namespaces -o wide
NAMESPACE     NAME                                READY   STATUS    RESTARTS   AGE   IP             NODE        NOMINATED NODE
kube-system   coredns-576cbf47c7-84x8w            1/1     Running   0          11m   10.244.0.8     k8smaster   <none>
kube-system   coredns-576cbf47c7-v88p4            1/1     Running   0          11m   10.244.0.9     k8smaster   <none>
kube-system   etcd-k8smaster                      1/1     Running   0          79s   192.168.0.19   k8smaster   <none>
kube-system   kube-apiserver-k8smaster            1/1     Running   0          79s   192.168.0.19   k8smaster   <none>
kube-system   kube-controller-manager-k8smaster   1/1     Running   0          79s   192.168.0.19   k8smaster   <none>
kube-system   kube-flannel-ds-amd64-vzrx8         1/1     Running   0          90s   192.168.0.19   k8smaster   <none>
kube-system   kube-proxy-nn7p2                    1/1     Running   0          11m   192.168.0.19   k8smaster   <none>
kube-system   kube-scheduler-k8smaster            1/1     Running   0          78s   192.168.0.19   k8smaster   <none>
Comme seul le master est actif, vous ne voyez pour le moment que les pods system (les trucs de base) de votre cluster sur le node master. Normal.

Ajouter un node dans le cluster

Votre cluster n'a qu'un master. Chiant. Est-on certain de n'avoir qu'un seul node dans ce cluster ?
dada@k8smaster:~$ kubectl get nodes
NAME        STATUS   ROLES    AGE   VERSION
k8smaster   Ready    master   23m   v1.12.2
Oui, la commande get nodes le confirme. Ajoutons un peu d'action dans tout ça en lisant la fin du message d'initialisation :
You can now join any number of machines by running the following on each node
as root:

  kubeadm join 192.168.0.19:6443 --token wdjnql.rm60fa90l0o9qv49 --discovery-token-ca-cert-hash sha256:ede807fb6f732c00acb8d40a891c436aedd3ed88f915135df252c033d55b2e10
Note : ne perdez pas la dernière ligne ! Il faudra reset votre cluster et ainsi tout perdre si vous ne la sauvegardez pas !

Allez lancer une autre VM, disons le k8snode1, et exécutez la commande de join. Si tout va bien, vous devriez avoir le message suivant :
root@k8snode1:/home/dada#   kubeadm join 192.168.0.19:6443 --token wdjnql.rm60fa90l0o9qv49 --discovery-token-ca-cert-hash sha256:ede807fb6f732c00acb8d40a891c436aedd3ed88f915135df252c033d55b2e10
[preflight] running pre-flight checks
[discovery] Trying to connect to API Server "192.168.0.19:6443"
[discovery] Created cluster-info discovery client, requesting info from "https://192.168.0.19:6443"
[discovery] Requesting info from "https://192.168.0.19:6443" again to validate TLS against the pinned public key
[discovery] Cluster info signature and contents are valid and TLS certificate validates against pinned roots, will use API Server "192.168.0.19:6443"
[discovery] Successfully established connection with API Server "192.168.0.19:6443"
[kubelet] Downloading configuration for the kubelet from the "kubelet-config-1.12" ConfigMap in the kube-system namespace
[kubelet] Writing kubelet configuration to file "/var/lib/kubelet/config.yaml"
[kubelet] Writing kubelet environment file with flags to file "/var/lib/kubelet/kubeadm-flags.env"
[preflight] Activating the kubelet service
[tlsbootstrap] Waiting for the kubelet to perform the TLS Bootstrap...
[patchnode] Uploading the CRI Socket information "/var/run/dockershim.sock" to the Node API object "k8snode1" as an annotation

This node has joined the cluster:
* Certificate signing request was sent to apiserver and a response was received.
* The Kubelet was informed of the new secure connection details.

Run 'kubectl get nodes' on the master to see this node join the cluster.
Retournez taper la commande get nodes sur le master :
dada@k8smaster:~$ kubectl get nodes
NAME        STATUS   ROLES    AGE     VERSION
k8smaster   Ready    master   26m     v1.12.2
k8snode1    Ready    <none>   3m20s   v1.12.2
Vous êtes deux !

Amusons-nous à voir ce qu'il vient de se passer au niveau des pods :
dada@k8smaster:~$ kubectl get pods --all-namespaces -o wide
NAMESPACE     NAME                                READY   STATUS    RESTARTS   AGE     IP             NODE        NOMINATED NODE
kube-system   coredns-576cbf47c7-84x8w            1/1     Running   0          29m     10.244.0.8     k8smaster   <none>
kube-system   coredns-576cbf47c7-v88p4            1/1     Running   0          29m     10.244.0.9     k8smaster   <none>
kube-system   etcd-k8smaster                      1/1     Running   0          19m     192.168.0.19   k8smaster   <none>
kube-system   kube-apiserver-k8smaster            1/1     Running   0          19m     192.168.0.19   k8smaster   <none>
kube-system   kube-controller-manager-k8smaster   1/1     Running   0          19m     192.168.0.19   k8smaster   <none>
kube-system   kube-flannel-ds-amd64-6qm8n         1/1     Running   0          6m57s   192.168.0.30   k8snode1    <none>
kube-system   kube-flannel-ds-amd64-vzrx8         1/1     Running   0          19m     192.168.0.19   k8smaster   <none>
kube-system   kube-proxy-nn7p2                    1/1     Running   0          29m     192.168.0.19   k8smaster   <none>
kube-system   kube-proxy-phfww                    1/1     Running   0          6m57s   192.168.0.30   k8snode1    <none>
kube-system   kube-scheduler-k8smaster            1/1     Running   0          19m     192.168.0.19   k8smaster   <none>
Des pods se sont installés sur le k8snode1 ! Vous n'êtes plus seul avec votre master. Vous avez un copain !

Motivé ? Vous pouvez ajouter le node k8snode2 précédemment préparé dans le cluster, histoire de ne pas l'avoir fait chauffer pour rien. Si vous avez bien réussi votre coup, get nodes devrait vous répondre ceci :
dada@k8smaster:~$ kubectl get nodes
NAME        STATUS     ROLES    AGE   VERSION
k8smaster   Ready      master   41m   v1.12.2
k8snode1    Ready      <none>   18m   v1.12.2
k8snode2    Ready   <none>   6s    v1.12.

Bien joué !

Ça ne marche pas comme prévu ?

Très rapide abécédaire des commandes que vous pouvez utiliser si ça coince :

- kubeadm reset -f : elle supprime toute la configuration du cluster du node sur laquelle elle est exécutée. Ça permet de repartir de zéro.

- kubectl delete node <nomdunode> : supprime le node passé en paramètre du cluster, en gardant sa configuration.

La suite ?

Affichez le dashboard de k8s, parce que de la couleur et une interface, c'est mieux.

Préparer Virtualbox pour Kubernetes

Rédigé par dada / 01 novembre 2018 / 2 commentaires

J'ai un peu l'impression d'arriver après la bataille, mais soit. Mieux vaut tard que jamais, comme disent les gens. Je me lance dans une série de billets autour de Kubernetes, l'orchestrateur qui fait parler de lui depuis bien longtemps.
Pour mettre les mains dedans, j'ai choisi de m'amuser avec Virtualbox. Je sais qu'il existe d'autres outils et que certains préféreront se servir de service cloud pour leurs pérégrinations. Perso, j'ai pas spécialement envie d'alourdir ma facture chez Hetzner, même s'ils le méritent. Et Virtualbox marche très bien.

Équipement de départ

  • Debian Testing sur mon ThinkPad x280
  • Virtualbox 5.2.20
  • Debian 9 pour les nodes
  • Docker CE 17.03.3
  • Une Freebox Révolution
Vocabulaire : un node, c'est une VM sur laquelle vous allez faire tourner des pods. Les pods sont des conteneurs Docker, qui tournent donc sur des nodes. Ok ?

Préparer Virtualbox

La première VM

Je vous laisse installer une première machine sous Debian 9. Sans fioritures. Une Debian stable avec SSH fait parfaitement l'affaire.
Au niveau des spécifications techniques, pas la peine d'aller trop loin : 1 core / 2GB de ram et 8 Go d'espace disque suffiront.

Configurer son réseau

Votre machine sous Virtualbox va avoir besoin de 2 choses :
- Un accès internet
- Une IP permettant d'être accessible en SSH par la machine hôte et par les autres nodes.

Un accès internet

Simple, la première carte réseau mise en place par VB est configurée en NAT. Vous n'aviez rien à faire.

Une IP SSH/Nodes

Le DHCP de la Freebox fourni des IP en 192.168.0.XX. Pour choper une de ces IP, il faut aller dans la configuration réseau de la VM et ajouter une deuxième carte réseau :


Il faut la configurer en accès par pont et lui passer en paramètre le nom du réseau de votre PC. Pour moi, c'est celui de la carte Wifi wlp59s0. Si vous avez une carte Ethernet, vous devriez pouvoir choisir eth0.

Installer les bases pour Kubernetes

Ici, on va installer une version de k8s non configurée. C'est important de l'installer nue puisque cette VM servira de base aux autres.

Installer Docker

# apt-get install -y apt-transport-https ca-certificates curl gnupg2 software-properties-common
# curl -fsSL https://download.docker.com/linux/$(. /etc/os-release; echo "$ID")/gpg | apt-key add -
# add-apt-repository "deb https://download.docker.com/linux/debian stretch stable"
# apt-get update
# apt-get install -y docker-ce

Activez docker au démarrage :

systemctl enable docker
Configurez docker pour qu'il ne s'amuse qu'avec Systemd en créant le fichier /etc/docker/daemon.json :
root@k8snode1:/home/dada# cat /etc/docker/daemon.json
{
    "exec-opts": ["native.cgroupdriver=systemd"]
}

Et enfin, désactivez le swap avec la commande :

swapoff -a

Et commentez la ligne du fstab réactivant ce truc à chaque reboot :

# swap was on /dev/sda5 during installation
#UUID=5d159270-eaee-41ed-864c-711f242e044d none            swap    sw              0       0

Installer Kubernetes

# curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add -
# add-apt-repository "deb http://apt.kubernetes.io/ kubernetes-xenial main"
# apt-get update
# apt-get install -y kubelet kubeadm kubectl

Préparer le cluster

Kubernetes, c'est un cluster. Pour fonctionner correctement et pour vraiment s'amuser, il nous faut :
  • Un master
  • Deux nodes ou plus

Les nodes

Les nodes vont être créés à partir de la première machine de ce tuto. Pour les ajouter à Virtualbox, je vais vous demander de la cloner 2 fois. Virtualbox fait ça très bien : clique droit / cloner. Allez-y, c'est tout simple. Réaliser l'opération 2 fois.

Voici ce que vous devriez avoir maintenant :


Bon, les miennes sont "en fonction" puisqu'elles tournent à l'heure où je rédige ce billet, mais les vôtres devraient être arrêtées.

Connectez-vous en SSH aux machines

Au démarrage, votre machine n'aura peut-être pas activée son réseau. Du moins, par forcément. Si la commande ip a vous retourne quelque chose comme ça :
3: enp0s9: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
    link/ether 08:00:27:e4:f7:f0 brd ff:ff:ff:ff:ff:ff
C'est que l'interface n'est pas activée. Pour l'activer :
dhclient enp0s9
Et vous devriez avoir ça maintenant :
3: enp0s9: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 08:00:27:e4:f7:f0 brd ff:ff:ff:ff:ff:ff
    inet 192.168.0.31/24 brd 192.168.0.255 scope global enp0s9
       valid_lft forever preferred_lft forever
    inet6 fe80::a00:27ff:fee4:f7f0/64 scope link
       valid_lft forever preferred_lft forever
Remarquez la présence de la tant désirée IP : 192.168.0.31. Vous pouvez maintenant vous connecter à la machine avec un bon vieux :
ssh votreuser@192.168.0.31

Configurer les nodes

Rappel : étant des clones de la première machine virtuelle créée, ces nouvelles VM ont déjà docker et k8s d'installé.

Le hostname

Allez éditer le fichier /etc/hostname pour nommer vos machines. Exemple : k8snode1 et k8snode2. Vous allez éviter des warnings et des prises de tête en faisant ça.
dada@k8snode1:~$ cat /etc/hostname
k8snode1

Le hosts

Idem pour le fichier /etc/hosts : allez y ajouter, au bout de la ligne 127.0.0.1, le hostname de la machine.
dada@k8snode1:~$ cat /etc/hosts
127.0.0.1    localhost k8snode1
127.0.1.1    debian

# The following lines are desirable for IPv6 capable hosts
::1     localhost ip6-localhost ip6-loopback
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters

Le master

Pour le master, nous allons prendre la toute première machine que vous avez laissé nue. Si vous avez bien suivi et que je suis compréhensible : le node1 est le premier clone, le node2 est le second. Nous n'avons normalement pas encore touché à la machine d'origine. C'est ce que vous allez faire maintenant.

Configurez le hosts et le hostname de la même façon que pour les nodes, en prenant bien le temps de l'appeler k8smaster. Histoire de le différencier.

Tester tout ça

Maintenant que nous avons mis en place les machines, il va falloir vérifier qu'elles se comportent bien avant d'y lancer k8s.
  • Validez que vous pouvez bien vous connecter en SSH
  • Remplacez les IP qui traînent dans les exemples par les vôtres !
  • Pinguez les machines entre elles pour être bien certain d'éviter d'insulter k8s alors que le réseau est foireux
  • Rebootez les machines au moins une fois histoire de valider le réseau, le swap, le démarrage de docker et de kubernetes
Et c'est à partir de là qu'on va commencer à jouer !

La suite ?