Перейти к основному содержимому

MinIO SDK

MinIO Go Client SDK — официальная библиотека для языка Go, которая позволяет работать с S3-совместимыми хранилищами через API Amazon S3 (S3 API).

Настроить MinIO SDK

  1. Настройте доступ к S3.
  2. Установите библиотеку в проекте.
  3. Задайте переменные окружения.
  4. Настройте клиент.

1. Настроить доступ к S3

Настроить доступ может Владелец аккаунта или пользователь с ролью iam.admin.

  1. Создайте сервисного пользователя с ролью с доступом в S3. Если вы используете сервисного пользователя с ролью s3.user, object_storage_user или s3.bucket.user, в бакете должна быть настроена политика доступа и ее правила должны разрешать доступ этому пользователю.
  2. Выдайте пользователю S3-ключ.

2. Установить библиотеку

  1. Откройте CLI.

  2. Подключите библиотеку к вашему проекту:

    go get github.com/minio/minio-go/v7

3. Задать переменные окружения

Доступны разные способы указания S3-ключей. Мы рекомендуем указывать S3-ключи не в коде, а через переменные окружения. Подробнее о других способах в документации MinIO SDK.

  1. Откройте CLI.

  2. Задайте переменные:

    export AWS_ACCESS_KEY_ID=<access_key>
    export AWS_SECRET_ACCESS_KEY=<secret_key>

    Укажите:

4. Настройте клиент

  1. В вашем локальном проекте откройте файл main.go.

  2. Добавьте скрипт инициализации клиента:

    package main

    import (
    "context"
    "log"
    "github.com/minio/minio-go/v7"
    "github.com/minio/minio-go/v7/pkg/credentials"
    )

    func main() {

    creds := credentials.NewEnvAWS()

    endpoint := "<s3_domain>"

    minioClient, err := minio.New(endpoint, &minio.Options{
    Creds: creds,
    Secure: true,
    })
    if err != nil {
    log.Fatal(err)
    }

    }

    Укажите <s3_domain>домен S3 API. Домен зависит от пула, в котором находится S3.

Работа с MinIO SDK

Если при работе с MinIO SDK возникают ошибки, проверьте список возможных ошибок.

Получить список бакетов

  1. Откройте файл main.go с клиентом, который вы настроили на этапе 4, или создайте новый файл и скопируйте в него клиент.

  2. В блок func main() добавьте скрипт для получения списка бакетов:

    info, err := minioClient.ListBuckets(context.Background())
    if err != nil {
    log.Fatalf("cannot get ListBuckets: %s", err)
    }

    log.Printf("%#v\n", info)
    Пример полного скрипта
    package main

    import (
    "context"
    "log"
    "github.com/minio/minio-go/v7"
    "github.com/minio/minio-go/v7/pkg/credentials"
    )

    func main() {

    creds := credentials.NewEnvAWS()

    endpoint := "<s3_domain>"

    minioClient, err := minio.New(endpoint, &minio.Options{
    Creds: creds,
    Secure: true,
    })
    if err != nil {
    log.Fatal(err)
    }

    info, err := minioClient.ListBuckets(context.Background())
    if err != nil {
    log.Fatalf("cannot get ListBuckets: %s", err)
    }

    log.Printf("%#v\n", info)

    }

    Здесь <s3_domain>домен S3 API. Домен зависит от пула, в котором находится S3.

Создать бакет

  1. Откройте файл main.go с клиентом, который вы настроили на этапе 4, или создайте новый файл и скопируйте в него клиент.

  2. В блок func main() добавьте скрипт для создания бакета:

    bucketName := "<bucket_name>"

    err = minioClient.MakeBucket(
    context.Background(),
    bucketName,
    minio.MakeBucketOptions{Region: "<pool>"},
    )
    if err != nil {
    exists, errBucketExists := minioClient.BucketExists(context.Background(), bucketName)
    if errBucketExists == nil && exists {
    log.Printf("Bucket %s already exists", bucketName)
    } else {
    log.Fatalf("cannot create bucket: %s", err)
    }
    } else {
    log.Printf("Bucket %s created", bucketName)
    }

    Укажите:

    • опционально: <pool>пул, в котором будет создан бакет;
    • <bucket_name> — имя бакета.
    Пример полного скрипта
    package main

    import (
    "context"
    "log"

    "github.com/minio/minio-go/v7"
    "github.com/minio/minio-go/v7/pkg/credentials"
    )

    func main() {

    creds := credentials.NewEnvAWS()

    endpoint := "<s3_domain>"

    minioClient, err := minio.New(endpoint, &minio.Options{
    Creds: creds,
    Secure: true,
    })
    if err != nil {
    log.Fatal(err)
    }

    bucketName := "bucketName"

    err = minioClient.MakeBucket(
    context.Background(),
    bucketName,
    minio.MakeBucketOptions{Region: "ru-7"},
    )
    if err != nil {
    exists, errBucketExists := minioClient.BucketExists(context.Background(), bucketName)
    if errBucketExists == nil && exists {
    log.Printf("Bucket %s already exists", bucketName)
    } else {
    log.Fatalf("cannot create bucket: %s", err)
    }
    } else {
    log.Printf("Bucket %s created", bucketName)
    }
    }

    Здесь <s3_domain>домен S3 API. Домен зависит от пула, в котором находится S3.

Загрузить объект в бакет

  1. Откройте файл main.go с клиентом, который вы настроили на этапе 4, или создайте новый файл и скопируйте в него клиент.

  2. В блок func main() добавьте скрипт для загрузки объекта в бакет:

    objectName := "<object_name>"
    filePath := "<path>"
    contentType := "application/octet-stream"

    info, err := minioClient.FPutObject(
    context.Background(),
    "<bucket_name>",
    objectName,
    filePath,
    minio.PutObjectOptions{ContentType: contentType},
    )
    if err != nil {
    log.Fatalf("Error: %s", err)
    }

    log.Printf("File uploaded. Size: %d bytes", info.Size)

    Укажите:

    • <object_name> — имя, которое будет у объекта в S3;
    • <path> — путь до файла на локальном устройстве;
    • <bucket_name> — имя бакета.
    Пример полного скрипта
    package main

    import (
    "context"
    "log"
    "github.com/minio/minio-go/v7"
    "github.com/minio/minio-go/v7/pkg/credentials"
    )

    func main() {

    creds := credentials.NewEnvAWS()

    endpoint := "<s3_domain>"

    minioClient, err := minio.New(endpoint, &minio.Options{
    Creds: creds,
    Secure: true,
    })
    if err != nil {
    log.Fatal(err)
    }

    objectName := "object-name.csv"
    filePath := "/path/file.csv"
    contentType := "application/octet-stream"

    info, err := minioClient.FPutObject(
    context.Background(),
    "bucketName",
    objectName,
    filePath,
    minio.PutObjectOptions{ContentType: contentType},
    )
    if err != nil {
    log.Fatalf("Error: %s", err)
    }

    log.Printf("File uploaded. Size: %d bytes", info.Size)
    }

    Здесь <s3_domain>домен S3 API. Домен зависит от пула, в котором находится S3.

Получить список объектов в бакете

  1. Откройте файл main.go с клиентом, который вы настроили на этапе 4, или создайте новый файл и скопируйте в него клиент.

  2. В блок func main() добавьте скрипт для получения списка объектов в бакете:

    objectsChan := minioClient.ListObjects(context.TODO(), "<bucket_name>", minio.ListObjectsOptions{
    Recursive: true,
    })
    for object := range objectsChan {
    log.Printf("%#v\n", object)
    }

    Укажите <bucket_name> — имя бакета.

    Пример полного скрипта
    package main

    import (
    "context"
    "log"
    "github.com/minio/minio-go/v7"
    "github.com/minio/minio-go/v7/pkg/credentials"
    )

    func main() {

    creds := credentials.NewEnvAWS()

    endpoint := "<s3_domain>"

    minioClient, err := minio.New(endpoint, &minio.Options{
    Creds: creds,
    Secure: true,
    })
    if err != nil {
    log.Fatal(err)
    }

    objectsChan := minioClient.ListObjects(context.TODO(), "bucketName", minio.ListObjectsOptions{
    Recursive: true,
    })
    for object := range objectsChan {
    log.Printf("%#v\n", object)
    }
    }

    Здесь <s3_domain>домен S3 API. Домен зависит от пула, в котором находится S3.

Изменить статус версионирования в бакете

  1. Откройте файл main.go с клиентом, который вы настроили на этапе 4, или создайте новый файл и скопируйте в него клиент.

  2. В блок func main() добавьте скрипт для изменения статуса версионирования:

    err = minioClient.SetBucketVersioning(
    context.Background(),
    "<bucket_name>",
    minio.BucketVersioningConfiguration{Status: "<status>"},
    )
    if err != nil {
    log.Fatalf("cannot enable versioning: %s", err)
    }
    log.Printf("Versioning enabled for bucket %s", "<bucket_name>")

    Укажите:

    • <bucket_name> — имя бакета;

    • <status> — статус версионирования, который нужно установить в бакете. Возможные значения:

      • Enabled — включение версионирования;
      • Suspended — приостановка версионирования.
    Пример полного скрипта
    package main

    import (
    "context"
    "log"

    "github.com/minio/minio-go/v7"
    "github.com/minio/minio-go/v7/pkg/credentials"
    )

    func main() {

    creds := credentials.NewEnvAWS()

    endpoint := "<s3_domain>"

    minioClient, err := minio.New(endpoint, &minio.Options{
    Creds: creds,
    Secure: true,
    })
    if err != nil {
    log.Fatal(err)
    }

    bucketName := "bucketName"

    err = minioClient.SetBucketVersioning(
    context.Background(),
    bucketName,
    minio.BucketVersioningConfiguration{Status: "Enabled"},
    )
    if err != nil {
    log.Fatalf("cannot enable versioning: %s", err)
    }

    log.Printf("Versioning enabled for bucket %s", bucketName)
    }

    Здесь <s3_domain>домен S3 API. Домен зависит от пула, в котором находится S3.

  3. Опционально: в блок func main() добавьте скрипт для проверки статуса версионирования:

    bucketName := "<bucket_name>"

    config, err := minioClient.GetBucketVersioning(context.Background(), bucketName)
    if err != nil {
    log.Fatalf("cannot get versioning config: %s", err)
    }

    log.Printf("Versioning status: %s", config.Status)

    Укажите <bucket_name> — имя бакета.

Получить объект

  1. Откройте файл main.go с клиентом, который вы настроили на этапе 4, или создайте новый файл и скопируйте в него клиент.

  2. В блок import добавьте пакет io:

    import (
    "context"
    "log"
    "io"
    "github.com/minio/minio-go/v7"
    "github.com/minio/minio-go/v7/pkg/credentials"
    )
  3. В блок func main() добавьте скрипт для получения объекта:

    object, err := minioClient.GetObject(context.TODO(), "<bucket_name>", "<object_name>", minio.GetObjectOptions{})
    if err != nil {
    log.Fatalf("cannot get object: %s", err)
    }

    log.Printf("%#v\n", object)

    byteSlice, err := io.ReadAll(object)
    if err != nil {
    log.Fatalf("Error reading from reader: %s\n", err)
    }

    log.Printf("object contains: \"%s\"", byteSlice)

    Укажите:

    • <object_name> — имя объекта;
    • <bucket_name> — имя бакета.
    Пример полного скрипта
    package main

    import (
    "context"
    "log"
    "io"
    "github.com/minio/minio-go/v7"
    "github.com/minio/minio-go/v7/pkg/credentials"
    )

    func main() {

    creds := credentials.NewEnvAWS()

    endpoint := "<s3_domain>"

    minioClient, err := minio.New(endpoint, &minio.Options{
    Creds: creds,
    Secure: true,
    })
    if err != nil {
    log.Fatal(err)
    }

    object, err := minioClient.GetObject(context.TODO(), "bucketName", "objectName", minio.GetObjectOptions{})
    if err != nil {
    log.Fatalf("cannot get object: %s", err)
    }

    log.Printf("%#v\n", object)

    byteSlice, err := io.ReadAll(object)
    if err != nil {
    log.Fatalf("Error reading from reader: %s\n", err)
    }

    log.Printf("object contains: \"%s\"", byteSlice)
    }

    Здесь <s3_domain>домен S3 API. Домен зависит от пула, в котором находится S3.

Вы можете создать ссылку в публичном или приватном бакете через подписанный URL (Presigned URL). Подробнее о Presigned URLs в инструкции Sharing objects with presigned URLs документации AWS.

  1. Откройте файл main.go с клиентом, который вы настроили на этапе 4, или создайте новый файл и скопируйте в него клиент.

  2. В блок import добавьте пакет time.

    import (
    "context"
    "log"
    "time"

    "github.com/minio/minio-go/v7"
    "github.com/minio/minio-go/v7/pkg/credentials"
    )
  3. В блок func main() добавьте скрипт для создания ссылок на загрузку и скачивание:

    getURL, err := minioClient.PresignedGetObject(
    context.Background(),
    "<bucket_name>",
    "<object_name>",
    <expiry>,
    nil,
    )
    if err != nil {
    log.Fatalf("cannot generate presigned get url: %s", err)
    }
    log.Printf("Presigned GET URL: %s", getURL.String())

    putURL, err := minioClient.PresignedPutObject(
    context.Background(),
    "<bucket_name>",
    "<object_name>",
    <expiry>,
    )
    if err != nil {
    log.Fatalf("cannot generate presigned put url: %s", err)
    }
    log.Printf("Presigned PUT URL: %s", putURL.String())

    Укажите:

    • <bucket_name> — имя бакета;

    • <object_name> — имя объекта;

    • <expiry> — срок действия ссылки в формате <amount>*<time>, где:

      • <amount> — количество часов, минут или секунд, которое будет действовать ссылка;
      • <time> — единица времени, возможные значения: time.Hour, time.Minute или time.Second.
    Пример полного скрипта
    package main

    import (
    "context"
    "log"
    "time"

    "github.com/minio/minio-go/v7"
    "github.com/minio/minio-go/v7/pkg/credentials"
    )

    func main() {

    creds := credentials.NewEnvAWS()

    endpoint := "<s3_domain>"

    minioClient, err := minio.New(endpoint, &minio.Options{
    Creds: creds,
    Secure: true,
    })
    if err != nil {
    log.Fatal(err)
    }

    getURL, err := minioClient.PresignedGetObject(
    context.Background(),
    "bucketName",
    "objectName",
    30*time.Hour,
    nil,
    )
    if err != nil {
    log.Fatalf("cannot generate presigned get url: %s", err)
    }
    log.Printf("Presigned GET URL: %s", getURL.String())

    putURL, err := minioClient.PresignedPutObject(
    context.Background(),
    "bucketName",
    "objectName",
    time.Hour,
    )
    if err != nil {
    log.Fatalf("cannot generate presigned put url: %s", err)
    }
    log.Printf("Presigned PUT URL: %s", putURL.String())
    }

    Здесь <s3_domain>домен S3 API. Домен зависит от пула, в котором находится S3.

Получить метаданные объекта

  1. Откройте файл main.go с клиентом, который вы настроили на этапе 4, или создайте новый файл и скопируйте в него клиент.

  2. В блок func main() добавьте скрипт для получения метаданных объекта:

    info, err := minioClient.StatObject(
    context.Background(),
    "<bucket_name>",
    "<object_name>",
    minio.StatObjectOptions{},
    )
    if err != nil {
    log.Fatalf("cannot get object info: %s", err)
    }

    log.Printf("Key: %s", info.Key)
    log.Printf("Size: %d bytes", info.Size)
    log.Printf("ContentType: %s", info.ContentType)
    log.Printf("ETag: %s", info.ETag)
    log.Printf("LastModified: %s", info.LastModified)

    Укажите:

    • <bucket_name> — имя бакета;
    • <object_name> — имя объекта.
    Пример полного скрипта
    package main

    import (
    "context"
    "log"

    "github.com/minio/minio-go/v7"
    "github.com/minio/minio-go/v7/pkg/credentials"
    )

    func main() {

    creds := credentials.NewEnvAWS()

    endpoint := "<s3_domain>"

    minioClient, err := minio.New(endpoint, &minio.Options{
    Creds: creds,
    Secure: true,
    })
    if err != nil {
    log.Fatal(err)
    }

    info, err := minioClient.StatObject(
    context.Background(),
    "bucketName",
    "objectName",
    minio.StatObjectOptions{},
    )
    if err != nil {
    log.Fatalf("cannot get object info: %s", err)
    }

    log.Printf("Key: %s", info.Key)
    log.Printf("Size: %d bytes", info.Size)
    log.Printf("ContentType: %s", info.ContentType)
    log.Printf("ETag: %s", info.ETag)
    log.Printf("LastModified: %s", info.LastModified)
    }

    Здесь <s3_domain>домен S3 API. Домен зависит от пула, в котором находится S3.

Удалить объект

  1. Откройте файл main.go с клиентом, который вы настроили на этапе 4, или создайте новый файл и скопируйте в него клиент.

  2. В блок func main() добавьте скрипт для удаления объекта:

    err = minioClient.RemoveObject(
    context.Background(),
    "<bucket_name>",
    "<object_name>",
    minio.RemoveObjectOptions{VersionID: "<version_id>"},
    )
    if err != nil {
    log.Fatalf("cannot remove object: %s", err)
    }
    log.Printf("Object %s removed", "<object_name>")

    Укажите:

    • <bucket_name> — имя бакета;
    • <object_name> — имя объекта;
    • опционально: VersionID: "<version_id>" — опция, которая удаляет конкретную версию объекта, если в бакете включено версионирование. Укажите <version_id>идентификатор версии.
    Пример полного скрипта
    package main

    import (
    "context"
    "log"

    "github.com/minio/minio-go/v7"
    "github.com/minio/minio-go/v7/pkg/credentials"
    )

    func main() {

    creds := credentials.NewEnvAWS()

    endpoint := "<s3_domain>"

    minioClient, err := minio.New(endpoint, &minio.Options{
    Creds: creds,
    Secure: true,
    })
    if err != nil {
    log.Fatal(err)
    }

    err = minioClient.RemoveObject(
    context.Background(),
    "bucketName",
    "objectName",
    minio.RemoveObjectOptions{},
    )
    if err != nil {
    log.Fatalf("cannot remove object: %s", err)
    }

    log.Printf("Object %s removed", "objectName")
    }

    Здесь <s3_domain>домен S3 API. Домен зависит от пула, в котором находится S3.

Возможные ошибки

ОшибкаОписаниеРешение
AccessDeniedДоступ запрещенПроверьте ключи, политики доступа и разрешения пользователей
NoSuchBucketБакет не существуетПроверьте имя бакета и целевой пул
NoSuchKeyОбъект не найденПроверьте имя объекта и путь до него в бакете
BucketAlreadyExistsБакет с таким именем уже существуетУкажите другое имя
BucketNotEmptyБакет не пустУдалите все объекты и незавершенные загрузки перед удалением бакета
InvalidBucketNameНекорректное имя бакетаУкажите имя, которое содержит только строчные буквы, цифры, точки и дефисы
connection refusedНекорректный домен S3 APIУбедитесь, что домен соответствует пулу, в котором находится бакет
SignatureDoesNotMatchПодпись не совпадает: неверный секретный ключ или повреждены заголовки запросаИспользуйте корректный секретный ключ и проверьте заголовки запроса
MalformedXMLНекорректный XMLПроверьте синтаксис и структуру переданного XML
TooManyBucketsДостигнут лимит на количество бакетов. Удалите неиспользуемые бакеты или запросите увеличение квоты
RequestTimeoutПревышено время ожидания. Проверьте сетевое соединение или увеличьте таймаут запроса
MethodNotAllowedИспользуется неподходящий HTTP-метод для этой операции (GET/PUT/DELETE)