# Tout ensemble : une application ## Rappels K8s ### Vocabulaire - Node : Master ou Worker - Control plane : tous les master - Objets : pod / deployment / service / etc. - namespace Un objet est une spécification et un état; il appartient à un namespace (sauf exception). On fixe la spécification et kubernetes se débrouille pour que l'état corresponde à cette spécification. Les objets peuvent suivre des spécifications nouvelles (CRD : Custom Resource Definition ). Il faut imaginer alors k8s comme un espace de stockage de ces objets, et c'est à nous de faire une application qui les traite. Les "addons" de k8s s'appuient beaucoup sur ce mécanisme. ### Manipulation Au travers de l'API qui est exposée sur le port 6443 d'un master node. (Note : comme le port 6443 n'est pas ouvert, on fait un tunnel ssh entre localhost et un noeud master via `ssh -L 6443:127.0.0.1:6443 147.100.164.212` . Ceci expose le port 6443 de la machine sur laquelle on se connecte sur le port 6443 de localhost) On configure un fichier kubernetes.conf contenant l'adresse d'un master node + identifiants. ```yaml apiVersion: v1 clusters: - cluster: certificate-authority-data: ...... server: https://127.0.0.1:6443 name: cluster.local kind: Config preferences: {} users: - name: kubernetes-admin user: client-certificate-data: ..... client-key-data: LS....... ``` On peut alors accéder aux objets k8s : ```bash export KUBECONFIG=$(pwd)/kubernetes.conf kubectl get pods -o wide --all-namespaces ``` ## Exemple d'application ### Une application pour moi Une application c'est à la fois : - plusieurs programmes qui communiquent entre eux - un point d'entrée () - un certificat ssl - une base de données - ... C'est tout l'écosystème qui doit être déployé pour que ce soit en état de marche et qu'on puisse l'utiliser. ### Exemple Je suis développeur, j'écris une application pour laquelle, pour chaque nouvelle version, je crée un conteneur : - `registry.forgemia.inra.fr/sol_k8s/argocd_examples/hello_flask:0.1` - `registry.forgemia.inra.fr/sol_k8s/argocd_examples/hello_flask:0.2` - etc. Ce conteneur écoute sur le port 8000. Je le sais car je suis développeur et en plus je le documente dans le Dockerfile : ```Dockerfile FROM python:3 WORKDIR /app/ COPY . /app/ RUN pip install -r requirements.txt EXPOSE 8000 CMD ["flask","run","-h","0.0.0.0","-p","8000"] ``` Pour le déployer sur k8s il faut beaucoup d'objets : ```yaml --- # UN DEPLOIEMENT apiVersion: apps/v1 kind: Deployment metadata: name: app-hello-flask spec: replicas: 1 selector: matchLabels: app.kubernetes.io/name: hello-flask app.kubernetes.io/instance: app template: metadata: labels: app.kubernetes.io/name: hello-flask app.kubernetes.io/instance: app spec: containers: - name: hello-flask image: "registry.forgemia.inra.fr/sol_k8s/argocd_examples/hello_flask:0.1" imagePullPolicy: IfNotPresent ports: - name: http containerPort: 8000 protocol: TCP --- # UN SERVICE apiVersion: v1 kind: Service metadata: name: app-hello-flask spec: type: ClusterIP ports: - port: 8000 targetPort: http protocol: TCP name: http selector: app.kubernetes.io/name: hello-flask app.kubernetes.io/instance: app --- # UN INGRESS apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: app-hello-flask spec: rules: - host: "test.amoi" http: paths: - path: / pathType: ImplementationSpecific backend: service: name: app-hello-flask port: number: 8000 ``` Pour essayer, créez un fichier yaml pour chaque objet : deployment.yaml, service.yaml, ingress.yaml. Créez l'objet deployment : ```bash kubectl apply -f deployment.yaml ``` Observez la création du pod. De la même manière créez les autres objets : ```bash kubectl apply -f service.yaml kubectl apply -f ingress.yaml ``` Et kubernetes fait le reste : il crée d'autres objets si nécessaire (par exemple pour les certificats) et fait *converger* les états. Après avoir modifié le fichier /etc/hosts, vous pourrez accéder à l'application en allant sur http://test.amoi. Pour mettre à jour mon application, il suffira de modifier l'image pointée par ce fichier. *Remarque* : ce serait sympa d'avoir un template et de séparer les données utiles du reste.. ### Helm Helm permet justement d'avoir un template et de séparer les données utiles du reste : ```bash helm create hello-flask. ``` Cela génère une arborescence avec à la racine un fichier values.yaml et dans le reste de l'arborescence, des templates contenant le yaml de description d'objets k8s. Dans les values on a l'essentiel : ```yaml replicaCount: 1 image: repository: registry.forgemia.inra.fr/sol_k8s/argocd_examples/hello_flask pullPolicy: IfNotPresent tag: 0.1 service: type: ClusterIP port: 8000 ingress: enabled: true className: "" annotations: kubernetes.io/ingress.class: nginx cert-manager.io/cluster-issuer: letsencrypt-clusterissuer hosts: - host: hello.inrae.jrobert-orleans.fr paths: - path: / pathType: ImplementationSpecific tls: - secretName: hello-flask-ssl hosts: - hello.inrae.jrobert-orleans.fr ``` Et si je veux voir le résultat de ce 'helm chart' : ```bash helm template . ``` ## Argocd Et si on versionne ce "helm chart" dans un dépot git, on a une application toute prète à être déployée. Pour déployer une application versionnée dans un dépot on doit alors faire le lien entre git et kubernetes : 1. télécharger le helm chart 2. helm template 3. appliquer ce qu'on obtient avec kubectl 4. vérifier que tout s'est bien passé (et alerter si ce n'est pas le cas) 5. rester en veille sur des changements du dépot et revenir au point 1 si c'est le cas. Argocd fait tout ça pour nous. À voir en live : - déclaration d'un dépot dans argocd - modification des valeurs dans App details -> parameters - visualisation de l'état: - pods - network - logs des pods - différence entre état demandé et actuel - sync / rollback ### Petits détails - Accès à la forge par *argocd* pour cloner le dépot - Accès à la forge par *kubernetes* pour télécharger l'image