Dockerize your JS app

$ whoami

Інна Іващук

Senior Software Engineer

JS developer, music fan, movie-dependent and Star Wars fan 🤓

May the Force be with you!

4+ роки з GlobalLogic

більше 5 років у веб-розробці

        GitHub page

  • Хмарні провайдери і контейнери

  • Що таке Docker? Базове використання

  • Мережа Docker

  • Запуск JS додатку у Docker контейнері

  • docker-compose

  • Kahoot time

  • Q&A

Agenda

Вже доводилось стикались із Docker?

Docker vs NodeJS в Google Trends

 Web Development

Docker

+

Можлива ситуація на проекті

Requested changes

Use new API for authentication

Login

Що необхідно зробити?

  • локально налаштовуємо і установлюємо все необхідне (Java, Gradle, Maven, Mongo, PostgreSQL and etc)
  • вносимо зміни в JavaScript файлику
  • перевіряємо наші зміни, використовуючи локально розвернуту API
  • і нарешті - commit & push

Можлива ситуація

  • Зміни розгорнуто/опубліковано (deployed/published)
  • QAs починають валідацію, але виявляється, що наші зміни працюють не так, як очукувалось

Як це можна зробити

  • Встановити Docker
  • Викачати останню версію бекенд сервіса з Docker реєстру
  • Запустити все локально
  • Внести зміни і перевірити все локально
  • Profit 🤩

Так і з'явився Docker

Хмари та контейнери

Що таке хмарні технології?

Хмарна система або технологія хмарних обчислень відноситься до обчислювальних компонентів (апаратне забезпечення, програмне забезпечення та інфраструктура), які забезпечують надання послуг хмарних обчислень, таких як SaaS (програмне забезпечення як послуга), PaaS (платформа як послуга) та IaaS (інфраструктура) як послуга) через мережу (тобто Інтернет).

Які хмарні технології або сервіси використовуєте?

Магія хмарних технологій

    Microsoft змогла опублікувати супутникові фотознімки Bing Maps на 2,5 петабайта за допомогою машинного навчання Azure для побудови віртуального світу Flight Simulator. Можна сказати, це справді хмара, яка оживляє гру. Azure також допомагає моделювати погоду в режимі реального часу.

Хмарні провайдери

Сучасна SDLC з CI/CD, контейнерами, оркестраторами та хмарами

Хмарні провайдери і контейнери

Deploy

Deploy

Deploy

Deploy

Що таке Docker?

Docker

Docker - це відкрита платформа для розробки, доставки та запуску додатків.

  • дозволяє відокремити ваші програми від інфраструктури, щоб мати змогу швидко доставити програмне забезпечення
  • дозволяє керувати своєю інфраструктурою так само, як і своїми додатками
  • дозволяє швидко доставити, протестувати та розгорнути код
  • дозволяє значно зменшити затримку між написанням коду та запуском його у виробництво

Контейнери та віртуальні машини (VM)

    Контейнер запускається в Linux і спільно використовує ядро хост-машини з іншими контейнерами. Він запускає дискретний процес, не займаючи більше пам'яті, ніж будь-який інший виконуваний файл, роблячи його легким.

   На відміну від цього, віртуальна машина (VM) запускає повноцінну “гостьову” операційну систему з віртуальним доступом до ресурсів хосту через гіпервізор. Взагалі, віртуальні машини несуть багато накладних витрат, окрім того, що витрачається логікою вашого додатка.

Docker та підтримка ОС

Docker Engine доступний на різних платформах Linux, macOS та Windows 10 через Docker Desktop та у вигляді статичної двійкової інсталяції. Знайдіть бажану операційну систему нижче.

Docker Engine

Docker Engine - це клієнт-серверна програма з 3 основними компонентами:

  • server - це тип довготривалої програми, що називається daemon процесом (команда dockerd)

  • REST API -  визначає інтерфейси, які програми можуть використовувати для комунікації з daemon та вказівок щодо того, що робити

  • command-line interface (CLI) - клієнт (docker команди)

 

Архітектура Docker 🐳

Docker використовує архітектуру клієнт-сервер.

  • Docker daemon (dockerd) слідкує за Docker API запитами та керує Docker , такими як зображення, контейнери, мережі та томи. Daemon також може спілкуватися з іншими daemon для управління послугами Docker
  • Docker client (docker) - основний спосіб взаємодії багатьох користувачів Docker з Docker. Команда docker використовує Docker API
  • Docker registry - зберігає образи (image) Docker. Може бути загальнодоступною або приватною

Docker об'єкт - IMAGE (образ)

IMAGE (образ) - це шаблон лише для читання з інструкціями щодо створення контейнера Docker. Часто образ базується на іншомих, з деякими додатковими налаштуваннями.

     Щоб створити власний образ  потрібно створити Dockerfile з для визначення кроків, необхідних для створення образу та його запуску. Кожна інструкція в Dockerfile створює шар у зображенні. Коли ви змінюєте файл Docker і перебудовуєте образ, перебудовуються лише ті шари, які змінилися.

Docker об'єкти - CONTAINERS (контейнери)

    Container - це запущений екземпляр образу (image). Ми можемо створювати, запускати, зупиняти, переміщувати або видаляти контейнер за допомогою Docker API або CLI. Можна підключити контейнер до однієї або декількох мереж, приєднати до нього сховище або навіть створити новий образ на основі його поточного стану.
    Контейнер визначається його образами (images), а також будь-якими параметрами конфігурації, які надаються йому під час створення або запуску.

Docker об'єкти - CONTAINERS (контейнери)

File system

environment config

application image

Container

Docker архітектура: Docker об'єкти

    Services дозволяють масштабувати контейнери за допомогою декількох  Docker deamons, які працюють разом у "swarm" з кількома менеджерами та працівниками. Кожен член "swarm" є демоном Docker, і всі демони спілкуються за допомогою API Docker. Послуга дозволяє визначити бажаний стан, наприклад кількість копій служби, яка повинна бути доступна в будь-який момент часу.

Docker Swarm vs. Kubernetes

Docker Swarm переваги:

  • накладання мереж
  • балансування навантаження
  • висока доступність та кілька функцій для масштабовання

 

Docker Swarm недоліки:

  • власні засоби моніторингу
  • API Docker обмежує функціональність
  • для зручного управління інтерфейсом потрібен сторонній інструмент, такий як Portainer.io

 

Docker Volumes

  • легше створити резервну копію або перенести, ніж прив'язувати монтування
  • можна керувати за допомогою команд Docker CLI або Docker API
  • працює як на контейнерах Linux, так і на Windows
  • можна безпечніше розподілити між кількома контейнерами
  • дозволяють зберігати томи на віддалених хостах або хмарних постачальниках, шифрувати вміст томів або додавати інші функції
    вміст нових томів може бути попередньо заповнений контейнером
  • Docker Desktop має набагато вищу продуктивність, ніж монтування прив'язки з хостів Mac і Windows

 

Список основних Docker команд

$ docker run – запускає команду в новому контейнері

$ docker start – запускає або декілька зупинених контейнерів

$ docker stop – зупиняє один або декілька запущених контейнерів

$ docker build – будує образ (image), використовуючи Dockerfile

$ docker pull – витягує образ (image) з Docker реєстру

$ docker push – публікація образу (image) в Docker реєстру

$ docker ps - список контейнерів

$ docker images - список образів (images)

$ docker exec – виконати команду в run-time контейнера

$ docker search – пошук образу в Docker Hub

$ docker stats  відображати в реальному часі статистику використання ресурсів контейнерами

 

Повний список доступних команд можна знайти тут - Docker документація

$ docker stop $(docker ps -a -q) – зупинити всі контейнери

$ docker rm $(docker ps -a -q) – видалити всі зупинені контейнери
$ docker rm container-id – видалити контери по ID

$ docker rmi $(docker images -q) – видалити всі образи (images)

$ docker rmi image-id – видалити образ (image) по ID

 

Корисні Docker команди

Мережа Docker

Огляд мереж

    Однією з причин, чому контейнери та служби Docker настільки потужні, є те, що існує можливість з'єднати їх разом або підключити до робочих навантажень, що не належать Docker. Контейнери та служби Docker навіть не повинні знати, що вони розгорнуті на Docker, чи їх "peers" також є робочим навантаженням Docker чи ні.

Незалежно від того, чи працюють ваші хости Docker під управлінням Linux, Windows або їх поєднання, ви можете використовувати Docker для управління ними за допомогою платформного агностику.

Мережеві драйвери

Мережеву підсистему Docker можна підключити за допомогою драйверів. Кілька драйверів існують за замовчуванням і забезпечують базову функціональність мережі:

 

bridge

host

overlay

macvlan

none

Мережевий драйвер: Bridge

172.18.0.1

172.18.0.2

172.18.0.3

Мережевий драйвер: Host

Docker host

port:8080

Мережевий драйвер: Overlay

Docker host 1

Docker host 2

Мережевий драйвер: macvlan

Docker host

LAN

Підсумок

  • bridge мережі найкраще підходять, коли для спілкування на одному хості  між декількома контейнерами
  • host мережі найкраще підходять, коли мережевий стек не повинен бути ізольований від хоста Docker, але ви хочете, щоб інші аспекти контейнера були ізольованими
  • overlay мережі найкращі, коли вам потрібні контейнери, що працюють на різних хостах Docker для спілкування, або коли декілька програм працюють разом, використовуючи служби swarm
  • macvlan мережі найкраще підходять, коли потрібна установка VM або потрібно, щоб контейнери виглядати як фізичні хости у вашій мережі, кожен з яких має унікальну MAC-адресу
  • і ще одне - third-party мережеві плагіни  дозволяють виконати інтеграцію Docker із специфічним мережевим стеком

Деталі мережі

  • NETWORK ID —  ідентифікатор мережі, який присвоюється під час створення
  • NAME — ім'я мережі, можна налаштувати
  • DRIVER — драйвер використаний при створенні
  • SCOPE — місце, де використовується
$ docker network ls

NETWORK ID          NAME                DRIVER              SCOPE
6df045e07b11        bridge              bridge              local
9d45c14e604a        host                host                local
b285e48f2c94        none                null                local

Щоб перевірити детальну інформацію по мережі:

Створення мережі

$ docker network create bridge-network

Існує декілька варіантів:

​- найпростіший спосіб

$ docker network create --driver=bridge bridge-network

​- приклад з використанням overlay драйвера

$ docker network create -d overlay my-multihost-network

$ docker network create --driver overlay overlay_network
$ docker network create -d macvlan \
 >   --subnet=172.16.86.0/24 \
 >   --gateway=172.16.86.1 \
 >   -o parent=eth0 \
 >   my-macvlan-net

​- macvlan створення

Час запустити наш додаток, використовуючи Docker

Dockerfile

Необхідно створити Dockerfile в директорії нашого додатку

FROM mhart/alpine-node:14

# Create app directory
WORKDIR /usr/src/app

# A wildcard is used to ensure both package.json 
# AND package-lock.json are copied
COPY package*.json ./

# Install app dependencies
RUN yarn

# Bundle app source
COPY . .

# Build the app
RUN yarn build

EXPOSE 8080

# run CMD command "yarn start:prod"
CMD [ "node", "dist/main.js" ]

.dockerignore

Додати .dockerignore файл в тій же директорії

node_modules
npm-debug.log

Тепер можна створити образ (image)

Потрібно перейти до каталогу, в якому є знаходиться Dockerfile, і виконати наступну команду для створення образу (image) Docker. Прапорець -t дозволяє позначити образ, щоб його було легше знайти пізніше за допомогою команди docker images:

docker build -t myapp/nest-user-service .

Тепер образ (image) буде достпний для Docker:

$ docker images

# Example
REPOSITORY                      TAG        ID              CREATED
node                            12         1934b0b038d1    5 days ago
myapp/user-service              latest     d64d3505b0d2    1 minute ago

Запуск образу (image)

Запуск обазу за допомогою -d, запускає контейнер у від'єднаному режимі, залишаючи контейнер працюючим у фоновому режимі. Прапорець -p переспрямовує загальнодоступний порт до приватного порту всередині контейнера. Можна запустити раніше створений образ:

docker run -p 3030:8080 -d myapp/nest-user-service

Виведемо деталі нашого додатка:

# Get container ID
$ docker ps

# Print app output
$ docker logs <container id>

# Example
Running on http://localhost:8080

Перевірка контейнерів

Щоб протестувати свою програму, потрібно отримати порт нашого додатку, який Docker надав:
 

 
$ docker ps

# Example
ID            IMAGE                                COMMAND    ...   PORTS
ecce33b30ebf  myapp/nest-user-service:latest            npm start  ...   3030->8080

У наведеному вище прикладі Docker виконав меппінг порту 8080 всередині контейнера на порт 3030 на даній машині.

А як нарахунок інших сервісів або MondoDB? 

docker-compose допоможе нам з цією задачею

docker-compose

Що таке docker-compose?

     Compose - це інструмент для визначення та запуску багатоконтейнерних програм Docker.

     Використовуючи docker-compose,  з допомогою YAML файлів можна виконати налаштування додатку. Потім за допомогою однієї команди створити та запустити всі сервіси з використанням конфігурації.

Працює у будь-якому середовищі: production, staging, development, testing, а також робочі процеси CI.

Використання docker-compose це буквально три кроки:

  1. Визначте середовище додатку за допомогою Dockerfile, щоб його можна було відтворювати де завгодно

  2. Визначте сервіси, з яких складається додаток, у docker-compose.yml, щоб їх можна було запускати разом в ізольованому середовищі

  3. Виконати docker-compose up, щоб запустити всі сервіси додатоку

Крок 1: Створити Dockerfile

На цьому кроці конфігуруємо Dockerfile, який створює образ Docker. Образ буде містити всі залежності, яких необхідні для JS додатку, включаючи NodeJS.

FROM node:14

# Create app directory
WORKDIR /usr/src/app

# Install app dependencies
# A wildcard is used to ensure both package.json 
# AND package-lock.json are copied
COPY package*.json ./

RUN yarn


# Bundle app source
COPY . .

RUN yarn build

EXPOSE 8080
CMD [ "yarn", "start:prod" ]

Крок 2: Налаштувати сервіси у docker-compose.yml файлі

Створити файл docker-compose.yml в директорії проекту:

version: '3.3'
services:
  user-api:
    container_name: nest-user-service
    restart: always
    build: .
    ports:
      - '8080:3000'
    links:
      - mongo
  mongo:
    container_name: mongo
    image: mongo
    ports:
      - '27017:27017'

Даний файл  конфігурує два сервіса: user-api і mongo:

  •    user-api сервіс використовує образ, створений з використанням Dockerfile в даній директорії. Потім він прив’язує контейнер і хост машину до відкритого порту - 8080
  •    mongo сервіс використовує публічний Mongo образ (image), викачаний з реєстру Docker Hub

Крок 3: Створити і запустити додаток

З директорії проекту запустити програму, з допомогою команди:

Тепер можна перейти на http://localhost:8080/ в браузері, для того щоб перевірити чи додаток працює.

І для того, щоб перевірити доступні образи(image):

$ docker-compose up
docker image ls

Крок 5: Відредагувати compose файл та додати змінні середовища (env. vars.)

version: '3.3'
services:
  user-api:
    container_name: nest-user-service
    restart: always
    build: .
    ports:
      - '8080:3000'
    links:
      - mongo
    environment:
      - PORT=3000
      - DATABASE_URL=mongodb://mongo:27017/users
  mongo:
    container_name: mongo
    image: mongo
    ports:
      - '27017:27017'

Just do it

Популярне питання - "Як перебудувати тільки один сервіс?"

$ docker-compose up -d --force-recreate --no-deps --build user-api

Kahoot time     

Q & A

Код використаний на вебінарі - user-service

Налаштований CI/CD - GitHub Actions

Dockerize your JS app

By Inna Ivashchuk

Dockerize your JS app

Docker & docker-compose

  • 647