← Kursa Dön
📄 Text · 30 min

İlk Container'ın — docker run ile Tanışma

Docker kuruldu, her şey hazır. Şimdi Docker'ın en temel, en sık kullanılan, en güçlü komutunu öğrenme zamanı: docker run.

Bir otomat makinesi düşün. Para atarsın, buton seçersin, ürün düşer. İçeride kompresör mü çalışıyor, soğutma sistemi nasıl — bilmene gerek yok. Sen sadece butona basarsın. docker run da tam olarak bu. Tek bir komutla: image indirilir, container oluşturulur, network konfigüre edilir, dosya sistemi hazırlanır ve proses başlatılır. Sen sadece komutu yazarsın.

Bu derste docker run komutunu tüm detaylarıyla öğreneceğiz. Her parametresini, her davranışını, gerçek dünya örnekleriyle pratik yapacağız.


docker run — En Temel Komut

docker run [SEÇENEKLER] IMAGE [KOMUT] [ARGÜMANLAR]

Bu komut aslında iki işlemi birlikte yapıyor: önce image'dan bir container oluşturuyor (docker create), sonra bu container'ı başlatıyor (docker start). Ama biz genellikle ikisini birden yapan docker run'ı kullanırız.

En basit haliyle:

docker run nginx

Bu komutu çalıştırdığında ne oluyor? Docker önce nginx:latest image'ını yerelde arıyor. Bulamazsa Docker Hub'dan indiriyor. Sonra image'dan bir container oluşturuyor. Container'ın varsayılan komutunu (CMD) çalıştırıyor. Ve container ön planda (foreground) çalışmaya başlıyor — terminali meşgul ediyor. Ctrl+C ile durdurabilirsin.

Ama pratikte container'ları genellikle arka planda çalıştırırız. Şimdi en sık kullanılan seçenekleri tek tek öğrenelim.


Arka Planda Çalıştır: -d (Detached Mode)

# Ön planda — terminal meşgul olur
docker run nginx

# Arka planda — terminal serbest kalır
docker run -d nginx
# Çıktı: a1b2c3d4e5f6... (container ID)

-d flag'i container'ı arka plana gönderir. Container çalışmaya devam eder ama terminalin serbest kalır. Başka işler yapabilirsin. Çalışan container'ları görmek için docker ps kullanırsın.


Container'a İsim Ver: --name

Docker, isim vermediğin container'lara rastgele isimler atar: eager_einstein, silly_hawking gibi. Eğlenceli ama kafa karıştırıcı. Onun yerine her zaman anlamlı isimler ver:

docker run -d --name web-server nginx

Artık bu container'a ismiyle erişebilirsin:

docker stop web-server
docker start web-server
docker logs web-server
docker rm web-server

💡 Her zaman --name kullan. Rastgele isimlerle çalışmak, özellikle birden fazla container varken, çok karmaşıklaştırır.


Port Mapping: -p

Container'lar varsayılan olarak dış dünyadan erişilemez. İçeride bir web sunucusu çalışıyor olabilir ama sen tarayıcıdan ona ulaşamazsın. Port mapping ile container'ın portunu host'un portuna bağlarsın:

docker run -d -p 8080:80 nginx

Bu komut "host'un 8080 portuna gelen istekleri container'ın 80 portuna yönlendir" diyor. Şimdi tarayıcıda http://localhost:8080 açarsan Nginx'in karşılama sayfasını görürsün.

Birden fazla port da eşleyebilirsin:

docker run -d -p 8080:80 -p 8443:443 nginx

Eğer belirli bir IP'ye bağlamak istersen (mesela sadece localhost'tan erişilebilir olsun):

docker run -d -p 127.0.0.1:8080:80 nginx

Hangi portların eşlendiğini görmek için:

docker port web-server
# 80/tcp -> 0.0.0.0:8080

İnteraktif Mod: -it

Bazen container'ın içine girip etkileşimli çalışmak istersin — bir shell açmak, komut denemek, debug yapmak gibi. Bunun için -it flag'lerini kullanıyoruz:

docker run -it ubuntu bash

-i stdin'i açık tutar (klavyeden input girebilirsin), -t bir terminal emülatörü sağlar (renkler, satır düzeni doğru görünür). İkisi birlikte tam bir terminal deneyimi sunar.

Bu komutu çalıştırdığın anda kendini bir Ubuntu shell'inin içinde bulursun:

root@a1b2c3d4e5f6:/# whoami
root
root@a1b2c3d4e5f6:/# ls /
bin  boot  dev  etc  home  lib  ...
root@a1b2c3d4e5f6:/# exit

exit yazınca container durur — çünkü container'ın ana prosesi bash'ti ve o kapandı.

Aynı şekilde Python veya Node.js REPL'ini de container içinde çalıştırabilirsin:

# Python REPL
docker run -it python:3.12
>>> print("Merhaba Docker!")
Merhaba Docker!
>>> exit()

# Node.js REPL
docker run -it node:20
> console.log("Docker'dan selam!")
Docker'dan selam!
> .exit

Otomatik Temizlik: --rm

Normalde bir container durduğunda silinmez — docker ps -a ile hâlâ görürsün. Zamanla onlarca durmuş container birikir. --rm flag'i ile container durduğu anda otomatik silinir:

# --rm olmadan: container durmuş olarak kalır
docker run ubuntu echo "hello"
docker ps -a   # Exited container görürsün

# --rm ile: container durduğu anda silinir
docker run --rm ubuntu echo "hello"
docker ps -a   # Temiz — container yok

💡 Tek seferlik komutlarda, test ve deneme amaçlı container'larda her zaman --rm kullan. Yoksa zamanla durmuş container çöplüğü oluşur.


Environment Variables: -e

Uygulamaları konfigüre etmenin en yaygın yolu environment variable'lar. -e flag'i ile container'a değişken geçirebilirsin:

docker run -d \
    -e POSTGRES_USER=admin \
    -e POSTGRES_PASSWORD=secret123 \
    -e POSTGRES_DB=myapp \
    postgres:16

Çok sayıda değişken varsa dosyadan yüklemek daha temiz:

# .env dosyası oluştur
cat > .env << 'EOF'
POSTGRES_USER=admin
POSTGRES_PASSWORD=secret123
POSTGRES_DB=myapp
EOF

# Dosyadan yükle
docker run -d --env-file .env postgres:16

Container'ın environment variable'larını kontrol etmek için:

docker exec my-container env

Environment variable'ları Bölüm 4'te çok daha detaylı inceleyeceğiz.


Volume ve Bind Mount Temelleri

Container'lar geçici. Durdurduğunda veya sildiğinde içindeki veriler kaybolur. Ama veritabanı verisi, log dosyaları, kullanıcı yüklemeleri — bunlar kalıcı olmalı. İşte burada volume'lar devreye girer:

# Named volume: Docker-yönetimli kalıcı depolama
docker run -d \
    -v pgdata:/var/lib/postgresql/data \
    postgres:16
# pgdata volume'ü container silinse bile kalır!

# Bind mount: Host dizinini container'a bağla
docker run -d \
    -v $(pwd)/html:/usr/share/nginx/html \
    -p 8080:80 \
    nginx
# Host'taki html/ dizini container'da görünür
# Dosyaları host'ta düzenlersin, container'da anında yansır

Volume konusunu Bölüm 6'da derinlemesine ele alacağız. Şimdilik "veri kalıcı olsun istiyorsan volume kullan" kuralını hatırla.


Restart Policy — Container Çökerse Ne Olur?

Production'da container'lar çökebilir. Bir hata, bir memory leak, bir beklenmedik durum — ve container durur. Ne olacak? Elle mi başlatacaksın? Hayır. Restart policy ile otomatik yeniden başlatma tanımlarsın:

# Her zaman yeniden başlat
docker run -d --restart=always nginx

# Hata durumunda max 5 deneme
docker run -d --restart=on-failure:5 myapp

# Docker daemon restart'ında da başlat (elle durdurulmuşsa hariç)
docker run -d --restart=unless-stopped nginx

Production tavsiyesi: unless-stopped kullan. Container çökerse otomatik başlar, Docker servisi yeniden başlarsa da başlar. Ama sen docker stop ile durdurduysan, kendiliğinden başlamaz.


Kaynak Limitleri — Kontrolü Kaybetme

Bir container kontrolsüzce tüm CPU'yu veya RAM'i tüketebilir. Bu, aynı sunucudaki diğer container'ları ve hatta host sistemi çökertebilir. Kaynak limitleri ile bunu önlersin:

# Memory limiti — 256MB'ı aşarsa container durdurulur
docker run -d --memory=256m nginx

# CPU limiti — maksimum yarım CPU core
docker run -d --cpus=0.5 nginx

# İkisi birlikte
docker run -d --memory=512m --cpus=1 myapp

Kaynak kullanımını izlemek için:

docker stats
# CONTAINER   CPU %   MEM USAGE / LIMIT   MEM %
# web-server  0.05%   5.2MiB / 256MiB     2.03%

Kaynak limitlerini Bölüm 4'te çok daha detaylı inceleyeceğiz.


Gerçek Dünya Örnekleri

Teoriyi yeterince konuştuk, şimdi gerçek uygulamalar çalıştıralım.

Örnek 1: PostgreSQL Veritabanı

Diyelim ki bir projede PostgreSQL lazım. Eskiden PostgreSQL'i indirip kurar, konfigüre eder, servis olarak ayarlardın. Docker ile:

docker run -d \
    --name postgres \
    -e POSTGRES_USER=admin \
    -e POSTGRES_PASSWORD=supersecret \
    -e POSTGRES_DB=myapp \
    -v pgdata:/var/lib/postgresql/data \
    -p 5432:5432 \
    --restart=unless-stopped \
    postgres:16

Tek komutla PostgreSQL çalışıyor! Veritabanına bağlanmak için:

docker exec -it postgres psql -U admin -d myapp

Bu seni PostgreSQL shell'ine düşürür. SQL yazabilir, tablo oluşturabilir, veri ekleyebilirsin:

myapp=# CREATE TABLE users (id SERIAL, name TEXT);
myapp=# INSERT INTO users (name) VALUES ('Docker Öğrencisi');
myapp=# SELECT * FROM users;
myapp=# \q

Örnek 2: Redis Cache

docker run -d \
    --name redis \
    -p 6379:6379 \
    -v redis-data:/data \
    --restart=unless-stopped \
    redis:7 \
    redis-server --appendonly yes --requirepass mypassword

Burada ilginç bir şey var — image adından sonra redis-server --appendonly yes --requirepass mypassword yazdık. Bu, container'ın varsayılan komutunu (CMD) override ediyor. Redis'e "kalıcı depolama aç ve şifre zorunlu tut" diyoruz.

docker exec -it redis redis-cli -a mypassword
127.0.0.1:6379> SET greeting "Merhaba Docker!"
127.0.0.1:6379> GET greeting
# "Merhaba Docker!"
127.0.0.1:6379> exit

Örnek 3: Node.js Geliştirme Ortamı

Bu örnek özellikle geliştirme sürecinde çok kullanışlı. Proje dizinini container'a bağlıyoruz — host'ta kodu düzenliyoruz, container'da çalışıyor:

mkdir myproject && cd myproject

# Basit bir Express server oluşturalım
cat > package.json << 'EOF'
{
  "name": "docker-demo",
  "version": "1.0.0",
  "scripts": { "start": "node server.js", "dev": "node --watch server.js" },
  "dependencies": { "express": "^4.18.0" }
}
EOF

cat > server.js << 'EOF'
const express = require('express');
const app = express();
app.get('/', (req, res) => {
  res.json({ message: 'Merhaba Docker!', time: new Date() });
});
app.listen(3000, () => console.log('Server 3000 portunda çalışıyor'));
EOF

# Container'da çalıştır
docker run -it --rm \
    --name node-dev \
    -v $(pwd):/app \
    -w /app \
    -p 3000:3000 \
    node:20 \
    sh -c "npm install && npm run dev"

Tarayıcıda http://localhost:3000 aç — JSON yanıtı göreceksin. En güzeli: server.js'i düzenle, kaydet — Node.js --watch modu sayesinde otomatik yeniden başlar!


Container Yönetim Komutları

Container çalıştırmayı öğrendik. Şimdi çalışan container'ları nasıl yöneteceğimize bakalım.

Listeleme

docker ps                    # Çalışan container'lar
docker ps -a                 # Tüm container'lar (durmuşlar dahil)
docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"  # Özel format

Yaşam Döngüsü

docker start web-server      # Durmuş container'ı başlat
docker stop web-server       # Nazikçe durdur (SIGTERM → 10s → SIGKILL)
docker restart web-server    # Yeniden başlat
docker kill web-server       # Anında durdur (SIGKILL)

İnceleme

docker logs web-server       # Loglar
docker logs -f web-server    # Canlı log takibi (tail -f gibi)
docker logs --tail 50 web-server  # Son 50 satır
docker inspect web-server    # Tüm detaylar (JSON)
docker stats web-server      # Kaynak kullanımı

Container İçi İşlemler

docker exec -it web-server bash     # Shell aç
docker exec web-server cat /etc/hosts  # Tek komut çalıştır
docker cp web-server:/var/log/ ./logs/  # Container → Host dosya kopyala
docker cp ./config.txt web-server:/app/ # Host → Container dosya kopyala

Temizlik

docker rm web-server               # Durmuş container'ı sil
docker rm -f web-server            # Çalışıyorsa bile zorla sil
docker container prune             # Tüm durmuş container'ları sil

En Sık Karşılaşılan Hatalar

Container Hemen Duruyor

docker run -d ubuntu
docker ps   # Boş! Container yok!
docker ps -a   # STATUS: Exited (0) 1 second ago

Bu çok yaygın ve kafa karıştırıcı. Neden? Çünkü Ubuntu image'ının varsayılan komutu bash. Ama -it flag'leri olmadan bash'e input gönderemezsin, bash yapacak bir şey bulamayıp kapanır, ve container da onunla birlikte durur.

Çözümler:

# İnteraktif mod ile
docker run -it ubuntu bash

# Veya sürekli çalışan bir komut ver
docker run -d ubuntu sleep infinity

# Veya bir servis çalıştır
docker run -d ubuntu sh -c "while true; do echo 'alive'; sleep 60; done"

Nginx, PostgreSQL gibi servis container'ları bu sorunu yaşamaz — çünkü zaten sürekli çalışan bir foreground prosesleri var.

Port Zaten Kullanımda

docker run -d -p 8080:80 nginx
# Error: port is already allocated

Başka bir proses (veya başka bir container) 8080 portunu kullanıyor. Hangi proses olduğunu bulmak için:

sudo lsof -i :8080
# veya
sudo ss -tlnp | grep 8080

Çözüm: farklı port kullan (-p 8081:80).

Volume İzin Sorunu

docker run -v $(pwd)/data:/data myapp
# Permission denied

Container içindeki kullanıcı ile host'taki dosya izinleri uyuşmuyordur. Çözüm:

# Doğru kullanıcı ID ile çalıştır
docker run --user $(id -u):$(id -g) -v $(pwd)/data:/data myapp

docker run Parametre Özeti

Bir container başlatırken en sık kullandığın parametreleri toparlayalım:

docker run \
    -d                              # Arka planda çalıştır
    --name mycontainer              # İsim ver
    -p 8080:80                      # Port eşle
    -v /host/path:/container/path   # Bind mount
    -v volume-name:/data            # Named volume
    -e KEY=VALUE                    # Environment variable
    --env-file .env                 # Env dosyasından yükle
    --restart=unless-stopped        # Restart policy
    --memory=512m                   # RAM limiti
    --cpus=1                        # CPU limiti
    --rm                            # Durdurulunca otomatik sil
    image:tag                       # Çalıştırılacak image
    command args                    # Özel komut (opsiyonel)

Bu parametrelerin hepsini ezberleme. İhtiyacın olduğunda docker run --help ile her zaman bakabilirsin. Ama en temel olanları — -d, --name, -p, -v, -e — zamanla parmağına oturacak.


Bu Derste Ne Öğrendik?

  • docker run, Docker'ın en temel komutu — bir image'dan container oluşturur ve başlatır.

  • -d arka planda çalıştırır, -it interaktif mod açar, --rm otomatik temizlik yapar, -p port eşler, -v volume bağlar.

  • Her container'a anlamlı --name ver ve production'da kaynak limitleri (--memory, --cpus) belirle.

  • --restart policy ile container çökme davranışını kontrol et — production'da unless-stopped kullan.

  • docker exec ile çalışan container'da komut çalıştır, docker logs ile logları takip et.

  • Container hemen duruyorsa, sürekli çalışan bir foreground process gerekli. Servis container'ları (Nginx, PostgreSQL) bunu otomatik sağlar.


Hands-On Pratik: Adım Adım Dene

Bu derste öğrendiklerini pekiştirmek için şu adımları sırayla uygula:

# 1. Docker versiyonunu kontrol et
docker version

# 2. Sistem bilgilerini gör
docker info

# 3. Hello World çalıştır
docker run --rm hello-world

# 4. İnteraktif Ubuntu shell aç
docker run -it --rm ubuntu bash
# İçeride: ls, pwd, whoami komutlarını dene
# exit ile çık

# 5. Arka planda Nginx başlat
docker run -d -p 8080:80 --name my-nginx nginx

# 6. Çalışan container'ları listele
docker ps

# 7. Container loglarını gör
docker logs my-nginx

# 8. Container'ın içine gir
docker exec -it my-nginx sh
# İçeride: cat /etc/nginx/nginx.conf dene
# exit ile çık

# 9. Container kaynak kullanımını gör
docker stats --no-stream my-nginx

# 10. Container'ı durdur ve sil
docker stop my-nginx
docker rm my-nginx

# 11. Tüm container'ları listele (durmuş olanlar dahil)
docker ps -a

# 12. Durmuş tüm container'ları temizle
docker container prune -f

# 13. PostgreSQL veritabanı başlat
docker run -d --name testdb \
    -e POSTGRES_PASSWORD=test123 \
    -p 5432:5432 \
    postgres:16

# 14. Veritabanına bağlan ve SQL çalıştır
docker exec -it testdb psql -U postgres -c "SELECT version();"

# 15. Temizlik
docker stop testdb
docker rm testdb
docker system prune -f

Bu 15 adımı sorunsuz tamamladıysan, docker run komutunu ve temel container yönetimini öğrendin demektir. Her adımda ne olduğunu gözlemle — çıktılara dikkat et, hata alırsan yukarıdaki "Sık Karşılaşılan Hatalar" bölümüne bak.


Gelişmiş Seçenekler — İleride Lazım Olacak

Şu an için bunları bilmen yeterli ama referans olarak not et:

Hostname ve DNS

# Container'a özel hostname ver
docker run -d --hostname myserver nginx

# DNS sunucusu belirle
docker run -d --dns 8.8.8.8 nginx

# Hosts dosyasına kayıt ekle
docker run -d --add-host=api.local:192.168.1.100 myapp

Healthcheck

Container'ın sağlıklı çalışıp çalışmadığını izlemek için:

docker run -d \
    --health-cmd="curl -f http://localhost/ || exit 1" \
    --health-interval=30s \
    --health-timeout=10s \
    --health-retries=3 \
    nginx

docker ps çıktısında STATUS sütununda (healthy) veya (unhealthy) görürsün.

Log Limitleri

Container loglarının disk'i doldurmasını önlemek için:

docker run -d \
    --log-opt max-size=10m \
    --log-opt max-file=3 \
    nginx

Her container için maksimum 30MB log (3 dosya × 10MB).

Network Seçenekleri

# Host'un network'ünü doğrudan kullan (Linux only)
docker run -d --network host nginx

# Özel network oluştur ve kullan
docker network create mynet
docker run -d --network mynet --name web nginx
docker run -d --network mynet --name api myapp
# web ve api birbirini isimle bulabilir!

# Network erişimini tamamen kapat
docker run --network none alpine ping google.com
# ağ erişimi yok

Network konusunu Bölüm 5'te derinlemesine ele alacağız.


Bölüm 1 tamamlandı! Container nedir, Docker ekosistemi ne içerir, nasıl kurulur ve nasıl container çalıştırılır — hepsini öğrendin. Bir sonraki bölümde Docker image kavramına derinlemesine dalacağız — image'lar nasıl çalışır, katmanlı dosya sistemi nedir, image'ları nasıl yönetirsin.