În zilele noastre, două dintre instrumentele esențiale dintr-o cutie de instrumente pentru dezvoltatori sunt Docker și Kubernetes. Ambele le permit dezvoltatorilor să împacheteze aplicațiile în containere pentru a le rula în medii diferite.

Deși puteți realiza lucruri similare folosind ambele, în practică acestea diferă în ceea ce privește utilizarea lor.

În acest articol, veți obține o explicație despre Docker și Kubernetes și veți crea un exemplu de aplicație web NodeJS și o veți implementa folosind ambele tehnologii.

Ce este Docker?

Iată cum definesc oamenii Docker pe Wikipedia:

„Docker poate împacheta o aplicație și dependențele acesteia într-un container virtual care rulează pe orice server Linux. Aceasta permite aplicațiilor să ruleze într-o varietate de locații, cum ar fi locale, într-un cloud public și / sau într-un cloud privat. Docker folosește caracteristicile de izolare a resurselor kernel-ului Linux (cum ar fi cgroup-urile și spațiile de nume ale kernel-urilor) și un sistem de fișiere compatibil cu uniunea (cum ar fi OverlayFS) pentru a permite containerelor să ruleze într-o singură instanță Linux, evitând costurile de pornire și întreținere a mașinilor virtuale . ” – Wikipedia

Pe scurt, Docker este o platformă pentru a rula containere imuabile încapsulate cu performanțe apropiate de cele native pe o mașină dorită.

Există alternative la Docker care au proprietăți similare precum LC, rkt sau containerd. Docker este doar cel mai popular.

Ce este Kubernetes?

Iată cum definesc oamenii Kubernetes pe Wikipedia:

Kubernetes definește un set de blocuri de construcție („primitive”), care furnizează în mod colectiv mecanisme care implementează, întrețin și scalează aplicații bazate pe CPU, memorie sau valori personalizate. Kubernetes este cuplat slab și extensibil pentru a satisface diferite sarcini de lucru. Această extensibilitate este asigurată în mare parte de API-ul Kubernetes, care este utilizat de componentele interne, precum și de extensiile și containerele care rulează pe Kubernetes. Platforma își exercită controlul asupra resurselor de calcul și stocare definind resursele ca obiecte, care pot fi apoi gestionate ca atare. – Wikipedia

Pe scurt, Kubernetes gestionează mai multe gazde și implementează containere pe acestea. Cea mai utilizată tehnologie de container pentru a rula containere pe aceste gazde este Docker.

A spus destul, să ne murdărim mâinile și să experimentăm noi înșine diferențele.

Cum să construiți și să implementați o aplicație web NodeJS utilizând Docker și Kubernetes.

Dacă nu ați instalat încă Docker, ar trebui să faceți acest lucru. Verificați și instalați Docker de la https://docs.docker.com/get-docker/.

$ docker --version

Docker version 19.03.13, build 4484c46d9d

Să creăm un fișier pachet NodeJS și să adăugăm o singură dependență de server web numită Expres.

// file: package.json

{
  "name": "docker-vs-k8s",
  "version": "1.0.0",
  "description": "",
  "main": "server.js",
  "scripts": {
    "test": "echo "Error: no test specified" && exit 1",
    "start": "node server.js"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "express": "^4.17.1"
  }
}

În plus, trebuie să pornim serverul web și să definim un singur punct final.

// file: server.js

const express = require('express');

// Constants
const PORT = 8080;
const HOST = '0.0.0.0';

// App
const app = express();
app.get('/', (req, res) => {
  res.send('Hello World');
});

app.listen(PORT, HOST);
console.log(`Running on http://${HOST}:${PORT}`);

FYI: Este bine să săriți pasul următor dacă nu aveți instalat NodeJS. Pasul următor va utiliza o imagine Docker care vine cu un mediu de nod gata de utilizat.

Dacă aveți NodeJS instalat pe computerul dvs. local, atunci puteți încerca să rulați aplicația cu NodeJS simplu.

$ npm install
$ node server.js 

Running on http://0.0.0.0:8080

Deschis http: // localhost: 8080și veți vedea răspunsul dvs. Hello World.

Să găsim o imagine de bază Docker pentru a rula aplicația noastră

Publicul Docker Hub este o sursă excelentă. Dacă căutați „nod” veți găsi rapid un imag care a fost folosit de peste 1 miliard de ori.

Un container trebuie asamblat de la fundația sa. Pornim de la o imagine de bază care conține un mediu NodeJS gata de utilizat. De obicei, se bazează pe o imagine simplă Linux. Copiem toate fișierele necesare în container.

Ulterior, executăm comenzi, de exemplu, preluăm toate dependențele necesare. Ultimul pas este să spuneți containerului ce comandă să ruleze la pornirea containerului.

# file: 'Dockerfile'

# lts-alpine means long term support and alpine is a very small Linux 
# distribution that is a lot smaller than the default one (node:lts).
# smaller images mean faster builds and startup time that is very handy 
# when it comes to scaling containers for production up and down
FROM node:lts-alpine

# Create app directory
WORKDIR /usr/src/app

# Install app dependencies
COPY package*.json ./

# Install all dependencies
RUN npm install

# Copy sources
COPY server.js server.js

CMD [ "node", "server.js" ]

Acum, să construim imaginea:

docker build -t node-web-app .

Putem rula containerul Docker prin:

$ docker run --name my_container -p 8080:8080 node-web-app

Running on http://0.0.0.0:8080

Deschis http: // localhost: 8080 în browserul dvs. și veți vedea pagina Hello World. De data aceasta, rulează izolat într-un container.

Nici nu aveți nevoie de NodeJS sau de altceva pentru a construi și a rula acest container. Totul este încapsulat și, datorită naturii Docker, rulează cu performanțe native.

Să oprim acest container care ar putea rula în continuare în fundal:

$ docker rm -f my_container

FYI: Aproape 100% performanță nativă este adevărată numai pentru gazdele Linux. Pentru Mac OS și Windows, sunt necesare unele traduceri și virtualizări care vin cu unele degradări ale performanței. Pentru dezvoltare, ar trebui să fie ok. Cel mai important, serverele de producție rulează de obicei un Linux nativ care joacă frumos cu Docker.

În continuare, să folosim containerul nostru construit anterior într-un cluster Kubernetes. În acest tutorial, ne vom concentra pe un cluster local. Dacă mergeți la distanță, este foarte asemănător.

Într-o configurare la distanță, trebuie să vă împingeți imaginea într-un registru public, care permite clusterului dvs. la distanță să acceseze imaginea.

Aș putea scrie o altă postare de blog despre asta în viitor, dacă oamenii o vor solicita.

Rulați aplicația dvs. web în Kubernetes

Docker-ul dvs. vine deja cu o integrare Kubernetes. Deschideți aplicația Docker, accesați Setări -> Kubernetes și activați Kubernetes.

Aplicarea modificării poate dura ceva timp. Sunteți gata imediat ce starea Kubernetes din bara de jos a aplicației Docker este verde.

Dacă aveți probleme, mergeți la depanare (pictograma micuță eroare din colțul din dreapta sus) și apăsați reset la valorile implicite din fabrică. Ulterior, Docker ar trebui să repornească și trebuie să activați din nou Kubernetes.

Să instalăm kubectl, unul dintre cele mai importante instrumente pentru a interacționa cu clusterul dvs. Kubernetes. Urmați acest ghid pentru instalare: https://kubernetes.io/docs/tasks/tools/install-kubectl/.

Acum, putem verifica dacă totul este configurat corect:

$ kubectl get services

NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 3m14s

Să implementăm containerul Docker în clusterul nostru:

# file 'application/deployment.yaml'

apiVersion: apps/v1
kind: Deployment
metadata:
  name: node-web-app
spec:
  selector:
    matchLabels:
      app: node-web-app
  replicas: 2 # tells deployment to run 2 pods matching the template
  template:
    metadata:
      labels:
        app: node-web-app
    spec:
      containers:
        - name: node-web-app
          image: node-web-app
          
          # only use this to for local development
          # we never pushed our image to a remote registry
          # and by default Kubernetes pulls images
          # this property forces kubernetes to always use 
          # the local image that is not a good practice in production
          imagePullPolicy: Never
          ports:
            - containerPort: 8080

Deployment.yaml este un fișier care descrie ce implementare trebuie să faceți. Îl putem executa prin:

$ kubectl apply -f application/deployment.yaml

deployment.apps/node-web-app created

și verificați dacă containerele rulează:

$ kubectl get pods

NAME READY STATUS RESTARTS AGE
node-web-app-6788cfd6cc-bcbb2 1/1 Running 0 3s
node-web-app-6788cfd6cc-t5t6w 1/1 Running 0 3s

Kubernetes gestionează un cluster care conține o singură gazdă, care este mașina noastră locală. Pe un cluster la distanță, ar putea exista sute de noduri care găzduiesc implementări diferite.

A implementat două containere în mediul nostru. Aceste containere rulează într-o rețea izolată. Altfel, nu ar fi posibil să expunem același port de două ori.

Deci, cum putem accesa containerul real? Puteți accesa un container implementat definind un așa-numit serviciu. Fiecare aplicație publică are nevoie de un serviciu în față care să definească portul public expus.

# file 'application/service.yaml'

apiVersion: v1
kind: Service
metadata:
  name: my-service-for-my-webapp
spec:
  type: LoadBalancer
  selector:
    app: my-example-app
  ports:
    - protocol: TCP
      port: 80
      targetPort: 8080

Hartăm portul container 8080 la un port public 80 disponibil. Serviciul acționează ca un echilibru de sarcină. Distribuie cereri între containere.

Să ne implementăm serviciul:

$ kubectl apply -f ./application/service.yaml 

service/my-service-for-my-webapp created

putem verifica dacă serviciul nostru rulează:

$ kubectl describe svc my-service-for-my-webapp

Name: my-service-for-my-webapp
Namespace: default
Labels: <none>
Annotations: Selector: app=my-example-app
Type: LoadBalancer
IP: 10.104.18.24
LoadBalancer Ingress: localhost
Port: <unset> 80/TCP
TargetPort: 8080/TCP
NodePort: <unset> 32114/TCP
Endpoints: 10.1.0.17:8080,10.1.0.18:8080
Session Affinity: None
External Traffic Policy: Cluster
Events: <none>

Rezultatul este foarte descriptiv și confirmă ceea ce vrem să realizăm. Folosește puncte finale de la două containere implementate (așa-numitele pod-uri în Kubernetes).

Acum, puteți deschide http: // localhost: 80

Asta e! Ați creat un container Docker și l-ați folosit în clusterul dvs. Kubernetes. Această configurație este puternică și este fundamentul pentru multe produse și companii scalabile în zilele noastre.

Terminand

Să ne aranjăm spațiul de experimentare:

$ kubectl delete -f ./application/service.yaml 

service "my-service-for-my-webapp" deleted

$ kubectl delete -f application/deployment.yaml

deployment.apps "node-web-app" deleted

Pentru a menține resursele gratuite ale dispozitivului nostru, ar trebui să oprim și funcția Kubernetes din Docker.

Sper că ți-a plăcut acest exemplu practic. Motivați-vă către Google, verificați alte exemple, implementați containere, conectați-le și folosiți-le.

Veți afla multe funcții interesante în viitor, care vă permit să expediați aplicația către producție într-un mod fără efort, reutilizabil și scalabil.

Ca întotdeauna, apreciez orice feedback și comentarii. Spune mulțumesc urmărindu-mă pe Twitter și împărtășind această postare altora. Scriu postări pe blog pentru a-mi împărtăși cunoștințele într-un mod foarte „practic” de a stimula motivația, dorința și emoția.

Fericit andocare!

Referințe: