mirror of
https://github.com/wahyd4/home-docker.git
synced 2026-08-08 20:15:03 +10:00
Merge pull request #3 from wahyd4/upgrade-docker-images-2026-06
✨ chore: upgrade Docker images batch — June 2026
This commit is contained in:
@@ -84,7 +84,8 @@ spec:
|
||||
spec:
|
||||
containers:
|
||||
- name: pocket-id-oauth-proxy
|
||||
image: quay.io/oauth2-proxy/oauth2-proxy:v7.6.0
|
||||
# Updated: v7.6.0 -> v7.15.2 (minor bump within v7.x, low risk)
|
||||
image: quay.io/oauth2-proxy/oauth2-proxy:v7.15.2
|
||||
args:
|
||||
- --config=/etc/oauth2-proxy/oauth2_proxy.cfg
|
||||
env:
|
||||
|
||||
+2
-1
@@ -29,7 +29,8 @@ spec:
|
||||
effect: NoSchedule
|
||||
containers:
|
||||
- name: qdrant
|
||||
image: mirror.gcr.io/qdrant/qdrant:v1.16-unprivileged
|
||||
# Updated: v1.16-unprivileged -> v1.18.1-unprivileged (minor bump, low risk)
|
||||
image: mirror.gcr.io/qdrant/qdrant:v1.18.1-unprivileged
|
||||
ports:
|
||||
- containerPort: 6333
|
||||
- containerPort: 6334
|
||||
|
||||
+2
-1
@@ -47,7 +47,8 @@ spec:
|
||||
spec:
|
||||
containers:
|
||||
- name: n8n
|
||||
image: mirror.gcr.io/n8nio/n8n:2.15.0
|
||||
# Updated: 2.15.0 -> 2.23.1 (minor bump, low-medium risk; review n8n changelog for workflow-level breaking changes)
|
||||
image: mirror.gcr.io/n8nio/n8n:2.23.1
|
||||
imagePullPolicy: IfNotPresent
|
||||
securityContext:
|
||||
runAsUser: 0
|
||||
|
||||
@@ -58,7 +58,8 @@ spec:
|
||||
value: "true"
|
||||
- name: address
|
||||
value: 192.168.1.10
|
||||
image: ghcr.io/kube-vip/kube-vip:v0.4.4
|
||||
# Updated: v0.4.4 -> v0.9.2 (conservative upgrade within v0.x; v0->v1 major jump too risky for critical infra)
|
||||
image: ghcr.io/kube-vip/kube-vip:v0.9.2
|
||||
imagePullPolicy: IfNotPresent
|
||||
name: kube-vip
|
||||
resources: {}
|
||||
|
||||
+2
-1
@@ -31,7 +31,8 @@ spec:
|
||||
containers:
|
||||
- name: jackett
|
||||
# https://hub.docker.com/r/linuxserver/jackett/tags
|
||||
image: mirror.gcr.io/linuxserver/jackett:0.24.1124
|
||||
# Updated: 0.24.1124 -> 0.24.1985 (patch bump, low risk)
|
||||
image: mirror.gcr.io/linuxserver/jackett:0.24.1985
|
||||
securityContext:
|
||||
runAsUser: 0
|
||||
imagePullPolicy: IfNotPresent
|
||||
|
||||
+2
-1
@@ -57,7 +57,8 @@ spec:
|
||||
cpu: 200m
|
||||
memory: 256Mi
|
||||
- name: qbit
|
||||
image: mirror.gcr.io/linuxserver/qbittorrent:version-5.1.2-r4
|
||||
# Updated: version-5.1.2-r4 -> version-5.2.1_v2.0.12 (major: 5.1->5.2, medium risk; stable release with libtorrent v2.0.12)
|
||||
image: mirror.gcr.io/linuxserver/qbittorrent:version-5.2.1_v2.0.12
|
||||
securityContext:
|
||||
runAsUser: 0
|
||||
imagePullPolicy: IfNotPresent
|
||||
|
||||
@@ -11,7 +11,8 @@ spec:
|
||||
containers:
|
||||
- name: backup
|
||||
# Same image as in /etc/kubernetes/manifests/etcd.yaml
|
||||
image: k8s.gcr.io/etcd:3.5.1-0
|
||||
# Updated: 3.5.1-0 -> 3.5.30-0 (patch bump within 3.5.x, low risk)
|
||||
image: k8s.gcr.io/etcd:3.5.30-0
|
||||
env:
|
||||
- name: ETCDCTL_API
|
||||
value: "3"
|
||||
|
||||
@@ -0,0 +1,251 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Script to query Docker registries for latest versions."""
|
||||
import subprocess
|
||||
import json
|
||||
import re
|
||||
import sys
|
||||
import time
|
||||
|
||||
# Active images with pinned versions (not commented out, not :latest, not :edge)
|
||||
IMAGES = [
|
||||
("dockerhub", "library/caddy", "2", "mirror.gcr.io/caddy:2"),
|
||||
("dockerhub", "linuxserver/jackett", "0.24.1124", "mirror.gcr.io/linuxserver/jackett:0.24.1124"),
|
||||
("dockerhub", "linuxserver/qbittorrent", "version-5.1.2-r4", "mirror.gcr.io/linuxserver/qbittorrent:version-5.1.2-r4"),
|
||||
("dockerhub", "n8nio/n8n", "2.15.0", "mirror.gcr.io/n8nio/n8n:2.15.0"),
|
||||
("dockerhub", "library/postgres", "14", "mirror.gcr.io/postgres:14"),
|
||||
("dockerhub", "qdrant/qdrant", "v1.16-unprivileged", "mirror.gcr.io/qdrant/qdrant:v1.16-unprivileged"),
|
||||
("ghcr", "kube-vip/kube-vip", "v0.4.4", "ghcr.io/kube-vip/kube-vip:v0.4.4"),
|
||||
("quay", "oauth2-proxy/oauth2-proxy", "v7.6.0", "quay.io/oauth2-proxy/oauth2-proxy:v7.6.0"),
|
||||
]
|
||||
|
||||
def safe_version_sort_key(tag_str):
|
||||
parts = tag_str.lstrip('v').split('.')
|
||||
nums = []
|
||||
for p in parts:
|
||||
try:
|
||||
nums.append(int(re.match(r'(\d+)', p).group(1)))
|
||||
except (ValueError, AttributeError, TypeError):
|
||||
nums.append(0)
|
||||
return nums
|
||||
|
||||
def fetch_dockerhub_tag_details(image_name, max_items=200):
|
||||
try:
|
||||
result = subprocess.run(
|
||||
["curl", "-s", "-L", "-f",
|
||||
f"https://hub.docker.com/v2/repositories/{image_name}/tags?page_size={max_items}&page=1"],
|
||||
capture_output=True, text=True, timeout=20
|
||||
)
|
||||
if result.returncode != 0:
|
||||
return None, f"curl failed: {result.stderr[:300]}"
|
||||
|
||||
data = json.loads(result.stdout)
|
||||
tags_detail = []
|
||||
for tag_data in data.get("results", []):
|
||||
tag_name = tag_data.get("name", "")
|
||||
if tag_name and not tag_name.startswith("sha256:"):
|
||||
tags_detail.append({
|
||||
"name": tag_name,
|
||||
"last_updated": tag_data.get("last_updated", ""),
|
||||
})
|
||||
return tags_detail, None
|
||||
except Exception as e:
|
||||
return None, str(e)
|
||||
|
||||
def fetch_ghcr_tags(image_name):
|
||||
url = f"https://ghcr.io/v2/{image_name}/tags/list"
|
||||
result = subprocess.run(
|
||||
["curl", "-s", "-L", "-f", url],
|
||||
capture_output=True, text=True, timeout=20
|
||||
)
|
||||
if result.returncode != 0:
|
||||
return None, f"GHCR API failed: {result.stderr[:300]}"
|
||||
|
||||
try:
|
||||
data = json.loads(result.stdout)
|
||||
tags = data.get("tags", [])
|
||||
return [t for t in tags if not t.startswith("sha256:")], None
|
||||
except Exception as e:
|
||||
return None, str(e)
|
||||
|
||||
def fetch_quay_tags(image_name):
|
||||
url = f"https://quay.io/api/v1/repository/{image_name}?includeTags=true&limit=100"
|
||||
result = subprocess.run(
|
||||
["curl", "-s", "-L", "-f", url],
|
||||
capture_output=True, text=True, timeout=20
|
||||
)
|
||||
if result.returncode != 0:
|
||||
return None, f"Quay API failed: {result.stderr[:300]}"
|
||||
|
||||
try:
|
||||
data = json.loads(result.stdout)
|
||||
tags = list(data.get("tags", {}).keys())
|
||||
return tags, None
|
||||
except Exception as e:
|
||||
return None, str(e)
|
||||
|
||||
results = []
|
||||
|
||||
for registry_type, image_name, current_tag, display_name in IMAGES:
|
||||
print(f"\n{'='*70}")
|
||||
print(f"CHECKING: {display_name}")
|
||||
print(f"{'='*70}")
|
||||
|
||||
tags_detail = None
|
||||
err = None
|
||||
|
||||
time.sleep(0.5)
|
||||
|
||||
if registry_type == "dockerhub":
|
||||
tags_detail, err = fetch_dockerhub_tag_details(image_name)
|
||||
|
||||
if err:
|
||||
print(f" ❌ Error: {err}")
|
||||
results.append((display_name, current_tag, "ERROR", err))
|
||||
continue
|
||||
|
||||
if not tags_detail:
|
||||
print(f" ❌ No tags found")
|
||||
results.append((display_name, current_tag, "ERROR", "no tags found"))
|
||||
continue
|
||||
|
||||
all_tag_names = [t["name"] for t in tags_detail]
|
||||
print(f" Total tags: {len(all_tag_names)}")
|
||||
|
||||
# --- caddy ---
|
||||
if image_name == "library/caddy":
|
||||
# Filter for semver like v2.8.x, v2.9.x etc.
|
||||
specific = [t for t in all_tag_names
|
||||
if re.match(r'^v?\d+\.\d+\.\d+$', t)]
|
||||
specific.sort(key=safe_version_sort_key, reverse=True)
|
||||
print(f" Version tags: {specific[:15]}")
|
||||
latest_stable = specific[0] if specific else "2"
|
||||
print(f" → Latest stable version: {latest_stable}")
|
||||
|
||||
# '2' is a major-version alias that tracks latest 2.x
|
||||
results.append((display_name, current_tag, latest_stable,
|
||||
f"Tag '2' tracks latest 2.x ({latest_stable})"))
|
||||
|
||||
# --- jackett ---
|
||||
elif image_name == "linuxserver/jackett":
|
||||
# Jackett uses plain semver tags like 0.24.1124
|
||||
jackett_stable = [t for t in all_tag_names
|
||||
if re.match(r'^\d+\.\d+\.\d+$', t)]
|
||||
jackett_stable.sort(key=safe_version_sort_key, reverse=True)
|
||||
print(f" Stable tags (latest first): {jackett_stable[:10]}")
|
||||
latest_stable = jackett_stable[0] if jackett_stable else "unknown"
|
||||
print(f" → Latest stable version: {latest_stable}")
|
||||
results.append((display_name, current_tag, latest_stable, ""))
|
||||
|
||||
# --- qbittorrent ---
|
||||
elif image_name == "linuxserver/qbittorrent":
|
||||
qbit_tags = [t for t in all_tag_names if re.match(r'version-', t)]
|
||||
print(f" 'version-*' tags: {qbit_tags[:15]}")
|
||||
qbit_tags.sort(key=safe_version_sort_key, reverse=True)
|
||||
latest_stable = qbit_tags[0] if qbit_tags else "unknown"
|
||||
print(f" → Latest 'version-*' tag: {latest_stable}")
|
||||
results.append((display_name, current_tag, latest_stable, ""))
|
||||
|
||||
# --- n8n ---
|
||||
elif image_name == "n8nio/n8n":
|
||||
n8n_tags = [t for t in all_tag_names
|
||||
if re.match(r'^\d+\.\d+\.\d+$', t)
|
||||
and not re.search(r'(alpha|beta|rc|dev|nightly)', t, re.I)]
|
||||
n8n_tags.sort(key=safe_version_sort_key, reverse=True)
|
||||
print(f" Stable tags (latest first): {n8n_tags[:10]}")
|
||||
latest_stable = n8n_tags[0] if n8n_tags else "unknown"
|
||||
print(f" → Latest stable version: {latest_stable}")
|
||||
results.append((display_name, current_tag, latest_stable, ""))
|
||||
|
||||
# --- postgres ---
|
||||
elif image_name == "library/postgres":
|
||||
major_tags = [t for t in all_tag_names
|
||||
if re.match(r'^\d+$', t) and int(t) >= 10]
|
||||
major_tags.sort(key=int, reverse=True)
|
||||
print(f" Major version tags: {major_tags[:10]}")
|
||||
latest_stable = major_tags[0] if major_tags else "unknown"
|
||||
print(f" → Latest major version: {latest_stable}")
|
||||
results.append((display_name, current_tag, latest_stable, ""))
|
||||
|
||||
# --- qdrant ---
|
||||
elif image_name == "qdrant/qdrant":
|
||||
# Unprivileged tags
|
||||
unpriv = [t for t in all_tag_names if 'unprivileged' in t.lower()]
|
||||
unpriv.sort(key=safe_version_sort_key, reverse=True)
|
||||
print(f" Unprivileged tags: {unpriv[:15]}")
|
||||
|
||||
# Non-unprivileged stable
|
||||
stable = [t for t in all_tag_names
|
||||
if re.match(r'^v?\d+\.\d+', t)
|
||||
and 'unprivileged' not in t.lower()
|
||||
and not re.search(r'(alpha|beta|rc|dev|nightly)', t, re.I)]
|
||||
stable.sort(key=safe_version_sort_key, reverse=True)
|
||||
print(f" Stable version tags: {stable[:10]}")
|
||||
|
||||
latest_stable = unpriv[0] if unpriv else "unknown"
|
||||
print(f" → Latest unprivileged: {latest_stable}")
|
||||
results.append((display_name, current_tag, latest_stable, ""))
|
||||
|
||||
else:
|
||||
stable = [t for t in all_tag_names
|
||||
if re.match(r'^v?\d+\.\d+', t)
|
||||
and not re.search(r'(alpha|beta|rc|dev|nightly)', t, re.I)]
|
||||
stable.sort(key=safe_version_sort_key, reverse=True)
|
||||
latest_stable = stable[0] if stable else "unknown"
|
||||
results.append((display_name, current_tag, latest_stable, ""))
|
||||
|
||||
elif registry_type == "ghcr":
|
||||
all_tags, err = fetch_ghcr_tags(image_name)
|
||||
if err:
|
||||
print(f" ❌ Error: {err}")
|
||||
results.append((display_name, current_tag, "ERROR", err))
|
||||
continue
|
||||
|
||||
stable = [t for t in all_tags
|
||||
if re.match(r'^v?\d+\.\d+', t)
|
||||
and not re.search(r'(alpha|beta|rc|dev|nightly)', t, re.I)]
|
||||
stable.sort(key=safe_version_sort_key, reverse=True)
|
||||
latest_stable = stable[0] if stable else all_tags[0] if all_tags else "unknown"
|
||||
print(f" Tags: {all_tags[:20]}")
|
||||
print(f" → Latest stable version: {latest_stable}")
|
||||
results.append((display_name, current_tag, latest_stable, ""))
|
||||
|
||||
elif registry_type == "quay":
|
||||
all_tags, err = fetch_quay_tags(image_name)
|
||||
if err:
|
||||
print(f" ❌ Error: {err}")
|
||||
results.append((display_name, current_tag, "ERROR", err))
|
||||
continue
|
||||
|
||||
stable = [t for t in all_tags
|
||||
if re.match(r'^v?\d+\.\d+', t)
|
||||
and not re.search(r'(alpha|beta|rc|dev|nightly)', t, re.I)]
|
||||
stable.sort(key=safe_version_sort_key, reverse=True)
|
||||
latest_stable = stable[0] if stable else all_tags[0] if all_tags else "unknown"
|
||||
print(f" Tags (sample): {all_tags[:20]}")
|
||||
print(f" → Latest stable version: {latest_stable}")
|
||||
results.append((display_name, current_tag, latest_stable, ""))
|
||||
|
||||
# Print summary
|
||||
print("\n\n" + "="*70)
|
||||
print("SUMMARY")
|
||||
print("="*70)
|
||||
|
||||
for display_name, current_tag, latest_tag, note in results:
|
||||
print(f"\n {display_name}")
|
||||
print(f" Current: {current_tag}")
|
||||
|
||||
if latest_tag == "ERROR":
|
||||
print(f" Status: ❌ {note}")
|
||||
continue
|
||||
|
||||
# Normalize for comparison
|
||||
cur = current_tag.lstrip('v').lower()
|
||||
lat = latest_tag.lstrip('v').lower()
|
||||
|
||||
if cur == lat:
|
||||
print(f" Latest: {latest_tag} ✓")
|
||||
else:
|
||||
print(f" Latest: {latest_tag}")
|
||||
print(f" Status: ⚠ UPDATE AVAILABLE")
|
||||
|
||||
print()
|
||||
@@ -0,0 +1,176 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Extract all Docker image references from K8s YAML manifests."""
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
import fnmatch
|
||||
|
||||
REPO = "/home/ai-bot/Code/home-docker"
|
||||
EXCLUDE_DIRS = ["archive", "telephone", "legacy-docker-compose", ".github", ".git"]
|
||||
|
||||
# Patterns to skip: :latest, no tag, or templated variables like ${...}
|
||||
SKIP_TAG_PATTERNS = [
|
||||
re.compile(r'^latest$'),
|
||||
re.compile(r'^\$\{?.*\}?$'),
|
||||
]
|
||||
|
||||
def should_exclude(path):
|
||||
rel = os.path.relpath(path, REPO)
|
||||
parts = rel.split(os.sep)
|
||||
for ex in EXCLUDE_DIRS:
|
||||
if ex in parts:
|
||||
return True
|
||||
return False
|
||||
|
||||
def extract_images(content):
|
||||
"""Extract image references from YAML content (both image: field and image: line)."""
|
||||
images = set()
|
||||
for line in content.splitlines():
|
||||
# Match image: field in YAML
|
||||
m = re.match(r'^\s*image:\s*["\']?(.+?)["\']?\s*$', line)
|
||||
if not m:
|
||||
# Also match inline: image: "..."
|
||||
m = re.search(r'image:\s*["\']?([a-zA-Z0-9._/-]+(?::[a-zA-Z0-9._-]+)?)["\']?', line)
|
||||
if m:
|
||||
img = m.group(1).strip()
|
||||
# Skip if it contains env var patterns
|
||||
if '${' in img or '$(' in img or img.startswith('$'):
|
||||
continue
|
||||
images.add(img)
|
||||
continue
|
||||
img = m.group(1).strip().rstrip(',')
|
||||
# Handle YAML multiline/complex values
|
||||
img = img.strip('"').strip("'")
|
||||
# Skip if it contains env var patterns
|
||||
if '${' in img or '$(' in img or img.startswith('$'):
|
||||
continue
|
||||
# Skip empty
|
||||
if not img:
|
||||
continue
|
||||
images.add(img)
|
||||
return images
|
||||
|
||||
def parse_image(img_str):
|
||||
"""Parse image string into (registy_prefix, image_name, tag)."""
|
||||
img_str = img_str.strip()
|
||||
# Check for explicit registry (docker.io, ghcr.io, quay.io, etc.)
|
||||
registry = ""
|
||||
|
||||
if '/' in img_str:
|
||||
parts = img_str.split('/')
|
||||
# Check if first part looks like a registry (contains . or :port)
|
||||
if len(parts) >= 2 and ('.' in parts[0] or ':' in parts[0] or parts[0] == 'localhost' or parts[0] == 'docker.io'):
|
||||
registry = parts[0]
|
||||
image_path = '/'.join(parts[1:])
|
||||
else:
|
||||
image_path = img_str
|
||||
else:
|
||||
image_path = img_str
|
||||
|
||||
# Split tag
|
||||
if ':' in image_path:
|
||||
name, tag = image_path.rsplit(':', 1)
|
||||
else:
|
||||
name = image_path
|
||||
tag = 'latest'
|
||||
|
||||
# Skip :latest and no-tag (we only care about pinned versions)
|
||||
if tag == 'latest' or not tag:
|
||||
return None
|
||||
|
||||
# Skip if tag looks like a variable
|
||||
if re.match(r'^\$\{', tag) or tag.startswith('$'):
|
||||
return None
|
||||
|
||||
# Full qualified name with registry prefix for lookups
|
||||
if registry:
|
||||
full_name = f"{registry}/{name}"
|
||||
elif '/' not in name:
|
||||
full_name = f"docker.io/library/{name}"
|
||||
else:
|
||||
# Default to docker.io
|
||||
full_name = f"docker.io/{name}"
|
||||
|
||||
return {
|
||||
'raw': img_str,
|
||||
'registry': registry or 'docker.io',
|
||||
'name': name,
|
||||
'tag': tag,
|
||||
'full_name': full_name,
|
||||
'lookup_name': f"{name}" if not registry else f"{registry}/{name}",
|
||||
}
|
||||
|
||||
def main():
|
||||
all_images = {}
|
||||
files_with_images = {}
|
||||
|
||||
for root, dirs, files in os.walk(REPO):
|
||||
# Skip excluded dirs
|
||||
dirs[:] = [d for d in dirs if d not in EXCLUDE_DIRS and not d.startswith('.')]
|
||||
|
||||
for fname in files:
|
||||
if not (fname.endswith('.yaml') or fname.endswith('.yml')):
|
||||
continue
|
||||
fpath = os.path.join(root, fname)
|
||||
if should_exclude(fpath):
|
||||
continue
|
||||
|
||||
# Skip non-manifest files
|
||||
rel = os.path.relpath(fpath, REPO)
|
||||
if rel.startswith('legacy-docker-compose'):
|
||||
continue
|
||||
|
||||
try:
|
||||
with open(fpath, 'r') as f:
|
||||
content = f.read()
|
||||
except Exception as e:
|
||||
print(f"Error reading {fpath}: {e}", file=sys.stderr)
|
||||
continue
|
||||
|
||||
images = extract_images(content)
|
||||
if images:
|
||||
files_with_images[rel] = images
|
||||
for img_str in images:
|
||||
parsed = parse_image(img_str)
|
||||
if parsed:
|
||||
if img_str not in all_images:
|
||||
all_images[img_str] = parsed
|
||||
all_images[img_str]['files'] = []
|
||||
all_images[img_str]['files'].append(rel)
|
||||
|
||||
# Print results
|
||||
print("=" * 80)
|
||||
print("DOCKER IMAGES FOUND IN K8S MANIFESTS")
|
||||
print("=" * 80)
|
||||
|
||||
for img_str in sorted(all_images.keys()):
|
||||
info = all_images[img_str]
|
||||
print(f"\n--- {img_str} ---")
|
||||
print(f" Registry: {info['registry']}")
|
||||
print(f" Image Name: {info['name']}")
|
||||
print(f" Tag: {info['tag']}")
|
||||
print(f" Lookup Name: {info['lookup_name']}")
|
||||
print(f" Files: {', '.join(info['files'])}")
|
||||
|
||||
print("\n" + "=" * 80)
|
||||
print(f"Total unique images: {len(all_images)}")
|
||||
|
||||
# Output as JSON for further processing
|
||||
import json
|
||||
output = {}
|
||||
for img_str, info in sorted(all_images.items()):
|
||||
output[img_str] = {
|
||||
'registry': info['registry'],
|
||||
'image_name': info['name'],
|
||||
'tag': info['tag'],
|
||||
'lookup_name': info['lookup_name'],
|
||||
'files': info['files'],
|
||||
}
|
||||
|
||||
json_path = os.path.join(REPO, 'scripts', 'images.json')
|
||||
with open(json_path, 'w') as f:
|
||||
json.dump(output, f, indent=2)
|
||||
print(f"\nJSON output written to: {json_path}")
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -0,0 +1,112 @@
|
||||
# Docker 镜像版本检查报告
|
||||
## 仓库: /home/ai-bot/Code/home-docker
|
||||
## 检查时间: 2026-06-01
|
||||
|
||||
---
|
||||
|
||||
## 一、检查范围
|
||||
|
||||
- 排除了 `archive/` 和 `telephone/` 目录
|
||||
- 排除了 `legacy-docker-compose/` 目录(非 K8s 资源)
|
||||
- 排除了 `:.latest`、无标签(默认 `:latest`)和移动标签(如 `:edge`)
|
||||
- 排除了注释掉的代码块
|
||||
|
||||
---
|
||||
|
||||
## 二、活跃的固定版本镜像
|
||||
|
||||
共发现 **9 个** 活跃的固定版本镜像。
|
||||
|
||||
---
|
||||
|
||||
### 1. `mirror.gcr.io/caddy:2` → `caddy:2.11.3` ✓ (标签 '2' 是 major version 别名)
|
||||
- **文件**: `home-apps/home-proxy.yaml`, `media/static-file.yaml`
|
||||
- **说明**: `caddy:2` 是 major version 标签,会自动跟踪最新的 2.x 版本(当前最新为 2.11.3)
|
||||
- **建议**: 无需更新,`caddy:2` 会自动跟随 2.x 最新
|
||||
|
||||
### 2. `mirror.gcr.io/linuxserver/jackett:0.24.1124` → `jackett:0.24.1985` ⚠️ 需要更新
|
||||
- **文件**: `media/jackett.yaml`
|
||||
- **当前版本**: 0.24.1124
|
||||
- **最新版本**: 0.24.1985
|
||||
- **差距**: 落后 861 个构建版本
|
||||
|
||||
### 3. `mirror.gcr.io/linuxserver/qbittorrent:version-5.1.2-r4` → `version-5.2.1_v2.0.12` ⚠️ 需要更新
|
||||
- **文件**: `media/media.yaml`
|
||||
- **当前版本**: version-5.1.2-r4
|
||||
- **最新版本**: version-5.2.1_v2.0.12
|
||||
- **差距**: 从 qBittorrent 5.1.2 升级到 5.2.1
|
||||
|
||||
### 4. `mirror.gcr.io/n8nio/n8n:2.15.0` → `n8n:2.23.1` ⚠️ 需要更新
|
||||
- **文件**: `home-apps/n8n.yaml`
|
||||
- **当前版本**: 2.15.0
|
||||
- **最新版本**: 2.23.1
|
||||
- **差距**: 落后 9 个小版本
|
||||
|
||||
### 5. `mirror.gcr.io/postgres:14` → `postgres:18` ⚠️ 可能需要考虑更新
|
||||
- **文件**: `on-demand/once-postgres-backjobs.yaml`, `backup-jobs/backup-cronjobs.yaml`
|
||||
- **当前版本**: 14(PostgreSQL 14,已停止更新/维护)
|
||||
- **最新版本**: 18(PostgreSQL 18,最新 active 版本)
|
||||
- **说明**: 此镜像仅用于 pg_dump 备份命令,版本兼容性较好,但仍建议考虑升级
|
||||
- **PG 支持状态**: PostgreSQL 14 于 2025-11-13 停止接收修复
|
||||
|
||||
### 6. `mirror.gcr.io/qdrant/qdrant:v1.16-unprivileged` → `v1.18.1-unprivileged` ⚠️ 需要更新
|
||||
- **文件**: `db/qdrant.yaml`
|
||||
- **当前版本**: v1.16-unprivileged
|
||||
- **最新版本**: v1.18.1-unprivileged
|
||||
- **差距**: 落后 2 个 major 版本
|
||||
|
||||
### 7. `ghcr.io/kube-vip/kube-vip:v0.4.4` → `v1.2.0` ⚠️ 需要更新
|
||||
- **文件**: `kube-vip/daemonset.yaml`
|
||||
- **当前版本**: v0.4.4
|
||||
- **最新 GHCR 可用**: v1.2.0(GitHub release)
|
||||
- **最新 v0.9.x 可用**: v0.9.2
|
||||
- **差距**: 落后 0.4.4 → 1.2.0 共 28+ 个版本
|
||||
- **⚠️ 注意**: 这涉及 Kubernetes 集群 VIP 管理组件,升级需谨慎
|
||||
|
||||
### 8. `k8s.gcr.io/etcd:3.5.1-0` → `3.5.30-0` ⚠️ 需要更新
|
||||
- **文件**: `on-demand/once-etcd-job.yaml`
|
||||
- **当前版本**: 3.5.1-0
|
||||
- **最新 3.5.x 版本**: 3.5.30-0
|
||||
- **差距**: 落后 3.5.1 → 3.5.30(29 个小版本)
|
||||
- **说明**: 该镜像仅用于备份 Job(etcdctl snapshot),工具兼容性较好
|
||||
|
||||
### 9. `quay.io/oauth2-proxy/oauth2-proxy:v7.6.0` → `v7.15.2` ⚠️ 需要更新
|
||||
- **文件**: `adhoc-config/oauth2-proxy.yaml`
|
||||
- **当前版本**: v7.6.0
|
||||
- **最新版本**: v7.15.2
|
||||
- **差距**: 落后 7.6.0 → 7.15.2(9 个小版本)
|
||||
|
||||
---
|
||||
|
||||
## 三、跳过的镜像(不需要检查)
|
||||
|
||||
| 镜像 | 原因 |
|
||||
|------|------|
|
||||
| `mirror.gcr.io/oznu/cloudflare-ddns` | 无标签(默认 :latest) |
|
||||
| `czerkwonk/ping_exporter` | 无标签(默认 :latest) |
|
||||
| `mirror.gcr.io/qmcgaw/gluetun:latest` | :latest 标签 |
|
||||
| `ghcr.io/wahyd4/hey-search:latest` | :latest 标签 |
|
||||
| `mirror.gcr.io/wahyd4/aria2-ui:edge` | 移动标签 |
|
||||
| `tikazyq/crawlab:latest` | :latest 标签 |
|
||||
| `alpine:3` | 注释掉的代码块 |
|
||||
| `ghcr.io/wonderfall/nextcloud:24` | 注释掉的代码块 |
|
||||
| `docker.elastic.co/beats/elastic-agent:8.0.1` | 注释掉的代码块 |
|
||||
| `k8s.gcr.io/etcd:3.5.1-0` (in backup-cronjobs.yaml) | 注释掉的代码块 |
|
||||
|
||||
---
|
||||
|
||||
## 四、需要更新的镜像汇总
|
||||
|
||||
```
|
||||
镜像名:当前标签 → 最新可用标签 状态
|
||||
─────────────────────────────────────────────────────────────────
|
||||
linuxserver/jackett:0.24.1124 → 0.24.1985 ⚠️ 需要更新
|
||||
linuxserver/qbittorrent:version-5.1.2-r4 → version-5.2.1_v2.0.12 ⚠️ 需要更新
|
||||
n8nio/n8n:2.15.0 → 2.23.1 ⚠️ 需要更新
|
||||
postgres:14 → 18 ⚠️ 建议更新
|
||||
qdrant/qdrant:v1.16-unprivileged → v1.18.1-unprivileged ⚠️ 需要更新
|
||||
kube-vip/kube-vip:v0.4.4 → v1.2.0 ⚠️ 需要更新
|
||||
k8s.gcr.io/etcd:3.5.1-0 → 3.5.30-0 ⚠️ 需要更新
|
||||
oauth2-proxy/oauth2-proxy:v7.6.0 → v7.15.2 ⚠️ 需要更新
|
||||
caddy:2 (major version alias, tracks 2.x latest) ✓ 已最新
|
||||
```
|
||||
@@ -0,0 +1,122 @@
|
||||
{
|
||||
"alpine:3": {
|
||||
"registry": "docker.io",
|
||||
"image_name": "alpine",
|
||||
"tag": "3",
|
||||
"lookup_name": "alpine",
|
||||
"files": [
|
||||
"media/media.yaml"
|
||||
]
|
||||
},
|
||||
"docker.elastic.co/beats/elastic-agent:8.0.1": {
|
||||
"registry": "docker.elastic.co",
|
||||
"image_name": "beats/elastic-agent",
|
||||
"tag": "8.0.1",
|
||||
"lookup_name": "docker.elastic.co/beats/elastic-agent",
|
||||
"files": [
|
||||
"es/agent.yaml"
|
||||
]
|
||||
},
|
||||
"ghcr.io/kube-vip/kube-vip:v0.4.4": {
|
||||
"registry": "ghcr.io",
|
||||
"image_name": "kube-vip/kube-vip",
|
||||
"tag": "v0.4.4",
|
||||
"lookup_name": "ghcr.io/kube-vip/kube-vip",
|
||||
"files": [
|
||||
"kube-vip/daemonset.yaml"
|
||||
]
|
||||
},
|
||||
"ghcr.io/wonderfall/nextcloud:24": {
|
||||
"registry": "ghcr.io",
|
||||
"image_name": "wonderfall/nextcloud",
|
||||
"tag": "24",
|
||||
"lookup_name": "ghcr.io/wonderfall/nextcloud",
|
||||
"files": [
|
||||
"media/media.yaml"
|
||||
]
|
||||
},
|
||||
"k8s.gcr.io/etcd:3.5.1-0": {
|
||||
"registry": "k8s.gcr.io",
|
||||
"image_name": "etcd",
|
||||
"tag": "3.5.1-0",
|
||||
"lookup_name": "k8s.gcr.io/etcd",
|
||||
"files": [
|
||||
"on-demand/once-etcd-job.yaml",
|
||||
"backup-jobs/backup-cronjobs.yaml"
|
||||
]
|
||||
},
|
||||
"mirror.gcr.io/caddy:2": {
|
||||
"registry": "mirror.gcr.io",
|
||||
"image_name": "caddy",
|
||||
"tag": "2",
|
||||
"lookup_name": "mirror.gcr.io/caddy",
|
||||
"files": [
|
||||
"home-apps/home-proxy.yaml",
|
||||
"media/static-file.yaml"
|
||||
]
|
||||
},
|
||||
"mirror.gcr.io/linuxserver/jackett:0.24.1124": {
|
||||
"registry": "mirror.gcr.io",
|
||||
"image_name": "linuxserver/jackett",
|
||||
"tag": "0.24.1124",
|
||||
"lookup_name": "mirror.gcr.io/linuxserver/jackett",
|
||||
"files": [
|
||||
"media/jackett.yaml"
|
||||
]
|
||||
},
|
||||
"mirror.gcr.io/linuxserver/qbittorrent:version-5.1.2-r4": {
|
||||
"registry": "mirror.gcr.io",
|
||||
"image_name": "linuxserver/qbittorrent",
|
||||
"tag": "version-5.1.2-r4",
|
||||
"lookup_name": "mirror.gcr.io/linuxserver/qbittorrent",
|
||||
"files": [
|
||||
"media/media.yaml"
|
||||
]
|
||||
},
|
||||
"mirror.gcr.io/n8nio/n8n:2.15.0": {
|
||||
"registry": "mirror.gcr.io",
|
||||
"image_name": "n8nio/n8n",
|
||||
"tag": "2.15.0",
|
||||
"lookup_name": "mirror.gcr.io/n8nio/n8n",
|
||||
"files": [
|
||||
"home-apps/n8n.yaml"
|
||||
]
|
||||
},
|
||||
"mirror.gcr.io/postgres:14": {
|
||||
"registry": "mirror.gcr.io",
|
||||
"image_name": "postgres",
|
||||
"tag": "14",
|
||||
"lookup_name": "mirror.gcr.io/postgres",
|
||||
"files": [
|
||||
"on-demand/once-postgres-backjobs.yaml",
|
||||
"backup-jobs/backup-cronjobs.yaml"
|
||||
]
|
||||
},
|
||||
"mirror.gcr.io/qdrant/qdrant:v1.16-unprivileged": {
|
||||
"registry": "mirror.gcr.io",
|
||||
"image_name": "qdrant/qdrant",
|
||||
"tag": "v1.16-unprivileged",
|
||||
"lookup_name": "mirror.gcr.io/qdrant/qdrant",
|
||||
"files": [
|
||||
"db/qdrant.yaml"
|
||||
]
|
||||
},
|
||||
"mirror.gcr.io/wahyd4/aria2-ui:edge": {
|
||||
"registry": "mirror.gcr.io",
|
||||
"image_name": "wahyd4/aria2-ui",
|
||||
"tag": "edge",
|
||||
"lookup_name": "mirror.gcr.io/wahyd4/aria2-ui",
|
||||
"files": [
|
||||
"media/media.yaml"
|
||||
]
|
||||
},
|
||||
"quay.io/oauth2-proxy/oauth2-proxy:v7.6.0": {
|
||||
"registry": "quay.io",
|
||||
"image_name": "oauth2-proxy/oauth2-proxy",
|
||||
"tag": "v7.6.0",
|
||||
"lookup_name": "quay.io/oauth2-proxy/oauth2-proxy",
|
||||
"files": [
|
||||
"adhoc-config/oauth2-proxy.yaml"
|
||||
]
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user