vendredi 26 mars 2021

Kubernetes: Tips for CKAD exam by CNCF

 

Après avoir suivi quelques formations et de pratique de Kubernetes dans le cadre de mon travail, j’ai décidé de passer le certification CKAD de la CNCF afin de valider mes compétences.





Avant d’utiliser Vim, il faut le paramétrer afin d'éditer au mieux les fichiers YAML.

On édite le fichier  .vimrc :

vi ~/.vimrc :


Vous pouvez créer de déploiement depuis le manifest d'un pod. Il suffit de copier depuis la partie metatdata du pod et copier dans : deploy.spec.template.metadata

Dans cet exemple, il suffit de tapper : début de ligne du pod, fin de ligne du pod s, /^/ le nombre d'espaces pour le bon formatage : 17,53s/^/     /



Vous pouvez suivre la formation Udemy qui m'a été très utile pour mes préparatifs :

https://www.udemy.com/course/certified-kubernetes-application-developer/

Pour vous entrainer :

  •  https://killer.sh/
  • https://medium.com/bb-tutorials-and-thoughts/practice-enough-with-these-questions-for-the-ckad-exam-2f42d1228552
  • https://github.com/bmuschko/ckad-crash-course/tree/master/exercises
  • https://github.com/dgkanatsios/CKAD-exercises

Quelques commandes très utiles :

  • kubectl explain
  • kubectl api-resources

Mes liens favoris : Vous pouvez créer de bookmark  et installer ce plugin chrome permettant d'effectuer de recherches dans vos bookmarks (en tapant bm puis entrer dans la barre de recherche)  :

https://chrome.google.com/webstore/detail/bookmark-search/hhmokalkpaiacdofbcddkogifepbaijk

Les URLs :

A lire absolument si vous voulez comprendre en profondeur ! : Kubernetes in Action écrit par Marko Luksa aux éditions Manning.

https://kubernetes.io/docs/tasks/configure-pod-container/assign-pods-nodes-using-node-affinity/

https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/#define-a-liveness-command

https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-pod

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

https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/#concepts

https://kubernetes.io/docs/tasks/configure-pod-container/configure-pod-configmap/#define-a-container-environment-variable-with-data-from-a-single-configmap

https://kubernetes.io/docs/concepts/configuration/secret/#using-secrets-as-environment-variables

https://kubernetes.io/docs/tasks/configure-pod-container/configure-persistent-volume-storage/#create-a-persistentvolume

https://kubernetes.io/docs/concepts/storage/volumes/#types-of-volumes

https://kubernetes.io/docs/concepts/workloads/controllers/deployment/#creating-a-deployment

https://kubernetes.io/docs/concepts/workloads/controllers/job/#running-an-example-job

https://kubernetes.io/docs/concepts/workloads/controllers/cron-jobs/#example

https://kubernetes.io/docs/concepts/services-networking/service/#nodeport

https://kubernetes.io/docs/concepts/services-networking/network-policies/#networkpolicy-resource

https://kubernetes.io/docs/concepts/services-networking/ingress/

https://kubernetes.io/fr/docs/reference/kubectl/cheatsheet/

https://kubernetes.io/docs/reference/generated/kubectl/kubectl-commands

https://kubernetes.io/docs/concepts/services-networking/service/

https://kubernetes.io/docs/concepts/storage/storage-classes/

https://kubernetes.io/docs/concepts/storage/persistent-volumes/

https://kubernetes.io/docs/concepts/storage/persistent-volumes/#persistentvolumeclaims

https://kubernetes.io/docs/tasks/configure-pod-container/assign-cpu-resource/

https://kubernetes.io/docs/tasks/configure-pod-container/assign-memory-resource/

https://kubernetes.io/docs/tasks/administer-cluster/encrypt-data/

https://kubernetes.io/fr/docs/tasks/access-application-cluster/list-all-running-container-images/

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

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

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

https://kubernetes.io/docs/tasks/administer-cluster/manage-resources/memory-default-namespace/

https://kubernetes.io/docs/tasks/administer-cluster/manage-resources/cpu-default-namespace/

https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/

https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/

https://kubernetes.io/docs/concepts/services-networking/network-policies/

https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/

https://kubernetes.io/docs/tasks/access-application-cluster/communicate-containers-same-pod-shared-volume/

https://kubernetes.io/docs/reference/generated/kubectl/kubectl-commands#scale

https://kubernetes.io/docs/reference/generated/kubectl/kubectl-commands#rollout

https://kubernetes.io/docs/reference/generated/kubectl/kubectl-commands#exec

https://kubernetes.io/docs/concepts/workloads/pods/

https://kubernetes.io/fr/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/

https://kubernetes.io/docs/tasks/job/coarse-parallel-processing-work-queue/

https://kubernetes.io/docs/concepts/workloads/controllers/job/

https://kubernetes.io/docs/tasks/job/automated-tasks-with-cron-jobs/

https://kubernetes.io/fr/docs/tasks/configure-pod-container/assign-pods-nodes/

https://kubernetes.io/fr/docs/concepts/storage/volumes/

https://kubernetes.io/docs/reference/generated/kubectl/kubectl-commands#-em-configmap-em-

https://kubernetes.io/docs/tutorials/configuration/configure-redis-using-configmap/

https://kubernetes.io/docs/tutorials/stateful-application/mysql-wordpress-persistent-volume/

https://kubernetes.io/docs/tutorials/stateful-application/cassandra/

https://kubernetes.io/docs/tasks/tools/install-kubectl-linux/

https://kodekloud.com/courses/kubernetes-certification-course-labs/lectures/12039471

https://github.com/kubernetes/website/blob/master/content/en/examples/windows/emptydir-pod.yaml

https://kubernetes.io/blog/2016/07/autoscaling-in-kubernetes/

https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.20/

https://kubernetes.io/docs/concepts/workloads/pods/init-containers/

https://github.com/kubernetes/website/blob/master/content/en/examples/application/wordpress/wordpress-deployment.yaml

https://github.com/kubernetes/website/tree/master/content/en/examples/pods

https://github.com/kubernetes/website/blob/master/content/en/examples/application/job/rabbitmq/job.yaml

https://kubernetes.io/docs/concepts/cluster-administration/logging/

https://kubernetes.io/docs/tasks/manage-kubernetes-objects/update-api-object-kubectl-patch/

https://kubernetes.io/docs/tutorials/services/source-ip/

https://kubernetes.io/docs/tutorials/stateless-application/guestbook/

https://github.com/kubernetes/website/blob/master/content/en/examples/service/networking/nginx-secure-app.yaml

https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/

https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.20/#job-v1-batch

https://kubernetes.io/docs/concepts/storage/volumes/

vendredi 31 mai 2019

Scala implicit

Notion implicit en scala

La notion implicit de scala permet de faire : 
  • de passer automatiquement de paramètre à une méthode/fonction
  • de la conversion automatique;
  • d'ajouter de comportement dynamiquement à une classe.

Paramètre implicit


Un paramètre implicit injecté dynamiquement. La méthode sendMail dispose d'un paramètre from implicit. 


Lors qu’un paramètre d’une méthode/fonction est défini comme implicite, il n’est plus nécessaire de le spécifier lors de l’appel : le compilateur se charge de le déduire à partir du contexte.

À noter que, dans la signature d’une méthode, le mot clé implicit ne sert pas à déclarer un paramètre mais une liste de paramètres. Tous les paramètres implicites doivent être définis dans « la même paire de parenthèse ». Tous les paramètres suivant le mot clé seront donc des implicites  (dans l'exemple ci-dessus, body et from sont implicits)


On pourra bien appeler sendMail avec le paramètre from explicitement :



 ou déclarer  le paramètre from implicit de 3 manières : 

  • val 

  • def



  • object class si le paramètre est une structure complexe.


Il faudra noter :
  • la correspondance entre le paramètre implicite de la méthode sendMail et la variable est indépendante de leurs noms. Le compilateur utilise le type commun String pour lier from et sender,
  • deux variables implicites de même type dans la même portée provoquent une erreur de compilation, à la première utilisation. Dans notre exemple, on ne pourra pas avoir deux variables implicits de types String,
  • Pour pouvoir appeler la méthode sans le paramètre implicit depuis un autre fichier, il faudra faire import de l'object dans lequel le paramètre implicit est défini.

Conversion automatique


Cela consiste à définir une méthode de conversion implicit d'un type A à un type B. Le compilateur se charge d'appeler et effectuer automatiquement la conversion si nécessaire. Imaginons qu'on dispose d'une méthode show prenant en paramètre un type String :


Pour pouvoir appeler cette méthode avec les paramètres : Int, Double ou Float ou tout autre type, il faudra définir de méthodes implicit permettant de convertir Int en String, Double en String et Float en String :



Ajout d'un comportement dynamiquement à une classe


C'est une fonctionnalité proche de l'extension C#. Elle permet d'ajouter dynamiquement une nouvelle méthode à une classe existante. Prenons l'exemple du type String. On voulait ajouter une nouvelle méthode isPalindrome permettant de savoir si un String est un palindrome ou une autre méthode isQuestion pour savoir si une chaine de caractère est une question. Cela revient à faire :



Il suffit de définir une classe implicit avec un constructeur prenant en paramètre un String et définir les deux méthodes isPalindrome, isQuestion dans cette classe.


Une fois cette classe définie, il suffit de faire un import de RicheType pour pouvoir appeler les méthodes isPalindrome, isQuestion sur le type String


On pourra effectuer la même chose pour d'autres types notamment de type custom Person ...







mercredi 29 mai 2019

Scala : Structural types, rename import, type alias

Renommer import

On dispose d'import static en Java. Scala nous offre la possibilité de renommer les classes ainsi que les méthodes statiques importées. Un exemple vaut mieux qu'un long discours ...

Renommer une classe importée




Renommer une méthode statique importée

Type alias

Un type alias permet de renommer un type existant permettant ainsi d'éviter les ambiguïtés ...Dans cet exemple, on dispose d'une classe CommandLine qu'on pourrait définir ainsi :



Grâce aux alias, on peut avoir un code plus clair et parlant !!


Ici, on a renommé les types Int et Flot en Quantity et Price mieux parlant ...

Structural Types

L'idée de Structural Types est de pouvoir exprimer un type non pas en le déclarant comme une interface, une classe ou un Trait, mais plutôt en affirmant que le type doit posséder un comportement particulier (une méthode, fonction ...). Structural Type nous rappelle de duck typing utilisé dans plusieurs langages de programmation, tels que  Ruby. Le principe de duck typing est simple :
If it walks like a duck and quacks like a duck, it must be a duck (si ça marche comme un canard et si ça cancane comme un canard, alors ça doit être un canard)

Du coup, connaître le type même d'une valeur n'a aucune importance, il faut avant tout s'assurer qu'on peut lui appliquer les traitements souhaités.

Dans cet exemple, on définit une méthode doTalk qui prend en paramètre tout type ayant une méthode talk définie qu'il y ait ou non une relation d'héritage ou une interface commune entre les types. Cette méthode talk doit être sans paramètre et retourner un type String



Les deux classes Cat et Dog ont la méthode talk définie et peuvent donc être passées comme paramètre à la méthode doTalk. Par contre la classe Fake n'ayant pas la méthode talk définie
ne peut être passée à la méthode doTalk.



Il est également possible de définir un type alias et faire référence à cet alias comme paramètre de la méthode doTalk comme dans l'exemple ci-dessus :


   

lundi 27 mai 2019

Scala : Object-private and Package scope

Object-private scope : private[this]


En Scala comme en Java, l'accessibilité private donne le droit d'accès à un attribut privé d'une autre instance au sein de la même classe. Clarifions par un exemple... Dans l'exemple ci-dessus, la méthode m peut bien accéder à l'attribut value de l'objet Counter malgré que cet attribut soit déclaré privé. Ce comportement est normal car on est toujours au sein de la classe Counter


Comment peut-on empêcher qu'un attribut privé ne soit accessible que par  l'instance courante de l'objet ? Cela revient à générer une erreur de compilation à la ligne 12  other.value 

Scala nous offre une restriction supplémentaire qu'on appelle object-private scope. Il suffit de déclarer l'attribut comme private[this]. Le mot clé this indique que l'attribut n'est accessible que par l'instance courante. On remarque une erreur de compilation lorsque l'attribut value est déclaré  private[this]



Package scope

L'accessibilité private[nomPackage] donne le droit d'accès à une méthode ou un attribut depuis le package nomPackage et ses sous packages. Dans l'exemple ci-dessus, la méthode doX est déclarée comme private[scala] et donc accessible depuis le package scala contrairement à la méthode privée doY accessible uniquement au sein de la classe Foo



Dans le package other, ni doX ni doY n'est accessible depuis la classe Quux


case class vs case object



Case class


Une case classe est définie avec le mot clé case


Elle peut être instanciée sans le mot clé new. Cela est possible car scala génère automatiquement une classe qu’on appelle object companion ayant le même nom (Person) contenant deux méthodes :
§  apply : qui construit un objet via les paramètres de construction et
§  unapply : qui de-construit l’objet qu’on appelle également extracteur (extraction des attributs via l’objet)

Lors de l’appelle d’instanciation de Person(…) ; on fait appel à la méthode Person.apply.

Les cases classes sont serializables par défaut avec les méthodes toString, copy, equals (sur les attributs), hashCode implémentées …




Par défaut les attributs sont immutables (val) et publiques. Il est possible d’avoir des attributs mutables avec le mot clé var ou réduire la visibilité ..


Case object


Les cases objects sont équivalentes de cases classes n’ayant pas d’attributs de construction ; elles sont singletons et serializables avec une implémentation hashCode (à la différence des objects companions). Une case object permet par exemple de créer des enums, des messages Akka …










lundi 14 septembre 2015

Functional Programming : monoïde , functor, monad

 Monoïdes :

Un monoïde est un ensemble E doté d'une fonction * et d'un élément neutre e tel que :

-          (x,y) (E, E) ,  x*y  E (stabilité, magma) : respecte la lois de composition interne
-          (x,y,z)  (E, E, E), x*(y*z) = (x*y)*z (associativité)
-          Unifère (E a un élément neutre pour l’opération *) : c’est-à-dire il existe e qui appartient à E, et pour tout x qui appartient à E, x*e=e*x=x (existence d'un élément neutre)

Il existe plusieurs exemples de monoïdes :

-          L’ensemble de nombres entiers (N) muni de l’opération (+) avec 0 comme élément neutre (soit x, y, z des entiers) :  x + y est un entier ; x + 0 = 0 + x = x ; x + (y + z) = (x+y) + z
-          L’ensemble de nombre réel muni de l’opération de multiplication (*) et 1 comme élément neutre (soit x, y, z des réels) :  x*y reste un réel ; x*1 = 1*x = x ; x* (y*z) = (x*y) * z

Il existe aussi des contres exemples :

-          L’ensemble de nombre entiers négatifs (N-) muni de l’opération de multiplication (*) n’est pas monoïdes car N- n’est pas un magma. En effet si nous prenons deux éléments appartenant à (N-) par exemple -2 et -1, la multiplication -2*-1 = 2 n’appartient pas à (N-)
-          L’ensemble de nombre paire (2N) muni de l’opération de multiplication n’est également pas un monoïde car l’élément neutre pour la multiplication est 1, or 1 n’appartient pas à (2N) autrement dit (2N) n’est pas unifère ((2N, *) n’a pas d’élément neutre)

Pour un informaticien, un type T est un monoïde s’il existe une opération (T, T) => T et un élément neutre pour cette opération. Par exemple les entiers naturels avec l’addition et 0, les chaines de caractères avec la concaténation et "".  Un monoïde est donc simplement une structure de donnée ayant :
  •          Un ensemble d’objet de type T: exemple les nombres, les listes, …
  •           Une fonction binaire F qui prend en paramètre deux objets (t1, t2)  de type T et retourne un résultat également de type T : F (t1, t2) est de type T : def F(a: T, b: T): T et  (a F b) F c == a F (b F c)
  •           Un élément neutre e de type T : si t est de type T, F(t, e) = F (e, t) = t 
Exemple : Les Integer avec la fonction + et e = 0, ou avec la fonction * (multiplication) et e (élément neutre) = 1, ou Les list<T> avec la fonction concat et e = Nil (List(), liste vide), ou les ensembles (Set), avec la fonction Union et e = Set() (ensemble vide).

Functor

Un terme incompréhensible…pour simplifier la définition, disons que c’est une structure de donnée typée T (Integer, List<T>, Set<T>…) munie :

-          d’un constructeur : of = e :T => F[T]. Le constructeur nous donne ce qu’on appelle : élément boxé, encapsulé, contextualisé …
-          d’une fonction appelée bind avec comme signature (Figure 1)

-          d’un élément boxé (encapsulé) neutre (E) pour toute fonction f. Autrement dit, l’application de la fonction f par la fonction bind n’aura aucun effet sur l’élément neutre boxé E.

Figure 1 : Signature de la méthode bind

Des exemples pour clarifier mes propos :

Listes muni de la fonction bind = map (de java  8 ou scala) avec of = constructeur de List et la liste vide (E = List()) comme élément boxé neutre. La fonction map est très fréquente lorsque le programme consiste à parcourir une liste et appliquer une fonction à chacun de ses éléments.
La fonction map prend une fonction en paramètre et l’applique aux éléments de la liste et retourne la liste résultante :

Soit f = (x : Integer => 2*x),
-          List(1,2,3).map (f) = Lis(2*1, 2*2, 2*3) = List(2,4,6)
-          List().map (f) = Lis()

Option ou Maybe : élément boxé neutre = None, bind (None, f) = None et bind (Option(x), f) = Option(f)

Monades :

Une monade est avant tout une structure de donnée (comme List, Set, Integer, etc.) permettant d’encapsuler une valeur. Elle peut être vue comme une boite, vide ou ayant un contenu, qui nous fournit des abstractions et des opérations au-dessus de la valeur éventuellement encapsulée. 
Il existe différents types de boites correspondant à différents types de structures. Prenons un exemple pour le type Option de scala ou Maybe de Haskell. Une option de scala permet d’exprimer le fait que l’objet qu’on manipule contient peut être une valeur, mais peut-être pas. Dans ce cas, la boîte nous permet de manipuler cet objet potentiel sans s’inquiéter de la présence ou non d’une valeur. Une monade M est munie :

-          Constructeur de Monade : Une fonction notée of permettant d’encapsuler et de construire une valeur d’un type T donné. Cette encapsulation du type T est également appelée Boxée T et notée M[T]. Un exemple vaut mieux qu’un long discours : si T = Integer, of(Integer) peut être List<Integer>. Il suffit de définir une fonction pour ces objets Monades (List<Integer>) qui détermine comment appliquer une fonction à ces objets monades.

-          Une fonction notée apply qui définit comment on applique les fonctions (du type f : A => M[B]) aux objets Boxés M[A]. La fonction f retourne un élément Boxé. La signature de la fonction apply  (X : M[A], f : A => M[B]) => MA[B], elle applique la fonction f à un élément Boxé de type A et retourne un élément Boxé. Le paramètre du type A n’est pas nécessairement Boxé par contre son paramètre de retour est Boxé.
-          d’un élément boxé neutre (E) pour toute fonction f. Autrement dit, l’application de la fonction f par la fonction apply n’aura aucun effet sur l’élément neutre boxé E.

Un exemple vaut toujours mieux qu’une définition théorique :

Liste munie de la fonction apply = flatMap de scala et élément neutre E = liste vide = List() :

 La fonction flatMap s’applique à une liste. Elle applique une fonction g aux éléments de la liste. Cette fonction g a pour paramètre de retour une liste. Du coup, lorsqu'elle est appliquée à un élément de la liste, elle retourne une liste. La fonction flatMap permet de concaténer ces listes (les listes retournées par la fonction g) pour en donner une seule et unique liste. Exemple en Scala : 


Un autre exemple pour finir :

Soit une fonction :

f : (i: Int) => List (i.toDouble / 4, i.toDouble / 2).

La fonction f retourne bien une liste (élément boxé). Par contre elle prend un entier (Int) en paramètre non boxé ! Trouvons la fonction apply permettant d’appliquer la fonction f à une List[Int] : il suffit d’appliquer la fonction f aux éléments de la liste. Par exemple pour une liste : List[Int] (1, 2) = List[Double](1.0/4, 1.0/2, 2.0/4, 2.0/2) = List[Double](0.25, 0.5, 0.5, 1.0)....