Всем ли образам docker требуется базовый образ?

#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, вы увидите, что он начинается с нуля:

https://github.com/tianon/docker-brew-ubuntu-core/blob/3d44d0b838eeb78c5baee976a4a529976b326878/bionic/Dockerfile

Контейнеры 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"]