---
title: 'İmaj ve Katman Modeli'
source: 'https://academia.sh/tr/kurslar/konteynerler/imaj-ve-katman-modeli'
course: Konteynerler
language: tr
updated: '2026-08-17T18:09:04+00:00'
license: 'CC BY-SA 4.0'
---

# İmaj ve Katman Modeli

İmaj sıralı bir katman listesi olarak ölçülür: iki servisin ortak temel üzerine kurulduğunda kaç katmanı paylaştığı, kaç baytın bir kez saklandığı ve düz kopyalamaya göre kazancın ne olduğu sayılır; bir alt katman değişince kaç üst katmanın zincir kimliğinin geçersizleştiği ve silinen bir dosyanın depoda kaç bayt olarak durduğu ölçülür.

Önceki konu yalıtımın ne olduğunu tanımladı ve bir sürecin çevresine çekilen sınırın neyi kaç
bayta yalıttığını ölçtü. O ölçümlerin tamamı boyunca çalıştırılan şeyin **nereden geldiği** hiç
sorulmadı. Yalıtılan süreç bir dosya sisteminin içinde açılır ve o dosya sistemi bir yerden
gelir; bu ders onun nereden geldiğini ölçer.

Önceki kursta yapı çıktısı tek bir nesne olarak tanımlanmış, değişmezlik ilkesi ve içerik özeti
orada ölçülmüştü. Konteyner çıktısı aynı ilkeye bağlıdır — bir kez üretilir, yerinde
değiştirilmez, kimliği içeriğinin özetidir — ama tek dosya değildir. **İmaj**, sıralı bir
**katman** listesidir ve bu ayrımın nedeni sayılabilir: iki servis aynı tabanı kullandığında tek
dosyalık çıktı iki tam kopya saklar, katmanlı çıktı ortak bölümü bir kez saklar. Sorular
şunlardır: kaç katman paylaşılır, kaç bayt bir kez saklanır, bir alt katman değişince üstünde ne
geçersizleşir?

**IM1.** Aşağıdaki katman modeli `node` ile kurulur ve gerçek dizinler üzerinde koşar; gerçek bir
konteyner çalıştırılmaz. Katman bir dizindir, imaj bir katman adı listesidir. **IM2.** İçerik
özeti, sıralı yol ve bayt çiftleri üzerinden alınan sha256 değerinin ilk on iki onaltılık
basamağıdır; kısaltma okunabilirlik içindir ve önceki kursta kullanılan biçimle aynıdır.
**IM3.** Kurgudaki bölgesel ölçüm ağının iki servisi ölçülür: su sayacı okumalarını toplayan
servis ve okumaları doğrulayan servis. Ağ ve servisler kurgudur.

## Katman, İmaj, Zincir Kimliği

Katman modelinin üç parçası vardır. **Katman**, bir dosya kümesidir ve kendi içerik özetiyle
adlandırılır. **İmaj**, alttan üste sıralı bir katman listesidir; çalıştırılacak dosya sistemi bu
listenin sırayla üst üste bindirilmesiyle oluşur. **Zincir kimliği**, bir katmanın imaj içindeki
konumunu adlandırır ve önceki zincir kimliği ile katmanın içerik özetinden türetilir — aynı
katman iki farklı imajda aynı içerik özetini taşır ama altındaki yığın farklıysa farklı zincir
kimliği alır. Ayrım, ölçümün geri kalanının dayandığı yerdir.

**IM4.** Katman içerikleri satır sayısıyla ölçeklenen üretilmiş dosyalardır; ölçülen büyüklükler
bu üretimin gerçek bayt karşılığıdır, bir ürünün gerçek imaj boyutu değildir.

```js
// olcum-agi/katman.mjs — katmanlari gercek dizinler olarak kurar (model)
import { mkdirSync, writeFileSync, readFileSync, readdirSync, rmSync } from "node:fs";
import { createHash } from "node:crypto";

const KOK = "katmanlar";
const ozetle = (s) => createHash("sha256").update(s).digest("hex").slice(0, 12);

// Katman govdesi: satir sayisiyla olceklenen, uretimi yinelenebilir dosya icerigi.
export const govde = (ad, satir) =>
  Array.from({ length: satir }, (_, i) => `// ${ad} ${i}\nexport const a${i} = ${i * 7};\n`).join("");

export const KATMAN = {
  "temel-kok": { "kok/kabuk.js": govde("kabuk", 30), "kok/saat.js": govde("saat", 14) },
  "ortak-kutuphane": { "lib/olcu.js": govde("olcu", 120), "lib/kod.js": govde("kod", 46) },
  "ortak-ayar": { "ayar/bolge.json": '{"bolge":"kuzey","sayac":41820}\n' },
  "toplayici-bagimlilik": { "bagimlilik/kuyruk.js": govde("kuyruk", 190), "bagimlilik/csv.js": govde("csv", 62) },
  "toplayici-kaynak": { "uygulama/topla.js": govde("topla", 34), "uygulama/giris.js": govde("giris", 9) },
  "dogrulayici-bagimlilik": { "bagimlilik/kural.js": govde("kural", 88) },
  "dogrulayici-kaynak": { "uygulama/dogrula.js": govde("dogrula", 27), "uygulama/giris.js": govde("dgiris", 11) },
};

export const kur = (tanim = KATMAN) => {
  rmSync(KOK, { recursive: true, force: true });
  for (const [ad, dosyalar] of Object.entries(tanim))
    for (const [yol, icerik] of Object.entries(dosyalar)) {
      mkdirSync(`${KOK}/${ad}/${yol}`.split("/").slice(0, -1).join("/"), { recursive: true });
      writeFileSync(`${KOK}/${ad}/${yol}`, icerik);
    }
};

// Diskteki gercek dizini gezer; katmanin dosya listesi, bayti ve icerik ozeti buradan cikar.
export const gez = (ad, alt = "") => {
  const kok = `${KOK}/${ad}${alt}`;
  return readdirSync(kok, { withFileTypes: true }).flatMap((g) =>
    g.isDirectory() ? gez(ad, `${alt}/${g.name}`) : [`${alt}/${g.name}`.slice(1)]).sort();
};

export const katman = (ad) => {
  const yollar = gez(ad);
  const govdeler = yollar.map((y) => readFileSync(`${KOK}/${ad}/${y}`));
  return { ad, dosya: yollar.length, yollar,
    bayt: govdeler.reduce((t, g) => t + g.length, 0),
    ozet: ozetle(yollar.map((y, i) => `${y}\n${govdeler[i]}`).join("\n")) };
};

// Zincir kimligi: onceki zincirin kimligi ile katmanin icerik ozetinden turer.
export const zincir = (adlar) =>
  adlar.reduce((z, ad) => [...z, ozetle((z.at(-1) ?? "") + katman(ad).ozet)], []);

export const TOPLAYICI = ["temel-kok", "ortak-kutuphane", "ortak-ayar", "toplayici-bagimlilik", "toplayici-kaynak"];
export const DOGRULAYICI = ["temel-kok", "ortak-kutuphane", "ortak-ayar", "dogrulayici-bagimlilik", "dogrulayici-kaynak"];
```

Yığının sırası rastgele değildir: altta değişme sıklığı en düşük olan taban, üstte en sık değişen
uygulama kaynağı durur. Bu sıranın karşılığı bir sonraki ölçümde çıkar.

## Paylaşılan Katmanın Ölçüsü

İki servis aynı taban üzerine kurulur: kök dosyaları, ortak ölçü kütüphanesi ve bölge ayarı üç
katmandır. Üstlerinde her servisin kendi bağımlılık ve kaynak katmanları durur.

```js
// olcum-agi/olc.mjs — iki imajin katman paylasimini ve depo kazancini sayar
import { kur, katman, zincir, TOPLAYICI, DOGRULAYICI } from "./katman.mjs";

kur();
const hepsi = [...new Set([...TOPLAYICI, ...DOGRULAYICI])].map(katman);
console.log("katman".padEnd(24) + "dosya  bayt   icerik ozeti");
for (const k of hepsi)
  console.log(k.ad.padEnd(24) + String(k.dosya).padStart(3) + String(k.bayt).padStart(8) + "   " + k.ozet);

const boyut = (imaj) => imaj.reduce((t, ad) => t + katman(ad).bayt, 0);
const paylasilan = TOPLAYICI.filter((ad) => DOGRULAYICI.includes(ad));
const depo = hepsi.reduce((t, k) => t + k.bayt, 0);
const duz = boyut(TOPLAYICI) + boyut(DOGRULAYICI);

console.log(`\nokuma-toplayici: ${TOPLAYICI.length} katman, ${boyut(TOPLAYICI)} bayt`);
console.log(`dogrulayici    : ${DOGRULAYICI.length} katman, ${boyut(DOGRULAYICI)} bayt`);
console.log(`paylasilan katman ${paylasilan.length}, bir kez saklanan ${boyut(paylasilan)} bayt`);
console.log(`duz kopyalama ${duz} bayt / katman deposu ${hepsi.length} katman ${depo} bayt`);
console.log(`kazanc ${duz - depo} bayt, %${(100 - (depo * 100) / duz).toFixed(1)}`);
console.log("zincir kimlikleri (toplayici): " + zincir(TOPLAYICI).map((z) => z.slice(0, 8)).join(" "));
```

```
katman                  dosya  bayt   icerik ozeti
temel-kok                 2    1497   7388fc361497
ortak-kutuphane           2    5730   9a6817a68730
ortak-ayar                1      32   48b10c98a78a
toplayici-bagimlilik      2    9291   906f2e7219b3
toplayici-kaynak          2    1482   af5db4e03ee4
dogrulayici-bagimlilik    1    3131   fcc132f093eb
dogrulayici-kaynak        2    1363   f578b5ac2648

okuma-toplayici: 5 katman, 18032 bayt
dogrulayici    : 5 katman, 11753 bayt
paylasilan katman 3, bir kez saklanan 7259 bayt
duz kopyalama 29785 bayt / katman deposu 7 katman 22526 bayt
kazanc 7259 bayt, %24.4
zincir kimlikleri (toplayici): 6555bbc9 54daa57b adf0e7c1 3334e87d ad53ce55
```

İki imajın toplam boyutu **29 785 bayt**, katman deposunda saklanan ise **22 526 bayt**: ortak üç
katmanın **7 259 baytı** iki imaj için bir kez saklanır, kazanç yüzde 24,4'tür. Ölçünün okunması
gereken yeri oran değil, oranın **nereden geldiğidir**: kazanç, paylaşılan tabanın toplam içindeki
payı kadardır. Her servisin kendi bağımlılık katmanı büyüdükçe oran düşer, ortak taban büyüdükçe
yükselir. İki servis yerine yirmi servis aynı tabanı kullanırsa aynı 7 259 bayt yirmi imaj için bir
kez saklanır ve tasarruf katman sayısıyla değil, **paylaşan imaj sayısıyla** çarpılır.

Bu, önceki kursun tek dosyalık yapı çıktısına göre kazanılan şeydir. Aynı ölçüde ortamdan çıkarılan
fark da buradadır: ortak kütüphanenin sürümü ve bölge ayarı artık çalıştırılan makinede kurulu
olan bir şey değil, çıktının **içinde** duran ve özetle adlandırılan iki katmandır. Ortamda o
kütüphanenin başka bir sürümünün bulunması ölçümü değiştirmez, çünkü ölçülen dosya sistemi
katmanlardan doğar.

## Bir Alt Katman Değiştiğinde

Katmanlı çıktının bedeli, katmanların birbirine zincirle bağlı olmasıdır. Ortak kütüphaneye tek bir
satır eklenir ve iki imajda ne değiştiği sayılır.

**IM5.** Değişiklik en küçük ölçekte tutulur — ortak kütüphanenin bir dosyasına tek satır eklenir —
ki geçersizleşen zincirin uzunluğu değişikliğin büyüklüğünden değil, yalnız konumundan gelsin.
**IM6.** Silme, üst katmana konan bir işaret dosyasıyla modellenir: `silindi/` önekiyle yazılan
boş bir yol, alttaki aynı yolu görünümden çıkarır. Gerçek birleşim dosya sistemlerinde bu işaretin
biçimi başkadır, davranışı aynıdır.

```js
// olcum-agi/degis.mjs — alt katman degisince ne gecersizlesir, silinen dosya nerede kalir
import { writeFileSync, readFileSync } from "node:fs";
import { kur, katman, zincir, govde, KATMAN, TOPLAYICI, DOGRULAYICI } from "./katman.mjs";

kur();
const once = { t: zincir(TOPLAYICI), d: zincir(DOGRULAYICI) };
const oncekiOzet = Object.fromEntries([...TOPLAYICI, ...DOGRULAYICI].map((a) => [a, katman(a).ozet]));
const eskiBayt = katman("ortak-kutuphane").bayt;

writeFileSync("katmanlar/ortak-kutuphane/lib/olcu.js", govde("olcu", 121)); // tek satir eklendi
const sonra = { t: zincir(TOPLAYICI), d: zincir(DOGRULAYICI) };
const ozetDegisen = [...new Set([...TOPLAYICI, ...DOGRULAYICI])].filter((a) => katman(a).ozet !== oncekiOzet[a]);
const zincirDegisen = ["t", "d"].map((i) => once[i].filter((z, s) => z !== sonra[i][s]).length);

console.log(`icerik ozeti degisen katman : ${ozetDegisen.length} (${ozetDegisen.join(", ")})`);
console.log(`zincir kimligi gecersizlesen: ${zincirDegisen.reduce((a, b) => a + b)} (imaj basina ${zincirDegisen.join(", ")})`);
console.log(`icerigi ayni kalan ust katman: ${[...new Set([...TOPLAYICI, ...DOGRULAYICI])].length - ozetDegisen.length - 1}`);
console.log(`deponun buyumesi: ${katman("ortak-kutuphane").bayt} bayt (eski surum ${eskiBayt} bayt yerinde durur)`);

// Ust katman: bir yolu golgeler, bir yolu siler. Silme, alt katmani degil gorunumu degistirir.
kur({ ...KATMAN, "toplayici-yama": { "ayar/bolge.json": '{"bolge":"kuzey","sayac":41820,"tur":"yama"}\n',
  "silindi/lib/kod.js": "" } });
const yigin = [...TOPLAYICI, "toplayici-yama"];

const gorunum = new Map();
let golge = 0, silinenBayt = 0;
for (const ad of yigin)
  for (const yol of katman(ad).yollar) {
    if (yol.startsWith("silindi/")) {
      const hedef = yol.slice(8);
      silinenBayt += readFileSync(`katmanlar/${gorunum.get(hedef)}/${hedef}`).length;
      gorunum.delete(hedef);
    } else {
      if (gorunum.has(yol)) { golge++; silinenBayt += readFileSync(`katmanlar/${gorunum.get(yol)}/${yol}`).length; }
      gorunum.set(yol, ad);
    }
  }

const yiginBayt = yigin.reduce((t, ad) => t + katman(ad).bayt, 0);
console.log(`\nyigindaki katman ${yigin.length}, yigindaki toplam bayt ${yiginBayt}`);
console.log(`birlesim gorunumundeki dosya ${gorunum.size}, golgelenen yol ${golge}, silinen yol 1`);
console.log(`gorunumde olmayan ama depoda duran bayt: ${silinenBayt}`);
console.log("gorunumde lib/kod.js var mi: " + gorunum.has("lib/kod.js"));
```

```
icerik ozeti degisen katman : 1 (ortak-kutuphane)
zincir kimligi gecersizlesen: 8 (imaj basina 4, 4)
icerigi ayni kalan ust katman: 5
deponun buyumesi: 5767 bayt (eski surum 5730 bayt yerinde durur)

yigindaki katman 6, yigindaki toplam bayt 18077
birlesim gorunumundeki dosya 8, golgelenen yol 1, silinen yol 1
gorunumde olmayan ama depoda duran bayt: 1559
gorunumde lib/kod.js var mi: false
```

Tek satırlık bir değişiklik **bir** katmanın içerik özetini değiştirir ama **sekiz** zincir
kimliğini geçersizleştirir: iki imajın her birinde değişen katman ve onun üstündeki üç katman.
Üstteki beş ayrı katmanın içeriği bit düzeyinde aynı kalır; geçersizleşen şey içerik değil,
**konumdur**. Değişiklik ne kadar aşağıdaysa geçersizleşen zincir o kadar uzar — bir satırın
maliyeti, satırın kendisi değil, üstünde kaç katman olduğudur.

İkinci bedel depodadır. Değişmezlik ilkesi gereği eski katman silinmez: depo **5 730 baytlık**
sürümü yerinde tutar ve **5 767 baytlık** yenisini yanına ekler. Katman deposu yalnız büyür; iki
sürüm arasında bir satırlık fark olması bunu değiştirmez, çünkü katman içerik özetiyle adlanır ve
içeriği değişen katman yeni bir nesnedir. Küçük ve sık değişen katmanları üste, büyük ve seyrek
değişenleri alta koymanın karşılığı bu iki sayıdır.

Aynı ölçüm ters yönden de okunur. Aynı model üzerinde iki uç denendiğinde sayılar şöyle çıkar: en
üstteki kaynak katmanı değiştiğinde geçersizleşen zincir kimliği toplayıcı imajında **1**,
doğrulayıcı imajında **0**; en alttaki kök katmanı değiştiğinde imaj başına **5**, toplam **10**.
Aynı büyüklükteki bir değişikliğin bedeli konumuna göre birden ona kadar oynar. Yığın sırası bu
yüzden bir düzen tercihi değil, bir
maliyet kararıdır: her katmanın konumu, o katman değiştiğinde ödenecek bedeli önceden belirler.
Ölçünün karar taşıyan biçimi budur — katman sayısı tek başına iyi ya da kötü değildir, katmanın
**hangi sıklıkta değiştiği** ile **üstünde kaç katman olduğu** çarpımı bir bedeldir.

## Birleşim Görünümünün Gizlediği

Katmanlar üst üste bindirilirken bir **birleşim dosya sistemi** görünümü doğar: aynı yol iki
katmanda varsa üstteki kazanır, üst katmandaki bir silme işareti alttaki dosyayı görünümden
çıkarır. Ölçüm, görünümün gizlediğini sayar. Altı katmanlık yığın **18 077 bayt** taşır, birleşim
görünümünde **8 dosya** görünür; bir yol gölgelenmiş, bir yol silinmiştir. Ama görünümden çıkan
**1 559 bayt** hâlâ depodadır ve imajın parçasıdır.

Yalıtımın delindiği yer burasıdır. Katman modeli dosya sistemini ortamdan çıkarır ve çıktının
içine alır; karşılığında çıktının **geçmişini de** içine alır. Bir üst katmanda silinen dosya
görünümde yoktur, imajda vardır: alt katman diskte durduğu ve içerik özetiyle çözülebildiği için
imajı eline geçiren biri o dosyayı okuyabilir. Silme bir görünüm işlemidir, bir depo işlemi
değil.

```bash
# dogrula.sh — katmanlar diskte gercek dizin mi, silinen dosya hala orada mi
find katmanlar -type f | wc -l
ls katmanlar/toplayici-yama/silindi/lib/
wc -c katmanlar/ortak-kutuphane/lib/kod.js
```

```
      14
kod.js
    1527 katmanlar/ortak-kutuphane/lib/kod.js
```

Kabuktan bakıldığında yedi katmanın toplam on dört dosyası diskte durur; üst katmanda silme
işareti bulunan `lib/kod.js`, alt katmanda 1 527 baytlık gerçek içeriğiyle okunabilir hâldedir.
Birleşim görünümü onu göstermez, dosya sistemi gösterir.

## Katmanın Taşımadığı

Buraya kadarki ölçümler katman modelinin çıktının içine **aldığı** şeyi saydı: dosya sistemi
düzeni, kütüphane sürümü, ayar dosyası. Yalıtım bütçesinin diğer yarısı, içine alınmayanlardır.
Katman bir dosya kümesidir — süreç değildir, çekirdek değildir, saat değildir. Yığının en
altındaki `temel-kok` katmanı da yalnız dosyalardan oluşur; imaj çalıştığında altında duran
çekirdek, çalıştırıldığı makinenin çekirdeğidir.

Bunun üç somut karşılığı vardır. Birincisi işlemci mimarisi: katmanlardaki çalıştırılabilir
dosyalar bir mimari için üretilir, imaj bu bağı içinde taşımaz, dışarıda varsayar. İçerik özeti
dosyaların baytlarını adlandırır, o baytların hangi mimaride anlam taşıdığını değil; aynı özet,
başka bir mimaride çalışmayan bir dosya sistemi tanımlayabilir. İkincisi çekirdek arayüzü: katman
içindeki bir dosya ortamda bulunmayan bir çekirdek yeteneğini çağırırsa imaj kusursuz biçimde
çözülür, zincir kimlikleri doğrulanır ve süreç yine de başlamaz. Üçüncüsü makine künyesi: önceki
kursta yeniden üretilebilirliği bozan kaynaklar arasında sayılan zaman damgası ve mutlak yol,
katman içeriğine yazıldığı anda katmanın içerik özetine karışır. Katman modeli bu kaynakları
kapatmaz; yalnız nereye yazıldıklarını görünür kılar, çünkü artık ölçülebilir bir nesnenin
içindedirler.

Ayrım tek cümleye iner: imaj **ne çalıştırılacağını** taşır, **nerede çalıştırılacağını** taşımaz.
Bu dersin ölçtüğü 22 526 baytlık katman deposu, ortamdan çıkarılan farkın tamamıdır; geri kalanı
makinenin kendisi olarak durur. Yalıtım bütçesinin bu dersteki hesabı üç kalemdir: çıkarılan fark
bir dosya sistemi, bedeli 22 526 bayt ile her değişiklikte sekiz zincir kimliği, delindiği yer ise
görünümden çıkıp depoda kalan 1 559 bayttır.

## Özet

- İmaj tek dosyalık bir yapı çıktısı değil, alttan üste sıralı bir katman listesidir; her katman
  kendi içerik özetiyle, imaj içindeki her konum ise önceki zincirden ve katman özetinden türeyen
  bir zincir kimliğiyle adlanır.
- Ortak temel üzerine kurulan iki imaj üç katmanı paylaştı: düz kopyalamada 29 785 bayt olan
  toplam, katman deposunda 22 526 bayta indi; 7 259 bayt bir kez saklandı, kazanç yüzde 24,4 oldu.
  Kazanç paylaşan imaj sayısıyla çarpılır, katman sayısıyla değil.
- Ortak kütüphaneye eklenen tek satır bir katmanın içerik özetini değiştirdi ama sekiz zincir
  kimliğini geçersizleştirdi; içeriği bit düzeyinde aynı kalan beş üst katman yeni konum kimliği
  aldı. Değişiklik yığında ne kadar aşağıdaysa geçersizleşen zincir o kadar uzar.
- Değişmezlik gereği eski katman silinmez: 5 730 baytlık sürüm yerinde kalır, 5 767 baytlık yenisi
  yanına eklenir. Katman deposu yalnız büyür.
- Birleşim görünümü siler gibi görünür, depo silmez. Bir yol gölgelendiğinde ve bir yol
  silindiğinde görünümde 8 dosya kaldı, ama görünümün dışına çıkan 1 559 bayt imajın içinde durmayı
  sürdürdü.

## Sonraki Adım

Bu dersin katmanları elle tanımlandı: hangi dosyanın hangi katmana gireceği bir nesne
sabitinde yazılıydı. Gerçek bir imaj böyle kurulmaz — katmanlar, sırayla uygulanan yönergelerden
doğar ve her yönerge bir katman üretir. Bu da iki yeni soru açar. Birincisi, yönergelerin
kopyalayacağı dosyalar nereden gelir: derleme bağlamı olarak adlandırılan bu kümeye kaç dosya ve
kaç bayt girer, girenlerin kaçı imaja hiç ulaşmaz? İkincisi, bu kümeyi daraltan dışlama kuralı
kaç dosyayı ve kaç baytı keser? Sonraki ders bir imaj tanım dosyası biçimi tanımlar, yönergeleri
sırayla uygulayan bir yorumlayıcı yazar ve derleme bağlamının büyüklüğünü ölçer.
