https://docker.crank.ru/docs/docker-engine/learn-by-example/build-your-own-images/
Docker образы являются основой контейнеров. Каждый раз, когда мы используем docker run
мы указываем какой образ использовать. В предыдущих разделах вы использовали уже существовавшие образы Docker, к примеру образ ubuntu
и training/webapp
.
Вы также обнаружили, что Docker хранит загруженные образы на хосте. Если образ не присутствует на хосте, то он будет загружен с реестра: по умолчанию реестра Docker Hub .
В этом уроке мы исследуем образы Docker более подробно:
- Управление и работа с образами на локально на хосте Docker.
- Создание базовых образов.
- Загрузка образов в реестр Docker Hub .
Давайте начнем со списка образов которые присутствуют на хосте. Вы можете посмотреть список выполнив команду docker images
:
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
ubuntu 14.04 1d073211c498 3 days ago 187.9 MB
busybox latest 2c5ac3f849df 5 days ago 1.113 MB
training/webapp latest 54bb4e8718e8 5 months ago 348.7 MB
Вы можете увидеть образы которые мы использовали до этого. Каждый из них был загружен с Docker Hub когда вы запускали контейнер использующий образ. При просмотре списка образов, вы видите три важных параметра.
- Из какого репозитория образ, к примеру
ubuntu
. - Версия каждого образа, например
14.04
. - Уникальный ID каждого образа.
Совет: Вы можете использовать инструмент от стороннего производителя dockviz или Image layers site для отображения визуализации данных изображения.
Репозиторий может хранить разные версии образа. В случае с ubuntu
есть много вариантов Ubuntu 10.04, 12.04, 12.10, 13.04, 13.10 и 14.04. Каждый вариант обозначен тегом и вы можете выбрать нужный вам:
ubuntu:14.04
Итак, когда мы запускаем контейнер, мы ссылаемся на образ и его версию, например так:
$ docker run -t -i ubuntu:14.04 /bin/bash
Если вместо этого вы хотите запустить образ Ubuntu 12.04, выполните команду:
$ docker run -t -i ubuntu:12.04 /bin/bash
Если вы не указали вариант, например, вы просто используете ubuntu
, то Докер будет по умолчанию использовать образ ubuntu:latest
.
Совет: Всегда указывайте версию образа, например,
ubuntu:14.04
. Таким образом, вы всегда точно знаете, какой вариант образа вы используете. Это полезно для поиска неисправностей и отладки.
Итак, как же получить новый образ? Docker автоматически скачает любой образ который вы используете, но которого еще нет на вашем Docker хосте. Но это может увеличить время запуска контейнера. Если вы хотите заранее загрузить образ, вы можете сделать это командой docker pull
. Предположим, вы хотите скачать образ centos
.
$ docker pull centos
Using default tag: latest
latest: Pulling from library/centos
f1b10cd84249: Pull complete
c852f6d61e65: Pull complete
7322fbe74aa5: Pull complete
Digest: sha256:90305c9112250c7e3746425477f1c4ef112b03b4abe78c612e092037bfecc3b7
Status: Downloaded newer image for centos:latest
Вы можете видеть как каждый слой образа был скачан и теперь вы можете запустить контейнер из образа не ожидая его загрузки.
$ docker run -t -i centos /bin/bash
bash-4.1#
Одной из особенностей Docker является то что множество людей создают собственные образы для различных целей. Многие из них загружают их на Docker Hub . Вы можете искать эти образы на веб-сайте Docker Hub .
Вы также можете искать образы используя команду docker search
. Предположим, нашей команде нужны образы Ruby и Sinatra для разработки веб-приложения. Вы можете произвести поиск подходящего образа использовав команду docker search
для поиска всех образов содержащих слово sinatra
.
$ docker search sinatra
NAME DESCRIPTION STARS OFFICIAL AUTOMATED
training/sinatra Sinatra training image 0 [OK]
marceldegraaf/sinatra Sinatra test app 0
mattwarren/docker-sinatra-demo 0 [OK]
luisbebop/docker-sinatra-hello-world 0 [OK]
bmorearty/handson-sinatra handson-ruby + Sinatra for Hands on with D... 0
subwiz/sinatra 0
bmorearty/sinatra 0
. . .
Вы можете видеть что команда вернула много образов со словом sinatra
. В списке с результатами есть название, описание, рейтинг (который отражает социальную популярность образа), а также статус официальности автобилда. Официальные репозитории тщательно модерируються компанией Docker. Автоматические репозитории позволяют вам проверить источник и содержание образа.
вы просмотрели доступные образы и решили использовать образ training/sinatra
. До сих пор вы сталкивались с двумя типами репозиториев. Первый тип: образы вроде ubuntu
, которые называются базовыми или корневыми. Базовые образы поставляются компанией Docker, они проверены и поддерживаются. Их легко узнать по названиям из одного слова.
Также вы видели пользовательские образы, к примеру образ training/sinatra
который вы выбрали. Пользовательские образы принадлежат членам сообщества Docker, которые создают и занимаются их поддержкой. Вы можете легко отличить пользовательский образ, поскольку их имена строятся по шаблону владелец/образ
.
Вы выбрали образ training/sinatra
, и теперь можете скачать его командой docker pull
.
$ docker pull training/sinatra
Теперь ваша команда может использовать образ запуская в своих контейнерах.
$ docker run -t -i training/sinatra /bin/bash
root@a8cb6ce02d85:/#
Вы нашли образ training/sinatra
и он очень полезен, но это не совсем то что вам нужно и вы хотите сделать несколько изменений. Вы можете обновить или создать новый образ.
- Вы можете обновить контейнер созданный из образа и сделать коммит ваших изменений, при этом будет создан новый образ.
- Или вы можете добавить инструкции в
Dockerfile
для создания нового образа.
Для обновления образа вам нужно создать из него контейнер в который мы будем вносить изменения.
$ docker run -t -i training/sinatra /bin/bash
root@0b2616b0e5a8:/#
Примечание: Скопируйте ID созданного контейнера
0b2616b0e5a8
(у вас он может отличаться), он скоро вам понадобится.
Сперва давайте обновим Ruby внутри нашего контейнера:
root@0b2616b0e5a8:/# apt-get install -y ruby2.0-dev
Теперь добавим json
гем.
root@0b2616b0e5a8:/# gem2.0 install json
Когда все сделано можно выйти из контейнера командой exit
.
Теперь у вас есть модифицированный контейнер. Вы можете сделать коммит контейнера в образ командой docker commit
.
$ docker commit -m "Added json gem" -a "Kate Smith" \
0b2616b0e5a8 ouruser/sinatra:v2
4f177bd27a9ff0f6dc2a830403925b5360bfe0b93d476f7fc3231110e7f71b1c
Вы использовали команду docker commit
. при этом бало добавлено два флага: -m
и -a
. Флаг -m
по аналогии с git (или другими системами контроля версий) позволяет добавить к коммиту комментарий. Флаг -a
дает возможность указать автора обновления.
Вы также указали контейнер из которого хотите создать новый образ, 0b2616b0e5a8
(скопированный ранее ID контейнера) и название с версией для нового образа:
ouruser/sinatra:v2
Разберем название ouruser/sinatra:v2
более подробно. Оно содержит имя пользователя ouruser
, который создает образ. Далее идет само имя образа, здесь мы оставили имя оригинала без изменений sinatra
. В самом конце указывается тег (версия): v2
.
Теперь можно посмотреть на новый образ ouruser/sinatra
выполнив команду docker images
.
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
training/sinatra latest 5bc342fa0b91 10 hours ago 446.7 MB
ouruser/sinatra v2 3c59e02ddd1a 10 hours ago 446.7 MB
ouruser/sinatra latest 5db5f8471261 10 hours ago 446.7 MB
Используем новый образ для создания контейнера:
$ docker run -t -i ouruser/sinatra:v2 /bin/bash
root@78e82f680994:/#
Использование команды docker commit
для создания образа довольно простой, но несколько громоздкий способ и не всегда удобный для использования в команде. Вместо этого вы можете использовать команду, docker build
, что бы создать новый образ с нуля.
Для этого вам нужно создать файл Dockerfile
который будет содержать инструкции по которым Docker построит новый образ.
Сначала, создайте папку и Dockerfile
.
$ mkdir sinatra
$ cd sinatra
$ touch Dockerfile
Если вы используете Docker Machine на Windows, вы можете попасть в директорию хоста командой cd /c/Users/your_user_name
.
Каждая инструкция создает новый слой образа. Попробуйте простой пример создания собственного образа Sinatra для вашей воображаемой команды.
# This is a comment
FROM ubuntu:14.04
MAINTAINER Kate Smith <ksmith@example.com>
RUN apt-get update && apt-get install -y ruby ruby-dev
RUN gem install sinatra
Посмотрим что делает файл Dockerfile
. Каждая инструкция состоит из префикса и команды.
INSTRUCTION statement
Примечание: Используйте
#
что бы оставлять комментарии
Первая инструкция FROM
указывает Docker какой образ будет базовым, в данном случае им будет Ubuntu 14.04. С помощью инструкции MAINTAINER
можно указать автора поддерживающего образ.
И наконец, вы использовали две инструкции RUN
, которые выполняют команду внутри образа, к примеру устанавливают пакет. Здесь мы обновляем наш APT кэш и устанавливаем Ruby, RubyGems и затем Sinatra гем.
Теперь, давайте возьмем наш Dockerfile
и используем команду docker build
для создания образа.
$ docker build -t ouruser/sinatra:v2 .
Sending build context to Docker daemon 2.048 kB
Sending build context to Docker daemon
Step 1 : FROM ubuntu:14.04
---> e54ca5efa2e9
Step 2 : MAINTAINER Kate Smith <ksmith@example.com>
---> Using cache
---> 851baf55332b
Step 3 : RUN apt-get update && apt-get install -y ruby ruby-dev
---> Running in 3a2558904e9b
Selecting previously unselected package libasan0:amd64.
(Reading database ... 11518 files and directories currently installed.)
Preparing to unpack .../libasan0_4.8.2-19ubuntu1_amd64.deb ...
Unpacking libasan0:amd64 (4.8.2-19ubuntu1) ...
Selecting previously unselected package libatomic1:amd64.
Preparing to unpack .../libatomic1_4.8.2-19ubuntu1_amd64.deb ...
Unpacking libatomic1:amd64 (4.8.2-19ubuntu1) ...
Selecting previously unselected package libgmp10:amd64.
Preparing to unpack .../libgmp10_2%3a5.1.3+dfsg-1ubuntu1_amd64.deb ...
Unpacking libgmp10:amd64 (2:5.1.3+dfsg-1ubuntu1) ...
Selecting previously unselected package libisl10:amd64.
Preparing to unpack .../libisl10_0.12.2-1_amd64.deb ...
Unpacking libisl10:amd64 (0.12.2-1) ...
Selecting previously unselected package libcloog-isl4:amd64.
Preparing to unpack .../libcloog-isl4_0.18.2-1_amd64.deb ...
Unpacking libcloog-isl4:amd64 (0.18.2-1) ...
Selecting previously unselected package libgomp1:amd64.
Preparing to unpack .../libgomp1_4.8.2-19ubuntu1_amd64.deb ...
Unpacking libgomp1:amd64 (4.8.2-19ubuntu1) ...
Selecting previously unselected package libitm1:amd64.
Preparing to unpack .../libitm1_4.8.2-19ubuntu1_amd64.deb ...
Unpacking libitm1:amd64 (4.8.2-19ubuntu1) ...
Selecting previously unselected package libmpfr4:amd64.
Preparing to unpack .../libmpfr4_3.1.2-1_amd64.deb ...
Unpacking libmpfr4:amd64 (3.1.2-1) ...
Selecting previously unselected package libquadmath0:amd64.
Preparing to unpack .../libquadmath0_4.8.2-19ubuntu1_amd64.deb ...
Unpacking libquadmath0:amd64 (4.8.2-19ubuntu1) ...
Selecting previously unselected package libtsan0:amd64.
Preparing to unpack .../libtsan0_4.8.2-19ubuntu1_amd64.deb ...
Unpacking libtsan0:amd64 (4.8.2-19ubuntu1) ...
Selecting previously unselected package libyaml-0-2:amd64.
Preparing to unpack .../libyaml-0-2_0.1.4-3ubuntu3_amd64.deb ...
Unpacking libyaml-0-2:amd64 (0.1.4-3ubuntu3) ...
Selecting previously unselected package libmpc3:amd64.
Preparing to unpack .../libmpc3_1.0.1-1ubuntu1_amd64.deb ...
Unpacking libmpc3:amd64 (1.0.1-1ubuntu1) ...
Selecting previously unselected package openssl.
Preparing to unpack .../openssl_1.0.1f-1ubuntu2.4_amd64.deb ...
Unpacking openssl (1.0.1f-1ubuntu2.4) ...
Selecting previously unselected package ca-certificates.
Preparing to unpack .../ca-certificates_20130906ubuntu2_all.deb ...
Unpacking ca-certificates (20130906ubuntu2) ...
Selecting previously unselected package manpages.
Preparing to unpack .../manpages_3.54-1ubuntu1_all.deb ...
Unpacking manpages (3.54-1ubuntu1) ...
Selecting previously unselected package binutils.
Preparing to unpack .../binutils_2.24-5ubuntu3_amd64.deb ...
Unpacking binutils (2.24-5ubuntu3) ...
Selecting previously unselected package cpp-4.8.
Preparing to unpack .../cpp-4.8_4.8.2-19ubuntu1_amd64.deb ...
Unpacking cpp-4.8 (4.8.2-19ubuntu1) ...
Selecting previously unselected package cpp.
Preparing to unpack .../cpp_4%3a4.8.2-1ubuntu6_amd64.deb ...
Unpacking cpp (4:4.8.2-1ubuntu6) ...
Selecting previously unselected package libgcc-4.8-dev:amd64.
Preparing to unpack .../libgcc-4.8-dev_4.8.2-19ubuntu1_amd64.deb ...
Unpacking libgcc-4.8-dev:amd64 (4.8.2-19ubuntu1) ...
Selecting previously unselected package gcc-4.8.
Preparing to unpack .../gcc-4.8_4.8.2-19ubuntu1_amd64.deb ...
Unpacking gcc-4.8 (4.8.2-19ubuntu1) ...
Selecting previously unselected package gcc.
Preparing to unpack .../gcc_4%3a4.8.2-1ubuntu6_amd64.deb ...
Unpacking gcc (4:4.8.2-1ubuntu6) ...
Selecting previously unselected package libc-dev-bin.
Preparing to unpack .../libc-dev-bin_2.19-0ubuntu6_amd64.deb ...
Unpacking libc-dev-bin (2.19-0ubuntu6) ...
Selecting previously unselected package linux-libc-dev:amd64.
Preparing to unpack .../linux-libc-dev_3.13.0-30.55_amd64.deb ...
Unpacking linux-libc-dev:amd64 (3.13.0-30.55) ...
Selecting previously unselected package libc6-dev:amd64.
Preparing to unpack .../libc6-dev_2.19-0ubuntu6_amd64.deb ...
Unpacking libc6-dev:amd64 (2.19-0ubuntu6) ...
Selecting previously unselected package ruby.
Preparing to unpack .../ruby_1%3a1.9.3.4_all.deb ...
Unpacking ruby (1:1.9.3.4) ...
Selecting previously unselected package ruby1.9.1.
Preparing to unpack .../ruby1.9.1_1.9.3.484-2ubuntu1_amd64.deb ...
Unpacking ruby1.9.1 (1.9.3.484-2ubuntu1) ...
Selecting previously unselected package libruby1.9.1.
Preparing to unpack .../libruby1.9.1_1.9.3.484-2ubuntu1_amd64.deb ...
Unpacking libruby1.9.1 (1.9.3.484-2ubuntu1) ...
Selecting previously unselected package manpages-dev.
Preparing to unpack .../manpages-dev_3.54-1ubuntu1_all.deb ...
Unpacking manpages-dev (3.54-1ubuntu1) ...
Selecting previously unselected package ruby1.9.1-dev.
Preparing to unpack .../ruby1.9.1-dev_1.9.3.484-2ubuntu1_amd64.deb ...
Unpacking ruby1.9.1-dev (1.9.3.484-2ubuntu1) ...
Selecting previously unselected package ruby-dev.
Preparing to unpack .../ruby-dev_1%3a1.9.3.4_all.deb ...
Unpacking ruby-dev (1:1.9.3.4) ...
Setting up libasan0:amd64 (4.8.2-19ubuntu1) ...
Setting up libatomic1:amd64 (4.8.2-19ubuntu1) ...
Setting up libgmp10:amd64 (2:5.1.3+dfsg-1ubuntu1) ...
Setting up libisl10:amd64 (0.12.2-1) ...
Setting up libcloog-isl4:amd64 (0.18.2-1) ...
Setting up libgomp1:amd64 (4.8.2-19ubuntu1) ...
Setting up libitm1:amd64 (4.8.2-19ubuntu1) ...
Setting up libmpfr4:amd64 (3.1.2-1) ...
Setting up libquadmath0:amd64 (4.8.2-19ubuntu1) ...
Setting up libtsan0:amd64 (4.8.2-19ubuntu1) ...
Setting up libyaml-0-2:amd64 (0.1.4-3ubuntu3) ...
Setting up libmpc3:amd64 (1.0.1-1ubuntu1) ...
Setting up openssl (1.0.1f-1ubuntu2.4) ...
Setting up ca-certificates (20130906ubuntu2) ...
debconf: unable to initialize frontend: Dialog
debconf: (TERM is not set, so the dialog frontend is not usable.)
debconf: falling back to frontend: Readline
debconf: unable to initialize frontend: Readline
debconf: (This frontend requires a controlling tty.)
debconf: falling back to frontend: Teletype
Setting up manpages (3.54-1ubuntu1) ...
Setting up binutils (2.24-5ubuntu3) ...
Setting up cpp-4.8 (4.8.2-19ubuntu1) ...
Setting up cpp (4:4.8.2-1ubuntu6) ...
Setting up libgcc-4.8-dev:amd64 (4.8.2-19ubuntu1) ...
Setting up gcc-4.8 (4.8.2-19ubuntu1) ...
Setting up gcc (4:4.8.2-1ubuntu6) ...
Setting up libc-dev-bin (2.19-0ubuntu6) ...
Setting up linux-libc-dev:amd64 (3.13.0-30.55) ...
Setting up libc6-dev:amd64 (2.19-0ubuntu6) ...
Setting up manpages-dev (3.54-1ubuntu1) ...
Setting up libruby1.9.1 (1.9.3.484-2ubuntu1) ...
Setting up ruby1.9.1-dev (1.9.3.484-2ubuntu1) ...
Setting up ruby-dev (1:1.9.3.4) ...
Setting up ruby (1:1.9.3.4) ...
Setting up ruby1.9.1 (1.9.3.484-2ubuntu1) ...
Processing triggers for libc-bin (2.19-0ubuntu6) ...
Processing triggers for ca-certificates (20130906ubuntu2) ...
Updating certificates in /etc/ssl/certs... 164 added, 0 removed; done.
Running hooks in /etc/ca-certificates/update.d....done.
---> c55c31703134
Removing intermediate container 3a2558904e9b
Step 4 : RUN gem install sinatra
---> Running in 6b81cb6313e5
unable to convert "\xC3" to UTF-8 in conversion from ASCII-8BIT to UTF-8 to US-ASCII for README.rdoc, skipping
unable to convert "\xC3" to UTF-8 in conversion from ASCII-8BIT to UTF-8 to US-ASCII for README.rdoc, skipping
Successfully installed rack-1.5.2
Successfully installed tilt-1.4.1
Successfully installed rack-protection-1.5.3
Successfully installed sinatra-1.4.5
4 gems installed
Installing ri documentation for rack-1.5.2...
Installing ri documentation for tilt-1.4.1...
Installing ri documentation for rack-protection-1.5.3...
Installing ri documentation for sinatra-1.4.5...
Installing RDoc documentation for rack-1.5.2...
Installing RDoc documentation for tilt-1.4.1...
Installing RDoc documentation for rack-protection-1.5.3...
Installing RDoc documentation for sinatra-1.4.5...
---> 97feabe5d2ed
Removing intermediate container 6b81cb6313e5
Successfully built 97feabe5d2ed
В команде docker build
был использован флаг -t
для указания принадлежности образа пользователю ouruser
, имя репозитория sinatra
и тега (версии) v2
.
Вы также указываете расположение Dockerfile
используя .
поскольку Dockerfile
находится в текущем каталоге.
Примечание: Вы также можете указать путь к файлу
Dockerfile
.
Теперь вы можете увидеть процесс сборки образа в действии. Первое, что делает Докер это загружает контекст сборки: в основном содержимое каталога в котором происходит сборка. Это делается потому, что демон Docker делает фактическую сборку образа и она нуждается в локальном контексте, чтобы сделать это.
Далее вы можете увидеть как каждая инструкция Dockerfile
выполняется шаг за шагом. Обратите внимание что при каждом шаге создается новый контейнер,следующая инструкция выполняется внутри контейнера и затем делается коммит изменений, аналогично команде docker commit
которую мы недавно изучили. Когда все инструкции выполнены процедура завершается и выводится ID образа 97feabe5d2ed
(с полным именем ouruser/sinatra:v2
) а все промежуточные контейнеры удаляются.
Примечание: Образ не может иметь более 127 слоев, независимо от хранилища. Это ограничение устанавливается на глобальном уровне, чтобы стимулировать оптимизацию общего размера образов.
Теперь вы можете создать контейнер из нового образа.
$ docker run -t -i ouruser/sinatra:v2 /bin/bash
root@8196968dac35:/#
Примечание: Это только краткое введение в создание образов. Мы пропустили целую кучу других инструкций, которые вы можете использовать. Мы увидим больше инструкций в последующих разделах руководства или вы можете обратиться к ссылке Dockerfile для подробного описания и примеров к каждой инструкции. Чтобы помочь вам написать читаемый, легко обслуживаемый Dockerfile, мы также написали руководство Dockerfile лучшая практика .
Вы также можете добавить тег к уже существующему образу после коммита и сборки. Для этого используйте команду docker tag
. Теперь добавьте новый тег для образа ouruser/sinatra
.
$ docker tag 5db5f8471261 ouruser/sinatra:devel
Команда docker tag
принимает ID образа, в нашем случае 5db5f8471261
, имя пользователя, имя репозитория и новый тег.
Посмотрим на новый тег нашего образа выполнив команду docker images
.
$ docker images ouruser/sinatra
REPOSITORY TAG IMAGE ID CREATED SIZE
ouruser/sinatra latest 5db5f8471261 11 hours ago 446.7 MB
ouruser/sinatra devel 5db5f8471261 11 hours ago 446.7 MB
ouruser/sinatra v2 5db5f8471261 11 hours ago 446.7 MB
Образы использующие формат версии 2 или старше имеют контентно-адресный идентификатор называемый дайджест (digest). До тех пор пока вводные данные для генерации образа не изменны значение дайджеста тоже остаеться прежним. Таким образом дайджест можно считать хешем инструкций для построения образа. Для отображения образов и их дайджестов используйте флаг --digests
:
$ docker images --digests | head
REPOSITORY TAG DIGEST IMAGE ID CREATED SIZE
ouruser/sinatra latest sha256:cbbf2f9a99b47fc460d422812b6a5adff7dfee951d8fa2e4a98caa0382cfbdbf 5db5f8471261 11 hours ago 446.7 MB
При пуше или пуле в регистр 2.0, команды push
или pull
выводят в том числе и дайджест. Вы можете можете сделать pull
используя значение дайджеста.
$ docker pull ouruser/sinatra@sha256:cbbf2f9a99b47fc460d422812b6a5adff7dfee951d8fa2e4a98caa0382cfbdbf
Вы можете использовать дайджест в командах create
, run
и rmi
, также как в инструкции FROM
для Dockerfile.
После того, как вы создали новый образ вы можете запушить (push) его на Docker Hub с помощью команды docker push
. Это позволяет вам поделиться им с другими, либо публично, либо разместить его в приватный репозиторий .
$ docker push ouruser/sinatra
The push refers to a repository [ouruser/sinatra] (len: 1)
Sending image list
Pushing repository ouruser/sinatra (3 tags)
. . .
Вы можете удалять образы с Docker хоста также как и контейнеры используя команду docker rmi
.
Удалите образ training/sinatra
он больше вам не понадобится.
$ docker rmi training/sinatra
Untagged: training/sinatra:latest
Deleted: 5bc342fa0b91cabf65246837015197eecfa24b2213ed6a51a8974ae250fedd8d
Deleted: ed0fffdcdae5eb2c3a55549857a8be7fc8bc4241fb19ad714364cbfd7a56b22f
Deleted: 5c58979d73ae448df5af1d8142436d81116187a7633082650549c52c3a2418f0
Примечание: перед удалением образа с хоста, убедитесь что у вас нет запущенных контейнеров использующих данный образ.
До сих пор вы знали, как создавать отдельные приложения внутри контейнеров Докер. Теперь мы научимся строить целые стеки приложений из нескольких контейнеров Docker взаимодействующих друг с другом по сети.
Перейдите в раздел Сетевые контейнеры .