Зачем это нужно всей команде?
На самом деле я использую локальное зеркало не только для виртуальной машины с GitLab Runner'ом, но и на всех других машинах в сети указываю это зеркало. Зачем каждый раз качать одни и те же образы, если можно иметь локальную копию?
Данная проблема хоть и не частая, но, возможно знакома каждому:
Pulling docker image python:3.12...
Elapsed time: 15 minutes 59 secondsКазалось бы, что сложного, скачать образ при деплое? Но по каким-то странным причинам это занимает столько времени. Можно конечно искать виноватых, кто старается запретить интернет своей цензурой, но проще решить проблему радикально.
Решение: Локальный кэш для всей команды или домашней студии!
Преимущества для всей команды
🚀 В 10-100 раз быстрее загрузка образов
📉 На 90% меньше интернет-трафика
🌐 Не зависит от доступности Docker Hub
👥 Все разработчики работают быстрее
💾 Повторное использование одних и тех же образовЧто такое Docker Registry Mirror?
Это локальный кэш-прокси для Docker образов. Первый раз образ качается из интернеты, а все последующие разы — из локального кэша, доступного всем в сети.
Настраиваем зеркало за 5 минут
1. Создаем структуру проекта
mkdir docker-registry-mirror
cd docker-registry-mirror
mkdir images config2. docker-compose.yml
version: '3.8'
services:
registry-mirror:
image: registry:2
container_name: docker-registry-mirror
restart: unless-stopped
env_file:
- .env
ports:
- "5000:5000"
environment:
- REGISTRY_PROXY_REMOTEURL=https://registry-1.docker.io
- REGISTRY_STORAGE_FILESYSTEM_MAXTHREADS=100
- REGISTRY_PROXY_USERNAME=${DOCKERHUB_USERNAME:-}
- REGISTRY_PROXY_PASSWORD=${DOCKERHUB_PASSWORD:-}
volumes:
- ./images:/var/lib/registry
- ./config/config.yml:/etc/docker/registry/config.yml
networks:
- registry-net
networks:
registry-net:
driver: bridge
volumes:
registry-data:
driver: local3. config/config.yml
version: 0.1
log:
fields:
service: registry
storage:
cache:
blobdescriptor: inmemory
filesystem:
rootdirectory: /var/lib/registry
http:
addr: :5000
headers:
X-Content-Type-Options: [nosniff]
health:
storagedriver:
enabled: true
interval: 10s
threshold: 3
proxy:
remoteurl: https://registry-1.docker.io
username: ${DOCKERHUB_USERNAME}
password: ${DOCKERHUB_PASSWORD}4. .env файл
# Получите токен на hub.docker.com → Account Settings → Security → Access Tokens
DOCKERHUB_USERNAME=your_docker_id
DOCKERHUB_PASSWORD=your_access_tokenГде взять Docker Hub токен? 🔑
- Зайдите на hub.docker.com
- Account Settings → Security → Access Tokens
- "New Access Token" с правами Read Only
- Используйте как пароль в .env файле
Запускаем зеркало
docker compose up -dНастраиваем GitLab Runner
/etc/docker/daemon.json на ВМ с runner:
{
"registry-mirrors": ["http://ip-зеркала:5000"],
"insecure-registries": ["ip-зеркала:5000"]
}Перезагружаем Docker:
sudo systemctl daemon-reload
sudo systemctl restart dockerНастройка других машин в сети
Для Windows/macOS (Docker Desktop):
Зайдите в Settings → Docker Engine и добавьте:
{
"registry-mirrors": ["http://ip-зеркала:5000"],
"insecure-registries": ["ip-зеркала:5000"]
}Для Linux-машин:
# /etc/docker/daemon.json
{
"registry-mirrors": ["http://ip-зеркала:5000"],
"insecure-registries": ["ip-зеркала:5000"]
}Предзагрузка популярных образов
На самом деле предзагрузку делать не обязательно, так как при первом запросе контейнеры скачаются и лягут на зеркале.
Создайте скрипт precache.sh:
#!/bin/bash
IMAGES=(
"python:3.12"
"python:3.12-slim"
"node:20"
"alpine:latest"
"ubuntu:20.04"
"nginx:latest"
"redis:alpine"
"postgres:13"
)
for image in "${IMAGES[@]}"; do
echo "Precaching $image..."
docker pull $image
echo "---"
doneВыдайте права на запуск и запустите:
chmod +x precache.sh
./precache.shКак это работает в команде?
[Разработчик 1] ←→ [Registry Mirror] ←→ [Internet]
[Разработчик 2] ←→ [Registry Mirror]
[GitLab Runner] ←→ [Registry Mirror]Первый разработчик качает образ → образ сохраняется в зеркале → остальные берут из кэша, включая Gitlab Runner.
Проверяем работу зеркала
# Смотрим что в кэше
curl http://localhost:5000/v2/_catalog
# Тестируем скорость
time docker pull python:3.12
# Статистика использования
docker logs docker-registry-mirror | grep "response completed"Результаты
До: 15+ минут на pull образа
После: 10-30 секунд!
time docker pull python:3.12
3.12: Pulling from library/python
Digest: sha256:9e5892d80651101df6f1fed0614fb8fcb43bb60ca48f1d6f9ef26e27db069d25
Status: Image is up to date for python:3.12
docker.io/library/python:3.12
docker pull python:3.12 0.02s user 0.02s system 2% cpu 1.570 totalМониторинг и обслуживание
# Логи mirror
docker compose logs -f
# Размер кэша
du -sh images/
# Очистка старых образов (осторожно!)
docker exec docker-registry-mirror registry garbage-collect /etc/docker/registry/config.ymlПроблемы и решения
Ошибка: "http: server gave HTTP response to HTTPS client"
Скорее всего вы не указали адрес для не защищённого подключения.
{
"insecure-registries": ["ip-зеркала:5000"]
}Зеркале не отвечает
docker compose restart
curl http://localhost:5000/v2/_catalogВыводы
Локальное зеркало — это:
✅ Ускорение сборок в 10-100 раз
✅ Снижение интернет-трафика
✅ Независимость от доступности Docker Hub
✅ Простота настройки и обслуживания
Время сборок больше не будет вас беспокоить! 🎉
Как можно отблагодарить:
- Оформить удобную для вас подписку на Boosty.to
- Разово поддержать через DonationAlerts
