---
title: 'Yapı Çıktısı Depoları'
source: 'https://academia.sh/tr/kurslar/devops-temelleri/yapi-ciktisi-depolari'
course: 'DevOps Kültürü ve Temelleri'
language: tr
updated: '2026-08-17T18:09:05+00:00'
license: 'CC BY-SA 4.0'
---

# Yapı Çıktısı Depoları

Sürümlenmiş ikili ve paket saklama ölçülür: değişmez sürüm ile taşınabilir etiket ayrımı bir depo modelinde kurulur, taşınabilir etiketin kaç dağıtımda başka bir çıktıya işaret ettiği sayılır ve saklama kuralı geri alma penceresi, depo baytı ve ulaşılamaz dağıtım sayısı üzerinden taranır.

Önceki ders tek bir yapı çıktısı üretti ve kimliğinin içerik özeti olduğunu ölçtü. Özet
kimliktir ama ad değildir: onaltılık basamaklardan oluşan bir diziyi dağıtım kayıtlarına elle
taşımak sürdürülebilir bir düzen değildir. Ayrıca çıktı bir kez üretilip her yere dağıtılacaksa,
üretildiği an ile dağıtıldığı an arasında bir yerde durması ve geri alma gerektiğinde önceki
çıktının hâlâ bulunabilmesi gerekir.

Bu ders o duran yeri ele alır: **yapı çıktısı deposu** (artifact repository). Depo, sürümlenmiş
ikilileri ve paketleri saklayan, onlara ad veren ve istendiğinde geri veren bileşendir. Burada
bir ürün olarak değil, tür olarak ele alınır; ölçülen şey de deponun sunduğu iki adlandırma
biçiminin — değişmez sürüm ile taşınabilir etiketin — dağıtımda ne ürettiğidir.

**DK13.** Depo modeli iki işlevle sınırlıdır: değişmez sürüm kaydı ve ad çözümü. Erişim
denetimi, çoğaltma ve ağ katmanı modelin dışındadır. **DK14.** Yayım çizelgesi kendi
üretecimizle kurulur; tohum `20260311` görünürdür ve çizelge 24 sürümü ortalama dört günde bir
yayımlar. **DK15.** Sürüm boyutları 38–52 MB aralığında üreteçten gelir; gerçek bir ölçüm değil,
kurgunun büyüklük mertebesidir.

## Depo Ne Saklar

Depo iki ayrı şey saklar: **içerik** ve **ad**. İçerik, önceki dersin ölçtüğü nesnedir; adı ise
insanların dağıtım kaydına yazdığı sözdür. Bu iki şeyin ilişkisi ikiye ayrılır.

**Değişmez sürüm**, bir kez yayımlandıktan sonra başka bir içeriğe bağlanamayan addır. `1.5.0`
bir kez yayımlandıysa, `1.5.0` her zaman aynı çıktıdır. **Taşınabilir etiket** ise bir sürümü
gösteren ve zaman içinde başka bir sürüme taşınabilen addır: `kararli`, `son`, `hazirlik-adayi`
gibi. İkisi de addır, ama biri kimliğe, diğeri bir işaretçiye karşılık gelir.

Aşağıdaki model iki işlevi ve değişmezlik kuralının denetimini içerir.

```js
// olcum-agi/depo.mjs — surumlenmis yapi ciktisi deposu ve yayim cizelgesi (model)
import { createHash } from "node:crypto";

// Kendi uretecimiz: dogrusal esleme. Tohum cagirana aittir, cikti yinelenebilir.
export const uretec = (tohum) => () =>
  (tohum = (tohum * 1103515245 + 12345) % 2147483648) / 2147483648;

export const ozetle = (metin) => createHash("sha256").update(metin).digest("hex").slice(0, 12);

export const depoKur = () => {
  const surumler = new Map();   // degismez: surum -> { ozet, bayt, gun }
  const etiketler = new Map();  // tasinabilir: etiket -> surum
  const ret = [];
  return {
    surumler, etiketler, ret,
    yayimla(surum, ozet, bayt, gun) {
      const eski = surumler.get(surum);
      if (eski && eski.ozet !== ozet) { ret.push(surum); return "RET"; }
      if (eski) return "AYNI";
      surumler.set(surum, { ozet, bayt, gun });
      return "YAYIM";
    },
    etiketle: (etiket, surum) => etiketler.set(etiket, surum),
    coz(ad) {
      const surum = etiketler.get(ad) ?? ad;
      const kayit = surumler.get(surum);
      return kayit ? { surum, ozet: kayit.ozet } : null;
    },
  };
};

// n surumluk yayim cizelgesi: gun araliklari ve bayt boyutlari uretecten gelir.
export const cizelge = (n, ortalamaGun, tohum) => {
  const r = uretec(tohum);
  const liste = [];
  let gun = 0;
  for (let i = 1; i <= n; i++) {
    gun += 1 + Math.round(r() * (2 * ortalamaGun - 2));
    liste.push({
      surum: `1.${i}.0`, ozet: ozetle(`1.${i}.0-icerik`),
      bayt: 38_000_000 + Math.round(r() * 14_000_000), gun,
      temizKostu: r() > 0.45,
    });
  }
  return liste;
};
```

`yayimla` işlevinin üç yanıtı vardır ve bu üçü depo davranışının tamamıdır: yeni sürüm
kaydedilir, aynı içerikle yinelenen yayım yok sayılır, aynı ad başka içerikle geldiğinde
reddedilir. Üçüncüsü değişmezlik ilkesinin depodaki karşılığıdır — reddedilmezse, önceki dersin
ölçtüğü bütün özet karşılaştırmaları anlamını yitirir, çünkü `1.5.0` adının hangi nesneyi
gösterdiği zamana bağlı hâle gelir.

## Değişmez Sürüm ve Taşınabilir Etiket

Ölçüm 24 sürümü çizelgeye göre yayımlar ve arada gelen dağıtım isteklerini karşılar.

**DK16.** `son` etiketi her yayımda taşınır; `kararli` etiketi yalnız gecelik toplu işi temiz
koşan sürümlere taşınır. **DK17.** Dağıtım kaydı yalnız **istenen adı** saklar, çözülen sürümü
saklamaz — ölçülen kusurun kaynağı budur.

```js
// olcum-agi/etiket.mjs — tasinabilir etiketin kac dagitimda baska cikti tasidigini sayar
import { depoKur, cizelge } from "./depo.mjs";

const SURUMLER = cizelge(24, 4, 20260311);
const depo = depoKur();

// Dagitim istekleri: gun ve istenen ad. Ad ya tasinabilir etiket ya degismez surumdur.
const ISTEK = [
  [6, "kararli"], [11, "kararli"], [17, "son"], [23, "kararli"], [29, "kararli"],
  [34, "1.5.0"], [41, "kararli"], [48, "son"], [55, "kararli"], [66, "1.13.0"],
  [70, "kararli"], [79, "kararli"], [86, "son"], [92, "1.21.0"],
];

const kayitlar = [];
let sirada = 0;
for (const [gun, ad] of ISTEK) {
  while (sirada < SURUMLER.length && SURUMLER[sirada].gun <= gun) {
    const s = SURUMLER[sirada++];
    depo.yayimla(s.surum, s.ozet, s.bayt, s.gun);
    depo.etiketle("son", s.surum);
    if (s.temizKostu) depo.etiketle("kararli", s.surum);
  }
  kayitlar.push({ gun, ad, ...depo.coz(ad) });
}

console.log("gun".padEnd(5) + "istenen ad".padEnd(12) + "cozulen surum".padEnd(15) + "ozet");
for (const k of kayitlar) {
  console.log(String(k.gun).padEnd(5) + k.ad.padEnd(12) + k.surum.padEnd(15) + k.ozet);
}

const tasinabilir = kayitlar.filter((k) => k.ad === "kararli" || k.ad === "son");
const sonGorulen = new Map();
let degisim = 0;
for (const k of tasinabilir) {
  if (sonGorulen.has(k.ad) && sonGorulen.get(k.ad) !== k.ozet) degisim += 1;
  sonGorulen.set(k.ad, k.ozet);
}
const ayri = (ad) => new Set(kayitlar.filter((k) => k.ad === ad).map((k) => k.ozet)).size;

console.log(`\ntoplam dagitim ${kayitlar.length}: tasinabilir etiketle ${tasinabilir.length}, ` +
  `degismez surumle ${kayitlar.length - tasinabilir.length}`);
console.log(`"kararli" adiyla ${kayitlar.filter((k) => k.ad === "kararli").length} dagitim yapildi, ` +
  `${ayri("kararli")} ayri ciktiya isaret etti`);
console.log(`"son" adiyla ${kayitlar.filter((k) => k.ad === "son").length} dagitim yapildi, ` +
  `${ayri("son")} ayri ciktiya isaret etti`);
console.log(`ayni ad, onceki dagitimdan baska cikti: ${degisim} dagitim`);

// Degismezlik denetimi: yayimlanmis bir surum baska ozetle yeniden yayimlanmak istenirse.
console.log("\nayni surum, baska ozet: " + depo.yayimla("1.5.0", "ffffffffffff", 4e7, 99));
console.log("ayni surum, ayni ozet : " + depo.yayimla("1.5.0", depo.coz("1.5.0").ozet, 4e7, 99));
console.log("reddedilen yeniden yayim: " + depo.ret.length);
```

```
gun  istenen ad  cozulen surum  ozet
6    kararli     1.1.0          69a51066dd19
11   kararli     1.2.0          4a318efc7537
17   son         1.4.0          6c9ea8b0936a
23   kararli     1.2.0          4a318efc7537
29   kararli     1.6.0          e82d2dacf6b1
34   1.5.0       1.5.0          1d7edd1472a2
41   kararli     1.7.0          837826307ef8
48   son         1.10.0         4d590510b154
55   kararli     1.10.0         4d590510b154
66   1.13.0      1.13.0         e4438d40a263
70   kararli     1.16.0         6ed1bdfd5c1e
79   kararli     1.16.0         6ed1bdfd5c1e
86   son         1.19.0         39b3f9d7c5d7
92   1.21.0      1.21.0         90749e3c6c1c

toplam dagitim 14: tasinabilir etiketle 11, degismez surumle 3
"kararli" adiyla 8 dagitim yapildi, 6 ayri ciktiya isaret etti
"son" adiyla 3 dagitim yapildi, 3 ayri ciktiya isaret etti
ayni ad, onceki dagitimdan baska cikti: 7 dagitim

ayni surum, baska ozet: RET
ayni surum, ayni ozet : AYNI
reddedilen yeniden yayim: 1
```

Sayılar tek bir cümleye toplanır: **on dört dağıtımın on biri bir ada yapıldı ve o ad yedisinde
bir öncekinden başka bir çıktı taşıdı.** `kararli` adıyla yapılan sekiz dağıtım altı ayrı
nesneyi üretime taşımıştır; kayıtta yazan söz ise sekizinde de aynıdır.

Tabloda iki durum ayrıca okunmalıdır. Gün 11 ile gün 23 arasında `kararli` etiketi yerinde
kalmıştır: arada yayımlanan sürümler gecelik toplu işi temiz koşmadığı için etiket taşınmamış,
iki dağıtım da `1.2.0` çıktısını almıştır. Yani taşınabilir etiket her zaman taşınmaz; taşınıp
taşınmadığı dağıtımı isteyen taraftan görünmez. Gün 55 ile gün 79 arasında ise tersi olmuştur:
aynı ad, `1.10.0` yerine `1.16.0` çıktısını taşımıştır.

Bu, geri almanın da ölçülebilir tuzağıdır. Gün 79'da bir sorun görülüp "kararlı sürüme dönelim"
denirse, çözülen nesne gün 55'te dağıtılan `1.10.0` değil, güncel `1.16.0` olur — geri alma
isteği ileri bir dağıtım üretir. Geri almanın çalışması için istenen adın **değişmez sürüm**
olması gerekir; tabloda üç dağıtım bunu yapmıştır.

**Farkın saklandığı yer burada ad çözümüdür.** Çözüm dağıtım anında yapılır ve kayda geçmez;
dağıtım kaydında yalnız `kararli` yazar. Sonradan bakan biri, hangi dağıtımın hangi nesneyi
taşıdığını on bir kayıtta okuyamaz. Fark bildirilmemiş değildir yalnızca — kaydedilmemiştir.
Kapatılması da tek satırlıktır: dağıtım kaydına istenen adın yanına çözülen sürüm ve özet de
yazılır; o zaman on bir belirsiz kaydın on biri okunabilir hâle gelir.

Çıktının son üç satırı değişmezlik denetimini gösterir. Yayımlanmış `1.5.0` başka bir özetle
yeniden yayımlanmak istendiğinde depo `RET` döndürür; aynı özetle geldiğinde `AYNI` der ve
yeniden yazma yapmaz. Bu ikinci davranış, yapı adımının iki kez koşması durumunda hatayla
sonuçlanmamasını sağlar — yeniden üretilebilir bir yapı için doğal karşılıktır.

## Girdi Tarafı ve Üstveri

Depo yalnız yapı adımının çıktısını saklamaz; aynı türden bir depo, yapı adımının **girdisi**
olan paketleri de saklar. Ölçülen ad çözümü sorunu bu tarafta da aynen geçerlidir. Bir yapı
adımı girdi paketini değişmez sürümle değil taşınabilir bir adla — "uyumlu en yeni" türünden
bir ifadeyle — istiyorsa, önceki dersin dört bozucu kaynağı kapatılmış olsa bile iki koşum
farklı çıktı üretebilir; çünkü aradan geçen sürede ad başka bir nesneye taşınmıştır. Bu,
yeniden üretilebilirliği bozan **beşinci kaynaktır** ve öncekilerin hepsinden farklı olarak
yapı adımının kendi içinde değil, dışarıda durur. Ölçülen orandaki gibi: adla çözülen on bir
istekten yedisinde nesne değişmişti; aynı belirsizlik girdi tarafında yapı adımına taşınır.
Kapatılması, girdi sürümlerinin ad değil sürüm olarak sabitlenmesiyle olur.

İkinci konu üstveridir. Önceki dersin bıraktığı boşluk, özetin çıktının hangi kaynaktan
üretildiğini söylememesiydi. Depo bu boşluğu kapatabilecek yerdir: her sürüm kaydına üç alan
eklenir — çıktının üretildiği kaynak sürümü, yapı koşumunun kimliği ve o koşumda geçen
sınamaların sonucu. Bu üç alan yazıldığında "üretimde koşan nesne hangi kaynaktan geldi"
sorusu depodan okunur; yazılmadığında yanıt yalnız insanların hatırasındadır. Üç alanın da
çıktının **içine** değil, yanına yazıldığına dikkat edilmelidir: içine yazmak, önceki dersin
ölçtüğü gibi her koşumda özeti değiştirir ve yeniden üretilebilirliği bozar.

## Saklama Kuralı Neyi Kapatır

Depo sınırsız değildir. Saklama kuralı hangi sürümlerin ne kadar tutulacağını söyler.
**DK18.** Kural sayıya bağlıdır: "son K sürüm tutulur". Tarama, K değiştikçe üç niceliği birden
ölçer — deponun baytı, geri alma penceresi ve önceki ölçümdeki dağıtımların kaçının hedefinin
silinmiş olacağı.

```js
// olcum-agi/saklama.mjs — saklama kuralini tarar: pencere, bayt ve ulasilamaz dagitim
import { cizelge } from "./depo.mjs";

const S = cizelge(24, 4, 20260311);
const son = S[S.length - 1];
// Onceki olcumde 14 dagitimin cozuldugu surumler:
const DAGITILAN = ["1.1.0", "1.2.0", "1.4.0", "1.2.0", "1.6.0", "1.5.0", "1.7.0",
  "1.10.0", "1.10.0", "1.13.0", "1.16.0", "1.16.0", "1.19.0", "1.21.0"];

const mb = (b) => (b / 1e6).toFixed(0) + " MB";
console.log("kural".padEnd(14) + "depo".padEnd(10) + "geri alma penceresi".padEnd(21) + "ulasilamaz dagitim");
for (const k of [3, 5, 8, 12, 18, 24]) {
  const tutulan = S.slice(-k);
  const bayt = tutulan.reduce((t, s) => t + s.bayt, 0);
  const adlar = new Set(tutulan.map((s) => s.surum));
  const ulasilamaz = DAGITILAN.filter((v) => !adlar.has(v)).length;
  console.log(`son ${k} surum`.padEnd(14) + mb(bayt).padEnd(10) +
    `${son.gun - tutulan[0].gun} gun`.padEnd(21) + `${ulasilamaz}/${DAGITILAN.length}`);
}

console.log("");
for (const aralik of [4, 2]) {
  const c = cizelge(24, aralik, 20260311);
  console.log(`yayim araligi ~${aralik} gun: 24 surum ${c[23].gun} gune yayiliyor, ` +
    `"son 8 surum" penceresi ${c[23].gun - c[16].gun} gun`);
}

const toplam = S.reduce((t, s) => t + s.bayt, 0);
console.log(`\nkural yoksa: ${S.length} surum ${mb(toplam)}; bu hizda yillik buyume ` +
  mb((toplam / son.gun) * 365));
```

```
kural         depo      geri alma penceresi  ulasilamaz dagitim
son 3 surum   129 MB    4 gun                14/14
son 5 surum   214 MB    11 gun               13/14
son 8 surum   352 MB    23 gun               12/14
son 12 surum  535 MB    37 gun               9/14
son 18 surum  805 MB    69 gun               6/14
son 24 surum  1073 MB   97 gun               0/14

yayim araligi ~4 gun: 24 surum 99 gune yayiliyor, "son 8 surum" penceresi 23 gun
yayim araligi ~2 gun: 24 surum 47 gune yayiliyor, "son 8 surum" penceresi 11 gun

kural yoksa: 24 surum 1073 MB; bu hizda yillik buyume 3955 MB
```

Tarama saklama kuralını bir tercih tablosuna çevirir. "Son sekiz sürüm" kuralı depoyu 352 MB'de
tutar ama geri alma penceresini 23 güne indirir: 23 günden eski bir sürüme dönmek istendiğinde
nesne artık yoktur. Aynı kural altında, ölçülen on dört dağıtımın on ikisinin taşıdığı çıktı
silinmiştir; yani "hangi sürümü koşuyorduk" sorusunun yanıtı bilinse bile o sürüm geri
getirilemez. Pencereyi 69 güne çıkarmak deponun 805 MB'ye, yani iki katından fazlasına
büyümesini gerektirir.

Sayıya bağlı kuralın gizlediği bir bağımlılık vardır: **pencere, yayım sıklığına bağlıdır.**
Aynı "son sekiz sürüm" kuralı, dört günde bir yayımlayan bir ekipte 23 günlük, iki günde bir
yayımlayan bir ekipte 11 günlük pencere verir. Kural metni değişmemiştir, kuralın anlamı
değişmiştir. Dağıtım sıklığını artırmak — teslimat ölçütlerinden birini iyileştirmek — hiçbir
şey yapılmadan geri alma penceresini yarıya indirir; bu, bir ölçütü iyileştiren kararın
başkasında ölçülen değişimine örnektir. Pencerenin sıklıktan bağımsız olması isteniyorsa kural
süreye bağlanır ("doksan günden eski sürümler silinir") ya da iki koşul birlikte yazılır.

Kural konmadığında da bir sayı vardır: bu hızda depo yılda yaklaşık 3955 MB büyür. Sınırsız
saklama bir karar değil, ertelenmiş bir karardır; ertelendiğinde de silmeye çoğunlukla yer
kalmadığı gün, yani geri alma penceresinin en çok gerektiği anda başlanır.

## Özet

- Yapı çıktısı deposu iki şey saklar: içerik ve ad. Ad iki türlüdür — bir kez bağlandıktan
  sonra değişmeyen sürüm ve zaman içinde başka sürüme taşınabilen etiket.
- Değişmezlik denetimi depoda uygulanır: aynı sürüm başka içerikle yeniden yayımlanmak
  istendiğinde reddedilir, aynı içerikle geldiğinde yok sayılır.
- Ölçümde 14 dağıtımın 11'i taşınabilir bir ada yapılmış, ad bunların 7'sinde bir öncekinden
  başka bir çıktı taşımıştır; `kararli` adıyla yapılan 8 dağıtım 6 ayrı nesne dağıtmıştır.
- Fark, dağıtım anındaki ad çözümünde saklıdır ve kaydedilmediği için sonradan okunamaz. Çözülen
  sürümün ve özetin kayda yazılması 11 belirsiz kaydı okunabilir kılar; geri almanın çalışması
  için istenen adın değişmez sürüm olması gerekir.
- Saklama kuralı üç niceliği birden belirler: "son 8 sürüm" 352 MB depo, 23 gün geri alma
  penceresi ve 14 dağıtımdan 12'sinin hedefinin silinmesi demektir. Sayıya bağlı kuralın
  penceresi yayım sıklığı arttıkça kısalır; sıklık iki katına çıkınca pencere 23 günden 11 güne
  inmiştir.

## Sonraki Adım

Depoda duran çıktı artık tek ve adlandırılmıştır, ama önceki dersin sonunda bir borç kalmıştı:
ortama göre değişen on iki değer çıktının içinden çıkarıldı ve "ortamın künyesine" konuldu.
Bu değerlerin hepsi aynı türden değildir. Fatura kapısının adresi ile o kapıya bağlanmak için
kullanılan anahtar aynı yerden okunur, ama biri kütüğe yazılabilir, diğeri yazılamaz; biri
dağıtım kaydında görünebilir, diğeri görünemez. Sonraki ders bu sınırı çizer ve ölçer: ortamdan
gelen değerlerin kaçı yapılandırma, kaçı sır sayılır, sır kaç ayrı yoldan dışarı sızabilir ve
sızıntının kapatıldığı bir denetimle nasıl gösterilir?
