Introduzione a Docker e Kubernetes

I sistemi distribuiti su larga scala costituiti da più servizi cooperanti stanno diventando sempre più importanti. Questi sistemi funzionano su cluster di centinaia, migliaia o più server. Sviluppare, implementare e mantenere questi sistemi in modo efficiente ed economico è un compito arduo.

La virtualizzazione e più recentemente la containerizzazione consentono una condivisione e gestione flessibile delle risorse. Docker ha reso la containerizzazione popolare. Dai un'occhiata a questo articolo di Envato Tuts + per una grande introduzione: Guida per gli autostoppisti di Docker e modulo.

Google ha gestito per anni il suo immenso software e data center sulla containerizzazione e accumulato a lotto di esperienza e knowhow. Kubernetes è un progetto open-source di Google che porta tutta la conoscenza alle masse.

In questo articolo, esplorerò brevemente Docker e poi approfondirò profondamente Kubernetes. Userò come esempio in esecuzione un servizio API REST di Python 3. Saltiamo dentro.

Il servizio di quotazione

Il servizio preventivo è un'API REST che consente di aggiungere citazioni e ottenere un elenco di tutte le citazioni. È implementato come un servizio web Python 3 utilizzando l'eccellente libreria hug. Espone un singolo endpoint chiamato / virgolette. Puoi ottenere tutte le offerte o pubblicare un nuovo preventivo. Aggiungiamo alcune citazioni:

curl http: // localhost: 8000 / quotes -d "quote = TV è un chewing gum per gli occhi. ~ Frank Lloyd Wright" curl http: // localhost: 8000 / quotes -d "quote = È meglio morire sul tuo piedi che vivere sulle ginocchia. ~ Emiliano Zapata "curl http: // localhost: 8000 / quotes -d" quote = Dobbiamo prestare molta attenzione quando diamo consigli ai più giovani: a volte lo seguono! ~ Edsger W. Dijkstra "

Se cerchi http: // localhost: 8000 / quotes otterrai: ["La TV è un chewing gum per gli occhi. ~ Frank Lloyd Wright", "È meglio morire in piedi che vivere in ginocchio. ~ Emiliano Zapata", "Dobbiamo stare molto attenti quando diamo consigli ai più giovani: a volte lo seguono! ~ Edsger W. Dijkstra "] Se vuoi solo vedere la documentazione generata automaticamente da HUG, vai a: http: // localhost: 8000

"404": "La chiamata API che hai provato a creare non è stata definita. Ecco una definizione dell'API che ti aiuta ad andare avanti :)", "documentation": "/ quotes": "GET": "esempi ": [" http: // localhost: 8000 / quotes "]," outputs ": " content_type ":" application / json "," format ":" JSON (JavaScript serializzato Notation oggetto) "," POST " : "output": "content_type": "application / json", "format": "JSON (JavaScript serializzato Notation Object)", "inputs": "quote": "type": "Testo di base / valore stringa"

Nozioni di base Docker

Non spiegherò molto su Docker e lo applicherò solo al servizio di quotazione.

Dockingizing di un'applicazione Python

Per prima cosa abbiamo bisogno di un Dockerfile. Esegue i seguenti passi:

  1. Basato sull'ultima immagine di Ubuntu
  2. Installa Python 3 e alcune altre dipendenze
  3. Copia la directory del servizio preventivo
  4. Installa le dipendenze del servizio preventivo dal file requirement.txt
  5. Espone la porta 8000
  6. Avvia il servizio di quotazione tramite hug

DA ubuntu: l'ultimo MAINTAINER Gigi Sayfan "[email protected]" RUN apt-get update -y RUN apt-get install -y python3 python3-pip python3-dev build-essential COPY. / quote-service WORKDIR / quote-service RUN pip3 install -r requisiti.txt ESPOSI 8000 ENTRYPOINT hug -f app.py

Costruire un'immagine

Il prossimo passo è costruire un'immagine Docker. Questo è semplice come:

build docker .

Mi piace anche taggare le immagini:

tag docker 715624b7e22a g1g1 / quote-service

G1G1 è il mio nome utente su Docker Hub.

Per verificare che l'immagine sia stata creata correttamente, digita:

finestra mobile ps --all 

Dovresti vedere la nuova immagine:

ID CONTENITORE IMMAGINE COMANDO CREATO STATO PORTO NOMI 715624b7e22a g1g1 / quote-servizio "/ bin / sh -c 'hug -f a" 4 ore fa Su 35 minuti 0.0.0.0:8000->8000/tcp agitated_northcutt

Spingendo un'immagine all'hub Docker

Quando crei un'immagine, puoi anche spingerla su Docker Hub, in modo che possa essere utilizzata da altre persone (o te stesso su una macchina diversa).

docker push g1g1 / quote-service

Si noti che è necessario creare un account su Docker Hub e accedere localmente usando:

login docker

Esecuzione di un'applicazione Dockerized

Ok. Eseguiamo l'immagine del servizio di quotazione ed esponiamo la porta 8000 all'host.

finestra mobile run -i -t -p 8000 g1g1 / quote-service

Tu dovresti vedere: / ################################################# ####################### "-------- "... ------- ..." .----. : / ::::: -: ---------: - ::::: // ... + :::: ---- ## / - / oo +: - ## - --- :::: // '// :: ------- / oosoo ------- ::: //. ## ## ## ## ##### .-: ------./++ o / o -.------ :: - ' ## ## ## ## ## ----.-./ + O +: ... ----. .: ///. ######## ## ## ## '----.- :::::: ------' .- :::: //. ## ## ## ## ## ####: // ::--. -:... ----- ... ": - :::::: -. ' ## ## ## ## ## ##: / ::::::::: -:- ". :::::-. ## ## #### ###### .--::::::: ... :::."... :: ... :: ABBRACCIA LE API DEL FUTURO :: -.: - - :: :: - VERSIONE 1.9.6 :: - - :: -::- -:: - ########################################################### ######################### Copyright (C) 2015 Timothy Edmund Crosley con licenza MIT

Servire sulla porta 8000 ... "Questo è piuttosto bello. Prima di provare ad accedere al tuo fantastico servizio di quotazione sulla porta 8000, potresti dover eseguire un lavoro extra a seconda del tuo ambiente.

Se si esegue su Mac OS X utilizzando VirtualBox e docker-machine, potrebbe essere necessario pubblicare la porta 8000 su VirtualBox per renderla accessibile sull'host.

Supponendo che hai provato a navigare http: // localhost: 8000 / quotes. Oh, no. Errore interno del server! Quello che è successo?

Diamo un'occhiata al codice:

redis_host = os.environ.get ('QUOTE_STORE_SERVICE_HOST', 'localhost') redis_server = redis.StrictRedis (host = redis_host, porta = 6379, db = 0)

Il servizio quote sta tentando di connettersi a un server redis. L'indirizzo host può essere configurato come una variabile di ambiente e, se non è impostato, verrà impostato come predefinito su localhost. Sfortunatamente, redis non è installato di default e non è in esecuzione all'interno del contenitore. Risolviamolo temporaneamente. Per ottenere l'accesso alla shell nel contenitore, digitare il seguente comando:

Esegui finestra mobile -it 715624b7e22a / bin / bash

Quindi otterrai l'accesso alla shell al contenitore e puoi installare i redis:

root @ 715624b7e22a: / quote-service # apt-get install redis-server

Infine, esegui redis: root @ 715624b7e22a: / quote-service # redis-server [25] 29 Nov 00: 14: 24.546 # Attenzione: nessun file di configurazione specificato, utilizzando la configurazione predefinita. Per specificare un file di configurazione utilizzare redis-server /path/to/redis.conf _._ _.- "__" -._ _.- ". '_." -._ Redis 2.8.4 (00000000 / 0) 64 bit .- ".-.\ /" .,"-._ (' , .- | , ) Funzionamento in modalità stand alone |-._-... - __ ... -.-._ |' .-'| Porta: 6379 | -._ . / .-'| PID: 25 -._ -. -./ _.- '_.-' |-.-._ -..-'_.-'_.-' | | -._-._ _.-'_.- '| http://redis.io -._ -._-.__.-'_.- '_.-' |-._-._ -..-'_.-'.-'| | -._-._ .-'.-'| -._ -.-.__.-'_.- '_.-' -. -.__.- '_.-' -._ _.- "-.__.- '

[25] 29 Nov 00: 14: 24.547 # Server avviato, versione Redis 2.8.4 [25] 29 Nov 00: 14: 24.547 # WARNING overcommit_memory è impostato su 0! Il salvataggio dello sfondo potrebbe non riuscire in condizioni di memoria insufficiente. Per risolvere questo problema, aggiungere 'vm.overcommit_memory = 1' a /etc/sysctl.conf e quindi riavviare o eseguire il comando 'sysctl vm.overcommit_memory = 1' affinché questo abbia effetto. [25] 29 novembre 00: 14: 24.547 * DB caricato dal disco: 0.000 secondi [25] 29 Nov 00: 14: 24.547 * Il server è ora pronto ad accettare connessioni sulla porta 6379 "Ora è possibile iniziare ad aggiungere preventivi e ottenere citazioni attraverso il http: // localhost: 8000 / quotes endpoint.

Posizionando l'applicazione (servizio di quotazione) e il database (redis) funziona in un pizzico per un server. Ma ovviamente non scala. Inserisci Kubernetes.

Nozioni di base di Kubernetes

Kubernetes, a.k.a. K8S, è un framework supponente per la gestione e l'orchestrazione di più contenitori. Ha il suo modo di fare le cose, che di solito è molto buono. È ancora in fase di sviluppo, quindi ci sono ancora alcuni spigoli qua e là. Kubernetes ha molti concetti ed è molto flessibile. Spiegherò e dimostrerò i concetti applicandoli al servizio di quotazione.

Impostare un cluster

Esistono molti modi per configurare un cluster Kubernetes. Kubernetes può essere eseguito su bare metal, su Google Container Engine, su AWS, su bare metal (con Linux) e localmente su qualsiasi sistema operativo che utilizza macchine virtuali. Ai fini di questo articolo, ho creato un cluster di un master e due serventi utilizzando il cluster K8s della GUI CoreOS OSX. Su Mac OS X fornisce un piccolo menu in cui è possibile accedere a molti strumenti di gestione dei cluster.

Segui le istruzioni e sarai pronto per partire in pochissimo tempo.

Se non utilizzi Mac OSX o semplicemente non ti interessa molto per la GUI, puoi utilizzare questo progetto per configurare un cluster di test in una VM di Vagrant.

Userò la riga di comando da ora in poi.

Lo strumento da riga di comando kubectl

kubectl è il coltellino svizzero di Kubernetes. Puoi controllare e gestire completamente il tuo cluster dalla comodità della tua console usando nient'altro che kubectl.

Ecco la lista dei comandi: visualizza Visualizza una o più risorse Descrivi Mostra dettagli di una risorsa specifica crea Crea una risorsa per nome file o stdin aggiorna Aggiorna una risorsa per nome file o stdin. elimina Elimina una risorsa per nome file, stdin, risorsa e ID o per risorse e selettore etichetta. namespace SUPERCEDED: imposta e visualizza l'attuale registro dello spazio dei nomi di Kubernetes Stampa i log di un contenitore in un pod. rolling-update Esegue un aggiornamento continuo del ReplicationController specificato. ridimensiona Imposta una nuova dimensione per un controller di replica. exec Esegui un comando in un contenitore. port-forward Inoltra una o più porte locali a un pod. proxy Esegui un proxy sul server di esecuzione del server API Kubernetes Esegui una determinata immagine sul cluster. interrompi con grazia una risorsa per ID o nomefile. esporre Prendere un'applicazione replicata ed esporla come etichetta di servizio di Kubernetes Aggiornare le etichette su una risorsa config config modifica i file kubeconfig cluster-info Visualizza informazioni sul cluster api-versioni Stampa le versioni API disponibili. versione Stampa le informazioni sulla versione del client e del server. aiuto Guida per qualsiasi comando

Sentiti libero di usare il comando di aiuto o la documentazione per indagare su ciò che ciascuno fa. Molti di questi sono utilizzati per eseguire operazioni manuali che vengono eseguite meglio utilizzando i file di configurazione in un sistema distribuito su larga scala e scalabile, ma è indispensabile per l'esplorazione rapida e la risoluzione dei problemi. I comandi più comuni che userò molto sono: get, create, delete e start.

Pods

Un pod è l'unità base di implementazione e gestione in Kubernetes. Un pod è un gruppo di uno o più contenitori. Puoi specificare un pod usando un file YAML dedicato o come parte di un servizio di Kubernetes (vedi sotto). Un pod viene sempre distribuito su un singolo host e tutti i contenitori in un pod possono accedervi vicendevolmente tramite localhost. Tutti i contenitori del pod vengono sempre avviati, arrestati e ridimensionati.

Per controllare tutti i pod nel cluster, digitare:

kubectl ottiene i pod

Il risultato sarà qualcosa del tipo: NOME READY STATUS RESTARTS AGE quote-frontend-4kyns 1/1 In esecuzione 0 1h quote-frontend-v4xk1 1/1 In esecuzione 0 1h quote-store-controller-y4ya1 1/1 In esecuzione 0 23h ### Volumi

I contenitori non dovrebbero mantenere uno stato persistente. Quando un container si arresta in modo anomalo o si riavvia, il suo file system locale viene cancellato. Se si desidera mantenere lo stato persistente, è necessario utilizzare volumi persistenti. Poiché tutto in Kubernetes è basato su pod, è necessario definire anche i volumi in un pod. Ecco un file di definizione del pod con un volume persistente: apiVersione: tipo v1: pod metadata: nome: quote-store etichette: app: quote-api ruolo: persistent-storage spec: contenitori: - nome: redis image: redis volumeMounts: - nome: quote-store-volume mountPath: / data / redis volumi: - nome: quote-store-volume emptyDir: Si noti che i volumi persistenti sono limitati al nodo e sopravviveranno al crash del contenitore e al riavvio, ma non errori di nodo / host. È ancora necessario eseguire il lavoro di replica e backup dei dati importanti.

Controller di replica

Una delle caratteristiche più importanti di Kubernetes è la sua capacità di gestire e scalare facilmente su e giù il numero di pod. In genere, nel tuo sistema avrai diversi tipi di pod e vorresti essere in grado di specificare quanti pod di ogni tipo dovrebbero essere attivi e in esecuzione.

Saluta i controller di replica. Un controller di replica ha un modello pod che definisce un gruppo di contenitori, un set di etichette per identificare questi pod e il numero di pod desiderati. Il controller di replica si assicura che il numero di pod in esecuzione identificati dalle sue etichette corrisponda sempre al numero desiderato. Se un pod termina, il controller di replica ne creerà immediatamente uno nuovo.

Esistono diversi casi d'uso interessanti supportati dai controller di replica, come ad esempio disponibilità elevata, ridimensionamento elastico e aggiornamenti continui. Ad esempio, è possibile aggiungere e rimuovere i pod dal dominio di un controller di replica modificandone l'etichetta.

I controller di replica sono specificati in un file YAML, ovviamente. Ecco un esempio: "apiVersion: tipo v1: ReplicationController

metadata: nome: quote-frontend spec: repliche: il selettore 2 # identifica l'insieme di pod che questo # controller di replica è responsabile della gestione del selettore: app: quote-api ruolo: frontend # podTemplate definisce il 'cookie cutter' utilizzato per la creazione di # nuovi pod quando necessario modello: metadati: etichette: # Importante: queste etichette devono corrispondere al selettore sopra # Il server api applica questo vincolo. app: quote-api ruolo: frontend spec: contenitori: - nome: quote-service immagine: g1g1 / quote-service env: - nome: GET_HOSTS_FROM # valore: valore dns: porte env: - containerPort: 8000 "Le specifiche del modello per Il contenitore del servizio preventivo utilizza l'immagine g1g1 / quote-servizio che ho spinto prima in Docker Hub ENV sezione in cui la condivisione delle informazioni tra i pod può avvenire tramite DNS o variabili di ambiente.

Per creare un controller di replica, digitare:

kubectl crea -f

Per visualizzare i controller di replica correnti nel cluster, digitare:

kubectl get rc

Dovresti vedere qualcosa come: CONTROLLER CONTAINER (S) IMAGE (S) SELECTOR REPLICAS AGE preventivo-frontend quote-servizio g1g1 / quote-servizio app = quote-api, ruolo = frontend 2 1h quote-store-controller master redis app = quote-api, ruolo = persistente -storaggio 1 1d ### Servizi

Un servizio espone il suo pod al resto del cluster e possibilmente esternamente tramite variabili di ambiente o DNS. Ad esempio, il servizio di quotazione è costituito da due tipi di pod: un pod di negozio redis e un pod front-end. Il contenitore front-end dovrebbe essere in grado di trovare il contenitore del negozio e i client dovrebbero essere in grado di colpire un singolo endpoint pubblico per accedere al servizio.

Il servizio Kubernetes è implementato in un altro file YAML. Ogni componente del sistema a cui è necessario accedere da altri componenti deve disporre di un proprio file di servizio. Ecco i due file di servizio per i componenti del servizio preventivo:

SRV-quote-frontend.yaml

apiVersione: tipo v1: metadati del servizio: nome: specifica preventivo-frontend: tipo: porte NodePort: - porta: 8000 # la porta che questo servizio deve servire su # il contenitore su ciascun pod a cui connettersi, può essere un nome # (ad es. 'www') o un numero (es. 80) targetPort: 80 protocollo: TCP # proprio come il selettore nel controller di replica, # ma questa volta identifica il set di pod per il carico del traffico # verso. selector: app: quote-api ruolo: frontend #### srv-quote-store.yaml apiVersione: tipo v1: metadati del servizio: nome: specifica quote-negozio: porte: - porta: 6379 # la porta che questo servizio deve servire su targetPort: 6379 # come il selettore nel controller di replica, # ma questa volta identifica il set di pod per il bilanciamento del traffico # verso. selector: app: quote-api ruolo: persistent-storage L'host e la porta di ciascun servizio sono resi disponibili per ogni contenitore nel cluster. Ad esempio, se si esegue una shell interattiva su uno dei contenitori frontend:

kubectl quote-frontend-4kyns exec -i -t bash

Quindi è possibile verificare che l'ambiente contenga le informazioni necessarie sull'host e sulla porta per connettersi all'archivio quote. root @ quote-frontend-4kyns: / quote-service # env | grep STORE QUOTE_STORE_PORT_6379_TCP_ADDR = 10.100.234.192 QUOTE_STORE_PORT_6379_TCP_PROTO = tcp QUOTE_STORE_SERVICE_PORT = 6379 QUOTE_STORE_PORT_6379_TCP_PORT = 6379 QUOTE_STORE_PORT = tcp: //10.100.234.192: 6379 QUOTE_STORE_PORT_6379_TCP = tcp: //10.100.234.192: 6379 QUOTE_STORE_SERVICE_HOST = 10.100.234.192 Semplicemente, per rinfrescare la memoria, questo è esattamente ciò che fa il frontend: redis_host = os.environ.get ('QUOTE_STORE_SERVICE_HOST', 'localhost') redis_server = redis.StrictRedis (host = redis_host, porta = 6379, db = 0) ## Conclusione

Docker e Kubernetes sono tecnologie entusiasmanti. Questo articolo ha a malapena scalfito la superficie di ciò che è possibile. I vantaggi sono enormi, ma l'infrastruttura, gli strumenti e le migliori pratiche sono ancora in evoluzione. Se sei anche lontanamente connesso a sistemi distribuiti su larga scala, ti consiglio di rimanere almeno in cima a queste tecnologie e di immergere idealmente le dita dei piedi e provare a usarle. Esistono molti modi per sperimentare e imparare senza la migrazione all'ingrosso dell'intera infrastruttura di produzione.

Per quanto riguarda Kubernetes, ci sono alcune altre alternative per la gestione e l'orchestrazione di più contenitori, come la composizione originale di Mesos e Docker. Credo che Kubernetes sia più architettonicamente valido, abbia molto slancio e sia migliore delle alternative.