Статьи

Запуск личного реестра Docker на EC2

Docker предоставляет реализацию реестра с  открытым исходным кодом,  называемую «Распространение», что позволяет любому легко запустить частный реестр Docker. 

Запуск серверного программного обеспечения в облаке AWS имеет несколько преимуществ:

  • Сложное управление сетевой инфраструктурой
  • Сложные инструменты контроля доступа
  • Упругие балансировщики нагрузки
  • Интегрированное управление DNS

AWS также предоставляет услуги управления контейнерами Docker через Elastic Container Service (ECS) и Elastic Beanstalk. Эти две службы отличаются по одному важному признаку: ECS ориентирован на управление задачами и службами (запускаемыми в виде контейнеров) на предварительно подготовленном и настроенном оборудовании, а Elastic Beanstalk — это инструмент для предоставления целых стеков, предназначенных для запуска указанного приложения.

Elastic Beanstalk используется для определения платформ и контекста для приложений, которые он запускал. Теперь, благодаря интеграции Docker, вы можете запускать независимое от платформы приложение в контейнерах, и ECS подчеркивает преимущества развертывания на основе Docker лучше, чем Elastic Beanstalk. По этой причине и принимая во внимание богатство существующего контента на Elastic Beanstalk, в этой статье будет использоваться ECS.

Служба Elastic Container Service (ECS) не является службой предоставления хоста. Хотя консоль управления предоставляет экран для предоставления базовой кластерной инфраструктуры, она использует только шаблон CloudFormation на серверной части. После того, как кластер подготовлен с этим шаблоном, изменения в новую инфраструктуру должны быть внесены непосредственно с помощью инструмента, специфичного для ресурса. Это также означает, что интеграция с существующей инфраструктурой или специализацией труднодостижима с этим автоматическим поставщиком кластера. Если вы знакомы с AWS в целом, вам следует подготовить собственные ECS-хосты EC2 (подробнее об этом чуть позже).

ECS занимается управлением «кластерами», «задачами» и «услугами». Кластер — это имя, которое разрешается в набор узлов-членов. Когда хост ECS подключается к сети, он запускает агент, который подключается к службе ECS и регистрируется в именованном кластере. Задача — это контейнер, запускаемый один раз, а служба — это контейнер, который следует перезапустить, если он остановится. Когда вы создаете новую задачу или службу, вы указываете кластер, где она должна быть запущена. Кластер обрабатывает задачи планирования и экземпляры служб для узлов-участников.

Чтобы интегрировать любой хост Docker с кластером ECS, этот хост должен запустить контейнер ECSAgent и задать имя кластера, к которому вы хотите присоединиться  /etc/ecs/ecs.config на хосте. Если вы настраивали хост ECS для работы в кластере с именем «default», вы можете установить для пользовательских данных для конфигурации запуска следующий скрипт:

#!/bin/bash
echo ECS_CLUSTER=default >> /etc/ecs/ecs.config

Пока что используйте раздел ECS Консоли управления AWS, чтобы создать кластер по умолчанию. Это обеспечит все вплоть до нового VPC. Вы можете создать его самостоятельно, но это утомительно и нюансировано. Будьте готовы к более длинному проекту, если вы идете по этому маршруту. Экземпляры ECS создаются с помощью Amazon Linux AMI, где предварительно установлены Docker и агент ECS.

Прежде чем начать, убедитесь, что вы создали учетную запись AWS, установили интерфейс командной строки (CLI) AWS и настроили свою среду для работы с этой учетной записью. Вы можете найти информацию об установке и настройке CLI  здесь.

Подготовьте ресурсы AWS для вашего личного реестра Docker

Проект  Docker Distribution  является открытой реализацией Docker Registry API. В то время как кластер ECS уже должен быть обеспечен всеми ресурсами AWS, необходимыми для запуска контейнера, проект распределения имеет (необязательно) интеграцию на уровне приложений с S3. Чтобы воспользоваться этим, вам потребуется предоставить несколько зависимостей AWS на уровне приложения.

Первый ресурс AWS, который вы создадите, — это корзина S3, в которой реестр будет хранить свои данные. Вы можете создать новое ведро через консоль управления или из командной строки. Замените «my-docker-registry-data» на имя по вашему выбору в следующей команде:

# Use the AWS ClI and "make bucket" (mb) command.
aws s3 mb s3://my-docker-registry-data

Ранее я упоминал о сложных инструментах управления доступом AWS. Что ж, новая корзина S3 бесполезна, если ваш личный реестр Docker не может читать или писать в нее. Следующим шагом является создание новой политики IAM, которая предоставляет привилегии чтения / записи в корзину.

Создайте новый файл с именем «registry-policy.json» и включите следующий документ. Обязательно замените «my-docker-registry-data» именем, выбранным для вашего нового сегмента S3.

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "s3:ListBucket"
            ],
            "Resource": [
                "arn:aws:s3:::my-docker-registry-data"
            ]
        },
        {
            "Effect": "Allow",
            "Action": [
                "s3:PutObject",
                "s3:GetObject",
                "s3:DeleteObject"
            ],
            "Resource": [
                "arn:aws:s3:::my-docker-registry-data/*"
            ]
        }
    ]
}

После сохранения файла политики зарегистрируйте его в AWS с помощью следующей команды. Для этого действия потребуются права управления IAM:

aws iam create-policy --policy-name registryaccess --policy-document file://registry-policy.json

Затем создайте нового пользователя IAM и учетные данные для своего реестра и присоедините только что созданную политику. Выберите имя пользователя, специфичное для варианта использования. Я использовал «Реестр». Вы можете создать пользователя из командной строки с помощью этих двух команд:

# Create a user
aws iam create-user --user-name Registry
# Create credentials for the new user
aws iam create-access-key --user-name Registry
# Output similar to:
# {
#     "AccessKey": {
#         "UserName": "Registry",
#         "Status": "Active",
#         "CreateDate": "2015-03-09T18:39:23.411Z",
#         "SecretAccessKey": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
#         "AccessKeyId": "AKIAXXXXXXXXXXXXX"
#     }
# }

Обратите внимание на AccessKeyId и SecretAccessKey, предоставленные выходными данными ответа. Вам нужно будет передать эти значения в реестр, чтобы он мог проходить аутентификацию с помощью AWS в качестве пользователя реестра. Прежде чем двигаться дальше, присоедините созданную политику к новому пользователю с помощью следующей команды. Обязательно замените  <YOUR AWS ACCOUNT ID> своим действительным идентификатором учетной записи

aws iam attach-user-policy --policy-arn arn:aws:iam::<YOUR AWS ACCOUNT ID>:policy/registryaccess --user-name Registry

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

Запуск частного реестра Docker с ECS

Запуск любого приложения в кластере ECS означает идентификацию изображения или изображений, которые вы хотите запустить, определение контейнеров, которые будут использовать эти изображения, и настройку параметров масштабирования. Вы собираетесь запустить специализацию  "registry:2" изображения в этом примере.

Вы можете создать свою собственную специализацию с помощью config.yml и Dockerfile, аналогичных двум следующим. Вы можете найти документацию для  файла конфигурации Docker Distribution  здесь. Если вы предпочитаете повторно использовать ресурсы, а не беспокоитесь о создании репозитория Docker Hub, то вам следует использовать образ, который я выпустил с этой точной конфигурацией. Имя репозитория:  "allingeek/registry:2-s3." Если вы хотите более специализировать свою конфигурацию, вам нужно будет создать свой собственный или создать существующий образ.

# config.yml
version: 0.1
log:
    fields:
        service: registry
http:
    addr: :5000
storage:
    cache:
        layerinfo: inmemory
    s3:
        accesskey: <your awsaccesskey>
        secretkey: <your awssecretkey>
        region: <your bucket region>
        bucket: <your bucketname>
        encrypt: true
        secure: true
        v4auth: true
        chunksize: 5242880
        rootdirectory: /

# Dockerfile
FROM registry:2
COPY config.yml /etc/docker/registry/config.yml

Что бы ни случилось, не включайте в эти файлы свой ключ доступа AWS или секретный ключ AWS. Они должны быть привязаны к контролю версий, чтобы иметь какое-либо применение, и последнее, что вы хотите сделать, это передать секреты контролю версий. В следующем разделе вы увидите, что существуют лучшие способы внедрения конфигурации во время выполнения. После того как вы определили образ, который вы собираетесь запустить в ECS, вам нужно определить семейство задач и службу.

Семейство задач определяет версионный набор определений контейнеров. В этом примере нам понадобится только один контейнер. Создайте новый файл с именем «registry-task.json» и вставьте его в следующий документ. Замените  <YOUR NEW IAM USER ACCESS KEY> и  <YOUR NEW IAM USER SECRET ACCESS KEY> на AccessKey и SecretAccessKey, возвращенные  create-user командой, которую вы запускали ранее. Вам также необходимо заменить  <YOUR S3 BUCKET REGION> и  <YOUR S3 BUCKET NAME> на соответствующие значения.

[
    {
      "name": "registry",
      "image": "allingeek/registry:2-s3",
      "cpu": 1024,
      "memory": 1000,
      "entryPoint": [],
      "environment": [
        {
          "name": "REGISTRY_STORAGE_S3_ACCESSKEY",
          "value": "<YOUR NEW IAM USER ACCESS KEY>"
        },
        {
          "name": "REGISTRY_STORAGE_S3_SECRETKEY",
          "value": "<YOUR NEW IAM USER SECRET ACCESS KEY>"
        },
        {
          "name": "REGISTRY_STORAGE_S3_REGION",
          "value": "<YOUR S3 BUCKET REGION>"
        },
        {
          "name": "REGISTRY_STORAGE_S3_BUCKET",
          "value": "<YOUR S3 BUCKET NAME>"
        }
      ],
      "command": ["/etc/docker/registry/config.yml"],
      "portMappings": [
        {
          "hostPort": 5000,
          "containerPort": 5000,
          "protocol": "tcp"
        }
      ],
      "volumesFrom": [],
      "links": [],
      "mountPoints": [],
      "essential": true
    }
]

Переменные среды, объявленные в этом определении контейнера, переопределяют значения для соответствующих записей в файле config.yml, упакованном с изображением. Этот документ будет иметь версии в AWS и доступен только пользователям с разрешениями на обслуживание ECS. Поскольку этот документ содержит секретные материалы, не передавайте этот файл для контроля версий и не делайте его доступным в любом общедоступном месте.

Создав файл списка определений контейнеров, зарегистрируйте новое семейство задач с помощью следующей команды:

aws ecs register-task-definition --family registry --container-definitions file://registry-task.json

Далее вам нужно определить сервис, который будет работать в вашем кластере. Вы можете найти  документацию по CLI для команды create-service  здесь. Функции членства в балансировщике нагрузки, предоставляемые ECS, позволяют сэкономить время, поэтому вы можете попробовать их здесь.

Создайте новый документ с описанием вашего сервиса. Назовите новый файл «registry-service.json». Скопируйте и вставьте следующее в этот файл и замените  <YOUR ELB NAME... его именем балансировщика нагрузки, созданного для вашего кластера. Если вы использовали поставщик кластера, предоставленный консолью управления, то это должен быть единственный балансировщик нагрузки в этом VPC. Если вы встроили свои собственные узлы ECS в свой собственный VPC и зарегистрировали свой собственный кластер, то вам следует создать новый ELB в этом VPC.

{
  "serviceName": "s3-registry-elb",
  "taskDefinition": "registry",
  "loadBalancers": [
    {
      "loadBalancerName": "<YOUR ELB NAME, something like: EC2Contai-EcsElast-S06278JGSJCM>",
      "containerName": "registry",
      "containerPort": 5000
    }
  ],
  "desiredCount": 1,
  "role": "ecsServiceRole"
}

Краткое примечание о роли IAM с именем «ecsServiceRole». Это роль IAM, которая должна была быть создана во время подготовки кластера. Если вы столкнулись с проблемами, когда эта роль не была создана, вы можете создать ее самостоятельно с помощью следующей политики:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "elasticloadbalancing:Describe*",
        "elasticloadbalancing:DeregisterInstancesFromLoadBalancer",
        "elasticloadbalancing:RegisterInstancesWithLoadBalancer",
        "ec2:Describe*",
        "ec2:AuthorizeSecurityGroupIngress"
      ],
      "Resource": [
        "*"
      ]
    },
    {
      "Effect": "Allow",
      "Action": [
        "s3:ListBucket"
      ],
      "Resource": [
        "arn:aws:s3:::ecs-registry-demo"
      ]
    },
    {
      "Effect": "Allow",
      "Action": [
        "s3:PutObject",
        "s3:GetObject",
        "s3:DeleteObject"
      ],
      "Resource": [
        "arn:aws:s3:::ecs-registry-demo/*"
      ]
    }
  ]
}

После того, как вы создали документ описания сервиса (и необходимую роль IAM), продолжайте и запустите сервис с вашим кластером. По умолчанию ECS создает кластер с именем «default», и вы можете опустить аргумент «cluster» в следующей команде. Но если вы создали свой собственный, вам нужно будет заменить  <YOUR CLUSTER NAME> на имя, которое вы выбрали.

aws ecs create-service --service-name s3-registry-elb --cluster <YOUR CLUSTER NAME> --cli-input-json file://ecs-simple-service-elb.json

Когда кластер настроен, проверьте принадлежность экземпляра вашего ELB и конфигурацию слушателя. Вы должны обнаружить, что порт 80 перенаправляется на порт 5000 на узле ECS, где была развернута служба. Когда это так, запустите веб-браузер и нажмите  http://<YOUR ELB CNAME>/v2/. Вы должны получить ответ вроде:

{}

Теперь это то, что я бы назвал антиклиматическим! Вы развернули небезопасный и не прошедший проверку подлинности реестр Docker. Лучшим тестом было бы подтолкнуть изображение и попробовать потянуть его снова. Если вы хотите сделать это, вам нужно внести  изменения в конфигурацию вашего локального демона Docker .

В заключении

Узлы Elastic Container Service и ECS обеспечивают простую интеграцию с существующей технологией масштабирования и балансировки нагрузки AWS. Его интеграция с Docker Hub упрощает начало работы. Основная сложность в работе с этим сервисом заключается в предоставлении кластера и соответствующей инфраструктуры. Имея это в виду, ECS делает определение и развертывание сервисов столь же простым, как несколько команд.

Вы можете самостоятельно расширить этот пример несколькими различными способами. Во-первых, защитите свой личный реестр Docker, загрузив SSL-сертификат в AWS, и настройте балансировщик нагрузки с помощью прослушивателя HTTPS. Во-вторых, рассмотрите возможность реализации механизма проверки подлинности реестра. Инструкции для этого можно найти в  документации по конфигурации Distribute . Наконец, попробуйте масштабировать службу до нескольких экземпляров и посмотрите, как служба поддерживает членство в экземпляре ELB.