Существует два способа создания образов. Вы можете изменить существующий контейнер, а затем зафиксировать его как новый образ, или вы можете написать свой Dockerfile и создать его для образа. Мы перейдем к обоим и объясним плюсы и минусы.
Ручные сборки
С помощью ручных сборок вы обрабатываете свой контейнер как обычный компьютер. Вы устанавливаете пакеты, вы пишете файлы, и когда все это будет сказано и сделано, вы фиксируете его и получаете новый образ, который вы используете в качестве шаблона, чтобы создать еще много идентичных контейнеров или даже основывать другие образы.
Начнем с alpine image, которое является очень маленьким и спартанским образов на основе Alpine Linux. Мы можем запустить его в интерактивном режиме, чтобы попасть в оболочку. Наша цель – добавить файл « yeah», содержащий текст «it works!». В корневой каталог, а затем создать новое изображение из него, называемое «да-альпийское».
Вот так. Приятно, мы уже в корневом каталоге. Посмотрим, что там.
1 | > docker run -it alpine /bin/sh |
2 | / # ls |
3 | bin dev etc home lib linuxrc media mnt proc root run sbin srv sys tmp usr var |
Какой редактор доступен? Нет vim, нет nano?
1 | / # vim |
2 | /bin/sh: vim: not found |
3 | / # nano |
4 | /bin/sh: nano: not found |
Ну что ж. Мы просто хотим создать файл:
1 | / # echo “it works!” > yeah |
2 | / # cat yeah |
3 | it works! |
4 |
Я вышел из интерактивной оболочки, и я вижу контейнер с именем «vibrant_spenc» с docker ps -all
. Флаг -all
важен, потому что контейнер больше не работает.
1 | > docker ps –all |
2 | CONTAINER ID IMAGE COMMAND CREATED STATUS NAMES |
3 | c8faeb05de5f alpine “/bin/sh” 6 minutes ago Exited vibrant_spence |
Здесь я создаю новый образ из контейнера «vibrate_spence». Я добавил сообщение о фиксации «mine, mine, mine» в качестве отметки.
1 | > docker commit -m “mine, mine, mine” vibrant_spence yeah-alpine |
2 | sha256:e3c98cd21f4d85a1428…e220da99995fd8bf6b49aa |
Давайте посмотрим. Да, есть новый образ, и в его истории вы можете увидеть новый слой с комментарием «mine, mine, mine».
1 | > docker images |
2 | REPOSITORY TAG IMAGE ID SIZE |
3 | yeah-alpine latest e3c98cd21f4d 4.8 MB |
4 | python latest 775dae9b960e 687 MB |
5 | d4w/nsenter latest 9e4f13a0901e 83.8 kB |
6 | ubuntu-with-ssh latest 87391dca396d 221 MB |
7 | ubuntu latest bd3d4369aebc 127 MB |
8 | hello-world latest c54a2cc56cbb 1.85 kB |
9 | alpine latest 4e38e38c8ce0 4.8 MB |
10 | nsqio/nsq latest 2a82c70fe5e3 70.7 MB |
11 | |
12 | > docker history yeah-alpine |
13 | IMAGE CREATED SIZE COMMENT |
14 | e3c98cd21f4d 40 seconds ago 66 B mine, mine, mine |
15 | 4e38e38c8ce0 7 months ago 4.8 MB |
Теперь для настоящего теста. Удалим контейнер и создадим новый контейнер из образа. Ожидаемый результат заключается в том, что файл «yeah» будет присутствовать в новом контейнере.
1 | > docker rm vibrant_spence |
2 | vibrant_spence |
3 | |
4 | > docker run -it yeah-alpine /bin/sh |
5 | / # cat yeah |
6 | it works! |
7 | / # |
Что я могу сказать? Да, это работает!
Использование Dockerfile
Создание образов из модифицированных контейнеров классно, но нет ответственности. Трудно отслеживать изменения и знать, каковы были конкретные изменения. Дисциплинированный способ создания образов состоит в их создании с помощью Dockerfile.
Dockerfile – текстовый файл, похожий на сценарий оболочки, но он поддерживает несколько команд. Каждая команда, которая модифицирует файловую систему, создает новый слой. В первой части мы обсудили важность правильного разделения образа на слои. Dockerfile – большая тема сама по себе.
Здесь я просто продемонстрирую пару команд для создания другого образа «oh-yeah-alpine» на основе Dockerfile. В дополнение к созданию печально известного файла «yeah», давайте также установим vim. В альпийском дистрибутиве Linux используется система управления пакетами под названием «apk». Вот наш Dockerfile:
1 | FROM alpine |
2 | |
3 | # Copy the “yeah” file from the host |
4 | COPY yeah /yeah |
5 | |
6 | # Update and install vim using apk |
7 | RUN apk update && apk add vim |
8 | |
9 | CMD cat /yeah |
Базовым образом является alpine. Он копирует файл «yeah» из одного и того же каталога хоста, где находится файл Dockerfile (путь контекста сборки). Затем он выполняет apk update
и устанавливает vim. Наконец, он устанавливает команду, которая выполняется при запуске контейнера. В этом случае он выведет на экран содержимое файла « yeah».
ОК. Теперь, когда мы знаем, к чему мы стремимся, давайте построим наш орбраз. Параметр «-t» задает репозиторий. Я не указал тег, поэтому он будет по умолчанию «последним».
1 | > docker build -t oh-yeah-alpine . |
2 | Sending build context to Docker daemon 3.072 kB |
3 | Step 1/4 : FROM alpine |
4 | —> 4e38e38c8ce0 |
5 | Step 2/4 : COPY yeah /yeah |
6 | —> 1b2a228cc2a5 |
7 | Removing intermediate container a6221f725845 |
8 | Step 3/4 : RUN apk update && apk add vim |
9 | —> Running in e2c0524bd792 |
10 | fetch https://dl-cdn.alpinelinux.org/…/APKINDEX.tar.gz |
11 | fetch http://dl-cdn.alpinelinux.org…/x86_64/APKINDEX.tar.gz |
12 | v3.4.6-60-gc61f5bf [http://dl-cdn.alpinelinux.org/alpine/v3.4/main] |
13 | v3.4.6-33-g38ef2d2 [http://dl-cdn.alpinelinux.org/…/v3.4/community] |
14 | OK: 5977 distinct packages available |
15 | (1/5) Installing lua5.2-libs (5.2.4-r2) |
16 | (2/5) Installing ncurses-terminfo-base (6.0-r7) |
17 | (3/5) Installing ncurses-terminfo (6.0-r7) |
18 | (4/5) Installing ncurses-libs (6.0-r7) |
19 | (5/5) Installing vim (7.4.1831-r2) |
20 | Executing busybox-1.24.2-r9.trigger |
21 | OK: 37 MiB in 16 packages |
22 | —> 7fa4cba6d14f |
23 | Removing intermediate container e2c0524bd792 |
24 | Step 4/4 : CMD cat /yeah |
25 | —> Running in 351b4f1c1eb1 |
26 | —> e124405f28f4 |
27 | Removing intermediate container 351b4f1c1eb1 |
28 | Successfully built e124405f28f4 |
Выглядит неплохо. Давайте проверим, что образ был создан:
1 | > docker images | grep oh-yeah |
2 | |
3 | oh-yeah-alpine latest e124405f28f4 About a minute ago 30.5 MB |
Обратите внимание, что установка vim и его зависимостей раздула размер контейнера с 4,8 Мбайт базового альпийского образа до массивных 30,5 МБ!
Все очень хорошо. Но работает ли это?
1 | > docker run oh-yeah-alpine |
2 | it works! |
О да, это работает!
Если вы все еще подозрительны, давайте перейдем в контейнер и откроем файл «yeah» с помощью нашего недавно установленного vim.
1 | > docker run -it oh-yeah-alpine /bin/sh |
2 | / # vim yeah |
3 | |
4 | it works! |
5 | ~ |
6 | ~ |
7 | . |
8 | . |
9 | . |
10 | ~ |
11 | “yeah” 1L, 10C |
Контекст сборки и файл .dockerignore
Я не сказал вам, но изначально, когда я пытался построить oh-yeah-alpine образ, он просто висел в течение нескольких минут. Проблема в том, что я просто поместил Dockerfile в свой домашний каталог. Когда Docker создает образ, он сначала упаковывает весь каталог, в котором находится Dockerfile (включая подкаталоги), и делает его доступным для команд COPY в Dockerfile.
Docker не пытается быть умным и анализирует ваши команды COPY. Он просто собирает все это. Обратите внимание, что содержимое сборки не будет заканчиваться вашим образом, но это замедлит вашу команду сборки, если ваш контекст сборки излишне большой.
В этом случае я просто скопировал Dockerfile и «yeah» в подкаталог и выполнил команду сборки docker в этом подкаталоге. Но иногда у вас есть сложное дерево каталогов, из которого вы хотите скопировать определенные подкаталоги и файлы и игнорировать другие. Используйте файл .dockerignore.
Этот файл позволяет вам точно контролировать, что входит в контекст сборки. Мой любимый трюк заключается в том, чтобы сначала исключить все, а затем начать включать в себя части, которые мне нужны. Например, в этом случае я мог бы создать следующий файл .dockerignore и сохранить файл Docker и «yeah» в моем домашнем каталоге:
1 | # Exclude EVERYTHING first |
2 | * |
3 | |
4 | # Now selectively include stuff |
5 | !yeah |
В контексте сборки нет необходимости включать сам файл Dockerfile или файл «.dockerignore».
Копирование против монтажа
Копирование файлов в образ иногда требуется вам, но в других случаях вы можете захотеть, чтобы ваши контейнеры были более динамичными и работали с файлами на хосте. Именно здесь вступают в силу тома и монтаж файловой системы.
Монтаж хост-каталогов – это другая игра с мячом. Данные принадлежат хосту, а не контейнеру. Данные могут быть изменены, когда контейнер остановлен. Один и тот же контейнер можно запустить с установленными разными каталогами хоста.
Тегирование образов
Маркировка образов очень важна, если вы разрабатываете систему на основе микросервисов и генерируете много образов, которые иногда должны быть связаны друг с другом. Вы можете добавить образу столько меток, сколько хотите.
Вы уже видели по умолчанию «latest» тег. Иногда имеет смысл добавлять другие теги, такие как «tested», «release-1.4» или git коммит, соответствующий этому образу.
Вы можете пометить образ во время сборки или позже. Вот как добавить тег к существующему образу. Обратите внимание, что, хотя он называется тегом, вы также можете назначить новый репозиторий.
1 | > docker tag oh-yeah-alpine oh-yeah-alpine:cool-tag |
2 | > docker tag oh-yeah-alpine oh-yeah-alpine-2 |
3 | |
4 | > docker images | grep oh-yeah |
5 | oh-yeah-alpine-2 latest e124405f28f4 30.5 MB |
6 | oh-yeah-alpine cool-tag e124405f28f4 30.5 MB |
7 | oh-yeah-alpine latest e124405f28f4 30.5 MB |
Вы также можете отменить тег удаляя образ по имени своего тега. Это немного страшно, потому что если вы удаляете последний тег случайно, вы теряете образ. Но если вы создаете образы из Dockerfile, вы можете просто его пересобрать.
1 | > docker rmi oh-yeah-alpine-2 |
2 | Untagged: oh-yeah-alpine-2:latest |
3 | |
4 | > docker rmi oh-yeah-alpine:cool-tag |
5 | Untagged: oh-yeah-alpine:cool-tag |
Если я попытаюсь удалить последний оставшийся помеченный образ, я получаю сообщение об ошибке, потому что он используется контейнером.
1 | > docker rmi oh-yeah-alpine |
2 | |
3 | Error response from daemon: conflict: unable to remove repository |
4 | reference “oh-yeah-alpine” (must force) – |
5 | container a1443a7ca9d2 is using its referenced image e124405f28f4 |
Но если я удалю контейнер …
1 | > docker rmi oh-yeah-alpine |
2 | Untagged: oh-yeah-alpine:latest |
3 | Deleted: sha256:e124405f28f48e…441d774d9413139e22386c4820df |
4 | Deleted: sha256:7fa4cba6d14fdf…d8940e6c50d30a157483de06fc59 |
5 | Deleted: sha256:283d461dadfa6c…dbff864c6557af23bc5aff9d66de |
6 | Deleted: sha256:1b2a228cc2a5b4…23c80a41a41da4ff92fcac95101e |
7 | Deleted: sha256:fe5fe2290c63a0…8af394bb4bf15841661f71c71e9a |
8 | |
9 | > docker images | grep oh-yeah |
Ага. Он исчез. Но не волнуйся. Мы можем его пересобрать:
1 | > docker build -t oh-yeah-alpine . |
2 | |
3 | > docker images | grep oh-yeah |
4 | oh-yeah-alpine latest 1e831ce8afe1 1 minutes ago 30.5 MB |
Верно, он вернулся. Dockerfile помог!
Работа с реестрами образов
Образы очень похожи в некоторых отношениях на git-хранилища. Они также построены из упорядоченного набора коммитов. Вы можете думать о двух образах, которые используют те же базовые образы, как о ветках в git (хотя в Docker нет слияния или перезагрузки). Реестр образов является эквивалентом центрального сервиса git-хостинга, такого как GitHub. Угадайте, как называется официальный реестр образов Docker? Правильно, Docker Hub.
Вытягивание образов
Когда вы запускаете образ, если он не существует, Docker попытается вытащить его из одного из ваших настроенных реестров образов. По умолчанию он переходит в Docker Hub, но вы можете управлять этим в файле «~/.docker/config.json». Если вы используете другой реестр, вы можете следовать их инструкциям, которые обычно включают вход с использованием их учетных данных.
Удалим образ «hello world» и снова вытащим его с помощью команды docker pull
.
1 | > dockere images | grep hello-world |
2 | hello-world latest c54a2cc56cbb 7 months ago 1.85 kB |
3 | |
4 | > docker rmi hello-world |
5 | hello-world |
Он исчез. Теперь вытаскиваем.
1 | > docker pull hello-world |
2 | Using default tag: latest |
3 | latest: Pulling from library/hello-world |
4 | 78445dd45222: Pull complete |
5 | Digest: sha256:c5515758d4c5e1e…07e6f927b07d05f6d12a1ac8d7 |
6 | Status: Downloaded newer image for hello-world:latest |
7 | |
8 | > dockere images | grep hello-world |
9 | hello-world latest 48b5124b2768 2 weeks ago 1.84 kB |
Последний hello-world был заменен более новой версией.
Выгрузка образов
Выгрузка образов немного более сложная. Сначала вам нужно создать учетную запись на Docker Hub (или другом реестре). Затем вы входите в систему. Затем вам нужно пометить образ, который вы хотите выложить, в соответствии с именем вашей учетной записи («g1g1» в моем случае).
1 | > docker login -u g1g1 -p <password> |
2 | Login Succeeded |
3 | |
4 | > docker tag hello-world g1g1/hello-world |
5 | |
6 | > docker images | grep hello |
7 | |
8 | g1g1/hello-world latest 48b5124b2768 2 weeks ago 1.84 kB |
9 | hello-world latest 48b5124b2768 2 weeks ago 1.84 kB |
Теперь я могу выложить образ помеченный, тегом g1g1/hello-world.
1 | > docker push g1g1/hello-world |
2 | The push refers to a repository [docker.io/g1g1/hello-world] |
3 | 98c944e98de8: Mounted from library/hello-world |
4 | latest: digest: sha256:c5515758d4c5e…f6d12a1ac8d7 size: 524 |
Вывод
Образы Docket – это шаблоны для ваших контейнеров. Они разработаны для того, чтобы быть эффективными и предлагать максимальное повторное использование, используя драйвер хранения файловой системы наложения.
Docker предоставляет множество инструментов для регистрации, проверки, создания и маркировки образов. Вы можете загружать и перемещать образы в реестры образов, такие как Docker Hub, для простого управления и обмена образами.
Свежие комментарии