{"id":22929262,"url":"https://github.com/kaymekaydex/minio-lecture","last_synced_at":"2025-04-01T16:29:04.454Z","repository":{"id":115703639,"uuid":"552304515","full_name":"KaymeKaydex/minio-lecture","owner":"KaymeKaydex","description":null,"archived":false,"fork":false,"pushed_at":"2024-02-12T18:37:45.000Z","size":2357,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-02-07T10:33:38.901Z","etag":null,"topics":["bmstu","bmstu-iu5","minio","s3"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/KaymeKaydex.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-10-16T09:31:32.000Z","updated_at":"2024-11-15T07:33:22.000Z","dependencies_parsed_at":null,"dependency_job_id":"0cc4f211-48a8-487b-8758-4fe8404baa77","html_url":"https://github.com/KaymeKaydex/minio-lecture","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/KaymeKaydex%2Fminio-lecture","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/KaymeKaydex%2Fminio-lecture/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/KaymeKaydex%2Fminio-lecture/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/KaymeKaydex%2Fminio-lecture/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/KaymeKaydex","download_url":"https://codeload.github.com/KaymeKaydex/minio-lecture/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246668908,"owners_count":20814744,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["bmstu","bmstu-iu5","minio","s3"],"created_at":"2024-12-14T09:33:12.546Z","updated_at":"2025-04-01T16:29:04.430Z","avatar_url":"https://github.com/KaymeKaydex.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Методические указания по выполнению дз ст [S3 хранилище]\nВ данном домашнем задании мы познакомимся с хранилищем S3,\nобсудим зачем оно нужно, как работает и как правильно его настрить и использовать.\nНеобходимо настроить файловое хранилище S3 \nи разработать методы доступа к нему. Хранилище необходимо для синхронизации двух узлов (условные клиент и сервер облака). Должна быть предусмотрена синхронизация, если одна из версий устарела (на клиенте не было интернета)\n\n## Этап №1\n### План:\n1. Установить docker\n2. Что такое S3. Почему не сохранять все просто на диск?\n3. Разобрать конфигурацию кластера s3 в docker-compose и установить.\n4. Разобраться во внутренней конфигурации панели администратора minio\n5. Бакеты. Создать свой первый бакет, загрузить файл и сгенерировать ссылку на файл в хранилище.\n\n### 1. Установка docker\nПолезные материалы:\n- Про docker: https://habr.com/ru/post/310460/?ysclid=l7ilstl2mt144186154\n- Официальная документация docker: https://docs.docker.com/get-started/overview/\n\nДля начала введем для себя 3 определения:\n* Docker - Программное обеспечение для автоматизации развёртывания и управления приложениями в средах с поддержкой контейнеризации, контейнеризатор приложений. Позволяет «упаковать» приложение со всем его окружением и зависимостями в контейнер.\n  Говоря простым языком - это программа, позволяющая упаковывать ваши приложения так, чтобы вы не замечали разницу между языками,\n  легко обменивались программным обеспечением.\n* Docker контейнер - сущности,\n  которые предоставляют схожий с виртуальными машинами уровень изоляции,\n  но благодаря правильному задействованию низкоуровневых механизмов основной операционной системы делают это с в разы меньшей нагрузкой.\n* Docker image - \"образ\" какого-то контейнера, контейнер который один разработчик передает другому в формате image`a\n\n\nПриступим непосредственно к установке:\nОдин из самых важных навыков программиста - способность читать и понимать то, что вы должны сделать,\nпотому постараюсь обойти подробную информацию о том как нажать на кнопочку скачать и как переводить тест на сайте.\n\n[Windows](https://docs.docker.com/desktop/install/windows-install/)\n[Linux](https://docs.docker.com/desktop/install/linux-install/)\n[MacOS](https://docs.docker.com/desktop/install/mac-install/)\n\nПроверим его работоспособность:\n\nОткройте консоль. Введите команду\n```shell\n$ docker version\nClient:\n Cloud integration: v1.0.22\n Version:           20.10.12\n API version:       1.41\n Go version:        go1.16.12\n Git commit:        e91ed57\n Built:             Mon Dec 13 11:46:56 2021\n OS/Arch:           darwin/arm64\n Context:           default\n Experimental:      true\n\nServer: Docker Desktop 4.5.0 (74594)\n Engine:\n  Version:          20.10.12\n  API version:      1.41 (minimum version 1.12)\n  Go version:       go1.16.12\n  Git commit:       459d0df\n  Built:            Mon Dec 13 11:43:07 2021\n  OS/Arch:          linux/arm64\n  Experimental:     false\n containerd:\n  Version:          1.4.12\n  GitCommit:        7b11cfaabd73bb80907dd23182b9347b4245eb5d\n runc:\n  Version:          1.0.2\n  GitCommit:        v1.0.2-0-g52b36a2\n docker-init:\n  Version:          0.19.0\n  GitCommit:        de40ad0\n```\nЕсли вдруг по какой-то причине вы видите ошибку, например:\n```shell\nCannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?\n```\nЗначит что-то пошло не так, если вы не найдете свою проблему в FAQ, постарайтесь сначала поискать ее в интернете.\n\nВместе с программой докер, к вам должен был установиться docker compose. Проверим его установку:\n```shell\n$ docker compose version\nDocker Compose version v2.2.3\n# или, возможно, у вас сработает эта команда\n# проблема различия возникает из-за версии приложения и ОС\n$ docker-compose version\ndocker-compose version 1.29.2, build 5becea4c\ndocker-py version: 5.0.0\nCPython version: 3.9.0\nOpenSSL version: OpenSSL 1.1.1h  22 Sep 2020\n```\n\n### 2. Что такое S3. Почему не сохранять все просто на диск?\nS3 - облачный сервис для надежного хранения любых типов данных, резервного копирования и архивирования.\n\nДля каких задач подходит «Объектное хранилище S3»?\n* Хранение файлов, необходимых для работы сайтов и мобильных приложений.\n* Создание архивов больших объемов данных.\n* Хранение статического контента и мультимедийных файлов.\n* Хранение пользовательских данных и резервных копий.\n* Раздача статических файлов.\n* Хранение данных backend-платформ.\n* Интеграция с системами электронного документооборота.\n* Хранение лог-файлов.\n\nПочему просто не сохранять файлы на диск? \n\nОтвет достаточно прост: \n\n* отсутсвие простого горизонтального масштабирования(вы конечно можете использовать протоколы по типу sftp и отправлять файлы на разные машины, но это определенно требует новых доработок со стороны кода)\n* отсуствие встроенной репликации данных(придется решать эту проблему своими силами)\n* сложная и проблематичная интеграция\n* надженость хранения(что произойдет если 1 диск на котором вы хранили файлы сломается?)\n\nАрхитектура minio же изначально поразумевает автоматическую реплизацию(они повторяются елси один из серверов сломался, ответит второй. все конечно зависит от фактора репликации - количество копий, которые вы будете хранить) ваших данных.\n![Создание проекта](docs/4.png)\n![Создание проекта](docs/2.png)\n\n### 3. Разобрать конфигурацию кластера s3 в docker-compose и установить.\nДавайте составим архитектуру проекта, который будем конфигурировать для 1 этапа:\n![Создание проекта](docs/1.png)\nРазберем его по частям: \n1. Необходимо сконфигурировать кластер minio. \n2. Нам подребуется веб сервер nginx, который будет работать в режиме балансировщика кластера. Он будет переадресовывать ваши запросы внутрь кластера minio \n3. Пользователь будет заходить в nginx. Nginx будет проксировать запрос внутрь одной из нод minio.\n\nВ корне данного проекта вы можете найти cледующие файлы:\n ```docker-compose.yaml```, ```nginx.conf```\n\nРазберем конфигурацию nginx:\n```nginx\n# определяет учетные данные пользователя и группы, используемые рабочими процессами. Если группа опущена, используется группа, имя которой = имени пользователя.\nuser  nginx; \n# Определяет количество рабочих процессов.\n# Оптимальное значение зависит от многих факторов, включая (но не ограничиваясь ими) количество ядер процессора, количество жестких дисков, на которых хранятся данные, и структуру загрузки.\n# Если кто-то сомневается в выбранном значении, хорошим началом было бы установить его на количество доступных ядер процессора (значение “auto” попытается автоматически определить его).\nworker_processes  auto;\n\n# то куда будут записываться ваши log файлы. сейчас мы сохраняем ошибки warn уровня\nerror_log  /var/log/nginx/error.log warn; \n# путь до pid файла\npid        /var/run/nginx.pid;\n\n# Задает максимальное количество одновременных подключений, которые могут быть открыты процессом.\nevents {\n    worker_connections  4096;\n}\n\nhttp {\n    include       /etc/nginx/mime.types;\n    default_type  application/octet-stream;\n\n    log_format  main  '$remote_addr - $remote_user [$time_local] \"$request\" '\n                      '$status $body_bytes_sent \"$http_referer\" '\n                      '\"$http_user_agent\" \"$http_x_forwarded_for\"';\n\n    access_log  /var/log/nginx/access.log  main;\n    sendfile        on;\n    keepalive_timeout  65;\n\n    # include /etc/nginx/conf.d/*.conf;\n\n    # устанавливаем адреса s3 api в кластере\n    upstream minio {\n        server minio1:9000;\n        server minio2:9000;\n        server minio3:9000;\n        server minio4:9000;\n    }\n\n    # устанавливаем адреса консолей в кластере\n    upstream console {\n        ip_hash;\n        server minio1:9001;\n        server minio2:9001;\n        server minio3:9001;\n        server minio4:9001;\n    }\n\n    server {\n        # слушаем 9000 порт\n        listen       9000;\n        listen  [::]:9000;\n        server_name  localhost;\n\n        # To allow special characters in headers\n        ignore_invalid_headers off;\n        # Allow any size file to be uploaded.\n        # Set to a value such as 1000m; to restrict file size to a specific value\n        client_max_body_size 0;\n        # To disable buffering\n        proxy_buffering off;\n        proxy_request_buffering off;\n\n        location / {\n            proxy_set_header Host $http_host;\n            proxy_set_header X-Real-IP $remote_addr;\n            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n            proxy_set_header X-Forwarded-Proto $scheme;\n\n            proxy_connect_timeout 300;\n            # Default is HTTP/1, keepalive is only enabled in HTTP/1.1\n            proxy_http_version 1.1;\n            proxy_set_header Connection \"\";\n            chunked_transfer_encoding off;\n\n            # переадресовывапем на upstream(несколько адресов) кластера.\n            # nginx сам выполнит балансировку.\n            proxy_pass http://minio;\n        }\n    }\n\n    server {\n        # слушаем порт 9001\n        listen       9001;\n        listen  [::]:9001;\n        server_name  localhost;\n\n        # To allow special characters in headers\n        ignore_invalid_headers off;\n        # Allow any size file to be uploaded.\n        # Set to a value such as 1000m; to restrict file size to a specific value\n        client_max_body_size 0;\n        # To disable buffering\n        proxy_buffering off;\n        proxy_request_buffering off;\n\n        location / {\n            proxy_set_header Host $http_host;\n            proxy_set_header X-Real-IP $remote_addr;\n            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n            proxy_set_header X-Forwarded-Proto $scheme;\n            proxy_set_header X-NginX-Proxy true;\n\n            # This is necessary to pass the correct IP to be hashed\n            real_ip_header X-Real-IP;\n\n            proxy_connect_timeout 300;\n\n            # To support websocket\n            proxy_http_version 1.1;\n            proxy_set_header Upgrade $http_upgrade;\n            proxy_set_header Connection \"upgrade\";\n\n            chunked_transfer_encoding off;\n            # переадресовываем в один из адресов upstream console\n            proxy_pass http://console;\n        }\n    }\n}\n```\nРазберем конфигурацию docker-compose:\n```yaml\n# устанавливаем версию в соотвествии с необходимой нам\n# подробнее на https://docs.docker.com/compose/compose-file/compose-versioning/\nversion: '3.7'\n\n# настройки и конфигурации, общие для всех контейнеров\nx-minio-common: \u0026minio-common\n  image: quay.io/minio/minio:RELEASE.2022-10-15T19-57-03Z # устанавливаем image\n  # команда которая выполняется при запуске контейнера\n  # --console-address \":9001\" - указываем запустить консоль администратора на порту 9001\n  #  http://minio{1...4}/data{1...2}  - указывает ноде адреса других нод,\n  # чтобы они могли связаться между собой\n  # если сломается одна из нод,\n  # остальные ноды это поймут и будут предпринимать действия чтобы сохранить файлы\n  command: server --console-address \":9001\" http://minio{1...4}/data{1...2} \n  environment: # env конфигурация, подробнее: https://github.com/KaymeKaydex/web-2022/tree/go-lab2/tutorials/lab2/golang#поговорим-про-переменные-окружения\n    MINIO_ACCESS_KEY: minio # пароль админа\n    MINIO_SECRET_KEY: minio124 # логин админа\n  expose:\n    - \"9000\" # открыть порты\n    - \"9001\"\n    # environment:\n    # MINIO_ROOT_USER: minioadmin\n    # MINIO_ROOT_PASSWORD: minioadmin\n  healthcheck: # проверка состояния работоспособности кластера происходит путем выполнения get запроса на http://localhost:9000/minio/health/live\n    test: [\"CMD\", \"curl\", \"-f\", \"http://localhost:9000/minio/health/live\"]\n    interval: 30s\n    timeout: 20s\n    retries: 3\n\n# запускает 4 контейнера docker, в которых запущены экземпляры сервера minio.\n# используя обратный прокси-сервер nginx, балансировку нагрузки, вы можете получить доступ\n# через порт 9000.\nservices:\n  minio1:\n    \u003c\u003c: *minio-common\n    hostname: minio1 # указываем что адрес внутри подсети docker будет http://minio1:9000/ и на порту 9001 для админки соотвественно\n    volumes: # куда физически переадресовать* память(в какие разделы) из виртуальной(в докере) на вашу машину. по сути это работает как хард линк на файл/папку\n      - data1-1:/data1\n      - data1-2:/data2\n\n  minio2: # аналогично ставим 2-4 ноды\n    \u003c\u003c: *minio-common\n    hostname: minio2\n    volumes:\n      - data2-1:/data1\n      - data2-2:/data2\n\n  minio3:\n    \u003c\u003c: *minio-common\n    hostname: minio3\n    volumes:\n      - data3-1:/data1\n      - data3-2:/data2\n\n  minio4:\n    \u003c\u003c: *minio-common\n    hostname: minio4\n    volumes:\n      - data4-1:/data1\n      - data4-2:/data2\n\n  nginx: # наш еще один сервис в подсети docker будет nginx \n    image: nginx:1.19.2-alpine # исходники сервиса взять отсюда\n    hostname: nginx # hostname внутри подсети docker будет nginx\n    volumes:\n      # куда физически переадресовать* память(в какие разделы) из виртуальной(в докере) на вашу машину. по сути это работает как хард линк на файл/папку. \n      # доступ даем на ro (read only)\n      - ./nginx.conf:/etc/nginx/nginx.conf:ro \n    ports:\n      - \"9000:9000\" # форвардим порт 9000 из нашей локальной сети(localhost) (forward port) на исхоодный(внутри подсети docker)(source port)\n      - \"9001:9001\" # левый порт - порт вашей локальной сети компьютера, таргетный. порт справа - соурс порт - порт внутри подсети докера. \n    depends_on: # не запускай nginx пока не запустится весь кластер minio\n      - minio1\n      - minio2\n      - minio3\n      - minio4\n\n## По умолчанию в этой конфигурации используется локальный драйвер docker по умолчанию,\n## Для пользовательских томов замените на конфигурацию драйвера тома.\nvolumes:\n  data1-1:\n  data1-2:\n  data2-1:\n  data2-2:\n  data3-1:\n  data3-2:\n  data4-1:\n  data4-2:\n```\nРазберитесь с каждой строчкой которая была употреблена, чтобы для вас это не казалось магией.\nНаша конфигурация кластера готова.\nПопробуем запустить!\n\n(не вводите символ # или $ в командах. Это просто строка приглашения.\n$ означает что вы работаете под обычным пользователем, а # - под рутом. Это и есть его основное назначение, никаких дополнительных функций в этом символе нет.)\n\nЗайдите в папку этого репозитория и проверьте что все файлы, которые мы обсудили в наличии:\n```shell\n$ ls -la\ntotal 80\ndrwxr-xr-x  12 maxim-konovalov  staff    384 Oct 16 16:07 .\ndrwxr-xr-x  10 maxim-konovalov  staff    320 Oct 16 14:46 ..\ndrwxr-xr-x  13 maxim-konovalov  staff    416 Oct 16 15:30 .git\n-rw-r--r--   1 maxim-konovalov  staff    274 Oct 16 14:48 .gitignore\ndrwxr-xr-x   7 maxim-konovalov  staff    224 Oct 16 15:33 .idea\n-rw-r--r--   1 maxim-konovalov  staff   1072 Oct 16 14:46 LICENSE\n-rw-r--r--   1 maxim-konovalov  staff  20142 Oct 16 16:07 README.md\ndrwxr-xr-x   3 maxim-konovalov  staff     96 Oct 16 14:48 cmd\n-rw-r--r--   1 maxim-konovalov  staff   1654 Oct 16 13:25 docker-compose.yml\ndrwxr-xr-x   6 maxim-konovalov  staff    192 Oct 16 15:27 docs\n-rw-r--r--   1 maxim-konovalov  staff     22 Oct  9 21:19 go.mod\n-rw-r--r--   1 maxim-konovalov  staff   3046 Oct 16 13:15 nginx.conf\n```\nЗапустим с помощью docker compose нашу документацию\n```shell\n$ docker compose up # укажите еще флаг -d чтобы все запустилось в режиме демона\n[+] Running 6/5\n ⠿ Network minio-lecture_default     Created                                                                                                                           0.0s\n ⠿ Container minio-lecture-minio2-1  Created                                                                                                                           0.1s\n ⠿ Container minio-lecture-minio4-1  Created                                                                                                                           0.1s\n ⠿ Container minio-lecture-minio3-1  Created                                                                                                                           0.1s\n ⠿ Container minio-lecture-minio1-1  Created                                                                                                                           0.1s\n ⠿ Container minio-lecture-nginx-1   Created                                                                                                                           0.0s\nAttaching to minio-lecture-minio1-1, minio-lecture-minio2-1, minio-lecture-minio3-1, minio-lecture-minio4-1, minio-lecture-nginx-1\nminio-lecture-minio2-1  | WARNING: MINIO_ACCESS_KEY and MINIO_SECRET_KEY are deprecated.\nminio-lecture-minio2-1  |          Please use MINIO_ROOT_USER and MINIO_ROOT_PASSWORD\nminio-lecture-minio2-1  | \nminio-lecture-minio2-1  | API: SYSTEM()\nminio-lecture-minio2-1  | Time: 13:09:14 UTC 10/16/2022\nminio-lecture-minio2-1  | Error: Marking minio4:9000 offline temporarily; caused by Post \"http://minio4:9000/minio/storage/data1/v49/readall?disk-id=\u0026file-path=format.json\u0026volume=.minio.sys\": dial tcp 192.168.176.5:9000: connect: connection refused (*fmt.wrapError)\nminio-lecture-minio2-1  |        9: internal/logger/logger.go:259:logger.LogIf()\nminio-lecture-minio2-1  |        8: internal/logger/logonce.go:104:logger.(*logOnceType).logOnceIf()\nminio-lecture-minio2-1  |        7: internal/logger/logonce.go:135:logger.LogOnceIf()\nminio-lecture-minio2-1  |        6: internal/rest/client.go:253:rest.(*Client).Call()\nminio-lecture-minio2-1  |        5: cmd/storage-rest-client.go:151:cmd.(*storageRESTClient).call()\nminio-lecture-minio2-1  |        4: cmd/storage-rest-client.go:538:cmd.(*storageRESTClient).ReadAll()\nminio-lecture-minio2-1  |        3: cmd/format-erasure.go:396:cmd.loadFormatErasure()\nminio-lecture-minio2-1  |        2: cmd/format-erasure.go:332:cmd.loadFormatErasureAll.func1()\nminio-lecture-minio2-1  |        1: internal/sync/errgroup/errgroup.go:123:errgroup.(*Group).Go.func1()\nminio-lecture-minio2-1  | \nminio-lecture-minio2-1  | API: SYSTEM()\nminio-lecture-minio2-1  | Time: 13:09:14 UTC 10/16/2022\nminio-lecture-minio2-1  | Error: Marking minio1:9000 offline temporarily; caused by Post \"http://minio1:9000/minio/storage/data1/v49/readall?disk-id=\u0026file-path=format.json\u0026volume=.minio.sys\": dial tcp 192.168.176.3:9000: connect: connection refused (*fmt.wrapError)\nminio-lecture-minio2-1  |        9: internal/logger/logger.go:259:logger.LogIf()\nminio-lecture-minio2-1  |        8: internal/logger/logonce.go:104:logger.(*logOnceType).logOnceIf()\nminio-lecture-minio2-1  |        7: internal/logger/logonce.go:135:logger.LogOnceIf()\nminio-lecture-minio2-1  |        6: internal/rest/client.go:253:rest.(*Client).Call()\nminio-lecture-minio2-1  |        5: cmd/storage-rest-client.go:151:cmd.(*storageRESTClient).call()\nminio-lecture-minio2-1  |        4: cmd/storage-rest-client.go:538:cmd.(*storageRESTClient).ReadAll()\nminio-lecture-minio2-1  |        3: cmd/format-erasure.go:396:cmd.loadFormatErasure()\nminio-lecture-minio2-1  |        2: cmd/format-erasure.go:332:cmd.loadFormatErasureAll.func1()\nminio-lecture-minio2-1  |        1: internal/sync/errgroup/errgroup.go:123:errgroup.(*Group).Go.func1()\nminio-lecture-minio2-1  | \nminio-lecture-minio2-1  | API: SYSTEM()\nminio-lecture-minio2-1  | Time: 13:09:14 UTC 10/16/2022\nminio-lecture-minio2-1  | Error: Marking minio3:9000 offline temporarily; caused by Post \"http://minio3:9000/minio/storage/data2/v49/readall?disk-id=\u0026file-path=format.json\u0026volume=.minio.sys\": dial tcp 192.168.176.4:9000: connect: connection refused (*fmt.wrapError)\nminio-lecture-minio2-1  |        9: internal/logger/logger.go:259:logger.LogIf()\nminio-lecture-minio2-1  |        8: internal/logger/logonce.go:104:logger.(*logOnceType).logOnceIf()\nminio-lecture-minio2-1  |        7: internal/logger/logonce.go:135:logger.LogOnceIf()\nminio-lecture-minio2-1  |        6: internal/rest/client.go:253:rest.(*Client).Call()\nminio-lecture-minio2-1  |        5: cmd/storage-rest-client.go:151:cmd.(*storageRESTClient).call()\nminio-lecture-minio2-1  |        4: cmd/storage-rest-client.go:538:cmd.(*storageRESTClient).ReadAll()\nminio-lecture-minio2-1  |        3: cmd/format-erasure.go:396:cmd.loadFormatErasure()\nminio-lecture-minio2-1  |        2: cmd/format-erasure.go:332:cmd.loadFormatErasureAll.func1()\nminio-lecture-minio2-1  |        1: internal/sync/errgroup/errgroup.go:123:errgroup.(*Group).Go.func1()\nminio-lecture-minio2-1  | \nminio-lecture-minio2-1  | API: SYSTEM()\nminio-lecture-minio2-1  | Time: 13:09:14 UTC 10/16/2022\nminio-lecture-minio2-1  | Error: Read failed. Insufficient number of drives online (*errors.errorString)\nminio-lecture-minio2-1  |        6: internal/logger/logger.go:259:logger.LogIf()\nminio-lecture-minio2-1  |        5: cmd/prepare-storage.go:242:cmd.connectLoadInitFormats()\nminio-lecture-minio2-1  |        4: cmd/prepare-storage.go:282:cmd.waitForFormatErasure()\nminio-lecture-minio2-1  |        3: cmd/erasure-server-pool.go:109:cmd.newErasureServerPools()\nminio-lecture-minio2-1  |        2: cmd/server-main.go:708:cmd.newObjectLayer()\nminio-lecture-minio2-1  |        1: cmd/server-main.go:533:cmd.serverMain()\nminio-lecture-minio1-1  | WARNING: MINIO_ACCESS_KEY and MINIO_SECRET_KEY are deprecated.\nminio-lecture-minio1-1  |          Please use MINIO_ROOT_USER and MINIO_ROOT_PASSWORD\nminio-lecture-minio3-1  | WARNING: MINIO_ACCESS_KEY and MINIO_SECRET_KEY are deprecated.\nminio-lecture-minio3-1  |          Please use MINIO_ROOT_USER and MINIO_ROOT_PASSWORD\nminio-lecture-minio4-1  | WARNING: MINIO_ACCESS_KEY and MINIO_SECRET_KEY are deprecated.\nminio-lecture-minio4-1  |          Please use MINIO_ROOT_USER and MINIO_ROOT_PASSWORD\nminio-lecture-minio2-1  | \nminio-lecture-minio2-1  | API: SYSTEM()\nminio-lecture-minio2-1  | Time: 13:09:14 UTC 10/16/2022\nminio-lecture-minio2-1  | Error: Read failed. Insufficient number of drives online (*errors.errorString)\nminio-lecture-minio2-1  |        6: internal/logger/logger.go:259:logger.LogIf()\nminio-lecture-minio2-1  |        5: cmd/prepare-storage.go:242:cmd.connectLoadInitFormats()\nminio-lecture-minio2-1  |        4: cmd/prepare-storage.go:302:cmd.waitForFormatErasure()\nminio-lecture-minio2-1  |        3: cmd/erasure-server-pool.go:109:cmd.newErasureServerPools()\nminio-lecture-minio2-1  |        2: cmd/server-main.go:708:cmd.newObjectLayer()\nminio-lecture-minio2-1  |        1: cmd/server-main.go:533:cmd.serverMain()\nminio-lecture-minio2-1  | Waiting for a minimum of 4 drives to come online (elapsed 0s)\nminio-lecture-minio2-1  | \nminio-lecture-minio2-1  | Client 'http://minio1:9000/minio/storage/data2/v49' re-connected in 188.502ms\nminio-lecture-minio4-1  | \nminio-lecture-minio4-1  | API: SYSTEM()\nminio-lecture-minio4-1  | Time: 13:09:14 UTC 10/16/2022\nminio-lecture-minio4-1  | Error: Marking minio3:9000 offline temporarily; caused by Post \"http://minio3:9000/minio/storage/data1/v49/readall?disk-id=\u0026file-path=format.json\u0026volume=.minio.sys\": dial tcp 192.168.176.4:9000: connect: connection refused (*fmt.wrapError)\nminio-lecture-minio4-1  |        9: internal/logger/logger.go:259:logger.LogIf()\nminio-lecture-minio4-1  |        8: internal/logger/logonce.go:104:logger.(*logOnceType).logOnceIf()\nminio-lecture-minio4-1  |        7: internal/logger/logonce.go:135:logger.LogOnceIf()\nminio-lecture-minio4-1  |        6: internal/rest/client.go:253:rest.(*Client).Call()\nminio-lecture-minio4-1  |        5: cmd/storage-rest-client.go:151:cmd.(*storageRESTClient).call()\nminio-lecture-minio4-1  |        4: cmd/storage-rest-client.go:538:cmd.(*storageRESTClient).ReadAll()\nminio-lecture-minio4-1  |        3: cmd/format-erasure.go:396:cmd.loadFormatErasure()\nminio-lecture-minio4-1  |        2: cmd/format-erasure.go:332:cmd.loadFormatErasureAll.func1()\nminio-lecture-minio4-1  |        1: internal/sync/errgroup/errgroup.go:123:errgroup.(*Group).Go.func1()\nminio-lecture-minio2-1  | Client 'http://minio4:9000/minio/storage/data1/v49' re-connected in 207.869833ms\nminio-lecture-minio2-1  | Client 'http://minio4:9000/minio/storage/data2/v49' re-connected in 208.1285ms\nminio-lecture-minio4-1  | Waiting for all MinIO sub-systems to be initialized.. lock acquired\nminio-lecture-minio2-1  | Client 'http://minio4:9000/minio/storage/data1/v49' re-connected in 86.2515ms\nminio-lecture-minio4-1  | Client 'http://minio3:9000/minio/storage/data2/v49' re-connected in 60.504583ms\nminio-lecture-minio2-1  | Client 'http://minio3:9000/minio/storage/data1/v49' re-connected in 117.823375ms\nminio-lecture-minio4-1  | Automatically configured API requests per node based on available memory on the system: 37\nminio-lecture-minio2-1  | Client 'http://minio3:9000/minio/storage/data2/v49' re-connected in 133.205042ms\nminio-lecture-minio4-1  | All MinIO sub-systems initialized successfully in 76.677083ms\nminio-lecture-minio2-1  | Client 'http://minio1:9000/minio/storage/data1/v49' re-connected in 291.779417ms\nminio-lecture-minio2-1  | Client 'http://minio3:9000/minio/storage/data1/v49' re-connected in 295.254208ms\nminio-lecture-minio1-1  | Waiting for all MinIO sub-systems to be initialized.. lock acquired\nminio-lecture-minio4-1  | Client 'http://minio3:9000/minio/storage/data1/v49' re-connected in 105.200417ms\nminio-lecture-minio2-1  | Client 'http://minio1:9000/minio/storage/data2/v49' re-connected in 156.731042ms\nminio-lecture-minio2-1  | Client 'http://minio4:9000/minio/storage/data2/v49' re-connected in 161.032667ms\nminio-lecture-minio4-1  | Client 'http://minio3:9000/minio/lock/v7' re-connected in 116.688709ms\nminio-lecture-minio2-1  | Client 'http://minio3:9000/minio/storage/data2/v49' re-connected in 349.319333ms\nminio-lecture-minio2-1  | Client 'http://minio1:9000/minio/storage/data1/v49' re-connected in 201.184416ms\nminio-lecture-nginx-1   | /docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration\nminio-lecture-nginx-1   | /docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/\nminio-lecture-nginx-1   | /docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh\nminio-lecture-nginx-1   | 10-listen-on-ipv6-by-default.sh: Getting the checksum of /etc/nginx/conf.d/default.conf\nminio-lecture-minio4-1  | MinIO Object Storage Server\nminio-lecture-minio4-1  | Copyright: 2015-2022 MinIO, Inc.\nminio-lecture-minio4-1  | License: GNU AGPLv3 \u003chttps://www.gnu.org/licenses/agpl-3.0.html\u003e\nminio-lecture-minio4-1  | Version: RELEASE.2022-10-15T19-57-03Z (go1.18.7 linux/arm64)\nminio-lecture-minio4-1  | \nminio-lecture-minio4-1  | \nminio-lecture-minio4-1  | API: SYSTEM()\nminio-lecture-minio4-1  | Time: 13:09:15 UTC 10/16/2022\nminio-lecture-minio4-1  | DeploymentID: 92a93f42-872d-4f31-8182-fdad501c304f\nminio-lecture-minio4-1  | Error: drive not found: http://minio3:9000/data1 (*errors.errorString)\nminio-lecture-minio4-1  |        3: internal/logger/logger.go:259:logger.LogIf()\nminio-lecture-minio4-1  |        2: cmd/erasure.go:191:cmd.getDisksInfo.func1()\nminio-lecture-minio4-1  |        1: internal/sync/errgroup/errgroup.go:123:errgroup.(*Group).Go.func1()\nminio-lecture-minio4-1  | \nminio-lecture-minio4-1  | API: SYSTEM()\nminio-lecture-minio4-1  | Time: 13:09:15 UTC 10/16/2022\nminio-lecture-minio4-1  | DeploymentID: 92a93f42-872d-4f31-8182-fdad501c304f\nminio-lecture-minio4-1  | Error: drive not found: http://minio3:9000/data2 (*errors.errorString)\nminio-lecture-minio4-1  |        3: internal/logger/logger.go:259:logger.LogIf()\nminio-lecture-minio4-1  |        2: cmd/erasure.go:191:cmd.getDisksInfo.func1()\nminio-lecture-minio4-1  |        1: internal/sync/errgroup/errgroup.go:123:errgroup.(*Group).Go.func1()\nminio-lecture-minio4-1  | Use `mc admin info` to look for latest server/drive info\nminio-lecture-minio4-1  |  Status:         6 Online, 2 Offline. \nminio-lecture-minio4-1  | API: http://192.168.176.5:9000  http://127.0.0.1:9000 \nminio-lecture-minio4-1  | Console: http://192.168.176.5:9001 http://127.0.0.1:9001 \nminio-lecture-minio4-1  | \nminio-lecture-minio4-1  | Documentation: https://min.io/docs/minio/linux/index.html\nminio-lecture-nginx-1   | 10-listen-on-ipv6-by-default.sh: Enabled listen on IPv6 in /etc/nginx/conf.d/default.conf\nminio-lecture-nginx-1   | /docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh\nminio-lecture-nginx-1   | /docker-entrypoint.sh: Configuration complete; ready for start up\nminio-lecture-minio1-1  | Automatically configured API requests per node based on available memory on the system: 37\nminio-lecture-minio1-1  | All MinIO sub-systems initialized successfully in 147.445833ms\nminio-lecture-minio3-1  | Waiting for all MinIO sub-systems to be initialized.. lock acquired\nminio-lecture-minio1-1  | MinIO Object Storage Server\nminio-lecture-minio1-1  | Copyright: 2015-2022 MinIO, Inc.\nminio-lecture-minio1-1  | License: GNU AGPLv3 \u003chttps://www.gnu.org/licenses/agpl-3.0.html\u003e\nminio-lecture-minio1-1  | Version: RELEASE.2022-10-15T19-57-03Z (go1.18.7 linux/arm64)\nminio-lecture-minio1-1  | \nminio-lecture-minio1-1  | Status:         8 Online, 0 Offline. \nminio-lecture-minio1-1  | API: http://192.168.176.3:9000  http://127.0.0.1:9000 \nminio-lecture-minio1-1  | Console: http://192.168.176.3:9001 http://127.0.0.1:9001 \nminio-lecture-minio1-1  | \nminio-lecture-minio1-1  | Documentation: https://min.io/docs/minio/linux/index.html\nminio-lecture-minio3-1  | Automatically configured API requests per node based on available memory on the system: 37\nminio-lecture-minio2-1  | Waiting for all MinIO sub-systems to be initialized.. lock acquired\nminio-lecture-minio3-1  | All MinIO sub-systems initialized successfully in 281.016042ms\nminio-lecture-minio3-1  | MinIO Object Storage Server\nminio-lecture-minio3-1  | Copyright: 2015-2022 MinIO, Inc.\nminio-lecture-minio3-1  | License: GNU AGPLv3 \u003chttps://www.gnu.org/licenses/agpl-3.0.html\u003e\nminio-lecture-minio3-1  | Version: RELEASE.2022-10-15T19-57-03Z (go1.18.7 linux/arm64)\nminio-lecture-minio3-1  | \nminio-lecture-minio3-1  | Status:         8 Online, 0 Offline. \nminio-lecture-minio3-1  | API: http://192.168.176.4:9000  http://127.0.0.1:9000 \nminio-lecture-minio3-1  | Console: http://192.168.176.4:9001 http://127.0.0.1:9001 \nminio-lecture-minio3-1  | \nminio-lecture-minio3-1  | Documentation: https://min.io/docs/minio/linux/index.html\nminio-lecture-minio2-1  | Automatically configured API requests per node based on available memory on the system: 35\nminio-lecture-minio2-1  | All MinIO sub-systems initialized successfully in 299.530083ms\nminio-lecture-minio2-1  | MinIO Object Storage Server\nminio-lecture-minio2-1  | Copyright: 2015-2022 MinIO, Inc.\nminio-lecture-minio2-1  | License: GNU AGPLv3 \u003chttps://www.gnu.org/licenses/agpl-3.0.html\u003e\nminio-lecture-minio2-1  | Version: RELEASE.2022-10-15T19-57-03Z (go1.18.7 linux/arm64)\nminio-lecture-minio2-1  | \nminio-lecture-minio2-1  | Status:         8 Online, 0 Offline. \nminio-lecture-minio2-1  | API: http://192.168.176.2:9000  http://127.0.0.1:9000 \nminio-lecture-minio2-1  | Console: http://192.168.176.2:9001 http://127.0.0.1:9001 \nminio-lecture-minio2-1  | \nminio-lecture-minio2-1  | Documentation: https://min.io/docs/minio/linux/index.html\n```\nЗайдем в панель администратора из браузера: http://localhost:9001/login\n![Создание проекта](docs/5.png)\nВведем пароль и логин, которые мы указали в docker-compose.yml файле и зайдем в панель администратора:\n![Создание проекта](docs/6.png)\nПроверим что мы все сделали правильно и посмотрим любой исходящий запрос в консоли разработчика:\n![Создание проекта](docs/7.png)\nЗаголовок ответа Server nginx нам явно указывает что наш запрос сначала пошел внутрь nginx`а,\nа только после ушел внутрь подсети докера на тот же порт.\nВ консоли мы можем увидеть следующее(если вы запустили без флага -d):\n```shell\nminio-lecture-nginx-1   | 192.168.176.1 - - [16/Oct/2022:13:12:53 +0000] \"GET /static/js/5926.6813a97f.chunk.js.map HTTP/1.1\" 200 22724 \"http://localhost:9001/buckets\" \"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.0 Safari/605.1.15\" \"-\"\nminio-lecture-nginx-1   | 192.168.176.1 - - [16/Oct/2022:13:12:53 +0000] \"GET /static/js/701.ab5785ea.chunk.js.map HTTP/1.1\" 200 19780 \"http://localhost:9001/buckets\" \"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.0 Safari/605.1.15\" \"-\"\nminio-lecture-nginx-1   | 192.168.176.1 - - [16/Oct/2022:13:12:53 +0000] \"GET /static/js/4455.cdf95486.chunk.js.map HTTP/1.1\" 200 87234 \"http://localhost:9001/buckets\" \"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.0 Safari/605.1.15\" \"-\"\nminio-lecture-nginx-1   | 192.168.176.1 - - [16/Oct/2022:13:12:53 +0000] \"GET /static/js/9467.361c4c5c.chunk.js.map HTTP/1.1\" 200 134986 \"http://localhost:9001/buckets\" \"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.0 Safari/605.1.15\" \"-\"\nminio-lecture-nginx-1   | 192.168.176.1 - - [16/Oct/2022:13:12:53 +0000] \"GET /static/js/5171.e5224ef3.chunk.js.map HTTP/1.1\" 200 506010 \"http://localhost:9001/buckets\" \"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.0 Safari/605.1.15\" \"-\"\nminio-lecture-nginx-1   | 192.168.176.1 - - [16/Oct/2022:13:12:53 +0000] \"GET /static/js/696.c93c6454.chunk.js.map HTTP/1.1\" 200 76186 \"http://localhost:9001/buckets\" \"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.0 Safari/605.1.15\" \"-\"\nminio-lecture-nginx-1   | 192.168.176.1 - - [16/Oct/2022:13:12:53 +0000] \"GET /static/css/main.b20a708b.css.map HTTP/1.1\" 200 28742 \"http://localhost:9001/buckets\" \"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.0 Safari/605.1.15\" \"-\"\nminio-lecture-nginx-1   | 192.168.176.1 - - [16/Oct/2022:13:12:53 +0000] \"GET /static/js/main.c6cd5e83.js.map HTTP/1.1\" 200 5148650 \"http://localhost:9001/buckets\" \"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.0 Safari/605.1.15\" \"-\"\nminio-lecture-nginx-1   | 192.168.176.1 - - [16/Oct/2022:13:13:13 +0000] \"GET /static/js/8277.ffa83ea5.chunk.js HTTP/1.1\" 200 14998 \"http://localhost:9001/buckets/add-bucket\" \"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.0 Safari/605.1.15\" \"-\"\nminio-lecture-nginx-1   | 192.168.176.1 - - [16/Oct/2022:13:13:13 +0000] \"GET /static/js/8277.ffa83ea5.chunk.js.map HTTP/1.1\" 200 56877 \"http://localhost:9001/buckets/add-bucket\" \"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.0 Safari/605.1.15\" \"-\"\nminio-lecture-nginx-1   | 192.168.176.1 - - [16/Oct/2022:13:13:13 +0000] \"GET /api/v1/buckets HTTP/1.1\" 200 17 \"http://localhost:9001/buckets/add-bucket\" \"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.0 Safari/605.1.15\" \"-\"\n```\nЭто логи nginx о входящих запросах.\n### 4. Разобраться во внутренней конфигурации панели администратора minio\nКонсоль MinIO - это богатый графический пользовательский интерфейс,\nкоторый обеспечивает функциональность,\nаналогичную инструменту командной строки mc. \nВ случае если вы являетесь адиминистратором крупного проекта - вы как правило не будете пользоваться GUI,\nчтобы не вностить лишнюю и бессмысленную нагрузку на сервер. \nВ момент пока вы только учитесь вы можете пользоваться GUI.\n\nСтраница консоли MinIO предоставляет представление сегментов в развертывании\nВы можете использовать консоль MinIO для административных задач,\nтаких как Управление идентификацией и доступом,\nМониторинг показателей и журналов или Настройка сервера.\n\n#### Console Object Browser MinIO\n![Создание проекта](docs/8.png)\n\nВ разделе Обозревателя объектов консоли отображаются все бакеты и объекты, к которым имеет доступ аутентифицированный пользователь.\n\nИспользуйте строку поиска для поиска определенных бакетов и объектов. Выберите строку для корзины или объекта для просмотра.\n\nВыберите Create Bucket, чтобы создать новый бакет внутри кластера.\nВ каждом бакете есть кнопки управления и просмотра.\nВыберите Manage, чтобы открыть интерфейс управления для бакета:\n    \nНекоторые функции управления могут быть недоступны, если аутентифицированный пользователь не имеет необходимых административных разрешений.\n   \n* В Summary отображается сводная информация о конфигурации бакета. \n* Events view поддерживает настройку событий уведомления с использованием настроенного целевого объекта уведомления.\n* Replication поддерживает создание правил репликации бакета на стороне сервера и управление ими.\n* Lifecycle поддерживает создание Правил управления жизненным циклом объекта для бакета и управление ими.\n* В Access Audit отображаются все политики и пользователи, имеющие доступ к этому сегменту.\n* Access Rules поддерживает создание анонимных политик бакета и управление ими для присоединения к бакету или префиксу бакета. Анонимные правила позволяют клиентам получать доступ к корзине(бакету) или префиксу без явной аутентификации с использованием учетных данных пользователя.\n\nВыберите Обзор, чтобы просмотреть содержимое бакета.\nВы можете просматривать и загружать отдельные объекты,\nзагружать новые объекты или использовать функцию перемотки назад для просмотра только тех версий объекта,\nкоторые существовали на выбранную временную метку.\n#### Identity\nРаздел Идентификации предоставляет интерфейс управления для пользователей, управляемых MinIO.\n\nРаздел содержит следующие подразделы. Некоторые подразделы могут быть недоступны, если у прошедшего проверку пользователя нет необходимых административных разрешений.\n![Создание проекта](docs/9.png)\n\nВ разделе Пользователи отображаются все пользователи, управляемые MinIO.\n\n* Этот раздел недоступен для развертываний с использованием внешнего менеджера удостоверений, такого как Active Directory или поставщика, совместимого с OIDC.\n* Выберите Создать пользователя, чтобы создать нового пользователя, управляемого MinIO.\n* Вы можете назначить группы и политики пользователю во время создания.\n* Выберите строку пользователя, чтобы просмотреть сведения об этом пользователе.\n* Вы можете просматривать и изменять назначенные пользователю группы и политики.\n* Вы также можете просматривать любые учетные записи служб, связанные с пользователем, и управлять ими.\n\nПодробнее ознакомтесь с панелью администратора на официальном сайте с документацией minio: https://min.io/docs/minio/linux/administration/minio-console.html\n### 5. Бакеты. Создать свой первый бакет, загрузить файл и сгенерировать ссылку на файл в хранилище. \nДанные в S3-хранилище хранятся в едином формате: в виде объектов, помещенных в бакеты (контейнеры).\nМожно сказать что бакет - сущность чем-то похожая на папку 1 уровня.\n\nНажмите на Create Bucket\n![Создание проекта](docs/10.png)\nЗададим возможность версионирования файлов. \nУберем блокировку объектов.\nКвота(максимальный размер бакета) тоже нам не нужна.\nПравила удаления объектов нам тоже не нужны.\n![Создание проекта](docs/11.png)\nМы создали наш первый бакет. Давайте загрузим в него какой-нибудь файл. Нажимаем на upload.\n\n![Создание проекта](docs/12.png)\nФайл успешно загружен.\nНажмите на шестеренку и в настройках бакета сделайте ему паблик полиси.\nНажмите на файл левой кнопкой мыши чтобы открыть плашку справа. В ней мы нажмем на кнопку share.\nТам сгенерировалась ссылка подобного вида:\n```shell\nhttp://192.168.208.4:9000/test/b46xpy.jpg?X-Amz-Algorithm=AWS4-HMAC-SHA256\u0026X-Amz-Credential=HEK3NFWVQ28UQ5PVU0EN%2F20221016%2Fus-east-1%2Fs3%2Faws4_request\u0026X-Amz-Date=20221016T145908Z\u0026X-Amz-Expires=604800\u0026X-Amz-Security-Token=eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJhY2Nlc3NLZXkiOiJIRUszTkZXVlEyOFVRNVBWVTBFTiIsImV4cCI6MTY2NTkzNTkwNCwicGFyZW50IjoibWluaW8ifQ.e9dMHTmnk_Hq83Zo_o0EtQ5LBdRwVZaAkrDhtQiB72dKGwdSPIePX1GDVvyFWRWlCJwSPQoinMBFlcjkRO8YIg\u0026X-Amz-SignedHeaders=host\u0026versionId=bbd197a2-1526-44a6-be74-aea5b0bd323d\u0026X-Amz-Signature=186dddb381e8bb53638b6fc98ac296a0cf5a58e3d24c50d7162e1fb7c4c59f1c\n```\nПревратим ее в:\n```shell\nhttp://127.0.0.1:9000/test/b46xpy.jpg\n```\nЗайдем на этот адрес и увидим нашу картинку(файлик):\n![Создание проекта](docs/13.png)\nТеперь у нас есть ссылка на паблик файл в s3 чтобы показать нашему другу!\n## Этап №2\nэтап 2 находится в разработке\n\n## PS\n- Если вы нашли опечатку/ошибку создайте об этом issue к этому репозиторию\n- Лучшая благодарность звездочка на гитхабе :)\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkaymekaydex%2Fminio-lecture","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkaymekaydex%2Fminio-lecture","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkaymekaydex%2Fminio-lecture/lists"}