Перейти к основному содержимому

Как заставить Docker-Compose всегда использовать последний образ

· 5 мин. чтения

1. Введение

В наших проектах мы часто используем docker-compose для развертывания наших контейнерных приложений. С CI и CD изменения кода и развертывания в настоящее время очень часты. Следовательно, важно убедиться, что docker-compose всегда использует самые последние образы приложений .

В этом уроке мы рассмотрим несколько вариантов достижения того же.

2. Явное извлечение изображений

Возьмем простой пример файла docker-compose:

version: '2.4'
services:
db:
image: postgres
my_app:
image: "foreach/test-app:latest"
ports:
- "8080:8080"

Здесь мы использовали два сервиса: один — база данных PostgreSQL, а другой — тестовое приложение. Мы используем следующую команду для развертывания наших приложений:

$ docker-compose up -d

Это извлекает оба образа из удаленного репозитория (скажем, dockerhub ) и создает соответствующие контейнеры.

Проблема возникает, когда мы повторно развертываем наше приложение с помощью той же команды. Поскольку образы уже существуют в локальном репозитории, он не проверяет, есть ли какие-либо изменения для этих образов в удаленном репозитории. Итак, наш вариант — заранее вытащить все изображения из файла docker-compose :

$ docker-compose pull
Pulling db ... done
Pulling my_app ... done

Эта команда сначала проверяет наличие доступных обновлений для обоих образов в dockerhub . Затем он загружает только необходимые слои, чтобы поддерживать актуальность изображения с пульта.

Однако мы не всегда можем предпочесть извлекать образ Postgres . Если мы используем стабильную версию базы данных, изменений в образе не будет. Таким образом, нет смысла загружать его для каждого развертывания. Иногда существующие файлы данных несовместимы с новой версией. Это может нарушить развертывание. В этом случае мы можем использовать только имена конкретных сервисов в команде pull :

$ docker-compose pull my_app
Pulling my_app ... done

Теперь, если мы выполним команду up , это точно воссоздаст контейнеры с последним образом :

$ docker-compose up -d
Starting docker-test_db_1 ... done
Starting docker-test_my_app_1 ... done

Мы можем, конечно, объединить обе команды, чтобы создать однострочную строку:

$ docker-compose pull && docker-compose up -d

3. Удаление локальных изображений

Давайте снова рассмотрим тот же пример. Мы уже знаем, что основная проблема заключается в существовании локальных изображений. Итак, второй вариант, который у нас есть, — остановить все контейнеры и удалить их образы из локального репозитория :

$ docker-compose down --rmi all
Stopping docker-test_my_app_1 ... done
Removing docker-test_db_1 ... done
Removing docker-test_my_app_1 ... done
Removing network docker-test_default
Removing image postgres
Removing image foreach/test-app:latest

Команда down останавливает и удаляет контейнеры. Параметр –rmi удаляет изображения из локального репозитория. Тип rmi local удаляет только те образы, которые были созданы локально . Таким образом, лучше использовать тип rmi all , чтобы гарантировать удаление всех образов, используемых текущей конфигурацией.

Теперь мы снова запускаем наш контейнер с помощью команды up :

$ docker-compose up -d
Creating network "docker-test_default" with the default driver
Pulling db (postgres:)...
latest: Pulling from library/postgres
7d63c13d9b9b: Pull complete
cad0f9d5f5fe: Pull complete
...
Digest: sha256:eb83331cc518946d8ee1b52e6d9e97d0cdef6195b7bf25323004f2968e91a825
Status: Downloaded newer image for postgres:latest
Pulling my_app (foreach/test-app:latest)...
latest: Pulling from foreach/test-app
df5590a8898b: Already exists
705bb4cb554e: Already exists
...
Digest: sha256:31c05c8245192b32b8b359fc58b5e45d8397674ccf41f5f17a7d3109772ab5c1
Status: Downloaded newer image for foreach/test-app:latest
Creating docker-test_db_1 ... done
Creating docker-test_my_app_1 ... done

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

Недостатком этого подхода является то, что вы не можете выбрать определенные изображения для удаления. Таким образом, он всегда удаляет изображение postgres и снова загружает то же изображение, что не нужно. Чтобы решить эту проблему, мы можем использовать docker rmi для удаления определенного образа:

$ docker rmi -f foreach/test-app:latest
Untagged: foreach/test-app:latest
Untagged: foreach/test-app@sha256:31c05c8245192b32b8b359fc58b5e45d8397674ccf41f5f17a7d3109772ab5c1
Deleted: sha256:7bc07b4eb1c23f7a91afeb7133f107e0a8318fb77655d7d5f2f395a035a13eb7

4. Восстановление изображений

Давайте посмотрим на тот же пример файла docker-compose с другим вкусом:

version: '2.4'
services:
db:
image: postgres
my_app:
build: ./test-app
ports:
- "8080:8080"

Здесь мы использовали ту же службу базы данных с Postgres. Но для сервиса my_app мы дали раздел сборки вместо того, чтобы использовать готовый образ. Этот раздел содержит контекст сборки test-app . Файл докера, который находится в каталоге test-app, выглядит следующим образом:

FROM openjdk:11
COPY target/test-app-0.0.1-SNAPSHOT.jar app.jar
ENTRYPOINT ["java","-jar","/app.jar"]

В этом сценарии при повторном развертывании с помощью команды up docker -compose снова повторно использует локальный образ, если он существует. Итак, нам нужно убедиться, что docker-compose перестраивает образ каждый раз, когда мы инициируем развертывание. Мы можем сделать это с помощью опции --build :

$ docker-compose up -d --build
Building my_app
[+] Building 2.5s (8/8) FINISHED
=> [internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 41B 0.0s
=> [internal] load .dockerignore 0.0s
=> => transferring context: 2B 0.0s
=> [internal] load metadata for docker.io/library/openjdk:11 2.3s
=> [auth] library/openjdk:pull token for registry-1.docker.io 0.0s
=> [1/2] FROM docker.io/library/openjdk:11@sha256:1b04b1958a4a61900feec994e3938a2a5d8f88db8ec9515f46a25cbe561b65d9 0.0s
=> [internal] load build context 0.0s
=> => transferring context: 84B 0.0s
=> CACHED [2/2] COPY target/test-app-0.0.1-SNAPSHOT.jar app.jar 0.0s
=> exporting to image 0.0s
=> => exporting layers 0.0s
=> => writing image sha256:4867a3f0b0a043cd54e16086e2d3c81dbf4c418806399f60fc7d7ffc094c7159 0.0s
=> => naming to docker.io/library/docker-test_my_app 0.0s

Starting docker-test_db_1 ...
Starting docker-test_db_1 ... done

Альтернативный подход — использовать команду build перед запуском команды up :

$ docker-compose build --pull --no-cache
db uses an image, skipping
Building my_app
... 0.0s
=> => naming to docker.io/library/docker-test_my_app

Эта команда предлагает еще два варианта. Параметр –pull запрашивает извлечение базового образа Dockerfile из удаленного репозитория при создании образа. Опция --no-cache означает, что локальный кеш пропускается. Однако он пропускает создание службы db , потому что мы использовали там прямой образ.

Теперь, если мы перезапустим нашу конфигурацию компоновки, контейнеры будут использовать последний образ:

$ docker-compose up -d
Starting docker-test_db_1 ... done
Recreating docker-test_my_app_1 ... done

5. Вывод

В этой статье мы увидели, почему docker-compose может не использовать последний образ во время развертывания. Мы также узнали несколько способов заставить docker-compose всегда использовать самые последние образы для воссоздания контейнеров с этим образом. Мы также обсудили подводные камни подходов и способы их смягчения.

Код, относящийся к статье, доступен на GitHub .