#docker #dockerfile
#docker #dockerfile
Вопрос:
Я новичок в docker и пытаюсь понять идею базового образа. Чтобы уточнить свой вопрос, я хотел бы привести пример MySQL. Я вижу в Dockerfile MySQL, что он использует Ubuntu в качестве базового образа. Обязательно ли, чтобы он использовал базовый образ Linux?
Насколько я понимаю, когда мы используем обычную ОС (например, Ubuntu), MySQL будет использовать системные вызовы Linux для выполнения чтения / записи в постоянное хранилище. Таким образом, я ожидаю, что MySQL в docker будет делать то же самое, ожидать, что системные вызовы, выполняемые с образом Ubuntu, на котором установлен MySQL, будут переведены docker в системные вызовы, выполняемые операционной системой ядра хоста. Правильно ли я понимаю?
Это означало бы, что в образе ubuntu нет ядра, поэтому приложение, расположенное поверх образа Ubuntu, думает, что оно запущено в Ubuntu, за исключением того, что системные вызовы выполняются в операционной системе ядра, правильно ли это понимание?
Ответ №1:
Образы Docker не требуют строго базового образа.
Вы можете начать свой Dockerfile со строки С нуля. Это дает указание Docker создать изображение, в котором в качестве первого слоя ничего нет.
Смотрите: https://hub.docker.com/_/scratch
Это то, что вы делаете, когда собираетесь самостоятельно вставлять все двоичные файлы, которые хотите, в свое изображение.
Если вы посмотрите на образ Ubuntu, вы увидите, что он начинается с нуля:
Контейнеры Docker — это, по сути, просто пространства имен и контрольные группы в операционной системе хоста, которые изолируют набор ресурсов. Нет отдельного ядра или трансляции системного вызова. Это процессы, выполняемые непосредственно в ядре хоста, только изолированно.
Чтобы проиллюстрировать это, вы можете запустить systemd-cgtop
на главном компьютере, когда у вас запущены некоторые контейнеры. Ваши запущенные контейнеры будут отображаться в группе управления / docker /YOUR_CONTAINERS_ID, и вы сможете видеть, какие ресурсы потребляет каждый контейнер, точно так же, как вы видите процессы, запущенные в вашей группе управления при выполнении обычной top
команды.
Причина, по которой вы можете запускать практически любой вариант контейнера Linux практически на любой версии Linux, которая может запускать Docker, заключается в том, что ядро совместимо со всеми дистрибутивами. Именно поэтому вам также необходимо установить виртуальную машину Linux, чтобы иметь возможность запускать Docker в Windows и Mac.
Для получения более подробной информации смотрите: https://superuser.com/questions/889472/docker-containers-have-their-own-kernel-or-not
Ответ №2:
В этом контексте дистрибутив Linux — это просто набор файлов, и нет жесткого требования иметь «дистрибутив» в образе Docker.
Давайте возьмем простую классическую программу на C:
#include <stdio.h>
int main(int args, char **argv) {
printf("Hello, world!n");
return 0;
}
В обычной системе Linux gcc
будет создан двоичный файл ELF, в котором указано, что для запуска ему нужна библиотека libc.so.6
. При вызове программы printf()
реализация этого находится в этой библиотеке; и когда код этой библиотеки в конечном итоге выполняет системный вызов для записи в файловый дескриптор 1, он будет перенаправлен в ядро.
В Docker все контейнеры совместно используют ядро хоста, но имеют независимые изолированные файловые системы. Таким образом, до тех пор, пока образ содержит двоичный файл и все совместно используемые библиотеки, от которых он зависит, обычно для него не требуется дистрибутив Linux сам по себе. (Ядро не является частью образа, и если вы используете образ Ubuntu Docker, то «ядра Ubuntu» не существует; оно использует все, что использует хост.)
Если для вас это имеет смысл, и вы используете язык, который компилируется в собственные двоичные файлы (C, C , Go, Rust), то обычно вы можете создать статический двоичный файл и создать образ Docker, FROM scratch
содержащий только этот двоичный файл (без «дистрибутива», без библиотек, без оболочки; будьте осторожны, чтобы не использовать CMD string
форму Docker, потому что она будет запущена /bin/sh -c 'string'
, а у вас ее нет /bin/sh
). Или, если вы уверены в том, что делаете, вы можете создать образ, FROM scratch
содержащий /lib/ld-linux.so
загрузчик и разделяемые библиотеки, которые вам нужны, но не дистрибутив как таковой.
# Build the program, which needs a full C toolchain.
FROM ubuntu:18.04 AS builder
RUN apt-get update
amp;amp; DEBIAN_FRONTEND=noninteractive
apt-get install --no-install-recommends --assume-yes
build-essential
WORKDIR /app
COPY hello.c .
RUN gcc -static -o hello hello.c
# Then create an image that _only_ contains the static binary.
FROM scratch
COPY --from=builder /app/hello /hello
ENTRYPOINT ["/hello"]