Wprowadzenie
Docker to platforma kontenerowa, która jest lekkim, zwirtualizowanym, przenośnym, zdefiniowanym programowo, standaryzowanym środowiskiem. Umożliwia uruchamianie oprogramowania w izolacji od innego oprogramowania działającego na fizycznej maszynie hosta. Docker jest kluczowym elementem aspektu ciągłego rozwoju i integracji (Continuous Development and Integration) w inżynierii oprogramowania. Oferuje on lekką alternatywę dla maszyn wirtualnych i pozwala programistom cieszyć się rozproszonymi architekturami aplikacji. Aby uzyskać szczegółowy przegląd ekosystemu Docker, zapoznaj się z tym artykułem.
Proces budowania aplikacji za pomocą Dockera rozpoczyna się od utworzenia przez programistę obrazu dla swojej aplikacji. Następnie obraz ten zostanie wdrożony wewnątrz kontenera. Obraz zawiera definiujące komponenty aplikacji, takie jak kod aplikacji, biblioteki, pliki konfiguracyjne, zmienne środowiskowe oraz środowisko uruchomieniowe. Obraz standaryzuje środowisko wewnątrz kontenera, nadając konteneryzacji cechy przenośności. Node.js to otwartoźródłowe, wieloplatformowe środowisko uruchomieniowe JavaScript dla backendu, które może wykonywać kod JavaScript poza przeglądarką internetową. Jest ono zbudowane w oparciu o należący do Chrome V8 JavaScript Engine. Express.js to minimalistyczny backendowy framework JavaScript, który działa na bazie Node.js.
W tym samouczku utworzymy obraz dla strony internetowej działającej na frameworku Express. Użyjemy Bootstrap, który jest biblioteką frontendową, aby poprawić wygląd frontendu. Po utworzeniu obrazu zbudujemy kontener i prześlemy go do Docker Hub. Docker Hub pozwala programistom na hostowanie skonteneryzowanych aplikacji w celu łatwego wdrożenia w dowolnym środowisku Docker. Gdy Twój kontener znajdzie się na Docker Hub, pobierzemy go i zbudujemy kolejny obraz, który będzie faktycznie obsługiwał naszą stronę internetową.
Wymagania wstępne
To będzie praktyczny samouczek. Powinieneś przygotować środowisko, które umożliwi Ci śledzenie kroków.
- Powinieneś posiadać zainstalowany system Ubuntu 20.04 jako początkowe środowisko operacyjne oraz utworzyć użytkownika niebędącego rootem z uprawnieniami sudo. Zaloguj się jako użytkownik niebędący rootem i przejdź do kolejnych kroków.
- Musisz zainstalować Dockera. Wykonaj kroki 1, 2, 3 i 4 z naszego samouczka dotyczącego tego, jak zainstalować i obsługiwać Dockera na Ubuntu. Powinno to działać na dowolnej dystrybucji Ubuntu.
- Utwórz konto Docker Hub, jeśli jeszcze go nie masz. Możesz skorzystać z tego linku, aby przejść do Szybkiego przewodnika po Docker Hub.
- Zainstaluj Node.js i NPM. NPM to menedżer pakietów JavaScript. Możesz postępować zgodnie z tymi instrukcjami dotyczącymi instalacji Node i npm.
Krok 1: Konfiguracja zależności aplikacji
Przed utworzeniem obrazu musisz stworzyć kod źródłowy aplikacji. Kod źródłowy aplikacji obejmuje kod, zawartość statyczną oraz zależności, które zostaną skopiowane do kontenera. Zacznij od utworzenia katalogu dla swojego projektu w katalogu domowym użytkownika niebędącego rootem. Nazwiemy go node_express, ale możesz użyć dowolnej innej nazwy katalogu:
|
1 |
mkdir node_express |
Następnie przejdź do tego katalogu:
|
1 |
cd node_express |
To będzie katalog główny Twojej aplikacji. Aplikacja node.js oczekuje pliku package.json w folderze głównym. Npm używa tego pliku do określenia, jakich zależności potrzebuje Twoja aplikacja. Wprowadź następujące polecenie, aby utworzyć ten plik:
|
1 |
nano package.json |
Następnie dodaj do pliku poniższy fragment kodu. Możesz dowolnie zaktualizować nazwę, autora, opis oraz plik punktu wejścia:
|
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" } } |
Jak widać, ten plik określa nazwę projektu, wersję, autora oraz licencję, na której kod aplikacji będzie udostępniany. Zaleca się używanie krótkiej i opisowej nazwy dla projektu, aby uniknąć duplikatów w rejestrze npm. Określiliśmy licencję ISC dla projektu, która pozwala na bezpłatne kopiowanie, modyfikowanie lub dystrybucję kodu aplikacji.
Co najważniejsze, należy zwrócić uwagę na następujące dyrektywy w pliku:
- “
main”: ta dyrektywa określa punkt wejścia aplikacji, który ustawiliśmy jako index.js. Ten plik utworzymy za chwilę. - “
dependencies”: ta dyrektywa określa zależności aplikacji, które zostaną pobrane z rejestru npm po uruchomieniu polecenianpm, w naszym przypadku chcemy Express w wersji 4.17.1 i nowszej.
Możesz teraz zapisać plik, naciskając Ctrl + O. Następnie zamknij plik, naciskając Ctrl + X. Następnie zainstalujemy zależności, uruchamiając następujące polecenie:
|
1 |
npm install |
Polecenie to instaluje zależności aplikacji określone w pliku package.json wewnątrz katalogów node_modules. Zostały one automatycznie utworzone przy pierwszym uruchomieniu polecenia. Po zainstalowaniu zależności aplikacji możesz teraz zacząć dodawać kod aplikacji.
Krok 2: Dodawanie plików kodu aplikacji
Stworzymy prostą stronę z przepisami, dzięki uprzejmości allrecipes. Głównym punktem wejścia dla aplikacji jest plik index.js. Dodamy katalog views, który będzie zawierał różne strony i statyczne zasoby projektu. Strona będzie miała stronę główną (landing page), która będzie zawierać informacje wprowadzające i linki do niektórych przepisów.
Kod naszej strony głównej zostanie umieszczony w pliku home.html. Najpierw utwórz plik index.js, wprowadzając następujące polecenie:
|
1 |
nano index.js |
Dodaj następujący kod, który importuje i tworzy aplikację Express. Określa on również obiekt Router, katalog bazowy oraz port, na którym ta aplikacja będzie obsługiwana:
|
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 to funkcja JavaScript, która ładuje moduł. W tym przypadku ładujemy moduł express. Następnie użyjemy zaimportowanego modułu do utworzenia obiektów express i router. Obiekt router wykonuje funkcje routingu aplikacji, odpowiadając na wywołania metod HTTP, które będziemy dodawać do tego obiektu w miarę postępów w samouczku.
Ustawiliśmy również path oraz port. Stała path definiuje katalog bazowy dla kodu. W naszym przypadku jest to podkatalog views wewnątrz głównego katalogu projektu. port określa port, na którym aplikacja express powinna nasłuchiwać, w naszym przykładzie ustawiliśmy go na 8090.
Gdy mamy już stałe, możemy określić niektóre trasy dla aplikacji za pomocą obiektu router. Dodaj następujący kod do pliku index.js, aby określić trasy:
|
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'); }); |
Możesz dodać middleware do tras za pomocą funkcji router.use. W tym przypadku dodajemy funkcję, która rejestruje żądania routera przed przekazaniem ich do tras aplikacji. Żądanie GET do głównego adresu aplikacji zwróci plik home.html stronę. Następnie dodaliśmy strony dla trzech przepisów, które również będą pobierane za pomocą żądania GET do konkretnej strony przepisu.
Na koniec dodaj następujący kod, aby zamontować router oprogramowanie pośredniczące (middleware) oraz statyczne zasoby aplikacji. Dodatkowo wskaż aplikacji express, aby nasłukiwała na porcie 8090:
|
1 2 3 4 5 6 |
app.use(express.static(path)); app.use('/', router); app.listen(port, function () { console.log('Przykładowa aplikacja Nodejs Express nasłuchuje na porcie ' + port) }) |
Twój kompletny plik index.js powinien wyglądać następująco:
|
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('Przykładowa aplikacja Nodejs Express nasłuchuje na porcie ' + port) }) |
Możesz teraz zapisać i zamknąć plik. Następnym krokiem jest dodanie statycznych stron internetowych do katalogu views. Zacznij od wprowadzenia następującego polecenia, aby utworzyć ten katalog:
|
1 |
mkdir views |
Wprowadź następujące polecenie, aby otworzyć plik strony docelowej home.html:
|
1 |
nano views/home.html |
Dodaj do pliku następujący kod. Kod ten importuje Bootstrap i oferuje odwiedzającym stronę informacje o tym, czym jest ta witryna:
|
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="pl"> <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 i współtwórcy Bootstrap"> <meta name="generator" content="Hugo 0.80.0"> <title>Niesamowite Przepisy</title> <!-- Główny CSS Bootstrap --> <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">Przełącz nawigację</span> </button> <a class="navbar-brand" href="#">Niesamowite Przepisy</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">Strona główna</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">Chlebek bananowy</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">Niesamowity przepis</h1> <p class="lead text-muted"> Znajdź i dziel się codziennymi inspiracjami kulinarnymi z tych niesamowitych przepisów. Odkrywaj przepisy, kucharzy, filmy i poradniki oparte na jedzeniu, które kochasz, i znajomych, których obserwujesz. <br /> <em>(Nic poważnego, to tylko dla naszej demonstracyjnej aplikacji obrazu node-express-docker)</em> </p> </div> </div> </section> </main> </body> </html> |
Oprócz importowania Bootstrapa, strona dodaje również podstawowe menu nawigacyjne ułatwiające poruszanie się po stronach i powrót do strony głównej. Dodaliśmy również linię importującą nasz niestandardowy plik CSS:
|
1 |
<link href="css/custom.css" rel="stylesheet"> |
Użyjemy tego pliku do dodania niestandardowego stylu do aplikacji w późniejszym czasie. Teraz utwórzmy trzy strony dla przepisów. Zaczynamy od utworzenia strony lasagna. Otwórz plik w edytorze nano za pomocą następującego polecenia:
|
1 |
nano views/lasagna.html |
W otwartym pliku dodaj następujący kod. Ten plik zaimportuje Bootstrapa, plik custom.css, określi menu nawigacyjne i przedstawi informacje o przepisie na lasagnę:
|
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="pl"> <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 i współtwórcy Bootstrapa"> <meta name="generator" content="Hugo 0.80.0"> <title>Przepis na lasagne</title> <!-- Podstawowy CSS Bootstrap --> <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">Przełącz nawigację</span> </button> <a class="navbar-brand" href="#">Niesamowite przepisy</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">Strona główna</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">Chlebek bananowy</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">Najlepszy przepis na lasagne</h1> <p class="lead text-muted"> To najlepsza lasagne, jaką kiedykolwiek zrobisz. <br /> <em>(Nic poważnego, to tylko na potrzeby naszej demonstracyjnej aplikacji z obrazem node-express-docker)</em> </p> <h3>Składniki</h3> <ul class="list-group"> <li class="list-group-item">1 funt słodkiej włoskiej kiełbasy</li> <li class="list-group-item">¾ funta chudej mielonej wołowiny</li> <li class="list-group-item">½ szklanki posiekanej cebuli</li> <li class="list-group-item">2 ząbki czosnku, rozgniecione</li> <li class="list-group-item">1 puszka (28 uncji) rozgniecionych pomidorów</li> <li class="list-group-item">2 puszki (6 uncji) koncentratu pomidorowego</li> <li class="list-group-item">2 puszki (6,5 uncji) sosu pomidorowego z puszki</li> <li class="list-group-item">½ szklanki wody</li> <li class="list-group-item">2 łyżki białego cukru</li> <li class="list-group-item">1 ½ łyżeczki suszonych liści bazylii</li> <li class="list-group-item">½ łyżeczki nasion kopru włoskiego</li> <li class="list-group-item">1 łyżeczka przyprawy włoskiej</li> <li class="list-group-item">1 ½ łyżeczki soli, podzielone, lub do smaku</li> <li class="list-group-item">¼ łyżeczki mielonego czarnego pieprzu</li> <li class="list-group-item">4 łyżki posiekanej świeżej natki pietruszki</li> <li class="list-group-item">12 płatów makaronu do lasagne</li> <li class="list-group-item">16 uncji sera ricotta</li> <li class="list-group-item">1 jajko</li> <li class="list-group-item">¾ funta sera mozzarella, pokrojonego w plastry</li> <li class="list-group-item">¾ szklanki tartego parmezanu</li> </ul> </div> </div> </section> </main> </body> </html> |
Postępujmy zgodnie z tym samym procesem, aby utworzyć plik dla strony z przepisem na guacamole. Otwórz plik za pomocą nano, uruchamiając następujące polecenie:
|
1 |
nano views/guacamole.html |
Następnie dodaj ten kod do pliku:
|
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="pl"> <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>Przepis na guacamole</title> <!-- Podstawowy CSS Bootstrap --> <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">Przełącz nawigację</span> </button> <a class="navbar-brand" href="#">Niesamowite Przepisy</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">Strona główna</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">Chlebek bananowy</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">Najlepszy przepis na guacamole</h1> <p class="lead text-muted"> Możesz przygotować tę sałatkę z awokado na gładko lub z kawałkami, w zależności od upodobań. <br /> <em>(Nic poważnego, to tylko dla naszej demonstracyjnej aplikacji z obrazem node-express-docker)</em> </p> <h3>Składniki</h3> <ul class="list-group"> <li class="list-group-item">3 awokado – obrane, bez pestek i rozgniecione</li> <li class="list-group-item">sok wyciśnięty z 1 limonki</li> <li class="list-group-item">1 łyżeczka soli</li> <li class="list-group-item">½ szklanki pokrojonej w kostkę cebuli</li> <li class="list-group-item">3 łyżki posiekanej świeżej kolendry</li> <li class="list-group-item">2 pomidory rzymskie (śliwkowe), pokrojone w kostkę</li> <li class="list-group-item">1 łyżeczka posiekanego czosnku</li> <li class="list-group-item">1 szczypta mielonego pieprzu cayenne (opcjonalnie)</li> </ul> </div> </div> </section> </main> </body> </html> |
Na koniec utwórzmy plik banana_bread.html, wpisując polecenie:
|
1 |
nano views/banana_bread.html |
Następnie dodaj do pliku następujący kod HTML:
|
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="pl"> <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>Przepis na chlebek bananowy</title> <!-- Główny plik CSS Bootstrap --> <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">Przełącz nawigację</span> </button> <a class="navbar-brand" href="#">Niesamowite przepisy</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">Strona główna</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">Chlebek bananowy</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">Najlepszy przepis na chlebek bananowy</h1> <p class="lead text-muted"> Po co iść na kompromis w kwestii bananowego smaku? Ten chlebek bananowy jest wilgotny i pyszny, o intensywnym bananowym smaku! Przyjaciele i rodzina uwielbiają mój przepis i mówią, że jest zdecydowanie najlepszy! Jest wspaniały po opieczeniu!! Smacznego! <br /> <em>(Nic poważnego, to tylko na potrzeby naszej demonstracyjnej aplikacji z obrazem node-express-docker)</em> </p> <h3>Składniki</h3> <ul class="list-group"> <li class="list-group-item">2 szklanki mąki pszennej</li> <li class="list-group-item">1 łyżeczka sody oczyszczonej</li> <li class="list-group-item">¼ łyżeczki soli</li> <li class="list-group-item">½ szklanki masła</li> <li class="list-group-item">¾ szklanki brązowego cukru</li> <li class="list-group-item">2 jajka, roztrzepane</li> <li class="list-group-item">2⅓ szklanki rozgniecionych, bardzo dojrzałych bananów</li> </ul> </div> </div> </section> </main> </body> </html> |
Teraz utworzyliśmy już wszystkie strony. Jeśli pamiętasz, mamy dodać plik css/custom.css file. Enter the following command to create the directory:
|
1 |
mkdir views/css |
Następnie utwórz i otwórz plik w edytorze nano za pomocą polecenia:
|
1 |
nano views/css/custom.css |
Możesz dodać więcej kodu CSS, aby ostylować swoją stronę według własnego uznania. Dla zwięzłości dodajmy do pliku następujący fragment kodu:
|
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; } } |
Po zakończeniu zapisz i zamknij plik.
Możesz teraz uruchomić aplikację, ponieważ mamy już zainstalowany kod źródłowy aplikacji i zależności projektu.
Skonfigurowaliśmy aplikację tak, aby nasłuchiwała na porcie 8090, uruchom następujące polecenie, aby nakazać zaporze sieciowej zezwolenie na ruch przez ten port. Jeśli określiłeś inny port, zastąp numer portu w poleceniu:
|
1 |
sudo ufw allow 8090 |
Teraz możesz uruchomić aplikację. Najpierw jednak upewnij się, że znajdujesz się w katalogu głównym projektu, uruchamiając następujące polecenie:
|
1 |
cd ~/node_express |
Uruchom aplikację za pomocą polecenia node index.js. Jeśli określiłeś inny punkt wejścia, zastąp go swoim punktem wejścia:
|
1 |
node index.js |
Jeśli przejdziesz w przeglądarce pod adres http://your_public_server_ip:8090, zobaczysz stronę główną Przepisów, tak jak została zdefiniowana:
W nawigacji widoczne są linki do różnych przepisów. Kliknijmy na niektóre z nich. Poniżej znajduje się Lasagne - strona przepisu:
A tutaj mamy Guacamole - strona przepisu:
Do tego momentu utworzyłeś aplikację i przetestowałeś, że działa zgodnie z oczekiwaniami. Możesz wyjść z serwera, naciskając Ctrl + C, i przejść do tworzenia pliku Dockerfile. Pliki Dockerfile pomagają w skalowalności, umożliwiając odtworzenie instancji aplikacji w razie potrzeby.
Krok 3: Tworzenie pliku Dockerfile
Docker odczytuje instrukcje określone w pliku Dockerfile podczas budowania obrazów. Określa on środowisko uruchomieniowe aplikacji. Dzięki temu pomaga programistom uniknąć rozbieżności w zależnościach lub zmieniających się wersjach środowiska uruchomieniowego. Wprowadź następujące polecenie, aby utworzyć plik Dockerfile:
|
1 |
nano Dockerfile |
Obraz Dockera jest tworzony przy użyciu kilku warstw obrazów, które budują się jedna na drugiej. Zaczynasz od dodania obrazu bazowego, który stanowi punkt wyjścia dla aplikacji.
Ponieważ aplikacja ma działać w środowisku node.js, zaczniemy od dodania obrazu node:10-alpine dla node.js. Obecnie, gdy piszemy ten samouczek, jest to zalecana wersja LTS Node.js. Wybraliśmy ten konkretny obraz, ponieważ pochodzi on z projektu Alpine Linux. Dzięki temu pomoże to utrzymać rozmiar naszego obrazu na minimalnym poziomie. Istnieje kilka wariantów obrazów na stronie obrazów Node w Docker Hub, które możesz wybrać w zależności od swoich potrzeb.
Dodaj następujący kod, aby ustawić obraz bazowy aplikacji za pomocą dyrektywy FROM:
|
1 |
FROM node:10-alpine |
Ten obraz zawiera Node.js i npm. Każdy Dockerfile musi zaczynać się od dyrektywy FROM. Obraz Docker node domyślnie zawiera użytkownika node niebędącego rootem, którego można użyć do uruchomienia kontenera aplikacji zamiast roota. Zabezpieczenia Dockera zalecają nieuruchamianie kontenerów jako root i ograniczenie uprawnień tylko do tych, które są wymagane do działania jego zasobów.
W takim przypadku będziemy używać katalogu domowego użytkownika node jako katalogu roboczego dla aplikacji, a także samego użytkownika wewnątrz kontenera. Możesz zapoznać się z tym przewodnikiem po najlepszych praktykach dotyczącym obrazu Docker Node, aby uzyskać więcej informacji.
Utworzymy podkatalog node_modules wewnątrz /home/node wraz z katalogiem aplikacji, aby pomóc usprawnić uprawnienia do kodu aplikacji. Utworzenie tych katalogów zapewnia, że mają one odpowiednie uprawnienia, gdy uruchomimy polecenie npm install lokalnie wewnątrz kontenerów. Po utworzeniu katalogów należy ustawić ich własność na użytkownika node. Zrobimy to wewnątrz pliku Dockerfile, dodając następującą linię:
|
1 |
mkdir -p /home/node/app/node_modules && chown -R node:node /home/node/app |
Następnie ustawisz katalog roboczy, dodając następującą linię:
|
1 |
WORKDIR /home/node/app |
Zawsze warto ustawić WORKDIR, aby Docker nie musiał tworzyć go domyślnie.
Dodaj następującą linię, aby skopiować pliki package.json i package-lock.json:
|
1 |
COPY package*.json ./ |
Zaleca się dodanie instrukcji COPY przed uruchomieniem npm install lub skopiowaniem kodu źródłowego aplikacji. Pozwala to na skorzystanie z mechanizmu buforowania Dockera. Podczas procesu budowania Docker sprawdza, czy ma zapisaną w pamięci podręcznej warstwę dla każdej instrukcji. Oznacza to, że jeśli nie zmieniłeś pliku package.json, Docker użyje istniejącej warstwy obrazu i uniknie ponownej instalacji modułów node, co przyspieszy proces budowania.
Przed uruchomieniem npm install, dodaj następującą linię, aby przełączyć użytkownika na node, aby upewnić się, że wszystkie pliki aplikacji i katalog node_modules należą do użytkownika node niebędącego rootem:
|
1 |
USER node |
Nasz kontener jest teraz gotowy do uruchomienia polecenia npm install. Dodaj następującą linię do pliku Dockerfile:
|
1 |
RUN npm install |
Po zainstalowaniu node_modules, dodaj następującą linię, która nakaże Dockerowi skopiowanie kodu aplikacji do katalogu aplikacji w kontenerze z odpowiednimi uprawnieniami i własnością, tj. dla użytkownika node niebędącego rootem:
|
1 |
COPY --chown=node:node . . |
Ostatnim krokiem jest udostępnienie portu 8090 w kontenerze, tak jak zdefiniowaliśmy to w naszym pliku wejściowym index.js:
|
1 2 |
EXPOSE 8090 CMD [ "node", "index.js" ] |
EXPOSE określa, które porty w kontenerze będą otwarte w czasie działania. CMD uruchamia polecenie startu aplikacji, w tym przypadku node index.js.
W pliku Dockerfile powinna znajdować się tylko jedna instrukcja CMD, ponieważ tylko ostatnia odnosi skutek. Zapoznaj się z dokumentacją referencyjną Dockerfile, aby zapoznać się z listą rzeczy, które można zrobić za pomocą Dockerfile.
Twój kompletny plik Dockerfile powinien wyglądać następująco:
|
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" ] |
Możesz teraz zapisać i zamknąć plik.
Następnym krokiem jest dodanie pliku .dockerignore. Podobnie jak plik .gitignore, plik .dockerignore określa, które pliki i katalogi w katalogu projektu nie powinny być kopiowane do kontenera.
Otwórz plik w edytorze nano:
|
1 |
nano .dockerignore |
Dodaj następujące linie wewnątrz pliku:
|
1 2 3 4 |
node_modules npm-debug.log Dockerfile .dockerignore |
Jeśli pracujesz z repozytorium git, powinieneś również dodać katalog .git oraz plik .gitignore. Zapisz i zamknij plik.
Jeśli wszystko poszło dobrze, czas zbudować obraz aplikacji za pomocą polecenia docker build. Możesz dodać flagę –t do polecenia docker build, aby oznaczyć obraz łatwą do zapamiętania nazwą, w przeciwieństwie do losowego ciągu znaków, który Docker ustawia domyślnie. Będziemy również przesyłać obraz do Docker Hub, więc najlepiej jest dołączyć swoją nazwę użytkownika Docker Hub w tagu.
Użyjemy nodejs-express-image jako nazwy tagu. Możesz wybrać dowolną nazwę tagu. Oto polecenie do zbudowania obrazu:
|
1 |
sudo docker build -t your_dockerhub_username/nodejs-express-image . |
Pamiętaj, aby zastąpić your_dockerhub_username swoją rzeczywistą nazwą użytkownika Docker Hub. Kropka (.) na końcu określa, że kontekstem budowania jest bieżący katalog.
Proces budowania trwa minutę lub dwie. Po jego zakończeniu wprowadź polecenie, aby sprawdzić swoje obrazy:
|
1 |
sudo docker images |
Powinieneś zobaczyć coś takiego:
Pamiętaj, że zastąpiliśmy your_dockerhub_username rzeczywistą nazwą użytkownika.
Po potwierdzeniu, że obraz został zbudowany, możesz teraz utworzyć kontener z tym obrazem za pomocą docker run. Uwzględnione zostaną następujące flagi:
-p: publikuje port w kontenerze i mapuje go na port w systemie hosta. Do celów demonstracyjnych użyjemy portu 80 w systemie hosta. Jeśli jednak na tym porcie działa inny proces, możesz go zmodyfikować w razie potrzeby. Dowiedz się więcej o bindowaniu portów z dokumentacji Dockera.-d: dla trybu odłączonego (detached). Pozwala kontenerowi na dalsze działanie w tle.--name: możesz użyć tej flagi, aby ustawić łatwą do zapamiętania nazwę, zamiast pozwalać Dockerowi na przypisanie losowego ciągu znaków.
Polecenie utworzenia kontenera jest następujące. Zastąp odpowiednio swoją nazwę użytkownika Docker Hub:
|
1 |
sudo docker run --name nodejs-express-image -p 80:8090 -d your_dockerhub_username/nodejs-express-image |
Poczekaj, aż kontener zostanie zbudowany i uruchomiony. Możesz użyć tego polecenia, aby sprawdzić wszystkie uruchomione kontenery:
|
1 |
sudo docker ps |
Powinieneś zobaczyć dane wyjściowe podobne do następujących:
Jak widać na wyjściu, kontener jest teraz uruchomiony. Możesz go wyświetlić w przeglądarce, odwiedzając publiczny adres IP swojego serwera bez podawania portu. Strona główna zostanie załadowana:
Pomyślnie wdrożyłeś statyczną stronę internetową Node Express za pomocą Dockera. Zobaczmy, jak możemy przesłać ten obraz do Docker Hub w celu przyszłego użycia i skalowania.
Krok 4: Praca z repozytoriami obrazów Docker
Możesz przesyłać swoje obrazy do rejestrów obrazów, takich jak Docker Hub, i zapisywać je do przyszłego użytku, udostępniać innym programistom lub umożliwiać skalowanie kontenerów. Możemy przesłać utworzony obraz do Docker Hub i użyć go do ponownego utworzenia kontenera.
Użyj następującego polecenia, aby zalogować się na swoje konto Docker Hub. Zastąp je swoją rzeczywistą nazwą użytkownika Docker Hub:
|
1 |
sudo docker login -u your_dockerhub_username |
Wprowadź hasło po wyświetleniu monitu. Po zalogowaniu plik ~/.docker/config.json zostanie utworzony w katalogu domowym użytkownika, zawierający Twoje dane uwierzytelniające Docker Hub.
Po skonfigurowaniu wprowadź następujące polecenie, aby przesłać obraz do Docker Hub, określając tag ustawiony wcześniej podczas budowania obrazu:
|
1 |
sudo docker push your_dockerhub_username/nodejs-express-image |
To polecenie przesyła obraz platformy Docker na Twoje konto Docker Hub. Jeśli odwiedzisz swoje konto, zobaczysz niedawno przesłany obraz:
Możemy przetestować użyteczność repozytorium obrazów, niszcząc bieżący kontener aplikacji i odbudowując go przy użyciu obrazu z repozytorium.
Wyświetl listę swoich bieżących kontenerów, wprowadzając polecenie:
|
1 |
sudo docker ps |
Powinieneś zobaczyć dane wyjściowe podobne do tych:
Zanotuj CONTAINER ID wyświetlony w danych wyjściowych, skopiuj go i użyj do zatrzymania kontenera za pomocą polecenia, zastępując identyfikator swoim:
|
1 |
sudo docker stop 1bb2d65279bb |
Wprowadź następujące polecenie, aby wyświetlić listę wszystkich obrazów platformy Docker dostępnych w Twoim systemie:
|
1 |
sudo docker images –a |
W danych wyjściowych pojawi się nazwa Twojego obrazu, obraz node.js oraz inne obrazy z procesu budowania.
Wprowadź następujące polecenie, aby usunąć obrazy, w tym nieużywane lub wiszące obrazy:
|
1 |
sudo docker system prune |
Wpisz y, aby potwierdzić. Spowoduje to usunięcie zatrzymanych kontenerów i obrazów. Jeśli wyświetlisz ich listę, zobaczysz pustą listę w danych wyjściowych:
Teraz usunąłeś zarówno kontener, w którym działa aplikacja, jak i sam obraz. Dowiedz się więcej o usuwaniu kontenerów, obrazów i wolumenów platformy Docker, postępując zgodnie z naszym samouczkiem.
Możemy teraz odtworzyć cały proces, najpierw pobierając obraz z Docker Hub za pomocą następującego polecenia. Zastąp odpowiednio swoją nazwę użytkownika Docker Hub:
|
1 |
sudo docker pull your_dockerhub_username/nodejs-express-image |
Ponownie wyświetl listę swoich obrazów platformy Docker za pomocą polecenia:
|
1 |
sudo docker images |
Powinieneś zobaczyć obraz w danych wyjściowych:
Możesz teraz odbudować swój kontener, używając polecenia z Kroku 3. Oczywiście zastąp swoją nazwę użytkownika Docker Hub tam, gdzie to konieczne:
|
1 |
sudo docker run --name nodejs-express-image -p 80:8090 -d your_dockerhub_username/nodejs-express-image |
Wyświetl listę swoich kontenerów, aby potwierdzić, że został odbudowany:
|
1 |
sudo docker ps |
Powinieneś zobaczyć podobne dane wyjściowe:
W przeglądarce przejdź do publicznego adresu IP swojego serwera, a powinieneś zobaczyć działającą aplikację.
Podsumowanie
Jeśli przeszedłeś przez ten samouczek do tego miejsca, masz teraz statyczną stronę internetową stworzoną za pomocą Express i Bootstrap oraz wdrożoną za pomocą platformy Docker. Użyłeś plików statycznej strony internetowej do zbudowania obrazu platformy Docker i użyłeś tego obrazu do utworzenia kontenera. Następnie przesłałeś obraz do rejestru obrazów platformy Docker, Docker Hub, udostępniając go do przyszłego użytku lub skalowania. Aby przetestować użycie rejestru obrazów, usunąłeś obrazy i kontenery, pobrałeś obrazy z rejestru i odbudowałeś kontenery.
Ten samouczek wyjaśnił, jak wdrożyć aplikację Node.js. Jeśli chcesz dowiedzieć się, jak korzystać z innego stosu programistycznego, mamy samouczek dotyczący Wdrażania aplikacji Laravel za pomocą Docker Compose na serwerze Nginx.
Więcej zasobów dotyczących korzystania z platformy Docker można znaleźć w następujących samouczkach:
- Jak zainstalować i skonfigurować Docker Compose na Ubuntu 20.04
- Jak udostępniać dane między kontenerem platformy Docker a hostem
- Instalacja i konfiguracja Dockera na CentOS 7
Miłego korzystania z komputera!











Komentarze
Brak komentarzy. Bądź pierwszy.