data.mdx.frontmatter.hero_image

Mikroserwis Node z Docker-em

2017-04-23 | Docker, Node | bd90

Pamiętacie te czasy, gdy deploy aplikacji równał się z otworzeniem klienta FTP-a czy SFTP-a i przekopiowaniu plików na serwer? Prawdę mówiąc, mimo że mamy już 2017 rok, to z większością moich aplikacji nadal tak robię. Są to małe twory leżące na pojedynczych serwerach. Niewielki nakład pracy powodował, że nie odczuwałem motywacji do przeniesienia ich w świat kontenerów.

Co w przypadku, kiedy nasza aplikacja jest już bardziej skomplikowana, wymaga dobrze skonfigurowanego środowiska, a dodatkowo ma być łatwa w odpaleniu na innych serwerach?

Hej przygodo - przygotuj się na poznanie Docker-a!

Docker to łatwe i przyjemne w obsłudze narzędzie do umieszczania rozproszonych aplikacji w wirtualnych kontenerach. Obsługuje go większość serwerów Linuxowych.

Instalacja Docker-a

Windows

Jeżeli macie zainstalowany package manager chocolatey to do zainstalowania docker-a wystarczy wpisać pojedynczą komendę w konsoli:

C:\\> choco install docker

W przeciwnym wypadku instrukcje do zainstalowania chocolatey macie tutaj.

MAC OS X

Dla systemu spod znaku jabłka polecam instalację za pomocą obrazu ściągniętego ze strony docker-a . Próbowałem go instalować za pomocą brew, lecz nie działo to wtedy zbyt stabilnie (możliwe, że winę za to ponosiła instalacja wersji beta).

Linux

Opis jak zainstalować docker-a pod systemami operacyjnymi linux znajdziecie pod adresem https://docs.docker.com/engine/installation/linux/ubuntu/

Server Node.js

W chwili obecnej nie ma większego sensu skupiać się za bardzo na implementacji samego mikroserwisu. Jest to po prostu aplikacja serwująca "Hello World!" po wejściu na adres http://localhost:3000

const express = require('express')
const app = express()

app.get('/', (req, res) => res.send('Hello World!'))
app.listen(3000, () => console.log('Server is running on :3000'))

Wykorzystując framework https://expressjs.com/ możemy zmieścić się w 5 linijkach kodu. Do poprawnego działania musimy dodatkowo zainstalować paczkę experss prze npm-a.

$ npm init $ npm i -D express 

Następnie do pliku package.json dodać nowe zadanie w sekcji scripts:

"start": "node index.js"

Konfiguracja Docker-a

Najpierw, aby dodać docker-a do projektu, musimy stworzyć pliki Dockerfile i .dockerignore

$ touch Dockerfile $ touch .dockerignore 

Następnie przechodzimy do uzupełnienia pliku .dockerignore, który przypomina plik .gitignore. W tym pliku wypisujemy wszystkie pliki / foldery, których nie chcemy umieścić w obrazie docker-a. Dla naszej przykładowej aplikacji stworzymy następująca zawartosć pliku:

node_modules npm-debug.log 

Mając uzupełniony plik .dockerignore możemy przejść do napisania treści pliku Dockerfile. Jednak jeszcze przed "klepaniem" jeszcze jedna, bardzo ważna uwaga:

Każde polecenie w pliku tworzy nową warstwę w obrazie docker-a, dlatego warto utrzymywać ten plik tak krótki jak się tylko da.

Mając to na uwadze możemy przystąpić do tworzenia naszego obrazu. We wstępie musimy zdecydować, jaki obraz chcemy edytować. Mój wybór padł na node:boron, który jest obrazem ostatniej wersji LTS Node-a. Użycie tego obrazu definiujemy za pomocą komendy:

FROM node:boron

Następnie tworzymy "workspace" dla aplikacji. W tym właśnie miejscu będziemy przetrzymywać wszystkie źródła.

RUN mkdir -p /user/src/app WORKDIR /usr/src/app

Dodatkowo dzięki poleceniu WORKDIR ustawiliśmy naszą ścieżkę wykonywalną na stworzony wcześniej folder. Spowoduje to, że wszystkie polecenia jakie wywołamy będą odpalane w tej konkretnej lokacji.

Teraz musimy zająć się instalacją zależności naszej aplikacji. Potrzebujemy do tego pliku package.json.

COPY package.json /usr/src/app RUN npm install

Pewnie część z was zastanawia się, dlaczego w tym miejscu nie przekopiowałem całej aplikacji, pomimo tego że wcześniej pisałem o tym że każda komenda w pliku Dockerfile tworzy nową warstwę w obrazie docker-a. Jest to pewnego rodzaju wyjątek wpływający na optymalizacje. Oddzielenie kopiowania pliku package.json i instalacji zależności od kopiowania źródeł pozwala docker-owi na cache-owanie warstwy w której znajdują się wszystkie node_modules aż do momentu zmiany pliku package.json. Skutkiem tego jest brak przymusu ponownego pobierania modułów z npm-a przy każdym budowaniu obrazu .

Teraz po kolei:

Przechodzimy do kopiowania źródeł aplikacji,

COPY . /usr/src/app

Zdefiniowania porta, na którym nasza aplikacja będzie nasłuchiwać wewnątrz kontenera

EXPOSE 3000

I wisienka na torcie: odpalenia naszej aplikacji za pomocą skryptu npm

CMD ["npm", "start"]

Po tych wszystkich zabiegach plik DockerFile przedstawia się następująco:

FROM node:boron

# Create app directory
RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app

# Install app dependencies
COPY package.json /usr/src/app/
RUN npm install

# Bundle app source
COPY . /usr/src/app

EXPOSE 3000
CMD [ "npm", "start" ]

To jest moment, w którym możemy przejść do zwieńczenia naszego dzieła i zbudowania naszego obrazu docker-a. Wykonamy to za pomocą jednego polecenia docker build.

$ docker build -t bd90/node-microservice .

Polecam stosowanie flagi -t w komendzie build aby nadać prostą nazwę naszemu kontenerowi.

Jeśli wszystko zakończyło się bez błędów to po wpisaniu komendy:

$ docker images

Po wszystkim, co uczyniliśmy, powinniśmy otrzymać listę wszystkich naszych obrazów docker-a, a na niej obraz o wdzięcznej nazwie bd90/node-microservice.

Żeby uruchomić kontener na naszym komputerze i zbindować jego port 3000 z portem 8000 musimy wywołać komendę docker run z wykorzystanie flag -p (ustawienia portu) i -d (ustawieniem, który kontener ma zostać uruchomiony).

$ docker run -p 8000:3000 -d bd90/node-microservice

Po wykonaniu tej komendy nasza aplikacja powinna być dostępna pod adresem http://localhost:8000.

Na koniec jeden mały tip: Wszystkie aktywne kontenery możemy wypisać za pomocą polecenia docker ps.

$ docker ps

I to by było na tyle, jeśli chodzi o początek przygody z Docker-em i wykorzystaniem go do poskromienia procesu zarządzania mikroserwisem od strony DevOps-owej.

Mam nadzieje że komuś przyda się ten artykuł i do następnego :)

By Bd90 | 23-04-2017 | Docker, Node