Docker: заметки веб-разработчика. Итерация вторая

от автора

Привет, друзья!

Продолжаю делиться с вами заметками о Docker.

Заметки состоят из 3 частей: первые две теоретические, третья практическая.

Если быть более конкретным:

  • первая часть посвящена самому Docker, Docker CLI и Dockerfile;
  • вторая часть полностью о Docker Compose;
  • в третьей части мы разработаем и «контейнеризуем» приложение, состоящее из клиента, сервера и базы данных, развернем его (задеплоим) и настроим CI/CD.

Это часть номер два.

Вот часть номер раз.

Пришел к выводу, что в первой части был излишне многословен, в этой части буду более лаконичным.

Хочу немного дополнить первую часть, а именно: показать парочку примеров Dockerfile для Node.js-приложений.

Пример с официального сайта Node.js

FROM node:16  # создание директории приложения WORKDIR /usr/src/app  # установка зависимостей # символ астериск ("*") используется для того чтобы по возможности # скопировать оба файла: `package.json` и `package-lock.json` COPY package*.json ./  RUN npm install # для создания сборки для продакшн # RUN npm ci --only=production  # копируем исходный код COPY . .  EXPOSE 4000 CMD [ "node", "server.js" ]

Инструкции COPY package*.json ./ и COPY . . выполняются по отдельности в целях извлечения максимальной выгоды из кеширования слоев. Зависимости проекта меняются на так часто, как файлы, не имеет смысла устанавливать их при каждой сборке образа.

Пример из статьи «10 лучших практик по контейнеризации Node.js-приложений с помощью Docker»

Пример является сокращенным и для продакшна.

FROM node:lts-alpine@sha256:b2da3316acdc2bec442190a1fe10dc094e7ba4121d029cb32075ff59bb27390a RUN apk add dumb-init ENV NODE_ENV production WORKDIR /usr/src/app COPY --chown=node:node . . RUN npm ci --only=production USER node CMD ['dumb-init', 'node', 'server.js']

Docker Compose

Compose — это инструмент для определения и запуска Docker-приложений, состоящих из нескольких контейнеров. Для настройки сервисов приложения используется файл docker-compose.yml.

Процесс использования Compose, как правило, состоит из 3 этапов:

  • определение среды приложения с помощью Dockerfile;
  • определение сервисов, из которых состоит приложение, в docker-compose.yml (для совместного запуска сервисов в изолированной среде);
  • выполнение команды docker compose up для запуска приложения.

Пример файла docker-compose.yml:

version: "3.9"  # опционально services:  web:    build: .    ports:      - "5000:5000"    volumes:      - .:/code      - logvolume:/var/log    links:      - redis  redis:    image: redis volumes:  logvolume: {}

Compose позволяет делать следующее:

  • запускать, останавливать и повторно собирать сервисы;
  • получать статус запущенных сервисов;
  • получать логи запущенных сервисов;
  • выполнять команды в сервисах.

Compose предоставляет следующие возможности:

  • создание нескольких изолированных сред на одном хосте;
  • сохранение данных томов при создании контейнеров;
  • повторное создание только модифицированных контейнеров;
  • передача переменных среды окружения и возможность создания разных сред (для разработки, продакшна и т.д.).

Начало работы с Docker Compose.

docker compose

Команда docker compose является альтернативой docker-compose CLI и используется для управления Compose.

# сигнатура docker-compose [-f <arg>...] [--profile <name>...] [options] [COMMAND] [ARGS...]  # основные флаги -f - путь к docker-compose.yml -p - название проекта --project-path - альтернативная рабочая директория (по умолчанию рабочей является директория, содержащая docker-compose.yml)  # основные команды up - создание и запуск сервисов down - остановка и удаление контейнеров, сетей, образов и томов start - запуск сервисов stop - остановка сервисов restart - перезапуск сервисов create - создание сервисов rm - удаление остановленных контейнеров run - выполнение одноразовой команды exec - выполнение команды в запущенном контейнере

Полный список флагов и команд.

docker-compose.yml

Файл Compose — это файл в формате YAML, определяющий сервисы, сети и тома. Дефолтным путем этого файла является ./docker-compose.yml.

Определение сервиса включает в себя установку настроек, которые применяются к каждому контейнеру, запущенному для этого сервиса. Это похоже на передачу аргументов при выполнении команды docker run. Определения сети и тома аналогично выполнению команд docker network create и docker volume create.

Настройки, определенные в Dockerfile, такие как CMD, EXPOSE, VOLUME и ENV не нуждаются в дублировании в docker-compose.yml.

Рассмотрим основные настройки сервисов.

build

Настройки, применяемые во время сборки.

build может определяться в виде строки — пути к контексту сборки:

version: "3.9" services:  webapp:    build: ./dir

Или в виде объекта, где context — путь к контексту, dockerfile — используемый Dockerfile и args — аргументы:

version: "3.9" services:  webapp:    build:      context: ./dir      dockerfile: Dockerfile-alternate      args:        buildno: 1

В случае с args аргументы должны быть определены в Dockerfile:

# syntax=docker/dockerfile:1  ARG buildno ARG gitcommithash  RUN echo "Номер сборки: $buildno" RUN echo "Основано на коммите: $gitcommithash"

build:  context: .  args:    buildno: 1    gitcommithash: cdc3b19    # or    - buildno=1    - gitcommithash=cdc3b19

network

Сеть, к которой подключается контейнер во время сборки (для использования при выполнении команды RUN):

build:  context: .  network: host # or build:  context: .  network: custom_network_1

command

Перезапись дефолтной команды:

command: bundle exec thin -p 3000

depends_on

Зависимость между сервисами. Это означает следующее:

  • docker compose up запускает сервисы в определенном порядке. В примере ниже db и redis запускаются перед web;
  • docker compose up SERVICE автоматически включает зависимости SERVICE. В примере docker compose up web также создает и запускает db и redis;
  • docker compose stop останавливает сервисы в определенном порядке. В примере web останавливается перед db и redis.

version: "3.9" services:  web:    build: .    depends_on:      - db      - redis    redis:      image: redis    db:      image: postgres

restart_policy

Политика перезапуска — определяет, как и когда контейнер должен перезапускаться:

  • condition: условие перезапуска — none, on-failure или any (значение по умолчанию);
  • delay: время между попытками (по умолчанию равняется 5s);
  • max_attempts: количество попыток (по умолчанию — бесконечное);
  • window: время принятия решения об успехе перезапуска (по умолчанию — немедленно).

version: "3.9" services:  redis:    image: redis:alpine    deploy:      restart_policy:        condition: on-failure        delay: 5s        max_attempts: 3        window: 120s

entrypoint

Перезапись дефолтной точки входа:

entrypoint: /code/entrypoint.sh

env_file

Извлечение переменных среды окружения из файла. Может быть единичным значением или списком.

Если файл Compose определен с помощью docker compose -f FILE, пути в env_file будут относительными директории, в которой находится этот файл.

Переменные, определенные в разделе environment, перезаписывают эти значения.

env_file: .env # or env_file:  - ./common.env  - ./apps/web.env  - /opt/runtime_opts.env

expose

Выставление портов без их публикации на хосте — порты будут доступны только связанным (linked) сервисам. Могут определяться только внутренние порты:

expose:  - "3000"  - "8000"

external_links

Подключение к контейнеру, запущенному за пределами docker-compose.yml или даже за пределами Compose. Особенно полезно для контейнеров, предоставляющих общие или распределенные сервисы:

external_links:  - redis_1  - project_db_1:mysql  - project_db_1:postgresql

Обратите внимание: внешние контейнеры должны быть подключены хотя бы к одной сети, к которой подключен сервис.

image

Образ для контейнера. Может быть репозиторием/тегом или частичным идентификатором (partial identifier):

image: redis image: node:16 image: example-registry.com:4000/postgresql

links

Подключение контейнера к другому сервису. Подключаемый сервис определяется с помощью названия сервиса и синонима ссылки (link alias) ("SERVICE:ALIAS") или только названия:

web:  links:    - "db"    - "db:database"    - "redis"

network_mode

Сетевой режим:

network_mode: "bridge" network_mode: "host" network_mode: "none"

networks

Сети для подключения:

services:  some-service:    networks:     - some-network     - other-network

ports

Выставление портов.

Короткий синтаксис позволяет делать следующее:

  • определять оба порта (HOST:CONTAINER);
  • определять только порт контейнера (для хоста выбирается эфемерный порт);
  • определять IP-адрес хоста для привязки (bind) и оба порта (значением по умолчанию является 0.0.0.0, что означает все интерфейсы) (IPADDR:HOSTPORT:CONTAINERPORT).

ports:  - "3000"  - "8000:8000"  - "9090-9091:8080-8081"  - "127.0.0.1:8001:8001"  - "127.0.0.1::5000"  - "6060:6060/udp"

Длинный синтаксис позволяет настраивать дополнительные поля:

  • target: порт контейнера;
  • published: порт хоста (доступный публично);
  • protocol: протокол порта (tcp или udp);
  • mode: host | ingress.

restart

Определение политики перезапуска. Значением по умолчанию является no, что означает отключение автоматического перезапуска. always означает перезапуск в любом случае. on-failure означает перезапуск только в случае аварийной остановки контейнера. unless-stopped означает перезапуск контейнера во всех случаев, кроме преднамеренной остановки:

restart: "no" restart: always restart: on-failure restart: unless-stopped

volumes

Монтирование путей хоста (host paths) или именованных томов (named volumes), определенных в виде дополнительных настроек сервиса.

Пути хоста могут монтироваться как часть определения сервиса. Их не нужно указывать в ключе volume на верхнем уровне.

Однако, если необходимо, чтобы тома использовались несколькими сервисами, они должны быть перечислены в таком volume.

В следующем примере именованный том mydata используется сервисом web, для отдельного сервиса определяется bind mount (первый путь в volumes сервиса db). db также использует именованный том dbdata (второй путь), но определяет его с помощью устаревшего строкового формата для монтирования именованных томов. Именованные тома указываются в ключе volume верхнего уровня:

version: "3.9" services:  web:    image: nginx:alpine    volumes:      - type: volume        source: mydata        target: /data        volume:          nocopy: true      - type: bind        source: ./static        target: /opt/app/static   db:    image: postgres:latest    volumes:      - "/var/run/postgres/postgres.sock:/var/run/postgres/postgres.sock"      - "dbdata:/var/lib/postgresql/data"  volumes:  mydata:  dbdata:

Короткий синтаксис

В этом случае используется формат [SOURCE:]TARGET[:MODE], где SOURCE — это путь хоста или именованный том, TARGET — это путь монтирования тома в контейнере и MODEro для доступа только для чтения и rw для доступа для чтения и записи (дефолтное значение).

Для монтирования могут использоваться относительные пути (путь вычисляется, начиная с директории с файлом Compose). Относительные пути должны начинаться с . или ...

volumes:  # определяем только путь и делегируем создание тома движку  - /var/lib/mysql   # определяем связывание (mapping) абсолютных путей  - /opt/data:/var/lib/mysql   # путь хоста относительно директории с файлом `Compose`  - ./cache:/tmp/cache   # путь относительно пользователя  - ~/configs:/etc/configs/:ro   # именованный том  - datavolume:/var/lib/mysql

Длинный синтаксис

Длинный синтаксис позволяет настраивать дополнительные поля:

  • type: тип монтирования — volume, bind, tmpfs или npipe;
  • source: источник монтирования, путь хоста для bind mount или название тома, определенное в верхнеуровневом volumes;
  • target: путь монтирования тома в контейнере;
  • read_only: индикатор доступности тома только для чтения;
  • bind: дополнительные настройки связывания:
    • propagation: режим распространения, используемый для связывания;
  • volume: дополнительные настройки тома:
    • nocopy: индикатор запрета копирования данных тома.

version: "3.9" services:  web:    image: nginx:alpine    ports:      - "80:80"    volumes:      - type: volume        source: mydata        target: /data        volume:          nocopy: true      - type: bind        source: ./static        target: /opt/app/static  networks:  webnet:  volumes:  mydata:

Другие настройки, соответствующие настройкам команды docker run

user: postgres working_dir: /code  domainname: foo.com hostname: foo ipc: host mac_address: 02:42:ac:11:65:43  privileged: true  read_only: true shm_size: 64M stdin_open: true tty: true

Примеры определения продолжительности

2.5s 10s 1m30s 2h32m 5h34m56s

Примеры определения байтовых значений

2b 1024kb 2048k 300m 1gb

Замена переменных

Настройки могут содержать переменные среды окружения. Compose использует значения переменных из терминала при выполнении команды docker compose. Например, предположим, что терминал содержит POSTGRES_VERSION=9.3 и применяется такая настройка:

db:  image: "postgres:${POSTGRES_VERSION}"

При выполнении docker compose значение переменной POSTGRES_VERSION в настройках заменяется на 9.3 и мы получаем postgres:9.3.

Если значение переменной не установлено, переменная в настройках заменяется пустой строкой и мы получаем postgres:.

Дефолтные значения переменных могут быть установлены в файле .env, который должен находиться в той же директории, что и файл Compose. Значения переменных в терминале перезаписывают значения, определенные в .env.

Поддерживается 2 варианта синтаксиса: $VAR и ${VAR}. Второй вариант предоставляет такие дополнительные возможности, как:

  • определение значений по умолчанию:
    • ${VAR:-default}: оценивается как default, когда VAR не установлена или является пустой;
    • ${VAR-default}: оценивается как default только когда VAR не установлена;
  • определение обязательных значений:
    • ${VAR:?error}: ошибка возникает, если VAR не установлена или является пустой;
    • ${VAR?error}: ошибка возникает, только если VAR не установлена.

Расширенные возможности интерполяции переменных типа ${VAR/foo/bar} в настоящее время не поддерживаются.

Спецификация файла Compose версии 3.

Это конец второй части.

Благодарю за внимание и happy coding!



ссылка на оригинал статьи https://habr.com/ru/company/timeweb/blog/597613/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *