30 мая 2024 Docker Hub заблокировал пользователей из России, что повлияло на многие сервисы и проекты. В том числе на наш. В статье будет несколько способов оперативно получить доступ к Docker Hub из России.

Через облако - Amvera Cloud

Мы сами были не готовы к блокировке, но ранее настроили проксирование на уровне сети до API OpenAI, который также блокирует российских пользователей. Это позволило нам применить разработанную технологию для проксирования трафика к Docker Hub.

Если у вас небольшой проект, такой как бот или сайт, использующий Docker — образ, его достаточно просто  разместить у нас, и всё должно работать. Сделать это не сложно, достаточно  загрузить через push в Git код и настроить один конфигурационный файл.

Как это работает у нас

Мы используем Kubernetes, в котором проекты пользователей работают как приложения в подах. Настраивая проксирование до OpenAI, мы реализовали технологию, когда один под управляет трафиком на уровне ноды. И если трафик идет на определенные ресурсы, система его автоматически проксирует через иностранный IP.

Соответственно, пользователям ничего дополнительно делать не нужно. Достаточно только развернуть проект в Amvera и все будет работать.

Но данный способ подойдет не всем, рассмотрим альтернативные варианты.

Использовать зеркала Docker Hub

  • Как вариант, можно попробовать использовать зеркало от Google - https://mirror.gcr.io

  • Или от Яндекса - cr.yandex/mirror

Если у вас Kubernetes, возможно, вам помогут следующие инструкции.

а)

$ cat /etc/docker/daemon.json

"registry-mirrors": ["https://daocloud.io", "https://c.163.com/", "https://registry.docker-cn.com"]

б)

Использовать Dependency proxy гитлаба.

Любой образ можно скачать через него, достаточно завести группу и сделать к ней API ключ с правами read_registry. Дальше выполнить

docker pull gitlab.com/<GROUP_NAME>/dependency_proxy/containers/alpine:latest

Через проксирование

Вы можете самостоятельно реализовать proxy, о котором было в пункте выше, для этого вам нужно использовать следующие IP

Non-authoritative answer:
Name:  registry-1.docker.io
Address: 54.227.20.253
Name:  registry-1.docker.io
Address: 54.198.86.24
Name:  registry-1.docker.io
Address: 54.236.113.205

Подробнее о том как это сделать мы напишем в отдельной статье в ближайшие дни.

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

Если в статье или приведённом коде допущены ошибки, прошу извинить, так как материал писался в режиме тушения пожара. В ближайшее время мы все проверим и обновим материал, дополнив его другими способами. Надеюсь, эта информация поможет преодолеть блокировку со стороны Docker Hub пользователям из России.

Комментарии (20)


  1. VadimMichaylov
    30.05.2024 12:14
    +1

    Для Kubernetes, еще как вариант, можно использовать Kyverno для настройки


    1. jenyabykov
      30.05.2024 12:14

      Привожу пример как это сделать: https://kyverno.io/policies/other/replace-image-registry/replace-image-registry/


  1. timur_kim
    30.05.2024 12:14
    +6

    macOS:
    ~/.docker/daemon.json

    Docker Desktop:

    Settings -> Docker Engine


  1. nick_mna
    30.05.2024 12:14

    Есть еще ряд зеркал: https://huecker.io, https://yandex.cr/mirror/...
    Но, остался еще один вопрос: как производить поиск образов, как это было на сайте hub.docker.com?


    1. Hertan
      30.05.2024 12:14

      https://gallery.ecr.aws/ довольно таки удобен и пока не закрыт


  1. StasPlov
    30.05.2024 12:14

    Для простоты сего мероприятия я сделал хаб

    https://github.com/StasPlov/docker-unlock


    1. Hertan
      30.05.2024 12:14

      Да вас наверное будет удивительно, но зачастую данный файлик не является пустым, > перезапишет файл полностью, разумней было бы добавить эти записи через jq


      1. StasPlov
        30.05.2024 12:14

        Данный файлик обновляется не перетирается.


        1. zorn-v100500
          30.05.2024 12:14

          current_mirrors=$(grep -oP '(?<="registry-mirrors": [)[^]]*' /etc/docker/daemon.json | tr -d ' \n' | tr ',' '\n' | tr -d '"')

          Фуфуфу. А если у меня вот так ?

          "registry-mirrors" [
          "https://mirror-1.tld",
          "https://mirror-2.tld"
          ]

          И таки скрипт все перетирает кроме registry-mirrors


  1. dispatcherenko
    30.05.2024 12:14

    опреативно


  1. Mlkw
    30.05.2024 12:14

    А push через зеркало допустим?


    1. kirillkosolapov Автор
      30.05.2024 12:14

      Это немного про другое. Через push накатываются обновления кода. Т.е. вы просто загрузили код проекта, и больше ничего делать не нужно. Если вы развертываете с использованием Dockerfile, система просто сама правильно сходит на Docker Hub и загрузит что нужно


      1. 100cpro
        30.05.2024 12:14

        Поясните, пожалуйста, почему другое? У меня сейчас пулится через зеркало прекрасно, но тот же частный закрытый репозиторий не пушится. Говорит 403 и всё тут. Подскажите, как починить, буду очень признателен


        1. time-space
          30.05.2024 12:14

          поддерживаю, пуш не работает с зеркалом, 403 lolhello we saw that you are from Mordor, fuck you and not the docker


  1. Kenya-West
    30.05.2024 12:14
    +2

    Плейбук для Ansible:

    Код
    ---
    - name: Install Docker
      hosts: all
      become: true
      vars_files:
        - '{{ inventory_dir }}/vars/vars.yaml'
      vars:
        docker_config_file: "/etc/docker/daemon.json"
        docker_features:
          containerd-snapshotter: true
        docker_mirrors_ru:
          - "https://dockerhub.timeweb.cloud"
          - "https://mirror.gcr.io"
          - "https://daocloud.io"
          - "https://c.163.com"
          - "https://registry.docker-cn.com"
        
      tasks:
        - name: Get the public IP of the host
          command: curl -s ifconfig.me
          register: public_ip
          changed_when: false
    
        - name: Query IPInfo for geolocation information
          uri:
            url: "https://ipinfo.io/{{ public_ip.stdout }}/json"
            method: GET
            return_content: yes
          register: ipinfo_response
    
        - name: Parse the country from IPInfo response
          set_fact:
            country: "{{ ipinfo_response.json.country }}"
    
        - name: Debug country information
          debug:
            msg: "The country for IP {{ public_ip.stdout }} is {{ country }}"
    
        - name: Ensure Docker configuration file exists
          file:
            path: "{{ docker_config_file }}"
            state: touch
            mode: '0644'
          when: country == 'RU'
    
        - name: Read existing Docker configuration
          slurp:
            path: "{{ docker_config_file }}"
          register: docker_config_file_content
          when: country == 'RU'
    
        - name: Parse existing Docker configuration
          set_fact:
            docker_config: "{{ docker_config_file_content.content | b64decode | from_json | default({}) }}"
          when: country == 'RU' and docker_config_file_content.content | b64decode | length > 0
    
        - name: Use default Docker configuration
          set_fact:
            docker_config: {}
          when: country == 'RU' and not (docker_config_file_content.content | b64decode | length > 0)
    
        - name: Set Docker Hub mirrors
          set_fact:
            docker_config: "{{ docker_config | combine({'registry-mirrors': docker_mirrors_ru}) }}"
          when: country == 'RU'
    
        - name: Set Docker features
          set_fact:
            docker_config: "{{ docker_config | combine({'features': docker_features}) }}"
          when: country == 'RU'
    
        - name: Write updated Docker configuration
          copy:
            content: "{{ docker_config | to_nice_json }}"
            dest: "{{ docker_config_file }}"
            mode: '0644'
            backup: yes
          when: country == 'RU'
    
        - name: Restart Docker
          service:
            name: docker
            state: restarted
          when: country == 'RU'
    

    Работает для установленного Docker в режиме пользователя


  1. Shtopick
    30.05.2024 12:14

    На WSL файл находится по пути C:/Users/<username>/.docker/daemon.json


  1. Qweritos
    30.05.2024 12:14
    +1

    Для containerd (в т.ч. если он используется как CRI для кубера):

    /etc/containerd/config.toml

    version = 2
    [plugins]
    [plugins."io.containerd.grpc.v1.cri"]
    [plugins."io.containerd.grpc.v1.cri".registry.mirrors]
    [plugins."io.containerd.grpc.v1.cri".registry.mirrors."docker.io"]
    endpoint = ["https://mirror.gcr.io"]


  1. overslepter
    30.05.2024 12:14

    При указании зеркал в js демон докера перестает стартовать. Возвращаю предыдущую версию тут же стартует.

    Пробовал и одно зеркало и как в статье - несколько. Результат всегда один - "exit-code" с комментарием что докер стартует слишком часто.


    1. 5exi
      30.05.2024 12:14

      { "registry-mirrors" : [ "https://mirror.gcr.io", "https://dockerhub.timeweb.cloud" ] }

      В статье представлена лишь часть конфига. А не готовое решение.


    1. RangerX
      30.05.2024 12:14

      У меня примерно так было, когда я яндексовское зеркало пытался подставить. Оно ругалось так: invalid mirror: path, query, or fragment at end of the URI "https://cr.yandex/mirror"

      Т.е., видимо, должен быть ТОЛЬКО домен, без всяких путей (как /mirror у яндекса) и параметров.

      ЗЫ. версия докера 24.0.5