دریافت تاریخچه ایمیج
تاریخچه لایههای ایمیج و بیس ایمیجهای آن را نمایش میدهد.
🧩 دستور کلی
async historyOfImage(imageName, tag = "latest")
شرح عملکرد
این متد تاریخچه لایههای ایمیج را دریافت میکند. شامل:
- اعتبارسنجی پارامترهای تاریخچه
- بررسی وجود ایمیج در DB
- تأیید وجود تگ در لیست تگهای ایمیج
- دریافت تاریخچه لایههای ایمیج
- logging عملیات
مهم: این دستور برای پیدا کردن بیس ایمیجهای این ایمیج است. تاریخچه تمام لایههای ایمیج از base layer تا current layer نمایش داده میشود.
ورودیها
| پارامتر | نوع | اجباری | پیشفرض | توضیح |
|---|---|---|---|---|
imageName | String | ✅ بله | - | نام ایمیج (مثلاً myapp, myrepo/myapp) |
tag | String | خیر | "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'));
نکات عملی
-
لایههای ایمیج:
- لایه اول همیشه base image است
- ترتیب لایهها از base تا current
- هر لایه یک تغییر نشان میدهد
-
اندازه لایه:
- اندازه هر لایه جداگانه نمایش داده میشود
- اندازه کل = مجموع تمام لایهها
- لایههای بزرگ ممکن است مشکل ایجاد کنند
-
تگهای ایمیج:
- تگ از پیشفرض "latest" است
- میتواند تگ دیگری مشخص کنید
- تگ های متفاوت ممکن است تاریخچه متفاوت داشته باشند
-
بیس ایمیج:
- اولین لایه بیس ایمیج است
- بیس ایمیج تعیین میکند چه ایمیج از آن شروع شده
- بیس ایمیج معمولاً alpine یا ubuntu است
-
Performance:
- دریافت تاریخچه سریع است
- ایمیجهای بزرگ دارای تاریخچه طولانی هستند
- لایههای متعدد = بیشتر حافظه
-
تحلیل:
- میتوانید تاریخچهها را مقایسه کنید
- بیس ایمیج مشترک را پیدا کنید
- تغییرات بین نسخهها را بررسی کنید
دنباله عملیات
- اعتبارسنجی پارامترها
- بررسی وجود ایمیج در DB
- تأیید وجود تگ
- دریافت لیست تگهای ایمیج
- فراخوانی ImageManager برای دریافت تاریخچه
- پردازش و بازگشت نتایج
- Logging موفقیت
مرجع سریع
| وضعیت | کد | توضیح |
|---|---|---|
| موفق | 200 | دریافت تاریخچه موفق |
| پارامتر نامعتبر | 422 | InvalidHistoryParameters |
| DB خطا | 500 | FetchImageState |
| ایمیج یافت نشد | 404 | ImageNotFound |
| تگ یافت نشد | 404 | ImageTagNotFound |
| لیست تگها خطا | 500 | ListImageTagsFailure |
| تاریخچه خطا | 500 | FetchImageHistoryFailure |
| خطای عمومی | 500 | GenericFailure |
موارد استفاده
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