用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
直接命令不会经过审查 Prompt;运行前请先检查来源。
npx skills add https://github.com/microwind/ai-skills --skill dockerfile命令会保持在同一行。复制前请横向滚动并检查完整内容。
想先保存到本地?可下载 SkillsMP 当前能够提供的文件。
基于 SOC 职业分类
正在显示 SKILL.md
| name | Dockerfile分析器 |
| description | 当分析Dockerfile时,检查最佳实践,优化Docker配置,验证安全性。分析Dockerfile以优化和安全。 |
| license | MIT |
Docker镜像可能膨胀到GB级别且存在安全隐患。无效的Dockerfile会导致构建失败或创建不安全的容器。在构建和部署前必须进行分析。
核心原则: 轻量镜像构建速度快,安全镜像值得信赖。好的Dockerfile应该层次清晰、安全性高、体积小、构建快。
始终:
触发短语:
❌ 镜像过大
❌ 安全隐患
❌ 构建缓慢
❌ 维护困难
#!/usr/bin/env python3
import re
import os
import json
import hashlib
from pathlib import Path
from typing import Dict, List, Optional, Tuple
from dataclasses import dataclass
from enum import Enum
class Severity(Enum):
"""严重程度"""
INFO = "info"
WARNING = "warning"
ERROR = "error"
CRITICAL = "critical"
@dataclass
class DockerfileIssue:
"""Dockerfile问题"""
line_number: int
severity: Severity
rule: str
message: str
suggestion: str
line_content: str
@dataclass
class LayerInfo:
"""层次信息"""
instruction: str
content: str
estimated_size: int
cache_hit: bool = False
class DockerfileAnalyzer:
"""Dockerfile分析器"""
def __init__(self):
self.issues: [DockerfileIssue] = []
.layers: [LayerInfo] = []
.security_rules = ._load_security_rules()
.optimization_rules = ._load_optimization_rules()
() -> [, ]:
{
: {
: ,
: ,
: Severity.ERROR,
:
},
: {
: ,
: ,
: Severity.CRITICAL,
:
},
: {
: ,
: ,
: Severity.WARNING,
:
},
: {
: ,
: ,
: Severity.ERROR,
:
},
: {
: ,
: ,
: Severity.INFO,
:
}
}
() -> [, ]:
{
: {
: ,
: ,
: Severity.INFO,
:
},
: {
: ,
: ,
: Severity.WARNING,
:
},
: {
: ,
: ,
: Severity.INFO,
:
},
: {
: ,
: ,
: Severity.WARNING,
:
}
}
() -> [[, ]]:
:
(dockerfile_path, , encoding=) f:
lines = f.readlines()
instructions = []
i, line (lines, ):
line = line.strip()
line line.startswith():
line.endswith():
multi_line = line[:-]
j = i
j < (lines):
next_line = lines[j].strip()
next_line.endswith():
multi_line += + next_line[:-]
j +=
:
multi_line += + next_line
instructions.append((multi_line, i))
i = j
:
instructions.append((line, i))
instructions
FileNotFoundError:
FileNotFoundError()
Exception e:
Exception()
():
instruction, line_num instructions:
rule_name, rule .security_rules.items():
re.search(rule[], instruction, re.IGNORECASE):
issue = DockerfileIssue(
line_number=line_num,
severity=rule[],
rule=rule_name,
message=rule[],
suggestion=rule[],
line_content=instruction
)
.issues.append(issue)
():
instruction, line_num instructions:
rule_name, rule .optimization_rules.items():
re.search(rule[], instruction, re.IGNORECASE):
issue = DockerfileIssue(
line_number=line_num,
severity=rule[],
rule=rule_name,
message=rule[],
suggestion=rule[],
line_content=instruction
)
.issues.append(issue)
():
.layers = []
instruction, line_num instructions:
parts = instruction.split(, )
(parts) >= :
cmd_type = parts[].upper()
content = parts[]
estimated_size = ._estimate_layer_size(cmd_type, content)
layer = LayerInfo(
instruction=cmd_type,
content=content,
estimated_size=estimated_size
)
.layers.append(layer)
() -> :
cmd_type == :
* *
cmd_type == cmd_type == :
* *
cmd_type == :
content:
* *
content:
* *
:
* *
:
* *
() -> :
(layer.estimated_size layer .layers)
() -> []:
suggestions = []
total_size = .calculate_image_size()
total_size > * * :
suggestions.append()
run_instructions = [layer layer .layers layer.instruction == ]
(run_instructions) > :
suggestions.append()
copy_instructions = [layer layer .layers layer.instruction == ]
(copy_instructions) > :
suggestions.append()
.layers .layers[].content.lower():
suggestions.append()
suggestions
() -> :
issues_by_severity = {}
severity Severity:
issues_by_severity[severity.value] = [
{
: issue.line_number,
: issue.rule,
: issue.message,
: issue.suggestion,
: issue.line_content
}
issue .issues issue.severity == severity
]
total_issues = (.issues)
critical_issues = (issues_by_severity[])
error_issues = (issues_by_severity[])
warning_issues = (issues_by_severity[])
info_issues = (issues_by_severity[])
layer_analysis = {
: (.layers),
: (.calculate_image_size() / ( * ), ),
: [
{
: layer.instruction,
: (layer.estimated_size / ( * ), )
}
layer .layers
]
}
optimizations = .suggest_optimizations()
{
: {
: total_issues,
: critical_issues,
: error_issues,
: warning_issues,
: info_issues,
: (.calculate_image_size() / ( * ), )
},
: issues_by_severity,
: layer_analysis,
: optimizations
}
() -> :
.issues = []
.layers = []
instructions = .parse_dockerfile(dockerfile_path)
.analyze_security(instructions)
.analyze_optimization(instructions)
.analyze_layers(instructions)
.generate_report()
__name__ == :
argparse
parser = argparse.ArgumentParser(description=)
parser.add_argument(, nargs=, default=, =)
parser.add_argument(, =)
parser.add_argument(, choices=[, ], default=, =)
args = parser.parse_args()
analyzer = DockerfileAnalyzer()
:
report = analyzer.analyze(args.dockerfile)
args. == :
args.output:
(args.output, , encoding=) f:
json.dump(report, f, indent=, ensure_ascii=)
()
:
(json.dumps(report, indent=, ensure_ascii=))
:
( * )
()
( * )
summary = report[]
()
()
()
()
()
()
()
report[][]:
()
issue report[][]:
()
()
()
report[][]:
()
issue report[][]:
()
()
()
report[][]:
()
issue report[][]:
()
()
()
report[]:
()
suggestion report[]:
()
()
layer_analysis = report[]
()
()
()
Exception e:
()
exit()
#!/bin/bash
# dockerfile-optimizer.sh - Dockerfile优化工具
set -e
# 配置
DOCKERFILE=${1:-"Dockerfile"}
OUTPUT_FILE=${2:-"Dockerfile.optimized"}
BACKUP_FILE="Dockerfile.backup"
# 颜色输出
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'
log_info() {
echo -e "${GREEN}[INFO]${NC} $1"
}
log_warn() {
echo -e "${YELLOW}[WARN]${NC} $1"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
log_step() {
echo -e "${BLUE}[STEP]${NC} $1"
}
# 检查Dockerfile是否存在
check_dockerfile() {
if [ ! -f "$DOCKERFILE" ]; then
log_error "Dockerfile不存在: $DOCKERFILE"
exit 1
fi
log_info "分析Dockerfile: $DOCKERFILE"
}
() {
[ ! -f ];
log_info
}
() {
log_step
grep -q ;
log_warn
grep -q ;
sed -i.bak
log_info
grep -q ;
sed -i.bak
log_info
grep -q && ! grep -q ;
log_warn
}
() {
log_step
temp_file=$()
awk >
python3 -c
log_info
}
() {
log_step
grep -q && grep -q ;
log_warn
[ ! -f ];
log_warn
> .dockerignore <<
log_info
}
() {
log_step
! grep -q ;
log_warn
>>
>>
>>
>>
log_info
! grep -q ;
log_warn
sed -i
log_info
}
() {
log_step
! grep -q ;
grep -q ;
log_warn
grep -q ;
log_info
> Dockerfile.multi-stage <<
FROM node:18-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
RUN npm run build
FROM node:18-alpine AS runtime
RUN addgroup -g 1001 -S nodejs
RUN adduser -S nextjs -u 1001
WORKDIR /app
COPY --from=builder --=nextjs:nodejs /app/dist ./dist
COPY --from=builder --=nextjs:nodejs /app/node_modules ./node_modules
COPY --from=builder --=nextjs:nodejs /app/package.json ./package.json
USER nextjs
EXPOSE 3000
CMD [, ]
EOF
log_info
log_info
}
() {
log_step
report_file=
> <<
grep -q ;
>>
grep -q ;
>>
grep -q ;
>>
[ -f ];
>>
>>
>>
>>
>>
>>
>>
log_info
}
() {
log_info
check_dockerfile
backup_original
optimize_base_image
optimize_run_commands
optimize_copy_commands
add_security_config
optimize_multi_stage
generate_optimization_report
log_info
log_info
log_info
}
() {
}
[ = ] || [ = ];
show_help
0
main
#!/usr/bin/env python3
import re
import json
import requests
from typing import Dict, List, Optional
from dataclasses import dataclass
from enum import Enum
class VulnerabilityLevel(Enum):
"""漏洞等级"""
LOW = "low"
MEDIUM = "medium"
HIGH = "high"
CRITICAL = "critical"
@dataclass
class SecurityIssue:
"""安全问题"""
type: str
level: VulnerabilityLevel
description: str
recommendation: str
cve_id: Optional[str] = None
package: Optional[str] = None
version: Optional[str] = None
class DockerSecurityScanner:
"""Docker安全扫描器"""
def __init__(self):
self.security_issues: List[SecurityIssue] = []
self.base_image_vulnerabilities = {}
def scan_dockerfile(self, dockerfile_path: ) -> [SecurityIssue]:
.security_issues = []
:
(dockerfile_path, , encoding=) f:
content = f.read()
._scan_user_privileges(content)
._scan_secrets(content)
._scan_network_security(content)
._scan_file_permissions(content)
._scan_base_image(content)
.security_issues
FileNotFoundError:
FileNotFoundError()
Exception e:
Exception()
():
re.search(, content, re.IGNORECASE):
re.search(, content, re.IGNORECASE) content:
.security_issues.append(SecurityIssue(
=,
level=VulnerabilityLevel.HIGH,
description=,
recommendation=
))
re.search(, content, re.IGNORECASE):
.security_issues.append(SecurityIssue(
=,
level=VulnerabilityLevel.MEDIUM,
description=,
recommendation=
))
():
secret_patterns = [
(, ),
(, ),
(, ),
(, ),
(, ),
]
pattern, description secret_patterns:
re.search(pattern, content, re.IGNORECASE):
.security_issues.append(SecurityIssue(
=,
level=VulnerabilityLevel.CRITICAL,
description=description,
recommendation=
))
re.search(, content, re.IGNORECASE):
.security_issues.append(SecurityIssue(
=,
level=VulnerabilityLevel.HIGH,
description=,
recommendation=
))
():
expose_count = (re.findall(, content, re.IGNORECASE))
expose_count > :
.security_issues.append(SecurityIssue(
=,
level=VulnerabilityLevel.MEDIUM,
description=,
recommendation=
))
re.search(, content, re.IGNORECASE) re.search(, content, re.IGNORECASE):
.security_issues.append(SecurityIssue(
=,
level=VulnerabilityLevel.MEDIUM,
description=,
recommendation=
))
content:
.security_issues.append(SecurityIssue(
=,
level=VulnerabilityLevel.HIGH,
description=,
recommendation=
))
():
re.search(, content, re.IGNORECASE):
.security_issues.append(SecurityIssue(
=,
level=VulnerabilityLevel.MEDIUM,
description=,
recommendation=
))
re.search(, content, re.IGNORECASE):
.security_issues.append(SecurityIssue(
=,
level=VulnerabilityLevel.MEDIUM,
description=,
recommendation=
))
():
from_match = re.search(, content, re.IGNORECASE)
from_match:
base_image = from_match.group()
base_image base_image.count() == :
.security_issues.append(SecurityIssue(
=,
level=VulnerabilityLevel.HIGH,
description=,
recommendation=
))
base_image base_image.startswith():
:
.security_issues.append(SecurityIssue(
=,
level=VulnerabilityLevel.MEDIUM,
description=,
recommendation=
))
() -> :
:
vulnerabilities = {
: ,
: ,
: ,
: ,
: []
}
mock_vulns = [
{
: ,
: ,
: ,
: ,
:
},
{
: ,
: ,
: ,
: ,
:
}
]
vuln mock_vulns:
vulnerabilities[vuln[]] +=
vulnerabilities[].append(vuln)
vulnerabilities
Exception e:
{: (e)}
() -> :
dockerfile_issues = .scan_dockerfile(dockerfile_path)
image_vulnerabilities =
image_name:
image_vulnerabilities = .scan_image_vulnerabilities(image_name)
issues_by_level = {}
level VulnerabilityLevel:
issues_by_level[level.value] = [
{
: issue.,
: issue.description,
: issue.recommendation
}
issue dockerfile_issues issue.level == level
]
total_issues = (dockerfile_issues)
critical_count = (issues_by_level[])
high_count = (issues_by_level[])
medium_count = (issues_by_level[])
low_count = (issues_by_level[])
score =
score -= critical_count *
score -= high_count *
score -= medium_count *
score -= low_count *
score = (, score)
{
: score,
: total_issues,
: issues_by_level,
: image_vulnerabilities,
: ._generate_recommendations(dockerfile_issues)
}
() -> []:
recommendations = ()
issue issues:
recommendations.add(issue.recommendation)
recommendations.add()
recommendations.add()
recommendations.add()
recommendations.add()
(recommendations)
__name__ == :
argparse
parser = argparse.ArgumentParser(description=)
parser.add_argument(, nargs=, default=, =)
parser.add_argument(, =)
parser.add_argument(, =)
parser.add_argument(, choices=[, ], default=, =)
args = parser.parse_args()
scanner = DockerSecurityScanner()
:
report = scanner.generate_security_report(args.dockerfile, args.image)
args. == :
args.output:
(args.output, , encoding=) f:
json.dump(report, f, indent=, ensure_ascii=)
()
:
(json.dumps(report, indent=, ensure_ascii=))
:
( * )
()
( * )
()
()
()
level [, , , ]:
issues = report[][level]
issues:
level_names = {
: ,
: ,
: ,
:
}
()
issue issues:
()
()
()
report[]:
()
rec report[]:
()
()
report[] report[]:
vulns = report[]
()
()
()
()
()
Exception e:
()
exit()
Large Base 镜像s
ubuntu:latest (1.2GB) vs alpine:latest (7MB)node:18 (900MB) vs node:18-alpine (150MB)Unnecessary 层s
RUN command creates 一个 层RUN apt-get update && apt-get install should 是 ONE commandRunning 作为 Root
USER appuser directiveCopying Entire Directory
COPY . /app includes everything (node_modules, .git, etc.).dockerignore 到 exclude filesNot Pinning Base 镜像
FROM node uses latest (unpredictable)FROM node:18.14.0 (specific 版本).dockerignore excludes unnecessary files