Programowanie InnerLoop z użyciem Node.js

1. Przegląd

W tym module poznasz funkcje i możliwości, które usprawniają proces tworzenia aplikacji w środowisku skonteneryzowanym dla inżynierów oprogramowania zajmujących się opracowywaniem aplikacji w NodeJS. Typowe tworzenie kontenerów wymaga od użytkownika znajomości szczegółów dotyczących kontenerów i procesu kompilacji kontenerów. Deweloperzy zwykle muszą też przerywać pracę i opuszczać IDE, aby testować i debugować aplikacje w środowiskach zdalnych. Dzięki narzędziom i technologiom wymienionym w tym samouczku deweloperzy mogą efektywnie pracować z aplikacjami w kontenerach bez opuszczania środowiska IDE.

Czego się nauczysz

W tym module poznasz metody tworzenia aplikacji w kontenerach w GCP, w tym:

  • Tworzenie aplikacji startowej w Node.js
  • Konfigurowanie aplikacji Node.js na potrzeby tworzenia kontenerów
  • Kodowanie prostej usługi REST CRUD
  • Wdrażanie w GKE
  • Debugowanie stanu błędu
  • Korzystanie z punktu przerwania lub logów
  • Szybkie wdrażanie zmian z powrotem w GKE
  • Opcjonalnie: integracja CloudSQL na potrzeby trwałości backendu

2. Konfiguracja i wymagania

Samodzielne konfigurowanie środowiska

  1. Zaloguj się w konsoli Google Cloud i utwórz nowy projekt lub użyj istniejącego. Jeśli nie masz jeszcze konta Gmail ani Google Workspace, musisz je utworzyć.

b35bf95b8bf3d5d8.png

a99b7ace416376c4.png

bd84a6d3004737c5.png

  • Nazwa projektu to wyświetlana nazwa uczestników tego projektu. Jest to ciąg znaków, który nie jest używany przez interfejsy API Google. Możesz go w dowolnym momencie zaktualizować.
  • Identyfikator projektu musi być unikalny we wszystkich projektach Google Cloud i jest niezmienny (nie można go zmienić po ustawieniu). Konsola Cloud automatycznie generuje unikalny ciąg znaków. Zwykle nie musisz się nim przejmować. W większości modułów z kodem musisz odwoływać się do identyfikatora projektu (zwykle oznaczanego jako PROJECT_ID). Jeśli Ci się nie podoba, wygeneruj inny losowy identyfikator lub spróbuj użyć własnego i sprawdź, czy jest dostępny. Po utworzeniu projektu jest on „zamrażany”.
  • Istnieje też trzecia wartość, czyli numer projektu, którego używają niektóre interfejsy API. Więcej informacji o tych 3 wartościach znajdziesz w dokumentacji.
  1. Następnie musisz włączyć płatności w konsoli Cloud, aby korzystać z zasobów i interfejsów API Google Cloud. Ukończenie tego laboratorium nie powinno wiązać się z dużymi kosztami, a nawet z żadnymi. Aby wyłączyć zasoby i uniknąć naliczenia opłat po zakończeniu tego samouczka, postępuj zgodnie z instrukcjami „czyszczenia” na końcu ćwiczenia. Nowi użytkownicy Google Cloud mogą skorzystać z bezpłatnego okresu próbnego, w którym mają do dyspozycji środki w wysokości 300 USD.

Uruchamianie edytora Cloud Shell

To laboratorium zostało zaprojektowane i przetestowane pod kątem używania w edytorze Google Cloud Shell. Aby uzyskać dostęp do edytora:

  1. uzyskać dostęp do projektu Google na stronie https://console.cloud.google.com;
  2. W prawym górnym rogu kliknij ikonę edytora Cloud Shell.

8560cc8d45e8c112.png

  1. U dołu okna otworzy się nowy panel.
  2. Kliknij przycisk Otwórz edytor.

9e504cb98a6a8005.png

  1. Edytor otworzy się z eksploratorem po prawej stronie i edytorem w środkowej części.
  2. U dołu ekranu powinien być też dostępny panel terminala.
  3. Jeśli terminal NIE jest otwarty, użyj kombinacji klawiszy „Ctrl+`”, aby otworzyć nowe okno terminala.

Konfigurowanie gcloud

W Cloud Shell ustaw identyfikator projektu i region, w którym chcesz wdrożyć aplikację. Zapisz je jako zmienne PROJECT_IDREGION.

export PROJECT_ID=$(gcloud config get-value project)
export PROJECT_NUMBER=$(gcloud projects describe $PROJECT_ID --format='value(projectNumber)')

Konfigurowanie klastra GKE i bazy danych

  1. Pobierz skrypt konfiguracji i ustaw go jako wykonywalny.
wget https://raw.githubusercontent.com/GoogleCloudPlatform/container-developer-workshop/main/labs/nodejs/setup.sh
chmod +x setup.sh

wdrożyć infrastrukturę używaną w tym module;

W tym module wdrożysz kod w GKE i uzyskasz dostęp do danych przechowywanych w bazie danych Spanner. Poniższy skrypt konfiguracji przygotuje tę infrastrukturę.

  1. Otwórz plik setup.sh i edytuj wartości haseł, które są obecnie ustawione na CHANGEME.
  2. Uruchom skrypt konfiguracyjny, aby utworzyć klaster GKE i bazę danych Cloud SQL, które będą używane w tym laboratorium.
./setup.sh
  1. W Cloud Shell utwórz nowy katalog o nazwie mynodejsapp.
mkdir mynodejsapp
  1. Przejdź do tego katalogu i otwórz go jako obszar roboczy. Spowoduje to ponowne wczytanie edytora przez utworzenie konfiguracji obszaru roboczego w nowo utworzonym folderze.
cd mynodejsapp && cloudshell workspace .
  1. Zainstaluj Node i NPM za pomocą NVM.
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.1/install.sh | bash
        
        # This loads nvm bash_completion
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"  # This loads nvm
[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion"  

nvm install stable

nvm alias default stable

3. Tworzenie nowej aplikacji startowej

  1. Inicjowanie aplikacji

Utwórz plik package.json, uruchamiając to polecenie:

npm init
    Choose the entry point: (index.js) src/index.js and default values for the rest of the parameters. This will create the file with following contents
{
  "name": "mynodejsapp",
  "version": "1.0.0",
  "description": "",
  "main": "src/index.js",,
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC"
}
  1. Dodawanie punktu wejścia

Edytuj ten plik, aby dodać polecenie startowe do skryptu "start": "node src/index.js",. Po zmianie skrypty powinny wyglądać jak fragment kodu poniżej:

"scripts": {
    "start": "node src/index.js",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  1. Dodaj zależność Express

Dodawany przez nas kod również korzysta z express, więc dodajmy tę zależność do pliku package.json. Po wprowadzeniu wszystkich zmian plik package.json powinien wyglądać tak jak poniżej.

​​{
  "name": "mynodejsapp",
  "version": "1.0.0",
  "description": "",
  "main": "src/index.js",
  "scripts": {
    "start": "node src/index.js",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "Your Name",
  "license": "ISC",
  "dependencies": {
    "express": "^4.16.4"
  }
}
  1. Tworzenie pliku index.js

Utwórz katalog źródłowy o nazwie src.

Utwórz plik src/index.js z tym kodem:

const express = require('express');
const app = express();
const PORT = 8080;

app.get('/', (req, res) => {
    var message="Greetings from Node";
    res.send({ message: message });
  });

app.listen(PORT, () => {
  console.log(`Server running at: http://localhost:${PORT}/`);

});

Zwróć uwagę, że PORT ma wartość 8080.

Generowanie manifestów

Skaffold udostępnia zintegrowane narzędzia, które upraszczają tworzenie kontenerów. W tym kroku zainicjujesz narzędzie Skaffold, które automatycznie utworzy podstawowe pliki YAML Kubernetes. Aby rozpocząć proces, wykonaj polecenie poniżej.

W terminalu wykonaj to polecenie:

skaffold init --generate-manifests

Gdy pojawi się odpowiedni komunikat:

  • Wpisz 8080 jako port.
  • Wpisz y, aby zapisać konfigurację.

Do obszaru roboczego zostaną dodane 2 pliki: skaffold.yamldeployment.yaml.

Aktualizowanie nazwy aplikacji

Wartości domyślne uwzględnione w konfiguracji nie pasują obecnie do nazwy aplikacji. Zaktualizuj pliki, aby odwoływały się do nazwy aplikacji, a nie do wartości domyślnych.

  1. Zmiana wpisów w konfiguracji Skaffold
  • Otwórz: skaffold.yaml
  • Wybierz nazwę obrazu, która jest obecnie ustawiona jako package-json-image.
  • Kliknij prawym przyciskiem myszy i wybierz Zmień wszystkie wystąpienia.
  • Wpisz nową nazwę w formacie mynodejsapp.
  1. Zmiana wpisów w konfiguracji Kubernetes
  • Otwórz plik deployment.yaml
  • Wybierz nazwę obrazu, która jest obecnie ustawiona jako package-json-image.
  • Kliknij prawym przyciskiem myszy i wybierz Zmień wszystkie wystąpienia.
  • Wpisz nową nazwę w formacie mynodejsapp.

Zwróć uwagę, że w pliku skaffold.yaml sekcja build używa buildpacks do umieszczania aplikacji w kontenerze. Ten kod nie ma pliku Dockerfile, a deweloper nie musi znać Dockera, aby umieścić tę aplikację w kontenerze.

Ta konfiguracja Skaffold automatycznie włącza też szybką synchronizację między edytorem a działającym kontenerem. Aby włączyć szybką synchronizację, nie musisz niczego dodatkowo konfigurować.

4. Omówienie procesu tworzenia

W tej sekcji wykonasz kilka czynności za pomocą wtyczki Cloud Code, aby poznać podstawowe procesy i sprawdzić konfigurację aplikacji startowej.

Cloud Code jest zintegrowany z narzędziem Skaffold, aby usprawnić proces programowania. Gdy w kolejnych krokach wdrożysz aplikację w GKE, Cloud Code i Skaffold automatycznie skompilują obraz kontenera, wypchną go do Container Registry, a następnie wdrożą aplikację w GKE. Dzieje się to w sposób niewidoczny, co pozwala deweloperowi skupić się na innych aspektach. Cloud Code usprawnia też proces programowania, zapewniając tradycyjne funkcje debugowania i szybkiej synchronizacji w przypadku programowania opartego na kontenerach.

Wdrażanie w Kubernetes

  1. W panelu u dołu edytora Cloud Shell wybierz Cloud Code .

fdc797a769040839.png

  1. W panelu, który pojawi się u góry, kliknij Uruchom w Kubernetes. Jeśli pojawi się taka prośba, wybierz Yes (Tak), aby użyć bieżącego kontekstu Kubernetes.

cfce0d11ef307087.png

  1. Gdy po raz pierwszy uruchomisz to polecenie, u góry ekranu pojawi się pytanie, czy chcesz użyć bieżącego kontekstu Kubernetes. Aby zaakceptować i użyć bieżącego kontekstu, kliknij „Yes” (Tak).

817ee33b5b412ff8.png

  1. Następnie pojawi się pytanie o to, którego repozytorium kontenerów chcesz użyć. Naciśnij Enter, aby zaakceptować podaną wartość domyślną.

eb4469aed97a25f6.png

  1. Wybierz kartę Wyjście w dolnym panelu, aby wyświetlić postęp i powiadomienia.

f95b620569ba96c5.png

  1. Aby wyświetlić dodatkowe szczegóły i logi przesyłane strumieniowo na żywo z kontenerów, w menu po prawej stronie wybierz „Kubernetes: Run/Debug - Detailed” (Kubernetes: uruchamianie/debugowanie – szczegółowe).

94acdcdda6d2108.png

  1. Aby wrócić do widoku uproszczonego, wybierz „Kubernetes: Uruchom/Debuguj” z menu rozwijanego.
  2. Po zakończeniu kompilacji i testów na karcie Wyniki pojawi się komunikat Resource deployment/mynodejsapp status completed successfully oraz adres URL: „Forwarded URL from service demo-app: http://localhost:8080”.
  3. W terminalu Cloud Code najedź kursorem na adres URL w danych wyjściowych (http://localhost:8080), a następnie w wyświetlonej etykiecie narzędzia wybierz Otwórz podgląd w przeglądarce.

Odpowiedź będzie następująca:

{"message":"Greetings from Node"}

Gorące przeładowanie

  1. Wejdź na src/index.js. Edytuj kod wiadomości powitalnej na 'Hello from Node'

Zauważ, że w oknie Output, w widoku Kubernetes: Run/Debug, obserwator synchronizuje zaktualizowane pliki z kontenerem w Kubernetes.

Update initiated
File sync started for 1 files for gcr.io/myproject/mynodejsapp:latest@sha256:f554756b3b4d6c301c4b26ef96102227cfa2833270db56241248ae42baa1971a
File sync succeeded for 1 files for gcr.io/myproject/mynodejsapp:latest@sha256:f554756b3b4d6c301c4b26ef96102227cfa2833270db56241248ae42baa1971a
Update succeeded
  1. Jeśli przejdziesz do widoku Kubernetes: Run/Debug - Detailed, zauważysz, że rozpoznaje on zmiany w pliku i ponownie uruchamia węzeł.
files modified: [src/index.js]
Copying files:map[src/index.js:[/workspace/src/index.js]]togcr.io/myproject/mynodejsapp:latest@sha256:f554756b3b4d6c301c4b26ef96102227cfa2833270db56241248ae42baa1971a
Syncing 1 files for gcr.io/myproject/mynodejsapp:latest@sha256:f554756b3b4d6c301c4b26ef96102227cfa2833270db56241248ae42baa1971a
Watching for changes...
[mynodejsapp]
[mynodejsapp]> mynodejsapp@1.0.0 start /workspace
[mynodejsapp]> node src/index.js
[mynodejsapp]
[mynodejsapp]Server running at: http://localhost:8080/
  1. Aby zobaczyć zaktualizowane wyniki, odśwież przeglądarkę.

Debugowanie

  1. Otwórz widok debugowania i zatrzymaj bieżący wątek 647213126d7a4c7b.png.
  2. Kliknij Cloud Code w menu u dołu i wybierz Debug on Kubernetes, aby uruchomić aplikację w trybie debug.
  • W widoku Kubernetes Run/Debug - Detailed okna Output zauważ, że Skaffold wdroży tę aplikację w trybie debugowania.
  • Tworzenie i wdrażanie aplikacji zajmie kilka minut. Tym razem zobaczysz dołączony debuger.
Port forwarding pod/mynodejsapp-6bbcf847cd-vqr6v in namespace default, remote port 9229 -> http://127.0.0.1:9229
[mynodejsapp]Debugger attached.
  1. Dolny pasek stanu zmieni kolor z niebieskiego na pomarańczowy, co oznacza, że jest w trybie debugowania.
  2. W widoku Kubernetes Run/Debug zobaczysz, że uruchomiono kontener z możliwością debugowania.
**************URLs*****************
Forwarded URL from service mynodejsapp-service: http://localhost:8080
Debuggable container started pod/mynodejsapp-deployment-6bc7598798-xl9kj:mynodejsapp (default)
Update succeeded
***********************************

Wykorzystywanie punktów przerwania

  1. Otwórz src/index.js
  2. Znajdź zdanie var message="Greetings from Node";
  3. Dodaj punkt przerwania do tego wiersza, klikając puste miejsce po lewej stronie numeru wiersza. Pojawi się czerwony wskaźnik, który oznacza, że punkt przerwania został ustawiony.
  4. Odśwież przeglądarkę i zwróć uwagę, że debuger zatrzymuje proces w punkcie przerwania i umożliwia zbadanie zmiennych i stanu aplikacji, która jest uruchomiona zdalnie w GKE.
  5. Klikaj w sekcji zmiennych, aż znajdziesz zmienną "message".
  6. Wykonaj wiersz, klikając Krok dalej 7cfdee4fd6ef5c3a.png.
  7. Obserwuj, jak bieżąca wartość zmiennej "message" zmienia się na "Greetings from Node".
  8. Kliknij dwukrotnie nazwę zmiennej „target” i w wyskakującym okienku zmień wartość na inną, np. "Hello from Node".
  9. Kliknij przycisk Dalej w panelu sterowania debugowaniem.
  10. Sprawdź odpowiedź w przeglądarce, w której powinna się teraz wyświetlać wpisana przez Ciebie zaktualizowana wartość.
  11. Zatrzymaj tryb „Debugowanie”, naciskając przycisk zatrzymania 647213126d7a4c7b.png, i usuń punkt przerwania, klikając go ponownie.

5. Tworzenie prostej usługi REST CRUD

Na tym etapie aplikacja jest w pełni skonfigurowana pod kątem tworzenia skonteneryzowanych aplikacji, a Ty znasz już podstawowy przepływ pracy programisty w Cloud Code. W kolejnych sekcjach przećwiczysz zdobytą wiedzę, dodając punkty końcowe usługi REST, które łączą się z zarządzaną bazą danych w Google Cloud.

Konfigurowanie zależności

Kod aplikacji używa bazy danych do przechowywania danych usługi REST. Upewnij się, że zależności są dostępne, dodając w pliku package.json ten kod:

  1. Dodaj do pliku package.json jeszcze 2 zależności: pgsequelize, aby utworzyć aplikację CRUD Postgres. Sekcja zależności po opublikowaniu zmian będzie wyglądać tak:
    "dependencies": {
    "express": "^4.16.4",
    "pg": "^8.7.3",
    "sequelize": "^6.17.0"
  }

Kodowanie usługi REST

  1. Dodawanie do tej aplikacji kodu aplikacji CRUD
wget -O app.zip https://github.com/GoogleCloudPlatform/container-developer-workshop/raw/main/labs/nodejs/app.zip

unzip app.zip

Ten kod ma

  • folder models z modelem encji dla item;
  • folder controllers z kodem, który wykonuje operacje CRUD;
  • folder routes, który kieruje określone wzorce adresów URL do różnych wywołań;
  • folder config ze szczegółami połączenia z bazą danych;
  1. Zwróć uwagę, że konfiguracja bazy danych w pliku db.config.js odnosi się do zmiennych środowiskowych, które należy podać, aby połączyć się z bazą danych. Musisz też przeanalizować żądanie przychodzące pod kątem kodowania adresu URL.
  2. Dodaj poniższy fragment kodu w src/index.js, aby móc połączyć się z kodem CRUD z głównego pliku JavaScript tuż przed ostatnią sekcją, która zaczyna się od app.listen(PORT, () => {
const bodyParser = require('body-parser')
app.use(bodyParser.json())
app.use(
 bodyParser.urlencoded({
   extended: true,
 })
)
const db = require("../app/models");
db.sequelize.sync();
require("../app/routes/item.routes")(app);
  1. Edytuj wdrożenie w pliku deployment.yaml, aby dodać zmienne środowiskowe, które będą zawierać informacje o połączeniu z bazą danych.

Zaktualizuj wpis specyfikacji na końcu pliku, aby pasował do tej definicji:

    spec:
      containers:
      - name: mynodejsapp
        image: mynodejsapp
        env:
        - name: DB_HOST
          value: ${DB_INSTANCE_IP}        
        - name: DB_PORT
          value: "5432"  
        - name: DB_USER
          valueFrom:
            secretKeyRef:
              name: gke-cloud-sql-secrets
              key: username
        - name: DB_PASS
          valueFrom:
            secretKeyRef:
              name: gke-cloud-sql-secrets
              key: password
        - name: DB_NAME
          valueFrom:
            secretKeyRef:
              name: gke-cloud-sql-secrets
              key: database
  1. Zastąp wartość DB_HOST adresem bazy danych.
export DB_INSTANCE_IP=$(gcloud sql instances describe mytest-instance \
    --format=json | jq \
    --raw-output ".ipAddresses[].ipAddress")

envsubst < deployment.yaml > deployment.new && mv deployment.new deployment.yaml

Wdrażanie i weryfikowanie aplikacji

  1. W panelu u dołu edytora Cloud Shell kliknij Cloud Code, a następnie u góry ekranu kliknij Debug on Kubernetes.
  2. Po zakończeniu kompilacji i testów na karcie Wyniki pojawi się komunikat Resource deployment/mynodejsapp status completed successfully oraz adres URL: „Forwarded URL from service mynodejsapp: http://localhost:8080”.
  3. Dodaj kilka produktów.

W terminalu Cloud Shell uruchom te polecenia:

URL=localhost:8080
curl -X POST $URL/items -d '{"itemName":"Body Spray", "itemPrice":3.2}' -H "Content-Type: application/json"
curl -X POST $URL/items -d '{"itemName":"Nail Cutter", "itemPrice":2.5}' -H "Content-Type: application/json"
  1. Sprawdź żądanie GET, uruchamiając $URL/items w przeglądarce. Polecenie curl możesz też uruchomić z poziomu wiersza poleceń.
curl -X GET $URL/items
  1. Test Delete: teraz spróbuj usunąć element, uruchamiając to polecenie: W razie potrzeby zmień wartość identyfikatora produktu.
curl -X DELETE $URL/items/1
    This throws an error message
{"message":"Could not delete Item with id=[object Object]"}

Identyfikowanie i rozwiązywanie problemu

  1. Uruchom ponownie aplikację w trybie debugowania i znajdź problem. Oto kilka porad:
  • Wiemy, że z poleceniem DELETE jest coś nie tak, ponieważ nie zwraca ono oczekiwanego wyniku. Punkt przerwania należy ustawić w metodzie itemcontroller.js->exports.delete.
  • Uruchom wykonywanie krok po kroku i obserwuj zmienne na każdym etapie, aby zobaczyć wartości zmiennych lokalnych w oknie po lewej stronie.
  • Aby obserwować konkretne wartości, np. request.params, dodaj tę zmienną do okna Obserwowanie.
  1. Zwróć uwagę, że wartość przypisana do id to undefined. Aby rozwiązać problem, zmień kod.

Poprawiony fragment kodu będzie wyglądać tak:

// Delete a Item with the specified id in the request
exports.delete = (req, res) => {
    const id = req.params.id;
  1. Po ponownym uruchomieniu aplikacji spróbuj usunąć plik.
  2. Zakończ sesję debugowania, klikając czerwony kwadrat na pasku narzędzi debugowania 647213126d7a4c7b.png.

6. Czyszczenie

Gratulacje! W tym module udało Ci się utworzyć od podstaw nową aplikację Node.js i skonfigurować ją do pracy w trybie wdrożenia na gorąco z kontenerami. Następnie wdrożyliśmy i debugowaliśmy aplikację w zdalnym klastrze GKE, korzystając z tego samego przepływu pracy dewelopera, który jest stosowany w tradycyjnych stosach aplikacji.

Aby zwolnić miejsce po ukończeniu modułu:

  1. Usuwanie plików użytych w laboratorium
cd ~ && rm -rf mynodejsapp && rm -f setup.sh
  1. Usuwanie projektu w celu usunięcia całej powiązanej infrastruktury i zasobów