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 i
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ą . 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ć . Projekt jest jeszcze w fazie rozwoju.
Źródło: habr.com
