پرش به مطلب اصلی

دریافت تاریخچه ایمیج

تاریخچه لایه‌های ایمیج و بیس ایمیج‌های آن را نمایش می‌دهد.


🧩 دستور کلی

async historyOfImage(imageName, tag = "latest")

شرح عملکرد

این متد تاریخچه لایه‌های ایمیج را دریافت می‌کند. شامل:

  • اعتبارسنجی پارامترهای تاریخچه
  • بررسی وجود ایمیج در DB
  • تأیید وجود تگ در لیست تگ‌های ایمیج
  • دریافت تاریخچه لایه‌های ایمیج
  • logging عملیات

مهم: این دستور برای پیدا کردن بیس ایمیج‌های این ایمیج است. تاریخچه تمام لایه‌های ایمیج از base layer تا current layer نمایش داده می‌شود.


ورودی‌ها

پارامترنوعاجباریپیش‌فرضتوضیح
imageNameString✅ بله-نام ایمیج (مثلاً myapp, myrepo/myapp)
tagStringخیر"latest"تگ ایمیج (مثلاً v1.0, stable, alpine)

خروجی

نوع: Array<Object>

لیست لایه‌های ایمیج از base تا current:

[
{
layer: "sha256:abc123...",
size: 5242880,
created: "2025-01-15T10:30:00Z",
author: "base-image",
message: "base layer",
tags: ["latest"]
},
{
layer: "sha256:def456...",
size: 2097152,
created: "2025-02-20T14:45:00Z",
author: "myapp",
message: "add dependencies",
tags: []
},
{
layer: "sha256:ghi789...",
size: 1048576,
created: "2025-03-10T08:15:00Z",
author: "myapp",
message: "copy application",
tags: ["v1.0"]
}
]

استثناها (Errors)

InvalidHistoryParameters (422)

پیام: "Invalid history parameters."

زمان رخ دادن: پارامترهای تاریخچه نامعتبر باشند

جزئیات:

{
"type": "VALIDATION_ERROR",
"statusCode": 422,
"imageName": "invalid@image",
"tag": "latest",
"error": "Image name contains invalid characters"
}

راهنمای حل:

  • نام ایمیج: فقط حروف، اعداد، '-', '_', '/' مجاز
  • تگ: فقط حروف، اعداد، '.', '-' مجاز
  • پارامترها باید معتبر باشند

FetchImageState (500)

پیام: "Failed to check image state in database."

زمان رخ دادن: خطا در بررسی وجود ایمیج در DB

جزئیات:

{
"type": "DB_ERROR",
"statusCode": 500,
"imageName": "myapp",
"tag": "latest",
"error": "Database query failed"
}

راهنمای حل:

  • اتصال دیتابیس را بررسی کنید
  • دیتابیس را restart کنید
  • لاگ‌های دیتابیس را بررسی کنید

ImageNotFound (404)

پیام: "Image not found."

زمان رخ دادن: ایمیج با این نام و تگ موجود نیست

جزئیات:

{
"type": "NOT_FOUND",
"statusCode": 404,
"imageName": "nonexistent-app",
"tag": "latest",
"error": "Image not found in database"
}

راهنمای حل:

  • نام ایمیج را بررسی کنید
  • تگ را بررسی کنید
  • listImages() استفاده کنید
  • ایمیج واقعاً موجود است؟

ListImageTagsFailure (500)

پیام: "Failed to list image tags."

زمان رخ دادن: خطا در دریافت لیست تگ‌های ایمیج

جزئیات:

{
"type": "IMAGE_SERVICE_ERROR",
"statusCode": 500,
"imageName": "myapp",
"error": "Image service communication failed"
}

راهنمای حل:

  • ImageManager را بررسی کنید
  • اتصال سرویس را تأیید کنید
  • لاگ‌های سیستم را بررسی کنید

ImageTagNotFound (404)

پیام: "Image tag not found."

زمان رخ دادن: تگ مشخص شده در ایمیج موجود نیست

جزئیات:

{
"type": "NOT_FOUND",
"statusCode": 404,
"imageName": "myapp",
"tag": "v99.0",
"availableTags": ["latest", "v1.0", "v1.1"]
}

راهنمای حل:

  • لیست تگ‌های موجود را بررسی کنید
  • تگ صحیح را وارد کنید
  • listImages() استفاده کنید

FetchImageHistoryFailure (500)

پیام: "Failed to fetch image history."

زمان رخ دادن: خطا در دریافت تاریخچه ایمیج

جزئیات:

{
"type": "IMAGE_SERVICE_ERROR",
"statusCode": 500,
"imageName": "myapp",
"tag": "latest",
"error": "History fetch failed"
}

راهنمای حل:

  • ImageManager را بررسی کنید
  • metadata ایمیج موجود است؟
  • لاگ‌های سیستم را بررسی کنید

GenericFailure (500)

پیام: "Generic failure during history fetch."

زمان رخ دادن: خطای عمومی

جزئیات:

{
"type": "GENERIC_ERROR",
"statusCode": 500,
"error": "History fetch failed"
}

راهنمای حل:

  • سیستم لاگ را بررسی کنید
  • تمام سرویس‌ها را restart کنید
  • دوباره تلاش کنید

مثال‌های استفاده

مثال 1: دریافت تاریخچه ایمیج ساده

const K3Core = require('k3-core');

(async () => {
const k3 = new K3Core();

try {
const history = await k3.imageCore.historyOfImage('myapp');
console.log('Image history:', history);

console.log('\nBase images chain:');
history.forEach((layer, index) => {
console.log(`${index + 1}. ${layer.author} - ${layer.message}`);
console.log(` Layer: ${layer.layer.substring(0, 12)}...`);
console.log(` Size: ${(layer.size / 1024 / 1024).toFixed(2)} MB`);
});
} catch (error) {
console.log('ERROR:', error.createFullMessage());
}
})();

مثال 2: دریافت تاریخچه تگ خاص

(async () => {
const k3 = new K3Core();

try {
const history = await k3.imageCore.historyOfImage('nginx', 'v1.0');
console.log('History for nginx:v1.0:', history);

console.log('\nLayers info:');
console.log(`Total layers: ${history.length}`);

const totalSize = history.reduce((sum, layer) => sum + layer.size, 0);
console.log(`Total size: ${(totalSize / 1024 / 1024).toFixed(2)} MB`);
} catch (error) {
console.log('ERROR: Failed to get history');
console.log(error.message);
}
})();

مثال 3: مقایسه تاریخچه چند ایمیج

(async () => {
const k3 = new K3Core();

try {
// Get history for multiple images
const apacheHistory = await k3.imageCore.historyOfImage('apache');
const nginxHistory = await k3.imageCore.historyOfImage('nginx');

console.log('=== Apache History ===');
apacheHistory.forEach((layer, i) => {
console.log(`${i + 1}. ${layer.author}: ${layer.message}`);
});

console.log('\n=== Nginx History ===');
nginxHistory.forEach((layer, i) => {
console.log(`${i + 1}. ${layer.author}: ${layer.message}`);
});

console.log(`\nApache layers: ${apacheHistory.length}`);
console.log(`Nginx layers: ${nginxHistory.length}`);
} catch (error) {
console.log('ERROR:', error.message);
}
})();

مثال 4: تتبع بیس ایمیج

(async () => {
const k3 = new K3Core();

try {
const history = await k3.imageCore.historyOfImage('myapp', 'latest');

console.log('=== Base Image Chain ===\n');

history.forEach((layer, index) => {
const indent = ' '.repeat(index);
console.log(`${indent}├─ Layer ${index + 1}`);
console.log(`${indent}│ Author: ${layer.author}`);
console.log(`${indent}│ Message: ${layer.message}`);
console.log(`${indent}│ Size: ${(layer.size / 1024 / 1024).toFixed(2)} MB`);
console.log(`${indent}│ Created: ${new Date(layer.created).toLocaleString()}`);

if (layer.tags && layer.tags.length > 0) {
console.log(`${indent}│ Tags: ${layer.tags.join(', ')}`);
}

if (index < history.length - 1) {
console.log(`${indent}`);
}
});
} catch (error) {
console.log('ERROR:', error.message);
}
})();

مثال 5: تحلیل تاریخچه

(async () => {
const k3 = new K3Core();

const analyzeHistory = async (imageName, tag = 'latest') => {
try {
const history = await k3.imageCore.historyOfImage(imageName, tag);

// Calculate statistics
const totalSize = history.reduce((sum, layer) => sum + layer.size, 0);
const avgLayerSize = totalSize / history.length;
const largestLayer = history.reduce((max, layer) =>
layer.size > max.size ? layer : max
);

const createdDates = history.map(l => new Date(l.created));
const oldestLayer = new Date(Math.min(...createdDates.map(d => d.getTime())));
const newestLayer = new Date(Math.max(...createdDates.map(d => d.getTime())));

console.log(`\n=== ${imageName}:${tag} Analysis ===\n`);
console.log(`Total layers: ${history.length}`);
console.log(`Total size: ${(totalSize / 1024 / 1024).toFixed(2)} MB`);
console.log(`Average layer size: ${(avgLayerSize / 1024 / 1024).toFixed(2)} MB`);
console.log(`Largest layer: ${(largestLayer.size / 1024 / 1024).toFixed(2)} MB`);
console.log(` By: ${largestLayer.author}`);
console.log(` Message: ${largestLayer.message}`);
console.log(`\nOldest layer: ${oldestLayer.toLocaleDateString()}`);
console.log(`Newest layer: ${newestLayer.toLocaleDateString()}`);
console.log(`Age: ${Math.floor((newestLayer - oldestLayer) / (1000 * 60 * 60 * 24))} days`);

return {
layers: history.length,
size: totalSize,
avgSize: avgLayerSize,
maxSize: largestLayer.size,
created: oldestLayer,
updated: newestLayer
};
} catch (error) {
console.log('ERROR:', error.message);
}
};

await analyzeHistory('myapp', 'v1.0');
})();

مثال 6: تحقق از بیس ایمیج

(async () => {
const k3 = new K3Core();

const checkBaseImage = async (imageName, expectedBase) => {
try {
const history = await k3.imageCore.historyOfImage(imageName);

// Get the first (base) layer
const baseLayer = history[0];

console.log(`Image: ${imageName}`);
console.log(`Base image author: ${baseLayer.author}`);
console.log(`Expected base: ${expectedBase}`);

if (baseLayer.author.includes(expectedBase)) {
console.log('✓ Base image matches');
return true;
} else {
console.log('✗ Base image does NOT match');
return false;
}
} catch (error) {
console.log('ERROR:', error.message);
return false;
}
};

await checkBaseImage('myapp', 'alpine');
})();

مثال 7: export تاریخچه

(async () => {
const k3 = new K3Core();
const fs = require('fs');

try {
const history = await k3.imageCore.historyOfImage('myapp', 'latest');

// Format for export
const exportData = {
image: 'myapp:latest',
exportedAt: new Date().toISOString(),
totalLayers: history.length,
layers: history.map(layer => ({
index: history.indexOf(layer) + 1,
layer: layer.layer,
author: layer.author,
message: layer.message,
size: {
bytes: layer.size,
mb: (layer.size / 1024 / 1024).toFixed(2)
},
created: layer.created,
tags: layer.tags || []
}))
};

// Save to JSON
const filename = `history-myapp-latest-${Date.now()}.json`;
fs.writeFileSync(filename, JSON.stringify(exportData, null, 2));
console.log(`History exported to: ${filename}`);

// Also create a CSV
let csv = 'Index,Author,Message,Size (MB),Created,Tags\n';
exportData.layers.forEach(layer => {
csv += `${layer.index},"${layer.author}","${layer.message}",${layer.size.mb},${layer.created},"${layer.tags.join(', ')}"\n`;
});

const csvFilename = `history-myapp-latest-${Date.now()}.csv`;
fs.writeFileSync(csvFilename, csv);
console.log(`CSV exported to: ${csvFilename}`);
} catch (error) {
console.log('ERROR:', error.message);
}
})();

مثال 8: مقایسه نسخه‌های مختلف

(async () => {
const k3 = new K3Core();

try {
// Get history for different versions
const v1History = await k3.imageCore.historyOfImage('myapp', 'v1.0');
const v2History = await k3.imageCore.historyOfImage('myapp', 'v2.0');

console.log('=== Version Comparison ===\n');

console.log(`v1.0: ${v1History.length} layers, ${(v1History.reduce((s, l) => s + l.size, 0) / 1024 / 1024).toFixed(2)} MB`);
console.log(`v2.0: ${v2History.length} layers, ${(v2History.reduce((s, l) => s + l.size, 0) / 1024 / 1024).toFixed(2)} MB`);

// Find common base
const commonLayers = [];
for (let i = 0; i < Math.min(v1History.length, v2History.length); i++) {
if (v1History[i].layer === v2History[i].layer) {
commonLayers.push(v1History[i]);
} else {
break;
}
}

console.log(`\nCommon base layers: ${commonLayers.length}`);
console.log(`v1.0 unique layers: ${v1History.length - commonLayers.length}`);
console.log(`v2.0 unique layers: ${v2History.length - commonLayers.length}`);
} catch (error) {
console.log('ERROR:', error.message);
}
})();

الگوهای خطا و راهنمای حل

الگو 1: ایمیج یافت نشد

خطا: ImageNotFound (404)

راهنمای حل:

const getHistoryWithCheck = async (imageName, tag = 'latest') => {
try {
const history = await k3.imageCore.historyOfImage(imageName, tag);
return history;
} catch (error) {
if (error.statusCode === 404) {
console.log(`Image ${imageName}:${tag} not found`);

// Get available images
const images = await k3.imageCore.listImages({ image: imageName });
console.log('Available images:');
images.forEach(img => console.log(` - ${img.Name}:${img.Tag}`));

throw new Error(`Image ${imageName}:${tag} not found. Use one from list above.`);
}
throw error;
}
};

await getHistoryWithCheck('myapp', 'v1.0');

الگو 2: تگ یافت نشد

خطا: ImageTagNotFound (404)

راهنمای حل:

const getHistoryWithTagValidation = async (imageName, tag = 'latest') => {
try {
const history = await k3.imageCore.historyOfImage(imageName, tag);
return history;
} catch (error) {
if (error.statusCode === 404 && error.message.includes('tag')) {
console.log(`Tag ${tag} not found for ${imageName}`);

// Get available tags
const images = await k3.imageCore.listImages({ image: imageName });
const tags = [...new Set(images.map(img => img.Tag))];
console.log('Available tags:');
tags.forEach(t => console.log(` - ${t}`));

throw new Error(`Tag ${tag} not found. Use one from list above.`);
}
throw error;
}
};

await getHistoryWithTagValidation('myapp', 'v1.0');

الگو 3: تحلیل تاریخچه اصلی

راهنمای حل:

class ImageHistoryAnalyzer {
constructor(k3) {
this.k3 = k3;
}

async analyzeImage(imageName, tag = 'latest') {
try {
const history = await this.k3.imageCore.historyOfImage(imageName, tag);

if (!history || history.length === 0) {
return { success: false, error: 'Empty history' };
}

// Base image info
const baseLayer = history[0];
const currentLayer = history[history.length - 1];

// Statistics
const totalSize = history.reduce((sum, l) => sum + l.size, 0);
const layers = history.map((l, i) => ({
index: i + 1,
author: l.author,
message: l.message,
size: (l.size / 1024 / 1024).toFixed(2),
created: new Date(l.created).toLocaleDateString()
}));

return {
success: true,
image: `${imageName}:${tag}`,
base: baseLayer.author,
totalLayers: history.length,
totalSize: (totalSize / 1024 / 1024).toFixed(2),
created: baseLayer.created,
updated: currentLayer.created,
layers: layers
};
} catch (error) {
return { success: false, error: error.message };
}
}

async getBaseImage(imageName, tag = 'latest') {
try {
const history = await this.k3.imageCore.historyOfImage(imageName, tag);
return {
success: true,
baseImage: history[0].author,
baseMessage: history[0].message,
baseSize: (history[0].size / 1024 / 1024).toFixed(2)
};
} catch (error) {
return { success: false, error: error.message };
}
}
}

const analyzer = new ImageHistoryAnalyzer(k3);
const analysis = await analyzer.analyzeImage('myapp', 'v1.0');
console.log('Analysis:', analysis);

const baseInfo = await analyzer.getBaseImage('myapp', 'v1.0');
console.log('Base image:', baseInfo);

الگو 4: مقایسه تاریخچه

راهنمای حل:

class HistoryComparator {
constructor(k3) {
this.k3 = k3;
}

async compareVersions(imageName, tag1 = 'latest', tag2 = 'v1.0') {
try {
const history1 = await this.k3.imageCore.historyOfImage(imageName, tag1);
const history2 = await this.k3.imageCore.historyOfImage(imageName, tag2);

// Find common base
let commonIndex = 0;
for (let i = 0; i < Math.min(history1.length, history2.length); i++) {
if (history1[i].layer === history2[i].layer) {
commonIndex = i + 1;
} else {
break;
}
}

return {
success: true,
comparison: {
version1: tag1,
version2: tag2,
v1Layers: history1.length,
v2Layers: history2.length,
commonBaseLayers: commonIndex,
v1UniqueLayes: history1.length - commonIndex,
v2UniqueLayes: history2.length - commonIndex,
v1Size: (history1.reduce((s, l) => s + l.size, 0) / 1024 / 1024).toFixed(2),
v2Size: (history2.reduce((s, l) => s + l.size, 0) / 1024 / 1024).toFixed(2)
},
baseImage: history1[0].author,
v1Changes: history1.slice(commonIndex).map(l => l.message),
v2Changes: history2.slice(commonIndex).map(l => l.message)
};
} catch (error) {
return { success: false, error: error.message };
}
}
}

const comparator = new HistoryComparator(k3);
const comparison = await comparator.compareVersions('myapp', 'v2.0', 'v1.0');
console.log('Comparison:', comparison);

الگو 5: تتبع تاریخچه

راهنمای حل:

class HistoryTracker {
constructor(k3) {
this.k3 = k3;
this.histories = new Map();
}

async trackHistory(imageName, tag = 'latest') {
try {
const history = await this.k3.imageCore.historyOfImage(imageName, tag);

const key = `${imageName}:${tag}`;
this.histories.set(key, {
fetchedAt: new Date(),
layerCount: history.length,
totalSize: history.reduce((s, l) => s + l.size, 0),
baseImage: history[0].author,
latestUpdate: history[history.length - 1].created,
history: history
});

return { success: true, tracked: key };
} catch (error) {
return { success: false, error: error.message };
}
}

compareTracked(key1, key2) {
const h1 = this.histories.get(key1);
const h2 = this.histories.get(key2);

if (!h1 || !h2) {
return { error: 'One or both histories not tracked' };
}

return {
key1: key1,
key2: key2,
h1Layers: h1.layerCount,
h2Layers: h2.layerCount,
h1Size: (h1.totalSize / 1024 / 1024).toFixed(2),
h2Size: (h2.totalSize / 1024 / 1024).toFixed(2),
sameBase: h1.baseImage === h2.baseImage
};
}

getTrackedList() {
return Array.from(this.histories.keys());
}
}

const tracker = new HistoryTracker(k3);
await tracker.trackHistory('app1', 'v1.0');
await tracker.trackHistory('app2', 'v2.0');
console.log('Tracked:', tracker.getTrackedList());
console.log('Comparison:', tracker.compareTracked('app1:v1.0', 'app2:v2.0'));

نکات عملی

  1. لایه‌های ایمیج:

    • لایه اول همیشه base image است
    • ترتیب لایه‌ها از base تا current
    • هر لایه یک تغییر نشان می‌دهد
  2. اندازه لایه:

    • اندازه هر لایه جداگانه نمایش داده می‌شود
    • اندازه کل = مجموع تمام لایه‌ها
    • لایه‌های بزرگ ممکن است مشکل ایجاد کنند
  3. تگ‌های ایمیج:

    • تگ از پیش‌فرض "latest" است
    • می‌تواند تگ دیگری مشخص کنید
    • تگ های متفاوت ممکن است تاریخچه متفاوت داشته باشند
  4. بیس ایمیج:

    • اولین لایه بیس ایمیج است
    • بیس ایمیج تعیین می‌کند چه ایمیج از آن شروع شده
    • بیس ایمیج معمولاً alpine یا ubuntu است
  5. Performance:

    • دریافت تاریخچه سریع است
    • ایمیج‌های بزرگ دارای تاریخچه طولانی هستند
    • لایه‌های متعدد = بیشتر حافظه
  6. تحلیل:

    • می‌توانید تاریخچه‌ها را مقایسه کنید
    • بیس ایمیج مشترک را پیدا کنید
    • تغییرات بین نسخه‌ها را بررسی کنید

دنباله عملیات

  1. اعتبارسنجی پارامترها
  2. بررسی وجود ایمیج در DB
  3. تأیید وجود تگ
  4. دریافت لیست تگ‌های ایمیج
  5. فراخوانی ImageManager برای دریافت تاریخچه
  6. پردازش و بازگشت نتایج
  7. Logging موفقیت

مرجع سریع

وضعیتکدتوضیح
موفق200دریافت تاریخچه موفق
پارامتر نامعتبر422InvalidHistoryParameters
DB خطا500FetchImageState
ایمیج یافت نشد404ImageNotFound
تگ یافت نشد404ImageTagNotFound
لیست تگ‌ها خطا500ListImageTagsFailure
تاریخچه خطا500FetchImageHistoryFailure
خطای عمومی500GenericFailure

موارد استفاده

Base Image Detection

const history = await historyOfImage('myapp', 'latest');
const baseImage = history[0].author; // alpine, ubuntu, etc.

Version Comparison

const v1 = await historyOfImage('app', 'v1.0');
const v2 = await historyOfImage('app', 'v2.0');
// Compare common base

Image Size Analysis

const history = await historyOfImage('myapp');
const totalSize = history.reduce((s, l) => s + l.size, 0);

Layer Inspection

const history = await historyOfImage('myapp');
history.forEach((layer, i) => {
console.log(`Layer ${i}: ${layer.author} - ${layer.message}`);
});


نسخه: 1.3
تاریخ آپدیت: 10 آذرماه ۱۴۰۴
تیم توسعه: K3 Development Team