[Перевод] Docker передает cnab-to-oci в проект CNAB… и что вообще такое CNAB?

Прим. перев.: Эта статья — перевод недавнего анонса из мира контейнеров. В прошлом месяце компания Docker объявила о передаче своей очередной разработки в руки более широкого Open Source-сообщества. Речь шла об инструменте конвертации метаданных CNAB-пакета в формат стандарта OCI (Open Container Initiative) — для удобной возможности распространения содержимого таких пакетов в реестрах для контейнеров (вроде Docker Registry). Но чтобы получше во всём этом разобраться, мы начнём с перевода другой заметки (написанной Jack Wallen для The New Stack) — о том, что вообще такое CNAB.

olcrexpnbwzzddv4c7tqhs---zg.png

Что такое CNAB и почему он важен для экосистемы cloud native?


Cloud Native Application Bundle (CNAB) — открытая спецификация, цель которой — упростить упаковку, установку контейнеризированных приложений и управление ими. С помощью таких пакетов пользователи могут определять ресурсы, которые затем разворачиваются в различных runtime-средах, таких как Docker, Azure, Kubernetes, Helm, службы автоматизации (например, используемые в GitOps) и т.д.

Спецификация CNAB стала результатом сотрудничества многих компаний, в том числе Microsoft, HashiCorp, Bitnami, Intel, Pivotal и DataDog. Хотя многие из компаний, участвующих в разработке, предлагают собственные облачные услуги, CNAB не зависит от конкретной реализации облака (cloud-agnostic). Другими словами, он работает с любой инфраструктурой и программным обеспечением и не привязан к конкретному поставщику услуг.

Некоторое время назад была выпущена версия CNAB 1.0, то есть проект теперь вполне готов к применению в production. Любой IT-профессионал, имеющий отношение к облачным сервисам/контейнерам, обязан быть в курсе происходящего со CNAB.

Дополнительные подробности


«С ростом сложности современных мультисервисных, распределенных приложений все острее стоит проблема упрощения процессов сборки, распространения и использования», — говорит Robert Duffner, директор по совместному маркетингу в Docker. Любому, кто работал с Kubernetes, эта проблема хорошо знакома, поскольку K8s очень быстро может стать довольно запутанным и сложным. Duffner продолжает: «Современные приложения состоят из множества разнообразных компонентов и сервисов. Они могут включать различные облачные ресурсы, управляемые сервисы, продукты SaaS, контейнеры, форматы конфигурации (чарты Helm, YAML-файлы Kubernetes, файлы Docker Compose), функции и многое другое.

Но при чем тут CNAB? «CNAB объединяет эти разнообразные компоненты, предоставляя единый формат упаковки для мультисервисных приложений. Дальше с этими пакетами можно работать, управлять ими и делиться (через реестр вроде Docker Hub), словно это составной и неизменный объект, не зависящий от какой-либо конкретной среды/облачной реализации».

Чтобы прояснить этот момент, переключимся на более конкретную тему — Kubernetes и Docker (эти технологии занимают важнейшее место в сфере деплоя контейнеров). Вот как Duffner объясняет преимущества CNAB для Kubernetes и Docker: «CNAB помогает изменить наше отношение к процессам сборки, совместного использования и запуска контейнеров, поскольку повышает диалог до уровня приложения».

В качестве поясняющего позицию примера приводится Docker App: «Именно это произошло с Docker App — нашей реализацией спецификации CNAB. Она разработана как раз для того, чтобы перенести простоту, ассоциирующуюся с образами Docker, на процесс сборки мультисервисных приложений, их распространение и запуск с использованием различных форматов конфигурации».
Высочайшее внимание к стандартизации, уделяемое в CNAB, позволяет собрать контейнеры и сервисы в единое и неделимое целое. Спецификация состоит из следующих частей:

  • CNAB — содержит информацию об основах ядра CNAB 1.0
  • CNAB Registry — описывает, как можно хранить пакеты CNAB внутри реестров OCI (этот раздел еще не завершен).
  • CNAB Security — описывает механизмы подписи, проверки и подтверждения пакетов CNAB.
  • CNAB Claims — об одноимённой системе, которая рассказывает, как можно отформатировать записи об инсталляциях CNAB для хранения.
  • CNAB Dependencies — описывает, как включать в пакет другие пакеты в качестве зависимостей.


Что такое пакет (bundle)?


В настоящее время есть множество способов развернуть контейнеризированное приложение. Можно воспользоваться Docker, Docker Compose, Kubernetes и другими инструментами, каждый из которых предъявляет собственные требования к формату конфигурационных файлов. CNAB собирает все необходимые метаданные в одном файле — bundle.json. Этот файл разбит на следующие составляющие:

  • Версия схемы пакета.
  • Высокоуровневая информация о пакете.
  • Информация о вызываемых (invocation) образах.
  • Карта образов, включенных в пакет.
  • Спецификация переопределяемых параметров (и ссылка на схему проверки).
  • Список учетных данных, необходимых приложению.
  • Опциональное описание пользовательских действий.
  • Перечень результатов, выводимых приложением.
  • Набор определений схемы, используемой для проверки введенных пользователем данных.


Пакеты бывают двух видов:

  • Тонкие (thin) пакеты содержат только один объект — дескриптор пакета в формате JSON (который должен представлять собой канонический JSON).
  • Толстые (thick) пакеты содержат несколько объектов: дескриптор пакета, один или более вспомогательных (вызываемых) образов, ноль или более образов. Толстый пакет включает файл bundle.json, который должен лежать в корне сжатого архива.


bundle.json похож на docker-compose.yml в том смысле, что описывает комплексную конфигурацию для развертывания образа. Разница между ними в том, что в CNAB четко определены содержание и формат этого файла, а также месторасположение всех связанных файлов.

По теме пакетов Duffner говорит следующее: «Сборка, распространение и запуск современных распределенных приложений, состоящих из разнообразных частей: веб-компонентов, инструментов машинного обучения, функций, API и т.д., — это весьма сложный процесс». Любой, кто пытался развернуть сложные контейнеры, знает об этом. Как CNAB справляется с такой сложностью? «Одним из преимуществ Docker App (реализации CNAB) является упрощение приложений с помощью Docker Compose, а затем их непосредственное развертывание в облаке. Так что четко описываемый, неизменяемый (immutable) подход и наличие стандартного способа развертывания cloud native-приложений действительно важны».

Кто выигрывает больше всего


Неудивительно, что CNAB преимущественно ориентирована на корпоративное применение. Действительно, простой деплой контейнеров не сравнится с многогранной сложностью сервиса, используемого компанией из списка Fortune 500. Duffner отмечает: «Крупные компании являются основными потребителями CNAB. Многие из них используют сотни, а то и тысячи распределенных приложений и мечтают упростить их сборку, управление ими и повысить безопасность по всей цепочке поставок программного обеспечения».

Впрочем, от CNAB выиграют не только крупные компании. Duffner считает, что разработчики и команды DevOps, которые в настоящее время вынуждены справляться со сложностью развертывания современных приложений, значительно выиграют от внедрения спецификации CNAB. С ее помощью они смогут «улучшить взаимодействие и сократить время вывода ПО на рынок».

Полная спецификация для CNAB версии 1.0 доступна здесь.

Docker передает библиотеку cnab-to-oci в cnab.io


12 февраля компания Docker с радостью и гордостью сообщила о безвозмездной передаче библиотеки cnab-to-oci проекту CNAB. Этот проект появился в прошлом году после того, как Microsoft и Docker перенесли спецификацию CNAB в фонд Joint Development Foundation, входящий в Linux Foundation. Тогда репозиторий спецификации CNAB переехал из репозитория deislab на GitHub в новый репозиторий cnabio. Библиотека cnab-go, написанная на Go и содержащая реализацию спецификации, и duffle (референсная реализация CLI) также переехали в новый репозиторий.

Для чего нужна библиотека cnab-to-oci?


Команда Docker помогала разрабатывать спецификации CNAB и ее исходные реализации, а также возглавляла работу над библиотекой cnab-to-oci. Цель последней — распространение CNAB-пакетов (bundles) через существующие реестры контейнеров. В настоящее время этой библиотекой пользуются три CNAB-инструмента: Docker App, Porter и duffle, а также Docker Hub. С её помощью реестры могут push’ить и pull’ить пакеты CNAB, а также делиться ими. Наработки, сделанные в процессе создания этой библиотеки, будут использоваться как базис для будущей спецификации CNAB Registry.

Сама передача репозитория уже произошла, так что, начиная с текущего момента, в Go-импортах следует ссылаться на github.com/cnabio/cnab-to-oci.

Как cnab-to-oci хранит пакеты CNAB в реестре?


Как вам, вероятно, известно, в спецификации образов OCI есть два основных объекта: OCI Manifest и OCI Image Index. Первый хорошо известен и представляет классический образ Docker. Второй поначалу использовался для хранения мульти-архитектурных образов (в качестве примера см. nginx).

Однако вы можете не знать о том, что спецификация не ограничивает использование OCI Index’ов только мульти-архитектурными образами. С их помощью можно хранить все, что угодно. Главное, чтобы содержимое удовлетворяло спецификации (которая, к слову, достаточно открыта).

cnab-to-oci пользуется этой открытостью для push’а файла bundle.json, invocation-образа и образов компонентов (или образов сервисов для Docker App). В итоге все хранится в одном и том же репозитории. Таким образом, когда кто-то извлекает (pull) свой пакет, вмести с ним также можно получить и все компоненты.

kojpfrsfqxaeeqi-jvaifqm_k6a.png

Демонстрация работы


Хотя cnab-to-oci реализована в виде библиотеки, которой могут пользоваться другие инструменты, репозиторий содержит удобный консольный инструмент, способный осуществлять push и pull любых файлов bundle.json, относящихся к спецификации CNAB.

Следующая команда выполняет push образцового пакета в репозиторий Docker Hub. В репозиторий загружаются все манифесты, обнаруженные в пакете, затем команда создает OCI Index и загружает его. Итоговый дайджест (хэш) указывает на OCI Index пакета.

$ make bin/cnab-to-oci
…
$ ./bin/cnab-to-oci push examples/helloworld-cnab/bundle.json -t hubusername/repo:demo –log-level=debug –auto-update-bundle

DEBU[0000] Fixing up bundle docker.io/hubusername/repo:demo
DEBU[0000] Updating entry in relocation map for "cnab/helloworld:0.1.1”
Starting to copy image cnab/helloworld:0.1.1…
Completed image cnab/helloworld:0.1.1 copy
DEBU[0004] Bundle fixed
DEBU[0004] Pushing CNAB Bundle docker.io/hubusername/repo:demo
DEBU[0004] Pushing CNAB Bundle Config
DEBU[0004] Trying to push CNAB Bundle Config
DEBU[0004] CNAB Bundle Config Descriptor
DEBU[0004] {
  "mediaType”: "application/vnd.cnab.config.v1+json”,
  "digest”: "sha256:e91b9dfcbbb3b88bac94726f276b89de46e4460b55f6e6d6f876e666b150ec5b”,
  "size”: 498
}
DEBU[0005] Trying to push CNAB Bundle Config Manifest
DEBU[0005] CNAB Bundle Config Manifest Descriptor
DEBU[0005] {
  "mediaType”: "application/vnd.oci.image.manifest.v1+json”,
  "digest”: "sha256:6ec4fd695cace0e3d4305838fdf9fcd646798d3fea42b3abb28c117f903a6a5f”,
  "size”: 188
}
DEBU[0006] Failed to push CNAB Bundle Config Manifest, trying with a fallback method
DEBU[0006] Trying to push CNAB Bundle Config
DEBU[0006] CNAB Bundle Config Descriptor
DEBU[0006] {
  "mediaType”: "application/vnd.oci.image.config.v1+json”,
  "digest”: "sha256:e91b9dfcbbb3b88bac94726f276b89de46e4460b55f6e6d6f876e666b150ec5b”,
  "size”: 498
}
DEBU[0006] Trying to push CNAB Bundle Config Manifest
DEBU[0006] CNAB Bundle Config Manifest Descriptor
DEBU[0006] {
  "mediaType”: "application/vnd.oci.image.manifest.v1+json”,
  "digest”: "sha256:b9616da7500f8c7c9a5e8d915714cd02d11bcc71ff5b4fd190bb77b1355c8549”,
  "size”: 193
}
DEBU[0006] CNAB Bundle Config pushed
DEBU[0006] Pushing CNAB Index
DEBU[0006] Trying to push OCI Index
DEBU[0006] {"schemaVersion”:2,”manifests”:[{"mediaType”:”application/vnd.oci.image.manifest.v1+json”,”digest”:”sha256:b9616da7500f8c7c9a5e8d915714cd02d11bcc71ff5b4fd190bb77b1355c8549″,”size”:193,”annotations”:{"io.cnab.manifest.type”:”config”}},{"mediaType”:”application/vnd.docker.distribution.manifest.v2+json”,”digest”:”sha256:a59a4e74d9cc89e4e75dfb2cc7ea5c108e4236ba6231b53081a9e2506d1197b6″,”size”:942,”annotations”:{"io.cnab.manifest.type”:”invocation”}}],”annotations”:{"io.cnab.keywords”:”[\”helloworld\”,\”cnab\”,\”tutorial\”]”,”io.cnab.runtime_version”:”v1.0.0″,”org.opencontainers.artifactType”:”application/vnd.cnab.manifest.v1″,”org.opencontainers.image.authors”:”[{\”name\”:\”Jane Doe\”,\”email\”:\”jane.doe@example.com\”,\”url\”:\”https://example.com\”}]”,”org.opencontainers.image.description”:”A short description of your bundle”,”org.opencontainers.image.title”:”helloworld”,”org.opencontainers.image.version”:”0.1.1″}}
DEBU[0006] OCI Index Descriptor
DEBU[0006] {
  "mediaType”: "application/vnd.oci.image.index.v1+json”,
  "digest”: "sha256:fcee8577f3acc8ddc6e0280e6d1eb15be70bdff460fe7353abf917a872487af2”,
  "size”: 926
}
DEBU[0007] CNAB Index pushed
DEBU[0007] CNAB Bundle pushed
Pushed successfully, with digest "sha256:fcee8577f3acc8ddc6e0280e6d1eb15be70bdff460fe7353abf917a872487af2”


Давайте проверим, что пакет действительно загружен в Docker Hub:

lo60v_nyorwjr0l1aeoyilaoehi.png

Теперь можно обратно получить пакет из репозитория. Мы получим только файл bundle.json, но в нем теперь будет ссылка на манифест образа каждого компонента внутри того же репозитория реестра. Docker Engine извлечет все образы, нужные пакету, во время выполнения. Другими словами, провести pull пакета весьма легко.

$ ./bin/cnab-to-oci pull hubusername/repo:demo –log-level=debug

DEBU[0000] Pulling CNAB Bundle docker.io/hubusername/repo:demo
DEBU[0000] Getting OCI Index Descriptor
DEBU[0001] {
  "mediaType”: "application/vnd.oci.image.index.v1+json”,
  "digest”: "sha256:fcee8577f3acc8ddc6e0280e6d1eb15be70bdff460fe7353abf917a872487af2”,
  "size”: 926
}
DEBU[0001] Fetching OCI Index sha256:fcee8577f3acc8ddc6e0280e6d1eb15be70bdff460fe7353abf917a872487af2
DEBU[0001] {
  "schemaVersion”: 2,
  "manifests”: [
    {
      "mediaType”: "application/vnd.oci.image.manifest.v1+json”,
      "digest”: "sha256:b9616da7500f8c7c9a5e8d915714cd02d11bcc71ff5b4fd190bb77b1355c8549”,
      "size”: 193,
      "annotations”: {
        "io.cnab.manifest.type”: "config”
      }
    },
    {
      "mediaType”: "application/vnd.docker.distribution.manifest.v2+json”,
      "digest”: "sha256:a59a4e74d9cc89e4e75dfb2cc7ea5c108e4236ba6231b53081a9e2506d1197b6”,
      "size”: 942,
      "annotations”: {
        "io.cnab.manifest.type”: "invocation”
      }
    }
  ],
  "annotations”: {
    "io.cnab.keywords”: "[\”helloworld\”,\”cnab\”,\”tutorial\”]”,
    "io.cnab.runtime_version”: "v1.0.0”,
    "org.opencontainers.artifactType”: "application/vnd.cnab.manifest.v1”,
    "org.opencontainers.image.authors”: "[{\”name\”:\”Jane Doe\”,\”email\”:\”jane.doe@example.com\”,\”url\”:\”https://example.com\”}]”,
    "org.opencontainers.image.description”: "A short description of your bundle”,
    "org.opencontainers.image.title”: "helloworld”,
    "org.opencontainers.image.version”: "0.1.1”
  }
}
DEBU[0001] Getting Bundle Config Manifest Descriptor
DEBU[0001] {
  "mediaType”: "application/vnd.oci.image.manifest.v1+json”,
  "digest”: "sha256:b9616da7500f8c7c9a5e8d915714cd02d11bcc71ff5b4fd190bb77b1355c8549”,
  "size”: 193,
  "annotations”: {
    "io.cnab.manifest.type”: "config”
  }
}
DEBU[0001] Getting Bundle Config Manifest sha256:b9616da7500f8c7c9a5e8d915714cd02d11bcc71ff5b4fd190bb77b1355c8549
DEBU[0001] {
  "schemaVersion”: 2,
  "config”: {
    "mediaType”: "application/vnd.oci.image.config.v1+json”,
    "digest”: "sha256:e91b9dfcbbb3b88bac94726f276b89de46e4460b55f6e6d6f876e666b150ec5b”,
    "size”: 498
  },
  "layers”: null
}
DEBU[0001] Fetching Bundle sha256:e91b9dfcbbb3b88bac94726f276b89de46e4460b55f6e6d6f876e666b150ec5b
DEBU[0002] {
  "schemaVersion”: "v1.0.0”,
  "name”: "helloworld”,
  "version”: "0.1.1”,
  "description”: "A short description of your bundle”,
  "keywords”: [
    "helloworld”,
    "cnab”,
    "tutorial”
  ],
  "maintainers”: [
    {
      "name”: "Jane Doe”,
      "email”: "jane.doe@example.com”,
      "url”: "https://example.com”
    }
  ],
  "invocationImages”: [
    {
      "imageType”: "docker”,
      "image”: "cnab/helloworld:0.1.1”,
      "contentDigest”: "sha256:a59a4e74d9cc89e4e75dfb2cc7ea5c108e4236ba6231b53081a9e2506d1197b6”,
      "size”: 942,
      "mediaType”: "application/vnd.docker.distribution.manifest.v2+json”
    }
  ]
}


cnab-to-oci была интегрирована в Docker App в последнем бета-релизе v0.9.0-beta1. Это позволит пользователям проводить push и pull всего приложения, используя тот же интерфейс, что и при работе с обычными образами Docker-контейнеров. Поскольку Docker App является стандартной средой выполнения CNAB, она вполне способна справиться с таким типовым примером:

$ docker app pull hubusername/repo:demo
Successfully pulled "helloworld” (0.1.1) from docker.io/hubusername/repo:demo

$ docker app run hubusername/repo:demo
Port parameter was set to 
Install action
Action install complete for upbeat_nobel
App "upbeat_nobel” running on context "default”


Хотите узнать больше?


Тем, кто хочет больше узнать о CNAB, рекомендуем обратиться к следующим публикациям:
Мы также планируем выступить на KubeCon Europe 2020 (которую, к слову, перенесли на август — прим. перев.) с докладом под названием «Sharing is Caring! Push your Cloud Application to an OCI Registry — Silvin Lubecki & Djordje Lukic».

И конечно же, вы можете найти дополнительную информацию о cnab-to-oci в репозитории проекта на GitHub. Любой вклад приветствуется!

P.S. от переводчика


Читайте также в нашем блоге:

© Habrahabr.ru