Jak spakować aplikację VueJS + NodeJS + MongoDB w Dockerze

Jak spakować aplikację VueJS + NodeJS + MongoDB w Dockerze
Jak można zrozumieć z poprzedniego artykułu, pracowałam przy różnych projektach. Pierwsze dni w nowym zespole zazwyczaj przebiegają podobnie: backendowiec siada obok mnie i dokonuje magicznych działań związanych z instalacją i wdrażaniem aplikacji. Docker jest nieoceniony dla frontendowców, ponieważ backend często napisany jest w szerokim zakresie stosów PHP/Java/Python/C#, a frontend nie musi za każdym razem odrywać backendu, aby wszystko zainstalować i uruchomić. Tylko w jednym miejscu widziałam zestawienie Docker-Jenkins z przejrzystym wdrożeniem, logami i zintegrowanymi testami automatycznymi.

O Dockerze napisano wiele szczegółowych artykułów. W tym artykule mowa będzie o wdrażaniu Single Page Application z wykorzystaniem VueJS/Vue Router, część serwerowa w postaci RESTful API z NodeJS, a jako baza danych wykorzystana zostanie MongoDB. Do opisu i uruchomienia kilku aplikacji-kontenerów używa się Docker Compose.

Po co potrzebny jest Docker

Docker umożliwia automatyzację procesu wdrażania aplikacji. Programista nie musi już samodzielnie instalować programów ani zmagać się z niekompatybilnością wersji na swoim komputerze. Wystarczy zainstalować Dockera i wpisać 1-2 polecenia w konsolę. Najwygodniej robić to na Linuxie.

Wprowadzenie

Instalujemy Docker i Docker compose

Struktura folderów

Tworzymy 2 foldery dla aplikacji klienckiej i serwerowej. Plik z rozszerzeniem .yml to konfiguracja Docker Compose, w której definiowane są i powiązane kontenery aplikacji.
docker-compose.yml:

version: "3"
services:
  mongo:
    container_name: mongo
    hostname: mongo
    image: mongo
    ports:
      - "27017:27017"
  server:
    build: server/
    #command: node ./server.js #tutaj można nadpisać CMD z Dockerfile w /server
    ports:
      - "3000:3000"
    links:
      - mongo
  client:
    build: client/
    #command: http-server ./dist #tutaj można nadpisać CMD z Dockerfile w /client
    network_mode: host
    ports:
      - "8089:8089"
    depends_on:
      - server

Tworzymy 3 usługi w Dockerze: dla NodeJS, MongoDB i dla statyków na Vue. Aby połączyć klienta z serwerem, dodano depends on server. Do powiązania MongoDB z serwerowym API używa się links mongo. Serwer, klient, mongo — to nazwy usług.

Klient na VueJS

W folderze /client znajduje się aplikacja na VueJS. Aplikacja została stworzona za pomocą Vue Cli. Podczas budowania obrazu aplikacja kliencka jest kompilowana do zestawu statycznych plików w folderze /dist. W Dockerfile opisano zestaw poleceń do budowy obrazu:

FROM node:10
WORKDIR /client
COPY ./package*.json ./
RUN npm install
RUN npm install -g http-server
COPY . .
RUN npm run build
EXPOSE 8081
CMD ["npm", "test:dev"]

Zwróć uwagę, że plik package.json jest kopiowany i instalowany osobno od pozostałych plików projektu. Ma to na celu poprawę wydajności, aby zawartość folderu /node_modules była cachowana przy kolejnych kompilacjach. Każda linia polecenia jest cachowana osobno.

Na koniec, podczas uruchamiania kontenera wykonywane jest polecenie npm run dev. To polecenie jest opisane w pliku package.json:


"scripts": {
	 "test:dev": "http-server dist -p 8081 -c 1 --push-state"
}

Aby uruchomić pliki z folderu /dist, globalnie instalowane jest http-server, a w dev-dependencies pakiet spa-http-server, aby Vue Router działał poprawnie. Flaga —push-state przekierowuje na index.html. Flaga -c z wartością 1 sekunda została dodana, aby http-server nie cachować skryptów. To przykładowa instalacja, w rzeczywistym projekcie lepiej używać nginx.

W sklepie Vuex tworzymy pole apiHost: 'http://localhost:3000', gdzie określany jest port NodeJS API. Część kliencka jest gotowa. Teraz wszystkie zapytania z klienta do backendu przechodzą na ten url.

NodeJS server API

W folderze /server tworzymy server.js i Dockerfile:


FROM node:10
WORKDIR /server
COPY ./package*.json ./
RUN npm install
COPY . .
EXPOSE 3000
CMD ["node", "server.js"]

W server.js jest określany url dla bazy danych const url = 'mongodb://mongo:27017/';. Zezwalamy na żądania cross-domain z klienta:


const clientUrl = 'http://localhost:8081';
const corsOptions = {
  origin: clientUrl,
  optionsSuccessStatus: 200,  // niektóre starsze przeglądarki (IE11, różne SmartTV) mają problemy z 204
};
app.use(cors());
app.all('/*', (req, res, next) => {
  res.header('Access-Control-Allow-Origin', clientUrl);
  res.header('Access-Control-Allow-Headers', 'X-Requested-With');
  next();
});
  app.get('/getProducts', cors(corsOptions), (req, res) => {
    products.getContent
      .then(data => res.json(data), err => res.json(err));
  });
  app.get('/getUsers', cors(corsOptions), (req, res) => {
    db.getUsers()
      .then(data => res.json(data), err => res.json(err));
  });

Podsumowanie

Teraz przejdźmy do katalogu projektu i uruchommy docker-compose build do budowy obrazów i docker-compose up do uruchamiania kontenerów. Polecenie uruchomi 3 kontenery: server, client, mongo. Dla serwera na NodeJS można skonfigurować hot-reload, powiązując go z folderem user. A klient w etapie rozwoju należy uruchamiać lokalnie z hot reload, uruchamiając osobno server i mongo. Aby uruchomić osobny serwis, wystarczy podać jego nazwę docker-compose up client. Pamiętaj, aby czasami wykonać prune i usunięcie kontenerów (containers), sieci (networks) i obrazów (images), aby zwolnić zasoby.

Pełny kod można zobaczyć tutaj. Projekt jest jeszcze w fazie rozwoju.

Źródło: habr.com

Kup niezawodny hosting stron z ochroną DDoS, serwery VPS VDS 🔥 Kup niezawodny hosting stron z ochroną DDoS, serwery VPS VDS - ProHoster