ubuntu@prepakube-1:~$ ./rke up
INFO[0000] Running RKE version: v1.0.0
INFO[0000] Initiating Kubernetes cluster
INFO[0000] [dialer] Setup tunnel for host [192.168.76.124]
INFO[0000] [dialer] Setup tunnel for host [192.168.76.125]
INFO[0000] [dialer] Setup tunnel for host [192.168.76.120]
WARN[0000] Failed to set up SSH tunneling for host [192.168.76.124]: Can't retrieve Docker Info: error during connect: Get http://%2Fvar%2Frun%2Fdocker.sock/v1.24/info: Unable to access node with address [192.168.76.124:22] using SSH. Please check if you are able to SSH to the node using the specified SSH Private Key and if you have configured the correct SSH username. Error: ssh: handshake failed: ssh: unable to authenticate, attempted methods [none publickey], no supported methods remain
WARN[0000] Removing host [192.168.76.124] from node lists
WARN[0000] [state] can't fetch legacy cluster state from Kubernetes: Cluster must have at least one etcd plane host: failed to connect to the following etcd host(s) [192.168.76.124]
INFO[0000] [certificates] Generating CA kubernetes certificates
INFO[0000] [certificates] Generating Kubernetes API server aggregation layer requestheader client CA certificates
INFO[0000] [certificates] Generating Kubernetes API server certificates
INFO[0001] [certificates] Generating Service account token key
INFO[0001] [certificates] Generating Kube Controller certificates
INFO[0001] [certificates] Generating Kube Scheduler certificates
INFO[0001] [certificates] Generating Kube Proxy certificates
INFO[0001] [certificates] Generating Node certificate
INFO[0001] [certificates] Generating admin certificates and kubeconfig
INFO[0001] [certificates] Generating Kubernetes API server proxy client certificates
INFO[0002] Successfully Deployed state file at [./cluster.rkestate]
INFO[0002] Building Kubernetes cluster
INFO[0002] [dialer] Setup tunnel for host [192.168.76.125]
INFO[0002] [dialer] Setup tunnel for host [192.168.76.120]
FATA[0002] Cluster must have at least one etcd plane host: please specify one or more etcd in cluster config
Pour comprendre l'erreur, il faut lire un peu plus haut dans les logs :
WARN[0000] Failed to set up SSH tunneling for host [192.168.76.124]: Can't retrieve Docker Info: error during connect: Get http://%2Fvar%2Frun%2Fdocker.sock/v1.24/info: Unable to access node with address [192.168.76.124:22] using SSH. Please check if you are able to SSH to the node using the specified SSH Private Key and if you have configured the correct SSH username. Error: ssh: handshake failed: ssh: unable to authenticate, attempted methods [none publickey], no supported methods remain
WARN[0000] Removing host [192.168.76.124] from node lists
''rke'' n'a pas été capable de se connecter à l'une des machine, elle a donc été supprimée. Mais il se trouve que c'est la seule dont le rôle est ''controle pane'', le cluster ne peut donc pas être mis en place.
ubuntu@prepakube-1:~$ ./rke up
INFO[0000] Running RKE version: v1.0.0
INFO[0000] Initiating Kubernetes cluster
FATA[0000] Failed to validate cluster: Cluster can't have duplicate node: 192.168.76.124
Dans le fichier ''cluster.yml'', il y a plusieurs fois la même IP pour deux hosts différents. Corrigez cela.
=== Problème avec le proxy ===
ubuntu@prepakube-1:~$ ./rke up
INFO[0000] Running RKE version: v1.0.0
INFO[0000] Initiating Kubernetes cluster
INFO[0000] [certificates] Generating Kubernetes API server certificates
INFO[0000] [certificates] Generating admin certificates and kubeconfig
INFO[0000] [certificates] Generating kube-etcd-192-168-76-124 certificate and key
...
INFO[0126] [controlplane] Successfully started Controller Plane..
INFO[0126] Using proxy environment variable HTTP_PROXY with value [http://proxy.univ-lyon1.fr:3128]
INFO[0126] Using proxy environment variable HTTPS_PROXY with value [http://proxy.univ-lyon1.fr:3128]
INFO[0126] Using proxy environment variable NO_PROXY with value [univ-lyon1.fr,127.0.0.1,localhost]
INFO[0126] [authz] Creating rke-job-deployer ServiceAccount
FATA[0152] Failed to apply the ServiceAccount needed for job execution: Post https://192.168.76.124:6443/apis/rbac.authorization.k8s.io/v1/clusterrolebindings?timeout=30s: Forbidden
ubuntu@prepakube-1:~$
Les machines étant configurées pour utiliser le proxy de l'université afin d'aller sur internet et comme rke utilise des requêtes HTTP, il est possible que la configuration du proxy empêche l'une des machines du cluster d'en contacter une autre. En effet, la requête passe par le proxy qui refuse ce type de connexion. Vous devez donc vérifier votre configuration des VMs. Cela peut aussi venir du fait que vous n'ayez pas modifié les variables d'environnement. Par exemple si vous n'avez pas pensé à vous déconnecter puis vous reconnecter à la machine (Les variables sont chargées à la connexion).
===== Installation de kubectl=====
* Installez le package ''kubectl'' comme indiqué {{https://kubernetes.io/docs/tasks/tools/install-kubectl/#install-kubectl|ici}}.
* Installer aussi les complétions kubectl pour votre SHELL (bash, zsh...)
La génération du cluster à créé un fichier de description ''kube_config_cluster.yml''. C'est un fichier qui permet à ''kubectl'' de contacter le cluster. Vous pouvez soit copier ce fichier sous le nom ''~/.kube/config'' soit ajouter ''%%--kubeconfig nomdufichier%%'' à chaque commande. Il est aussi possible de spécifier le chemin du fichier avec ''export KUBECONFIG=/chemin/vers/mon/fichier/kube_config_cluster.yml''.
Pour vérifier la configuration, vous pouvez lister les nœuds du cluster avec la commande ''kubectl get nodes'' qui doit afficher 3 noeuds.
kubectl get nodes
NAME STATUS ROLES AGE VERSION
master Ready controlplane,etcd 3m57s v1.17.14
worker-1 Ready worker 3m50s v1.17.14
worker-2 Ready worker 3m49s v1.17.14
===== Un premier pod =====
L'unité de base du cluster est un //pod//. C'est un ensemble de 1 ou plusieurs conteneurs, en général un seul. Les conteneurs d'un même pod sont forcement instanciés sur le même nœud et se retrouverons dans les mêmes espace de nom, c'est à dire par exemple qu'ils pourront se contacter directement via l'adresse ''localhost''.
Vous pouvez tester le cluster avec un premier pod (l'exemple est pris {{http://www.projectatomic.io/docs/gettingstarted/|ici}}).
Les objets kubernetes peuvent être crées par des commandes ''kubectl'', mais le plus simple est de créer des fichiers ''yml'' et de les //appliquer// via la commande ''kubectl apply -f nomfichier.yml''
Créez tout d'abord un fichier de description test_www.yml :
apiVersion: v1
kind: Pod
metadata:
name: www
spec:
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
hostPort: 8080
Et utilisez les commandes pour creer le pod:
# pour créer le pod
kubectl apply -f test_www.yml
# ou
kubectl create -f test_www.yml
# pour voir les pods existants
kubectl get pods
# pour voir les détails d'un pod
kubectl describe pod
# pour voir les logs d'un pods
kubectl logs
# pour exécuter une commande dans le pod
kubectl exec -it
# pour supprimer un pod
kubectl delete pods
* Sur quel noeud a été instancié le pod ?
* Avec votre navigateur testez la réponse de nginx sur le port ''8080'' du noeud qui instancie le pod
* Vérifiez dans les logs que c'est bien ce dernier qui est contacté
* Testez la réponse à partir du port ''8080'' d'un autre noeud. Cela fonctionne-t-il ? Est-ce différent de ce qui se passe avec //swarm// ?
* Allez sur le noeud qui instancie le pod, retrouver le docker crée et supprimez le. Est-il automatiquement recréé ? Est-ce différent de ce qui se passe avec //swarm// ?
* Lisez l'aide de la commande ''kubectl scale'' (avec l'option ''%%--help%%''). Pouvez-vous augmenter le nombre de pods qui fournisse le service ? Est-ce différent de ce qui se passe avec //swarm// ?
* Supprimez le pod
===== Un premier contrôleur =====
Normalement vous ne passez jamais directement par une création de //pods// mais on charge un contrôleur de le faire. Ce dernier va par exemple s'occuper de créer des répliquas, de maintenir l'existence du nombre demandé de répliquas fonctionnels ... Nous ne verrons ici que la ressource //deployment// qui est le moyen plus direct de créer des pods et de les modifier.
Une documentation plus complète des [[https://kubernetes.io/docs/concepts/workloads/controllers/deployment/|déploiements est ici]]
Créer un fichier ''busy.yml'' contenant ceci :
apiVersion: apps/v1
kind: Deployment
metadata:
name: dep-busy
labels:
app: dep-busybox
tp: kubernetes
spec:
replicas: 2
selector:
matchLabels:
app: busybox
tp: kubernetes
template:
metadata:
labels:
app: busybox
tp: kubernetes
spec:
containers:
- name: busy
image: busybox
command: ['sh', '-c', 'echo Hello Kubernetes! && sleep 3600']
Le type d'objet est ''Deployment'', Le ''label'' servira à faire des requêtes pour retrouver l'objet. Les spécifications contiennent :
- le nombre de répliquas demandés;
- le ''matchLabel'' c'est à dire le moyen pour le contrôleur de retrouver les //pods// créés.
- le //template// des //pods// à créer.
La partie //template// prend donc les options que peuvent prendre les spécifications de //pods//. Ici : le pods crée contiendra un conteneur de nom ''busy'' et se base sur l'image docker ''busybox''. Il est important que les labels des //pods// (champs de ''spec.template.metadata.labels'') contiennent les champs recherchés par le contrôleur (''spec.selector.matchLabels'').
* Créez votre déploiement grâce à ''kubectl apply ...''.
* Vérifiez les créations du //deployment// et du //replicaset// (objet effectivement chargé de la réplication) des //pods// grâce à ''kubectl get ...''.
* Regardez les logs de vos //pods// (''kubectl logs NOMDUPOD'')
//Busybox// est une image avec des commandes simples qui vont permettre de faire des tests.
* Grâce à ''kubectl describe pod NOMDUPOD'' retrouver sur quel nœud est implémenté l'un des //pods// créés, et son adresse IP.
* Grâce à ''kubectl exec -it NOMDUPOD -- sh'' ouvrez un shell dans le //pod//, essayer de pinger l'autre pod.
===== Configuration des conteneurs =====
=== Variables d'environnement ===
Comme avec docker, beaucoup de configurations utilisent des variables d'environnements qui peuvent être positionnées dans le fichier de description.[[https://kubernetes.io/docs/tasks/inject-data-application/define-environment-variable-container/|Voir ici la méthode]] pour ajouter des variables aux //pods//.
je suis le serveur php
Un bon moyen pour cela est d'exécuter un conteneurs d'initialisation dont la commande est :
["sh", "-c", "echo 'je suis le serveur php
\n' > /var/www/html/index.php"]
Pour créer la connexion, nous allons utiliser un nouvel objet de kubernetes, le //service//. [[https://kubernetes.io/fr/docs/concepts/services-networking/service/|La documentation est ici]].
Dans l'exemple suivant :
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
selector:
app: MyApp
ports:
- protocol: TCP
port: 80
targetPort: 9376
Le service dont le nom est ''my-service'' transfert le nom ''my-service:80'' vers le port ''9376'' de tous les //pods// dont les labels contiendrons ''{app: MyApp}''.
* Créez un service de nom ''serv-php'' qui transférera le port 80 vers le port 80 des //pods// php créés précédemment.
* Testez le bon fonctionnement du service en exécutant une requête http depuis le pod ''busybox''
$ kubectl exec -it NOMDUPOD -- sh
/ # wget http://serv-php/ -O -
Connecting to serv-php (10.43.79.61:80)
writing to stdout
je suis le serveur php
Array
(
[HTTP_HOST] => serv-php
[HTTP_USER_AGENT] => Wget
[HTTP_CONNECTION] => close
[PATH] => /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
[SERVER_SIGNATURE] => Apache/2.4.38 (Debian) Server at serv-php Port 80
[SERVER_SOFTWARE] => Apache/2.4.38 (Debian)
[SERVER_NAME] => serv-php
[SERVER_ADDR] => 10.42.1.33
[SERVER_PORT] => 80
[REMOTE_ADDR] => 10.42.2.17
[DOCUMENT_ROOT] => /var/www/html
[REQUEST_SCHEME] => http
[CONTEXT_PREFIX] =>
[CONTEXT_DOCUMENT_ROOT] => /var/www/html
[SERVER_ADMIN] => webmaster@localhost
[SCRIPT_FILENAME] => /var/www/html/index.php
[REMOTE_PORT] => 48724
[GATEWAY_INTERFACE] => CGI/1.1
[SERVER_PROTOCOL] => HTTP/1.1
[REQUEST_METHOD] => GET
[QUERY_STRING] =>
[REQUEST_URI] => /
[SCRIPT_NAME] => /index.php
[PHP_SELF] => /index.php
[REQUEST_TIME_FLOAT] => 1578645615.917
[REQUEST_TIME] => 1578645615
[argv] => Array
(
)
[argc] => 0
)
- 100% |************************************************************************************************************************| 1067 0:00:00 ETA
written to stdout
===== Rendre accessible les services depuis l'extérieur =====
Jusqu'à présent, les accès se font via les Pods dans le cluster. Pour finir il faut être capable d'ouvrir le service sur l'extérieur. Pour cela, il faut mettre en place un //Ingress//, [[https://kubernetes.io/fr/docs/concepts/services-networking/ingress/|La documentation est ici]].
Un peu comme les services ''nginx'' que vous avez déjà utilisé, l'ingress va recevoir les requêtes de l'extérieur et les redispatcher sur les services internes en fonction de ce qui est demandé. Pour cela, il se base sur le nom //DNS// utilisé pour accéder au service et sur le contenu des requêtes HTTP.
Vous pouvez créer une ressource ingress en vous basant sur cette exemple de la documentation :
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: simple-fanout-example
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
rules:
- host: foo.bar.com
http:
paths:
- path: /foo
backend:
serviceName: service1
servicePort: 4200
- path: /bar
backend:
serviceName: service2
servicePort: 8080
Ici,
* les requêtes ''http://foo.bar.com/foo'' seront dispatchées sur ''service1:4200''
* les requêtes ''http://foo.bar.com/bar'' seront dispatchées sur ''service2.8080''
Pour mettre en place cela, il faut que vous ajoutiez un nom DNS à votre cluster. Pour cela, la plateforme openstack est maintenant munie du service ''Designate'' qui vous permet de gérer un nom valable sur le réseau de l'université.
* Dans la plateforme openstack, dans l'onglet ''compute'' ouvrez le menu ''DNS'' puis ''Zones'' cliquez sur ''cc.os.univ-lyon1.fr'' et ''create reccord set'' ce qui vous permet d'ajouter un champs ''A'' c'est à dire une correspondance entre un nom DNS et une ou plusieurs adresse IP.
* Pour le nom ''VOTRENOM.cc.os.univ-lyon1.fr'' ajouter les 2 adresses IP de vos //worker//
* Bien vérifier que votre enregistrement est avec le statut **Active**. Faites attention la fonction **refresh** de votre navigateur ne va pas fonctionner avec le module angular de Designate (il faut donc passer par un autre menu puis revenir dans la zone DNS )
* Depuis la réseau de l'université vous pouvez essayer de faire un ''ping'' en utilisant le nom DNS
Le service ''designate'' est nouveau et pas très bien rodé. Si vous ne parvenez pas à créer le nom, abandonnez et utiliser le nom dns qui a été automatiquement créé pour vos machine: ''NOMDELAMACHINE.cc.os.univ-lyon1.fr''
Il faut maintenant faire la correspondance entre ce nom et l'accès au service php
* Créez une ressource //ingress// qui envoie les requêtes [[http://VOTRENOM.cc.os.univ-lyon1.fr/]] sur le service php que vous avez crée.
* Vérifiez que cela fonctionne avec votre navigateur.