Ceci est une ancienne révision du document !
Table des matières
Dernière mise-à-jour : 2020/01/30 03:44
DVOPF2 - Orchestration de Conteneurs avec Docker Swarm et Kubernetes
L'Orchestration de Conteneurs
Les principales solutions de containerization sont :
- Container Linux qui utilise rkt (anciennement Rocket),
Les principales solutions d'orchestration de conteneurs sont :
L'orchestration de conteneurs apporte :
- La haute disponibilité,
- L'équilibrage de charge,
- L'augmentation et la réduction du Services (Scale up / scale down) automatiques et transparentes.
Présentation de Kubernetes (k8s)
Master
- Contrôleur du cluster,
- Responsable de l'orchestration.
Le Master contient :
- Serveur API,
- Front end,
- Service etcd,
- Key-value store qui stocke toutes les données utilisées pour gérer le cluster et gére les vérrous,
- Controlleur,
- Surveille l'état des conteneurs, neouds et end-points. Responsable de la mise en place de nouveaux conteneurs en cas de défaillances.
- Ordonnonceur,
- Distribue les conteneurs existants aux noeuds et cherche des nouveaux conteneurs et les attribue aux noeuds,
Noeuds (Minion)
- Machine physique ou virtuelle sur laquelle est installé Kubernetes,
- Un travailleur sur lequels Kubernetes lance des conteneurs,
Le Noeud contient :
- Service kubelet,
- Agent qui s'exécute sur chaque noeud. Responsable de la surveillance des conteneurs.
- Container runtime,
- Docker,
- rkt (rocket),
- CRI-O (crio).
Que Contient ce Cours ?
Vous allez apprendre l'orchestration de conteneurs grâce à des LABS :
- LAB #1 - Installation de Kubernetes avec Minikube,
- LAB #2 - Importation de la Machine Virtuelle Kubemaster,
- LAB #3 - Installation de Docker, kubeadm, kubelet et kubectl,
- LAB #4 - Création et Configuration des Noeuds,
- LAB #5 - Création du Réseau pour Kubernetes,
- LAB #6 - Connexion à vos Machines Virtuelles avec SSH,
- LAB #7 - Création du Cluster Kubernetes,
- LAB #8 - Création d'un POD,
- LAB #9 - Utilisation de Contrôleurs de Réplication et ReplicaSets,
- LAB #10 - Gestion des Deployments,
- LAB #11 - Gestion du Réseau et des Services,
- LAB #12 - Gestion de l'Architecture des Microservices.
LAB #1 - Création de Machines Virtuelles Docker avec Docker Machine
Préparation
VirtualBox
Téléchargez la bonne version de VirtualBox 64 bits à partir du lien https://www.virtualbox.org/wiki/Downloads et installez-la.
Docker-CE
Installer Docker-CE sur votre machine hôte :
Mac
- Voir le lien https://docs.docker.com/docker-for-mac/install/.
Linux
- Ubuntu - voir le lien https://docs.docker.com/engine/installation/linux/docker-ce/ubuntu/,
- Debian - voir le lien https://docs.docker.com/engine/installation/linux/docker-ce/debian/,
- CentOS - voir le lien https://docs.docker.com/engine/installation/linux/docker-ce/centos/,
- Fedora - voir le lien https://docs.docker.com/engine/installation/linux/docker-ce/fedora/,
Windows 7, 8 et 10
- Téléchargez Docker Toolbox à partir de cette page https://docs.docker.com/toolbox/toolbox_install_windows/
- Fermez toutes les machines virtuelles ainsi que VirtualBox,
- Installez DockerToolBox.exe (décochez VirtualBox dans la liste de produits à installer),
- Exécutez Docker Toolbox et laissez l'application créer une machine virtuelle,
- Ouvrez VirtualBox. Vous verrez une machine virtuelle Default,
- Ouvrez cmd.
Installation de docker-machine
Pour installer docker-machine sur votre machine hôte, utilisez une des commandes suivantes :
Mac
curl -L https://github.com/docker/machine/releases/download/v0.12.2/docker-machine-`uname -s`-`uname -m` >/usr/local/bin/docker-machine && chmod +x /usr/local/bin/docker-machine
Linux
curl -L https://github.com/docker/machine/releases/download/v0.12.2/docker-machine-`uname -s`-`uname -m` >/tmp/docker-machine && chmod +x /tmp/docker-machine && cp /tmp/docker-machine /usr/local/bin/docker-machine
Windows
Si vous utilisez Git BASH :
if [[ ! -d "$HOME/bin" ]]; then mkdir -p "$HOME/bin"; fi && curl -L https://github.com/docker/machine/releases/download/v0.12.2/docker-machine-Windows-x86_64.exe > "$HOME/bin/docker-machine.exe" && chmod +x "$HOME/bin/docker-machine.exe"
Si vous n'utilisez PAS Git BASH :
Téléchargez la version adéquate pour l'architecture de votre machine à partir de l'adresse https://github.com/docker/machine/releases/.
Création du manager1
Créez la machine virtuelle manager1 :
hnorris-laptop ~ # docker-machine create --driver virtualbox manager1 Creating CA: /root/.docker/machine/certs/ca.pem Creating client certificate: /root/.docker/machine/certs/cert.pem Running pre-create checks... (manager1) Image cache directory does not exist, creating it at /root/.docker/machine/cache... (manager1) No default Boot2Docker ISO found locally, downloading the latest release... (manager1) Latest release for github.com/boot2docker/boot2docker is v17.06.2-ce (manager1) Downloading /root/.docker/machine/cache/boot2docker.iso from https://github.com/boot2docker/boot2docker/releases/download/v17.06.2-ce/boot2docker.iso... (manager1) 0%....10%....20%....30%....40%....50%....60%....70%....80%....90%....100% Creating machine... (manager1) Copying /root/.docker/machine/cache/boot2docker.iso to /root/.docker/machine/machines/manager1/boot2docker.iso... (manager1) Creating VirtualBox VM... (manager1) Creating SSH key... (manager1) Starting the VM... (manager1) Check network to re-create if needed... (manager1) Found a new host-only adapter: "vboxnet0" (manager1) Waiting for an IP... Waiting for machine to be running, this may take a few minutes... Detecting operating system of created instance... Waiting for SSH to be available... Detecting the provisioner... Provisioning with boot2docker... Copying certs to the local machine directory... Copying certs to the remote machine... Setting Docker configuration on the remote daemon... Checking connection to Docker... Docker is up and running! To see how to connect your Docker Client to the Docker Engine running on this virtual machine, run: docker-machine env manager1
Les options de la commande docker-machine sont :
hnorris-laptop ~ # docker-machine --help Usage: docker-machine [OPTIONS] COMMAND [arg...] Create and manage machines running Docker. Version: 0.12.2, build 9371605 Author: Docker Machine Contributors - <https://github.com/docker/machine> Options: --debug, -D Enable debug mode --storage-path, -s "/root/.docker/machine" Configures storage path [$MACHINE_STORAGE_PATH] --tls-ca-cert CA to verify remotes against [$MACHINE_TLS_CA_CERT] --tls-ca-key Private key to generate certificates [$MACHINE_TLS_CA_KEY] --tls-client-cert Client cert to use for TLS [$MACHINE_TLS_CLIENT_CERT] --tls-client-key Private key used in client TLS auth [$MACHINE_TLS_CLIENT_KEY] --github-api-token Token to use for requests to the Github API [$MACHINE_GITHUB_API_TOKEN] --native-ssh Use the native (Go-based) SSH implementation. [$MACHINE_NATIVE_SSH] --bugsnag-api-token BugSnag API token for crash reporting [$MACHINE_BUGSNAG_API_TOKEN] --help, -h show help --version, -v print the version Commands: active Print which machine is active config Print the connection config for machine create Create a machine env Display the commands to set up the environment for the Docker client inspect Inspect information about a machine ip Get the IP address of a machine kill Kill a machine ls List machines provision Re-provision existing machines regenerate-certs Regenerate TLS Certificates for a machine restart Restart a machine rm Remove a machine ssh Log into or run a command on a machine with SSH. scp Copy files between machines start Start a machine status Get the status of a machine stop Stop a machine upgrade Upgrade a machine to the latest version of Docker url Get the URL of a machine version Show the Docker Machine version or a machine docker version help Shows a list of commands or help for one command Run 'docker-machine COMMAND --help' for more information on a command.
Création des Travailleurs
Créez maintenant 5 travailleurs - worker1 jusqu'à worker5 :
hnorris-laptop ~ # docker-machine create --driver virtualbox worker1 Running pre-create checks... Creating machine... (worker1) Copying /root/.docker/machine/cache/boot2docker.iso to /root/.docker/machine/machines/worker1/boot2docker.iso... (worker1) Creating VirtualBox VM... (worker1) Creating SSH key... (worker1) Starting the VM... (worker1) Check network to re-create if needed... (worker1) Waiting for an IP... Waiting for machine to be running, this may take a few minutes... Detecting operating system of created instance... Waiting for SSH to be available... Detecting the provisioner... Provisioning with boot2docker... Copying certs to the local machine directory... Copying certs to the remote machine... Setting Docker configuration on the remote daemon... Checking connection to Docker... Docker is up and running! To see how to connect your Docker Client to the Docker Engine running on this virtual machine, run: docker-machine env worker1
hnorris-laptop ~ # docker-machine create --driver virtualbox worker2 ... hnorris-laptop ~ # docker-machine create --driver virtualbox worker3 ... hnorris-laptop ~ # docker-machine create --driver virtualbox worker4 ... hnorris-laptop ~ # docker-machine create --driver virtualbox worker5 ...
Les options de la sous-commande create de la commande docker-machine sont :
hnorris-laptop ~ # docker-machine create --help Usage: docker-machine create [OPTIONS] [arg...] Create a machine Description: Run 'docker-machine create --driver name' to include the create flags for that driver in the help text. Options: --driver, -d "virtualbox" Driver to create machine with. [$MACHINE_DRIVER] --engine-env [--engine-env option --engine-env option] Specify environment variables to set in the engine --engine-insecure-registry [--engine-insecure-registry option --engine-insecure-registry option] Specify insecure registries to allow with the created engine --engine-install-url "https://get.docker.com" Custom URL to use for engine installation [$MACHINE_DOCKER_INSTALL_URL] --engine-label [--engine-label option --engine-label option] Specify labels for the created engine --engine-opt [--engine-opt option --engine-opt option] Specify arbitrary flags to include with the created engine in the form flag=value --engine-registry-mirror [--engine-registry-mirror option --engine-registry-mirror option] Specify registry mirrors to use [$ENGINE_REGISTRY_MIRROR] --engine-storage-driver Specify a storage driver to use with the engine --swarm Configure Machine to join a Swarm cluster --swarm-addr addr to advertise for Swarm (default: detect and use the machine IP) --swarm-discovery Discovery service to use with Swarm --swarm-experimental Enable Swarm experimental features --swarm-host "tcp://0.0.0.0:3376" ip/socket to listen on for Swarm master --swarm-image "swarm:latest" Specify Docker image to use for Swarm [$MACHINE_SWARM_IMAGE] --swarm-join-opt [--swarm-join-opt option --swarm-join-opt option] Define arbitrary flags for Swarm join --swarm-master Configure Machine to be a Swarm master --swarm-opt [--swarm-opt option --swarm-opt option] Define arbitrary flags for Swarm master --swarm-strategy "spread" Define a default scheduling strategy for Swarm --tls-san [--tls-san option --tls-san option] Support extra SANs for TLS certs --virtualbox-boot2docker-url The URL of the boot2docker image. Defaults to the latest available version [$VIRTUALBOX_BOOT2DOCKER_URL] --virtualbox-cpu-count "1" number of CPUs for the machine (-1 to use the number of CPUs available) [$VIRTUALBOX_CPU_COUNT] --virtualbox-disk-size "20000" Size of disk for host in MB [$VIRTUALBOX_DISK_SIZE] --virtualbox-host-dns-resolver Use the host DNS resolver [$VIRTUALBOX_HOST_DNS_RESOLVER] --virtualbox-hostonly-cidr "192.168.99.1/24" Specify the Host Only CIDR [$VIRTUALBOX_HOSTONLY_CIDR] --virtualbox-hostonly-nicpromisc "deny" Specify the Host Only Network Adapter Promiscuous Mode [$VIRTUALBOX_HOSTONLY_NIC_PROMISC] --virtualbox-hostonly-nictype "82540EM" Specify the Host Only Network Adapter Type [$VIRTUALBOX_HOSTONLY_NIC_TYPE] --virtualbox-hostonly-no-dhcp Disable the Host Only DHCP Server [$VIRTUALBOX_HOSTONLY_NO_DHCP] --virtualbox-import-boot2docker-vm The name of a Boot2Docker VM to import [$VIRTUALBOX_BOOT2DOCKER_IMPORT_VM] --virtualbox-memory "1024" Size of memory for host in MB [$VIRTUALBOX_MEMORY_SIZE] --virtualbox-nat-nictype "82540EM" Specify the Network Adapter Type [$VIRTUALBOX_NAT_NICTYPE] --virtualbox-no-dns-proxy Disable proxying all DNS requests to the host [$VIRTUALBOX_NO_DNS_PROXY] --virtualbox-no-share Disable the mount of your home directory [$VIRTUALBOX_NO_SHARE] --virtualbox-no-vtx-check Disable checking for the availability of hardware virtualization before the vm is started [$VIRTUALBOX_NO_VTX_CHECK] --virtualbox-share-folder Mount the specified directory instead of the default home location. Format: dir:name [$VIRTUALBOX_SHARE_FOLDER] --virtualbox-ui-type "headless" Specify the UI Type: (gui|sdl|headless|separate) [$VIRTUALBOX_UI_TYPE]
Lister les VM Docker
Pour lister les VM Docker ainsi que leurs états, il convient d'utilise la sous-commande ls de la commande docker-machine :
hnorris-laptop ~ # docker-machine ls NAME ACTIVE DRIVER STATE URL SWARM DOCKER ERRORS manager1 - virtualbox Running tcp://192.168.99.100:2376 v17.06.2-ce worker1 - virtualbox Running tcp://192.168.99.101:2376 v17.06.2-ce worker2 - virtualbox Running tcp://192.168.99.102:2376 v17.06.2-ce worker3 - virtualbox Running tcp://192.168.99.103:2376 v17.06.2-ce worker4 - virtualbox Running tcp://192.168.99.104:2376 v17.06.2-ce worker5 - virtualbox Running tcp://192.168.99.105:2376 v17.06.2-ce
Important - Si vous avez Windows 7, 8 ou 10 et vous utilisez Docker Toolbox, les adresses IP des machines seront décalées de 1. Par exemple pour manager1, l'adresse sera 192.168.99.101 et pour worker1 192.168.99.102. Vous devez donc en tenir compte dans la suite du cours.
Obtenir l'adresse IP des VM
Une autre façon d'obtenir les adresses IP des VM est d'utiliser la sous-commande ip :
hnorris-laptop ~ # docker-machine ip manager1 192.168.99.100 hnorris-laptop ~ # docker-machine ip worker1 192.168.99.101 hnorris-laptop ~ # docker-machine ip worker2 192.168.99.102 hnorris-laptop ~ # docker-machine ip worker3 192.168.99.103 hnorris-laptop ~ # docker-machine ip worker4 192.168.99.104 hnorris-laptop ~ # docker-machine ip worker5 192.168.99.105
Se connecter à une VM Docker
Pour se connecter à une VM Docker, il convient d'utiliser la sous-commande ssh de la commande docker-machine :
hnorris-laptop ~ # docker-machine ssh manager1 ## . ## ## ## == ## ## ## ## ## === /"""""""""""""""""\___/ === ~~~ {~~ ~~~~ ~~~ ~~~~ ~~~ ~ / ===- ~~~ \______ o __/ \ \ __/ \____\_______/ _ _ ____ _ _ | |__ ___ ___ | |_|___ \ __| | ___ ___| | _____ _ __ | '_ \ / _ \ / _ \| __| __) / _` |/ _ \ / __| |/ / _ \ '__| | |_) | (_) | (_) | |_ / __/ (_| | (_) | (__| < __/ | |_.__/ \___/ \___/ \__|_____\__,_|\___/ \___|_|\_\___|_| Boot2Docker version 17.06.2-ce, build HEAD : ff16afa - Wed Sep 6 00:17:25 UTC 2017 Docker version 17.06.2-ce, build cec0b72 docker@manager1:~$
Important - Notez que la distribution de la VM est Boot2Docker. Cette distribution est basée sur Tiny Core Linux, s'exécute entièrement dans la mémoire vive, pèse 27 Mo et démarre en approximativement 5 secondes.
Ayant été créées par root, les VM Docker ainsi que leurs fichiers associés sont stockés dans le répertoire /root/.docker/machine/machines/ :
hnorris-laptop ~ # locate manager1 /root/.docker/machine/machines/manager1 /root/.docker/machine/machines/manager1/boot2docker.iso /root/.docker/machine/machines/manager1/ca.pem /root/.docker/machine/machines/manager1/cert.pem /root/.docker/machine/machines/manager1/config.json /root/.docker/machine/machines/manager1/disk.vmdk /root/.docker/machine/machines/manager1/id_rsa /root/.docker/machine/machines/manager1/id_rsa.pub /root/.docker/machine/machines/manager1/key.pem /root/.docker/machine/machines/manager1/manager1 /root/.docker/machine/machines/manager1/server-key.pem /root/.docker/machine/machines/manager1/server.pem /root/.docker/machine/machines/manager1/manager1/Logs /root/.docker/machine/machines/manager1/manager1/manager1.vbox /root/.docker/machine/machines/manager1/manager1/manager1.vbox-prev /root/.docker/machine/machines/manager1/manager1/Logs/VBox.log
LAB #2 - Orchéstration avec Docker Swarm,
Initialiser Docker Swarm
Pour initialiser Docker swarm, il convient d'utiliser la commande docker swarm init à partir de la VM Docker manager1 en stipulant l'adresse IP de manager1 :
docker@manager1:~$ docker swarm init --advertise-addr 192.168.99.100 Swarm initialized: current node (yuwpmvtfmdxn8i7nllkyzkxkp) is now a manager. To add a worker to this swarm, run the following command: docker swarm join --token SWMTKN-1-5bd9w9tapfqmd41f2psqdkoqwfo48fqsznnalk2slc28vlp6uh-004kp8y71m09nd7p8ft7ldku0 192.168.99.100:2377 To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.
Le Statut Leader
Consultez le statut de la VM Docker manager1 :
docker@manager1:~$ docker node ls ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS yuwpmvtfmdxn8i7nllkyzkxkp * manager1 Ready Active Leader
A un instant t il ne peut y avoir q'un seul Leader. Il est possible de créer d'autres noeuds de gestion en le rejoignant à swarm en utilisant le token prévu à cet effet. Par contre ces noeuds de gestion restent en attente d'une éventuelle défaillance du Leader actuel.
Pour connaître le token nécessaire pour ejoindre swarm en tant que noeud de gestion, saisissez la commande suivante :
docker@manager1:~$ docker swarm join-token manager To add a manager to this swarm, run the following command: docker swarm join --token SWMTKN-1-5bd9w9tapfqmd41f2psqdkoqwfo48fqsznnalk2slc28vlp6uh-8rvbxvqewsrv6yyts7z2lq9pt 192.168.99.100:2377
Rejoindre le Swarm
Rejoignez les 5 machines travailleurs à swarm en utilisant le token worker :
docker@worker1:~$ docker swarm join --token SWMTKN-1-5bd9w9tapfqmd41f2psqdkoqwfo48fqsznnalk2slc28vlp6uh-004kp8y71m09nd7p8ft7ldku0 192.168.99.100:2377 This node joined a swarm as a worker.
docker@worker2:~$ docker swarm join --token SWMTKN-1-5bd9w9tapfqmd41f2psqdkoqwfo48fqsznnalk2slc28vlp6uh-004kp8y71m09nd7p8ft7ldku0 192.168.99.100:2377 This node joined a swarm as a worker.
docker@worker3:~$ docker swarm join --token SWMTKN-1-5bd9w9tapfqmd41f2psqdkoqwfo48fqsznnalk2slc28vlp6uh-004kp8y71m09nd7p8ft7ldku0 192.168.99.100:2377 This node joined a swarm as a worker.
docker@worker4:~$ docker swarm join --token SWMTKN-1-5bd9w9tapfqmd41f2psqdkoqwfo48fqsznnalk2slc28vlp6uh-004kp8y71m09nd7p8ft7ldku0 192.168.99.100:2377 This node joined a swarm as a worker.
docker@worker5:~$ docker swarm join --token SWMTKN-1-5bd9w9tapfqmd41f2psqdkoqwfo48fqsznnalk2slc28vlp6uh-004kp8y71m09nd7p8ft7ldku0 192.168.99.100:2377 This node joined a swarm as a worker.
L'état des VM Docker peut être consulter en utilisant de nouveau la commande docker node ls :
docker@manager1:~$ docker node ls ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS 1f5qtolgtonqmhjk5ppwc8x1b worker1 Ready Active kmyjdwp9ojhzje4hlw7ffhuxv worker2 Ready Active oyszb44k8yw5btz3c1wq2ot2e worker4 Ready Active p6jpyopzzy0zg4znegi63hzjq worker5 Ready Active yitkfnk99ecisrny9g3r9kfhk worker3 Ready Active yuwpmvtfmdxn8i7nllkyzkxkp * manager1 Ready Active Leader
Notez que vous ne pouvez pas utiliser cette commande à partir d'un travailleur :
docker@worker5:~$ docker node ls Error response from daemon: This node is not a swarm manager. Worker nodes can't be used to view or modify cluster state. Please run this command on a manager node or promote the current node to a manager.
Consulter les Informations de Swarm
Il est possible de visualiser les informations concernant le swarm en utilisant la commande docker info :
docker@manager1:~$ docker info ... Swarm: active NodeID: yuwpmvtfmdxn8i7nllkyzkxkp Is Manager: true ClusterID: sqll9xmii9qkrd35d1limn1od Managers: 1 Nodes: 6 Orchestration: Task History Retention Limit: 5 Raft: Snapshot Interval: 10000 Number of Old Snapshots to Retain: 0 Heartbeat Tick: 1 Election Tick: 3 Dispatcher: Heartbeat Period: 5 seconds CA Configuration: Expiry Duration: 3 months Force Rotate: 0 Root Rotation In Progress: false Node Address: 192.168.99.100 Manager Addresses: 192.168.99.100:2377 ...
Important - Quand le moteur Docker est en mode swarm, les noeuds de gestion implémentent le Raft Consensus Algorithm pour gérer l'état du cluster.
Démarrer un Service
Dans cet example, nous allons démarrer le service nginx avec les propriètes suivantes :
- Mappage du port nginx sur le port 80 de la machine hôte,
- 5 instances du service,
- Un nom unique de web.
docker@manager1:~$ docker service create --replicas 5 -p 80:80 --name web nginx 4xtuwgbvr17lvfzoumh1y4mq4 Since --detach=false was not specified, tasks will be created in the background. In a future release, --detach=false will become the default.
Pour consulter l'état de ce service, utilisez la commande docker service ls :
docker@manager1:~$ docker service ls ID NAME MODE REPLICAS IMAGE PORTS 4xtuwgbvr17l web replicated 5/5 nginx:latest *:80->80/tcp
Ce service fonctionne dans des conteneurs Docker :
docker@manager1:~$ docker service ps web ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS jkm2hapcthht web.1 nginx:latest worker3 Running Running about a minute ago q55eqdhr1qf1 web.2 nginx:latest worker4 Running Running about a minute ago imqdkw4ei6gs web.3 nginx:latest manager1 Running Running about a minute ago k4vjd0g7ijww web.4 nginx:latest worker1 Running Running about a minute ago b7xbmy1npgf9 web.5 nginx:latest worker2 Running Running about a minute ago
Important - Notez qu'il n'y a pas de conteneur sur worker5.
Pour constater le lancement du daemon nginx, lancez la commande docker ps sur la machine manager1 :
docker@manager1:~$ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 4107cb687eda nginx:latest "nginx -g 'daemon ..." 2 minutes ago Up 2 minutes 80/tcp web.3.imqdkw4ei6gskwacnb4pime5f
Connectez-vous sur chaque VM Docker pour constater que le service nginx fonctionne :
docker@manager1:/$ curl 192.168.99.100 <!DOCTYPE html> <html> <head> <title>Welcome to nginx!</title> <style> body { width: 35em; margin: 0 auto; font-family: Tahoma, Verdana, Arial, sans-serif; } </style> </head> <body> <h1>Welcome to nginx!</h1> <p>If you see this page, the nginx web server is successfully installed and working. Further configuration is required.</p> <p>For online documentation and support please refer to <a href="http://nginx.org/">nginx.org</a>.<br/> Commercial support is available at <a href="http://nginx.com/">nginx.com</a>.</p> <p><em>Thank you for using nginx.</em></p> </body> </html> docker@manager1:/$ curl 192.168.99.101 <!DOCTYPE html> <html> <head> <title>Welcome to nginx!</title> <style> body { width: 35em; margin: 0 auto; font-family: Tahoma, Verdana, Arial, sans-serif; } </style> </head> <body> <h1>Welcome to nginx!</h1> <p>If you see this page, the nginx web server is successfully installed and working. Further configuration is required.</p> <p>For online documentation and support please refer to <a href="http://nginx.org/">nginx.org</a>.<br/> Commercial support is available at <a href="http://nginx.com/">nginx.com</a>.</p> <p><em>Thank you for using nginx.</em></p> </body> </html> docker@manager1:/$ curl 192.168.99.102 <!DOCTYPE html> <html> <head> <title>Welcome to nginx!</title> <style> body { width: 35em; margin: 0 auto; font-family: Tahoma, Verdana, Arial, sans-serif; } </style> </head> <body> <h1>Welcome to nginx!</h1> <p>If you see this page, the nginx web server is successfully installed and working. Further configuration is required.</p> <p>For online documentation and support please refer to <a href="http://nginx.org/">nginx.org</a>.<br/> Commercial support is available at <a href="http://nginx.com/">nginx.com</a>.</p> <p><em>Thank you for using nginx.</em></p> </body> </html> docker@manager1:/$ curl 192.168.99.103 <!DOCTYPE html> <html> <head> <title>Welcome to nginx!</title> <style> body { width: 35em; margin: 0 auto; font-family: Tahoma, Verdana, Arial, sans-serif; } </style> </head> <body> <h1>Welcome to nginx!</h1> <p>If you see this page, the nginx web server is successfully installed and working. Further configuration is required.</p> <p>For online documentation and support please refer to <a href="http://nginx.org/">nginx.org</a>.<br/> Commercial support is available at <a href="http://nginx.com/">nginx.com</a>.</p> <p><em>Thank you for using nginx.</em></p> </body> </html> docker@manager1:/$ curl 192.168.99.104 <!DOCTYPE html> <html> <head> <title>Welcome to nginx!</title> <style> body { width: 35em; margin: 0 auto; font-family: Tahoma, Verdana, Arial, sans-serif; } </style> </head> <body> <h1>Welcome to nginx!</h1> <p>If you see this page, the nginx web server is successfully installed and working. Further configuration is required.</p> <p>For online documentation and support please refer to <a href="http://nginx.org/">nginx.org</a>.<br/> Commercial support is available at <a href="http://nginx.com/">nginx.com</a>.</p> <p><em>Thank you for using nginx.</em></p> </body> </html> docker@manager1:/$ curl 192.168.99.105 <!DOCTYPE html> <html> <head> <title>Welcome to nginx!</title> <style> body { width: 35em; margin: 0 auto; font-family: Tahoma, Verdana, Arial, sans-serif; } </style> </head> <body> <h1>Welcome to nginx!</h1> <p>If you see this page, the nginx web server is successfully installed and working. Further configuration is required.</p> <p>For online documentation and support please refer to <a href="http://nginx.org/">nginx.org</a>.<br/> Commercial support is available at <a href="http://nginx.com/">nginx.com</a>.</p> <p><em>Thank you for using nginx.</em></p> </body> </html>
Important - Notez que le service est même disponible en consultant l'adresse IP de worker5.
Augmentation et Réduction du Service
Actuellement, il existe 5 conteneurs en cours d'exécution. Pour procéder à un scale-up à 8 conteneurs, il convient d'utiliser la commande docker service scale :
docker@manager1:/$ docker service scale web=8 web scaled to 8
Notez que la commande docker service ls confirme le fait qu'il y a 8 replicas :
docker@manager1:/$ docker service ls ID NAME MODE REPLICAS IMAGE PORTS 4xtuwgbvr17l web replicated 8/8 nginx:latest *:80->80/tcp
Des trois replicas supplémentaires, deux ont été lancés sur worker5 tandis que le troisième a été lancé sur worker1 :
docker@manager1:/$ docker service ps web ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS jkm2hapcthht web.1 nginx:latest worker3 Running Running 20 minutes ago q55eqdhr1qf1 web.2 nginx:latest worker4 Running Running 20 minutes ago imqdkw4ei6gs web.3 nginx:latest manager1 Running Running 20 minutes ago k4vjd0g7ijww web.4 nginx:latest worker1 Running Running 20 minutes ago b7xbmy1npgf9 web.5 nginx:latest worker2 Running Running 20 minutes ago kg3bivcg0wln web.6 nginx:latest worker5 Running Running 47 seconds ago ik3u0jfgey64 web.7 nginx:latest worker5 Running Running 47 seconds ago 6bw5ptw7xao8 web.8 nginx:latest worker1 Running Running 57 seconds ago
Consulter le Statut d'un Noeud
Pour se renseigner sur le statut du noeud courant, il convient d'utiliser la commande docker node inspect avec le mot clef self :
docker@manager1:/$ docker node inspect self [ { "ID": "yuwpmvtfmdxn8i7nllkyzkxkp", "Version": { "Index": 9 }, "CreatedAt": "2017-09-08T11:43:55.289178512Z", "UpdatedAt": "2017-09-08T11:43:55.89870884Z", "Spec": { "Labels": {}, "Role": "manager", "Availability": "active" }, "Description": { "Hostname": "manager1", "Platform": { "Architecture": "x86_64", "OS": "linux" }, "Resources": { "NanoCPUs": 1000000000, "MemoryBytes": 1044123648 }, "Engine": { "EngineVersion": "17.06.2-ce", "Labels": { "provider": "virtualbox" }, "Plugins": [ { "Type": "Log", "Name": "awslogs" }, { "Type": "Log", "Name": "fluentd" }, { "Type": "Log", "Name": "gcplogs" }, { "Type": "Log", "Name": "gelf" }, { "Type": "Log", "Name": "journald" }, { "Type": "Log", "Name": "json-file" }, { "Type": "Log", "Name": "logentries" }, { "Type": "Log", "Name": "splunk" }, { "Type": "Log", "Name": "syslog" }, { "Type": "Network", "Name": "bridge" }, { "Type": "Network", "Name": "host" }, { "Type": "Network", "Name": "macvlan" }, { "Type": "Network", "Name": "null" }, { "Type": "Network", "Name": "overlay" }, { "Type": "Volume", "Name": "local" } ] }, "TLSInfo": { "TrustRoot": "-----BEGIN CERTIFICATE-----\nMIIBajCCARCgAwIBAgIUNuU4I89kxId2QXulofRKxJa9XRcwCgYIKoZIzj0EAwIw\nEzERMA8GA1UEAxMIc3dhcm0tY2EwHhcNMTcwOTA4MTEzOTAwWhcNMzcwOTAzMTEz\nOTAwWjATMREwDwYDVQQDEwhzd2FybS1jYTBZMBMGByqGSM49AgEGCCqGSM49AwEH\nA0IABEqgLUbyjyNuP35aAzW+aqVB8AkghvpF5hq1KnMveHbl4Ilr+EyDjlYZkbnt\nGb/xmsy/tOP8uz598ZX/JlR4fZyjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMB\nAf8EBTADAQH/MB0GA1UdDgQWBBSzoKGrN0ELfEIMsjxuYj5LAckD2jAKBggqhkjO\nPQQDAgNIADBFAiB34DOvDtIYjJ+GzbPMGu9Dd/cJGvy7CJg1tNUG3SoOrAIhAJZ4\nTJBucTomFSDsj5Y/R6TfhcpXpsksk7JwYgEglu44\n-----END CERTIFICATE-----\n", "CertIssuerSubject": "MBMxETAPBgNVBAMTCHN3YXJtLWNh", "CertIssuerPublicKey": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAESqAtRvKPI24/floDNb5qpUHwCSCG+kXmGrUqcy94duXgiWv4TIOOVhmRue0Zv/GazL+04/y7Pn3xlf8mVHh9nA==" } }, "Status": { "State": "ready", "Addr": "192.168.99.100" }, "ManagerStatus": { "Leader": true, "Reachability": "reachable", "Addr": "192.168.99.100:2377" } } ]
Pour se renseigner sur le statut d'un autre noeud, il convient d'utiliser la commande docker node inspect avec le nom du noeud concerné :
docker@manager1:/$ docker node inspect worker1 [ { "ID": "1f5qtolgtonqmhjk5ppwc8x1b", "Version": { "Index": 15 }, "CreatedAt": "2017-09-08T11:48:42.011596185Z", "UpdatedAt": "2017-09-08T11:48:42.093455479Z", "Spec": { "Labels": {}, "Role": "worker", "Availability": "active" }, "Description": { "Hostname": "worker1", "Platform": { "Architecture": "x86_64", "OS": "linux" }, "Resources": { "NanoCPUs": 1000000000, "MemoryBytes": 1044123648 }, "Engine": { "EngineVersion": "17.06.2-ce", "Labels": { "provider": "virtualbox" }, "Plugins": [ { "Type": "Log", "Name": "awslogs" }, { "Type": "Log", "Name": "fluentd" }, { "Type": "Log", "Name": "gcplogs" }, { "Type": "Log", "Name": "gelf" }, { "Type": "Log", "Name": "journald" }, { "Type": "Log", "Name": "json-file" }, { "Type": "Log", "Name": "logentries" }, { "Type": "Log", "Name": "splunk" }, { "Type": "Log", "Name": "syslog" }, { "Type": "Network", "Name": "bridge" }, { "Type": "Network", "Name": "host" }, { "Type": "Network", "Name": "macvlan" }, { "Type": "Network", "Name": "null" }, { "Type": "Network", "Name": "overlay" }, { "Type": "Volume", "Name": "local" } ] }, "TLSInfo": { "TrustRoot": "-----BEGIN CERTIFICATE-----\nMIIBajCCARCgAwIBAgIUNuU4I89kxId2QXulofRKxJa9XRcwCgYIKoZIzj0EAwIw\nEzERMA8GA1UEAxMIc3dhcm0tY2EwHhcNMTcwOTA4MTEzOTAwWhcNMzcwOTAzMTEz\nOTAwWjATMREwDwYDVQQDEwhzd2FybS1jYTBZMBMGByqGSM49AgEGCCqGSM49AwEH\nA0IABEqgLUbyjyNuP35aAzW+aqVB8AkghvpF5hq1KnMveHbl4Ilr+EyDjlYZkbnt\nGb/xmsy/tOP8uz598ZX/JlR4fZyjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMB\nAf8EBTADAQH/MB0GA1UdDgQWBBSzoKGrN0ELfEIMsjxuYj5LAckD2jAKBggqhkjO\nPQQDAgNIADBFAiB34DOvDtIYjJ+GzbPMGu9Dd/cJGvy7CJg1tNUG3SoOrAIhAJZ4\nTJBucTomFSDsj5Y/R6TfhcpXpsksk7JwYgEglu44\n-----END CERTIFICATE-----\n", "CertIssuerSubject": "MBMxETAPBgNVBAMTCHN3YXJtLWNh", "CertIssuerPublicKey": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAESqAtRvKPI24/floDNb5qpUHwCSCG+kXmGrUqcy94duXgiWv4TIOOVhmRue0Zv/GazL+04/y7Pn3xlf8mVHh9nA==" } }, "Status": { "State": "ready", "Addr": "192.168.99.101" } } ]
L'option –pretty produit une sortie plus facilement lisible :
docker@manager1:/$ docker node inspect --pretty worker1 ID: 1f5qtolgtonqmhjk5ppwc8x1b Hostname: worker1 Joined at: 2017-09-08 11:48:42.011596185 +0000 utc Status: State: Ready Availability: Active Address: 192.168.99.101 Platform: Operating System: linux Architecture: x86_64 Resources: CPUs: 1 Memory: 995.8MiB Plugins: Log: awslogs, fluentd, gcplogs, gelf, journald, json-file, logentries, splunk, syslog Network: bridge, host, macvlan, null, overlay Volume: local Engine Version: 17.06.2-ce Engine Labels: - provider=virtualbox TLS Info: TrustRoot: -----BEGIN CERTIFICATE----- MIIBajCCARCgAwIBAgIUNuU4I89kxId2QXulofRKxJa9XRcwCgYIKoZIzj0EAwIw EzERMA8GA1UEAxMIc3dhcm0tY2EwHhcNMTcwOTA4MTEzOTAwWhcNMzcwOTAzMTEz OTAwWjATMREwDwYDVQQDEwhzd2FybS1jYTBZMBMGByqGSM49AgEGCCqGSM49AwEH A0IABEqgLUbyjyNuP35aAzW+aqVB8AkghvpF5hq1KnMveHbl4Ilr+EyDjlYZkbnt Gb/xmsy/tOP8uz598ZX/JlR4fZyjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMB Af8EBTADAQH/MB0GA1UdDgQWBBSzoKGrN0ELfEIMsjxuYj5LAckD2jAKBggqhkjO PQQDAgNIADBFAiB34DOvDtIYjJ+GzbPMGu9Dd/cJGvy7CJg1tNUG3SoOrAIhAJZ4 TJBucTomFSDsj5Y/R6TfhcpXpsksk7JwYgEglu44 -----END CERTIFICATE----- Issuer Subject: MBMxETAPBgNVBAMTCHN3YXJtLWNh Issuer Public Key: MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAESqAtRvKPI24/floDNb5qpUHwCSCG+kXmGrUqcy94duXgiWv4TIOOVhmRue0Zv/GazL+04/y7Pn3xlf8mVHh9nA==
Haute Disponibilité
Quand un noeud est actif, il est capable de recevoir de nouvelles tâches à partir du manager :
- pendant un scale-up,
- pendant une une mise à jour progressive,
- quand un autre noeud reçois une instruction de se mettre en indisponibilité,
- quand un service se mets en échec sur un autre noeud
Rappelez-vous que la swarm contient 6 VM Docker :
docker@manager1:/$ docker node ls ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS 1f5qtolgtonqmhjk5ppwc8x1b worker1 Ready Active kmyjdwp9ojhzje4hlw7ffhuxv worker2 Ready Active oyszb44k8yw5btz3c1wq2ot2e worker4 Ready Active p6jpyopzzy0zg4znegi63hzjq worker5 Ready Active yitkfnk99ecisrny9g3r9kfhk worker3 Ready Active yuwpmvtfmdxn8i7nllkyzkxkp * manager1 Ready Active Leader
et que sur les 6 VM Docker, il y a 8 conteneurs,
docker@manager1:/$ docker service ps web ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS jkm2hapcthht web.1 nginx:latest worker3 Running Running 25 minutes ago q55eqdhr1qf1 web.2 nginx:latest worker4 Running Running 25 minutes ago imqdkw4ei6gs web.3 nginx:latest manager1 Running Running 25 minutes ago k4vjd0g7ijww web.4 nginx:latest worker1 Running Running 25 minutes ago b7xbmy1npgf9 web.5 nginx:latest worker2 Running Running 25 minutes ago kg3bivcg0wln web.6 nginx:latest worker5 Running Running 5 minutes ago ik3u0jfgey64 web.7 nginx:latest worker5 Running Running 5 minutes ago 6bw5ptw7xao8 web.8 nginx:latest worker1 Running Running 5 minutes ago
dont deux se trouvent sur worker1 :
docker@manager1:/$ docker node ps worker1 ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS k4vjd0g7ijww web.4 nginx:latest worker1 Running Running 26 minutes ago 6bw5ptw7xao8 web.8 nginx:latest worker1 Running Running 6 minutes ago
Mettez worker1 en mode d'indisponibilité en utilisant l'option –availability drain :
docker@manager1:/$ docker node update --availability drain worker1 worker1
Constatez que le service web a été déplacé sur deux autres noeuds, manager1 et worker4 :
docker@manager1:/$ docker service ps web ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS jkm2hapcthht web.1 nginx:latest worker3 Running Running 29 minutes ago q55eqdhr1qf1 web.2 nginx:latest worker4 Running Running 29 minutes ago imqdkw4ei6gs web.3 nginx:latest manager1 Running Running 29 minutes ago 6cv6j4tz0nk5 web.4 nginx:latest manager1 Running Running 33 seconds ago k4vjd0g7ijww \_ web.4 nginx:latest worker1 Shutdown Shutdown 33 seconds ago b7xbmy1npgf9 web.5 nginx:latest worker2 Running Running 29 minutes ago kg3bivcg0wln web.6 nginx:latest worker5 Running Running 9 minutes ago ik3u0jfgey64 web.7 nginx:latest worker5 Running Running 9 minutes ago wht3r8c9wga6 web.8 nginx:latest worker4 Running Running 33 seconds ago 6bw5ptw7xao8 \_ web.8 nginx:latest worker1 Shutdown Shutdown 33 seconds ago
Supprimer un Service
Pour supprimer un service il convient d'utiliser la commande docker service rm
docker@manager1:/$ docker service rm web web
docker@manager1:/$ docker service ls ID NAME MODE REPLICAS IMAGE PORTS
docker@manager1:/$ docker service inspect web [] Status: Error: no such service: web, Code: 1
LAB #3 - Installation de Kubernetes avec Minikube
Minikube permet de créer un cluster avec un seul noeud.
Préparation
kubectl
Installer kubectl sur votre machine hôte : Voir le lien https://kubernetes.io/docs/tasks/tools/install-kubectl/.
Minikube
Installer Minikube sur votre machine hôte : Voir le lien https://kubernetes.io/docs/tasks/tools/install-minikube/.
Installation
Installez un cluster Kubernetes dans une seule machine virtuelle (noeud) en utilisant minikube :
trainee@kubernetes:~$ minikube start 😄 minikube v0.34.1 on linux (amd64) 🔥 Creating virtualbox VM (CPUs=2, Memory=2048MB, Disk=20000MB) ... 💿 Downloading Minikube ISO ... 184.30 MB / 184.30 MB [============================================] 100.00% 0s 📶 "minikube" IP address is 192.168.99.100 🐳 Configuring Docker as the container runtime ... ✨ Preparing Kubernetes environment ... 💾 Downloading kubeadm v1.13.3 💾 Downloading kubelet v1.13.3 🚜 Pulling images required by Kubernetes v1.13.3 ... 🚀 Launching Kubernetes v1.13.3 using kubeadm ... 🔑 Configuring cluster permissions ... 🤔 Verifying component health ..... 💗 kubectl is now configured to use "minikube" 🏄 Done! Thank you for using minikube!
Vérifiez que Kubernetes est bien installé en utilisant la commande kubectl :
trainee@kubernetes:~$ kubectl get nodes NAME STATUS ROLES AGE VERSION minikube Ready master 4m47s v1.13.3
Installez maintenant un conteneur, appelé ici un POD :
trainee@kubernetes:~$ kubectl run hello-minikube --image=k8s.gcr.io/echoserver:1.10 --port=8080 kubectl run --generator=deployment/apps.v1 is DEPRECATED and will be removed in a future version. Use kubectl run --generator=run-pod/v1 or kubectl create instead. deployment.apps/hello-minikube created
Vérifiez le statut du POD :
trainee@kubernetes:~$ kubectl get pods NAME READY STATUS RESTARTS AGE hello-minikube-6fd785d459-7j47t 1/1 Running 0 78s
Ce POD est un serveur web. Nous avons besoin de le configurer de façon à pouvoir le contacter de notre machine hôte :
trainee@kubernetes:~$ kubectl expose deployment hello-minikube --type=NodePort service/hello-minikube exposed
Pour accèder à la page web du POD, nous avons besoin de son adresse IP :
trainee@kubernetes:~$ minikube service hello-minikube --url http://192.168.99.100:30915
Consultez la page web du POD :
trainee@kubernetes:~$ curl http://192.168.99.100:30915 Hostname: hello-minikube-6fd785d459-7j47t Pod Information: -no pod information available- Server values: server_version=nginx: 1.13.3 - lua: 10008 Request Information: client_address=172.17.0.1 method=GET real path=/ query= request_version=1.1 request_scheme=http request_uri=http://192.168.99.100:8080/ Request Headers: accept=*/* host=192.168.99.100:30915 user-agent=curl/7.58.0 Request Body: -no body in request-
Supprimez maintenant le déploiement :
trainee@kubernetes:~$ kubectl delete deployment hello-minikube deployment.extensions "hello-minikube" deleted
LAB #4 - Importation de la Machine Virtuelle Kubemaster
Importez la machine virtuelle kubemaster :
Fichier > Importer un appareil virtuel ...
Le nom d'utilisateur et le mot de passe sont :
Utilisateur | Mot de Passe |
---|---|
trainee | trainee |
Exécutez la commande apt-get update :
trainee@kubemaster:~$ sudo su - [sudo] password for trainee: trainee root@kubemaster:~# apt-get update Hit:1 http://fr.archive.ubuntu.com/ubuntu xenial InRelease Hit:2 http://fr.archive.ubuntu.com/ubuntu xenial-updates InRelease Hit:3 http://fr.archive.ubuntu.com/ubuntu xenial-backports InRelease Hit:4 http://security.ubuntu.com/ubuntu xenial-security InRelease Reading package lists... Done
Important : Notez que le mot de passe trainee ne sera pas en clair.
Notez que les machines virtuelles utilisées avec Kubernetes doivent être sous une des distrubutions suivantes :
- Ubuntu 16.04+,
- Debian 9,
- CentOS 7,
- RHEL 7,
- Fedora 25/26 (best-effort),
- HypriotOS v1.0.1+,
- Container Linux (tested with 1800.6.0).
Chaque machine doit avoir :
- Un minimum de 2 GO de RAM,
- Un minimu de 2 CPU.
Les machines doivent :
- être dans le même réseau,
- posséder un nom d'hôte unique, une adresse MAC unique ainsi qu'un product_uuid unique,
- avoir le swap désactivé,
- avoir l'utilisation de dnsmasq par NetworkManager sous Systemd désactivée.
Certains ports doivent être ouverts sur le noeud maître :
Protocole | Direction | Port(s) | Exécutable |
---|---|---|---|
TCP | Entrante | 6443* | Kubernetes API server |
TCP | Entrante | 2379-2380 | etcd server client API |
TCP | Entrante | 10250 | Kubelet API |
TCP | Entrante | 10251 | kube-scheduler |
TCP | Entrante | 10252 | kube-controller-manager |
ainsi que sur chaque noeud travailleur :
Protocole | Direction | Port(s) | Exécutable |
---|---|---|---|
TCP | Entrante | 10250 | Kubelet API |
TCP | Entrante | 30000-32767 | Services NodePort |
LAB #5 - Installation de Docker, kubeadm, kubelet et kubectl
Vous allez créer un cluster comprenant un noeud maître et deux noeuds travailleurs.
Installation de Docker
Utilisez APT pour installer Docker :
root@kubemaster:~# apt-get install docker.io
Vérifiez que Docker-CE soit bien installé :
root@kubemaster:~# docker version Client: Version: 18.06.1-ce API version: 1.38 Go version: go1.10.4 Git commit: e68fc7a Built: Fri Jan 25 14:33:54 2019 OS/Arch: linux/amd64 Experimental: false Server: Engine: Version: 18.06.1-ce API version: 1.38 (minimum version 1.12) Go version: go1.10.4 Git commit: e68fc7a Built: Thu Jan 24 10:56:33 2019 OS/Arch: linux/amd64 Experimental: false
Important : A la date de la création de ce cours Kubernetes version 1.13.3 n'a été validé qu'avec des versions 18.06 et inférieures de Docker-CE.
Installation de kubeadm, kubelet et kubectl
Installez les prérequis pour l'installation de Docker-CE :
root@kubemaster:~# apt-get -y install apt-transport-https curl
Ajoutez la clef GPG pour le dépôt Kubernetes :
root@kubemaster:~# curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add - OK
Ajoutez le dépôt de Kubernetes :
root@kubemaster:~# echo "deb https://apt.kubernetes.io/ kubernetes-xenial main" | tee -a /etc/apt/sources.list.d/kubernetes.list deb https://apt.kubernetes.io/ kubernetes-xenial main
Procédez à l'installation de kubeadm, kubelet et kubectl :
root@kubemaster:~# apt-get update && apt-get install -y kubeadm kubelet kubectl
A Faire : Prenez une instantanée de votre machine virtuelle.
LAB #6 - Création et Configuration des Noeuds
Arrêtez la machine virtuelle et créez deux clones en générant de nouvelles adresses MAC pour toutes les interfaces réseau :
A Faire : Prenez une instantanée de vos trois machines virtuelles.
LAB #7 - Création du Réseau pour Kubernetes
Chaque machine virtuelle possède deux interfaces réseau. La première est NATée afin de pouvoir sortir sur Internet. Afin de créer un cluster efficace, il faut configurer la deuxième interface en adresse IP fixe. Créez donc le réseau privé hôte vboxnet1 en 192.168.56.1/24 dans VirtualBox :
Réseau > Créer
Configurez ensuite la deuxième interface réseau de chaque machine virtuelle en la plaçant dans le réseau privé hôte :
Détails > Réseau > Interface 2
Cochez Activer l'interface réseau et choisissez :
- Mode d'accès réseau =⇒ Réseau privé hôte
- Nom =⇒ vboxnet1
Démarrez les trois machines virtuelles. Modifiez le nom d'hôte et le fichier /etc/hosts des machines virtuelles kubenode1 et kubenode2 :
trainee@kubemaster:~$ sudo su - [sudo] password for trainee: trainee root@kubemaster:~# nmcli g hostname kubenode1 root@kubemaster:~# vi /etc/hosts root@kubemaster:~# cat /etc/hosts 127.0.0.1 localhost 127.0.1.1 kubenode1 # The following lines are desirable for IPv6 capable hosts ::1 ip6-localhost ip6-loopback fe00::0 ip6-localnet ff00::0 ip6-mcastprefix ff02::1 ip6-allnodes ff02::2 ip6-allrouters
trainee@kubemaster:~$ sudo su - [sudo] password for trainee: trainee root@kubemaster:~# nmcli g hostname kubenode2 root@kubemaster:~# vi /etc/hosts root@kubemaster:~# cat /etc/hosts 127.0.0.1 localhost 127.0.1.1 kubenode2 # The following lines are desirable for IPv6 capable hosts ::1 ip6-localhost ip6-loopback fe00::0 ip6-localnet ff00::0 ip6-mcastprefix ff02::1 ip6-allnodes ff02::2 ip6-allrouters
Important : Notez que le mot de passe trainee ne sera pas en clair.
Configurez l'interface enp0s8 de la machine virtuelle kubemaster :
root@kubemaster:~# nmcli connection add con-name ip_fixe ifname enp0s8 type ethernet ip4 192.168.56.2/24 Connection 'ip_fixe' (928f7107-5d45-4f70-98fb-5d27eeb444e5) successfully added. root@kubemaster:~# nmcli c show NAME UUID TYPE DEVICE Wired connection 2 421548fa-f55a-357e-8ae4-8791eee9a58c 802-3-ethernet enp0s3 docker0 f21f037e-e14f-4608-b09e-10f428225b39 bridge docker0 ip_fixe 928f7107-5d45-4f70-98fb-5d27eeb444e5 802-3-ethernet enp0s8 Wired connection 1 3a77257b-e878-3e0d-97d9-d35b0112c03e 802-3-ethernet -- root@kubemaster:~# nmcli connection del "Wired connection 1" Connection 'Wired connection 1' (3a77257b-e878-3e0d-97d9-d35b0112c03e) successfully deleted. root@kubemaster:~# nmcli c show NAME UUID TYPE DEVICE Wired connection 2 421548fa-f55a-357e-8ae4-8791eee9a58c 802-3-ethernet enp0s3 docker0 f21f037e-e14f-4608-b09e-10f428225b39 bridge docker0 ip_fixe 928f7107-5d45-4f70-98fb-5d27eeb444e5 802-3-ethernet enp0s8
Configurez l'interface enp0s8 de la machine virtuelle kubenode1 :
root@kubemaster:~# nmcli connection add con-name ip_fixe ifname enp0s8 type ethernet ip4 192.168.56.3/24 Connection 'ip_fixe' (6e95709f-3444-4d5e-a771-c4dd84fa0357) successfully added. root@kubemaster:~# nmcli c show NAME UUID TYPE DEVICE Wired connection 2 58dd66a0-816a-314d-8352-027ea04bf85a 802-3-ethernet enp0s3 docker0 ebf6bb55-3fe7-4f27-8aba-4cbf142cb43b bridge docker0 ip_fixe 6e95709f-3444-4d5e-a771-c4dd84fa0357 802-3-ethernet enp0s8 Wired connection 1 17af16eb-2503-36f6-b85e-c7e977ed11d2 802-3-ethernet -- root@kubemaster:~# nmcli connection del "Wired connection 1" Connection 'Wired connection 1' (17af16eb-2503-36f6-b85e-c7e977ed11d2) successfully deleted. root@kubemaster:~# nmcli c show NAME UUID TYPE DEVICE Wired connection 2 58dd66a0-816a-314d-8352-027ea04bf85a 802-3-ethernet enp0s3 docker0 ebf6bb55-3fe7-4f27-8aba-4cbf142cb43b bridge docker0 ip_fixe 6e95709f-3444-4d5e-a771-c4dd84fa0357 802-3-ethernet enp0s8
Configurez l'interface enp0s8 de la machine virtuelle kubenode2 :
root@kubemaster:~# nmcli connection add con-name ip_fixe ifname enp0s8 type ethernet ip4 192.168.56.4/24 Connection 'ip_fixe' (06a92de1-a047-4a73-858e-c3fced41b0b8) successfully added. root@kubemaster:~# nmcli c show NAME UUID TYPE DEVICE Wired connection 2 93f8951b-77f2-3f34-898f-6fbaa6ea8df6 802-3-ethernet enp0s3 docker0 3c445d6a-c1a3-422d-9a0a-72d19e6ac8bc bridge docker0 ip_fixe 06a92de1-a047-4a73-858e-c3fced41b0b8 802-3-ethernet enp0s8 Wired connection 1 e9944ce6-1ec4-3a5b-9b49-cb53f9ae4bc4 802-3-ethernet -- root@kubemaster:~# nmcli connection del "Wired connection 1" Connection 'Wired connection 1' (e9944ce6-1ec4-3a5b-9b49-cb53f9ae4bc4) successfully deleted. root@kubemaster:~# nmcli c show NAME UUID TYPE DEVICE Wired connection 2 93f8951b-77f2-3f34-898f-6fbaa6ea8df6 802-3-ethernet enp0s3 docker0 3c445d6a-c1a3-422d-9a0a-72d19e6ac8bc bridge docker0 ip_fixe 06a92de1-a047-4a73-858e-c3fced41b0b8 802-3-ethernet enp0s8
A Faire : Re-démarrez les trois machines virtuelles.
Installez le paquet openssh-server dans chaque machine virtuelle :
trainee@kubemaster:~$ sudo su - [sudo] password for trainee: trainee root@kubemaster:~# apt-get install -y openssh-server
trainee@kubenode1:~$ sudo su - [sudo] password for trainee: trainee root@kubenode1:~# apt-get install -y openssh-server
trainee@kubenode2:~$ sudo su - [sudo] password for trainee: trainee root@kubenode2:~# apt-get install -y openssh-server
Important : Notez que le mot de passe trainee ne sera pas en clair.
A Faire : Prenez une instantanée de vos trois machines virtuelles.
LAB #8 - Connexion à vos Machines Virtuelles avec SSH
Vous devez vous connecter aux machines virtuelles de la façon suivante :
MAC et Linux
Ouvrez un terminal et tapez la commande suivante pour la machine kubemaster :
$ ssh -l trainee localhost -p 2022
Ouvrez un autre terminal et tapez la commande suivante pour la machine kubenode1 :
$ ssh -l trainee localhost -p 3022
Ouvrez un autre terminal et tapez la commande suivante pour la machine kubenode2 :
$ ssh -l trainee localhost -p 4022
Windows
Ouvrez putty et utilisez les informations suivantes pour vous connecter à kubemaster :
- Host Name –> localhost
- Port –> 2022
Ouvrez putty et utilisez les informations suivantes pour vous connecter à kubenode1 :
- Host Name –> localhost
- Port –> 3022
Ouvrez putty et utilisez les informations suivantes pour vous connecter à kubenode2 :
- Host Name –> localhost
- Port –> 4022
Vérifiez la connectivité de chaque machine virtuelle :
trainee@kubemaster:~$ ping -c 4 192.168.56.3 PING 192.168.56.3 (192.168.56.3) 56(84) bytes of data. 64 bytes from 192.168.56.3: icmp_seq=1 ttl=64 time=0.762 ms 64 bytes from 192.168.56.3: icmp_seq=2 ttl=64 time=0.765 ms 64 bytes from 192.168.56.3: icmp_seq=3 ttl=64 time=0.819 ms 64 bytes from 192.168.56.3: icmp_seq=4 ttl=64 time=0.682 ms --- 192.168.56.3 ping statistics --- 4 packets transmitted, 4 received, 0% packet loss, time 3006ms rtt min/avg/max/mdev = 0.682/0.757/0.819/0.048 ms trainee@kubemaster:~$ ping -c 4 192.168.56.4 PING 192.168.56.4 (192.168.56.4) 56(84) bytes of data. 64 bytes from 192.168.56.4: icmp_seq=1 ttl=64 time=1.26 ms 64 bytes from 192.168.56.4: icmp_seq=2 ttl=64 time=0.710 ms 64 bytes from 192.168.56.4: icmp_seq=3 ttl=64 time=0.684 ms 64 bytes from 192.168.56.4: icmp_seq=4 ttl=64 time=0.710 ms --- 192.168.56.4 ping statistics --- 4 packets transmitted, 4 received, 0% packet loss, time 3002ms rtt min/avg/max/mdev = 0.684/0.841/1.260/0.242 ms trainee@kubemaster:~$ ping -c 4 www.free.fr PING www.free.fr (212.27.48.10) 56(84) bytes of data. 64 bytes from www.free.fr (212.27.48.10): icmp_seq=1 ttl=53 time=64.6 ms 64 bytes from www.free.fr (212.27.48.10): icmp_seq=2 ttl=53 time=76.3 ms 64 bytes from www.free.fr (212.27.48.10): icmp_seq=3 ttl=53 time=75.3 ms 64 bytes from www.free.fr (212.27.48.10): icmp_seq=4 ttl=53 time=87.2 ms --- www.free.fr ping statistics --- 4 packets transmitted, 4 received, 0% packet loss, time 3004ms rtt min/avg/max/mdev = 64.674/75.894/87.200/7.975 ms
trainee@kubenode1:~$ ping -c 4 192.168.56.2 PING 192.168.56.2 (192.168.56.2) 56(84) bytes of data. 64 bytes from 192.168.56.2: icmp_seq=1 ttl=64 time=0.605 ms 64 bytes from 192.168.56.2: icmp_seq=2 ttl=64 time=0.597 ms 64 bytes from 192.168.56.2: icmp_seq=3 ttl=64 time=0.717 ms 64 bytes from 192.168.56.2: icmp_seq=4 ttl=64 time=0.773 ms --- 192.168.56.2 ping statistics --- 4 packets transmitted, 4 received, 0% packet loss, time 3045ms rtt min/avg/max/mdev = 0.597/0.673/0.773/0.074 ms trainee@kubenode1:~$ ping -c 4 192.168.56.4 PING 192.168.56.4 (192.168.56.4) 56(84) bytes of data. 64 bytes from 192.168.56.4: icmp_seq=1 ttl=64 time=0.609 ms 64 bytes from 192.168.56.4: icmp_seq=2 ttl=64 time=0.494 ms 64 bytes from 192.168.56.4: icmp_seq=3 ttl=64 time=0.475 ms 64 bytes from 192.168.56.4: icmp_seq=4 ttl=64 time=0.385 ms --- 192.168.56.4 ping statistics --- 4 packets transmitted, 4 received, 0% packet loss, time 3004ms rtt min/avg/max/mdev = 0.385/0.490/0.609/0.084 ms trainee@kubenode1:~$ ping -c 4 www.free.fr PING www.free.fr (212.27.48.10) 56(84) bytes of data. 64 bytes from www.free.fr (212.27.48.10): icmp_seq=1 ttl=53 time=73.0 ms 64 bytes from www.free.fr (212.27.48.10): icmp_seq=2 ttl=53 time=72.5 ms 64 bytes from www.free.fr (212.27.48.10): icmp_seq=3 ttl=53 time=71.3 ms 64 bytes from www.free.fr (212.27.48.10): icmp_seq=4 ttl=53 time=70.4 ms --- www.free.fr ping statistics --- 4 packets transmitted, 4 received, 0% packet loss, time 3004ms rtt min/avg/max/mdev = 70.466/71.831/73.024/1.005 ms
trainee@kubenode2:~$ ping -c 4 192.168.56.2 PING 192.168.56.2 (192.168.56.2) 56(84) bytes of data. 64 bytes from 192.168.56.2: icmp_seq=1 ttl=64 time=0.725 ms 64 bytes from 192.168.56.2: icmp_seq=2 ttl=64 time=0.715 ms 64 bytes from 192.168.56.2: icmp_seq=3 ttl=64 time=0.766 ms 64 bytes from 192.168.56.2: icmp_seq=4 ttl=64 time=0.716 ms --- 192.168.56.2 ping statistics --- 4 packets transmitted, 4 received, 0% packet loss, time 3011ms rtt min/avg/max/mdev = 0.715/0.730/0.766/0.034 ms trainee@kubenode2:~$ ping -c 4 192.168.56.3 PING 192.168.56.3 (192.168.56.3) 56(84) bytes of data. 64 bytes from 192.168.56.3: icmp_seq=1 ttl=64 time=0.455 ms 64 bytes from 192.168.56.3: icmp_seq=2 ttl=64 time=0.694 ms 64 bytes from 192.168.56.3: icmp_seq=3 ttl=64 time=0.704 ms 64 bytes from 192.168.56.3: icmp_seq=4 ttl=64 time=0.723 ms --- 192.168.56.3 ping statistics --- 4 packets transmitted, 4 received, 0% packet loss, time 3005ms rtt min/avg/max/mdev = 0.455/0.644/0.723/0.109 ms trainee@kubenode2:~$ ping -c 4 www.free.fr PING www.free.fr (212.27.48.10) 56(84) bytes of data. 64 bytes from www.free.fr (212.27.48.10): icmp_seq=1 ttl=53 time=84.5 ms 64 bytes from www.free.fr (212.27.48.10): icmp_seq=2 ttl=53 time=80.1 ms 64 bytes from www.free.fr (212.27.48.10): icmp_seq=3 ttl=53 time=75.6 ms 64 bytes from www.free.fr (212.27.48.10): icmp_seq=4 ttl=53 time=56.9 ms --- www.free.fr ping statistics --- 4 packets transmitted, 4 received, 0% packet loss, time 3005ms rtt min/avg/max/mdev = 56.993/74.368/84.598/10.513 ms
LAB #9 - Création du Cluster Kubernetes
Préparation du kubemaster
Désactivez le swap sur kubemaster :
root@kubemaster:~# swapoff -a root@kubemaster:~# vi /etc/fstab root@kubemaster:~# cat /etc/fstab # /etc/fstab: static file system information. # # Use 'blkid' to print the universally unique identifier for a # device; this may be used with UUID= as a more robust way to name devices # that works even if disks are added and removed. See fstab(5). # # <file system> <mount point> <type> <options> <dump> <pass> # / was on /dev/sda1 during installation UUID=3fbe79a6-9d57-4bb0-b39a-ef1c0a306807 / ext4 errors=remount-ro 0 1 # swap was on /dev/sda5 during installation # UID=7c2c6644-2a9f-46cd-9326-d02ce30157d4 none swap sw 0 0
Désactivez l'utilisation de dnsmasq par NetworkManager :
root@kubemaster:~# vi /etc/NetworkManager/NetworkManager.conf root@kubemaster:~# cat /etc/NetworkManager/NetworkManager.conf [main] plugins=ifupdown,keyfile,ofono #dns=dnsmasq [ifupdown] managed=false root@kubemaster:~# systemctl restart NetworkManager root@kubemaster:~# nmcli connection up ip_fixe
Initialisation du Maître du Cluster
Initialisez le maître du cluster kubemaster en spécifiant le CIDR de l'extension Calico ainsi que l'adresse IP du maître :
root@kubemaster:~# kubeadm init --pod-network-cidr=192.168.0.0/16 --apiserver-advertise-address=192.168.56.2 [init] Using Kubernetes version: v1.13.3 [preflight] Running pre-flight checks [preflight] Pulling images required for setting up a Kubernetes cluster [preflight] This might take a minute or two, depending on the speed of your internet connection [preflight] You can also perform this action in beforehand using 'kubeadm config images pull' [kubelet-start] Writing kubelet environment file with flags to file "/var/lib/kubelet/kubeadm-flags.env" [kubelet-start] Writing kubelet configuration to file "/var/lib/kubelet/config.yaml" [kubelet-start] Activating the kubelet service [certs] Using certificateDir folder "/etc/kubernetes/pki" [certs] Generating "etcd/ca" certificate and key [certs] Generating "etcd/server" certificate and key [certs] etcd/server serving cert is signed for DNS names [kubemaster localhost] and IPs [192.168.56.2 127.0.0.1 ::1] [certs] Generating "etcd/peer" certificate and key [certs] etcd/peer serving cert is signed for DNS names [kubemaster localhost] and IPs [192.168.56.2 127.0.0.1 ::1] [certs] Generating "etcd/healthcheck-client" certificate and key [certs] Generating "apiserver-etcd-client" certificate and key [certs] Generating "ca" certificate and key [certs] Generating "apiserver-kubelet-client" certificate and key [certs] Generating "apiserver" certificate and key [certs] apiserver serving cert is signed for DNS names [kubemaster kubernetes kubernetes.default kubernetes.default.svc kubernetes.default.svc.cluster.local] and IPs [10.96.0.1 192.168.56.2] [certs] Generating "front-proxy-ca" certificate and key [certs] Generating "front-proxy-client" certificate and key [certs] Generating "sa" key and public key [kubeconfig] Using kubeconfig folder "/etc/kubernetes" [kubeconfig] Writing "admin.conf" kubeconfig file [kubeconfig] Writing "kubelet.conf" kubeconfig file [kubeconfig] Writing "controller-manager.conf" kubeconfig file [kubeconfig] Writing "scheduler.conf" kubeconfig file [control-plane] Using manifest folder "/etc/kubernetes/manifests" [control-plane] Creating static Pod manifest for "kube-apiserver" [control-plane] Creating static Pod manifest for "kube-controller-manager" [control-plane] Creating static Pod manifest for "kube-scheduler" [etcd] Creating static Pod manifest for local etcd in "/etc/kubernetes/manifests" [wait-control-plane] Waiting for the kubelet to boot up the control plane as static Pods from directory "/etc/kubernetes/manifests". This can take up to 4m0s [apiclient] All control plane components are healthy after 29.026069 seconds [uploadconfig] storing the configuration used in ConfigMap "kubeadm-config" in the "kube-system" Namespace [kubelet] Creating a ConfigMap "kubelet-config-1.13" in namespace kube-system with the configuration for the kubelets in the cluster [patchnode] Uploading the CRI Socket information "/var/run/dockershim.sock" to the Node API object "kubemaster" as an annotation [mark-control-plane] Marking the node kubemaster as control-plane by adding the label "node-role.kubernetes.io/master=''" [mark-control-plane] Marking the node kubemaster as control-plane by adding the taints [node-role.kubernetes.io/master:NoSchedule] [bootstrap-token] Using token: tj88c6.amxztch66b7favdx [bootstrap-token] Configuring bootstrap tokens, cluster-info ConfigMap, RBAC Roles [bootstraptoken] configured RBAC rules to allow Node Bootstrap tokens to post CSRs in order for nodes to get long term certificate credentials [bootstraptoken] configured RBAC rules to allow the csrapprover controller automatically approve CSRs from a Node Bootstrap Token [bootstraptoken] configured RBAC rules to allow certificate rotation for all node client certificates in the cluster [bootstraptoken] creating the "cluster-info" ConfigMap in the "kube-public" namespace [addons] Applied essential addon: CoreDNS [addons] Applied essential addon: kube-proxy Your Kubernetes master has initialized successfully! 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 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/ You can now join any number of machines by running the following on each node as root: kubeadm join 192.168.56.2:6443 --token tj88c6.amxztch66b7favdx --discovery-token-ca-cert-hash sha256:44fc222fbb6f4c1bb9be01e1547e9417fd093bd38079253150e3fa78da9b30b6
Important : Notez le message Your Kubernetes master has initialized successfully!.
A Faire : Copiez dans un fichier la dernière ligne de la sortie, par exemple kubeadm join 192.168.56.2:6443 –token tj88c6.amxztch66b7favdx –discovery-token-ca-cert-hash sha256:44fc222fbb6f4c1bb9be01e1547e9417fd093bd38079253150e3fa78da9b30b6.
Créez maintenant la variable KUBECONFIG :
root@kubemaster:~# export KUBECONFIG=/etc/kubernetes/admin.conf
Installation d'une Extension Réseau
Afin que les PODs puissent communiquer entre eux, il faut installer une extension pour le réseau . Il existe plusieurs extensions sur lesquelles nous reviendrons plus tard dans ce cours :
- Calico,
- Cilium,
- Flannel,
- Kube-router,
- Romana,
- Weave Net,
- JuniperContrail/TungstenFabric,
- Canal (utilise Flannel pour le réseau et Calico pour le pare-feu).
Afin d'obtenir un cluster nous allons utiliser la première extension de la liste, à savoir Calico :
root@kubemaster:~# kubectl apply -f https://docs.projectcalico.org/v3.5/getting-started/kubernetes/installation/hosted/kubernetes-datastore/calico-networking/1.7/calico.yaml configmap/calico-config created daemonset.extensions/calico-node created serviceaccount/calico-node created customresourcedefinition.apiextensions.k8s.io/felixconfigurations.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/bgppeers.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/bgpconfigurations.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/ippools.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/hostendpoints.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/clusterinformations.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/globalnetworkpolicies.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/globalnetworksets.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/networkpolicies.crd.projectcalico.org created clusterrole.rbac.authorization.k8s.io/calico-node created clusterrolebinding.rbac.authorization.k8s.io/calico-node created
Vérifiez que tout est dans un état Running :
root@kubemaster:~# kubectl get pods --all-namespaces NAMESPACE NAME READY STATUS RESTARTS AGE kube-system calico-node-jrhn2 1/1 Running 0 2m26s kube-system coredns-86c58d9df4-86gf9 1/1 Running 0 4m15s kube-system coredns-86c58d9df4-vhnvx 1/1 Running 0 4m15s kube-system etcd-kubemaster 1/1 Running 0 3m33s kube-system kube-apiserver-kubemaster 1/1 Running 0 3m44s kube-system kube-controller-manager-kubemaster 1/1 Running 0 3m36s kube-system kube-proxy-hlp6b 1/1 Running 0 4m15s kube-system kube-scheduler-kubemaster 1/1 Running 0 3m41s
Connexion des Travailleurs au Maître
Désactivez le swap sur kubenode1 et kubenode2 :
root@kubenode1:~# swapoff -a root@kubenode1:~# vi /etc/fstab root@kubenode1:~# cat /etc/fstab # /etc/fstab: static file system information. # # Use 'blkid' to print the universally unique identifier for a # device; this may be used with UUID= as a more robust way to name devices # that works even if disks are added and removed. See fstab(5). # # <file system> <mount point> <type> <options> <dump> <pass> # / was on /dev/sda1 during installation UUID=3fbe79a6-9d57-4bb0-b39a-ef1c0a306807 / ext4 errors=remount-ro 0 1 # swap was on /dev/sda5 during installation # UUID=7c2c6644-2a9f-46cd-9326-d02ce30157d4 none swap sw 0 0
root@kubenode2:~# swapoff -a root@kubenode2:~# vi /etc/fstab root@kubenode2:~# cat /etc/fstab # /etc/fstab: static file system information. # # Use 'blkid' to print the universally unique identifier for a # device; this may be used with UUID= as a more robust way to name devices # that works even if disks are added and removed. See fstab(5). # # <file system> <mount point> <type> <options> <dump> <pass> # / was on /dev/sda1 during installation UUID=3fbe79a6-9d57-4bb0-b39a-ef1c0a306807 / ext4 errors=remount-ro 0 1 # swap was on /dev/sda5 during installation # UUID=7c2c6644-2a9f-46cd-9326-d02ce30157d4 none swap sw 0 0
Utilisez la commande sauvegardée ci-dessus pour joindre les deux noeuds au Maître :
root@kubenode1:~# kubeadm join 192.168.56.2:6443 --token tj88c6.amxztch66b7favdx --discovery-token-ca-cert-hash sha256:44fc222fbb6f4c1bb9be01e1547e9417fd093bd38079253150e3fa78da9b30b6 [preflight] Running pre-flight checks [discovery] Trying to connect to API Server "192.168.56.2:6443" [discovery] Created cluster-info discovery client, requesting info from "https://192.168.56.2:6443" [discovery] Requesting info from "https://192.168.56.2: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.56.2:6443" [discovery] Successfully established connection with API Server "192.168.56.2:6443" [join] Reading configuration from the cluster... [join] FYI: You can look at this config file with 'kubectl -n kube-system get cm kubeadm-config -oyaml' [kubelet] Downloading configuration for the kubelet from the "kubelet-config-1.13" ConfigMap in the kube-system namespace [kubelet-start] Writing kubelet configuration to file "/var/lib/kubelet/config.yaml" [kubelet-start] Writing kubelet environment file with flags to file "/var/lib/kubelet/kubeadm-flags.env" [kubelet-start] 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 "kubenode1" 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.
root@kubenode2:~# kubeadm join 192.168.56.2:6443 --token tj88c6.amxztch66b7favdx --discovery-token-ca-cert-hash sha256:44fc222fbb6f4c1bb9be01e1547e9417fd093bd38079253150e3fa78da9b30b6 [preflight] Running pre-flight checks [discovery] Trying to connect to API Server "192.168.56.2:6443" [discovery] Created cluster-info discovery client, requesting info from "https://192.168.56.2:6443" [discovery] Requesting info from "https://192.168.56.2: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.56.2:6443" [discovery] Successfully established connection with API Server "192.168.56.2:6443" [join] Reading configuration from the cluster... [join] FYI: You can look at this config file with 'kubectl -n kube-system get cm kubeadm-config -oyaml' [kubelet] Downloading configuration for the kubelet from the "kubelet-config-1.13" ConfigMap in the kube-system namespace [kubelet-start] Writing kubelet configuration to file "/var/lib/kubelet/config.yaml" [kubelet-start] Writing kubelet environment file with flags to file "/var/lib/kubelet/kubeadm-flags.env" [kubelet-start] 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 "kubenode2" 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.
A Faire : Prenez une instantanée de vos trois machines virtuelles.
LAB #10 - Création d'un POD
Présentation d'un POD
Un POD est un objet qui encapsule un conteneur. Le conteneur est un instance d'une application. La relation entre un POD et une conteneur d'application est en règle générale 1:1, c'est-à-dire que dans le cas d'une augmentation de la charge, des PODs additionnels sont créés, chacun contenant un conteneur d'application au lieu de créer plusieurs conteneurs dans le même POD.
A l'inverse, dans le cas d'une réduction de la charge, des PODs sont détruits. Avec Kubernetes, on ne crée pas de conteneurs multiples du même type dans le même POD. Par contre, il est possible d'avoirs des conteneurs de types différents dans le même POD.
Dans ce cas on parle d'un conteneur d'application et un ou des conteneur(s) Helper. Le conteneur d'application et le conteneur Helper peuvent communiquer directement parce qu'ils partagent le même espace réseau. De même, ils ont accès au même espace de stockage.
Un POD permet donc de dispenser l'administrateur de la gestion de liens Docker ainsi que des volumes.
Lors da la création d'un POD avec la commande kubectl, celle-ci télécharge l'image Docker necéssaire à la création du conteneur à partir du Docker Hub.
Création Manuelle d'un POD
Commencez par créer un POD dénommé nginx à partir de l'image nginx :
root@kubemaster:~# kubectl run --generator=run-pod/v1 nginx --image=nginx pod/nginx created
Visualisez les PODS avec la commande kubectl :
root@kubemaster:~# kubectl get pods NAME READY STATUS RESTARTS AGE nginx 1/1 Running 0 8s
Consultez les informations concernant ce POD :
root@kubemaster:~# kubectl describe pods Name: nginx Namespace: default Priority: 0 PriorityClassName: <none> Node: kubenode2/10.0.2.15 Start Time: Fri, 22 Feb 2019 14:05:35 +0100 Labels: run=nginx Annotations: cni.projectcalico.org/podIP: 192.168.2.6/32 Status: Running IP: 192.168.2.6 Containers: nginx: Container ID: docker://8820884671a7ff86177acd33c25d5c22aad2693f907533f25c6bccbbcf72975a Image: nginx Image ID: docker-pullable://nginx@sha256:dd2d0ac3fff2f007d99e033b64854be0941e19a2ad51f174d9240dda20d9f534 Port: <none> Host Port: <none> State: Running Started: Fri, 22 Feb 2019 14:05:39 +0100 Ready: True Restart Count: 0 Environment: <none> Mounts: /var/run/secrets/kubernetes.io/serviceaccount from default-token-v72fl (ro) Conditions: Type Status Initialized True Ready True ContainersReady True PodScheduled True Volumes: default-token-v72fl: Type: Secret (a volume populated by a Secret) SecretName: default-token-v72fl Optional: false QoS Class: BestEffort Node-Selectors: <none> Tolerations: node.kubernetes.io/not-ready:NoExecute for 300s node.kubernetes.io/unreachable:NoExecute for 300s Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Pulling 84s kubelet, kubenode2 pulling image "nginx" Normal Pulled 81s kubelet, kubenode2 Successfully pulled image "nginx" Normal Created 81s kubelet, kubenode2 Created container Normal Started 81s kubelet, kubenode2 Started container Normal Scheduled 79s default-scheduler Successfully assigned default/nginx to kubenode2
Important : Notez que la dernière ligne indique clairement que le POD tourne sur kubenode2.
Utilisez maintenant le commande kubectl avec l'option -o wide :
root@kubemaster:~# kubectl get pods -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES nginx 1/1 Running 0 5m 192.168.2.6 kubenode2 <none> <none>
Important : Notez que l'adresse IP du POD est la 192.168.2.6. Cette adresse est dynamique. Si le POD s'arrête et un autre démarre, l'adresse IP du nouveau POD sera différent.
Important : Notez que dans la colonne NOMINATED NODE il est marqué <none>. En effet il est possible d'assigner un POD à un noeud spécifique grâce à l'utilisation d'une étiquette définie pour le ou les noeuds nominés. Ce sujet est traité plus en détail dans le cours Maîtriser l'Orchestration avec Kubernetes. Pour plus d'information maintenant, consultez le lien https://kubernetes.io/docs/tasks/configure-pod-container/assign-pods-nodes/.
Important : Notez que dans la colonne READINESS GATES il est marqué <none>. En effet il est possible d'assigner à un POD des conditions spécifiques pour que Kubenetes considère que le POD est dans un état de ready. Ce sujet est traité plus en détail dans le cours Maîtriser l'Orchestration avec Kubernetes. Pour plus d'information maintenant, consultez le lien https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#pod-readiness-gate.
Création d'un POD à l'aide d'un fichier YAML
Kubernetes utilise des fichiers YAML pour créer des objets. Par conséquent, la définition du POD à créer est décrite dans un fichier YAML. Créez le fichier pod-definition.yaml :
root@kubemaster:~# vi pod-definition.yaml root@kubemaster:~# cat pod-definition.yaml --- apiVersion: v1 kind: Pod metadata: name: myapp-pod labels: app: myapp type: front-end spec: containers: - name: nginx-container image: nginx
Dans ce fichier on trouve les champs suivants :
apiVersion
- Ce champs est obligatoire,
- La version de l'API diffère selon le type d'objet qui est créé,
- La valeur du champs est sous la forme d'une chaîne.
kind
- Ce champs est obligatoire,
- La valeur de l'apiServer par rapport au type d'objet est :
kind | apiVersion |
---|---|
Pod | v1 |
Service | v1 |
ReplicaSet | apps/v1 |
Deployment | apps/v1 |
metadata
- Ce champs est obligatoire,
- Il contient des informations telles le nom et les étiquettes,
- Les informations sont sous la forme d'un dictionnaire YAML :
metadata: name: myapp-pod labels: app: myapp type: front-end
spec
- Ce champs est obligatoire,
- Il contient des informations pour Kubernetes spécifiques au type d'objet à créer,
- Les informations sont sous la forme d'un liste YAML :
spec: containers: - name: nginx-container image: nginx
Utilisation du Fichier YAML
Utilisez maintenant le fichier YAML afin de créer un POD :
root@kubemaster:~# kubectl create -f pod-definition.yaml pod/myapp-pod created
root@kubemaster:~# kubectl get pods NAME READY STATUS RESTARTS AGE myapp-pod 1/1 Running 0 19s nginx 1/1 Running 0 68m
A Faire : Prenez une instantanée de vos trois machines virtuelles.
LAB #11 - Utilisation de Contrôleurs de Réplication et ReplicaSets
Contrôleurs de Réplication
Un Contrôleur de Réplication permet d'exécuter plusieurs instances du même POD de façon à offrir de la haute disponibilité au cas où l'application crash et le POD se met en échec. Même dans le cas où il n'y a qu'un seul POD, le Contrôleur de Réplication peut démarrer automatiquement un autre POD contenant l'application :
Un Contrôleur de Réplication permet aussi de démarrer de nouveaux PODs en cas d'augmentation de la charge ainsi que d'assurer l'équilibrage de la charge entre les PODs :
Dans le cas où le premier noeud venait à court de ressources, un Contrôleur de Réplication est capable de démarrer de nouveaux PODs sur un deuxième noeud :
Pour créer un Contrôleur de Réplication, il convient de créer un fichier YAML. Créez donc le fichier cr-definition.yaml :
root@kubemaster:~# vi cr-definition.yaml root@kubemaster:~# cat cr-definition.yaml --- apiVersion: v1 kind: ReplicationController metadata: name: myapp-cr labels: app: myapp type: front-end spec: template: metadata: name: myapp-pod labels: app: myapp type: front-end spec: containers: - name: nginx-container image: nginx replicas: 3
Dans ce fichier est placée une section appelée template. Cette section est un gabarit pour la création de PODs supplémentaires et est indentique au contenu du fichier pod-definition.yaml sans les champs apiVersion et kind :
root@kubemaster:~# cat pod-definition.yaml apiVersion: v1 kind: Pod metadata: name: myapp-pod labels: app: myapp type: front-end spec: containers: - name: nginx-container image: nginx
Le champs replicas qui se trouve au même niveau de template indique le nombre de PODs à créer.
Utilisez le fichier rc-definition.yaml pour créer le Contrôleur de Réplication :
root@kubemaster:~# kubectl create -f cr-definition.yaml replicationcontroller/myapp-cr created
Pour visualiser le Contrôleur de Réplication, utilisez la commande suivante :
root@kubemaster:~# kubectl get replicationcontroller NAME DESIRED CURRENT READY AGE myapp-cr 3 3 3 71s
Pour visualiser les PODs créés par le Contrôleur de Réplication, utilisez la commande suivante :
root@kubemaster:~# kubectl get pods NAME READY STATUS RESTARTS AGE myapp-cr-257q6 1/1 Running 0 4m11s myapp-cr-cvnxh 1/1 Running 0 4m11s myapp-pod 1/1 Running 0 24h nginx 1/1 Running 1 26h
Important : Notez que le Contrôleur de Réplication a créé deux replicas myapp-cr-257q6 et myapp-cr-cvnxh car le premier existait déjà myapp-pod. Pour indentifier un POD du même type déjà en place, le Contrôleur de Réplication se fie au champ labels dans la section template.
Supprimez maintenant le POD myapp-pod :
root@kubemaster:~# kubectl delete pod myapp-pod pod "myapp-pod" deleted
Constatez ensuite la réaction du Contrôleur de Réplication :
root@kubemaster:~# kubectl get pods NAME READY STATUS RESTARTS AGE myapp-cr-257q6 1/1 Running 0 8m4s myapp-cr-cvnxh 1/1 Running 0 8m4s myapp-cr-g8mpp 1/1 Running 0 8s nginx 1/1 Running 1 26h
Important : Notez que le Contrôleur de Réplication a créé le POD myapp-cr-g8mpp.
Pour consulter le statut d'un Contrôleur de Réplication, utilisez la commande suivante :
root@kubemaster:~# kubectl describe replicationcontrollers/myapp-cr Name: myapp-cr Namespace: default Selector: app=myapp,type=front-end Labels: app=myapp type=front-end Annotations: <none> Replicas: 3 current / 3 desired Pods Status: 3 Running / 0 Waiting / 0 Succeeded / 0 Failed Pod Template: Labels: app=myapp type=front-end Containers: nginx-container: Image: nginx Port: <none> Host Port: <none> Environment: <none> Mounts: <none> Volumes: <none> Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal SuccessfulCreate 36m replication-controller Created pod: myapp-cr-257q6 Normal SuccessfulCreate 36m replication-controller Created pod: myapp-cr-cvnxh Normal SuccessfulCreate 28m replication-controller Created pod: myapp-cr-g8mpp
Pour suprimer un Contrôleur de Réplication, utilisez la commande suivante :
root@kubemaster:~# kubectl delete replicationcontroller myapp-cr replicationcontroller "myapp-cr" deleted
ReplicaSets
Un ReplicaSet remplit la même fonction qu'un Contrôleur de Réplication. ReplicaSets sont la façon la plus récente de gérer la réplication.
Pour créer un ReplicaSet, créez le fichier replicaset-definition.yaml :
root@kubemaster:~# vi replicaset.definition.yaml root@kubemaster:~# cat replicaset.definition.yaml --- apiVersion: apps/v1 kind: ReplicaSet metadata: name: myapp-replicaset labels: app: myapp type: front-end spec: template: metadata: name: myapp-pod labels: app: myapp type: front-end spec: containers: - name: nginx-container image: nginx replicas: 3 selector: matchLabels: type: front-end
Important : Notez que dans le cas d'un ReplicaSet, celui-ci identifie les PODs sous son conrtôle par la valeur du champ matchLabels..
Utilisez le fichier replicaset-definition.yaml pour créer le ReplicaSet :
root@kubemaster:~# kubectl create -f replicaset-definition.yaml replicaset.apps/myapp-replicaset created
Pour visualiser le ReplicaSet, utilisez la commande suivante :
root@kubemaster:~# kubectl get replicaset NAME DESIRED CURRENT READY AGE myapp-replicaset 3 3 3 67s
Pour visualiser les PODs créés par le ReplicaSet, utilisez la commande suivante :
root@kubemaster:~# kubectl get pods NAME READY STATUS RESTARTS AGE myapp-replicaset-2cllb 1/1 Running 0 87s myapp-replicaset-5nnsg 1/1 Running 0 87s myapp-replicaset-w4prx 1/1 Running 0 87s nginx 1/1 Running 1 26h
Modifiez maintenant le fichier replicaset-definition.yaml en augmentant le nombre de replicas de 3 à 6 :
root@kubemaster:~# vi replicaset-definition.yaml root@kubemaster:~# cat replicaset-definition.yaml --- apiVersion: apps/v1 kind: ReplicaSet metadata: name: myapp-replicaset labels: app: myapp type: front-end spec: template: metadata: name: myapp-pod labels: app: myapp type: front-end spec: containers: - name: nginx-container image: nginx replicas: 6 selector: matchLabels: type: front-end
Exécutez ensuite la commande kubectl replace :
root@kubemaster:~# kubectl get pods NAME READY STATUS RESTARTS AGE myapp-replicaset-2cllb 1/1 Running 0 16m myapp-replicaset-5nnsg 1/1 Running 0 16m myapp-replicaset-w4prx 1/1 Running 0 16m nginx 1/1 Running 1 26h root@kubemaster:~# kubectl replace -f replicaset-definition.yaml replicaset.apps/myapp-replicaset replaced
Visualiser le ReplicaSet :
root@kubemaster:~# kubectl get replicaset NAME DESIRED CURRENT READY AGE myapp-replicaset 6 6 6 17m
Visualiser les PODs créés par le ReplicaSet :
root@kubemaster:~# kubectl get pods NAME READY STATUS RESTARTS AGE myapp-replicaset-2cllb 1/1 Running 0 18m myapp-replicaset-5nnsg 1/1 Running 0 18m myapp-replicaset-8mw6z 1/1 Running 0 87s myapp-replicaset-fm7mq 1/1 Running 0 87s myapp-replicaset-q4fhf 1/1 Running 0 87s myapp-replicaset-w4prx 1/1 Running 0 18m nginx 1/1 Running 1 26h
Exécutez ensuite la commande suivante :
root@kubemaster:~# kubectl scale --replicas=9 -f replicaset-definition.yaml replicaset.apps/myapp-replicaset scaled
Visualiser le ReplicaSet :
root@kubemaster:~# kubectl get replicaset NAME DESIRED CURRENT READY AGE myapp-replicaset 9 9 6 20m
Visualiser les PODs créés par le ReplicaSet :
root@kubemaster:~# kubectl get pods NAME READY STATUS RESTARTS AGE myapp-replicaset-28lhh 1/1 Running 0 2m59s myapp-replicaset-2cllb 1/1 Running 0 23m myapp-replicaset-5nnsg 1/1 Running 0 23m myapp-replicaset-8mw6z 1/1 Running 0 6m14s myapp-replicaset-bsx9v 1/1 Running 0 2m59s myapp-replicaset-fm7mq 1/1 Running 0 6m14s myapp-replicaset-q4fhf 1/1 Running 0 6m14s myapp-replicaset-vxw5c 1/1 Running 0 2m59s myapp-replicaset-w4prx 1/1 Running 0 23m nginx 1/1 Running 1 26h
Notez que dans ce cas, la valeur des replicas dans le fichier replicaset-definition.yaml n'a pas été modifiée :
root@kubemaster:~# cat replicaset-definition.yaml --- apiVersion: apps/v1 kind: ReplicaSet metadata: name: myapp-replicaset labels: app: myapp type: front-end spec: template: metadata: name: myapp-pod labels: app: myapp type: front-end spec: containers: - name: nginx-container image: nginx replicas: 6 selector: matchLabels: type: front-end
Dernièrement, exécutez la commande suivante :
root@kubemaster:~# kubectl scale --replicas=3 replicaset myapp-replicaset replicaset.extensions/myapp-replicaset scaled
Visualiser le ReplicaSet :
root@kubemaster:~# kubectl get replicaset NAME DESIRED CURRENT READY AGE myapp-replicaset 3 3 3 25m
Visualiser les PODs créés par le ReplicaSet :
root@kubemaster:~# kubectl get pods NAME READY STATUS RESTARTS AGE myapp-replicaset-2cllb 1/1 Running 0 26m myapp-replicaset-5nnsg 1/1 Running 0 26m myapp-replicaset-w4prx 1/1 Running 0 26m nginx 1/1 Running 1 26h
Important : Notez que ce sont les premiers PODs créés qui sont retenus.
Créez maintenant un POD en dehors du ReplicaSet :
root@kubemaster:~# kubectl create -f pod-definition.yaml pod/myapp-pod created
Consultez la liste des PODs :
root@kubemaster:~# kubectl get pods NAME READY STATUS RESTARTS AGE myapp-pod 0/1 Terminating 0 3s myapp-replicaset-2cllb 1/1 Running 0 13h myapp-replicaset-5nnsg 1/1 Running 0 13h myapp-replicaset-w4prx 1/1 Running 0 13h nginx 1/1 Running 1 39h
Important : Notez que myapp-pod est dans un état Terminating. En effet le ReplicaSet ne permet pas la création d'un POD ayant la même étiquette que celle spécifiée par le champ matchLabels du fichier replicaset-definition.yaml.
Pour supprimer le ReplicaSet, utilisez la commande suivante :
root@kubemaster:~# kubectl delete replicaset myapp-replicaset replicaset.extensions "myapp-replicaset" deleted
Consultez maintenant tous les objets du cluster :
root@kubemaster:~# kubectl get all NAME READY STATUS RESTARTS AGE pod/nginx 1/1 Running 1 39h NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 47h service/nginx NodePort 10.97.86.167 <none> 80:31072/TCP 46h
A Faire : Prenez une instantanée de vos trois machines virtuelles.
LAB #12 - Gestion des Deployments
Un Deployment sous Kubernetes est un objet hiérarchiquement supérieur à un ReplicaSet :
Le Deployment permet la gestion des :
- déploiements de PODs (Rollouts),
- mises à jour roulantes (Rolling Updates),
- retours en arrière (Rollbacks).
Avant de continuer, supprimez le service nginx et le POD nginx :
root@kubemaster:~# kubectl delete service nginx service "nginx" deleted root@kubemaster:~# kubectl delete pod nginx pod "nginx" deleted
Vérifiez qu'il ne reste que l'objet ClusterIP :
root@kubemaster:~# kubectl get all NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 2d4h
Rollouts
Pour créer un Deployment, il convient de créer un fichier YAML. Créez donc le fichier deployment-definition.yaml :
root@kubemaster:~# vi deployment-definition.yaml root@kubemaster:~# cat deployment-definition.yaml --- apiVersion: apps/v1 kind: Deployment metadata: name: myapp-deployment labels: app: myapp type: front-end spec: template: metadata: name: myapp-pod labels: app: myapp type: front-end spec: containers: - name: nginx-container image: nginx replicas: 3 selector: matchLabels: type: front-end
Utilisez la commande suivante pour créer le Deployment :
root@kubemaster:~# kubectl create -f deployment-definition.yaml deployment.apps/myapp-deployment created
Constatez la création de celui-ci :
root@kubemaster:~# kubectl get deployments NAME READY UP-TO-DATE AVAILABLE AGE myapp-deployment 3/3 3 3 25s
Notez que la création du Deployment a également créé un ReplicaSet :
root@kubemaster:~# kubectl get replicasets NAME DESIRED CURRENT READY AGE myapp-deployment-667d46455b 3 3 3 48s
Important : Notez que la valeur 667d46455b est générée d'une manière aléatoire en intren par Kubernetes.
Bien entendu, la création de Deployment a créé le nombre de PODs indiqué dans le fichier YAML :
root@kubemaster:~# kubectl get pods NAME READY STATUS RESTARTS AGE myapp-deployment-667d46455b-8hlqf 1/1 Running 0 78s myapp-deployment-667d46455b-fgk9q 1/1 Running 0 78s myapp-deployment-667d46455b-qrm8s 1/1 Running 0 78s
Pour voir tous ces objets en même temps, utilisez la commande kubectl get all :
root@kubemaster:~# kubectl get all NAME READY STATUS RESTARTS AGE pod/myapp-deployment-667d46455b-8hlqf 1/1 Running 0 98s pod/myapp-deployment-667d46455b-fgk9q 1/1 Running 0 98s pod/myapp-deployment-667d46455b-qrm8s 1/1 Running 0 98s NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 2d8h NAME READY UP-TO-DATE AVAILABLE AGE deployment.apps/myapp-deployment 3/3 3 3 99s NAME DESIRED CURRENT READY AGE replicaset.apps/myapp-deployment-667d46455b 3 3 3 99s
Pour obtenir plus d'informations concernant le Deployment, utilisez la commande kubectl describe :
root@kubemaster:~# kubectl describe deployments Name: myapp-deployment Namespace: default CreationTimestamp: Sun, 24 Feb 2019 14:58:32 +0100 Labels: app=myapp type=front-end Annotations: deployment.kubernetes.io/revision: 1 Selector: type=front-end Replicas: 3 desired | 3 updated | 3 total | 3 available | 0 unavailable StrategyType: RollingUpdate MinReadySeconds: 0 RollingUpdateStrategy: 25% max unavailable, 25% max surge Pod Template: Labels: app=myapp type=front-end Containers: nginx-container: Image: nginx Port: <none> Host Port: <none> Environment: <none> Mounts: <none> Volumes: <none> Conditions: Type Status Reason ---- ------ ------ Available True MinimumReplicasAvailable Progressing True NewReplicaSetAvailable OldReplicaSets: <none> NewReplicaSet: myapp-deployment-667d46455b (3/3 replicas created) Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal ScalingReplicaSet 2m1s deployment-controller Scaled up replica set myapp-deployment-667d46455b to 3
Lors du Rollout du Deployment une Révision est créée. Cette Révision est incrémentée lors de chaque mise-à-jour :
Pour consulter le statut du Rollout, il convient d'utiliser la commande suivante :
root@kubemaster:~# kubectl rollout status deployment/myapp-deployment deployment "myapp-deployment" successfully rolled out
Pour consulter la liste des Révisions, utilisez la commande suivante :
root@kubemaster:~# kubectl rollout history deployment/myapp-deployment deployment.extensions/myapp-deployment REVISION CHANGE-CAUSE 1 <none>
Important : Notez que la valeur de CHANGE-CAUSE est <none> parce que l'option –record n'a pas été spécifiée sur la ligne de commande.
Supprimez donc le Deployment avec la commande suivante :
root@kubemaster:~# kubectl delete deployment myapp-deployment deployment.extensions "myapp-deployment" deleted
Vérifiez la suppression du Deployment :
root@kubemaster:~# kubectl get all NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 2d8h
Créez le Deployment de nouveau en ajoutant l'option –record :
root@kubemaster:~# kubectl create -f deployment-definition.yaml --record deployment.apps/myapp-deployment created
Consultez le statut du Rollout :
root@kubemaster:~# kubectl rollout status deployment/myapp-deployment deployment "myapp-deployment" successfully rolled out
Consultez la liste des Révisions :
root@kubemaster:~# kubectl rollout history deployment/myapp-deployment deployment.extensions/myapp-deployment REVISION CHANGE-CAUSE 1 kubectl create --filename=deployment-definition.yaml --record=true
Important : Notez que la valeur de CHANGE-CAUSE est la commande qui a été saisie.
Rolling Updates
Il existe deux méthodes de Deployment en cas de mise-à-jours :
- Recreate,
- Dans ce cas tous les PODs existants sont détruits en même temps et des PODs contenant la mise-à-jour sont créés dans un deuxième temps. L'inconvénient de cette méthode est évident - entre la déstruction des PODs et la re-création des nouveaux PODs, l'application n'est pas disponible,
- Rolling Update
- Dans ce cas, les PODs sont détruits un-par-un. Après chaque déstruction, un nouveau POD est créé contenant la mise-à-jour. De cette façon, l'application reste disponible.
Important : Notez que Rolling Update est la méthode par défaut.
Modifiez maintenant le fichier deployment-description.yaml en spécifiant la version 1.12 de nginx :
root@kubemaster:~# vi deployment-definition.yaml root@kubemaster:~# cat deployment-definition.yaml --- apiVersion: apps/v1 kind: Deployment metadata: name: myapp-deployment labels: app: myapp type: front-end spec: template: metadata: name: myapp-pod labels: app: myapp type: front-end spec: containers: - name: nginx-container image: nginx:1.12 replicas: 3 selector: matchLabels: type: front-end
Appliquez ce changement :
root@kubemaster:~# kubectl apply -f deployment-definition.yaml --record Warning: kubectl apply should be used on resource created by either kubectl create --save-config or kubectl apply deployment.apps/myapp-deployment configured
Consultez le statut du Deployment :
root@kubemaster:~# kubectl rollout status deployment/myapp-deployment Waiting for deployment "myapp-deployment" rollout to finish: 1 out of 3 new replicas have been updated... Waiting for deployment "myapp-deployment" rollout to finish: 1 out of 3 new replicas have been updated... Waiting for deployment "myapp-deployment" rollout to finish: 1 out of 3 new replicas have been updated... Waiting for deployment "myapp-deployment" rollout to finish: 2 out of 3 new replicas have been updated... Waiting for deployment "myapp-deployment" rollout to finish: 2 out of 3 new replicas have been updated... Waiting for deployment "myapp-deployment" rollout to finish: 2 out of 3 new replicas have been updated... Waiting for deployment "myapp-deployment" rollout to finish: 1 old replicas are pending termination... Waiting for deployment "myapp-deployment" rollout to finish: 1 old replicas are pending termination... deployment "myapp-deployment" successfully rolled out
Notez qu'il y a maintenant une Révision supplémentaire :
root@kubemaster:~# kubectl rollout history deployment/myapp-deployment deployment.extensions/myapp-deployment REVISION CHANGE-CAUSE 1 kubectl create --filename=deployment-definition.yaml --record=true 2 kubectl apply --filename=deployment-definition.yaml --record=true
Consultez les détails du Deployment myapp-deployment :
root@kubemaster:~# kubectl describe deployment myapp-deployment Name: myapp-deployment Namespace: default CreationTimestamp: Sun, 24 Feb 2019 15:03:04 +0100 Labels: app=myapp type=front-end Annotations: deployment.kubernetes.io/revision: 2 kubectl.kubernetes.io/last-applied-configuration: {"apiVersion":"apps/v1","kind":"Deployment","metadata":{"annotations":{"kubernetes.io/change-cause":"kubectl apply --filename=deployment-d... kubernetes.io/change-cause: kubectl apply --filename=deployment-definition.yaml --record=true Selector: type=front-end Replicas: 3 desired | 3 updated | 3 total | 3 available | 0 unavailable StrategyType: RollingUpdate MinReadySeconds: 0 RollingUpdateStrategy: 25% max unavailable, 25% max surge Pod Template: Labels: app=myapp type=front-end Containers: nginx-container: Image: nginx:1.12 Port: <none> Host Port: <none> Environment: <none> Mounts: <none> Volumes: <none> Conditions: Type Status Reason ---- ------ ------ Available True MinimumReplicasAvailable Progressing True NewReplicaSetAvailable OldReplicaSets: <none> NewReplicaSet: myapp-deployment-5bb6c654c8 (3/3 replicas created) Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal ScalingReplicaSet 5m3s deployment-controller Scaled up replica set myapp-deployment-667d46455b to 3 Normal ScalingReplicaSet 2m52s deployment-controller Scaled up replica set myapp-deployment-5bb6c654c8 to 1 Normal ScalingReplicaSet 2m12s deployment-controller Scaled down replica set myapp-deployment-667d46455b to 2 Normal ScalingReplicaSet 2m12s deployment-controller Scaled up replica set myapp-deployment-5bb6c654c8 to 2 Normal ScalingReplicaSet 100s deployment-controller Scaled down replica set myapp-deployment-667d46455b to 1 Normal ScalingReplicaSet 100s deployment-controller Scaled up replica set myapp-deployment-5bb6c654c8 to 3 Normal ScalingReplicaSet 94s deployment-controller Scaled down replica set myapp-deployment-667d46455b to 0
Important : Notez que l'image utilisée est bien la nginx:1.12. Notez ensuite que dans la section Events, les PODs ont été Scaled down un-par-un et Scaled up un-par-un. Notez aussi que la valeur de StrategyType peut être soit Recreate soit RollingUpdate. Dernièrement, notez la valeur de RollingUpdateStrategy. 25% max unavailable indique qu'à un instant “t” 75% des PODs doivent être disponibles tandis que 25% max surge indique le nombre total des PODs ne peut pas dépasser 1,25 fois la valeur du champ Replicas.
Lors de la mise-à-jour le Deployment crée un autre ReplicaSet contenant les PODs mis-à-jour en suivant la méthode Rolling Update. Ceci peut être vu en regardant la sortie de la commande kubectl get replicasets :
root@kubemaster:~# kubectl get replicasets NAME DESIRED CURRENT READY AGE myapp-deployment-5bb6c654c8 3 3 3 3m34s myapp-deployment-667d46455b 0 0 0 5m45s
La modification de la version de l'image peut aussi être effectuée sur la ligne de commande :
root@kubemaster:~# kubectl set image deployment/myapp-deployment nginx-container=nginx:1.14 --record deployment.extensions/myapp-deployment image updated
Le nom du conteneur nginx-container est défini dans le fichier de définition du POD :
root@kubemaster:~# cat pod-definition.yaml apiVersion: v1 kind: Pod metadata: name: myapp-pod labels: app: myapp type: front-end spec: containers: - name: nginx-container image: nginx
Consultez le statut du Deployment :
root@kubemaster:~# kubectl rollout status deployment/myapp-deployment Waiting for deployment "myapp-deployment" rollout to finish: 2 out of 3 new replicas have been updated... Waiting for deployment "myapp-deployment" rollout to finish: 2 out of 3 new replicas have been updated... Waiting for deployment "myapp-deployment" rollout to finish: 2 out of 3 new replicas have been updated... Waiting for deployment "myapp-deployment" rollout to finish: 1 old replicas are pending termination... Waiting for deployment "myapp-deployment" rollout to finish: 1 old replicas are pending termination... deployment "myapp-deployment" successfully rolled out
Notez qu'il y a maintenant une Révision supplémentaire :
root@kubemaster:~# kubectl rollout history deployment/myapp-deployment deployment.extensions/myapp-deployment REVISION CHANGE-CAUSE 1 kubectl create --filename=deployment-definition.yaml --record=true 2 kubectl apply --filename=deployment-definition.yaml --record=true 3 kubectl set image deployment/myapp-deployment nginx-container=nginx:1.14 --record=true
Lors de la mise-à-jour le Deployment crée un autre ReplicaSet contenant les PODs mis-à-jour en suivant la méthode Rolling Update. Ceci peut être vu en regardant la sortie de la commande kubectl get replicasets :
root@kubemaster:~# kubectl get replicasets NAME DESIRED CURRENT READY AGE myapp-deployment-5bb6c654c8 0 0 0 6m8s myapp-deployment-5c4b64dd4 3 3 3 2m1s myapp-deployment-667d46455b 0 0 0 8m19s
Consultez les détails du Deployment myapp-deployment :
root@kubemaster:~# kubectl describe deployment myapp-deployment Name: myapp-deployment Namespace: default CreationTimestamp: Sun, 24 Feb 2019 15:03:04 +0100 Labels: app=myapp type=front-end Annotations: deployment.kubernetes.io/revision: 3 kubectl.kubernetes.io/last-applied-configuration: {"apiVersion":"apps/v1","kind":"Deployment","metadata":{"annotations":{"kubernetes.io/change-cause":"kubectl apply --filename=deployment-d... kubernetes.io/change-cause: kubectl set image deployment/myapp-deployment nginx-container=nginx:1.14 --record=true Selector: type=front-end Replicas: 3 desired | 3 updated | 3 total | 3 available | 0 unavailable StrategyType: RollingUpdate MinReadySeconds: 0 RollingUpdateStrategy: 25% max unavailable, 25% max surge Pod Template: Labels: app=myapp type=front-end Containers: nginx-container: Image: nginx:1.14 Port: <none> Host Port: <none> Environment: <none> Mounts: <none> Volumes: <none> Conditions: Type Status Reason ---- ------ ------ Available True MinimumReplicasAvailable Progressing True NewReplicaSetAvailable OldReplicaSets: <none> NewReplicaSet: myapp-deployment-5c4b64dd4 (3/3 replicas created) Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal ScalingReplicaSet 11m deployment-controller Scaled up replica set myapp-deployment-667d46455b to 3 Normal ScalingReplicaSet 9m12s deployment-controller Scaled up replica set myapp-deployment-5bb6c654c8 to 1 Normal ScalingReplicaSet 8m32s deployment-controller Scaled down replica set myapp-deployment-667d46455b to 2 Normal ScalingReplicaSet 8m32s deployment-controller Scaled up replica set myapp-deployment-5bb6c654c8 to 2 Normal ScalingReplicaSet 8m deployment-controller Scaled down replica set myapp-deployment-667d46455b to 1 Normal ScalingReplicaSet 8m deployment-controller Scaled up replica set myapp-deployment-5bb6c654c8 to 3 Normal ScalingReplicaSet 7m54s deployment-controller Scaled down replica set myapp-deployment-667d46455b to 0 Normal ScalingReplicaSet 5m5s deployment-controller Scaled up replica set myapp-deployment-5c4b64dd4 to 1 Normal ScalingReplicaSet 4m45s deployment-controller Scaled down replica set myapp-deployment-5bb6c654c8 to 2 Normal ScalingReplicaSet 4m20s (x4 over 4m45s) deployment-controller (combined from similar events): Scaled down replica set myapp-deployment-5bb6c654c8 to 0
Important : Notez que l'image utilisée est bien la nginx:1.14.
Rollbacks
Grâce au système des Révisions, il est possible de revenir en arrière vers la version précédente N-1 de l'application. Saisissez la commande suivante :
root@kubemaster:~# kubectl rollout undo deployment/myapp-deployment deployment.extensions/myapp-deployment rolled back
Saisissez la commande kubectl get replicasets :
root@kubemaster:~# kubectl get replicasets NAME DESIRED CURRENT READY AGE myapp-deployment-5bb6c654c8 3 3 3 11m myapp-deployment-5c4b64dd4 0 0 0 7m18s myapp-deployment-667d46455b 0 0 0 13m
Important : Notez que l'application est revenue à la version précédente.
Utilisez la commande kubectl rollout history :
root@kubemaster:~# kubectl rollout history deployment/myapp-deployment deployment.extensions/myapp-deployment REVISION CHANGE-CAUSE 1 kubectl create --filename=deployment-definition.yaml --record=true 3 kubectl set image deployment/myapp-deployment nginx-container=nginx:1.14 --record=true 4 kubectl apply --filename=deployment-definition.yaml --record=true
Important : Notez que Révision 2 est devenue la Révision 4 démontrant ainsi le Rollback.
Créez maintenant une erreur d'un Rollout :
root@kubemaster:~# kubectl set image deployment/myapp-deployment nginx-container=nginx1.14 --record deployment.extensions/myapp-deployment image updated
Important : Notez que l'erreur est nginx1.14 qui devrait être nginx:1.14.
Constatez le statut du Deployment :
root@kubemaster:~# kubectl rollout status deployment/myapp-deployment Waiting for deployment "myapp-deployment" rollout to finish: 1 out of 3 new replicas have been updated...
Important : Notez que le Rollout est bloqué. L'erreur error: deployment “myapp-deployment” exceeded its progress deadline va être retournée au bout d'une dixaine de minutes !
Pour visualiser ce qui se passe, utilisez la commande kubectl get deployments :
^Croot@kubemaster:~# kubectl get deployments NAME READY UP-TO-DATE AVAILABLE AGE myapp-deployment 3/3 1 3 24m
La commande kubectl get pods démontre un statut de ImagePullBackOff pour le premier POD dans le nouveau ReplicaSet qui indique que Kubernetes ne peut pas effectuer le pull de l'image à partir de Docker Hub :
root@kubemaster:~# kubectl get pods NAME READY STATUS RESTARTS AGE myapp-deployment-5bb6c654c8-q6mk9 1/1 Running 0 17m myapp-deployment-5bb6c654c8-qq5pj 1/1 Running 0 17m myapp-deployment-5bb6c654c8-zz579 1/1 Running 0 17m myapp-deployment-7fb978884b-7mgnn 0/1 ImagePullBackOff 0 12m
En consultant l'historique du Rollout, une Révision supplémentaire a été ajoutée suite à la commande en erreur :
root@kubemaster:~# kubectl rollout history deployment/myapp-deployment deployment.extensions/myapp-deployment REVISION CHANGE-CAUSE 1 kubectl create --filename=deployment-definition.yaml --record=true 3 kubectl set image deployment/myapp-deployment nginx-container=nginx:1.14 --record=true 4 kubectl apply --filename=deployment-definition.yaml --record=true 5 kubectl set image deployment/myapp-deployment nginx-container=nginx1.14 --record=true
Pour rectifier cette erreur il convient de faire un Rollback :
root@kubemaster:~# kubectl rollout undo deployment/myapp-deployment deployment.extensions/myapp-deployment rolled back
Constatez ensuite la réussite de la commande :
root@kubemaster:~# kubectl get pods NAME READY STATUS RESTARTS AGE myapp-deployment-5bb6c654c8-q6mk9 1/1 Running 0 24m myapp-deployment-5bb6c654c8-qq5pj 1/1 Running 0 24m myapp-deployment-5bb6c654c8-zz579 1/1 Running 0 24m root@kubemaster:~# kubectl rollout history deployment/myapp-deployment deployment.extensions/myapp-deployment REVISION CHANGE-CAUSE 1 kubectl create --filename=deployment-definition.yaml --record=true 3 kubectl set image deployment/myapp-deployment nginx-container=nginx:1.14 --record=true 5 kubectl set image deployment/myapp-deployment nginx-container=nginx1.14 --record=true 6 kubectl apply --filename=deployment-definition.yaml --record=true
A Faire : Prenez une instantanée de vos trois machines virtuelles.
LAB #13 - Gestion du Réseau et des Services
Kubernetes impose des conditions pour l'implmentation d'un réseau :
- Les PODs sur un noeud peuven communiquer avec tous les PODs sur tous le noeuds sans utiliset NAT,
- Les agents sur un noeud (par exemple kubelet) peuvent communiquer avec tous les PODs sur le noeud.
Important : La description technique et détaillée de l'approche réseau de Kubernetes peut être consultée à l'adresse : https://kubernetes.io/docs/concepts/cluster-administration/networking/.
Dans le cluster de ce cours, le réseau mis en place pour Kubernetes est le 192.168.56.0/24 :
root@kubemaster:~# ifconfig enp0s8 enp0s8 Link encap:Ethernet HWaddr 08:00:27:85:a2:9d inet addr:192.168.56.2 Bcast:192.168.56.255 Mask:255.255.255.0 inet6 addr: fe80::144f:5340:f32:34f8/64 Scope:Link UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:533192 errors:0 dropped:0 overruns:0 frame:0 TX packets:773213 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:49793997 (49.7 MB) TX bytes:821628826 (821.6 MB)
root@kubenode1:~# ifconfig enp0s8 enp0s8 Link encap:Ethernet HWaddr 08:00:27:73:26:89 inet addr:192.168.56.3 Bcast:192.168.56.255 Mask:255.255.255.0 inet6 addr: fe80::3fe7:3080:6d6a:171b/64 Scope:Link UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:391942 errors:0 dropped:0 overruns:0 frame:0 TX packets:273657 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:291617590 (291.6 MB) TX bytes:25364500 (25.3 MB)
root@kubenode2:~# ifconfig enp0s8 enp0s8 Link encap:Ethernet HWaddr 08:00:27:85:f3:3c inet addr:192.168.56.4 Bcast:192.168.56.255 Mask:255.255.255.0 inet6 addr: fe80::779b:ad9f:2e18:9ec2/64 Scope:Link UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:193701 errors:0 dropped:0 overruns:0 frame:0 TX packets:130808 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:146512826 (146.5 MB) TX bytes:12439676 (12.4 MB)
Actuellement il y a 3 PODs dans le cluster :
root@kubemaster:~# kubectl get pods NAME READY STATUS RESTARTS AGE myapp-deployment-5bb6c654c8-q6mk9 1/1 Running 0 17h myapp-deployment-5bb6c654c8-qq5pj 1/1 Running 0 17h myapp-deployment-5bb6c654c8-zz579 1/1 Running 0 17h
En sachant que le réseau par défaut de Docker est bridge, constatons que les conteneurs dans ces PODs ne sont pas dans ce réseau :
root@kubemaster:~# docker network inspect bridge [ { "Name": "bridge", "Id": "3dba8dc1f10d2902e5ec5c4130082950ccbdb9c9efc3b64b78edd57d5914bbf7", "Created": "2019-02-21T12:04:40.654203509+01:00", "Scope": "local", "Driver": "bridge", "EnableIPv6": false, "IPAM": { "Driver": "default", "Options": null, "Config": [ { "Subnet": "172.17.0.0/16", "Gateway": "172.17.0.1" } ] }, "Internal": false, "Attachable": false, "Ingress": false, "ConfigFrom": { "Network": "" }, "ConfigOnly": false, "Containers": {}, "Options": { "com.docker.network.bridge.default_bridge": "true", "com.docker.network.bridge.enable_icc": "true", "com.docker.network.bridge.enable_ip_masquerade": "true", "com.docker.network.bridge.host_binding_ipv4": "0.0.0.0", "com.docker.network.bridge.name": "docker0", "com.docker.network.driver.mtu": "1500" }, "Labels": {} } ]
Important : Notez que cette sortie démontre que la section “Containers”: {}, est vide.
En effet sous Kubernetes, les adresses IP ne sont pas attachées aux conteneurs mais aux PODs :
root@kubemaster:~# kubectl get pods -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES myapp-deployment-5bb6c654c8-q6mk9 1/1 Running 0 40m 192.168.1.30 kubenode1 <none> <none> myapp-deployment-5bb6c654c8-qq5pj 1/1 Running 0 40m 192.168.1.31 kubenode1 <none> <none> myapp-deployment-5bb6c654c8-zz579 1/1 Running 0 40m 192.168.2.31 kubenode2 <none> <none>
Important : Notez que les adresses 192.168.1.x sont associées aux PODs sur kubenode1 tandis que les adresses 192.168.2.x sont associées aux PODs sur kubenode2. Ces adresses sont issues du réseau 192.168.0.0/16 stipulé par l'option –pod-network-cidr lors de l'initialisation du maître du cluster.
En sachant que dans chaque POD existe un conteneur Nginx, testez si vous pouvez afficher la page d'accueil de Nginx en vous connectant à kubenode1 et kubenode2 à partir de votre machine hôte soit avec un navigateur soit en ligne de commande :
trainee@kubernetes:~$ curl 192.168.56.3 curl: (7) Failed to connect to 192.168.56.3 port 80: Connexion refusée trainee@kubernetes:~$ curl 192.168.56.4 curl: (7) Failed to connect to 192.168.56.4 port 80: Connexion refusée
Important : Notez l'échec de la connexion.
Testez maintenant si vous pouvez afficher la page d'accueil de Nginx en vous connectant à un des PODs à partir de votre machine hôte soit avec un navigateur soit en ligne de commande :
trainee@kubernetes:~$ curl 192.168.1.30 curl: (7) Failed to connect to 192.168.1.30 port 80: Aucun chemin d'accès pour atteindre l'hôte cible
Bien évidement, il est possible d'afficher la page en vous connectant à un des PODs de l'intérieur du cluster :
trainee@kubernetes:~$ ssh 192.168.56.2 The authenticity of host '192.168.56.2 (192.168.56.2)' can't be established. ECDSA key fingerprint is SHA256:pBg4jSkCMVZguOzmJjsqUjKfusz757jTqrvbDpISIXg. Are you sure you want to continue connecting (yes/no)? yes Warning: Permanently added '192.168.56.2' (ECDSA) to the list of known hosts. trainee@192.168.56.2's password: Welcome to Ubuntu 16.04.5 LTS (GNU/Linux 4.4.0-142-generic x86_64) * Documentation: https://help.ubuntu.com * Management: https://landscape.canonical.com * Support: https://ubuntu.com/advantage 33 packages can be updated. 0 updates are security updates. Last login: Sun Feb 24 14:56:54 2019 from 10.0.2.2 trainee@kubemaster:~$ curl 192.168.1.30 <!DOCTYPE html> <html> <head> <title>Welcome to nginx!</title> <style> body { width: 35em; margin: 0 auto; font-family: Tahoma, Verdana, Arial, sans-serif; } </style> </head> <body> <h1>Welcome to nginx!</h1> <p>If you see this page, the nginx web server is successfully installed and working. Further configuration is required.</p> <p>For online documentation and support please refer to <a href="http://nginx.org/">nginx.org</a>.<br/> Commercial support is available at <a href="http://nginx.com/">nginx.com</a>.</p> <p><em>Thank you for using nginx.</em></p> </body> </html>
Important : Retenez donc qu'à ce stade il n'est pas possible d'afficher la page d'accueil de Nginx en vous connectant de l'extérieur du cluster.
Lors de l'installation du cluster nous avons spécifié l'utilisation d'une extension réseau appelée Calico, issue de la liste suivante :
- Canal (utilise Flannel pour le réseau et Calico pour le pare-feu).
Important : Une étude comparitive des extensions réseau pour Kubernetes peut être trouvée à la page : https://itnext.io/benchmark-results-of-kubernetes-network-plugins-cni-over-10gbit-s-network-36475925a560.
Ces extensions permettent la mise en place de Services :
- NodePort,
- Ce Service rend un POD accessible sur un port du Noeud le contenant,
- ClusterIP
- Ce Service crée une adresse IP virtuelle afin de permettre la communication entre de services différents dansle cluster, par exemple des serveurs front-end avec des serveurs back-end,
- LoadBalancer
- Ce service provisionne un equilibrage de charge pour l'application dans certains fournisseurs Cloud.
Le Service NodePort
Le Service NodePort définit trois ports :
- TargetPort : le port sur le POD,
- Port : le port sur le Service lié à un IP du Cluster,
- NodePort : le port sur le Noeud issu de la plage 30000-32767.
Si dans le même noeud, plusieurs PODs ont les étiquettes qui correspondent au selector du Service, le Service identifie les PODs et s'étend automatiquement pour englober tous les PODs. Les PODs sont appelés des End-Points :
Important : Notez que dans ce cas l'équilibrage de charge est automatique est utilise l'algorythme Random avec une affinity de session..
De même, quand les PODs sont distribués sur plusieurs noeuds, le Service s'étend pour tout englober :
Créez donc le fichier YAML service-definition.yaml :
root@kubemaster:~# vi service-definition.yaml root@kubemaster:~# cat service-definition.yaml apiVersion: v1 kind: Service metadata: name: myapp-service spec: type: NodePort ports: - targetPort: 80 port: 80 nodePort: 30008 selector: app: myapp type: front-end
Important : Notez que la valeur par défaut du champ type est ClusterIP. Notez aussi que dans ports, seul le champ port est obligatoire. Si le champ targetPort est manquant, sa valeur par défaut est celle du champ port. Si le champ nodePort est manquant, sa valeur par défaut est le premier port disponible dans la plage 30 000 et 32 767. Dernièrement, il est possble de spécifier de multiples définitions de ports dans le service.
Le champs selector contient les étiquettes des PODs concernés par la mise en place du Service :
root@kubemaster:~# cat pod-definition.yaml apiVersion: v1 kind: Pod metadata: name: myapp-pod labels: app: myapp type: front-end spec: containers: - name: nginx-container image: nginx
Créez le Service en utilisant le fichier service-definition.yaml :
root@kubemaster:~# kubectl create -f service-definition.yaml service/myapp-service created
Constatez la création du Service :
root@kubemaster:~# kubectl get services NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 2d9h myapp-service NodePort 10.109.119.46 <none> 80:30008/TCP 57s
Important : Notez que le Service a une adresse IP du cluster et qu'il a exposé le port 30 008.
Testez maintenant si vous pouvez afficher la page d'accueil de Nginx en vous connectant à un des PODs à partir de votre machine hôte en utilisant le port exposé soit avec un navigateur soit en ligne de commande :
trainee@kubernetes:~$ curl 192.168.56.3:30008 <!DOCTYPE html> <html> <head> <title>Welcome to nginx!</title> <style> body { width: 35em; margin: 0 auto; font-family: Tahoma, Verdana, Arial, sans-serif; } </style> </head> <body> <h1>Welcome to nginx!</h1> <p>If you see this page, the nginx web server is successfully installed and working. Further configuration is required.</p> <p>For online documentation and support please refer to <a href="http://nginx.org/">nginx.org</a>.<br/> Commercial support is available at <a href="http://nginx.com/">nginx.com</a>.</p> <p><em>Thank you for using nginx.</em></p> </body> </html> trainee@kubernetes:~$ curl 192.168.56.4:30008 <!DOCTYPE html> <html> <head> <title>Welcome to nginx!</title> <style> body { width: 35em; margin: 0 auto; font-family: Tahoma, Verdana, Arial, sans-serif; } </style> </head> <body> <h1>Welcome to nginx!</h1> <p>If you see this page, the nginx web server is successfully installed and working. Further configuration is required.</p> <p>For online documentation and support please refer to <a href="http://nginx.org/">nginx.org</a>.<br/> Commercial support is available at <a href="http://nginx.com/">nginx.com</a>.</p> <p><em>Thank you for using nginx.</em></p> </body> </html>
Le Service ClusterIP
Le Service ClusterIP permet de regrouper les PODs offrant le même service afin de faciliter la communication, par exemple :
- 3 PODs front-end = une adresse ClusterIP,
- 3 PODs back-end = une autre adresse ClusterIP.
Pour créer un Service ClusterIP, créez le fichier clusterip-definition.yaml :
root@kubemaster:~# vi clusterip-definition.yaml root@kubemaster:~# cat clusterip-definition.yaml apiVersion: v1 kind: Service metadata: name: back-end spec: type: ClusterIP ports: - targetPort: 80 port: 80 selector: app: myapp type: front-end
Créez le Service en utilisant le fichier clusterip-definition.yaml :
root@kubemaster:~# kubectl create -f clusterip-definition.yaml service/back-end created
Vérifiez maintenant la présence du Service :
root@kubemaster:~# kubectl get services NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE back-end ClusterIP 10.96.138.47 <none> 80/TCP 31s kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 2d10h myapp-service NodePort 10.109.119.46 <none> 80:30008/TCP 29m