Создание частного реестра Docker в Ubuntu 18.04

Реестр Docker — это приложение для хранения и доставки образов Docker. Реестры собирают образы в одном месте и сокращают время сборки. Образы Docker обеспечивают единую среду исполнения благодаря виртуализации, однако для создания образа может потребоваться много времени. Например, вместо того чтобы отдельно устанавливать зависимости пакетов, разработчики могут загрузить из реестра сжатый образ, содержащий всё необходимое. С помощью TravisCI или других инструментов непрерывной интеграции можно автоматизировать отправку образов в реестр: это позволяет мгновенно обновлять образы во время разработки и производства.

Docker Hub – это бесплатный публичный реестр, где можно хранить пользовательские образы Docker. Но в отдельных ситуациях образ должен оставаться закрытым для общего доступа. Образы, как правило, содержат весь код, необходимый для запуска приложения, поэтому для коммерческих программ нужно использовать частный реестр.

В этом мануале вы научитесь настраивать свой частный реестр Docker и защищать его. Вы узнаете, как с помощью Docker Compose определить конфигурации запуска приложений Docker, как использовать Nginx для перенаправления трафика HTTPS в работающий контейнер Docker. В итоге вы сможете размещать свои собственные образы Docker в частном реестре и безопасно извлекать их с удаленного сервера.

Требования

  • Два сервера Ubuntu 18.04, настроенные по этому мануалу (включая пользователя sudo и брандмауэр). На сервере 1 будет находиться частный реестр Docker, а сервер 2 будет выступать в качестве клиента.
  • На обоих серверах нужно установить Docker и Docker Compose. Инструкции вы найдете в мануале Установка Docker Compose в Ubuntu 18.04. Для установки Docker Compose достаточно выполнить первый раздел этого обучающего модуля.
  • На сервере 1 (который для частного реестра Docker) нужен веб-сервер Nginx. Читайте мануал Установка Nginx в Ubuntu 18.04.
  • Сертификат Let’s Encrypt. Обратитесь к мануалу Создание сертификата Let’s Encrypt для Nginx в Ubuntu 18.04. Убедитесь, что весь трафик протокола HTTP перенаправляется на HTTPS.
  • Домен для сервера 1.

1: Установка и настройка реестра Docker

Инструмент командной строки Docker справится с запуском и управлением одним или двумя контейнерами Docker, но для полноценного развертывания больших приложений внутри контейнеров Docker необходимо, чтобы разные компоненты работали параллельно. Например, многие приложения используют Nginx или другой веб-сервер для обслуживания кода приложения, а также PHP или другой язык скриптов и сервер СУБД типа MySQL.

Docker Compose позволяет записать один файл .yml для настройки каждого контейнера и записи всех данных, которые нужны контейнерам для взаимодействия друг с другом. После этого вы можете использовать инструмент командной строки docker-compose для управления всеми компонентами, которые входят в ваше приложение.

Сам по себе реестр Docker – это по сути приложение с несколькими компонентами, а потому мы будем использовать Docker Compose для управления его конфигурацией. Чтобы запустить экземпляр реестра, нужно указать в файле docker-compose.yml место, в котором реестр сможет хранить свои данные.

На сервере 1, который предназначен для частного реестра Docker, создайте каталог docker-registry, перейдите в него, а затем создайте подкаталог data. Используйте эти команды:

mkdir ~/docker-registry && cd $_
mkdir data

Откройте текстовый редактор и создайте конфигурационный файл docker-compose.yml:

nano docker-compose.yml

Поместите в файл следующие строки, которые определяют базовую конфигурацию реестра Docker:

version: '3'
services:
registry:
image: registry:2
ports:
- "5000:5000"
environment:
REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY: /data
volumes:
- ./data:/data

Блок environment определяет в контейнере реестра Docker переменную среды с путем /data. Приложение Docker Registry проверяет ее при запуске и будет сохранять свои данные в папку /data.

Но поскольку вы добавили строку volumes: — ./data:/data, Docker будет связывать каталог /data в этом контейнере с каталогом /data на сервере 1. В итоге все данные реестра Docker будут храниться локально, в каталоге ~/docker-registry/data на сервере 1.

Конфигурация 5000:5000 в разделе ports связывает порт 5000 на сервере 1 с портом 5000 запущенного контейнера. Это позволяет отправлять запросы на порт 5000 на сервер, и этот запрос перенаправится в приложение реестра.

Теперь можно запустить Docker Compose, чтобы протестировать настройки:

docker-compose up

В результатах вы увидите панели загрузки, которые сообщат, что Docker загружает образ реестра из собственного реестра Docker. Через пару минут вы увидите примерно следующий вывод (версии могут отличаться):

Starting docker-registry_registry_1 ... done
Attaching to docker-registry_registry_1
registry_1  | time="2018-11-06T18:43:09Z" level=warning msg="No HTTP secret provided - generated random secret. This may cause problems with uploads if multiple registries are behind a load-balancer. To provide a shared secret, fill in http.secret in the configuration file or set the REGISTRY_HTTP_SECRET environment variable." go.version=go1.7.6 instance.id=c63483ee-7ad5-4205-9e28-3e809c843d42 version=v2.6.2
registry_1  | time="2018-11-06T18:43:09Z" level=info msg="redis not configured" go.version=go1.7.6 instance.id=c63483ee-7ad5-4205-9e28-3e809c843d42 version=v2.6.2
registry_1  | time="2018-11-06T18:43:09Z" level=info msg="Starting upload purge in 20m0s" go.version=go1.7.6 instance.id=c63483ee-7ad5-4205-9e28-3e809c843d42 version=v2.6.2
registry_1  | time="2018-11-06T18:43:09Z" level=info msg="using inmemory blob descriptor cache" go.version=go1.7.6 instance.id=c63483ee-7ad5-4205-9e28-3e809c843d42 version=v2.6.2
registry_1  | time="2018-11-06T18:43:09Z" level=info msg="listening on [::]:5000" go.version=go1.7.6 instance.id=c63483ee-7ad5-4205-9e28-3e809c843d42 version=v2.6.2

Предупреждение «No HTTP secret provided» мы устраним чуть позже. Вывод показывает, что контейнер запускается. Последняя строка вывода показывает, что прослушивание порта 5000 успешно началось.

По умолчанию Docker Compose будет ждать ваших команд. Нажмите CTRL+C, чтобы закрыть контейнер реестра Docker.

Итак, вы настроили полноценный реестр Docker, который прослушивает порт 5000. Сейчас реестр запускается исключительно вручную. Кроме того, в реестре нет встроенных механизмов аутентификации, а это значит, что сейчас любой может получить к нему доступ. Пора решить эти проблемы безопасности.

2: Настройка форвардинга портов Nginx

Ранее мы настроили на сервере реестра Docker протокол HTTPS для Nginx, а теперь вы можете настроить форвардинг портов Nginx. Выполнив этот раздел, вы сможете получать доступ к своему реестру по адресу example.com.

Согласно требованиям к этому мануалу вы должны были создать и настроить файл /etc/nginx/sites-available/example.com и поместить в него конфигурации вашего сервера.

Откройте этот файл в текстовом редакторе:

sudo nano /etc/nginx/sites-available/example.com

Найдите строку location. Она выглядит примерно так:

...
location / {
...
}
...

Сейчас вам нужно перенаправить трафик на порт 5000, по которому будет работать ваш реестр. Также следует добавить в запрос заголовки, которые будут предоставлять дополнительную информацию о сервере. Удалите все содержимое раздела location и вставьте в него следующее:

/etc/nginx/sites-available/example.com
...
location / {
# Do not allow connections from docker 1.5 and earlier
# docker pre-1.6.0 did not properly set the user agent on ping, catch "Go *" user agents
if ($http_user_agent ~ "^(docker\/1\.(3|4|5(?!\.[0-9]-dev))|Go ).*$" ) {
return 404;
}
proxy_pass                          http://localhost:5000;
proxy_set_header  Host              $http_host;   # required for docker client's sake
proxy_set_header  X-Real-IP         $remote_addr; # pass on real client's IP
proxy_set_header  X-Forwarded-For   $proxy_add_x_forwarded_for;
proxy_set_header  X-Forwarded-Proto $scheme;
proxy_read_timeout                  900;
}
...

Раздел $http_user_agent убеждается, что версия клиента Docker выше 1.5 и что UserAgent не является приложением Go. Поскольку мы используем версию реестра 2.0, старые клиенты не будут поддерживаться. Дополнительную информацию о заголовках nginx можно найти в руководстве по Nginx в реестре Docker.

Сохраните и закройте файл. Перезапустите Nginx, чтобы активировать изменения:

sudo service nginx restart

Чтобы убедиться, что форвардинг трафика Nginx работает правильно, запустите реестр:

cd ~/docker-registry
docker-compose up

Откройте в браузере следующий url:

https://example.com/v2

Вы увидите пустой объект JSON или:

{}

В терминале появится такой вывод:

registry_1  | time="2018-11-07T17:57:42Z" level=info msg="response completed" go.version=go1.7.6 http.request.host=cornellappdev.com http.request.id=a8f5984e-15e3-4946-9c40-d71f8557652f http.request.method=GET http.request.remoteaddr=128.84.125.58 http.request.uri="/v2/" http.request.useragent="Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_2) AppleWebKit/604.4.7 (KHTML, like Gecko) Version/11.0.2 Safari/604.4.7" http.response.contenttype="application/json; charset=utf-8" http.response.duration=2.125995ms http.response.status=200 http.response.written=2 instance.id=3093e5ab-5715-42bc-808e-73f310848860 version=v2.6.2
registry_1  | 172.18.0.1 - - [07/Nov/2018:17:57:42 +0000] "GET /v2/ HTTP/1.0" 200 2 "" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_2) AppleWebKit/604.4.7 (KHTML, like Gecko) Version/11.0.2 Safari/604.4.7"

Как видно из последней строки, запрос GET был направлен по адресу /v2/, который представляет конечную точку для отправки запроса из браузера. Контейнер получил отправленный запрос путем форвардинга портов и возвратил {}. Код 200 в последней строке означает, что контейнер успешно обработал запрос.

Итак, вы успешно настроили форвардинг портов.

3: Настройка аутентификации

Теперь веб-сервер Nginx перенаправляет запросы на правильный порт, и вы можете защитить свой реестр Docker системой аутентификации HTTP, чтобы ограничить доступ к нему. Для этого нужно создать файл аутентификации с помощью htpasswd и внести в него пользователей. Аутентификация HTTP настраивается быстро и обеспечивает высокую безопасность, если использовать соединение HTTPS, как это делаем мы.

Для установки пакета htpasswd запустите следующую команду:

sudo apt install apache2-utils

Теперь нужно создать каталог, где будут храниться учетные данные для аутентификации, и перейдете в этот каталог. Опция $_ раскрывается в последний аргумент предыдущей команды (~/docker-registry/auth):

mkdir ~/docker-registry/auth && cd $_

Теперь давайте создадим первого пользователя. Вместо username укажите любое имя пользователя. Флаг -B включает шифрование bcrypt, более надежное, чем шифрование по умолчанию. Введите пароль в диалоговое окно:

htpasswd -Bc registry.password username

Примечание: Чтобы добавить в файл других пользователей, еще раз запустите предыдущую команду с опцией -c (что означает create):

htpasswd registry.password username

Теперь нужно отредактировать docker-compose.yml, чтобы настроить Docker для использования нового файла для аутентификации пользователей.

cd ~/docker-registry
nano docker-compose.yml

Вы также можете добавить переменные среды и том для каталога auth/, отредактировав файл docker-compose.yml, чтобы указать Docker нужный способ аутентификации. Добавьте в файл следующие строки:

version: '3'
services:
registry:
image: registry:2
ports:
- "5000:5000"
environment:
REGISTRY_AUTH: htpasswd

REGISTRY_AUTH_HTPASSWD_REALM: Registry


REGISTRY_AUTH_HTPASSWD_PATH: /auth/registry.password

REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY: /data
volumes:
- ./auth:/auth
- ./data:/data

В строке REGISTRY_AUTH вы указали htpasswd как схему аутентификации, а в REGISTRY_AUTH_HTPASSWD_PATH  задали путь к файлу аутентификации. Строка REGISTRY_AUTH_HTPASSWD_REALM означает имя области htpasswd.

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

docker-compose up

Откройте в браузере адрес https://example.com/v2.

Введите имя вашего пользователя и его пароль, и вы снова увидите {}. Только что вы проверили базовую настройку аутентификации. Реестр возвратил результат только после ввода правильной комбинации учетных данных.

4: Запуск реестра Docker как сервиса

Чтобы реестр запускался каждый раз вместе с системой, нужно добавить его в автозагрузку. Также в случае непредвиденного сбоя системы вам нужно сделать так, чтобы реестр перезапускался при перезагрузке сервера. Откройте файл docker-compose.yml:

nano docker-compose.yml

Добавьте следующую строку в раздел registry::

...
registry:
restart: always
...

Теперь вы можете запустить реестр как фоновый процесс, благодаря чему можно выходить из сессии ssh с сохранением работы процесса:

docker-compose up -d

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

5: Увеличение размера загружаемых файлов в Nginx

Прежде чем отправить образ в реестр, нужно убедиться, что реестр может принять объемные файлы. Docker разделяет большие образы на несколько слоев, их размер иногда превышает 1 ГБ. По умолчанию у Nginx есть лимит выгрузки файлов – 1 МБ. Нам нужно отредактировать конфигурационный файл nginx и увеличить максимальный размер загружаемого файла до 2 ГБ.

sudo nano /etc/nginx/nginx.conf

Найдите раздел http и добавьте в него следующую строку:

...
http {
client_max_body_size 2000M;
...
}
...

Перезапустите Nginx, чтобы активировать изменения:

sudo service nginx restart

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

6: Загрузка файлов в  частный реестр Docker

Теперь можно загрузить образ в частный реестр Docker, но для этого нужно создать тестовый образ. В данном мануале мы создадим простой образ на основе образа ubuntu из Docker Hub. Docker Hub — это публичный реестр с огромным количеством готовых образов, которые можно использовать для быстрой контейнеризации приложений. С помощью нашего тестового образа ubuntu мы проверим загрузку образов в реестр и их извлечение.

Создайте на своем клиентском сервере (сервере 2) небольшой пустой образ для отправки в закрытый реестр. Флаги -i и -t предоставляют доступ к контейнеру через интерактивную оболочку:

docker run -t -i ubuntu /bin/bash

После завершения загрузки появится диалоговое окно Docker. Обратите внимание, ваш идентификатор контейнера после root@ может отличаться. Создайте файл по имени SUCCESS. Далее мы будем использовать данный файл, чтобы определить, успешно ли загрузился образ:

touch /SUCCESS

Выйдите из контейнера Docker:

exit

Следующая команда создает новый образ по имени test-image на основе запущенного образа и внесенных в него изменений. В этом случае в новый образ добавится файл /SUCCESS .

Сохраните изменение:

docker commit $(docker ps -lq) test-image

Сейчас образ есть только на локальном компьютере. Вы можете отправить его в ваш частный реестр. Войдите в свой реестр Docker:

docker login https://example.com

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

docker tag test-image example.com/test-image

Отправьте образ с тегом в реестр:

docker push example.com/test-image

Вывод будет выглядеть примерно так:

The push refers to a repository [example.com/test-image]
e3fbbfb44187: Pushed
5f70bf18a086: Pushed
a3b5c80a4eba: Pushed
7f18b442972b: Pushed
3ce512daaf78: Pushed
7aae4540b42d: Pushed
...

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

7: Извлечение образов из частного реестра Docker

Вернитесь на сервер 1, чтобы проверить процедуру извлечения образа с клиентского сервера 2. Также для тестирования можно использовать третий сервер.

Войдите в систему, указав учетные данные, которые вы выбрали ранее:

docker login https://example.com

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

docker pull example.com/test-image

Docker загрузит образ и вернется в командную строку. Если запустить образ на сервере 1, вы увидите, что в нем есть ранее созданный файл SUCCESS :

docker run -it example.com/test-image /bin/bash

Выведите список файлов в bash:

ls

Вы увидите тот файл SUCCESS, который вы создали:

SUCCESS  bin  boot  dev  etc  home  lib  lib64  media   mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var

Теперь у вас есть частный реестр с поддержкой аутентификации, в котором вы можете хранить свои образы.

Tags: , , ,