Inleiding
Docker is een containerplatform dat een lichtgewicht, gevirtualiseerde, draagbare, softwaregedefinieerde gestandaardiseerde omgeving is. Het stelt de software in staat om geïsoleerd te draaien van andere software die op de fysieke hostmachine draait. Docker is een bepalend onderdeel van het Continuous Development en Integration-aspect van softwareontwikkeling. Het biedt een lichtgewicht alternatief voor virtuele machines en stelt ontwikkelaars in staat om te genieten van gedistribueerde applicatiearchitecturen. Voor een grondig overzicht van het Docker-ecosysteem, bekijk dit artikel.
Het proces van het bouwen van een applicatie met Docker begint met een ontwikkelaar die een image voor hun applicatie maakt. Vervolgens wordt de image geïmplementeerd in een container. De image bevat bepalende componenten van een applicatie, zoals de applicatiecode, bibliotheken, configuratiebestanden, omgevingsvariabelen en de runtime-omgeving. De image standaardiseert de omgeving binnen een container, wat containerisatie de draagbaarheidskarakteristieken geeft. Node.js is een open-source, cross-platform backend JavaScript-runtime-omgeving die JavaScript-code buiten een webbrowser kan uitvoeren. Het is gebouwd op de V8 JavaScript Engine. Express.js is een minimalistisch backend JavaScript-framework dat bovenop Node.js draait.
In deze handleiding maken we een image voor een website die op het Express-framework draait. We gebruiken Bootstrap, een frontend-bibliotheek, om de frontend er beter uit te laten zien. Zodra we de image hebben gemaakt, bouwen we een container en pushen we deze naar Docker Hub. Met Docker Hub kunnen ontwikkelaars gecontaineriseerde applicaties hosten voor eenvoudige implementatie in elke Docker-omgeving. Zodra je container op Docker Hub wordt gehost, zullen we deze pullen en een andere image bouwen die daadwerkelijk onze website zal serveren.
Vereisten
Dit wordt een praktische handleiding. Je moet een omgeving creëren waarin je de stappen kunt volgen.
- Je moet beschikken over een installatie van Ubuntu 20.04 als je initiële besturingsomgeving en een non-root gebruiker met sudo-privileges aanmaken. Log in met de non-root gebruiker en ga verder met de volgende stappen.
- Je moet Docker installeren. Volg stappen 1, 2, 3 en 4 van onze handleiding over hoe je Docker installeert en gebruikt op Ubuntu. Dit zou moeten werken voor elke Ubuntu-distributie.
- Maak een Docker Hub-account aan als je dat nog niet hebt. Je kunt deze link volgen voor de Docker Hub Snelstartgids.
- Installeer Node.js and NPM. NPM is een JavaScript-pakketbeheerder. Je kunt deze instructies volgen voor het installeren van Node en npm.
Stap 1: Applicatie-afhankelijkheden configureren
Je moet de broncode van je applicatie maken voordat je de image kunt maken. De broncode van de applicatie bevat code, statische inhoud en afhankelijkheden die naar de container worden gekopieerd. Begin met het maken van een map voor je project in de thuismap van de non-root gebruiker. We noemen deze node_express, maar het staat je vrij om een mapnaam te gebruiken die je zelf wilt:
|
1 |
mkdir node_express |
Ga vervolgens naar deze map:
|
1 |
cd node_express |
Dit wordt de hoofdmap van je applicatie. Een node.js applicatie verwacht een package.json bestand in de hoofdmap. Npm gebruikt dit bestand om te bepalen welke afhankelijkheden je applicatie nodig heeft. Voer de volgende opdracht in om dit bestand te maken:
|
1 |
nano package.json |
Voeg daarna het volgende codefragment toe aan het bestand. Je kunt de naam, auteur, beschrijving en het startbestand naar wens aanpassen:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
{ "name": "node-express-docker-image", "version": "1.0.0", "description": "Nodejs Express Docker Image Example", "author": "hackins", "main": "index.js", "license": "ISC", "keywords": [ "nodejs", "express", "bootstrap" ], "dependencies": { "express": "^4.17.1" } } |
Zoals je kunt zien, specificeert dit bestand de projectnaam, versie, auteur en licentie waaronder de applicatiecode zal worden gedeeld. Het wordt aanbevolen om een korte en beschrijvende naam voor je project te gebruiken om duplicaten te voorkomen in de npm registry. We hebben de ISC-licentie voor het project gespecificeerd, die het gratis kopiëren, wijzigen of distribueren van de applicatiecode toestaat.
Het belangrijkste is dat je let op de volgende richtlijnen in het bestand:
- “
main”: deze richtlijn specificeert het startpunt van de applicatie, dat we hebben ingesteld als index.js. We zullen dit bestand binnenkort aanmaken. - “
dependencies”: deze richtlijn specificeert de applicatie-afhankelijkheden die uit de npm registry worden opgehaald wanneer we hetnpm-commando uitvoeren, in ons geval willen we Express-versie 4.17.1 en hoger.
Je kunt het bestand nu opslaan door op Ctrl + O te drukken. Sluit het bestand vervolgens door op Ctrl + X te drukken. Vervolgens installeren we de afhankelijkheden door het volgende commando uit te voeren:
|
1 |
npm install |
Het commando installeert de applicatie-afhankelijkheden die zijn gespecificeerd in het package.json bestand in de node_modules mappen. Deze zijn automatisch aangemaakt toen je het commando voor het eerst uitvoerde. Nu de applicatie-afhankelijkheden zijn geïnstalleerd, kun je beginnen met het toevoegen van de applicatiecode.
Stap 2: Je applicatiecodebestanden toevoegen
We gaan een eenvoudige receptenwebsite maken, met dank aan allrecipes. Het belangrijkste startpunt voor de applicatie is het index.js bestand. We voegen een views map toe die de verschillende pagina's en statische bestanden van het project zal bevatten. De website krijgt een landingspagina met inleidende informatie en links naar enkele recepten.
De code voor onze landingspagina wordt geplaatst in het home.html bestand. Maak eerst het index.js bestand aan door het volgende commando in te voeren:
|
1 |
nano index.js |
Voeg de volgende code toe, die een Express-applicatie importeert en aanmaakt. Het specificeert ook het Router-object, de basismap en de poort waarop deze app wordt aangeboden:
|
1 2 3 4 5 6 |
const express = require('express'); const app = express(); const router = express.Router(); const path = __dirname + '/views/'; const port = 8090; |
require is een JavaScript-functie die een module laadt. In dit geval laden we de express-module. Vervolgens gebruiken we de geïmporteerde module om de express- en router-objecten te maken. Het router-object voert de routeringsfuncties van de app uit door te reageren op HTTP-methode-aanroepen die we in de loop van de tutorial aan dit object zullen toevoegen.
We hebben ook path en port. De constante path definieert de basismap voor de code. In ons geval is dat de views submap binnen de hoofdmap van het project. De port specificeert de poort waarop de express-app moet luisteren, in ons voorbeeld hebben we deze ingesteld op 8090.
Zodra we de constanten hebben, kunnen we enkele routes voor de applicatie specificeren met behulp van het router object. Voeg de volgende code toe aan het index.js bestand om de routes te specificeren:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
router.use(function (req,res,next) { console.log('/' + req.method); next(); }); router.get('/', function(req,res){ res.sendFile(path + 'home.html'); }); router.get('/lasagna', function(req,res){ res.sendFile(path + 'lasagna.html'); }); router.get('/guacamole', function(req,res){ res.sendFile(path + 'guacamole.html'); }); router.get('/banana-bread', function(req,res){ res.sendFile(path + 'banana_bread.html'); }); |
Je kunt middleware toevoegen aan routes met behulp van de router.use functie. In dit geval voegen we een functie toe die de verzoeken van de router logt voordat ze worden doorgegeven aan de applicatieroutes. Een GET verzoek naar de basis van de applicatie zal een home.html pagina. Vervolgens hebben we pagina's toegevoegd voor drie recepten die ook zullen worden opgehaald met behulp van het GET-verzoek naar de specifieke receptpagina.
Voeg ten slotte de volgende code toe om de router middleware en de statische bestanden van de applicatie te koppelen. Geef daarnaast de express-applicatie de opdracht om te luisteren op poort 8090:
|
1 2 3 4 5 6 |
app.use(express.static(path)); app.use('/', router); app.listen(port, function () { console.log('Nodejs Express voorbeeld-app luistert op poort ' + port) }) |
Je complete index.js-bestand zou er als volgt uit moeten zien:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
const express = require('express'); const app = express(); const router = express.Router(); const path = __dirname + '/views/'; const port = 8090; router.use(function (req,res,next) { console.log('/' + req.method); next(); }); router.get('/', function(req,res){ res.sendFile(path + 'home.html'); }); router.get('/lasagna', function(req,res){ res.sendFile(path + 'lasagna.html'); }); router.get('/guacamole', function(req,res){ res.sendFile(path + 'guacamole.html'); }); router.get('/banana-bread', function(req,res){ res.sendFile(path + 'banana_bread.html'); }); app.use(express.static(path)); app.use('/', router); app.listen(port, function () { console.log('Nodejs Express voorbeeld-app luistert op poort ' + port) }) |
Je kunt het bestand nu opslaan en sluiten. De volgende stap is het toevoegen van de statische webpagina's aan de views-map. Begin met het invoeren van de volgende opdracht om de map aan te maken:
|
1 |
mkdir views |
Voer de volgende opdracht in om het home.html-landingspaginabestand te openen:
|
1 |
nano views/home.html |
Voeg de volgende code toe aan het bestand. De code importeert Bootstrap en biedt websitebezoekers wat informatie over waar de website over gaat:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 |
<!DOCTYPE html> <html lang="nl"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="description" content=""> <meta name="author" content="Mark Otto, Jacob Thornton en Bootstrap-bijdragers"> <meta name="generator" content="Hugo 0.80.0"> <title>Geweldige recepten</title> <!-- Bootstrap-basis-CSS --> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta2/dist/css/bootstrap.min.css" rel="stylesheet" crossorigin="anonymous"> <link href="css/custom.css" rel="stylesheet"> </head> <body> <nav class="navbar navbar-dark bg-dark navbar-static-top navbar-expand-md"> <div class="container"> <button type="button" class="navbar-toggler collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false"> <span class="sr-only">Navigatie in-/uitschakelen</span> </button> <a class="navbar-brand" href="#">Geweldige recepten</a> <div class="collapse navbar-collapse justify-content-center" id="bs-example-navbar-collapse-1"> <ul class="nav navbar-nav justify-content-center"> <li class="active nav-item"> <a href="/" class="nav-link">Home</a> </li> <li class="nav-item"> <a href="/lasagna" class="nav-link">Lasagne</a> </li> <li class="nav-item"> <a href="/guacamole" class="nav-link">Guacamole</a> </li> <li class="nav-item"> <a href="/banana-bread" class="nav-link">Bananenbrood</a> </li> </ul> </div> </div> </nav> <main> <section class="py-5 text-center container"> <div class="row py-lg-5"> <div class="col-lg-6 col-md-8 mx-auto"> <h1 class="fw-light">Geweldig recept</h1> <p class="lead text-muted"> Vind en deel dagelijkse kookinspiratie uit deze geweldige recepten. Ontdek recepten, koks, video's en handleidingen op basis van het eten waar je van houdt en de vrienden die je volgt. <br /> <em>(Niets ernstigs, dit is gewoon voor onze demo node-express-docker image-app)</em> </p> </div> </div> </section> </main> </body> </html> |
Naast het importeren van Bootstrap voegt de pagina ook een eenvoudig navigatiemenu toe om ons te helpen door de pagina's te navigeren en terug te keren naar de landingspagina. We hebben ook een regel toegevoegd om ons aangepaste CSS-bestand te importeren:
|
1 |
<link href="css/custom.css" rel="stylesheet"> |
We zullen dit bestand later gebruiken om aangepaste styling aan de applicatie toe te voegen. Laten we nu de drie pagina's voor de recepten maken. We beginnen eerst met het maken van de lasagne-pagina. Open het bestand met de nano-editor met behulp van de volgende opdracht:
|
1 |
nano views/lasagna.html |
Voeg de volgende code toe aan het geopende bestand. Dit bestand importeert Bootstrap, het custom.css-bestand, specificeert een navigatiemenu en biedt wat informatie over het lasagnerecept:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 |
<!DOCTYPE html> <html lang="nl"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="description" content=""> <meta name="author" content="Mark Otto, Jacob Thornton en Bootstrap-bijdragers"> <meta name="generator" content="Hugo 0.80.0"> <title>Lasagnerecept</title> <!-- Bootstrap core CSS --> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta2/dist/css/bootstrap.min.css" rel="stylesheet" crossorigin="anonymous"> <link href="css/custom.css" rel="stylesheet"> </head> <body> <nav class="navbar navbar-dark bg-dark navbar-static-top navbar-expand-md"> <div class="container"> <button type="button" class="navbar-toggler collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false"> <span class="sr-only">Navigatie in-/uitschakelen</span> </button> <a class="navbar-brand" href="#">Geweldige recepten</a> <div class="collapse navbar-collapse justify-content-center" id="bs-example-navbar-collapse-1"> <ul class="nav navbar-nav justify-content-center"> <li class="active nav-item"> <a href="/" class="nav-link">Home</a> </li> <li class="nav-item"> <a href="/lasagna" class="nav-link">Lasagne</a> </li> <li class="nav-item"> <a href="/guacamole" class="nav-link">Guacamole</a> </li> <li class="nav-item"> <a href="/banana-bread" class="nav-link">Bananenbrood</a> </li> </ul> </div> </div> </nav> <main> <section class="py-5 text-center container bg-light"> <div class="row py-lg-5"> <div class="col-lg-6 col-md-8 mx-auto"> <h1 class="fw-light">Het beste lasagnerecept</h1> <p class="lead text-muted"> Dit is de beste lasagne die je ooit zult maken. <br /> <em>(Niets ernstigs, dit is alleen voor onze demo node-express-docker image-app)</em> </p> <h3>Ingrediënten</h3> <ul class="list-group"> <li class="list-group-item">1 pond zoete Italiaanse worst</li> <li class="list-group-item">¾ pond mager rundergehakt</li> <li class="list-group-item">½ kopje gesnipperde ui</li> <li class="list-group-item">2 teentjes knoflook, geperst</li> <li class="list-group-item">1 blik (28 ounce) geplette tomaten</li> <li class="list-group-item">2 blikjes (6 ounce) tomatenpuree</li> <li class="list-group-item">2 blikjes (6,5 ounce) tomatensaus</li> <li class="list-group-item">½ kopje water</li> <li class="list-group-item">2 eetlebels witte suiker</li> <li class="list-group-item">1 ½ theelepel gedroogde basilicumblaadjes</li> <li class="list-group-item">½ theelepel venkelzaad</li> <li class="list-group-item">1 theelepel Italiaanse kruiden</li> <li class="list-group-item">1 ½ theelepel zout, verdeeld, of naar smaak</li> <li class="list-group-item">¼ theelepel gemalen zwarte peper</li> <li class="list-group-item">4 eetlebels gehakte verse peterselie</li> <li class="list-group-item">12 lasagnebladen</li> <li class="list-group-item">16 ounces ricottakaas</li> <li class="list-group-item">1 ei</li> <li class="list-group-item">¾ pond mozzarellakaas, in plakjes</li> <li class="list-group-item">¾ kopje geraspte Parmezaanse kaas</li> </ul> </div> </div> </section> </main> </body> </html> |
Laten we hetzelfde proces volgen om een bestand te maken voor de guacamole receptpagina. Open het bestand met nano door de volgende opdracht uit te voeren:
|
1 |
nano views/guacamole.html |
Voeg vervolgens deze code toe aan het bestand:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 |
<!DOCTYPE html> <html lang="nl"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="description" content=""> <meta name="author" content="Mark Otto, Jacob Thornton, and Bootstrap contributors"> <meta name="generator" content="Hugo 0.80.0"> <title>Guacamole-recept</title> <!-- Bootstrap-basis-CSS --> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta2/dist/css/bootstrap.min.css" rel="stylesheet" crossorigin="anonymous"> <link href="css/custom.css" rel="stylesheet"> </head> <body> <nav class="navbar navbar-dark bg-dark navbar-static-top navbar-expand-md"> <div class="container"> <button type="button" class="navbar-toggler collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false"> <span class="sr-only">Navigatie in-/uitschakelen</span> </button> <a class="navbar-brand" href="#">Geweldige recepten</a> <div class="collapse navbar-collapse justify-content-center" id="bs-example-navbar-collapse-1"> <ul class="nav navbar-nav justify-content-center"> <li class="active nav-item"> <a href="/" class="nav-link">Home</a> </li> <li class="nav-item"> <a href="/lasagna" class="nav-link">Lasagne</a> </li> <li class="nav-item"> <a href="/guacamole" class="nav-link">Guacamole</a> </li> <li class="nav-item"> <a href="/banana-bread" class="nav-link">Bananenbrood</a> </li> </ul> </div> </div> </nav> <main> <section class="py-5 text-center container bg-light"> <div class="row py-lg-5"> <div class="col-lg-6 col-md-8 mx-auto"> <h1 class="fw-light">Het beste guacamole-recept</h1> <p class="lead text-muted"> Je kunt deze avocadosalade glad of met stukjes maken, afhankelijk van je smaak. <br /> <em>(Niets ernstigs, dit is alleen voor onze demo node-express-docker image-app)</em> </p> <h3>Ingrediënten</h3> <ul class="list-group"> <li class="list-group-item">3 avocado's - geschild, ontpit en geprakt</li> <li class="list-group-item">1 limoen, uitgeperst</li> <li class="list-group-item">1 theelepel zout</li> <li class="list-group-item">½ kopje gesnipperde ui</li> <li class="list-group-item">3 eetlepels fijngehakte verse koriander</li> <li class="list-group-item">2 roma (pruim)tomaten, in blokjes gesneden</li> <li class="list-group-item">1 theelepel fijngehakte knoflook</li> <li class="list-group-item">1 snufje gemalen cayennepeper (optioneel)</li> </ul> </div> </div> </section> </main> </body> </html> |
Laten we tot slot het bestand banana_bread.html maken door de volgende opdracht in te voeren:
|
1 |
nano views/banana_bread.html |
Voeg vervolgens de volgende HTML-code toe aan het bestand:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 |
<!DOCTYPE html> <html lang="nl"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="description" content=""> <meta name="author" content="Mark Otto, Jacob Thornton en Bootstrap-bijdragers"> <meta name="generator" content="Hugo 0.80.0"> <title>Recept voor bananenbrood</title> <!-- Bootstrap-basis-CSS --> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta2/dist/css/bootstrap.min.css" rel="stylesheet" crossorigin="anonymous"> <link href="css/custom.css" rel="stylesheet"> </head> <body> <nav class="navbar navbar-dark bg-dark navbar-static-top navbar-expand-md"> <div class="container"> <button type="button" class="navbar-toggler collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false"> <span class="sr-only">Navigatie in-/uitschakelen</span> </button> <a class="navbar-brand" href="#">Geweldige recepten</a> <div class="collapse navbar-collapse justify-content-center" id="bs-example-navbar-collapse-1"> <ul class="nav navbar-nav justify-content-center"> <li class="active nav-item"> <a href="/" class="nav-link">Home</a> </li> <li class="nav-item"> <a href="/lasagna" class="nav-link">Lasagne</a> </li> <li class="nav-item"> <a href="/guacamole" class="nav-link">Guacamole</a> </li> <li class="nav-item"> <a href="/banana-bread" class="nav-link">Bananenbrood</a> </li> </ul> </div> </div> </nav> <main> <section class="py-5 text-center container bg-light"> <div class="row py-lg-5"> <div class="col-lg-6 col-md-8 mx-auto"> <h1 class="fw-light">Het beste recept voor bananenbrood</h1> <p class="lead text-muted"> Waarom concessies doen aan de bananensmaak? Dit bananenbrood is smeuïg en heerlijk met heel veel bananensmaak! Vrienden en familie zijn dol op mijn recept en zeggen dat het veruit het beste is! Het is heerlijk geroosterd!! Geniet ervan! <br /> <em>(Niets ernstigs, dit is alleen voor onze demo node-express-docker image app)</em> </p> <h3>Ingrediënten</h3> <ul class="list-group"> <li class="list-group-item">2 kopjes bloem</li> <li class="list-group-item">1 theelepel baking soda</li> <li class="list-group-item">¼ theelepel zout</li> <li class="list-group-item">½ kopje boter</li> <li class="list-group-item">¾ kopje bruine suiker</li> <li class="list-group-item">2 eieren, geklopt</li> <li class="list-group-item">2⅓ kopjes geprakte overrijpe bananen</li> </ul> </div> </div> </section> </main> </body> </html> |
Nu hebben we alle pagina's gemaakt. Als je het nog weet, moeten we het css/custom.css-bestand toevoegen. Voer de volgende opdracht uit om de map aan te maken:
|
1 |
mkdir views/css |
Maak vervolgens het bestand aan en open het in de nano-editor met de opdracht:
|
1 |
nano views/css/custom.css |
Je kunt meer CSS-code toevoegen om je website naar wens op te maken. Laten we voor de kortheid het volgende codefragment aan het bestand toevoegen:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 |
.bd-placeholder-img { font-size: 1.125rem; text-anchor: middle; -webkit-user-select: none; -moz-user-select: none; user-select: none; } @media (min-width: 768px) { .bd-placeholder-img-lg { font-size: 3.5rem; } } |
Sla het bestand op en sluit het als je klaar bent.
Je kunt de applicatie starten omdat we nu de broncode van de applicatie en de projectafhankelijkheden hebben geïnstalleerd.
We had set the app to listen on a port 8090, voer de volgende opdracht uit om de firewall opdracht te geven verkeer via deze poort toe te staan. Als je een andere poort had opgegeven, vervang dan het poortnummer in de opdracht:
|
1 |
sudo ufw allow 8090 |
Nu kun je de applicatie starten. Maar zorg er eerst voor dat je je in de hoofdmap van het project bevindt door de volgende opdracht uit te voeren:
|
1 |
cd ~/node_express |
Start de applicatie met node index.js. Als je een ander startpunt hebt opgegeven, vervang dit dan door jouw startpunt:
|
1 |
node index.js |
Als je met je browser navigeert naar http://your_public_server_ip:8090, zie je de bestemmingspagina van Recepten zoals gedefinieerd:
Je kunt de links naar de verschillende recepten in de navigatie zien. Laten we op een paar klikken. Hieronder hebben we de Lasagne receptpagina:
And hier hebben we de Guacamole receptpagina:
Tot zover heb je je applicatie gemaakt en getest of deze naar verwachting werkt. Je kunt de server afsluiten door op Ctrl + C te drukken en doorgaan met het maken van de Dockerfile. Dockerfiles helpen bij de schaalbaarheid door het mogelijk te maken om een instantie van een applicatie opnieuw te maken wanneer dat nodig is.
Stap 3: De Dockerfile maken
Docker leest de instructies die zijn gespecificeerd in een Dockerfile bij het bouwen van images. Het specificeert de runtime-omgeving van een applicatie. Hierdoor helpt het ontwikkelaars discrepanties met afhankelijkheden of veranderende runtime-versies te voorkomen. Voer de volgende opdracht in om de Dockerfile aan te maken:
|
1 |
nano Dockerfile |
Een Docker-image wordt gemaakt met behulp van verschillende lagen van images die op elkaar voortbouwen. Je begint met het toevoegen van een base-image om het startpunt voor de app te vormen.
Aangezien de applicatie verwacht te draaien in een node.js-omgeving, beginnen we met het toevoegen van de node:10-alpine-image voor node.js. Momenteel, op het moment dat we deze handleiding schrijven, is dit de aanbevolen LTS-versie van Node.js. We hebben voor deze specifieke image gekozen omdat deze is afgeleid van het Alpine Linux-project. Hierdoor helpt het om onze image-grootte tot een minimum te beperken. Er zijn verschillende image-varianten onder de Docker Hub Node images-pagina waaruit je kunt kiezen, afhankelijk van je behoeften.
Voeg de volgende code toe om de base-image van de applicatie in te stellen met behulp van de FROM-instructie:
|
1 |
FROM node:10-alpine |
Deze image bevat Node.js en npm. Elke Dockerfile moet beginnen met een FROM-instructie. De Docker node-image wordt standaard geleverd met een niet-root node-gebruiker die je kunt gebruiken om je applicatiecontainer als root uit te voeren. Docker-beveiliging raadt aan om de containers niet als root uit te voeren en de privileges te beperken tot alleen die welke vereist zijn om de bronnen uit te voeren.
In dat geval gebruiken we de home-directory van de node-gebruiker als de werkdirectory voor de applicatie en als de gebruiker binnen de container. Je kunt deze Docker Node image best practices-handleiding raadplegen voor meer informatie.
We maken de node_modules subdirectory aan binnen /home/node samen met de app-directory om de machtigingen voor de applicatiecode te stroomlijnen. Het aanmaken van deze directories zorgt ervoor dat ze de juiste machtigingen hebben wanneer we de npm install-opdracht lokaal binnen de containers uitvoeren. Zodra je de directories hebt aangemaakt, moet je het eigendom ervan instellen op de node-gebruiker. We doen dit binnen de Dockerfile door de volgende regel toe te voegen:
|
1 |
mkdir -p /home/node/app/node_modules && chown -R node:node /home/node/app |
Vervolgens stel je de werkdirectory in door de volgende regel toe te voegen:
|
1 |
WORKDIR /home/node/app |
Het is een goed idee om altijd de WORKDIR in te stellen, zodat Docker er niet standaard een hoeft aan te maken.
Voeg de volgende regel toe om de package.json and package-lock.json-bestanden te kopiëren:
|
1 |
COPY package*.json ./ |
Het wordt aanbevolen om de COPY-instructie toe te voegen voordat je npm install of de broncode van de applicatie kopieert. Hiermee kun je profiteren van het caching-mechanisme van Docker. Tijdens het bouwproces controleert Docker of er voor elke instructie een gecachte laag is. Dit betekent dat als je het package.json-bestand niet hebt gewijzigd, Docker de bestaande image-laag zal gebruiken en het opnieuw installeren van node-modules vermijdt, wat zorgt voor snellere bouwprocessen.
Voordat je npm install uitvoert, voeg je de volgende regel toe om de gebruiker over te schakelen naar node om ervoor te zorgen dat alle applicatiebestanden en de node_modules-directory eigendom zijn van de niet-root node-gebruiker:
|
1 |
USER node |
Onze container is nu klaar om de npm install-opdracht uit te voeren. Voeg de volgende regel toe aan de Dockerfile:
|
1 |
RUN npm install |
Zodra node_modules zijn geïnstalleerd, voeg je de volgende regel toe die Docker vertelt om de applicatiecode naar de applicatiedirectory op de container te kopiëren met de juiste machtigingen en eigendom, d.w.z. de niet-root node-gebruiker:
|
1 |
COPY --chown=node:node . . |
De laatste stap is het blootstellen van de poort 8090 op de container, zoals we hadden gedefinieerd in ons startbestand index.js:
|
1 2 |
EXPOSE 8090 CMD [ "node", "index.js" ] |
EXPOSE stelt in welke poorten op de container open zullen zijn tijdens runtime. CMD voert de opdracht uit om de applicatie te starten, in dit geval node index.js.
Je mag maar één CMD-instructie in de Dockerfile hebben, aangezien alleen de laatste effect heeft. Bekijk de Dockerfile-referentiedocumentatie voor een lijst met dingen die je kunt doen met Dockerfile.
Je complete Dockerfile zou er zo uit moeten zien:
|
1 2 3 4 5 6 7 8 9 |
FROM node:10-alpine RUN mkdir -p /home/node/app/node_modules && chown -R node:node /home/node/app WORKDIR /home/node/app COPY package*.json ./ USER node RUN npm install COPY --chown=node:node . . EXPOSE 8090 CMD [ "node", "index.js" ] |
Je kunt het bestand nu opslaan en sluiten.
Het volgende dat je doet is het toevoegen van het .dockerignore-bestand. Net als het .gitignore-bestand, specificeert het .dockerignore welke bestanden en mappen binnen de projectmap niet naar de container gekopieerd mogen worden.
Open het bestand met de nano-editor:
|
1 |
nano .dockerignore |
Voeg de volgende regels toe aan het bestand:
|
1 2 3 4 |
node_modules npm-debug.log Dockerfile .dockerignore |
Als je met een git-repo werkt, moet je ook de .git-map en het .gitignore-bestand toevoegen. Sla het bestand op en sluit het.
Als alles goed is gegaan, is het tijd om de applicatie-image te bouwen met het docker build-commando. Je kunt de –t-vlag toevoegen aan het docker build-commando om de image te taggen met een herkenbare naam in plaats van de willekeurige tekenreeks die Docker standaard instelt. We zullen de image ook naar Docker Hub pushen, dus het is het beste om je Docker Hub-gebruikersnaam in de tag op te nemen.
We zullen nodejs-express-image als tagnaam gebruiken. Je bent vrij om een tagnaam te kiezen die je leuk vindt. Hier is het commando om de image te bouwen:
|
1 |
sudo docker build -t your_dockerhub_username/nodejs-express-image . |
Vergeet niet om your_dockerhub_username te vervangen door je daadwerkelijke Docker Hub-gebruikersnaam. De . (punt) aan het einde geeft aan dat de build-context de huidige map is.
Het bouwproces duurt een minuut of twee. Zodra het klaar is, voer je het commando in om je images te controleren:
|
1 |
sudo docker images |
Je zou zoiets als dit moeten zien:
Onthoud dat we your_dockerhub_username hebben vervangen door een daadwerkelijke gebruikersnaam.
Na het bevestigen dat je image is gebouwd, kun je nu een container maken met de image met behulp van docker run. De volgende vlaggen zullen worden opgenomen:
-p: publiceert de poort op de container en koppelt deze aan een poort op het hostsysteem. We zullen poort 80 op het hostsysteem gebruiken voor demonstratiedoeleinden. Als je echter een ander proces op die poort hebt draaien, kun je dit desgewenst aanpassen. Lees meer over poortkoppeling in de Docker-documentatie.-d: voor de losgekoppelde (detached) modus. Hiermee kan de container op de achtergrond blijven draaien.--name: dit kun je gebruiken om een herkenbare naam in te stellen in plaats van Docker een willekeurige tekenreeks te laten toewijzen.
Het commando om de container te bouwen is als volgt. Vervang je Docker Hub-gebruikersnaam op de juiste manier:
|
1 |
sudo docker run --name nodejs-express-image -p 80:8090 -d your_dockerhub_username/nodejs-express-image |
Wacht tot de container is gebouwd en begint te draaien. Je kunt dit commando gebruiken om alle actieve containers te inspecteren:
|
1 |
sudo docker ps |
Je zou een uitvoer moeten zien die lijkt op de volgende:
Zoals te zien is in de uitvoer, draait de container nu. Je kunt deze in de browser bekijken als je het openbare IP-adres van je server bezoekt zonder de poort in de browser. Je startpagina zal laden:
Je hebt met succes een statische Node Express-website geïmplementeerd met Docker. Laten we eens kijken hoe we deze image naar Docker Hub kunnen pushen voor toekomstig gebruik en schaalbaarheidsdoeleinden.
Stap 4: Werken met Docker Image Repositories
Je kunt je images pushen naar image-registries zoals Docker Hub en ze opslaan voor toekomstig gebruik, ze delen met andere ontwikkelaars of het schalen van je containers mogelijk maken. We kunnen de image die we hebben gemaakt naar Docker Hub pushen en deze gebruiken om een container opnieuw te maken.
Gebruik de volgende opdracht om in te loggen op je Docker Hub-account. Vervang deze door je daadwerkelijke Docker Hub-gebruikersnaam:
|
1 |
sudo docker login -u your_dockerhub_username |
Voer je wachtwoord in wanneer daarom wordt gevraagd. Zodra je bent ingelogd, wordt er een ~/.docker/config.json -bestand aangemaakt in de thuismap van je gebruiker met daarin je Docker Hub-inloggegevens.
Als dat is ingesteld, voer je de volgende opdracht in om de image naar Docker Hub te pushen, waarbij je de tag opgeeft die je eerder bij het bouwen van de image hebt ingesteld:
|
1 |
sudo docker push your_dockerhub_username/nodejs-express-image |
Deze opdracht pusht de docker-image naar je Docker Hub-account. Als je je account bezoekt, kun je je onlangs gepushte image zien:
We kunnen het nut van de image-repository testen door de huidige applicatiecontainer te vernietigen en deze opnieuw op te bouwen met behulp van de image in de repository.
Toon een lijst van je huidige containers door de volgende opdracht in te voeren:
|
1 |
sudo docker ps |
Je zou een uitvoer moeten zien die vergelijkbaar is met deze:
Noteer de CONTAINER ID die in je uitvoer wordt vermeld, kopieer deze en gebruik deze om je container te stoppen met de opdracht, waarbij je de ID vervangt door die van jou:
|
1 |
sudo docker stop 1bb2d65279bb |
Voer de volgende opdracht in om alle docker-images weer te geven die beschikbaar zijn op je systeem:
|
1 |
sudo docker images –a |
De uitvoer toont de naam van je image, de node.js-image en andere images van het bouwproces.
Voer de volgende opdracht in om de images te verwijderen, inclusief ongebruikte of zwevende (dangling) images:
|
1 |
sudo docker system prune |
Typ y om te bevestigen. Dit verwijdert de gestopte containers en images. Als je ze opvraagt, zie je een lege lijst in de uitvoer:
Nu heb je zowel de container waarin de applicatie draait als de image zelf verwijderd. Leer meer over het verwijderen van Docker-containers, -images en -volumes door onze handleiding te volgen.
We kunnen nu het hele proces opnieuw doorlopen door eerst de image van Docker Hub op te halen met de volgende opdracht. Vervang je Docker Hub-gebruikersnaam op de juiste manier:
|
1 |
sudo docker pull your_dockerhub_username/nodejs-express-image |
Toon je Docker-images opnieuw met de opdracht:
|
1 |
sudo docker images |
Je zou de image in de uitvoer moeten zien:
Je kunt nu je container opnieuw bouwen met behulp van de opdracht uit Stap 3. Of course, replace your Docker Hub username where appropriate:
|
1 |
sudo docker run --name nodejs-express-image -p 80:8090 -d your_dockerhub_username/nodejs-express-image |
Toon een lijst van je containers om te bevestigen dat deze opnieuw is opgebouwd:
|
1 |
sudo docker ps |
Je zou een vergelijkbare uitvoer moeten zien:
Navigeer in je browser naar het openbare IP-adres van je server en je zou je app moeten zien draaien.
Conclusie
Als je de handleiding tot dit punt hebt gevolgd, heb je nu een statische website gemaakt met Express en Bootstrap, en geïmplementeerd met Docker. Je hebt de statische websitebestanden gebruikt om een Docker-image te bouwen en de image gebruikt om een container te maken. Vervolgens heb je de image gepusht naar een Docker-image-registry, Docker Hub, waardoor deze beschikbaar is voor toekomstig gebruik of schalen. Om het gebruik van de image-registry te testen, heb je de images en containers vernietigd, de images uit de registry opgehaald en de containers opnieuw opgebouwd.
In deze handleiding is uitgelegd hoe je een Node.js-app implementeert. Als je wilt leren hoe je een andere webontwikkelingsstack gebruikt, hebben we een handleiding over Een Laravel-app implementeren met Docker Compose op Nginx.
Raadpleeg de volgende handleidingen voor meer bronnen over het gebruik van Docker:
- Docker Compose installeren en configureren op Ubuntu 20.04
- Gegevens delen tussen een Docker-container en een host
- Docker installeren en instellen op CentOS 7
Veel computerplezier!











Reacties
Nog geen reacties. Wees de eerste.