Docker context что это
Погружаемся в Docker: Dockerfile и коммуникация между контейнерами
В прошлой статье мы рассказали, что такое Docker и как с его помощью можно обойти Vendor–lock. В этой статье мы поговорим о Dockerfile как о правильном способе подготовки образов для Docker. Также мы рассмотрим ситуацию, когда контейнерам нужно взаимодействовать друг с другом.
В InfoboxCloud мы сделали готовый образ Ubuntu 14.04 с Docker. Не забудьте поставить галочку «Разрешить управление ядром ОС» при создании сервера, это требуется для работы Docker.
Dockerfile
Подход docker commit, описанный в предыдущей статье, не является рекомендованным для Docker. Его плюс состоит в том, что мы настраиваем контейнер практически так, как привыкли настраивать стандартный сервер.
Вместо этого подхода мы рекомендуем использовать подход Dockerfile и команду docker build. Dockerfile использует обычный DSL с инструкциями для построения образов Docker. После этого выполняется команда docker build для построения нового образа с инструкциями в Dockerfile.
Написание Dockerfile
Давайте создадим простой образ с веб-сервером с помощью Dockerfile. Для начала создадим директорию и сам Dockerfile.
Созданная директория — билд-окружение, в которой Docker вызывает контекст или строит контекст. Docker загрузит контекст в папке в процессе работы Docker–демона, когда будет запущена сборка образа. Таким образом будет возможно для Docker–демона получить доступ к любому коду, файлам или другим данным, которые вы захотите включить в образ.
Добавим в Dockerfile информацию по построению образа:
Также Dockerfile поддерживает комментарии. Любая строчка, начинающаяся с # означает комментарий.
Первая инструкция в Dockerfile всегда должна быть FROM, указывающая, из какого образа нужно построить образ. В нашем примере мы строим образ из базового образа ubuntu версии 14:04.
Далее мы указываем инструкцию MAINTAINER, сообщающую Docker автора образа и его email. Это полезно, чтобы пользователи образа могли связаться с автором при необходимости.
Инструкция RUN исполняет команду в конкретном образе. В нашем примере с помощью ее мы обновляем APT репозитории и устанавливаем пакет с NGINX, затем создаем файл /usr/share/nginx/html/index.html.
Мы используем этот формат для указания массива, содержащего команду для исполнения и параметры команды.
Далее мы указываем инструкцию EXPOSE, которая говорит Docker, что приложение в контейнере должно использовать определенный порт в контейнере. Это не означает, что вы можете автоматически получать доступ к сервису, запущенному на порту контейнера (в нашем примере порт 80). По соображениям безопасности Docker не открывает порт автоматически, но ожидает, когда это сделает пользователь в команде docker run. Вы можете указать множество инструкций EXPOSE для указания, какие порты должны быть открыты. Также инструкция EXPOSE полезна для проброса портов между контейнерами.
Строим образ из нашего файла
, где trukhinyuri – название репозитория, где будет храниться образ, nginx – имя образа. Последний параметр — путь к папке с Dockerfile. Если вы не укажете название образа, он автоматически получит название latest. Также вы можете указать git репозиторий, где находится Dockerfile.
В данном примере мы строим образ из Dockerfile, расположенном в корневой директории Docker.
Что произойдет, если инструкция не исполнится?
Давайте переименуем в Dockerfile nginx в ngin и посмотрим.
Использования кеша сборок для шаблонизации
Используя кеш сборок можно строить образы из Dockerfile в форме простых шаблонов. Например шаблон для обновления APT-кеша в Ubuntu:
Инструкция ENV устанавливает переменные окружения в образе. В данном случае мы указываем, когда шаблон был обновлен. Когда необходимо обновить построенный образ, просто нужно изменить дату в ENV. Docker сбросит кеш и версии пакетов в образе будут последними.
Инструкции Dockerfile
Давайте рассмотрим и другие инструкции Dockerfile. Полный список можно посмотреть тут.
Инструкция CMD указывает, какую команду необходимо запустить, когда контейнер запущен. В отличие от команды RUN указанная команда исполняется не во время построения образа, а во время запуска контейнера.
ENTRYPOINT
Часто команду CMD путают с ENTRYPOINT. Разница в том, что вы не можете перегружать ENTRYPOINT при запуске контейнера.
При запуске контейнера параметры передаются команде, указанной в ENTRYPOINT.
Можно комбинировать ENTRYPOINT и CMD.
WORKDIR
С помощью WORKDIR можно установить рабочую директорию, откуда будут запускаться команды ENTRYPOINT и CMD.
Специфицирует пользователя, под которым должен быть запущен образ. Мы можем указать имя пользователя или UID и группу или GID.
VOLUME
Инструкция VOLUME добавляет тома в образ. Том — папка в одном или более контейнерах или папка хоста, проброшенная через Union File System (UFS).
Тома могут быть расшарены или повторно использованы между контейнерами. Это позволяет добавлять и изменять данные без коммита в образ.
В примере выше создается точка монтирования /opt/project для любого контейнера, созданного из образа. Таким образом вы можете указывать и несколько томов в массиве.
Инструкция ADD добавляет файлы или папки из нашего билд-окружения в образ, что полезно например при установке приложения.
Источником может быть URL, имя файла или директория.
В последнем примере архив tar.gz будет распакован в /var/www/wordpress. Если путь назначения не указан — будет использован полный путь включая директории.
Инструкция COPY отличается от ADD тем, что предназначена для копирования локальных файлов из билд-контекста и не поддерживает распаковки файлов:
ONBUILD
Инструкция ONBUILD добавляет триггеры в образы. Триггер исполняется, когда образ используется как базовый для другого образа, например, когда исходный код, нужный для образа еще не доступен, но требует для работы конкретного окружения.
Коммуникация между контейнерами
В предыдущей статье было показано, как запускать изолированные контейнеры Docker и как пробрасывать файловую систему в них. Но что, если приложениям нужно связываться друг с другом. Есть 2 способа: связь через проброс портов и линковку контейнеров.
Проброс портов
Такой способ связи уже был показан ранее. Посмотрим на варианты проброса портов чуть шире.
Когда мы используем EXPOSE в Dockerfile или параметр -p номер_порта – порт контейнера привязывается к произвольному порту хоста. Посмотреть этот порт можно командой docker ps или docker port имя_контейнера номер_порта_в_контейнере. В момент создания образа мы можем не знать, какой порт будет свободен на машине в момент запуска контейнера.
Можно привязать UDP порты, указав /udp:
Линковка контейнеров
Связь через сетевые порты — лишь один способ коммуникации. Docker предоставляет систему линковки, позволяющую связать множество контейнеров вместе и отправлять информацию о соединении от одного контейнера другому.
Префикс DB_ был взят из alias контейнера.
Можно просто использовать информацию из hosts, например команда ping db (где db – alias) будет работать.
Заключение
В этой статье мы научились использовать Dockerfile и организовывать связь между контейнерами. Это только вершина айсберга, очень многое осталось за кадром и будет рассмотрено в будущем. Для дополнительного чтения рекомендуем книгу The Docker Book.
Готовый образ с Docker доступен в облаке InfoboxCloud.
В случае, если вы не можете задавать вопросы на Хабре, можно задать в Сообществе InfoboxCloud.
Если вы обнаружили ошибку в статье, автор ее с удовольствием исправит. Пожалуйста напишите в ЛС или на почту о ней.
Docker Context
Estimated reading time: 8 minutes
Introduction
This guide shows how contexts make it easy for a single Docker CLI to manage multiple Swarm clusters, multiple Kubernetes clusters, and multiple individual Docker nodes.
A single Docker CLI can have multiple contexts. Each context contains all of the endpoint and security information required to manage a different cluster or node. The docker context command makes it easy to configure these contexts and switch between them.
As an example, a single Docker client on your company laptop might be configured with two contexts; dev-k8s and prod-swarm. dev-k8s contains the endpoint data and security credentials to configure and manage a Kubernetes cluster in a development environment. prod-swarm contains everything required to manage a Swarm cluster in a production environment. Once these contexts are configured, you can use the top-level docker context use to easily switch between them.
For information on using Docker Context to deploy your apps to the cloud, see Deploying Docker containers on Azure and Deploying Docker containers on ECS.
Prerequisites
To follow the examples in this guide, you’ll need:
Run docker context to verify that your Docker client supports contexts.
You will also need one of the following:
The anatomy of a context
A context is a combination of several properties. These include:
The easiest way to see what a context looks like is to view the default context.
This shows a single context called “default”. It’s configured to talk to a Swarm cluster through the local /var/run/docker.sock Unix socket. It has no Kubernetes endpoint configured.
This context is using “swarm” as the orchestrator ( metadata.stackOrchestrator ). It is configured to talk to an endpoint exposed on a local Unix socket at /var/run/docker.sock ( Endpoints.docker.Host ), and requires TLS verification ( Endpoints.docker.SkipTLSVerify ).
Create a new context
You can create new contexts with the docker context create command.
The following example creates a new context called “docker-test” and specifies the following:
The new context is stored in a meta.json file below
The current context is indicated with an asterisk (“*”).
Use a different context
You can use docker context use to quickly switch between contexts.
The following command will switch the docker CLI to use the “k8s-test” context.
Verify the operation by listing all contexts and ensuring the asterisk (“*”) is against the “k8s-test” context.
docker commands will now target endpoints defined in the “k8s-test” context.
Use the appropriate command below to set the context to docker-test using an environment variable.
Run a docker context ls to verify that the “docker-test” context is now the active context.
Exporting and importing Docker contexts
The docker context command makes it easy to export and import contexts on different machines with the Docker client installed.
You can use the docker context export command to export an existing context to a file. This file can later be imported on another machine that has the docker client installed.
By default, contexts will be exported as a native Docker contexts. You can export and import these using the docker context command. If the context you are exporting includes a Kubernetes endpoint, the Kubernetes part of the context will be included in the export and import operations.
There is also an option to export just the Kubernetes part of a context. This will produce a native kubeconfig file that can be manually merged with an existing
Let’s look at exporting and importing a native Docker context.
Exporting and importing a native Docker context
Check the contents of the export file.
Now, let’s look at exporting just the Kubernetes parts of a context.
Exporting a Kubernetes context
Verify that the exported file contains a valid kubectl config.
You can merge this with an existing
/.kube/config file on another machine.
Updating a context
You can use docker context update to update fields in an existing context.
The following example updates the “Description” field in the existing k8s-test context.
docker build
Description
Build an image from a Dockerfile
Usage
Extended description
The URL parameter can refer to three kinds of resources: Git repositories, pre-packaged tarball contexts and plain text files.
Git repositories
When the URL parameter points to the location of a Git repository, the repository acts as the build context. The system recursively fetches the repository and its submodules. The commit history is not preserved. A repository is first pulled into a temporary directory on your local host. After that succeeds, the directory is sent to the Docker daemon as the context. Local copy gives you the ability to access private repositories using local user credentials, VPN’s, and so forth.
Git URLs accept context configuration in their fragment section, separated by a colon ( : ). The first part represents the reference that Git will check out, and can be either a branch, a tag, or a remote reference. The second part represents a subdirectory inside the repository that will be used as a build context.
For example, run this command to use a directory called docker in the branch container :
The following table represents all the valid suffixes with their build contexts:
Build Syntax Suffix | Commit Used | Build Context Used |
---|---|---|
myrepo.git | refs/heads/master | / |
myrepo.git#mytag | refs/tags/mytag | / |
myrepo.git#mybranch | refs/heads/mybranch | / |
myrepo.git#pull/42/head | refs/pull/42/head | / |
myrepo.git#:myfolder | refs/heads/master | /myfolder |
myrepo.git#master:myfolder | refs/heads/master | /myfolder |
myrepo.git#mytag:myfolder | refs/tags/mytag | /myfolder |
myrepo.git#mybranch:myfolder | refs/heads/mybranch | /myfolder |
You cannot specify the build-context directory ( myfolder in the examples above) when using BuildKit as builder ( DOCKER_BUILDKIT=1 ). Support for this feature is tracked in buildkit#1684.
Tarball contexts
If you pass an URL to a remote tarball, the URL itself is sent to the daemon:
The download operation will be performed on the host the Docker daemon is running on, which is not necessarily the same host from which the build command is being issued. The Docker daemon will fetch context.tar.gz and use it as the build context. Tarball contexts must be tar archives conforming to the standard tar UNIX format and can be compressed with any one of the вЂxz’, вЂbzip2’, вЂgzip’ or вЂidentity’ (no compression) formats.
Text files
With Powershell on Windows, you can run:
If the Docker client loses connection to the daemon, the build is canceled. This happens if you interrupt the Docker client with CTRL-c or if the Docker client is killed for any reason. If the build initiated a pull which is still running at the time the build is cancelled, the pull is cancelled as well.
For example uses of this command, refer to the examples section below.
Options
Examples
Build with PATH
The transfer of context from the local machine to the Docker daemon is what the docker client means when you see the “Sending build context” message.
Build with URL
This will clone the GitHub repository and use the cloned repository as context. The Dockerfile at the root of the repository is used as Dockerfile. You can specify an arbitrary Git repository by using the git:// or git@ scheme.
This will read a Dockerfile from STDIN without context. Due to the lack of a context, no contents of any local directory will be sent to the Docker daemon. Since there is no context, a Dockerfile ADD only works if it refers to a remote URL.
Tag an image (-t)
Specify a Dockerfile (-f)
The above command will use the current directory as the build context and read a Dockerfile from stdin.
These two docker build commands do the exact same thing. They both use the contents of the debug file instead of looking for a Dockerfile and will use /home/me/myapp as the root of the build context. Note that debug is in the directory structure of the build context, regardless of how you refer to it on the command line.
Use a custom parent cgroup (—cgroup-parent)
Set ulimits in container (—ulimit)
Set build-time variables (—build-arg)
You can use ENV instructions in a Dockerfile to define variable values. These values persist in the built image. However, often persistence is not what you want. Users want to specify variables differently depending on which host they build an image on.
Using this flag will not alter the output you see when the ARG lines from the Dockerfile are echoed during the build process.
For detailed information on using ARG and ENV instructions, see the Dockerfile reference.
Optional security options (—security-opt)
Specify isolation technology for container (—isolation)
Add entries to container hosts file (—add-host)
Specifying target build stage (—target)
Custom build outputs
The example above uses the short-hand syntax, omitting the type options, and thus uses the default ( local ) exporter. The example below shows the equivalent using the long-hand CSV syntax, specifying both type and dest (destination path):
The example Dockerfile below uses a separate stage to collect the build-artifacts for exporting:
This feature requires the BuildKit backend. You can either enable BuildKit or use the buildx plugin which provides more output type options.
Specifying external cache sources
Upon importing the cache, the builder will only pull the JSON metadata from the registry and determine possible cache hits based on that information. If there is a cache hit, the matched layers are pulled into the local environment.
In addition to images, the cache can also be pulled from special cache manifests generated by buildx or the BuildKit CLI ( buildctl ). These manifests (when built with the type=registry and mode=max options) allow pulling layer data for intermediate stages in multi-stage builds.
The following example builds an image with inline-cache metadata and pushes it to a registry, then uses the image as a cache source on another machine:
After pushing the image, the image is used as cache source on another machine. BuildKit automatically pulls the image from the registry if needed.
On another machine:
This feature requires the BuildKit backend. You can either enable BuildKit or use the buildx plugin. The previous builder has limited support for reusing cache from pre-pulled images.
Squash an image’s layers (—squash) (experimental)
Overview
Once the image is built, squash the new layers into a new image with a single new layer. Squashing does not destroy any existing image, rather it creates a new image with the content of the squashed layers. This effectively makes it look like all Dockerfile commands were created with a single layer. The build cache is preserved with this method.
Squashing layers can be beneficial if your Dockerfile produces multiple layers modifying the same files, for example, files that are created in one step, and removed in another step. For other use-cases, squashing images may actually have a negative impact on performance; when pulling an image consisting of multiple layers, layers can be pulled in parallel, and allows sharing layers between images (saving space).
For most use cases, multi-stage builds are a better alternative, as they give more fine-grained control over your build, and can take advantage of future optimizations in the builder. Refer to the use multi-stage builds section in the userguide for more information.
Known limitations
Prerequisites
The example on this page is using experimental mode in Docker 19.03.
By default, experimental mode is disabled. To see the current configuration of the docker daemon, use the docker version command and check the Experimental line in the Engine section:
To enable experimental mode, users need to restart the docker daemon with the experimental flag enabled.
Enable Docker experimental
Then make sure the experimental flag is enabled:
If everything is right, the history looks like this:
Полная автоматизация «development» среды с помощью docker-compose
В этой статье мы поделимся опытом автоматизации запуска, тестирования и конфигурации больших проектов с использованием docker-compose. Несколько простых изменений могут помочь Вашей команде быть более эффективной и тратить время на важные, а не на рутинные задачи.
Docker в 2017
На конференции Dockercon 2016 CEO компании Docker рассказал, что количество приложений, которые запускаются в Docker выросло на 3100% за последние два года. Боле 460 тысяч приложений по всему миру запускаются в Docker. Это невероятно!
Если вы все еще не используете Docker, я бы посоветовал почитать отличную статью об использовании Docker во всем мире. Docker полностью изменил то, как мы пишем приложения и стал неотъемлемой частью для разработчиков и DevOps команд. В этой статье мы полагаем, что вы уже знакомы с Docker и хотим дать вам еще одну серьезную причину продолжать использовать его.
Что не так?
С начала моей карьеры, когда я занимался разработкой веб-приложений, запуск приложения в рабочем окружении всегда был непростой задачей. Приходилось делать много дополнительной работы от установки базы данных до конфигурации приложения, чтобы просто его запусить. Разработчики любят не любят писать документацию, и шаги для запуска проекта обычно спрятаны в головах членов команды. В итоге, запуск проекта становится болезненной задачей, особенно для новых ребят.
Многие проекты просты в начале, но становятся больше со временем. Это приводит к увеличению внешних зависимостей, таких как базы данных, очереди. В связи с ростом популярности микросервисов, многие проекты перестают быть монолитными и разделяются на несколько небольших частей. Любое такое изменение требует внимания всей команды, так как после таких изменений, проект нужно запускать по-другому. Обычно, разработчики, занимающиеся корневыми изменениями, пишут письмо, либо создают вики страничку с описанием шагов, которые нужно сделать, чтобы проект снова запустился на рабочих окружениях. Обычно это работает, но не всегда 🙂 Однажды наша команда попала в ситуацию, когда разработчик с другого континента сделал много изменений в проекте, написал длинное письмо и ушел спать. Я полагаю, Вы знаете, что было дальше. Все верно, он забыл упомянуть несколько важных моментов. В результате, на следующий день часть команды просто не смогла запустить проект и день был потерян.
Как инженеру, мне нравится автоматизировать все вокруг. Я верю, что запуск, тестирование и развертывание всегда должны быть одношаговыми. В этом случае, команда сможет сфокусироваться на важных задачах: разработке и улучшении продукта. Это было сложнее сделать 10 лет назад, но сейчас автоматизировать стало гораздо проще и, как мне кажется, каждая команда должна уделять этому время. Чем раньше — тем лучше.
Быстрый старт с docker-compose
Docker-compose это простой инструмент, который позволяет настроить и запустить несколько контейнеров одной командой. До того, как мы нырнем глубже в docker-compose, нужно немного остановиться на структуре проекта. Мы используем «monorepo». Код каждого сервиса (frontend, api, worker, etc) находится в своей директории и имеет Dockerfile. Пример структуры проекта можно посмотреть здесь.
Чтобы запустить проект, нам понадобиться одна команда:
При первом старте, все контейнеры будут построены или скачаны. Если вы работали с Docker, конфигурационный файл для docker-compose должен быть более-менее понятен, но стоит обратить внимание на несколько деталей:
Совет: Вы можете обернуть команду запуска проект в простой баш скрипт:
Частичный запуск
В этом примере docker-compose.yml некоторые сервисы зависят друг от друга:
В больших проектах всегда есть части, которые нужны лишь время от времени. Различные члены команды могут работать над различными частями приложения. Фронтенд разработчику, который работает над landing сайтом, нет нужды запускать проект целиком. Он может просто запустить только те части, которые ему действительно нужны.
>/dev/null назойливые логи
Часто мы используем инструменты, которые генерируют много логов, тем самым отвлекая нас от полезных логов нашего приложения. Чтобы отключить логи для конкретного сервиса, нужно просто установить logging driver в none.
Несколько файлов docker-compose
Так почему же вам может понадобиться несколько конфигурационных файлов? Первый вариант использования — это разбиение большого проекта на несколько более мелких. Интересно, что даже если вы запускаете несколько отдельных docker-compose, сервисы все равно смогут общаться друг с другом по имени из docker-compose. Например, вы можете разделить инфраструктурные контэйнеры (базы данных, очереди и т.д.) и контейнеры приложения в отдельные docker-compose файлы.
Запуск тестов
Наши тесты включают в себя различные типы: юнит, интеграционные, UI тестирование, проверку синтаксиса кода. У каждого сервиса свой набор тестов. Интеграционные и UI тесты требуют api и web frontend для их работы.
В самом начале нам показалось, что мы должны запускать тесты при каждом запуске docker-compose. Но очень скоро мы поняли, что это не всегда удобно и занимает слишком много времени. В каких-то случаях нам также хотелось иметь немного больше контроля над тем, какие тесты запускать. Для этого мы используем отдельный конфигурационный docker-compose файл:
Для запуска тестов необходимо, чтобы основной docker-compose был запущен. Интеграционные тесты используют рабочую версию api сервиса, а UI тесты используют web frontend сервиса. По сути тесты просто используют образы, которые собраны в основном docker-compose. Также возможен запуск тестов только для конкретного сервиса, например:
Данная команда запустит только тесты для api сервиса.
Префикс для контейнеров
Таким образом, префикс будет одинаковым во всех рабочих окружениях.
Заключение
Docker-compose это очень полезный и гибкий способ автоматизации запуска проектов.
Когда новые разработчики добавляются к нам в команду, мы даем им небольшую задачу, которую они должны закончить к концу первого рабочего дня. Каждый, кто присоединялся к нашей команде, справился с этим и был самым счастливым человеком на Земле. Уже с первых минут новые разработчики могут сфокусироваться на важных задачах и не тратить времени на то, чтобы запустить проект. Наша документация для старта проекта состоит из трех пунктов:
Для того, чтобы Вам было проще понять эту статью, у нас есть пример проекта на Github. Делитесь вашим опытом и задавайте вопросы.
Надеемся, что статья была полезной и поможет сделать Ваш проект лучше 🙂
Версию на английском, можно почитать здесь.