Bonjour à tous! Avant le lancement du cours sur la plate-forme d'infrastructure basée sur Kubernetes, nous avons préparé une traduction d'un autre matériel intéressant.
Cet article est destiné aux nouveaux arrivants à Kubernetes, qui seront intéressés à comprendre un exemple pratique de la façon d'écrire une API Golang pour gérer une liste TODO, puis comment la déployer sur Kubernetes.Chaque développeur aime une bonne liste TODO, non? Sinon, comment pourrions-nous nous organiser autrement?
Chaque développeur aime une bonne application TODO, non?Nous allons commencer par passer en revue la liste des composants nécessaires, puis continuer à configurer Kubernetes, fournir la base de données Postgresql, puis installer un cadre d'application qui nous aidera à déployer facilement l'API Go dans Kubernetes, sans se concentrer sur les détails.Nous allons créer deux points de terminaison dans l'API - l'un pour créer un nouvel enregistrement TODO, l'autre pour sélectionner tous les enregistrements TODO.Tout le code de ce tutoriel est disponible sur GitHub.La liste des composants nécessaires:
- Docker installé localement
Kubernetes exécute du code dans les images de conteneur, vous devez donc installer Docker sur votre ordinateur.Installez Docker: https://www.docker.comEnregistrez un compte Docker Hub pour stocker vos images Docker: https://hub.docker.com/Vous pouvez choisir un cluster local ou distant, mais lequel est le meilleur? Les options simplifiées, telles que k3d, fonctionnent sur n'importe quel ordinateur sur lequel Docker peut s'exécuter, de sorte que l'exécution d'un cluster local ne nécessite plus beaucoup de RAM. Un cluster distant peut également être une solution très efficace, mais gardez à l'esprit que toutes vos images Docker devront être téléchargées et téléchargées pour chaque changement.Installez k3d: https://github.com/rancher/k3dk3d n'installera pas kubectl (il s'agit de l'interface CLI pour Kubernetes), alors installez-le séparément d'ici: https://kubernetes.io/docs/tasks/tools / install-kubectlVous devez également installer Golang avec l'IDE sur votre ordinateur. Go est gratuit et vous pouvez le télécharger pour MacOS, Windows ou Linux à partir du lien suivant: https://golang.org/dlJe recommanderais d'utiliser Visual Studio Code, il est gratuit et dispose d'un ensemble de plugins pour Go que vous pouvez ajouter. Certains collègues préfèrent Goland de Jetbrains. Si vous êtes un programmeur Java, vous préféreriez probablement payer pour Goland, car cela vous rappellera leurs autres produits.Installez VSCode ou Golang .Créer un cluster
Vous devez installer tous les logiciels spécifiés dans la section précédente.Créez un nouveau cluster à l'aide de k3d:
k3d create
Configurez kubectl pour qu'il pointe vers un nouveau cluster. N'oubliez pas que plusieurs clusters peuvent être utilisés à partir d'un même ordinateur, il est donc extrêmement important de pointer vers le bon:export KUBECONFIG="$(k3d get-kubeconfig --name='k3s-default')"
Assurez-vous que le cluster possède au moins un nœud. Ici, vous pouvez voir que j'ai installé Kubernetes 1.17 - une version relativement nouvelle:kubectl get node
NAME STATUS ROLES AGE VERSION
k3d-k3s-default-server Ready master 48s v1.17.0+k3s.1
Nous allons stocker nos enregistrements TODO dans la table de base de données, nous devons donc maintenant l'installer. Postgresql est une base de données relationnelle populaire que nous pouvons installer dans un cluster à l'aide du graphique Helm.Installer Arkade
arkade est un CLI Go, similaire à "brew" ou "apt-get", mais pour les applications Kubernetes. Il utilise un projet Helm, kubectl ou CLI pour installer un projet ou un produit dans votre cluster.curl -sLS https:
Installez maintenant Postgresqlarkade install postgresql
===================================================================== = PostgreSQL has been installed. =
=====================================================================
Vous verrez également des informations sur la chaîne de connexion et comment démarrer la CLI Postgresql via l'image Docker à l'intérieur du cluster.Vous pouvez obtenir ces informations à tout moment en utilisant arkade info postgresql
.Nous concevrons la disposition de la tableCREATE TABLE todo (
id INT GENERATED ALWAYS AS IDENTITY,
description text NOT NULL,
created_date timestamp NOT NULL,
completed_date timestamp NOT NULL
);
Exécutez arkade info postgresql
pour obtenir à nouveau les informations de connexion. Ça devrait ressembler a quelque chose comme ca:export POSTGRES_PASSWORD=$(kubectl get secret --namespace default postgresql -o jsonpath="{.data.postgresql-password}" | base64 --decode)
kubectl run postgresql-client --rm --tty -i --restart='Never' --namespace default --image docker.io/bitnami/postgresql:11.6.0-debian-9-r0 --env="PGPASSWORD=$POSTGRES_PASSWORD" --command -- psql --host postgresql -U postgres -d postgres -p 5432
Maintenant, vous avez à l'invite de commande:, postgres = #
vous pouvez créer la table en la copiant à l'intérieur, puis exécutez \dt
pour afficher la table:postgres=# \dt
List of relations
Schema | Name | Type | Owner
--------+------+-------+----------
public | todo | table | postgres
(1 row)
Installer le cadre d'application
Tout comme les développeurs PHP ont accéléré leur flux de travail en utilisant les développeurs LAMP (Linux Apache + Mysql + PHP) et Rails en utilisant une pile pré-préparée, les développeurs Kubernetes peuvent utiliser des cadres d'application.La pile PLONK signifie Prometheus, Linux, OpenFaaS, NATS et Kubernetes.- Prometheus fournit des mesures, une mise à l'échelle automatique et une observabilité pour tester la santé de votre système, lui permet de répondre aux poussées de la demande et de réduire les coûts en fournissant des mesures pour prendre des décisions sur la mise à l'échelle à zéro.
- Linux, bien que n'étant pas la seule option pour exécuter des charges de travail dans Kubernetes, est standard et plus facile à utiliser.
- Au départ, OpenFaaS fournissait des fonctions portables aux développeurs, mais cela fonctionne très bien lors du déploiement d'API et de microservices. Sa polyvalence signifie que tous les conteneurs Docker avec un serveur HTTP peuvent être déployés et gérés.
- NATS est un projet CNCF populaire utilisé pour la messagerie et le pub / sub. Dans la pile PLONK, il offre la possibilité d'exécuter des demandes de manière asynchrone et pour la mise en file d'attente.
- Kubernetes est la raison pour laquelle nous sommes ici. Il fournit une infrastructure évolutive, auto-réparatrice et déclarative. Et si vous n'avez plus besoin d'une partie de toute cette grandeur, son API est simplifiée avec OpenFaaS.
Installez la pile PLONK via Arkade:arkade install openfaas
Lisez le message d'information et exécutez chaque commande:- Installez faas-cli.
- Obtenez votre mot de passe.
- Rediriger l'interface utilisateur de la passerelle OpenFaaS (via le port 8080)
- Et connectez-vous au système via la CLI.
Comme précédemment, vous pouvez recevoir un message d'information à l'aide de info openfaas
.Déployez votre API First Go
Il existe plusieurs façons de créer une API Go à l'aide de PLONK. La première option consiste à utiliser le Dockerfile et à déterminer manuellement le port TCP, la vérification de l'état, le serveur HTTP, etc. Cela peut être fait en utilisant faas-cli new --lang dockerfile API_NAME
, mais il existe un moyen plus simple et plus automatisé.La deuxième façon consiste à utiliser les modèles intégrés proposés par le magasin de fonctions:faas-cli template store list | grep go
go openfaas Classic Golang template
golang-http openfaas-incubator Golang HTTP template
golang-middleware openfaas-incubator Golang Middleware template
Puisque nous voulons créer une API de style HTTP traditionnelle, le modèle de middleware golang serait le plus approprié.Au début du didacticiel, vous vous êtes inscrit avec votre compte Docker Hub pour stocker vos images Docker. Chaque charge de travail Kubernetes doit être intégrée dans une image Docker avant de pouvoir être déployée.Tirez le motif spécial:faas-cli template store pull golang-middleware
Utilisez Scaffold pour votre API avec golang-middleware et votre nom d'utilisateur dans le Docker Hub:export PREFIX=alexellis2
export LANG=golang-middleware
export API_NAME=todo
faas-cli new --lang $LANG --prefix $PREFIX $API_NAME
Vous verrez deux fichiers générés:./todo.yml
- fournit un moyen de configurer, déployer et installer le modèle et le nom./todo/handler.go
- ici vous écrivez le code et ajoutez tous les autres fichiers ou packages dont vous avez besoin
Faisons quelques modifications, puis développons le code.package function
import (
"net/http"
"encoding/json"
)
type Todo struct {
Description string `json:"description"`
}
func Handle(w http.ResponseWriter, r *http.Request) {
todos := []Todo{}
todos = append(todos, Todo{Description: "Run faas-cli up"})
res, _ := json.Marshal(todos)
w.WriteHeader(http.StatusOK)
w.Header().Set("Content-Type", "application/json")
w.Write([]byte(res))
}
Si vous n'utilisez pas VScode et ses plugins pour éditer et formater le code, exécutez-le après chaque modification pour vous assurer que le fichier est correctement formaté.gofmt -w -s ./todo/handler.go
Déployez maintenant le code - créez d'abord une nouvelle image, lancez-la dans le Docker Hub et déployez-la sur le cluster à l'aide de l'API OpenFaaS:Invoke your endpoint when ready:
curl http:
{
"description": "Run faas-cli up"
}
Autoriser les utilisateurs à créer de nouveaux enregistrements TODO
Permettons maintenant aux utilisateurs de créer de nouvelles entrées dans leur liste TODO. Vous devez d'abord ajouter le lien ou la «dépendance» pour Aller à la bibliothèque Postgresql.Nous pouvons l'obtenir en utilisant les modules de vente ou Go qui ont été introduits dans Go 1.11 et installés par défaut dans Go 1.13.Modifiez handler.go
et ajoutez le module dont nous avons besoin pour accéder à Postgresql:import (
"database/sql"
_ "github.com/lib/pq"
...
Pour que les modules Go détectent les dépendances, nous devons déclarer quelque chose dans le fichier, que nous utiliserons plus tard. Si ce n'est pas le cas, VSCode supprimera ces lignes lors de l'enregistrement.Ajoutez ceci sous les importations dans le fichiervar db *sql.DB
Exécutez toujours ces commandes dans le todo
dossier où il se trouve handler.go
, et non au niveau racine c todo.yml
.Initialisez le nouveau module Go:cd todo/
ls
handler.go
export GO111MODULE=on
go mod init
Maintenant, mettez à jour le fichier en utilisant la bibliothèque pq:go get
go mod tidy
cat go.mod
module github.com/alexellis/todo1/todo
go 1.13
require github.com/lib/pq v1.3.0
Tout ce qui se trouve à l'intérieur go.mod
, copiez son contenu dansGO_REPLACE.txt
cat go.mod > GO_REPLACE.txt
Maintenant, assurons-nous que l'assembly fonctionne toujours avant d'ajouter le code d'insertion.faas-cli build -f todo.yml --build-arg GO111MODULE=on
Vous remarquerez peut-être que nous transmettons maintenant --build-arg
un modèle d'utilisation des modules Go.Lors de l'assemblage, vous verrez que les modules sont téléchargés au besoin sur Internet.Step 16/29 : RUN go test ./... -cover
---> Running in 9a4017438500
go: downloading github.com/lib/pq v1.3.0
go: extracting github.com/lib/pq v1.3.0
go: finding github.com/lib/pq v1.3.0
? github.com/alexellis/todo1/todo [no test files]
Removing intermediate container 9a4017438500
Configuration des secrets pour l'accès Postgresql
Nous pouvons créer un pool de connexions dans init ()
, une méthode qui ne s'exécutera qu'une seule fois au démarrage du programme.
func init() {
if _, err := os.Stat("/var/openfaas/secrets/password"); err == nil {
password, _ := sdk.ReadSecret("password")
user, _ := sdk.ReadSecret("username")
host, _ := sdk.ReadSecret("host")
dbName := os.Getenv("postgres_db")
port := os.Getenv("postgres_port")
sslmode := os.Getenv("postgres_sslmode")
connStr := "postgres://" + user + ":" + password + "@" + host + ":" + port + "/" + dbName + "?sslmode=" + sslmode
var err error
db, err = sql.Open("postgres", connStr)
if err != nil {
panic(err.Error())
}
err = db.Ping()
if err != nil {
panic(err.Error())
}
}
}
Comme vous l'avez remarqué, certaines informations sont extraites de ce qui est os.Getenv
lu dans l'environnement. Je considérerais ces valeurs comme non confidentielles, elles sont définies dans le fichier todo.y
.Le reste, comme le mot de passe et l'hôte, qui sont confidentiels, sont conservés dans les secrets de Kubernetes .Vous pouvez les créer à travers faas-cli secret create
ou à travers kubectl create secret generic -n openfaas-fn
.La chaîne sdk.ReadSecret
vient de OpenFaaS CloudEND_LINK, avec l'importation suivante: github.com/openfaas/openfaas-cloud/sdk
. Il lit un fichier secret sur le disque et renvoie une valeur ou une erreur.Obtenez les valeurs secrètes de arkade info postgresql
.Maintenant, pour chaque mot de passe, procédez comme suit:export POSTGRES_PASSWORD=$(kubectl get secret --namespace default postgresql -o jsonpath="{.data.postgresql-password}" | base64 --decode)
export USERNAME="postgres"
export PASSWORD=$POSTGRES_PASSWORD
export HOST="postgresql.default"
faas-cli secret create username --from-literal $USERNAME
faas-cli secret create password --from-literal $PASSWORD
faas-cli secret create host --from-literal $HOST
Vérifiez les secrets de disponibilité et de conformité:faas-cli secret ls
NAME
username
password
host
# And via kubectl:
kubectl get secret -n openfaas-fn
NAME TYPE DATA AGE
username Opaque 1 13s
password Opaque 1 13s
host Opaque 1 12s
Modifiez notre fichier YAML et ajoutez ce qui suit:secrets:
- host
- password
- username
environment:
postgres_db: postgres
postgres_sslmode: "disable"
postgres_port: 5432
Ensuite, mettez à jour les modules Go et réexécutez la génération:cd todo
go get
go mod tidy
cd ..
faas-cli build -f todo.yml --build-arg GO111MODULE=on
Successfully built d2c609f8f559
Successfully tagged alexellis2/todo:latest
Image: alexellis2/todo:latest built.
[0] < Building todo done in 22.50s.
[0] Worker done.
Total build time: 22.50s
L'assembly a fonctionné comme prévu, exécutons-le donc faas-cli
avec les mêmes arguments pour démarrer et déployer l'image. Si les informations d'identification et la configuration SQL sont correctes, nous ne verrons pas d'erreurs dans les journaux, cependant, si elles sont incorrectes, nous obtiendrons le code de panique dans init ().Vérifiez les journaux:faas-cli logs todo
2020-03-26T14:10:03Z Forking - ./handler []
2020-03-26T14:10:03Z 2020/03/26 14:10:03 Started logging stderr from function.
2020-03-26T14:10:03Z 2020/03/26 14:10:03 Started logging stdout from function.
2020-03-26T14:10:03Z 2020/03/26 14:10:03 OperationalMode: http
2020-03-26T14:10:03Z 2020/03/26 14:10:03 Timeouts: read: 10s, write: 10s hard: 10s.
2020-03-26T14:10:03Z 2020/03/26 14:10:03 Listening on port: 8080
2020-03-26T14:10:03Z 2020/03/26 14:10:03 Metrics listening on port: 8081
2020-03-26T14:10:03Z 2020/03/26 14:10:03 Writing lock-file to: /tmp/.lock
Alors que tout semble bien, essayons maintenant d'appeler le point de terminaison:echo | faas-cli invoke todo -f todo.yml
2020-03-26T14:11:02Z 2020/03/26 14:11:02 POST / - 200 OK - ContentLength: 35
Ainsi, nous avons maintenant établi une connexion réussie à la base de données et nous pouvons effectuer l'insertion. Comment savons-nous cela? Parce qu'il db.Ping ()
renvoie une erreur, sinon il aurait jeté une panique:err = db.Ping()
if err != nil {
panic(err.Error())
}
Suivez le lien pour plus de détails sur le package base de données / sql .Écrire le code d'insertion
Ce code insère une nouvelle ligne dans la table todo
et utilise une syntaxe spéciale dans laquelle la valeur n'est pas placée entre guillemets, mais est remplacée à la place par le code db.Query. Dans "l'ancien temps" de la programmation LAMP, une erreur courante qui a rendu de nombreux systèmes dangereux: le manque de nettoyage des données d'entrée et la concaténation des entrées utilisateur directement dans l'instruction SQL.Imaginez quelqu'un entrer une description; drop table todo
Ce ne serait pas très amusant.Par conséquent, nous exécutons db.Query
, puis passons l'instruction SQL à l'aide de $1
, $2
etc. pour chaque valeur, puis nous pouvons obtenir le résultat et / ou l'erreur. Nous devons également clôturer ce résultat, alors utilisez le report pour cela.func insert(description string) error {
res, err := db.Query(`insert into todo (id, description, created_date) values (DEFAULT, $1, now());`,
description)
if err != nil {
return err
}
defer res.Close()
return nil
}
Maintenant, connectons cela au code.func Handle(w http.ResponseWriter, r *http.Request) {
if r.Method == http.MethodPost && r.URL.Path == "/create" {
defer r.Body.Close()
body, _ := ioutil.ReadAll(r.Body)
if err := insert(string(body)); err != nil {
http.Error(w, fmt.Sprintf("unable to insert todo: %s", err.Error()), http.StatusInternalServerError)
}
}
}
Déployons-le et exécutons-le.echo | faas-cli invoke todo -f todo.yml
curl http:
curl http:
curl http:
Vérifiez les journaux de l'API:faas-cli logs todo
2020-03-26T14:35:29Z 2020/03/26 14:35:29 POST /create - 200 OK - ContentLength: 0
Vérifiez le contenu du tableau à l'aide de pgsql:export POSTGRES_PASSWORD=$(kubectl get secret
kubectl run postgresql-client
postgres=
id | description | created_date | completed_date
1 | faas-cli build | 2020-03-26 14:36:03.367789 |
2 | faas-cli push | 2020-03-26 14:36:03.389656 |
3 | faas-cli deploy | 2020-03-26 14:36:03.797881 |
Félicitations, vous disposez désormais d'une API TODO qui peut accepter les demandes entrantes via curl
ou tout autre client HTTP et les écrire dans la table de base de données.Demande d'enregistrement
Créons une nouvelle fonction pour interroger les enregistrements TODO à partir d'une table:func selectTodos() ([]Todo, error) {
var error err
var todos []Todo
return todos, err
}
Nous ne pouvons pas nommer cette méthode de sélection car il s'agit d'un mot clé réservé pour travailler avec des goroutines.Connectez maintenant la méthode au gestionnaire principal:} else if r.Method == http.MethodGet && r.URL.Path == "/list" {
todos, err := selectTodos()
if err != nil {
http.Error(w, fmt.Sprintf("unable to get todos: %s", err.Error()), http.StatusInternalServerError)
}
out, _ := json.Marshal(todos)
w.Header().Set("Content-Type", "application/json")
w.Write(out)
}
Maintenant qu'il y a des champs supplémentaires pour les dates dans notre schéma de données, mettez à jour la structure Todo:type Todo struct {
ID int `json:"id"`
Description string `json:"description"`
CreatedDate *time.Time `json:"created_date"`
CompletedDate *time.Time `json:"completed_date"`
}
Ajoutons maintenant le selectTodos()
code de requête à notre méthode :func selectTodos() ([]Todo, error) {
rows, getErr := db.Query(`select id, description, created_date, completed_date from todo;`)
if getErr != nil {
return []Todo{}, errors.Wrap(getErr, "unable to get from todo table")
}
todos := []Todo{}
defer rows.Close()
for rows.Next() {
result := Todo{}
scanErr := rows.Scan(&result.ID, &result.Description, &result.CreatedDate, &result.CompletedDate)
if scanErr != nil {
log.Println("scan err:", scanErr)
}
todos = append(todos, result)
}
return todos, nil
}
Comme précédemment, nous devons retarder la fermeture des lignes de la demande. Chaque valeur est insérée dans la nouvelle structure à l'aide de la méthode row.Scan. À la fin de la méthode, nous avons un morceau de contenu Todo.Essayons:faas-cli up -f todo.yml
curl http://127.0.0.1:8080/function/todo/list
Voici le résultat:[
{
"id": 2,
"description": "faas-cli build",
"created_date": "2020-03-26T14:36:03.367789Z",
"completed_date": null
},
{
"id": 3,
"description": "faas-cli push",
"created_date": "2020-03-26T14:36:03.389656Z",
"completed_date": null
},
{
"id": 4,
"description": "faas-cli deploy",
"created_date": "2020-03-26T14:36:03.797881Z",
"completed_date": null
}
]
Pour supprimer les valeurs, nous pouvons mettre à jour les annotations de structure en ajoutant omitempty
:CompletedDate *time.Time `json:"completed_date,omitempty"`
Pour résumer le travail accompli
Nous n'avons pas encore fini, mais c'est le bon moment pour nous arrêter et revoir ce que nous avons accompli jusqu'à présent. Nous:- Go, Docker, kubectl et VSCode (IDE) installés
- Déployer Kubernetes sur notre ordinateur local
- Postgresql installé à l'aide d'Arkade et de Helm3
- OpenFaaS installé et la pile PLONK pour les développeurs d'applications Kubernetes
- Création de l'API REST statique initiale à l'aide de Go et
golang-middleware
du modèle OpenFaaS - Ajout de la fonctionnalité «insérer» à notre API TODO
- Ajout d'une fonctionnalité de sélection à notre API TODO
L'exemple de code complet que nous avons créé jusqu'à présent est disponible sur mon compte GitHub: alexellis / kubernetes-todo-go-appEnsuite, nous pouvons faire beaucoup plus, par exemple:- Ajout d'authentification à l'aide d'un jeton de support statique
- Créez une page Web à l'aide d'un modèle HTML statique ou React pour afficher une liste TODO et créer de nouveaux éléments.
- Ajout de la prise en charge multi-utilisateurs à l'API
Et beaucoup plus. Nous pourrions également nous plonger dans la pile PLONK et déployer le tableau de bord Grafana pour commencer à surveiller notre API et comprendre combien de ressources sont utilisées avec le tableau de bord Kubernetes ou le serveur métrique (installé à l'aide arkade install
).En savoir plus sur arkade: https://get-arkade.devAssistez à l'atelier OpenFaaS pour en savoir plus sur ce qui précède: https://github.com/openfaas/workshop/Vous pouvez vous abonner à ma newsletter premium Insiders Updates surhttps: / /www.alexellis.io/et sur mon twitter Alex Ellis
En savoir plus sur le cours