[{"data":1,"prerenderedAt":29},["ShallowReactive",2],{"article-docker-nedir-konteyner-image-dockerfile-temelleri":3,"article-related-docker-nedir-konteyner-image-dockerfile-temelleri":28},{"articleId":4,"title":5,"slug":6,"content":7,"summary":8,"featuredImage":9,"metaTitle":5,"metaDescription":10,"metaKeywords":11,"isPublished":12,"publishedAt":13,"references":14,"authors":14,"viewCount":15,"likeCount":15,"commentCount":15,"readingTime":16,"authorId":17,"categoryId":18,"categoryName":19,"tags":20,"isActive":12,"isDeleted":25,"createDate":26,"updatedDate":27,"deletedDate":14,"createdUserId":17,"updatedUserId":17,"deletedUserId":14},"d6cacc1b-e7f3-428a-b868-9cf94b01f531","Docker Nedir? Konteyner, Image ve Dockerfile Temelleri","docker-nedir-konteyner-image-dockerfile-temelleri","\u003Ch2>Çözdüğü Problem: \"Bende Çalışıyordu\"\u003C/h2>\n\u003Cp>Bir uygulamanın geliştirici makinesinde çalışıp sunucuda çalışmaması, yazılım dünyasının en eski sürtüşmelerinden biridir. Sebep genellikle sürüm, bağımlılık ya da yapılandırma farkıdır — makinede kurulu olan ama kimsenin farkında olmadığı bir kütüphane, farklı bir çalışma zamanı sürümü, eksik bir ortam değişkeni.\u003C/p>\n\u003Cp>Docker bu problemi kökten ele alır: uygulamayı yalnızca kodla değil, çalışması için gereken her şeyle birlikte paketler. Sonuç olarak aynı paket, geliştiricinin dizüstünde de, test sunucusunda da, bulutta da aynı şekilde davranır.\u003C/p>\n\n\u003Ch2>Konteyner ve Sanal Makine Aynı Şey Değil\u003C/h2>\n\u003Cp>Sanal makine, kendi işletim sistemi çekirdeğini taşır. Konteyner ise ana makinenin çekirdeğini paylaşır; yalnızca uygulama ve bağımlılıkları izole edilir.\u003C/p>\n\u003Ctable>\n\u003Cthead>\n\u003Ctr>\u003Cth>\u003C/th>\u003Cth>Sanal makine\u003C/th>\u003Cth>Konteyner\u003C/th>\u003C/tr>\n\u003C/thead>\n\u003Ctbody>\n\u003Ctr>\u003Ctd>Kendi çekirdeği\u003C/td>\u003Ctd>Var\u003C/td>\u003Ctd>Yok — ana makineyi paylaşır\u003C/td>\u003C/tr>\n\u003Ctr>\u003Ctd>Tipik boyut\u003C/td>\u003Ctd>GB'lar\u003C/td>\u003Ctd>MB'lar\u003C/td>\u003C/tr>\n\u003Ctr>\u003Ctd>Başlangıç süresi\u003C/td>\u003Ctd>Dakikalar\u003C/td>\u003Ctd>Saniyeler\u003C/td>\u003C/tr>\n\u003Ctr>\u003Ctd>Aynı sunucuda kaç tane\u003C/td>\u003Ctd>Onlarca\u003C/td>\u003Ctd>Yüzlerce\u003C/td>\u003C/tr>\n\u003Ctr>\u003Ctd>İzolasyon sınırı\u003C/td>\u003Ctd>Donanım düzeyi — keskin\u003C/td>\u003Ctd>Süreç düzeyi — daha yumuşak\u003C/td>\u003C/tr>\n\u003Ctr>\u003Ctd>Farklı işletim sistemi\u003C/td>\u003Ctd>Çalıştırabilir\u003C/td>\u003Ctd>Çekirdek uyumu gerekir\u003C/td>\u003C/tr>\n\u003C/tbody>\n\u003C/table>\n\u003Cp>Konteynerler çekirdek düzeyinde tam izolasyon sunmaz. Güvenlik sınırı sanal makine kadar keskin değildir; \u003Cstrong>güvenilmeyen kodu çalıştırıyorsanız\u003C/strong> bu ayrım mimari kararlarda belirleyici olur.\u003C/p>\n\n\u003Ch2>Image ve Container İlişkisi\u003C/h2>\n\u003Cp>Image, çalıştırılabilir bir şablondur: salt okunur, değişmez bir paket. Container ise o image'ın çalışan bir örneğidir. Sınıf ve nesne ilişkisine benzetmek, kavramı oturtmak için pratik bir yoldur.\u003C/p>\n\u003Cpre>\u003Ccode># Image indir (şablon)\ndocker pull mcr.microsoft.com/dotnet/aspnet:8.0\n\n# Aynı image'dan üç bağımsız container\ndocker run -d --name api-1 -p 5001:8080 bapati-api:1.4.0\ndocker run -d --name api-2 -p 5002:8080 bapati-api:1.4.0\ndocker run -d --name api-3 -p 5003:8080 bapati-api:1.4.0\n\n# Ne çalışıyor, ne kadar yer kaplıyor?\ndocker ps\ndocker image ls\ndocker stats --no-stream\u003C/code>\u003C/pre>\n\u003Cp>Her container kendi yazılabilir katmanına sahiptir ve birbirinden bağımsız çalışır. \u003Ccode>api-1\u003C/code> içinde bir dosya oluşturmanız \u003Ccode>api-2\u003C/code>'yi etkilemez — ve \u003Ccode>api-1\u003C/code> silindiğinde o dosya da gider.\u003C/p>\n\n\u003Ch2>Dockerfile ve Katman Mantığı\u003C/h2>\n\u003Cp>Dockerfile, image'ın nasıl oluşturulacağını anlatan tarif dosyasıdır. Her satır image'a yeni bir katman ekler ve \u003Cstrong>katmanlar önbelleğe alınır\u003C/strong>. Bu nedenle nadiren değişen adımları üste, sık değişen adımları alta yazmak build sürelerini belirgin biçimde kısaltır.\u003C/p>\n\u003Cpre>\u003Ccode># --- 1. AŞAMA: derleme ---\nFROM mcr.microsoft.com/dotnet/sdk:8.0 AS derleme\nWORKDIR /kaynak\n\n# Önce SADECE proje dosyaları: bağımlılıklar nadiren değişir,\n# bu katman kaynak kod değiştiğinde önbellekten gelir.\nCOPY *.sln .\nCOPY BapatiApi.API/*.csproj        BapatiApi.API/\nCOPY BapatiApi.Application/*.csproj BapatiApi.Application/\nRUN dotnet restore\n\n# Kaynak kod en sona: her commit'te değişen tek katman bu olsun\nCOPY . .\nRUN dotnet publish BapatiApi.API/BapatiApi.API.csproj -c Release -o /cikti\n\n# --- 2. AŞAMA: çalışma ---\n# SDK (~800 MB) nihai imaja girmez, yalnızca runtime (~220 MB) kalır\nFROM mcr.microsoft.com/dotnet/aspnet:8.0\nWORKDIR /uygulama\nCOPY --from=derleme /cikti .\n\n# root olarak çalıştırma\nRUN adduser --disabled-password --gecos \"\" bapati\nUSER bapati\n\nEXPOSE 8080\nENTRYPOINT [\"dotnet\", \"BapatiApi.API.dll\"]\u003C/code>\u003C/pre>\n\u003Cp>Bu dosyadaki üç karar, üç ayrı sorunu çözüyor:\u003C/p>\n\u003Ctable>\n\u003Cthead>\n\u003Ctr>\u003Cth>Karar\u003C/th>\u003Cth>Kazanç\u003C/th>\u003C/tr>\n\u003C/thead>\n\u003Ctbody>\n\u003Ctr>\u003Ctd>\u003Ccode>.csproj\u003C/code>'ları önce kopyalamak\u003C/td>\u003Ctd>Kod değiştiğinde \u003Ccode>restore\u003C/code> yeniden çalışmaz — build dakikalardan saniyelere iner\u003C/td>\u003C/tr>\n\u003Ctr>\u003Ctd>Çok aşamalı build\u003C/td>\u003Ctd>Derleme araçları nihai imaja girmez — boyut ~3 kat küçülür\u003C/td>\u003C/tr>\n\u003Ctr>\u003Ctd>\u003Ccode>USER bapati\u003C/code>\u003C/td>\u003Ctd>Container ele geçirilse bile root yetkisi yok\u003C/td>\u003C/tr>\n\u003C/tbody>\n\u003C/table>\n\u003Cp>Bir de \u003Ccode>.dockerignore\u003C/code> dosyası şart: onsuz \u003Ccode>COPY . .\u003C/code> satırı \u003Ccode>node_modules\u003C/code>, \u003Ccode>bin\u003C/code>, \u003Ccode>obj\u003C/code> ve \u003Ccode>.git\u003C/code> klasörlerini de build bağlamına taşır ve her build'i yavaşlatır.\u003C/p>\n\u003Cpre>\u003Ccode># .dockerignore\n**/bin\n**/obj\n**/node_modules\n**/.git\n**/.vs\n**/*.user\n**/appsettings.Development.json\u003C/code>\u003C/pre>\n\n\u003Ch2>Veri Nerede Durur? Volume Meselesi\u003C/h2>\n\u003Cp>Container silindiğinde içindeki yazılabilir katman da silinir. Veritabanı verisini container içinde tutmak bu nedenle kalıcı bir çözüm değildir.\u003C/p>\n\u003Cpre>\u003Ccode># YANLIŞ: container silindiğinde veri de gider\ndocker run -d --name db postgres:16\n\n# DOĞRU: veri adlandırılmış bir volume'da, container'dan bağımsız\ndocker volume create bapati-db-veri\ndocker run -d --name db \\\n  -v bapati-db-veri:/var/lib/postgresql/data \\\n  -e POSTGRES_PASSWORD_FILE=/run/secrets/db_sifre \\\n  postgres:16\n\n# Container'ı sil, yeniden oluştur — veri yerinde\ndocker rm -f db\ndocker run -d --name db -v bapati-db-veri:/var/lib/postgresql/data postgres:16\u003C/code>\u003C/pre>\n\u003Cp>Kalıcı olması gereken her şeyin volume üzerinde tutulması, en sık atlanan ama en pahalıya mal olan kurallardan biridir. Volume'un iki türü vardır: \u003Cem>adlandırılmış volume\u003C/em> (Docker yönetir, üretim için uygundur) ve \u003Cem>bind mount\u003C/em> (ana makinedeki bir klasörü bağlar, geliştirmede kod paylaşmak için pratiktir).\u003C/p>\n\n\u003Ch2>Docker Compose ile Çoklu Servis\u003C/h2>\n\u003Cp>Gerçek uygulamalar tek konteynerden oluşmaz: API, veritabanı, önbellek ve belki bir mesaj kuyruğu bir arada çalışır. Compose, bu servisleri tek bir yapılandırma dosyasında tanımlamanızı ve hepsini tek komutla ayağa kaldırmanızı sağlar.\u003C/p>\n\u003Cpre>\u003Ccode>services:\n  api:\n    build: .\n    ports:\n      - \"5000:8080\"\n    environment:\n      ConnectionStrings__Varsayilan: \"Host=db;Database=bapati;Username=bapati\"\n    depends_on:\n      db:\n        condition: service_healthy      # sadece \"başladı\" değil, \"hazır\"\n    restart: unless-stopped\n\n  db:\n    image: postgres:16\n    volumes:\n      - db-veri:/var/lib/postgresql/data\n    environment:\n      POSTGRES_DB: bapati\n      POSTGRES_USER: bapati\n      POSTGRES_PASSWORD: ${DB_SIFRE}    # .env dosyasından, dosyaya yazılmaz\n    healthcheck:\n      test: [\"CMD-SHELL\", \"pg_isready -U bapati\"]\n      interval: 5s\n      retries: 5\n\nvolumes:\n  db-veri:\u003C/code>\u003C/pre>\n\u003Cp>Dikkat edilecek iki nokta var. Birincisi: API, veritabanına \u003Ccode>localhost\u003C/code> ile değil \u003Cstrong>servis adıyla\u003C/strong> (\u003Ccode>Host=db\u003C/code>) bağlanır — Compose her servis için ağ içinde bir ad çözümlemesi kurar. İkincisi: \u003Ccode>depends_on\u003C/code> tek başına yalnızca \"başlatma sırasını\" belirler; veritabanının bağlantı kabul etmeye \u003Cem>hazır\u003C/em> olmasını beklemek için \u003Ccode>healthcheck\u003C/code> gerekir. Bu ayrım, \"API açılışta veritabanına bağlanamıyor ama yeniden başlatınca düzeliyor\" sorununun tam sebebidir.\u003C/p>\n\u003Cp>Yeni bir geliştiricinin projeye katıldığı ilk gün ortamı dakikalar içinde kurabilmesi, çoğu ekipte Compose'un en somut faydasıdır:\u003C/p>\n\u003Cpre>\u003Ccode>git clone https://github.com/bapati/api.git\ncd api\ncp .env.ornek .env\ndocker compose up -d          # hepsi ayakta\u003C/code>\u003C/pre>\n\n\u003Ch2>Yaygın Hatalar\u003C/h2>\n\u003Ctable>\n\u003Cthead>\n\u003Ctr>\u003Cth>Hata\u003C/th>\u003Cth>Sonucu\u003C/th>\u003Cth>Doğrusu\u003C/th>\u003C/tr>\n\u003C/thead>\n\u003Ctbody>\n\u003Ctr>\u003Ctd>Parolayı Dockerfile'a yazmak\u003C/td>\u003Ctd>Katmanlarda kalıcı olur, imajı alan herkes görür\u003C/td>\u003Ctd>Ortam değişkeni ya da secret\u003C/td>\u003C/tr>\n\u003Ctr>\u003Ctd>\u003Ccode>latest\u003C/code> etiketi\u003C/td>\u003Ctd>Bugün çalışan yapı yarın farklı sürümle gelir\u003C/td>\u003Ctd>Sürümü sabitle: \u003Ccode>postgres:16.2\u003C/code>\u003C/td>\u003C/tr>\n\u003Ctr>\u003Ctd>root olarak çalıştırmak\u003C/td>\u003Ctd>Container ele geçerse yetki tam\u003C/td>\u003Ctd>\u003Ccode>USER\u003C/code> ile yetkisiz kullanıcı\u003C/td>\u003C/tr>\n\u003Ctr>\u003Ctd>Container'a SSH ile bağlanmak\u003C/td>\u003Ctd>Değişiklik kayıt dışı kalır, yeniden üretilemez\u003C/td>\u003Ctd>Değişikliği Dockerfile'a yaz\u003C/td>\u003C/tr>\n\u003Ctr>\u003Ctd>Log'u dosyaya yazmak\u003C/td>\u003Ctd>Container silinince log da gider\u003C/td>\u003Ctd>\u003Ccode>stdout\u003C/code>'a yaz, Docker toplasın\u003C/td>\u003C/tr>\n\u003Ctr>\u003Ctd>\u003Ccode>.dockerignore\u003C/code> yok\u003C/td>\u003Ctd>Build bağlamı yüzlerce MB olur\u003C/td>\u003Ctd>bin, obj, node_modules hariç\u003C/td>\u003C/tr>\n\u003Ctr>\u003Ctd>Sağlık kontrolü yok\u003C/td>\u003Ctd>Ölü container ayakta görünür\u003C/td>\u003Ctd>\u003Ccode>HEALTHCHECK\u003C/code> tanımla\u003C/td>\u003C/tr>\n\u003C/tbody>\n\u003C/table>\n\u003Cp>Parola konusunda sık yapılan bir incelik hatası da şudur: bir katmanda dosya oluşturup sonraki katmanda silmek onu \u003Cstrong>imajdan silmez\u003C/strong>. Katmanlar yığın gibi birikir; silinen dosya alt katmanda durmaya devam eder ve \u003Ccode>docker history\u003C/code> ile görülebilir.\u003C/p>\n\n\u003Ch2>Üretime Çıkarken: Boyut, Sağlık ve Tarama\u003C/h2>\n\u003Cp>Geliştirmede çalışan bir yapılandırma üretim için yeterli değildir. Üç şey eklenir: imaj küçültme, sağlık kontrolü ve güvenlik taraması.\u003C/p>\n\u003Cp>İmaj boyutu yalnızca disk meselesi değildir — her dağıtımda ağdan indirilir, her ölçekleme adımında yeniden çekilir. Temel imaj seçimi tek başına büyük fark yaratır:\u003C/p>\n\u003Ctable>\n\u003Cthead>\n\u003Ctr>\u003Cth>Temel imaj\u003C/th>\u003Cth>Yaklaşık boyut\u003C/th>\u003Cth>Not\u003C/th>\u003C/tr>\n\u003C/thead>\n\u003Ctbody>\n\u003Ctr>\u003Ctd>\u003Ccode>dotnet/sdk:8.0\u003C/code>\u003C/td>\u003Ctd>~800 MB\u003C/td>\u003Ctd>Yalnızca derleme aşamasında\u003C/td>\u003C/tr>\n\u003Ctr>\u003Ctd>\u003Ccode>dotnet/aspnet:8.0\u003C/code>\u003C/td>\u003Ctd>~220 MB\u003C/td>\u003Ctd>Standart çalışma imajı\u003C/td>\u003C/tr>\n\u003Ctr>\u003Ctd>\u003Ccode>dotnet/aspnet:8.0-alpine\u003C/code>\u003C/td>\u003Ctd>~110 MB\u003C/td>\u003Ctd>Daha küçük, farklı libc\u003C/td>\u003C/tr>\n\u003Ctr>\u003Ctd>\u003Ccode>node:20\u003C/code>\u003C/td>\u003Ctd>~1,1 GB\u003C/td>\u003Ctd>Tam araç zinciri\u003C/td>\u003C/tr>\n\u003Ctr>\u003Ctd>\u003Ccode>node:20-alpine\u003C/code>\u003C/td>\u003Ctd>~140 MB\u003C/td>\u003Ctd>Yerel modüllerde derleme gerekebilir\u003C/td>\u003C/tr>\n\u003C/tbody>\n\u003C/table>\n\u003Cp>Sağlık kontrolü ise orkestratörün \"bu container gerçekten hizmet veriyor mu\" sorusunu cevaplamasını sağlar. Süreç ayakta ama uygulama kilitlenmişse, sağlık kontrolü olmadan hiçbir şey fark etmez:\u003C/p>\n\u003Cpre>\u003Ccode>HEALTHCHECK --interval=30s --timeout=3s --start-period=20s --retries=3   CMD wget -qO- http://localhost:8080/saglik || exit 1\u003C/code>\u003C/pre>\n\u003Cp>Son olarak imajı yayınlamadan önce taramak gerekir. Kendi kodunuz temiz olsa bile temel imajdaki bir kütüphane bilinen bir açık taşıyor olabilir:\u003C/p>\n\u003Cpre>\u003Ccode># Bilinen güvenlik açıklarını tara\ndocker scout cves bapati-api:1.4.0\n\n# Katman katman ne kadar yer kaplıyor, hangi adım şişiriyor?\ndocker history bapati-api:1.4.0 --no-trunc\u003C/code>\u003C/pre>\n\u003Cp>Bu üç adımı dağıtım hattına (CI) koymak, sorunları üretimde değil derleme aşamasında yakalamayı sağlar.\u003C/p>\n\n\u003Ch2>Konteynerin Zihniyeti\u003C/h2>\n\u003Cp>Docker'ı verimli kullanmanın anahtarı bir araç değil bir yaklaşım: container'lar \u003Cstrong>tek iş yapan ve gerektiğinde atılabilen\u003C/strong> birimlerdir. Bir container'ı silip yeniden oluşturmak, onu tamir etmekten daha ucuz olmalıdır.\u003C/p>\n\u003Cp>Bu yaklaşım üç pratik kurala iner: durumu container dışında tut (volume ya da veritabanı), yapılandırmayı ortam değişkeniyle ver, ve her değişikliği imaja yaz. Bu üçü sağlandığında ölçekleme, güncelleme ve geri alma işlemlerinin hepsi tek komuta iner.\u003C/p>\n\n\u003Ch2>Geliştirme Ortamında Docker\u003C/h2>\u003Cp>Docker’ın en hızlı karşılık verdiği yer üretim değil, geliştirme ortamıdır. Bir projeye yeni katılan geliştiricinin veritabanı, önbellek ve mesaj kuyruğu kurmakla geçirdiği ilk gün, hazır bir yapılandırma dosyasıyla birkaç dakikaya iner.\u003C/p>\u003Cp>Bunun ötesinde bir fayda daha var: \u003Cstrong>sürüm çakışmalarının ortadan kalkması\u003C/strong>. Aynı makinede iki farklı projenin iki farklı veritabanı sürümüne ihtiyaç duyması, konteyner olmadan zahmetli bir iştir; konteynerle her proje kendi sürümünü taşır.\u003C/p>\u003Cp>Geliştirme ortamında sık kullanılan bir kolaylık da kaynak kodun konteynere bağlanmasıdır. Böylece kod değişikliği için imajın yeniden oluşturulması gerekmez; dosya değişir, uygulama yeniden başlar. Bu düzen, üretimde tercih edilmez ama geliştirmede döngüyü belirgin biçimde hızlandırır.\u003C/p>\u003Chr>\n\u003Cp>\u003Cstrong>Daha fazlası:\u003C/strong> Docker'ı uygulamalı anlattığımız bölüm 'Her Yazılımcının Bilmesi Gerekenler' serimizde; ayrıca BapatiVault serisinin final bölümünde bir .NET 8 API'sini Docker ile paketleyip dağıtıyoruz.\u003C/p>\n\u003Cp>\u003Ca href='/videos/docker-konteynerler-nedir-image-container-dockerfile-compose'>Videoyu sitemizde izle\u003C/a> &nbsp;·&nbsp; \u003Ca href='https://youtu.be/7fOdCXsZVXM' target='_blank' rel='noopener'>YouTube'da aç\u003C/a> &nbsp;·&nbsp; \u003Ca href='https://www.youtube.com/@BapatiTech' target='_blank' rel='noopener'>Kanala abone ol\u003C/a>\u003C/p>\u003Chr>\u003Cp>\u003Cstrong>Daha fazlası:\u003C/strong> Bir .NET uygulamasının konteynerle paketlenip dağıtıma hazırlanmasını uygulamalı gösterdiğimiz bölümle devam edebilirsiniz.\u003C/p>\u003Cp>\u003Ca href='/videos/unit-test-docker-net-8-xunit-moq-deploy-seri-finali-bapativault-bolum-1212'>Videoyu sitemizde izle\u003C/a> &nbsp;·&nbsp; \u003Ca href='https://youtu.be/eL7BMwsm9zs' target='_blank' rel='noopener'>YouTube'da aç\u003C/a> &nbsp;·&nbsp; \u003Ca href='https://www.youtube.com/@BapatiTech?sub_confirmation=1' target='_blank' rel='noopener'>Bapati kanalına abone ol\u003C/a>\u003C/p>","Docker nedir, konteyner ile sanal makine arasındaki fark ne? Image, Dockerfile, katman mantığı ve Compose temelleri sade anlatımla ele alınıyor.","https://img.youtube.com/vi/7fOdCXsZVXM/hqdefault.jpg","Docker nedir, konteyner ile sanal makine farkı ne? Image, Dockerfile, katman mantığı, volume ve Compose temelleri sade ve uygulamalı anlatımla.","docker, konteyner, container, image, dockerfile, docker compose, devops, sanallaştırma, dağıtım, deploy, mikroservis",true,"2026-07-27T22:02:00",null,0,6,"ea4ea297-567a-491b-ac52-37db0674498b","e43829ce-9504-4ccf-bbd6-9861953242aa","DevOps",[21],{"tagId":22,"name":23,"color":24},"3d2fc7de-a2ad-404e-8099-b4b74ec9bc22","Docker","#2496ED",false,"2026-07-27T19:02:02.77665","2026-08-23T13:45:15.0665551",[],1789725852008]