0

docker

Docker –  создание образов

01.08.2023

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

Ручные сборки

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

Начнем с alpine image, которое является очень маленьким и спартанским образов на основе Alpine Linux. Мы можем запустить его в интерактивном режиме, чтобы попасть в оболочку. Наша цель – добавить файл « yeah», содержащий текст «it works!». В корневой каталог, а затем создать новое изображение из него, называемое «да-альпийское».

Вот так. Приятно, мы уже в корневом каталоге. Посмотрим, что там.

1> docker run -it alpine /bin/sh
2/ # ls 
3bin 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 
3it works!
4

Я вышел из интерактивной оболочки, и я вижу контейнер с именем «vibrant_spenc» с docker ps -all. Флаг -all важен, потому что контейнер больше не работает.

1> docker ps –all
2CONTAINER ID IMAGE COMMAND CREATED STATUS NAMES
3c8faeb05de5f 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
2sha256:e3c98cd21f4d85a1428…e220da99995fd8bf6b49aa

Давайте посмотрим. Да, есть новый образ, и в его истории вы можете увидеть новый слой с комментарием «mine, mine, mine».

1> docker images
2REPOSITORY TAG IMAGE ID SIZE
3yeah-alpine latest e3c98cd21f4d 4.8 MB
4python latest 775dae9b960e 687 MB
5d4w/nsenter latest 9e4f13a0901e 83.8 kB
6ubuntu-with-ssh latest 87391dca396d 221 MB
7ubuntu latest bd3d4369aebc 127 MB
8hello-world latest c54a2cc56cbb 1.85 kB
9alpine latest 4e38e38c8ce0 4.8 MB
10nsqio/nsq latest 2a82c70fe5e3 70.7 MB
11
12> docker history yeah-alpine
13IMAGE CREATED SIZE COMMENT
14e3c98cd21f4d 40 seconds ago 66 B mine, mine, mine
154e38e38c8ce0 7 months ago 4.8 MB

Теперь для настоящего теста. Удалим контейнер и создадим новый контейнер из образа. Ожидаемый результат заключается в том, что файл «yeah» будет присутствовать в новом контейнере.

1> docker rm vibrant_spence
2vibrant_spence
3
4> docker run -it yeah-alpine /bin/sh
5/ # cat yeah 
6it works!
7/ #

Что я могу сказать? Да, это работает!

Использование Dockerfile

Создание образов из модифицированных контейнеров классно, но нет ответственности. Трудно отслеживать изменения и знать, каковы были конкретные изменения. Дисциплинированный способ создания образов состоит в их создании с помощью Dockerfile.

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

Здесь я просто продемонстрирую пару команд для создания другого образа «oh-yeah-alpine» на основе Dockerfile. В дополнение к созданию печально известного файла «yeah», давайте также установим vim. В альпийском дистрибутиве Linux используется система управления пакетами под названием «apk». Вот наш Dockerfile:

1FROM alpine
2
3# Copy the “yeah” file from the host 
4COPY yeah /yeah
5
6# Update and install vim using apk 
7RUN apk update && apk add vim
8
9CMD cat /yeah

Базовым образом  является alpine. Он копирует файл «yeah» из одного и того же каталога хоста, где находится файл Dockerfile (путь контекста сборки). Затем он выполняет apk update и устанавливает vim. Наконец, он устанавливает команду, которая выполняется при запуске контейнера. В этом случае он выведет на экран содержимое файла « yeah».

ОК. Теперь, когда мы знаем, к чему мы стремимся, давайте построим наш орбраз. Параметр «-t» задает репозиторий. Я не указал тег, поэтому он будет по умолчанию «последним».

1> docker build -t oh-yeah-alpine .
2Sending build context to Docker daemon 3.072 kB
3Step 1/4 : FROM alpine
4—> 4e38e38c8ce0
5Step 2/4 : COPY yeah /yeah
6—> 1b2a228cc2a5
7Removing intermediate container a6221f725845
8Step 3/4 : RUN apk update && apk add vim
9—> Running in e2c0524bd792
10fetch https://dl-cdn.alpinelinux.org/…/APKINDEX.tar.gz
11fetch http://dl-cdn.alpinelinux.org…/x86_64/APKINDEX.tar.gz
12v3.4.6-60-gc61f5bf [http://dl-cdn.alpinelinux.org/alpine/v3.4/main]
13v3.4.6-33-g38ef2d2 [http://dl-cdn.alpinelinux.org/…/v3.4/community]
14OK: 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)
20Executing busybox-1.24.2-r9.trigger
21OK: 37 MiB in 16 packages
22—> 7fa4cba6d14f
23Removing intermediate container e2c0524bd792
24Step 4/4 : CMD cat /yeah
25—> Running in 351b4f1c1eb1
26—> e124405f28f4
27Removing intermediate container 351b4f1c1eb1
28Successfully built e124405f28f4

Выглядит неплохо. Давайте проверим, что образ был создан:

1> docker images | grep oh-yeah
2
3oh-yeah-alpine latest e124405f28f4 About a minute ago 30.5 MB

Обратите внимание, что установка vim и его зависимостей раздула размер контейнера с 4,8 Мбайт базового альпийского образа до массивных 30,5 МБ!

Все очень хорошо. Но работает ли это?

1> docker run oh-yeah-alpine
2it works!

О да, это работает!

Если вы все еще подозрительны, давайте перейдем в контейнер и откроем файл «yeah» с помощью нашего недавно установленного vim.

1> docker run -it oh-yeah-alpine /bin/sh
2/ # vim yeah 
3
4it 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
5oh-yeah-alpine-2 latest e124405f28f4 30.5 MB
6oh-yeah-alpine cool-tag e124405f28f4 30.5 MB
7oh-yeah-alpine latest e124405f28f4 30.5 MB

Вы также можете отменить тег удаляя образ по имени своего тега. Это немного страшно, потому что если вы удаляете последний тег случайно, вы теряете образ. Но если вы создаете образы из Dockerfile, вы можете просто его пересобрать.

1> docker rmi oh-yeah-alpine-2
2Untagged: oh-yeah-alpine-2:latest
3
4> docker rmi oh-yeah-alpine:cool-tag
5Untagged: oh-yeah-alpine:cool-tag

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

1> docker rmi oh-yeah-alpine
2
3Error response from daemon: conflict: unable to remove repository
4reference “oh-yeah-alpine” (must force) –
5container a1443a7ca9d2 is using its referenced image e124405f28f4

Но если я удалю контейнер …

1> docker rmi oh-yeah-alpine
2Untagged: oh-yeah-alpine:latest
3Deleted: sha256:e124405f28f48e…441d774d9413139e22386c4820df
4Deleted: sha256:7fa4cba6d14fdf…d8940e6c50d30a157483de06fc59
5Deleted: sha256:283d461dadfa6c…dbff864c6557af23bc5aff9d66de
6Deleted: sha256:1b2a228cc2a5b4…23c80a41a41da4ff92fcac95101e
7Deleted: sha256:fe5fe2290c63a0…8af394bb4bf15841661f71c71e9a
8
9> docker images | grep oh-yeah

Ага. Он исчез. Но не волнуйся. Мы можем его пересобрать:

1> docker build -t oh-yeah-alpine .
2
3> docker images | grep oh-yeah
4oh-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
2hello-world latest c54a2cc56cbb 7 months ago 1.85 kB
3
4> docker rmi hello-world
5hello-world

Он исчез. Теперь вытаскиваем.

1> docker pull hello-world
2Using default tag: latest
3latest: Pulling from library/hello-world
478445dd45222: Pull complete 
5Digest: sha256:c5515758d4c5e1e…07e6f927b07d05f6d12a1ac8d7
6Status: Downloaded newer image for hello-world:latest
7
8> dockere images | grep hello-world
9hello-world latest 48b5124b2768 2 weeks ago 1.84 kB

Последний hello-world был заменен более новой версией.

Выгрузка образов

Выгрузка образов немного более сложная. Сначала вам нужно создать учетную запись на Docker Hub (или другом реестре). Затем вы входите в систему. Затем вам нужно пометить образ, который вы хотите выложить, в соответствии с именем вашей учетной записи («g1g1» в моем случае).

1> docker login -u g1g1 -p <password>
2Login Succeeded
3
4> docker tag hello-world g1g1/hello-world
5
6> docker images | grep hello
7
8g1g1/hello-world latest 48b5124b2768 2 weeks ago 1.84 kB
9hello-world latest 48b5124b2768 2 weeks ago 1.84 kB

Теперь я могу выложить образ помеченный, тегом g1g1/hello-world.

1> docker push g1g1/hello-world
2The push refers to a repository [docker.io/g1g1/hello-world]
398c944e98de8: Mounted from library/hello-world
4latest: digest: sha256:c5515758d4c5e…f6d12a1ac8d7 size: 524

Вывод

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

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

Свежие комментарии

Подписка

Лучшие статьи


Fatal error: Uncaught Error: Call to a member function have_posts() on null in /home/host1867038/the-devops.ru/htdocs/www/wp-content/themes/fox/inc/blog.php:380 Stack trace: #0 /home/host1867038/the-devops.ru/htdocs/www/wp-content/themes/fox/widgets/latest-posts/widget.php(257): fox56_blog_grid(NULL, Array) #1 /home/host1867038/the-devops.ru/htdocs/www/wp-content/themes/fox/widgets/latest-posts/register.php(33): include('/home/host18670...') #2 /home/host1867038/the-devops.ru/htdocs/www/wp-includes/class-wp-widget.php(394): Wi_Widget_Latest_Posts->widget(Array, Array) #3 /home/host1867038/the-devops.ru/htdocs/www/wp-includes/widgets.php(837): WP_Widget->display_callback(Array, Array) #4 /home/host1867038/the-devops.ru/htdocs/www/wp-content/themes/fox/inc/single.php(417): dynamic_sidebar('sidebar') #5 /home/host1867038/the-devops.ru/htdocs/www/wp-content/themes/fox/inc/single.php(136): fox56_single_sidebar() #6 /home/host1867038/the-devops.ru/htdocs/www/wp-content/themes/fox/inc/single.php(7): fox56_single_inner() #7 /home/host1867038/the-devops.ru/htdocs/www/wp-content/themes/fox/single.php(23): fox56_single() #8 /home/host1867038/the-devops.ru/htdocs/www/wp-includes/template-loader.php(106): include('/home/host18670...') #9 /home/host1867038/the-devops.ru/htdocs/www/wp-blog-header.php(19): require_once('/home/host18670...') #10 /home/host1867038/the-devops.ru/htdocs/www/index.php(17): require('/home/host18670...') #11 {main} thrown in /home/host1867038/the-devops.ru/htdocs/www/wp-content/themes/fox/inc/blog.php on line 380