Comment automatiser les déploiements sur DigitalOcean Kubernetes avec CircleCI

_L’auteur a sélectionné le Tech Education Fund pour recevoir un don dans le cadre du programme Write for DOnations. _

introduction

Avoir un processus de déploiement automatisé est une condition requise pour une application évolutive et résiliente, et GitOps, ou Git-based DevOps, est rapidement devenu Une méthode populaire d’organisation de CI / CD avec un référentiel Git en tant que «source unique de vérité». Des outils tels que CircleCI s’intègrent à votre référentiel GitHub, vous permettant de tester et de déployer votre code automatiquement le temps que vous apportez une modification à votre référentiel. Lorsque ce type de CI / CD est associé à la flexibilité de l’infrastructure Kubernetes, vous pouvez créer une application qui s’adapte facilement à l’évolution de la demande.

Dans cet article, vous utiliserez CircleCI pour déployer un exemple d’application sur un cluster DigitalOcean Kubernetes (DOKS). Après avoir lu ce didacticiel, vous pourrez appliquer ces mêmes techniques pour déployer d’autres outils de CI / CD pouvant être construits en tant qu’images Docker.

Conditions préalables

Pour suivre ce tutoriel, vous aurez besoin de:

Pour ce tutoriel, vous utiliserez la version de Kubernetes + 1.13.5 + et + kubectl + version + 1.10.7 +.

Étape 1 - Création de votre cluster DigitalOcean Kubernetes

Dans cette première étape, vous allez créer le cluster DigitalOcean Kubernetes (DOKS) à partir duquel vous allez déployer votre exemple d’application. Les commandes + kubectl + exécutées à partir de votre ordinateur local modifieront ou récupéreront des informations directement à partir du cluster Kubernetes.

Accédez à la page Kubernetes de votre compte DigitalOcean.

Cliquez sur * Créer un cluster Kubernetes * ou cliquez sur le bouton vert * Créer * en haut à droite de la page et sélectionnez * Clusters * dans le menu déroulant.

image: https: //assets.digitalocean.com/articles/cart_64920/Create_DOKS.gif [Création d’un cluster Kubernetes sur DigitalOcean]

La page suivante indique où vous allez spécifier les détails de votre cluster. Activé * Sélectionnez une version de Kubernetes * Choisissez la version * 1.13.5-do.0 *. Si celui-ci n’est pas disponible, choisissez-en un plus haut.

Pour * Choisissez une région de centre de données *, choisissez la région la plus proche de vous. Ce tutoriel utilisera * San Francisco - 2 *.

Vous avez ensuite la possibilité de construire votre * pool (s) de nœuds *. Sur Kubernetes, un nœud est un ordinateur subordonné qui contient les services nécessaires à l’exécution des pods. Sur DigitalOcean, chaque nœud est un droplet. Votre pool de nœuds sera constitué d’un seul * nœud standard *. Sélectionnez la configuration * 2GB / 1vCPU * et passez à * 1 Node * sur le nombre de nœuds.

Vous pouvez ajouter des balises supplémentaires si vous le souhaitez. Cela peut être utile si vous envisagez d’utiliser l’API DigitalOcean ou simplement pour mieux organiser vos pools de nœuds.

Sur * Choisissez un nom *, pour ce tutoriel, utilisez + kubernetes-deployment-tutorial. Cela facilitera le suivi tout au long de la lecture des sections suivantes. Enfin, cliquez sur le bouton vert * Créer un cluster * pour créer votre cluster.

Après la création du cluster, un bouton de l’interface utilisateur permettra de télécharger un fichier de configuration appelé * Download Config File *. C’est le fichier que vous utiliserez pour authentifier les commandes + kubectl + que vous allez exécuter sur votre cluster. Téléchargez-le sur votre machine + kubectl +.

La méthode par défaut pour utiliser ce fichier est de toujours passer l’indicateur + - kubeconfig + et son chemin d’accès sur toutes les commandes que vous exécutez avec + kubectl +. Par exemple, si vous avez téléchargé le fichier de configuration sur + Desktop +, vous exécuterez la commande + kubectl get pods + comme ceci:

kubectl --kubeconfig ~/Desktop/kubernetes-deployment-tutorial-kubeconfig.yaml get pods

Cela donnerait le résultat suivant:

OutputNo resources found.

Cela signifie que vous avez accédé à votre cluster. Le message + aucune ressource trouvée. + Est correct, car vous n’avez aucun pod sur votre cluster.

Si vous ne gérez pas d’autres clusters Kubernetes, vous pouvez copier le fichier kubeconfig dans un dossier de votre répertoire personnel appelé + .kube +. Créez ce répertoire s’il n’existe pas:

mkdir -p ~/.kube

Copiez ensuite le fichier de configuration dans le répertoire + .kube + nouvellement créé et renommez-le + config +:

cp  ~/.kube/config

Le fichier de configuration devrait maintenant avoir le chemin + ~ / .kube / config +. Il s’agit du fichier que + kubectl + lit par défaut lors de l’exécution d’une commande. Il n’est donc plus nécessaire de passer + - kubeconfig +. Exécutez ce qui suit:

kubectl get pods

Vous recevrez le résultat suivant:

OutputNo resources found.

Accédez maintenant au cluster avec les éléments suivants:

kubectl get nodes

Vous recevrez la liste des nœuds de votre cluster. Le résultat sera similaire à ceci:

OutputNAME                                    STATUS    ROLES     AGE       VERSION
kubernetes-deployment-tutorial-1-7pto   Ready     <none>    1h        v1.13.5

Dans ce tutoriel, vous allez utiliser les espaces de noms + default + pour toutes les commandes + kubectl + et les fichiers manifest, qui définissent la charge de travail et les paramètres de fonctionnement de Kubernetes. Les noms d’espaces sont comme des clusters virtuels au sein de votre cluster physique unique. Vous pouvez changer d’espace de noms de votre choix. assurez-vous simplement de toujours le transmettre en utilisant l’indicateur + - namespace + à + ​​kubectl +, et / ou en le spécifiant dans le champ de métadonnées du manifeste de Kubernetes. Ils constituent un excellent moyen d’organiser les déploiements de votre équipe et de leurs environnements d’exécution; Pour en savoir plus à leur sujet, consultez /official Kubernetes overview on Namespaces.

En terminant cette étape, vous pouvez maintenant exécuter + kubectl + contre votre cluster. Dans l’étape suivante, vous allez créer le référentiel Git local que vous allez utiliser pour héberger votre exemple d’application.

Étape 2 - Création du référentiel Git local

Vous allez maintenant structurer votre exemple de déploiement dans un référentiel Git local. Vous créerez également des manifestes Kubernetes qui seront globaux pour tous les déploiements que vous allez effectuer sur votre cluster.

Commencez par créer un nouveau référentiel Git localement que vous souhaitez transmettre ultérieurement à GitHub. Créez un dossier vide appelé + do-sample-app dans votre répertoire personnel et` + cd` dans celui-ci:

mkdir ~/do-sample-app
cd ~/do-sample-app

Créez maintenant un nouveau référentiel Git dans ce dossier avec la commande suivante:

git init .

Dans ce référentiel, créez un dossier vide appelé + kube +:

mkdir ~/do-sample-app/kube/

Ce sera l’emplacement où vous allez stocker les manifestes de ressources Kubernetes liés à l’exemple d’application que vous allez déployer sur votre cluster.

A présent, créez un autre dossier appelé + kube-general +, mais cette fois en dehors du référentiel Git que vous venez de créer. Faites-le dans votre répertoire personnel:

mkdir ~/kube-general/

Ce dossier est en dehors de votre référentiel Git car il sera utilisé pour stocker des manifestes qui ne sont pas spécifiques à un seul déploiement sur votre cluster, mais communs à plusieurs. Cela vous permettra de réutiliser ces manifestes généraux pour différents déploiements.

Avec vos dossiers créés et le référentiel Git de votre exemple d’application en place, il est temps d’organiser l’authentification et l’autorisation de votre cluster DOKS.

Étape 3 - Création d’un compte de service

Il n’est généralement pas recommandé d’utiliser l’utilisateur * admin * par défaut pour s’authentifier à partir d’autres Services dans votre cluster Kubernetes. Si vos clés du fournisseur externe étaient compromises, l’ensemble de votre cluster le serait également.

Au lieu de cela, vous allez utiliser un seul compte Service avec un rôle spécifique, qui fait partie du https: / /kubernetes.io/docs/reference/access-authn-authz/rbac/[RBAC Modèle d’autorisation Kubernetes].

Ce modèle d’autorisation est basé sur Roles et Resources. Vous commencez par créer un compte de service, qui est fondamentalement un utilisateur de votre cluster, puis vous créez un rôle dans lequel vous spécifiez les ressources auxquelles il a accès sur votre cluster. Enfin, vous créez un Role Binding, utilisé pour établir la connexion entre le rôle et le compte de service précédemment créé, en accordant au compte de service l’accès à toutes les ressources auxquelles le rôle a accès.

La première ressource Kubernetes que vous allez créer est le compte de service de votre utilisateur de CI / CD, que ce didacticiel nommera + cicd +.

Créez le fichier + cicd-service-account.yml + dans le dossier + ~ / kube-general + et ouvrez-le avec votre éditeur de texte préféré:

nano ~/kube-general/cicd-service-account.yml

Écrivez le contenu suivant dessus:

~ / kube-general / cicd-service-account.yml

apiVersion: v1
kind: ServiceAccount
metadata:
 name: cicd
 namespace: default

Ceci est un fichier YAML; toutes les ressources Kubernetes sont représentées par un. Dans ce cas, vous dites que cette ressource provient de la version de l’API Kubernetes + v1 + (en interne + kubectl + crée des ressources en appelant les API HTTP Kubernetes), et il s’agit d’un + ServiceAccount +.

Le champ + metadata + est utilisé pour ajouter plus d’informations sur cette ressource. Dans ce cas, vous donnez à ce + ServiceAccount + le nom + cicd + et vous le créez dans l’espace de noms + default +.

Vous pouvez maintenant créer ce compte de service sur votre cluster en exécutant + kubectl apply +, comme suit:

kubectl apply -f ~/kube-general/

Vous recevrez une sortie similaire à celle-ci:

Outputserviceaccount/cicd created

Pour vous assurer que votre compte de service fonctionne, essayez de vous connecter à votre cluster à l’aide de celui-ci. Pour ce faire, vous devez d’abord obtenir leur jeton d’accès respectif et le stocker dans une variable d’environnement. Chaque compte de service possède un jeton d’accès que Kubernetes enregistre sous la forme Secret.

Vous pouvez récupérer ce secret en utilisant la commande suivante:

TOKEN=$(kubectl get secret $(kubectl get secret | grep cicd-token | awk '{print $1}') -o jsonpath='{.data.token}' | base64 --decode)

Quelques explications sur ce que fait cette commande:

$(kubectl get secret | grep cicd-token | awk '{print $1}')

Ceci est utilisé pour récupérer le nom du secret lié à notre compte de service + cicd +. + kubectl get secret + renvoie la liste des secrets sur l’espace de noms par défaut, puis utilisez + grep + pour rechercher les lignes associées à votre compte de service + cicd +. Ensuite, vous renvoyez le nom, puisqu’il s’agit de la première chose sur la seule ligne renvoyée par + grep +.

kubectl get secret  -o jsonpath='{.data.token}' | base64 --decode

Cela ne récupérera que le secret de votre jeton de compte de service. Vous accédez ensuite au champ de jeton en utilisant + jsonpath +, et transmettez le résultat à + ​​base64 --decode +. Cela est nécessaire car le jeton est stocké en tant que chaîne Base64. Le jeton lui-même est un JSON Web Token.

Vous pouvez maintenant essayer de récupérer vos pods avec le compte de service + cicd +. Exécutez la commande suivante en remplaçant ++ par l’URL du serveur qui se trouve après + server: + dans + ~ kube / config +. Cette commande donnera une erreur spécifique que vous apprendrez plus tard dans ce tutoriel:

kubectl --insecure-skip-tls-verify --kubeconfig="/dev/null" --server= --token=$TOKEN get pods

+ - insecure-skip-tls-verify + ignore l’étape consistant à vérifier le certificat du serveur, car vous êtes en train de tester et n’avez pas besoin de le vérifier. + - kubeconfig =" / dev / null "+ permet de s’assurer que + kubectl + ne lit pas votre fichier de configuration et vos informations d’identification, mais utilise plutôt le jeton fourni.

Le résultat devrait ressembler à ceci:

OutputError from server (Forbidden): pods is forbidden: User "system:serviceaccount:default:cicd" cannot list resource "pods" in API group "" in the namespace "default"

C’est une erreur, mais cela nous montre que le jeton a fonctionné. L’erreur que vous avez reçue concerne le fait que votre compte de service n’a pas l’autorisation nécessaire pour répertorier la ressource + secrets +, mais que vous avez pu accéder au serveur lui-même. Si votre jeton n’avait pas fonctionné, l’erreur aurait été la suivante:

Outputerror: You must be logged in to the server (Unauthorized)

Maintenant que l’authentification a réussi, l’étape suivante consiste à corriger l’erreur d’autorisation pour le compte de service. Pour ce faire, vous devez créer un rôle avec les autorisations nécessaires et le lier à votre compte de service.

Étape 4 - Création du rôle et de la liaison de rôle

Kubernetes a deux façons de définir des rôles: en utilisant une ressource + Role + ou + + ClusterRole +. La différence entre le premier et le dernier est que le premier s’applique à un seul espace de noms, tandis que le second est valable pour l’ensemble du cluster.

Comme vous utilisez un seul espace de noms dans ce tutoriel, vous utiliserez un + rôle +.

Créez le fichier + ~ / kube-general / cicd-role.yml + et ouvrez-le avec votre éditeur de texte préféré:

nano ~/kube-general/cicd-role.yml

L’idée de base est d’autoriser l’accès à tout ce qui concerne la plupart des ressources Kubernetes dans l’espace de noms + default +. Votre + rôle + ressemblerait à ceci:

~ / kube-general / cicd-role.yml

kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
 name: cicd
 namespace: default
rules:
 - apiGroups: ["", "apps", "batch", "extensions"]
   resources: ["deployments", "services", "replicasets", "pods", "jobs", "cronjobs"]
   verbs: ["*"]

Ce YAML présente certaines similitudes avec celui que vous avez créé précédemment, mais ici vous dites que cette ressource est un + Role +, et qu’elle provient de l’API Kubernetes + rbac.authorization.k8s.io / v1 +. Vous nommez votre rôle + cicd + et vous le créez dans le même espace de noms que vous avez créé votre + ServiceAccount +, celui + default +.

Ensuite, vous avez le champ + rules +, qui est une liste de ressources auxquelles ce rôle a accès. Dans Kubernetes, les ressources sont définies en fonction du groupe d’API auquel elles appartiennent, du type de ressource lui-même et des actions que vous pouvez effectuer ensuite, qui sont représentées par un verbe. Ces verbes sont similaires à ceux HTTP.

Dans notre cas, vous dites que votre + rôle + est autorisé à tout faire, + * +, sur les ressources suivantes: + deployments,` + services`, + réplicasets,` + pods + , + jobs + , et + cronjobs + . Ceci s’applique également aux ressources appartenant aux groupes d’API suivants: `+" "+ (chaîne vide), + apps +, + batch +, et + extensions +. La chaîne vide désigne le groupe d’API racine. Si vous utilisez + apiVersion: v1 + lors de la création d’une ressource, cela signifie que cette ressource fait partie de ce groupe d’API.

Un + rôle + en soi ne fait rien; vous devez également créer un https://kubernetes.io/docs/reference/access-authn-authz/rbac/#rolebinding-and-clusterrolebinding [+ RoleBinding +], qui lie un + Role + à quelque chose, dans ce cas, un + ServiceAccount +.

Créez le fichier + ~ / kube-general / cicd-role-binding.yml + et ouvrez-le:

nano ~/kube-general/cicd-role-binding.yml

Ajoutez les lignes suivantes au fichier:

~ / kube-general / cicd-role-binding.yml

kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
 name: cicd
 namespace: default
subjects:
 - kind: ServiceAccount
   name: cicd
   namespace: default
roleRef:
 kind: Role
 name: cicd
 apiGroup: rbac.authorization.k8s.io

Votre + RoleBinding + contient des champs spécifiques qui n’ont pas encore été abordés dans ce tutoriel. + roleRef + est le + rôle + que vous voulez lier à quelque chose; dans ce cas, il s’agit du rôle + cicd + que vous avez créé précédemment. + sujets + est la liste des ressources que vous associez à votre rôle; dans ce cas, il s’agit d’un simple + ServiceAccount + appelé + cicd +.

Avec ces fichiers créés, vous pourrez utiliser + kubectl apply + à nouveau. Créez ces nouvelles ressources sur votre cluster Kubernetes en exécutant la commande suivante:

kubectl apply -f ~/kube-general/

Vous recevrez une sortie similaire à celle-ci:

Outputrolebinding.rbac.authorization.k8s.io/cicd created
role.rbac.authorization.k8s.io/cicd created
serviceaccount/cicd created

Maintenant, essayez la commande que vous avez exécutée précédemment:

kubectl --insecure-skip-tls-verify --kubeconfig="/dev/null" --server= --token=$TOKEN get pods

Comme vous n’avez pas de pods, cela donnera le résultat suivant:

OutputNo resources found.

Au cours de cette étape, vous avez donné au compte de service que vous allez utiliser sur CircleCI l’autorisation nécessaire pour effectuer des actions significatives sur votre cluster, telles que la liste, la création et la mise à jour de ressources. Il est maintenant temps de créer votre exemple d’application.

Étape 5 - Création de votre exemple d’application

Les Kubernetes + Deployment + que vous allez créer utiliseront l’image Nginx], et votre application sera une simple page HTML statique. C’est un bon début car il vous permet de vérifier si votre déploiement fonctionne en servant un code HTML simple directement à partir de Nginx. Comme vous le verrez plus tard, vous pouvez rediriger tout le trafic arrivant sur une adresse + address: port + local vers votre déploiement sur votre cluster pour vérifier s’il fonctionne.

Dans le référentiel que vous avez configuré précédemment, créez un nouveau fichier + Dockerfile + et ouvrez-le avec l’éditeur de texte de votre choix:

nano ~/do-sample-app/Dockerfile

Écrivez ce qui suit dessus:

~ / do-sample-app / Dockerfile

FROM nginx:1.14

COPY index.html /usr/share/nginx/html/index.html

Cela indiquera à Docker de construire le conteneur d’applications à partir d’une image + nginx +.

Créez maintenant un nouveau fichier + index.html et ouvrez-le:

nano ~/do-sample-app/index.html

Écrivez le contenu HTML suivant:

~ / do-sample-app / index.html

<!DOCTYPE html>
<title>DigitalOcean</title>
<body>
 Kubernetes Sample Application
</body>

Ce code HTML affichera un message simple vous permettant de savoir si votre application fonctionne.

Vous pouvez tester si l’image est correcte en construisant puis en l’exécutant.

Commencez par construire l’image avec la commande suivante, en remplaçant «++» par votre propre nom d’utilisateur Docker Hub. Vous devez spécifier votre nom d’utilisateur ici. Ainsi, lorsque vous le diffuserez plus tard sur Docker Hub, cela fonctionnera:

docker build ~/do-sample-app/ -t /do-kubernetes-sample-app

Maintenant, lancez l’image. Utilisez la commande suivante, qui démarre votre image et transmet tout trafic local sur le port + 8080 + au port + 80 + de l’image, le port que Nginx écoute par défaut:

docker run --rm -it -p 8080:80 /do-kubernetes-sample-app

L’invite de commande cesse d’être interactive pendant l’exécution de la commande. Au lieu de cela, vous verrez les journaux d’accès Nginx. Si vous ouvrez + localhost: 8080 + sur n’importe quel navigateur, une page HTML contenant le contenu de + ~ / do-sample-app / index.html + devrait s’afficher. Si vous n’avez pas de navigateur disponible, vous pouvez ouvrir une nouvelle fenêtre de terminal et utiliser la commande + curl + suivante pour extraire le code HTML de la page Web:

curl localhost:8080

Vous recevrez le résultat suivant:

Output<!DOCTYPE html>
<title>DigitalOcean</title>
<body>
 Kubernetes Sample Application
</body>

Arrêtez le conteneur (+ CTRL + + + + C + `sur le terminal où il est exécuté) et soumettez cette image à votre compte Docker Hub. Pour ce faire, connectez-vous d’abord à Docker Hub:

docker login

Entrez les informations requises sur votre compte Docker Hub, puis transmettez l’image à l’aide de la commande suivante (n’oubliez pas de remplacer le ++ par le vôtre):

docker push /do-kubernetes-sample-app

Vous avez maintenant transféré votre exemple d’image d’application sur votre compte Docker Hub. Dans l’étape suivante, vous allez créer un déploiement sur votre cluster DOKS à partir de cette image.

Étape 6 - Création du déploiement et du service Kubernetes

Avec votre image Docker créée et opérationnelle, vous allez maintenant créer un manifeste indiquant à Kubernetes comment en créer un Deployment sur votre cluster.

Créez le fichier de déploiement YAML + ~ / do-sample-app / kube / do-sample-deployment.yml + et ouvrez-le avec votre éditeur de texte:

nano ~/do-sample-app/kube/do-sample-deployment.yml

Ecrivez le contenu suivant sur le fichier, en veillant à remplacer "++" par votre nom d’utilisateur Docker Hub:

~ / do-sample-app / kube / do-sample-deployment.yml

apiVersion: apps/v1
kind: Deployment
metadata:
 name: do-kubernetes-sample-app
 namespace: default
 labels:
   app: do-kubernetes-sample-app
spec:
 replicas: 1
 selector:
   matchLabels:
     app: do-kubernetes-sample-app
 template:
   metadata:
     labels:
       app: do-kubernetes-sample-app
   spec:
     containers:
       - name: do-kubernetes-sample-app
         image: /do-kubernetes-sample-app:latest
         ports:
           - containerPort: 80
             name: http

Les déploiements de Kubernetes appartiennent au groupe d’API + apps +. Le + apiVersion + de votre manifeste est donc défini sur + apps / v1 +. Sur + metadata + vous avez ajouté un nouveau champ que vous n’avez pas encore utilisé, appelé + metadata.labels +. Ceci est utile pour organiser vos déploiements. Le champ + spec + représente la spécification de comportement de votre déploiement. Un déploiement est responsable de la gestion d’un ou plusieurs pods; dans ce cas, il n’aura qu’une réplique par le champ + spec.replicas +. En d’autres termes, il va créer et gérer un seul pod.

Pour gérer les pods, votre déploiement doit savoir de quels pods il est responsable. Le champ + spec.selector + est celui qui lui donne cette information. Dans ce cas, le déploiement sera responsable de tous les pods avec les balises + app = do-kubernetes-sample-app +. Le champ + spec.template + contient les détails du + Pod + créé par ce déploiement. Dans le modèle, vous avez également un champ + spec.template.metadata. Les + labels + à l’intérieur de ce champ doivent correspondre à ceux utilisés dans + spec.selector +. + spec.template.spec + est la spécification du pod lui-même. Dans ce cas, il contient un seul conteneur, appelé + do-kubernetes-sample-app. L’image de ce conteneur est celle que vous avez précédemment créée et transmise à Docker Hub.

Ce fichier YAML indique également à Kubernetes que ce conteneur expose le port + 80 + et lui donne le nom + http +.

Pour accéder au port exposé par votre + déploiement +, créez un service. Créez un fichier nommé + ~ / do-sample-app / kube / do-sample-service.yml + et ouvrez-le avec votre éditeur favori:

nano ~/do-sample-app/kube/do-sample-service.yml

Ensuite, ajoutez les lignes suivantes au fichier:

~ / do-sample-app / kube / do-sample-service.yml

apiVersion: v1
kind: Service
metadata:
 name: do-kubernetes-sample-app
 namespace: default
 labels:
   app: do-kubernetes-sample-app
spec:
 type: ClusterIP
 ports:
   - port: 80
     targetPort: http
     name: http
 selector:
   app: do-kubernetes-sample-app

Ce fichier donne à votre + Service + les mêmes étiquettes que celles utilisées lors de votre déploiement. Ce n’est pas obligatoire, mais cela aide à organiser vos applications sur Kubernetes.

La ressource de service a également un champ + spec +. Le champ + spec.type + est responsable du comportement du service. Dans ce cas, il s’agit d’un + ClusterIP +, ce qui signifie que le service est exposé sur une adresse IP interne au cluster et qu’il n’est accessible que depuis votre cluster. Il s’agit du type + spec.type + par défaut pour les services. + spec.selector + est le critère de sélection des étiquettes à utiliser lors de la sélection des pods à exposer par ce service. Puisque votre pod porte le tag + app: to-kubernetes-sample-app, vous l’avez utilisé ici. + spec.ports + sont les ports exposés par les conteneurs du pod que vous souhaitez exposer à partir de ce service. Votre pod a un seul conteneur qui expose le port + 80 +, nommé + http +, de sorte que vous l’utilisez ici comme + targetPort +. Le service expose également ce port sur le port + 80 +, avec le même nom, mais vous auriez pu utiliser une combinaison port / nom différente de celle du conteneur.

Avec vos fichiers de manifeste + Service et` + Deployment` créés, vous pouvez maintenant créer ces ressources sur votre cluster Kubernetes en utilisant + kubectl:

kubectl apply -f ~/do-sample-app/kube/

Vous recevrez le résultat suivant:

Outputdeployment.apps/do-kubernetes-sample-app created
service/do-kubernetes-sample-app created

Vérifiez si cela fonctionne en transférant un port de votre ordinateur vers le port que le service expose dans votre cluster Kubernetes. Vous pouvez le faire en utilisant + kubectl port-forward +:

kubectl port-forward $(kubectl get pod --selector="app=do-kubernetes-sample-app" --output jsonpath='{.items[0].metadata.name}') 8080:80

La commande de sous-shell + $ (kubectl get pod --selector =" app = do-kubernetes-sample-app "--output jsonpath = '{. Items [0] .metadata.name}') + récupère le nom de le pod correspondant à la balise que vous avez utilisée. Sinon, vous auriez pu le récupérer dans la liste des pods en utilisant + kubectl get pods +.

Après avoir exécuté + port-forward +, le shell cessera d’être interactif et générera les requêtes redirigées vers votre cluster:

OutputForwarding from 127.0.0.1:8080 -> 80
Forwarding from [::1]:8080 -> 80

L’ouverture de + localhost: 8080 + sur n’importe quel navigateur doit afficher la même page que celle affichée lors de l’exécution locale du conteneur, mais il provient désormais de votre cluster Kubernetes! Comme auparavant, vous pouvez également utiliser + curl + dans une nouvelle fenêtre de terminal pour vérifier si cela fonctionne:

curl localhost:8080

Vous recevrez le résultat suivant:

Output<!DOCTYPE html>
<title>DigitalOcean</title>
<body>
 Kubernetes Sample Application
</body>

Ensuite, il est temps de transférer tous les fichiers que vous avez créés dans votre référentiel GitHub. Pour ce faire, vous devez d’abord create un référentiel sur GitHub appelé + digital-ocean-kubernetes-deploy +.

Afin de garder ce référentiel simple à des fins de démonstration, n’initialisez pas le nouveau référentiel avec un fichier + README +, + license +, ou + .gitignore + lorsque vous y êtes invité sur l’interface utilisateur de GitHub. Vous pouvez ajouter ces fichiers ultérieurement.

Une fois le référentiel créé, pointez votre référentiel local sur celui de GitHub. Pour ce faire, appuyez sur les touches + CTRL + + + C + pour arrêter + kubectl port-forward + et récupérer la ligne de commande, puis exécutez les commandes suivantes pour ajouter une nouvelle télécommande appelée + origine +:

cd ~/do-sample-app/
git remote add origin https://github.com//digital-ocean-kubernetes-deploy.git

Il ne devrait y avoir aucune sortie de la commande précédente.

Ensuite, validez tous les fichiers que vous avez créés jusqu’à présent dans le référentiel GitHub. Tout d’abord, ajoutez les fichiers:

git add --all

Ensuite, validez les fichiers dans votre référentiel, avec un message de validation entre guillemets:

git commit -m "initial commit"

Cela donnera un résultat similaire à celui-ci:

Output[master (root-commit) db321ad] initial commit
4 files changed, 47 insertions(+)
create mode 100644 Dockerfile
create mode 100644 index.html
create mode 100644 kube/do-sample-deployment.yml
create mode 100644 kube/do-sample-service.yml

Enfin, poussez les fichiers sur GitHub:

git push -u origin master

Vous serez invité à entrer votre nom d’utilisateur et votre mot de passe. Une fois que vous avez entré ceci, vous verrez une sortie comme ceci:

OutputCounting objects: 7, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (7/7), done.
Writing objects: 100% (7/7), 907 bytes | 0 bytes/s, done.
Total 7 (delta 0), reused 0 (delta 0)
To github.com:/digital-ocean-kubernetes-deploy.git
* [new branch]      master -> master
Branch master set up to track remote branch master from origin.

Si vous allez sur la page de votre référentiel GitHub, vous verrez maintenant tous les fichiers. Avec votre projet sur GitHub, vous pouvez maintenant configurer CircleCI comme outil de CI / CD.

Étape 7 - Configuration de CircleCI

Pour ce tutoriel, vous utiliserez CircleCI pour automatiser les déploiements de votre application chaque fois que le code sera mis à jour. Vous devrez donc vous connecter à CircleCI en utilisant votre compte GitHub et configurer votre référentiel.

Tout d’abord, allez sur leur page d’accueil https://circleci.com [+ https: // circleci.com +], puis appuyez sur * Inscription *.

image: https: //assets.digitalocean.com/articles/cart_64920/CircleCI_Main_Site.png [page de circleci-home]

Vous utilisez GitHub, alors cliquez sur le bouton vert * S’inscrire avec GitHub *.

CircleCI va rediriger vers une page d’autorisation sur GitHub. CircleCI a besoin de certaines autorisations sur votre compte pour pouvoir créer vos projets. Cela permet à CircleCI d’obtenir votre courrier électronique, les clés de déploiement et l’autorisation de créer des points d’accès sur vos référentiels, et d’ajouter des clés SSH à votre compte. Si vous avez besoin de plus d’informations sur ce que CircleCI va faire avec vos données, consultez leur documentation sur l’intégration de GitHub.

image: https: //assets.digitalocean.com/articles/cart_64920/CircleCI_GitHub_Sign_In.png [autorisation de circleci-github]

Après avoir autorisé CircleCI, vous serez redirigé vers leur tableau de bord.

image: https: //assets.digitalocean.com/articles/cart_64920/CircleCI_Welcome_Page.png [circleci-project-dashboard]

Ensuite, configurez votre référentiel GitHub dans CircleCI. Cliquez sur * Configurer de nouveaux projets * dans le tableau de bord CircleCI ou, en tant que raccourci, ouvrez le lien suivant pour changer le texte en surbrillance avec votre propre nom d’utilisateur GitHub: `+ https: //circleci.com/setup-project/gh//digital -ocean-kubernetes-deploy + `.

Après cela, appuyez sur * Start Building *. Ne créez pas encore de fichier de configuration dans votre référentiel et ne vous inquiétez pas si la première construction échoue.

image: https: //assets.digitalocean.com/articles/cart_64840/Set_Up.png [circleci-start-building]

Ensuite, spécifiez certaines variables d’environnement dans les paramètres de CircleCI. Vous pouvez trouver les paramètres du projet en cliquant sur le petit bouton avec une icône de rouage en haut à droite de la page, puis en sélectionnant * Variables d’environnement *. Vous pouvez aussi aller directement à la page des variables d’environnement en utilisant l’URL suivante (rappelez-vous pour entrer votre nom d’utilisateur): + https: // circleci.com / gh // digital-ocean-kubernetes-deploy / edit # env-vars +. Appuyez sur * Ajouter une variable * pour créer de nouvelles variables d’environnement.

Tout d’abord, ajoutez deux variables d’environnement appelées + DOCKERHUB_USERNAME + et + DOCKERHUB_PASS + qui seront nécessaires ultérieurement pour transmettre l’image à Docker Hub. Définissez les valeurs sur votre nom d’utilisateur et votre mot de passe Docker Hub, respectivement.

Ajoutez ensuite trois autres éléments: + KUBERNETES_TOKEN +, + KUBERNETES_SERVER +, et + KUBERNETES_CLUSTER_CERTIFICATE +.

La valeur de + KUBERNETES_TOKEN + sera la valeur de la variable d’environnement locale que vous avez utilisée précédemment pour vous authentifier sur votre cluster Kubernetes à l’aide de votre compte utilisateur. Si vous avez fermé le terminal, vous pouvez toujours exécuter la commande suivante pour le récupérer à nouveau:

kubectl get secret $(kubectl get secret | grep cicd-token | awk '{print $1}') -o jsonpath='{.data.token}' | base64 --decode

+ KUBERNETES_SERVER + sera la chaîne que vous avez passée comme drapeau + - serveur + à + ​​kubectl + lorsque vous vous êtes connecté avec votre compte de service + cicd +. Vous pouvez trouver ceci après + server: + dans le fichier + ~ / .kube / config + ou dans le fichier + kubernetes-deployment-tutorial-kubeconfig.yaml + téléchargé à partir du tableau de bord de DigitalOcean lors de la première initialisation. configuration de votre cluster Kubernetes.

+ KUBERNETES CLUSTER CERTIFICATE + devrait également être disponible sur votre fichier + ~ / .kube / config. C’est le champ + certificate-university-data de l’élément` + cluster` lié à votre cluster. Ce devrait être une longue chaîne; assurez-vous de tout copier.

Ces variables d’environnement doivent être définies ici car la plupart d’entre elles contiennent des informations sensibles et il n’est pas sécurisé de les placer directement dans le fichier de configuration CircleCI YAML.

Avec CircleCI à l’écoute des modifications de votre référentiel et des variables d’environnement configurées, il est temps de créer le fichier de configuration.

Créez un répertoire appelé + .circleci + dans votre exemple de référentiel d’applications:

mkdir ~/do-sample-app/.circleci/

Dans ce répertoire, créez un fichier nommé + config.yml + et ouvrez-le avec votre éditeur favori:

nano ~/do-sample-app/.circleci/config.yml

Ajoutez le contenu suivant au fichier, en veillant à remplacer "++" par votre nom d’utilisateur Docker Hub:

~ / do-sample-app / .circleci / config.yml

version: 2.1
jobs:
 build:
   docker:
     - image: circleci/buildpack-deps:stretch
   environment:
     IMAGE_NAME: /do-kubernetes-sample-app
   working_directory: ~/app
   steps:
     - checkout
     - setup_remote_docker
     - run:
         name: Build Docker image
         command: |
           docker build -t $IMAGE_NAME:latest .
     - run:
         name: Push Docker Image
         command: |
           echo "$DOCKERHUB_PASS" | docker login -u "$DOCKERHUB_USERNAME" --password-stdin
           docker push $IMAGE_NAME:latest
workflows:
 version: 2
 build-master:
   jobs:
     - build:
         filters:
           branches:
             only: master

Cela configure un flux de travail avec un seul travail, appelé + build +, qui s’exécute pour chaque commit dans la branche + master +. Ce travail utilise l’image + circleci / buildpack-deps: stretch + pour exécuter ses étapes. Il s’agit d’une image de CircleCI basée sur l’image officielle + buildpack-deps + de Docker, mais avec quelques outils supplémentaires installés, tels que les fichiers binaires Docker. se.

Le flux de travail comporte quatre étapes:

  • + checkout + récupère le code de GitHub.

  • + setup_remote_docker + configure un environnement isolé et distant pour chaque construction. Cela est nécessaire avant d’utiliser une commande + docker dans une étape de travail. Cela est nécessaire car, lors de l’exécution des étapes dans une image de menu fixe, + setup_remote_docker + alloue un autre ordinateur pour exécuter les commandes.

  • La première étape + run + construit l’image, comme vous l’avez déjà fait localement. Pour cela, vous utilisez la variable d’environnement que vous avez déclarée dans + environment: +, + IMAGE_NAME + `(n’oubliez pas de changer la section surlignée avec vos propres informations).

  • La dernière étape run + envoie l’image à Dockerhub, en utilisant les variables d’environnement que vous avez configurées dans les paramètres du projet pour s’authentifier.

Enregistrez le nouveau fichier dans votre référentiel et transmettez les modifications en amont:

cd ~/do-sample-app/
git add .circleci/
git commit -m "add CircleCI config"
git push

Cela déclenchera une nouvelle construction sur CircleCI. Le flux de travail CircleCI va créer et envoyer correctement votre image sur Docker Hub.

image: https: //assets.digitalocean.com/articles/cart_64840/Build.png [Page de construction CircleCI avec informations de construction réussies]

Maintenant que vous avez créé et testé votre flux de travail CircleCI, vous pouvez configurer votre cluster DOKS pour récupérer l’image mise à jour à partir de Docker Hub et la déployer automatiquement lorsque des modifications sont apportées.

Étape 8 - Mise à jour du déploiement sur le cluster Kubernetes

Maintenant que l’image de votre application est créée et envoyée à Docker Hub chaque fois que vous transmettez des modifications à la branche + master + sur GitHub, il est temps de mettre à jour votre déploiement sur votre cluster Kubernetes afin qu’il récupère la nouvelle image et l’utilise en tant que base pour le déploiement.

Pour ce faire, corrigez d’abord un problème avec votre déploiement: il dépend actuellement d’une image portant la balise + latest +. Cette balise ne nous dit pas quelle version de l’image vous utilisez. Vous ne pouvez pas facilement verrouiller votre déploiement sur cette balise, car elle est écrasée chaque fois que vous transmettez une nouvelle image à Docker Hub. Si vous l’utilisez comme cela, vous perdez l’un des meilleurs avantages des applications conteneurisées: la reproductibilité.

Vous pouvez en savoir plus sur cet article sur pourquoi depending sur la dernière balise de Docker est un anti-modèle.

Pour corriger cela, vous devez d’abord apporter quelques modifications à votre étape de construction + Push Docker Image dans le fichier` + ~ / do-sample-app / .circleci / config.yml`. Ouvrez le fichier:

nano ~/do-sample-app/.circleci/config.yml

Ajoutez ensuite les lignes en surbrillance à votre étape + Push Docker Image:

~ / do-sample-app / .circleci / config.yml: 16-22

...
     - run:
         name: Push Docker Image
         command: |
           echo "$DOCKERHUB_PASS" | docker login -u "$DOCKERHUB_USERNAME" --password-stdin

           docker push $IMAGE_NAME:latest

...

Enregistrez et quittez le fichier.

CircleCI a certaines variables d’environnement spéciales définies par défaut. L’un d’eux est + CIRCLE_SHA1 +, qui contient le hachage du commit qu’il construit. Les modifications que vous avez apportées à + ​​~ / do-sample-app / .circleci / config.yml + utiliseront cette variable d’environnement pour baliser votre image avec le commit à partir duquel elle a été construite, en balisant toujours la dernière construction avec la dernière balise. De cette manière, vous avez toujours des images spécifiques disponibles, sans les écraser lorsque vous insérez quelque chose de nouveau dans votre référentiel.

Ensuite, modifiez votre fichier manifeste de déploiement pour qu’il pointe vers ce fichier. Ce serait simple si à l’intérieur de + ~ / do-sample-app / kube / do-sample-deployment.yml + vous pouviez définir votre image comme + / do-kubernetes-sample-app: $ COMMIT_SHA1 +, mais + kubectl + `ne fait pas de substitution de variable à l’intérieur des manifestes lorsque vous utilisez + kubectl apply + . Pour en tenir compte, vous pouvez utiliser https://www.gnu.org/software/gettext/manual/html_node/envsubst-Invocation.html [+ envsubst `]. ` envsubst +` est un outil cli, faisant partie du projet GNU gettext. Il vous permet de lui transmettre du texte. S’il trouve une variable dans le texte contenant une variable d’environnement correspondante, elle est remplacée par la valeur correspondante. Le texte résultant est ensuite renvoyé en tant que leur sortie.

Pour utiliser cela, vous allez créer un simple script bash qui sera responsable de votre déploiement. Créez un nouveau dossier nommé + scripts + à l’intérieur de + + / / do-sample-app / + `:

mkdir ~/do-sample-app/scripts/

Dans ce dossier, créez un nouveau script bash appelé + ci-deploy.sh + et ouvrez-le avec votre éditeur de texte préféré:

nano ~/do-sample-app/scripts/ci-deploy.sh

À l’intérieur, écrivez le script bash suivant:

~ / do-sample-app / scripts / ci-deploy.sh

#! /bin/bash
# exit script when any command ran here returns with non-zero exit code
set -e

COMMIT_SHA1=$CIRCLE_SHA1

# We must export it so it's available for envsubst
export COMMIT_SHA1=$COMMIT_SHA1

# since the only way for envsubst to work on files is using input/output redirection,
#  it's not possible to do in-place substitution, so we need to save the output to another file
#  and overwrite the original with that one.
envsubst <./kube/do-sample-deployment.yml >./kube/do-sample-deployment.yml.out
mv ./kube/do-sample-deployment.yml.out ./kube/do-sample-deployment.yml

echo "$KUBERNETES_CLUSTER_CERTIFICATE" | base64 --decode > cert.crt

./kubectl \
 --kubeconfig=/dev/null \
 --server=$KUBERNETES_SERVER \
 --certificate-authority=cert.crt \
 --token=$KUBERNETES_TOKEN \
 apply -f ./kube/

Passons en revue ce script en utilisant les commentaires du fichier. Premièrement, il y a ce qui suit:

set -e

Cette ligne permet de s’assurer que toute commande ayant échoué arrête l’exécution du script bash. Ainsi, si une commande échoue, les suivantes ne sont pas exécutées.

COMMIT_SHA1=$CIRCLE_SHA1
export COMMIT_SHA1=$COMMIT_SHA1

Ces lignes exportent la variable d’environnement CircleCI + $ CIRCLE_SHA1 + sous un nouveau nom. Si vous veniez de déclarer la variable sans l’exporter à l’aide de + export, elle ne serait pas visible pour la commande` + envsubst`.

envsubst <./kube/do-sample-deployment.yml >./kube/do-sample-deployment.yml.out
mv ./kube/do-sample-deployment.yml.out ./kube/do-sample-deployment.yml

+ envsubst + ne peut pas effectuer de substitution sur place. Autrement dit, il ne peut pas lire le contenu d’un fichier, remplacer les variables par leurs valeurs respectives et écrire la sortie dans le même fichier. Par conséquent, vous allez rediriger la sortie vers un autre fichier, puis remplacer le fichier d’origine par le nouveau.

echo "$KUBERNETES_CLUSTER_CERTIFICATE" | base64 --decode > cert.crt

La variable d’environnement + $ KUBERNETES_CLUSTER_CERTIFICATE + créée précédemment dans les paramètres de projet de CircleCI est en réalité une chaîne encodée en Base64. Pour l’utiliser avec + kubectl +, vous devez décoder son contenu et l’enregistrer dans un fichier. Dans ce cas, vous l’enregistrez dans un fichier nommé + cert.crt + dans le répertoire de travail en cours.

./kubectl \
 --kubeconfig=/dev/null \
 --server=$KUBERNETES_SERVER \
 --certificate-authority=cert.crt \
 --token=$KUBERNETES_TOKEN \
 apply -f ./kube/

Enfin, vous exécutez + kubectl +. La commande a des arguments similaires à ceux que vous avez exécutés lors du test de votre compte de service. Vous appelez + apply -f. / Kube / +, car sur CircleCI, le répertoire de travail actuel est le dossier racine de votre projet. +. / kube / + voici votre dossier + ~ / do-sample-app / kube +.

Enregistrez le fichier et assurez-vous qu’il est exécutable:

chmod +x ~/do-sample-app/scripts/ci-deploy.sh

Maintenant, éditez + ~ / do-sample-app / kube / do-sample-deployment.yml +:

nano ~/do-sample-app/kube/do-sample-deployment.yml

Modifiez la balise de la valeur de l’image du conteneur pour qu’elle ressemble à la suivante:

~ / do-sample-app / kube / do-sample-deployment.yml

     # ...
     containers:
       - name: do-kubernetes-sample-app
         image: /do-kubernetes-sample-app:
         ports:
           - containerPort: 80
             name: http

Enregistrez et fermez le fichier. Vous devez maintenant ajouter de nouvelles étapes à votre fichier de configuration CI pour mettre à jour le déploiement sur Kubernetes.

Ouvrez + ~ / do-sample-app / .circleci / config.yml + sur votre éditeur de texte préféré:

nano ~/do-sample-app/.circleci/config.yml

Ecrivez les nouvelles étapes suivantes, juste en dessous de celle que vous aviez auparavant:

~ / do-sample-app / .circleci / config.yml

...
     - run:
         name: Install envsubst
         command: |
           sudo apt-get update && sudo apt-get -y install gettext-base
     - run:
         name: Install kubectl
         command: |
           curl -LO https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubectl
           chmod u+x ./kubectl
     - run:
         name: Deploy Code
         command: ./scripts/ci-deploy.sh

Les deux premières étapes consistent à installer des dépendances, d’abord + envsubst +, puis + kubectl +. L’étape + Deploy Code + est responsable de l’exécution de notre script de déploiement.

Pour vous assurer que les modifications seront réellement reflétées sur votre déploiement de Kubernetes, éditez votre + index.html +. Changez le HTML en quelque chose d’autre, comme:

~ / do-sample-app / index.html

<!DOCTYPE html>
<title>DigitalOcean</title>
<body>
 Automatic Deployment is Working!
</body>

Une fois que vous avez enregistré la modification ci-dessus, validez tous les fichiers modifiés dans le référentiel et transmettez les modifications en amont:

cd ~/do-sample-app/
git add --all
git commit -m "add deploy script and add new steps to circleci config"
git push

Vous verrez la nouvelle version s’exécuter sur CircleCI et déployer correctement les modifications sur votre cluster Kubernetes.

Attendez la fin de la construction, puis exécutez la même commande que vous avez exécutée précédemment:

kubectl port-forward $(kubectl get pod --selector="app=do-kubernetes-sample-app" --output jsonpath='{.items[0].metadata.name}') 8080:80

Assurez-vous que tout fonctionne correctement en ouvrant votre navigateur sur l’URL + localhost: 8080 + ou en lui faisant une requête + curl +. Il devrait montrer le code HTML mis à jour:

curl localhost:8080

Vous recevrez le résultat suivant:

Output<!DOCTYPE html>
<title>DigitalOcean</title>
<body>
 Automatic Deployment is Working!
</body>

Félicitations, vous avez configuré le déploiement automatisé avec CircleCI!

Conclusion

Il s’agissait d’un tutoriel de base sur la procédure de déploiement de DigitalOcean Kubernetes à l’aide de CircleCI. À partir de là, vous pouvez améliorer votre pipeline de plusieurs façons. La première chose à faire est de créer un seul travail + build + pour plusieurs déploiements, chacun se déployant sur différents clusters Kubernetes ou différents espaces de noms. Cela peut être extrêmement utile lorsque vous avez différentes branches Git pour les environnements de développement, de stockage intermédiaire et de production, en veillant à ce que les déploiements soient toujours séparés.

Vous pouvez également créer votre propre image pour l’utiliser sur CircleCI, au lieu d’utiliser + buildpack-deps +. Cette image pourrait être basée sur celle-ci, mais pourrait déjà avoir les dépendances + kubectl + et + envsubst + installées.

Si vous souhaitez en savoir plus sur CI / CD sur Kubernetes, consultez les tutoriels de notre CI/CD on Série de webinaires Kubernetes, ou pour plus d’informations sur les applications sur Kubernetes, voir Modernizing Applications for Kubernetes.