MinIO ile Self-Hosted Nesne Depolama Kurulumu

Bulut depolama artık sadece büyük şirketlerin lüksü değil. AWS S3, Google Cloud Storage gibi servisler harika ama her ay gelen fatura ve veri çıkış ücretleri zamanla can yakıcı bir hal alıyor. İşte tam bu noktada MinIO devreye giriyor: S3 uyumlu, açık kaynaklı, kendi sunucunda çalıştırabileceğin bir nesne depolama sistemi. Bu yazıda MinIO’yu production ortamına uygun şekilde nasıl kuracağını, yapılandıracağını ve günlük operasyonlarda nasıl kullanacağını adım adım anlatacağım.

MinIO Nedir ve Neden Kullanmalısın?

MinIO, Go diliyle yazılmış, yüksek performanslı bir nesne depolama sistemi. En büyük avantajı Amazon S3 API’siyle tam uyumlu olması. Yani şu an S3 kullanan bir uygulaman varsa, endpoint adresini değiştirip MinIO’ya geçiş yapabilirsin ve uygulaman farkı anlamaz.

Gerçek dünya senaryosu olarak düşün: Bir startup’sın, her ay S3’e 500-600 dolar veriyorsun. Elinde 2-3 adet bare metal sunucu var. MinIO kurarsın, donanım maliyetini bir kez ödersin, sonrası sana kalmış. Ya da on-premise bir ortamda çalışıyorsun ve veri egemenliği (data sovereignty) nedeniyle verilerini dışarıya çıkaramıyorsun. MinIO bu durumda biçilmiş kaftan.

Öne çıkan özellikleri şöyle sıralayabilirim:

  • S3 uyumluluğu: SDK’lar, CLI araçları, mevcut uygulamalar değişiklik gerektirmeden çalışır
  • Yüksek performans: NVMe disk üzerinde saniyede 325 GB okuma hızına çıkabiliyor
  • Erasure coding: Veri kaybını önleyen dağıtık depolama mekanizması
  • Encryption: Server-side ve client-side şifreleme desteği
  • Versioning: S3 benzeri nesne sürümleme
  • Lifecycle policies: Otomatik veri yönetimi kuralları

Kurulum Ortamının Hazırlanması

Ben bu yazıda Ubuntu 22.04 üzerinde single-node kurulum yapacağım, ardından distributed (dağıtık) kuruluma geçeceğiz. Production için distributed kurulum şiddetle önerilir.

Önce sistemin güncel olduğundan emin ol:

sudo apt update && sudo apt upgrade -y
sudo apt install -y wget curl net-tools

MinIO binary’sini indiriyoruz:

wget https://dl.min.io/server/minio/release/linux-amd64/minio
chmod +x minio
sudo mv minio /usr/local/bin/

Versiyonu doğrula:

minio --version

Şimdi MinIO için ayrı bir kullanıcı oluşturalım. Root ile çalıştırmak güvenlik açısından iyi bir pratik değil:

sudo groupadd -r minio-user
sudo useradd -M -r -g minio-user minio-user
sudo mkdir -p /data/minio
sudo chown -R minio-user:minio-user /data/minio

Konfigürasyon Dosyasının Hazırlanması

MinIO’nun çalışma parametrelerini bir environment dosyasında tanımlayacağız:

sudo nano /etc/default/minio

Dosyanın içine şunları yaz:

# MinIO Konfigurasyonu
MINIO_VOLUMES="/data/minio"
MINIO_OPTS="--console-address :9001"
MINIO_ROOT_USER="minioadmin"
MINIO_ROOT_PASSWORD="guclu-bir-sifre-yaz-buraya"

# TLS aktifse
# MINIO_OPTS="--console-address :9001 --certs-dir /etc/minio/certs"

MINIO_ROOT_PASSWORD için mutlaka güçlü bir parola kullan. 8 karakterden uzun, büyük/küçük harf ve rakam içeren bir parola seç. Production’da bu değerleri HashiCorp Vault veya benzeri bir secret management aracından çekmen daha iyi olur.

Systemd Service Oluşturma

MinIO’yu bir servis olarak çalıştırmak için systemd unit dosyası oluşturalım:

sudo nano /etc/systemd/system/minio.service
[Unit]
Description=MinIO Object Storage
Documentation=https://docs.min.io
Wants=network-online.target
After=network-online.target
AssertFileIsExecutable=/usr/local/bin/minio

[Service]
WorkingDirectory=/usr/local/

User=minio-user
Group=minio-user
ProtectProc=invisible

EnvironmentFile=-/etc/default/minio
ExecStartPre=/bin/bash -c "if [ -z "${MINIO_VOLUMES}" ]; then echo "Variable MINIO_VOLUMES not set in /etc/default/minio"; exit 1; fi"

ExecStart=/usr/local/bin/minio server $MINIO_OPTS $MINIO_VOLUMES

# Restart ayarlari
Restart=always
RestartSec=5s

# Guvenlik sinirlamalari
LimitNOFILE=65536
TasksMax=infinity
TimeoutStopSec=infinity
SendSIGKILL=no

[Install]
WantedBy=multi-user.target

Servisi etkinleştir ve başlat:

sudo systemctl daemon-reload
sudo systemctl enable minio
sudo systemctl start minio
sudo systemctl status minio

Servis başarıyla çalışıyorsa 9000 portunda API, 9001 portunda web arayüzü (console) erişilebilir olacak.

MinIO Client (mc) Kurulumu ve Temel Operasyonlar

MinIO’yu komut satırından yönetmek için mc aracını kuralım:

wget https://dl.min.io/client/mc/release/linux-amd64/mc
chmod +x mc
sudo mv mc /usr/local/bin/

# MinIO sunucusunu ekle
mc alias set localminio http://localhost:9000 minioadmin guclu-bir-sifre-yaz-buraya

# Baglantıyı test et
mc admin info localminio

Şimdi bazı temel işlemler yapalım:

# Bucket oluştur
mc mb localminio/my-backups
mc mb localminio/app-uploads
mc mb localminio/media-files

# Dosya yukle
mc cp /etc/hostname localminio/my-backups/
mc cp --recursive /var/log/nginx/ localminio/my-backups/nginx-logs/

# Listeleme
mc ls localminio/
mc ls localminio/my-backups/

# Dosya indir
mc cp localminio/my-backups/hostname /tmp/hostname-restored

# Bucket istatistikleri
mc du localminio/my-backups

TLS/SSL Sertifikası ile Güvenli Erişim

Production ortamında MinIO’nun TLS ile çalışması şart. Let’s Encrypt veya kendi CA’nızdan aldığınız sertifikaları kullanabilirsiniz. Burada self-signed sertifika ile örnek yapacağım, gerçek ortamda Let’s Encrypt önerilir.

# Sertifika dizinini olustur
sudo mkdir -p /etc/minio/certs

# Self-signed sertifika uret
sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 
  -keyout /etc/minio/certs/private.key 
  -out /etc/minio/certs/public.crt 
  -subj "/CN=minio.sirketiniz.com/O=Sirket/C=TR" 
  -addext "subjectAltName=DNS:minio.sirketiniz.com,IP:192.168.1.100"

sudo chown -R minio-user:minio-user /etc/minio/certs
sudo chmod 600 /etc/minio/certs/private.key

/etc/default/minio dosyasını güncelle:

MINIO_VOLUMES="/data/minio"
MINIO_OPTS="--console-address :9001 --certs-dir /etc/minio/certs"
MINIO_ROOT_USER="minioadmin"
MINIO_ROOT_PASSWORD="guclu-bir-sifre-yaz-buraya"

Servisi yeniden başlat:

sudo systemctl restart minio

mc alias’ını HTTPS için güncelle:

mc alias set localminio https://minio.sirketiniz.com:9000 minioadmin guclu-bir-sifre-yaz-buraya --insecure

Gerçek sertifika kullanıyorsan --insecure flagini kaldırabilirsin.

Kullanıcı ve Erişim Politikaları

MinIO’da S3 benzeri IAM politikaları tanımlayabilirsin. Örneğin uygulama sunucularına sadece belirli bucket’lara erişim vermek için:

# Yeni kullanıcı olustur
mc admin user add localminio app-user guclu-uygulama-sifresi

# Sadece app-uploads bucket'ina tam erisim veren politika yaz
cat > /tmp/app-policy.json << 'EOF'
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "s3:GetObject",
        "s3:PutObject",
        "s3:DeleteObject",
        "s3:ListBucket"
      ],
      "Resource": [
        "arn:aws:s3:::app-uploads",
        "arn:aws:s3:::app-uploads/*"
      ]
    }
  ]
}
EOF

# Politikayı MinIO'ya yukle
mc admin policy create localminio app-policy /tmp/app-policy.json

# Kullaniciya politikayı ata
mc admin policy attach localminio app-policy --user app-user

Read-only erişim vermek istediğin durumlar da olacak. Örneğin bir CDN proxy servisi veya raporlama aracı için:

# Sadece okuma izni olan kullanici
mc admin user add localminio readonly-user baska-bir-sifre

mc admin policy attach localminio readonly --user readonly-user

readonly, readwrite, writeonly, diagnostics MinIO’nun hazır built-in politikaları. Bunları direkt kullanabilirsin.

Bucket Lifecycle Politikaları

Eski dosyaları otomatik olarak silmek veya farklı bir storage class’a taşımak için lifecycle kuralları işe yarıyor. Özellikle log dosyaları veya geçici upload’lar için:

# 30 gunden eski nesneleri sil
mc ilm rule add --expire-days 30 localminio/my-backups

# Tum kurallari listele
mc ilm rule ls localminio/my-backups

# Belirli prefix icin kural ekle
mc ilm rule add --expire-days 7 --prefix "temp/" localminio/app-uploads

JSON formatında daha karmaşık kurallar da tanımlayabilirsin:

cat > /tmp/lifecycle.json << 'EOF'
{
  "Rules": [
    {
      "ID": "delete-old-logs",
      "Status": "Enabled",
      "Filter": {
        "Prefix": "nginx-logs/"
      },
      "Expiration": {
        "Days": 14
      }
    },
    {
      "ID": "delete-temp-files",
      "Status": "Enabled",
      "Filter": {
        "Prefix": "temp/"
      },
      "Expiration": {
        "Days": 3
      }
    }
  ]
}
EOF

mc ilm import localminio/my-backups < /tmp/lifecycle.json

Backup Senaryosu: PostgreSQL Dump’larını MinIO’ya Gönderme

Şimdi gerçek bir senaryo yapalım. PostgreSQL veritabanı yedeğini alıp MinIO’ya gönderecek bir script yazalım:

#!/bin/bash
# /usr/local/bin/pg-backup-to-minio.sh

set -euo pipefail

# Degiskenler
DB_NAME="production_db"
DB_USER="postgres"
BACKUP_DIR="/tmp/pg-backups"
MINIO_ALIAS="localminio"
MINIO_BUCKET="my-backups"
RETENTION_DAYS=7
DATE=$(date +%Y-%m-%d_%H-%M-%S)
BACKUP_FILE="${BACKUP_DIR}/${DB_NAME}_${DATE}.sql.gz"

# Dizin olustur
mkdir -p ${BACKUP_DIR}

echo "[$(date)] PostgreSQL yedeği basliyor: ${DB_NAME}"

# Yedek al ve sikistir
pg_dump -U ${DB_USER} ${DB_NAME} | gzip > ${BACKUP_FILE}

echo "[$(date)] Yedek boyutu: $(du -sh ${BACKUP_FILE} | cut -f1)"

# MinIO'ya yukle
mc cp ${BACKUP_FILE} ${MINIO_ALIAS}/${MINIO_BUCKET}/database/$(basename ${BACKUP_FILE})

echo "[$(date)] MinIO'ya yuklendi"

# Lokal dosyayı temizle
rm -f ${BACKUP_FILE}

# MinIO'da eski yedekleri sil
mc find ${MINIO_ALIAS}/${MINIO_BUCKET}/database/ 
  --older-than ${RETENTION_DAYS}d 
  --name "*.sql.gz" | xargs -I{} mc rm {}

echo "[$(date)] Yedek tamamlandi"

Script’i çalıştırılabilir yap ve cron’a ekle:

chmod +x /usr/local/bin/pg-backup-to-minio.sh

# Her gece 02:00'de calistir
echo "0 2 * * * root /usr/local/bin/pg-backup-to-minio.sh >> /var/log/pg-backup.log 2>&1" | sudo tee -a /etc/cron.d/pg-backup

Distributed Kurulum (4 Node)

Single-node kurulum test ve küçük ortamlar için yeterli ama production’da en az 4 node ile distributed kurulum yapmalısın. Bu sayede erasure coding devreye giriyor ve disk kayıplarına karşı koruma sağlanıyor.

4 sunucunda (minio1, minio2, minio3, minio4) her birinde aynı işlemi yap:

# Her node'da MinIO binary'sini kur (yukarıdaki adimlar)
# Her node'da veri dizini olustur
sudo mkdir -p /data/minio
sudo chown -R minio-user:minio-user /data/minio

Her node’daki /etc/default/minio dosyası şöyle olacak:

MINIO_VOLUMES="http://minio{1...4}/data/minio"
MINIO_OPTS="--console-address :9001"
MINIO_ROOT_USER="minioadmin"
MINIO_ROOT_PASSWORD="guclu-bir-sifre-yaz-buraya"

# Distributed ortamda bu deger her node icin ayni olmali
MINIO_SITE_NAME="production-cluster"

/etc/hosts dosyasına her node’u ekle (DNS yoksa):

192.168.1.101 minio1
192.168.1.102 minio2
192.168.1.103 minio3
192.168.1.104 minio4

4 node’da da aynı anda servisi başlat. MinIO’nun tüm node’ların çevrimiçi olmasını beklediğini unutma, bu yüzden hepsini neredeyse aynı zamanda başlatman gerekiyor.

Monitoring ve Health Check

MinIO’nun sağlık durumunu izlemek için birkaç yöntem var:

# Genel cluster durumu
mc admin info localminio

# Disk kullanimi
mc admin prometheus generate localminio

# Health endpoint (HTTP 200 donerse saglıklı)
curl -I http://localhost:9000/minio/health/live
curl -I http://localhost:9000/minio/health/ready

Prometheus ile entegre etmek istiyorsan:

# Prometheus kullanicisi olustur
mc admin user add localminio prometheus prometheus-sifresi

# Prometheus politikasını ata
mc admin policy attach localminio diagnostics --user prometheus

# Scrape token uret
mc admin prometheus generate localminio

Çıktıda sana bir bearer token verecek. Bunu Prometheus konfigürasyonuna ekle:

# prometheus.yml icine ekle
scrape_configs:
  - job_name: 'minio'
    bearer_token: 'TOKEN_BURAYA'
    metrics_path: /minio/v2/metrics/cluster
    scheme: http
    static_configs:
      - targets: ['localhost:9000']

Nginx ile Reverse Proxy Yapılandırması

MinIO’yu doğrudan dışarıya açmak yerine Nginx arkasına almak hem güvenlik hem de SSL termination açısından daha temiz:

sudo apt install -y nginx

sudo nano /etc/nginx/sites-available/minio
# /etc/nginx/sites-available/minio

upstream minio_backend {
    server 127.0.0.1:9000;
}

upstream minio_console {
    server 127.0.0.1:9001;
}

server {
    listen 80;
    server_name minio.sirketiniz.com;
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl http2;
    server_name minio.sirketiniz.com;

    ssl_certificate /etc/letsencrypt/live/minio.sirketiniz.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/minio.sirketiniz.com/privkey.pem;

    # Buyuk dosya yukleme icin
    client_max_body_size 0;
    proxy_buffering off;
    proxy_request_buffering off;

    location / {
        proxy_pass http://minio_backend;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;

        # Websocket destegi
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";

        # Timeout degerlerini artir (buyuk dosyalar icin)
        proxy_connect_timeout 300;
        proxy_send_timeout 300;
        proxy_read_timeout 300;
    }
}

server {
    listen 443 ssl http2;
    server_name console.minio.sirketiniz.com;

    ssl_certificate /etc/letsencrypt/live/minio.sirketiniz.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/minio.sirketiniz.com/privkey.pem;

    location / {
        proxy_pass http://minio_console;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }
}
sudo ln -s /etc/nginx/sites-available/minio /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx

Sık Karşılaşılan Sorunlar ve Çözümleri

MinIO başlamıyor, “Unable to read from erasure set” hatası alıyorum:

Distributed kurulumda bazı diskler ya da node’lar erişilemiyor olabilir. Şunu kontrol et:

# Node'lar arası port erişimi kontrol et
nc -zv minio2 9000
nc -zv minio3 9000

# Firewall kurallarını kontrol et
sudo ufw status
sudo iptables -L -n | grep 9000

“XMinioStorageFull” hatası:

Disk dolmuş demek. Lifecycle policy yoksa eski dosyalar birikir:

# Disk kullanimi
df -h /data/minio
mc du localminio/

# En buyuk bucket'lari bul
mc du localminio/ --recursive --depth 1

Yükleme hızı düşük:

MINIO_OPTS içine --address ile interface belirtmek ve ağ konfigürasyonunu kontrol etmek gerekebilir. Ayrıca disk I/O’yu izle:

iostat -x 1 5
iotop -o

Sonuç

MinIO, doğru yapılandırıldığında production kalitesinde bir nesne depolama çözümü sunuyor. S3 uyumluluğu sayesinde mevcut altyapıya entegrasyonu son derece kolay. Tek dikkat etmen gereken nokta, distributed kurulumda node sayısını ve disk planlamasını önceden iyi yapman.

Özetle şu adımları takip etmişsin: binary kurulumu, systemd ile servis tanımı, TLS ile güvenli erişim, kullanıcı ve politika yönetimi, lifecycle kuralları ve gerçek dünya backup senaryosu. Üstüne bir de Nginx reverse proxy ekleyince elimizde oldukça sağlam bir kurulum çıkıyor.

Bir sonraki adım olarak MinIO’nun Kafka entegrasyonunu veya bucket notification özelliğini incelemeni öneririm. Bir nesne yüklendiğinde otomatik olarak event tetiklemek, özellikle image processing veya ETL pipeline’larında işleri çok kolaylaştırıyor. Ama bu konu başlı başına ayrı bir yazı.

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir