Перейти к содержанию

Docker

Описание

Docker - способ изоляции приложений на уровне linux ядра (cgoups, namespaces), то есть контейнеризация приложений.

Основные принципы:

  • состоит из слоев - слепков состояний файловой системы (OverlayFS)
  • докер - не виртуальная машина
  • докер - контейнер с минимальным набором софта, необходимым для работы приложения
  • docker-way - не хранить никаких данных внутри контейнера
  • контейнер живет пока жив процесс pid=1, вокруг которого рождается контейнер
  • контейнер может работать как foreground, так и в background

Docker registry - хранилища образов (напр. Docker hub).

Docker image - набор слоёв, каждый из которых результат выполнения Dockerfile. Иначе - шаблон для запуска контейнера.

  • Образы хранятся в /var/lib/docker.
  • Из одного образа можно запустить сколько угодно контейнеров, из которых в свою очередь можно создать другие образы (build), то есть образы могу переиспользоваться.
  • Имя образа состоит из .
  • imageid у образа всегда один, но имена и теги могут быть разные.
  • Образ не будет удален, пока все теги не будут удалены.

Начало работы

Для работы необходимо установить docker-ce. Установка описана здесь https://docs.docker.com/engine/install/

Демо контейнер

git clone https://github.com/docker/doodle.git

# BUILD container
# -t - 
cd doodle\cheers2019 ; docker build -t 3xh4l3/cheers2019 .

# RUN container
# -i - interactive. Keep stdin open.
# -t - alloc pseudo tty
# -rm - remove container after exit
docker run -it --rm 3xh4l3/cheers2019

docker login &&
docker push 3xh4l3/cheers2019

daemon.json

  • Включаем поддержку IPv6
  • Меняем стандартную адресацию докера на свою
{
  "ipv6": true,
  "fixed-cidr-v6": "2001:db8:1::/64",
  "bip": "100.80.0.1/12",
  "default-address-pools": [{
    "base": "100.80.0.0/12",
    "size": 24 
  }]
}

Команды

Общее

# Запустить свой registry
docker run -d -p 5000:5000 --restart=always --name registry registry:2

# Удалить вообще все. Фактически сбросить к исходному состоянию
docker system prune -a

# Список сетей
docker network ls

# Настройки конкретной сети
docker network inspect <network name>

Образы

Создать образ можно командой docker build <context>

В качестве context может быть локальная директория или ссылка на git репозиторий или tar файл. Также можно передать через pipe один Dockerfile.

Примеры

# Список загруженных или собственных сбилженных образов
docker images

# Создание
docker build .
docker build -t <imagename> <directory with Dockerfile>
docker build --no-cache -t ...
docker build - < Dockerfile
docker build - < context.tar.gz
docker build github.com/creack/docker-firefox

# Переименовать образ
docker tag <existing image name> <new image name>

# Загрузить образ в reigstry (например dockerhub)
docker push <repository>

# Скачать образ
docker pull wallarm/node

# Удалить образ 
docker rmi <image>

Ключи:

  • --no-cache - полностью пересоздать образ
  • -t - название будущего образа (name:tag)
  • -f - Dockerfile (по-умолчанию PATH/Dockerfile)

Контейнеры

# Список запущенных контейнеров
docker ps

# Создать контейнер
docker run -name=<container> <image> <process>

# Запустить ранее остановленный контейнер
docker start <container>

# Остановка контейнера
docker container stop <container> # SGITERM
docker container kill <container> # SIGKILL

# Удалить контейнер(ы)
docker rm <container id>
docker container rm -f $(docker ps -aq) # Удалить все
docker container rm $(docker ps –aq) # Удалить только остановленные

# Выполнить команду в запущенном контейнере
docker exec -it <container> <command>

# Запустить контейнер, чтобы протестировать какую-нибудь фичу
docker run --name=php-test --rm -ti php:7.1-fpm-alpine /bin/sh

Хитрости

Посмотреть, какой командой был запущен контейнер

docker run --rm -v /var/run/docker.sock:/var/run/docker.sock assaflavie/runlike <container>

Dockerfile

Best ptractices https://docs.docker.com/develop/develop-images/dockerfile_best-practices/

Для создания своих образов используется docker build, который берет набор инструкций из Dockerfile.

Dockerfile - набор инструкций для создания нового образа.

  • Каждая законченная команда создает новый слой - результат выполнения команды.
  • Слои независимы друг от друга. Связанные команды должны запускаться черезе &&.
  • Постоянные данные сохраняются от слоя к слою.

Директивы:

  • FROM - образ, на основе которого создается контейнер или новый образ

  • MAINTAINER - автор

  • RUN - выполняет команды, результатом которых является новый слой (образ), который в свою очередь используется для следующих инструкций. То есть эта директива подготавливает контейнер к запуску процесса (CMD). Юзаем && и переносы \ для длинных команд.

# Команды можно запускать через &&
RUN echo 1 \
  && echo 2 \
  && echo 3 

# Можн установить аргументы
# -e - немедленно выйти, если какая-либо команда завершилась с ошибкой
# -x - вывод каждой выполняемой команды (полезно при дебаге)
RUN set -ex \
  && ...
  • CMD - определяет, какая команда (процесс) будет запущена в контейнере

    Может быть только одна инструкция CMD в докерфайле Процесс не должен уходить в background Вывод можно оставлять в stdout

  • ENTRYPOINT - если в CMD передаются только аргументы без исполняемого файла, то исполняемый файл должен быть указан в данной директиве, то есть итоговая команда = ENTRYPOINT + CMD
  • COPY - скопировать в контейнер файлы из текущей директории
  • EXPOSE - указать, какие порты показать наружу внутри сети докера. Чтобы этот порт был доступен с хост системы, нужно сделать маппинг портов в хост систему.
    docker run -p 80:80 <image>
    

    Внутри контейнера нельзя биндиться на локалхост

  • ADD -

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

Примеры

rabbitmq

FROM rabbitmq:management

ADD rabbitmq.conf /etc/rabbitmq/rabbitmq.conf
ADD definitions.json /etc/rabbitmq/

RUN chown rabbitmq:rabbitmq /etc/rabbitmq/rabbitmq.conf /etc/rabbitmq/definitions.json

CMD ["rabbitmq-server"]

Docker-compose

Docker-compose - yaml файл, который описывает как запускать и связывать между собой контейнеры для служб работающих обычно в связке. Например MySQL+Apache.

# Поднять один из контейнеров стека
docker-compose up -d postgres

Systemd

Для удобного запуска контейнеров их легко можно засунуть в systemd. Для этого создаем сервисфайл:

>/etc/systemd/system/example.service
systemctl daemon-reload
systemctl edit --full example.service 

Содержимое файла

[Unit]
Description=My example service in docker
Requires=docker.service
After=docker.service

[Service]
Restart=always
RestartSec=3
ExecStartPre=/bin/sh -c "/usr/bin/docker rm -f example 2> /dev/null || /bin/true"
ExecStart=/usr/bin/docker run --rm -a STDIN -a STDOUT -a STDERR -p 80:80  --name example
ExecStop=/usr/bin/docker stop example

[Install]
WantedBy=multi-user.target
Запускаем
systemctl restart example.service 
journalctl -u example.service --no-pager -f

Полезные сборки

php7-fpm + gd

latest

FROM php:7.0-fpm-alpine
RUN apk add --no-cache freetype libpng libjpeg-turbo freetype-dev libpng-dev libjpeg-turbo-dev && \
  docker-php-ext-configure gd \
    --with-freetype \
    --with-jpeg && \
  docker-php-ext-install -j$(nproc) gd && \
  apk del --no-cache freetype-dev libpng-dev libjpeg-turbo-dev

WORKDIR /usr/share/nginx/html/

#ADD /root/php.ini /usr/local/etc/php/conf.d/40-custom.ini

CMD ["php-fpm"]

7.0

FROM php:7.0-fpm-alpine

RUN apk add --no-cache freetype libpng libjpeg-turbo freetype-dev libpng-dev libjpeg-turbo-dev libxml2-dev libwebp-dev libxpm-dev
RUN docker-php-ext-install xml
RUN docker-php-ext-configure gd \
    --with-gd \
    --with-webp-dir \
    --with-jpeg-dir \
    --with-png-dir \
    --with-zlib-dir \
    --with-xpm-dir \
    --with-freetype-dir \
    --enable-gd-native-ttf && \
  docker-php-ext-install -j$(nproc) gd && \
  apk del --no-cache freetype-dev libpng-dev libjpeg-turbo-dev

WORKDIR /usr/share/nginx/html/

ADD php.ini /usr/local/etc/php/conf.d/40-custom.ini

CMD ["php-fpm"]

php.ini

error_reporting = E_ALL & ~E_NOTICE & ~E_STRICT
display_errors = on
short_open_tag = on
post_max_size = 200M
upload_max_filesize = 200M
date.timezone = Asia/Krasnoyarsk
;заремарить следующую строку, иначе письма будут терять поле FROM
mail.add_x_header = of

python

Классическое приложение

# first stage
FROM python:3.8 AS builder
COPY requirements.txt .

# install dependencies to the local user directory (eg. /root/.local)
RUN pip install --user -r requirements.txt

# second unnamed stage
FROM python:3.8-slim
WORKDIR /code

# copy only the dependencies installation from the 1st stage image
COPY --from=builder /root/.local /root/.local
COPY ./src .

# update PATH environment variable
ENV PATH=/root/.local:$PATH

CMD [ "python", "./server.py" ]

Тестовые окружения

Всяческие локальные среды для быстрого тестирования.

MySQL

docker volume create mysql-volume
docker run --name=test-mysql -p3306:3306 -v mysql-volume:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=my-secret-pw -d mysql/mysql-server:5.7
# Проверяем, что запустился
docker logs mk-mysql
# Логинимся, чтобы разрешить root подключаться не только с локалхоста
docker exec -it test-mysql bash
# Консоль контейнера
mysql -u root -p
# MySQL консоль
mysql> update mysql.user set host = ‘%’ where user=’root’;
mysql> flush privileges;