В этой статье мы расскажем про базовые техники работы с Docker, а также погрузим читателя в основы докеризации приложений.

Предполагается, что читатель что-то слышал про Docker и хотел бы начать знакомство с технологией. Мы постараемся упростить этот процесс.

Введение

Docker — это платформа, позволяющая запускать приложения в изолированных контейнерах. Контейнеры обеспечивают приложениям стабильную и предсказуемую среду, где бы они ни запускались, будь то компьютер разработчика/сервер/облако/кластер Kubernetes.

Docker обеспечивает повторяемость и консистентность проекта. Благодаря этому разработчики могут сосредоточиться непосредственно на разработке приложения, не беспокоясь о проблемах совместимости и настройке окружения.

Чтобы понять, как работает Docker, нужно иметь представление о его двух основных единицах: образ и контейнер.

Контейнеры

Контейнеры — это легковесные, изолированные среды выполнения, внутри которых работают приложения.

В отличие от виртуальных машин, контейнеры используют общее ядро операционной системы, что делает их менее затратными с точки зрения ресурсов. Это позволяет запускать больше контейнеров на одном сервере по сравнению с количеством виртуальных машин.

Контейнеры предоставляют множество преимуществ, включая:

  • Изоляцию. Каждое приложение (в идеале) работает в своей собственной, изолированной среде внутри контейнера;

  • Повторяемость. Docker гарантирует, что контейнер, который работает на машине разработчика, будет также работать и на сервере, без каких-либо неожиданностей;

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

Образы

Образ Docker — это статичное описание содержимого контейнера, включающее в себя все зависимости, настройки окружения, библиотеки и бинарные файлы, необходимые для выполнения приложения. Можно сказать, что образ является готовым к использованию шаблоном для создания контейнеров.

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

Например, вы можете взять официальный образ Go и добавить в него свой код, получив новый образ, готовый к развертыванию (подробнее в разделе о Dockerfile).

Процесс создания нового образа (из официальной документации Docker)
Процесс создания нового образа (из официальной документации Docker)

Запуск первого контейнера с Docker

Предположим, что вы уже установили Docker CLI или Docker Desktop для своей системы и, возможно, попытались запустить свой первый hello world контейнер командой docker run hello-world.

Разберем подробнее, какие действия выполняет эта команда:

  1. Docker ищет образ hello-world в локальном хранилище. Если образ не найдется, то Docker скачает его с Docker Hub;

  2. Далее Docker создает контейнер на основе этого образа и запускает его;

  3. Контейнер выполняет скрипт, который выводит на экран приветственное сообщение и завершает работу.

Весь описанный процесс можно наблюдать в терминале, в котором выполняется команда. Если все прошло успешно, вы увидите сообщение, подтверждающее успешный запуск контейнера и его работу:

Hello from Docker!
This message shows that your installation appears to be working correctly.

Основные команды

Docker предоставляет широкие возможности для управления контейнерами и образами с помощью команд CLI. В этом разделе мы рассмотрим основные команды Docker, которые помогут вам эффективно управлять контейнерами.

Запуск контейнера — это основное действие, которое вы будете выполнять в Docker. Мы уже запускали контейнер hello-world в предыдущем разделе.

Теперь попробуем запустить более сложное приложение. Например, официальный образ операционной системы Ubuntu: docker run -it ubuntu bash

Эта команда делает следующее:

  • флаг --it объединяет две опции: -i (interactive) и -t (tty)

-i (--interactive) означает, что запускаемый контейнер будет получать стандартный поток ввода с хоста и направлять его в приложение, работающее в контейнере. По-умолчанию контейнеры стартуют изолированно, и stdin запущенного приложения не имеет связи с внешним миром.

-t (--tty) указывает докеру создать для запущенного приложения псевдотерминал, что позволит удобно работать с ним из вашего терминала.

  • ubuntu — название образа, который мы запускаем Ubuntu;

  • bash — команда внутри контейнера ubuntu.

Чтобы остановить контейнер, используется команда: docker stop <container_id>

Где <container_id> — это идентификатор контейнера, который вы хотите остановить. Вы можете определить идентификатор контейнера с помощью следующей команды: docker ps. Эта команда выводит список запущенных контейнеров вместе с их идентификаторами.

Если вам нужно перезапустить контейнер, используйте команду docker restart: docker restart <container_id>. ID контейнера можно получить из вывода команды ps, однако большинство команд, работающих с ID контейнеров, могут работать и с названиями.

Чтобы удалить контейнер, необходимо сначала остановить его, а затем использовать команду rm: docker rm <container_id>

Для одновременной остановки и удаления контейнера можно использовать флаг -f (force): docker rm -f <container_id>

Управление образами Docker

Для загрузки образа без его запуска можно использовать команду pull, например, docker pull ubuntu. Эта команда загрузит в локальное хранилище последний (latest) образ Ubuntu, однако при необходимости можно указать конкретную версию образа: docker pull ubuntu:20.04

Чтобы увидеть все доступные на вашем компьютере образы, используйте команду: docker images

Для удаления образа используйте команду docker rmi (remove image): docker rmi <image_id>

Получить идентификатор образа можно с помощью команды docker images.

Dockerfile и образы Docker

В этом разделе мы подробно рассмотрим, что такое образы Docker, их роль в контейнеризации, а также процесс создания собственных образов с помощью Dockerfile. Мы также разберем контекст Dockerfile и многоступенчатую сборку.

Что такое образы Docker?

Образ Docker — это лёгкий, автономный и исполняемый пакет, включающий всё необходимое для запуска части программного обеспечения, включая код, среды выполнения, библиотеки и системные зависимости. Образы Docker служат шаблоном для создания контейнеров. Образы описываются с помощью Dockerfile. 

Dockerfile — это текстовый файл специального формата, содержащий команды для сборки Docker-образа. Эти команды описывают шаги, необходимые для установки зависимостей и конфигурации вашего приложения с учетом контекста приложения.

Контекст Dockerfile — это набор файлов, которые будут отправлены на Docker daemon для сборки образа. Часто это директория, в которой находится сам Dockerfile и любые другие файлы, необходимые для сборки (в основном, код).

Простой пример Dockerfile

Рассмотрим простой пример Dockerfile для приложения на Node.js:

# Указываем базовый образ
FROM node:14
# Устанавливаем рабочую директорию внутри будущего контейнера
WORKDIR /app
# Копируем package.json и package-lock.json в /app (./ из-за WORKDIR)
COPY package*.json ./
# Устанавливаем зависимости
RUN npm install
# Копируем файлы приложения (с хоста (контекст) в образ (/app))
COPY . .
# Открываем порт
EXPOSE 3000
# Запускаем приложение
CMD ["node", "server.js"]

Теперь можно попробовать собрать приложение: docker build -t node-app:latest

-t указывает docker собрать образ с тегом
node-app — название образа
latest — тег

После того, как Docker завершит сборку успехом, можно запустить приложение: docker run node-app

Крайне важное замечание про Dockerfile: каждая команда создает свой собственный слой образа. Из-за этого образы могут раздуваться до огромных размеров. Для того, чтобы этого не происходило, существует поэтапная сборка.

Поэтапная (multistage) сборка

multistage -сборка позволяет уменьшить размер итоговых образов, используя несколько команд FROM.

В качестве примера рассмотрим сборку простого Go-приложения:

# BUILD STAGE
FROM golang:1.16 AS build
WORKDIR /go/src/app
COPY . .
RUN go build -o myapp

# RUN STAGE
FROM alpine:latest
WORKDIR /root/
COPY --from=build /go/src/app/myapp .
CMD ["./myapp"]

В итоговый образ попадет только то, что было в образе alpine плюс исполняемый файл myapp.

Docker Hub, репозитории образов

Docker Hub — это репозиторий, который предоставляет разработчикам возможность легко обмениваться и управлять контейнерными образами.

С помощью Docker Hub вы можете:

- Искать и загружать публичные образы, предоставляемые сообществом;
- Создавать и делиться собственными изображениями;
- Управлять автоматическими сборками и интеграциями с системой контроля версий.

Docker Hub предлагает огромное количество публичных образов, таких как образы операционных систем, баз данных, веб-серверов и различных приложений. Использование этих образов позволяет экономить время и усилия при настройке и развертывании приложений.

Один из основных процессов работы с Docker Hub — это загрузка (pull) и выгрузка (push) образов. Начнем с того, как загрузить образ из Docker Hub.

Команда docker pull позволяет скачать нужный образ на локальную машину.
docker pull ubuntu:latest

Эта команда загрузит последнюю версию образа Ubuntu. После загрузки образа, вы можете запустить контейнер на его основе:
docker run -it ubuntu:latest /bin/bash

Для выгрузки образов, сначала необходимо создать аккаунт на Docker Hub и авторизоваться в командной строке: docker login

После успешной авторизации, вы можете загрузить собственный образ. Сначала убедитесь, что image отмечен тегом:
docker tag <image_id> your_dockerhub_username/repo_name:tag

Теперь можно загрузить образ: docker push
your_dockerhub_username/repo_name:tag

Docker Hub предоставляет множество готовых образов для популярных инструментов, которые могут значительно упростить разработку и развертывание ваших проектов.

Рассмотрим несколько из них:

  1. Alpine Linux (alpine) — это крошечный дистрибутив Linux на основе BusyBox, его образ имеет размер всего 5 МБ;

  2. PHP (php-cli, php-fpm) — образы для интерпретатора php, включает все необходимое для разработки под этот язык;

  3. MySQL (mysql) — здесь понятно, всем известная БД;

  4. NGINX (nginx) — пригодится для создания обратного прокси-сервера;

  5. Redis (redis) — высокопроизводительная in-memory база данных, используемая для кеширования и управления сессиями;

  6. Node.js (node) — среда выполнения JavaScript, необходимая для запуска серверного кода на базе Node.js.

Более того, почти у каждого популярного образа есть alpine- и slim-версии, отличающиеся от обычных базой в виде alpine, а также уменьшенным объемом (обычно, slim-версии не включают в себя инструменты для сборки, а предназначены только для исполнения).

Любой образ из Docker Hub можно подтянуть с помощью команды docker pulll. Использование готовых образов сокращает время на настройку окружения.

Также стоит отметить, что Docker Hub — не единственный репозиторий образов.

Так, Gitlab (по крайней мере, self-hosted-версия) предлагает вам свое хранилище, которое очень удобно использовать в связке с Gitlab CI.

Сети

Работа с сетями — это одна из ключевых составляющих контейнеризации в Docker. Отсутствие настройки сетевого взаимодействия контейнеров может привести к проблемам с доступом к вашим сервисам.

Docker предоставляет несколько драйверов сетевого взаимодействия, из которых наиболее распространённые — bridge, host и overlay.

Bridge

Этот сетевой режим используется по умолчанию. В нем создается виртуальный мост (bridge), который позволяет контейнерам общаться друг с другом и с хост-машиной.

При запуске контейнера создается виртуальный интерфейс и подключается к мосту, предоставляя контейнерам IP-адреса из определенного диапазона. Bridge-сеть позволяет изолировать контейнеры от других сетевых интерфейсов хост-машины.

Для подключения контейнера к сети, укажите имя сети при запуске контейнера с использованием флага --network

docker network create --driver bridge app_network
docker run -d --network app_network --name app nginx

Host

В этом режиме контейнер использует сетевой стек хост-машины. Это означает, что контейнер и хост имеют общий IP-адрес и порты. Host-сеть полезна для уменьшения сетевой задержки, однако она уменьшает изоляцию между контейнером и хостом.

docker run -d --network host nginx

Overlay

Этот режим в основном используется в кластерных средах и Docker Swarm.

Overlay-сети позволяют контейнерам, работающим на разных физических или виртуальных машинах, общаться друг с другом так, будто они находятся на одной сети. Это достигается путем создания распределенной сети поверх существующей физической инфраструктуры.

docker network create --driver overlay --subnet 10.0.9.0/24 my_overlay_network

Коммуникация между контейнерами является ключевым аспектом для микросервисной архитектуры и распределенных систем. В Docker вы можете легко настроить взаимодействие между контейнерами, используя созданные вами сети.

После подключения к одной сети, контейнеры могут общаться друг с другом по именам хоста: docker exec container2 ping container1. Это становится возможным благодаря встроенному DNS-сервису Docker.

Для списка доступных сетей используйте команду: docker network ls

Для отключения контейнера от сети используйте команду: docker network disconnect <network_name> <container_id>

Чтобы удалить сеть, используйте команду: docker network rm <network_name>

Docker Volumes и связывание контейнера с файловой системой хоста (bind mounts)

Volumes и bind mounts — два ключевых механизма для работы с данными в контейнерах. Они необходимы, чтобы эффективно управлять данными, обеспечивать их сохранность и доступность.

Docker volumes существуют, чтобы хранить данные отдельно от контейнера. Даже в случае, если контейнер удалится, данные, хранящиеся в volume, останутся нетронутыми, что важно, когда проект уже развернут на площадке.

Bind Mounts немного отличаются от volumes. Этот подход представляет собой простое монтирование директорий с хоста в директории внутри контейнера. Это позволяет контейнерам иметь прямой доступ к данным на хосте, что удобно для среды разработки и тестирования.

Когда вы используете bind mounts, Docker не управляет содержимым целевой директории. Это означает, что изменения, внесенные в файлы на хосте, будут немедленно отражаться внутри контейнера, и наоборот.

Примеры использования bind mount и volume с указанием --mountв команде run:

  • volume: type=volume,src=my_volume,target=/usr/local/data

  • bind mount: type=bind,src=/path/to/data,target=/usr/local/data

Можно заметить, что volume и bind mounts отличаются только типом и значением src. В случае с volumes вы указываете название тома, а в случае с bind mounts указывается путь на хосте, который нужно опрокинуть в контейнер.

Volumes

Bind mounts

Путь на хосте

Выбирает Docker

Указывается разработчиком

Создает новый volume

Да

Нет

Поддерживает драйверы volumes

Да

Нет

Для создания volumes и bind mount также может использоваться следующий синтаксис команды docker run: docker run -d -v /path/on/host:/path/in/container my_image в случае использования bind mounts.

Или  docker volume create my_volume && docker run -d -v my_volume:/data my_image в случае использования томов.

Теперь данные по пути /data внутри контейнера будут храниться в my_volume. Volume можно отключать, заменять и делать еще много всего. Разово создав volume, пересоздавать его не нужно.

Docker Compose

Docker Compose — это мощный инструмент, разработанный для упрощения работы с многоконтейнерными приложениями. Docker Compose позволяет вам описать и запустить сложные приложения, состоящие из нескольких контейнеров, с минимальными усилиями. В этом разделе мы погрузимся в основы Docker Compose и его применение.

Основные возможности Docker Compose включают:

  • Декларативное описание сервисов, volumes и networks в формате yaml;

  • Управление всеми службами, указанными в конфигурационном файле, при помощи единой утилиты docker compose;

  • Управление жизненным циклом контейнеров.

Рассмотрим пример простого веб-приложения, состоящего из веб-сервера и базы данных.

Без Docker Compose запуск такого приложения потребовал бы выполнения серии команд для каждого контейнера, ручной настройки сетей и volumes. Docker Compose позволяет автоматизировать этот процесс, описав конфигурацию проекта в одном файле.

Для начала работы с Docker Compose необходимо создать файл docker-compose.yml, в котором будет описана конфигурация вашего приложения. Рассмотрим пример файла, в котором описаны два контейнера: web и db.

services:
    web:
        image: nginx:latest
        ports:
            - "8000:80"
        networks:
            - app-network
    app: 
        build:
            args:
                user: www-data
                uid: 33
                app_mode: development
            context: .
            dockerfile: Dockerfile
         restart: always
         image: app
         container_name: app
         working_dir: /var/www/
         volumes:
             -'./:/var/www'
         networks:
             - app-network
    db:
        image: mysql:latest
        volumes:
            -'app-db:/var/lib/mysql'
        environment:
            DB_PASSWORD: password
        networks:
            - app-network
networks:
    app-network:
        name: app-network
            driver: bridge
volumes:
    app-db:
        driver: local

Структура docker-compose.yml
services содержит описание всех служб (контейнеров), участвующих в работе приложения.

web: Определяет контейнер с веб-сервером Nginx, который будет доступен на порту 80.
Синтаксис "8000:80" читается так: "host_port:container_port". Докер будет слушать 8000 порт на хосте и проксировать его в nginx-контейнер и обратно.

app: главный контейнер с приложением. Описывается в Dockerfile, использует контекст текущей директории (привычная всем точка). Делает bind mount "./"  в "/var/www" в контейнере.

db: Определяет контейнер с базой данных MySQL, в который передается переменная среды DB_PASSWORD. А также данные базы данных хранятся в volume app-db, чтобы не потерять информацию в случае остановки контейнера.

networks: Определяет пользовательские сети, в данном случае bridge-сеть app-network, используемую всеми контейнерами для связи друг с другом.

volumes: Определяет все необходимые тома, в данном случае том для базы данных.

Для запуска всех служб, описанных в docker-compose.yml, используйте команду: docker compose up (если у вас установлена старая версия Docker Compose, то скорее всего нужно запускать docker-compose, через дефис).

Эта команда построит, запустит и свяжет все контейнеры, описанные в файле. После выполнения команды вы будете видеть все логи в своем stdout. Добавив флаг -d, контейнеры запустятся в фоновом режиме: docker compose up -d

Чтобы остановить все контейнеры и сети, используйте команду: docker compose down

Управление контейнерами

Для управления отдельными службами Docker Compose предоставляет удобные команды.

  • Просмотр списка запущенных контейнеров: docker compose ps

  • Просмотр всех контейнеров: docker compose ps -a

  • Просмотр логов приложения: docker compose logs <container_name>

  • Перезапуск контейнера: docker compose restart <container_name>

Заключение

В этой статье мы постарались дать инструкцию по использованию базовых техник работы с Docker для тех, кто только начинает знакомство с данной технологией.

Конечно, рассказать о Docker еще можно много. Пишите, что вас интересует, и, возможно, именно ваш комментарий станет темой для нашей следующей статьи.

Комментарии (49)


  1. fujinon
    18.06.2024 21:14

    В примере с docker compose сеть app-network не нужна, уберите ее совсем и docker compose создаст сеть по умолчанию.


    1. cyberia_studio Автор
      18.06.2024 21:14
      +3

      Можно. Но хорошим тоном будет всегда указывать сети явно. Например, если на сервере работает не один проект, а два и больше.


      1. mayorovp
        18.06.2024 21:14
        +4

        Хорошим тоном будет не создавать лишних сетей. Сеть default создаётся всегда, и "создавая сеть явно" вы удваиваете число создаваемых сетей на проект. Зачем?


        1. doox911
          18.06.2024 21:14

          А почему удваивается?


          1. mayorovp
            18.06.2024 21:14

            Потому что 2 в 2 раза больше чем 1.


        1. fujinon
          18.06.2024 21:14
          +1

          Не совсем всегда, а когда есть хотя бы один контейнер без кастомной сети. В данном примере будет создана только одна сеть app-network, но если хотя бы в одном из 3 контейнеров закомментировать networks, то дополнительно создастся XXX_default.


          1. mayorovp
            18.06.2024 21:14

            Странно, у меня создавалась всегда...


            1. fujinon
              18.06.2024 21:14

              Просто прогоните пример из статьи и убедитесь, делов-то) только сначала придется исправить опечатки))


        1. opusmode
          18.06.2024 21:14
          +1

          Смотрите, про хороший тон я не знаю, однако объясню вам логику, которая может быть.

          Итак, есть некий компоуз. В общем случае он действительно может запускаться где угодно и иметь дефолтную подсеть. Однако бывают случаи, когда мы не совсем знаем, где придётся его развернуть и толгда подсеть будет уже и не дефолтная.

          Опять же, в общем случае это как бы и не проблема - ну, а какая разница? Сервисы изолированы там, порты биндятся, всё круто, так? Так, но не совсем. БЫвают случаи, когда в компоузе указываются все имеющиеся сервисы, а после создаются профили. Например сервер или кластер СУБД может быть вынесен во вне. Или быть на хосте. Или ещё как-то. Почему так? Да в целом не ажно - так бывает. А ещё там может быть фаеволл. А ещё приложение может быть составным - ну, например, разные микросервисы, которые общаются друг с другом по API. Опять же, не спрашивайте, почему такое может быть. И да, может это не совсем нормальная ситуация, но жизнь вообще не идеально.

          Следовательно, мы не хотим годать, что там на хосте и в какую подсеть попадёт то или иное. Мы ведь докер зачем используем? Чтобы получать ожидаемые результаты, верно? Вот мы как бы и пишем сеть, что бы покрыть не самый удачный вариант и не гадать, каким сетян надо открыть доступы, куда стучаться, ну и вот это вот всё.

          Что нам это даёт? ДА банально экономию времени, как бы отсекая потенциальный траблшутинг. Перестраховка это? Да. Надо делать нормально и лучше контролировать ситуацию? Да. Но иногда это невозможно и написание нескольких строчек впрок создаёт меньше головняка, чем 1 лишняя сеть на хосте.

          А потом появляется привычка просто сразу закладывать риски, даже маловероятные.


          1. mayorovp
            18.06.2024 21:14

            Ну и какая во всех перечисленных вами случаях разница, дефолтная сеть используется контейнером или не дефолтная? Они ж отличаются только названием, и то если им название не указали явно...


  1. riky
    18.06.2024 21:14
    +1

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


    1. vvzvlad
      18.06.2024 21:14

      я хотел бы установить один сервер mysql на хосте для использования в разных проектах

      Зачем на хосте?


      1. riky
        18.06.2024 21:14
        +1

        можно и в докере. будет сильно проще?


        1. cat-chi
          18.06.2024 21:14

          В общем-то всё, что нужно – чтобы до сервера mysql был доступ из проектов. И тут даже неважно, docker или не docker, важно как настроена сеть и т.п.

          Может у вас все проекты в одной внутренней сети докера крутятся с mysql, тогда конечно проще.

          Или у вас отдельный хост конкретно под mysql, и тогда для проектов вообще не важно, как именно он развёрнут, они с ним будут работать как с чёрным ящиком.

          Тогда вопрос уже в том, важны ли накладные расходы, которые создаёт docker, на производительность диска, например.


          1. riky
            18.06.2024 21:14

            ну вот например есть сервис в контейнере который хочет подключиться в БД. какой хост указать в настройках сервиса чтобы он мог достучаться до mysql установленной на основном хосте? контейнеру сервиса надо добавлять сеть bridge ?


            1. cat-chi
              18.06.2024 21:14
              +1

              "Кошерный" путь – использовать особую магию докера. Добавить опцию host.docker.internal:host-gateway

              В compose-файле это будет выглядить как дополнительная запись в настройках сервиса:

              extra_hosts:
              - "host.docker.internal:host-gateway"

              После этого нужно будет настроить сервер mysql, чтобы он слушал сеть докера. И это при условии, что сервис поднят в сети докера по-умолчанию...

              В общем, не знаю, шаманство какое-то, сам таким не пользовался. Проще и правда поднять mysql в контейнере в той же сети, что и сервис.

              P.S. Более простой путь – выбрать тип сети host для контейнера с сервисом. Тогда он сможет дойти до mysql просто по localhost. Но это не секьюрно.


              1. koreychenko
                18.06.2024 21:14
                +1

                Можно поднять общий контейнер с базой, явно указать ему network name а дальше использовать этот network для контейнеров из других проектов, где нужно использовать эту базу.


            1. ainu
              18.06.2024 21:14
              +3

              Вообще, mysql может работать через линукс-сокеты, это надо и mysql и клиента подключить к одинаковой директории вроде

              volumes:
              - /var/run/mysqld/:/var/run/mysqld/


            1. fujinon
              18.06.2024 21:14

              Если я правильно понял, у вас на одной и той же машине БД не в контейнере и сервис в контейнере? Если так, то из внутренней сети контейнера IP-адрес хоста - это всегда 172.17.0.1.
              Но как тут уже сказали, лучше БД тоже поместить в контейнер, этот контейнер добавить в сеть сервиса, и тогда у БД внутри этой сети будет hostname, совпадающий с именем сервиса БД, который указан в docker-compose.yml.


              1. mayorovp
                18.06.2024 21:14

                IP-адрес хоста не может быть всегда 172.17.0.1 хотя бы потому, что он зависит от того, в какую сеть попал контейнер и какие у этой сети настройки.


        1. colesnic89
          18.06.2024 21:14

          Да хоть 50 баз данных, причем при необходимости можно даже разные версии ставить на одной хост машине


    1. Julegg
      18.06.2024 21:14
      +1

      Понятно что не тру, будет работать?

      А почему не должно работать? Вам надо будет лишь в проектах задавать один и тот же адрес и указывать корректное имя базы. А в случае, если запустите в контейнере - просто следить, чтобы контейнер работал.
      Вопрос только в том, что это не так уж и гибко.


    1. InTheWeb
      18.06.2024 21:14

      Будет, если поднять mysql как отдельный контейнер с пробросом порта на гостевую машину, все остальные контейнеры смогут взаимодействовать с ним по сети


  1. Sly_tom_cat
    18.06.2024 21:14
    +2

    Раз уж упомянут Golang и многоэтапная сборка, то неплохо бы упомянуть замечательную возможность golang - делать бинарики независимыми ни отчего вообще (ну на самом деле зависимость остается только от загрузчика программ ОС). Тогда образ второй фазы будет содержать только Go-шный бинарик.

    FROM golang:1.16 AS build
    WORKDIR /go/src/app
    COPY . .
    RUN go build -o myapp
    CGO_ENABLED=0 go build -o myapp

    FROM scratch
    WORKDIR /root/
    COPY --from=build /go/src/app/myapp .
    CMD ["./myapp"]


    1. Dancho67
      18.06.2024 21:14
      +11

      Эта фишка доступна любому статически компилируемому языку, не только лишь Go.


      1. cat-chi
        18.06.2024 21:14
        +1

        В других языках не всегда так просто отказаться от динамической линковки. Был болезненный опыт с C++... деталей уже не вспомню, давно было.

        А в Go всё собирается статически в 99% случаев.

        Кстати, а много вообще таких достаточно популярных языков, которые собирают код в статический бинарь и не тянут за собой тяжёлый рантайм?

        Ну вот например, можно ли как-то наколдовать "легковесную яву" в докере? У меня в своё время не получилось, но не могу сказать, что я сильно пытался.


    1. sergiodev
      18.06.2024 21:14

      В чём плюс этого подхода? У вас все зависимости просто зашитиы в бинарник, и теперь их нужно перекомпилёвывать и загружать в докер каждый раз заново, в то время как одна из главных особенностей докера - отделение зависимостей в отдельные слои, чтобы их каждый раз не качать.

      Я понимаю, если бы приходилось вручную деплоить экзешник на разные системы с разными установленными пакетами и потенциально без админских прав - тогда это безусловно было бы плюсом, а так не вижу преимуществ.


      1. Sulerad
        18.06.2024 21:14

        Если вы уже пишите на Go, то отказаться от статической линковки — задача нетривиальная. А если что так, что эдак, зависимости зашиваются в бинарник, то нет причин не уменьшить размер итогового образа.


      1. stvoid
        18.06.2024 21:14
        +3

        Вы вероятно не совсем поняли суть, которая тут происходит.

        1. У нас имеется образ с компилятором golang (это может быть любой образ, может вы собираете ffmpeg, там огромное количество всего вам понадобится). Этот образ, условно, пусть будет весить 600мб

        2. Компилируем бинарник (если это будет ffmpeg, то например компилируете его в один статичный бинарник, пусть на выходе это будет около 50мб)

        3. За конечный образ берете например alpine, т.к. у вас нет никакой линковки, то бинарник будет просто запускаться. Итог: конечный готовый образ у вас будет 60мб (условно), т.е. 50мб ffmpeg + OS alpine.

        Та часть dockerfile где мы компилировали мы можем выкинуть уже из системы.
        Аналогично делается сборка например веб приложений - собираем фронт в образе ноды, бинарник сервера в образе чего-либо, в конечный образ копируем результаты сборки фронта и бэка в любой легкий образ.


  1. a3000d
    18.06.2024 21:14
    +4

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


    1. cyberia_studio Автор
      18.06.2024 21:14
      +1

      Спасибо! Подумаем, можем ли мы развернуть эту тему в отдельной статье.


  1. Johan_Palych
    18.06.2024 21:14
    +1

    Почти все, что вы хотели бы знать про Docker

    https://www.google.com/search?q=docker+habr.com


  1. Sagittarius67
    18.06.2024 21:14
    +2

    - Создавать и делиться собственными изображениями;

    Фоточки можно хранить?


  1. MagMagals
    18.06.2024 21:14

    может еще кто подскажет как в докере запускать ui-приложения с открытием окна этого приложения в виндувсе


    1. Aquahawk
      18.06.2024 21:14
      +1

      без докера, но запустить gui приложение на сервере и пробросить иксы на винду умеет из коробки https://mobaxterm.mobatek.net/


  1. astroduck
    18.06.2024 21:14
    +1

    К сожалению, после того как полностью прикрыли возможность использовать Docker бесплатно для бизнеса, санкции практически закрыли возможность оплачивать лицензию, а в России так и не разрешили официально пиратить буржуйское ПО, есть большие сомнения по поводу целесообразности использования Docker в серьезных проектах. А также есть опасения что и дальше будут расти лицензионные ограничения. По сути это теперь не open source, хотя они пока и заявляют обратное.


    1. slonopotamus
      18.06.2024 21:14
      +3

      использовать Docker бесплатно для бизнес

      Мне кажется вы щас смешиваете три раздельные вещи:

      1. Исходники под открытой лицензией и совершенно бесплатны

      2. Качать образы с докерхаба можно совершенно бесплатно

      3. Аплоадить свои образы на докерхаб... Ну я бы очень подумал хорошо ли это с т.з. безопасности.


      1. ALexhha
        18.06.2024 21:14

        Качать образы с докерхаба можно совершенно бесплатно

        но есть лимиты

        Исходники под открытой лицензией и совершенно бесплатны

        ну тут скорее речь об docker desktop и иже с ними. Мы вот были вынуждены перейти на rancher desktop. Это просто боль и страдания после docker desktop


        1. slonopotamus
          18.06.2024 21:14
          +1

          но есть лимиты

          Поднять у себя в контуре кэширующую прокси полезно в любом случае на случай "докерхаб упал"/"кому-нибудь в очередной раз моча в голову ударила и заблокировали сетевую связь или с той или с этой стороны".


        1. slonopotamus
          18.06.2024 21:14
          +1

          Мы вот были вынуждены перейти на rancher desktop. Это просто боль и страдания после docker desktop

          А можете развернуть мысль? А то я тоже перешёл на rancher desktop и... Всё отлично работает.

          И про какую операционку на хост-машине речь? А то если там линукс, то польза от всех этих *desktop очень быстро стремится к нулю.


          1. ALexhha
            18.06.2024 21:14

            И про какую операционку на хост-машине речь? А то если там линукс, то
            польза от всех этих *desktop очень быстро стремится к нулю.

            macos intel/arm

            А можете развернуть мысль?

            когда в организации 1000+ пользователей то это боль. Начиная от ui, но это мелочи, и заканчивая непонятными вылетами. Еще была куча проблем со встроенным кубиком. И таких ошибок вагон и маленькая тележка.

            последнее что нашел в слеке
            % sudo launchctl load /Library/LaunchAgents/se.ivankrizsan.socat_launcher.plist
            Warning: Expecting a LaunchDaemons path since the command was ran as root. Got LaunchAgents instead.
            `launchctl bootstrap` is a recommended alternative.
            Load failed: 5: Input/output error
            Try running `launchctl bootstrap` as root for richer errors.

            А то я тоже перешёл на rancher desktop и... Всё отлично работает.

            у меня такая же нога и не болит ( с )


            1. slonopotamus
              18.06.2024 21:14

              у меня такая же нога и не болит ( с )

              Очевидно что не такая же, я потому и спросил в чём разница. Из вашего ответа стало понятно, разница в том что вы используете для серверной разработки наименее подходящую для этого операционку (а уж в arm исполнении там ещё больше приколов вылезает). А зачем вы это делаете?


              1. ALexhha
                18.06.2024 21:14

                Из вашего ответа стало понятно, разница в том что вы используете для
                серверной разработки

                что за серверная разработка )))

                а уж в arm исполнении там ещё больше приколов вылезает

                а пацаны то и не знали, оказывается arm фуфло ))) Просветите об этом всех облачных провайдеров, а то они тоже не в курсе по ходу. Проблемы были только с ранчером, с docker desktop особых проблем не было. Отсюда делаем вывод - что дело не в ОС

                наименее подходящую для этого операционку

                потому что в крупных организациях MacOS это отраслевой стандарт. Всякие windows/linux идут лесом


  1. YuriPanchul
    18.06.2024 21:14

    В стиле статьи чувствуется запах ChatGPT.

    Насколько я понимаю, главное назначение докера - это не возиться с несовместимостями между версиями питона в пакете Open Lane. Правильно?


    1. cyberia_studio Автор
      18.06.2024 21:14

      Главное назначение — обеспечить порядок в проектах, дать каждому приложению, развернутому в контейнере, свою, подходящую среду. Докер сам контролирует ресурсы между контерами, упрощает деплой и поддержку проектов.

      Также есть вытекающие ништяки в виде упрощения ввода нового члена команды в работу на проекте и удобное управление версиями артефактов в виде образов.


      1. YuriPanchul
        18.06.2024 21:14

        Я таких расплывчатых слов не понимаю. Что такое "порядок", "среда", "ресурсы", "образы"? Входят ли в "среду" следующее:

        1. Существование и содержимое файла /etc/udev/rules.d/90-intel-fpga.rules

        2. Версия tclsh, bash, prython3, make, gcc?

        3. Установленые пакеты для питона и тикля?

        4. Нахождение юзера в группе dialout для доступа к устройству /dev/ttyUSB0?

        5. Что еще?


  1. mikegordan
    18.06.2024 21:14
    +2

    "Всё что нужно знать"

    Мне не хватило

    1) почему ничего не написано про macvlan драйвер чтобы контейнеры получали IP как виртуальные машины от роутера и были доступны по IP из любого компьютера в твоей локальной сети

    2) как реализовать версионность образов. и тема как обновлять запущенные контейнеры на новые версии образов не коснулись в статье


    1. cyberia_studio Автор
      18.06.2024 21:14

      Версионность осуществляется с помощью тегов. Обновляется просто — обновляешь версию образа, пересоздаешь контейнер.


    1. ALexhha
      18.06.2024 21:14

      как реализовать версионность образов. и тема как обновлять запущенные контейнеры на новые версии образов не коснулись в статье

      это уже больше про ci/cd и Docker Swarm. Докер, как таковой, к этому особого отношения не имеет