v0.0.3 published
This commit is contained in:
156
dev/test/v0.0.4/select_best_mirror.sh
Normal file
156
dev/test/v0.0.4/select_best_mirror.sh
Normal file
@@ -0,0 +1,156 @@
|
||||
#!/bin/bash
|
||||
# 镜像源自动选择脚本
|
||||
# Mirror Source Auto Selection Script
|
||||
#
|
||||
# 此脚本将测试多个Ubuntu镜像源的连通性,并选择最快的源
|
||||
|
||||
# 定义镜像源列表
|
||||
declare -A MIRRORS=(
|
||||
["tsinghua"]="https://mirrors.tuna.tsinghua.edu.cn/ubuntu"
|
||||
["aliyun"]="https://mirrors.aliyun.com/ubuntu"
|
||||
["huawei"]="https://mirrors.huaweicloud.com/ubuntu"
|
||||
["ustc"]="https://mirrors.ustc.edu.cn/ubuntu"
|
||||
["163"]="https://mirrors.163.com/ubuntu"
|
||||
["sjtu"]="https://mirror.sjtu.edu.cn/ubuntu"
|
||||
["official"]="http://archive.ubuntu.com/ubuntu"
|
||||
)
|
||||
|
||||
# 测试镜像源连通性和速度
|
||||
test_mirror() {
|
||||
local name=$1
|
||||
local url=$2
|
||||
local test_file="ls-lR.gz"
|
||||
|
||||
echo "测试镜像源: $name ($url)"
|
||||
|
||||
# 测试连通性
|
||||
if ! curl -s --connect-timeout 5 --max-time 10 "$url/dists/jammy/Release" > /dev/null 2>&1; then
|
||||
echo " [FAIL] 连接失败"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# 测试下载速度 (下载少量数据)
|
||||
local start_time=$(date +%s.%N)
|
||||
if curl -s --connect-timeout 5 --max-time 10 "$url/dists/jammy/Release" > /dev/null 2>&1; then
|
||||
local end_time=$(date +%s.%N)
|
||||
local duration=$(echo "$end_time - $start_time" | bc -l 2>/dev/null || echo "0")
|
||||
echo " [SUCCESS] 响应时间: ${duration}s"
|
||||
echo "$duration:$name:$url"
|
||||
return 0
|
||||
else
|
||||
echo " [FAIL] 下载测试失败"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# 选择最佳镜像源
|
||||
select_best_mirror() {
|
||||
echo "=== Ubuntu 镜像源连通性测试 ==="
|
||||
echo
|
||||
|
||||
local results=()
|
||||
local temp_file="/tmp/mirror_test_results.txt"
|
||||
> "$temp_file"
|
||||
|
||||
# 测试所有镜像源
|
||||
for name in "${!MIRRORS[@]}"; do
|
||||
url="${MIRRORS[$name]}"
|
||||
if result=$(test_mirror "$name" "$url"); then
|
||||
if [[ $result =~ ^[0-9] ]]; then
|
||||
echo "$result" >> "$temp_file"
|
||||
fi
|
||||
fi
|
||||
echo
|
||||
done
|
||||
|
||||
# 选择最快的镜像源
|
||||
if [ -s "$temp_file" ]; then
|
||||
local best_line=$(sort -n "$temp_file" | head -n1)
|
||||
local best_time=$(echo "$best_line" | cut -d: -f1)
|
||||
local best_name=$(echo "$best_line" | cut -d: -f2)
|
||||
local best_url=$(echo "$best_line" | cut -d: -f3)
|
||||
|
||||
echo "=== 最佳镜像源选择结果 ==="
|
||||
echo "名称: $best_name"
|
||||
echo "URL: $best_url"
|
||||
echo "响应时间: ${best_time}s"
|
||||
echo
|
||||
|
||||
# 生成 sources.list 内容
|
||||
generate_sources_list "$best_url"
|
||||
|
||||
rm -f "$temp_file"
|
||||
return 0
|
||||
else
|
||||
echo "错误: 没有可用的镜像源"
|
||||
rm -f "$temp_file"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# 生成 sources.list 内容
|
||||
generate_sources_list() {
|
||||
local mirror_url=$1
|
||||
local sources_file="/tmp/sources.list.optimized"
|
||||
|
||||
cat > "$sources_file" << EOF
|
||||
# 优化的 Ubuntu 22.04 (Jammy) 镜像源配置
|
||||
# 自动选择的最佳镜像源: $mirror_url
|
||||
|
||||
deb $mirror_url jammy main restricted universe multiverse
|
||||
deb $mirror_url jammy-updates main restricted universe multiverse
|
||||
deb $mirror_url jammy-backports main restricted universe multiverse
|
||||
deb $mirror_url jammy-security main restricted universe multiverse
|
||||
|
||||
# 源码包 (可选)
|
||||
# deb-src $mirror_url jammy main restricted universe multiverse
|
||||
# deb-src $mirror_url jammy-updates main restricted universe multiverse
|
||||
# deb-src $mirror_url jammy-backports main restricted universe multiverse
|
||||
# deb-src $mirror_url jammy-security main restricted universe multiverse
|
||||
EOF
|
||||
|
||||
echo "已生成优化的 sources.list 文件: $sources_file"
|
||||
echo "内容如下:"
|
||||
echo "----------------------------------------"
|
||||
cat "$sources_file"
|
||||
echo "----------------------------------------"
|
||||
echo
|
||||
echo "使用方法:"
|
||||
echo "1. 在 Dockerfile 中添加:"
|
||||
echo " COPY sources.list.optimized /etc/apt/sources.list"
|
||||
echo "2. 或者在构建时复制:"
|
||||
echo " cp $sources_file /etc/apt/sources.list"
|
||||
}
|
||||
|
||||
# 主执行函数
|
||||
main() {
|
||||
echo "Ubuntu 镜像源自动优化工具"
|
||||
echo "========================="
|
||||
echo
|
||||
|
||||
# 检查必要的工具
|
||||
if ! command -v curl &> /dev/null; then
|
||||
echo "错误: 需要安装 curl"
|
||||
echo "Ubuntu/Debian: apt-get install curl"
|
||||
echo "CentOS/RHEL: yum install curl"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! command -v bc &> /dev/null; then
|
||||
echo "警告: 建议安装 bc 以获得精确的时间测量"
|
||||
echo "Ubuntu/Debian: apt-get install bc"
|
||||
fi
|
||||
|
||||
# 执行镜像源选择
|
||||
if select_best_mirror; then
|
||||
echo "镜像源优化完成!"
|
||||
echo "建议将生成的 sources.list 文件应用到您的 Dockerfile 中"
|
||||
else
|
||||
echo "镜像源优化失败!"
|
||||
echo "请检查网络连接或手动配置镜像源"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# 执行主函数
|
||||
main "$@"
|
||||
416
dev/test/v0.0.4/start.sh
Normal file
416
dev/test/v0.0.4/start.sh
Normal file
@@ -0,0 +1,416 @@
|
||||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
|
||||
# Enhanced Start Script for Hexo Blog Container v0.0.4
|
||||
# Features: Supervisor integration, enhanced monitoring, automatic recovery
|
||||
|
||||
readonly SCRIPT_VERSION="0.0.4-enhanced"
|
||||
readonly LOG_FILE="/var/log/container/startup.log"
|
||||
readonly CONFIG_DIR="/etc/container/templates"
|
||||
|
||||
# Colors for output
|
||||
readonly RED='\033[0;31m'
|
||||
readonly GREEN='\033[0;32m'
|
||||
readonly YELLOW='\033[1;33m'
|
||||
readonly BLUE='\033[0;34m'
|
||||
readonly NC='\033[0m' # No Color
|
||||
|
||||
# Logging function
|
||||
log() {
|
||||
local level="$1"
|
||||
shift
|
||||
local message="$*"
|
||||
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
|
||||
|
||||
echo -e "${timestamp} [${level}] ${message}"
|
||||
|
||||
# Write to log file if possible
|
||||
if [[ -w "/var/log/container" ]] || [[ -w "$LOG_FILE" ]]; then
|
||||
echo "${timestamp} [${level}] ${message}" >> "$LOG_FILE"
|
||||
fi
|
||||
|
||||
# Send to syslog
|
||||
logger -t "hexo-start" "${level}: ${message}"
|
||||
}
|
||||
|
||||
log_info() { log "${GREEN}INFO${NC}" "$@"; }
|
||||
log_warn() { log "${YELLOW}WARN${NC}" "$@"; }
|
||||
log_error() { log "${RED}ERROR${NC}" "$@"; }
|
||||
log_debug() { log "${BLUE}DEBUG${NC}" "$@"; }
|
||||
|
||||
# Error handler
|
||||
handle_error() {
|
||||
local line_number=$1
|
||||
log_error "Script failed at line ${line_number}"
|
||||
log_error "Attempting graceful shutdown..."
|
||||
cleanup
|
||||
exit 1
|
||||
}
|
||||
|
||||
trap 'handle_error ${LINENO}' ERR
|
||||
|
||||
# Cleanup function
|
||||
cleanup() {
|
||||
log_info "Performing cleanup..."
|
||||
# Kill any background processes if needed
|
||||
jobs -p | xargs -r kill 2>/dev/null || true
|
||||
}
|
||||
|
||||
trap cleanup EXIT
|
||||
|
||||
# Main startup function
|
||||
main() {
|
||||
log_info "Starting Hexo Blog Container ${SCRIPT_VERSION}"
|
||||
log_info "================================================"
|
||||
|
||||
# System information
|
||||
log_info "System: $(uname -a)"
|
||||
log_info "Memory: $(free -h | awk '/^Mem:/ {print $2}')"
|
||||
log_info "Disk: $(df -h / | awk 'NR==2 {print $4 " available"}')"
|
||||
|
||||
# Environment setup
|
||||
setup_environment
|
||||
|
||||
# User management
|
||||
setup_users
|
||||
|
||||
# Configure services
|
||||
configure_ssh
|
||||
configure_nginx
|
||||
configure_git
|
||||
configure_monitoring
|
||||
|
||||
# Pre-flight checks
|
||||
preflight_checks
|
||||
|
||||
# Start services
|
||||
if [[ "${SUPERVISOR_ENABLED:-true}" == "true" ]]; then
|
||||
start_with_supervisor
|
||||
else
|
||||
start_traditional
|
||||
fi
|
||||
}
|
||||
|
||||
setup_environment() {
|
||||
log_info "Setting up environment..."
|
||||
|
||||
# Create necessary directories
|
||||
mkdir -p /var/log/container
|
||||
mkdir -p /var/run/sshd
|
||||
mkdir -p /backup/auto
|
||||
mkdir -p /home/www/hexo
|
||||
mkdir -p /home/hexo/.ssh
|
||||
|
||||
# Set timezone if not set
|
||||
if [[ -n "${TZ:-}" ]]; then
|
||||
ln -sf "/usr/share/zoneinfo/${TZ}" /etc/localtime
|
||||
echo "${TZ}" > /etc/timezone
|
||||
log_info "Timezone set to: ${TZ}"
|
||||
fi
|
||||
|
||||
# Setup locale
|
||||
if [[ -n "${LANG:-}" ]]; then
|
||||
locale-gen "${LANG}" 2>/dev/null || true
|
||||
update-locale "LANG=${LANG}" 2>/dev/null || true
|
||||
log_info "Locale set to: ${LANG}"
|
||||
fi
|
||||
}
|
||||
|
||||
setup_users() {
|
||||
log_info "Setting up users..."
|
||||
|
||||
# Update hexo user UID/GID if specified
|
||||
if [[ -n "${PUID:-}" ]] && [[ "${PUID}" != "1000" ]]; then
|
||||
usermod -u "${PUID}" hexo
|
||||
log_info "Updated hexo user UID to: ${PUID}"
|
||||
fi
|
||||
|
||||
if [[ -n "${PGID:-}" ]] && [[ "${PGID}" != "1000" ]]; then
|
||||
groupmod -g "${PGID}" hexo
|
||||
log_info "Updated hexo group GID to: ${PGID}"
|
||||
fi
|
||||
|
||||
# Fix ownership after potential UID/GID changes
|
||||
chown -R hexo:hexo /home/hexo /home/www/hexo /var/log/container /backup
|
||||
log_info "Updated file ownership for hexo user"
|
||||
}
|
||||
|
||||
configure_ssh() {
|
||||
log_info "Configuring SSH server..."
|
||||
|
||||
# Process SSH configuration template
|
||||
if [[ -f "${CONFIG_DIR}/sshd_config.template" ]]; then
|
||||
envsubst < "${CONFIG_DIR}/sshd_config.template" > /etc/ssh/sshd_config
|
||||
log_info "SSH configuration applied from template"
|
||||
else
|
||||
log_warn "SSH template not found, using default configuration"
|
||||
fi
|
||||
|
||||
# Setup SSH banner
|
||||
if [[ -f "${CONFIG_DIR}/banner.txt" ]]; then
|
||||
cp "${CONFIG_DIR}/banner.txt" /etc/ssh/banner.txt
|
||||
log_info "SSH banner configured"
|
||||
fi
|
||||
|
||||
# Generate host keys if they don't exist
|
||||
if [[ ! -f /etc/ssh/ssh_host_rsa_key ]]; then
|
||||
ssh-keygen -t rsa -f /etc/ssh/ssh_host_rsa_key -N '' -q
|
||||
log_info "Generated SSH RSA host key"
|
||||
fi
|
||||
|
||||
if [[ ! -f /etc/ssh/ssh_host_ed25519_key ]]; then
|
||||
ssh-keygen -t ed25519 -f /etc/ssh/ssh_host_ed25519_key -N '' -q
|
||||
log_info "Generated SSH Ed25519 host key"
|
||||
fi
|
||||
|
||||
# Test SSH configuration
|
||||
if sshd -t; then
|
||||
log_info "SSH configuration is valid"
|
||||
else
|
||||
log_error "SSH configuration is invalid"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
configure_nginx() {
|
||||
log_info "Configuring Nginx server..."
|
||||
|
||||
# Process Nginx configuration template
|
||||
if [[ -f "${CONFIG_DIR}/nginx.conf.template" ]]; then
|
||||
envsubst < "${CONFIG_DIR}/nginx.conf.template" > /etc/nginx/nginx.conf
|
||||
log_info "Nginx configuration applied from template"
|
||||
else
|
||||
log_warn "Nginx template not found, using default configuration"
|
||||
fi
|
||||
|
||||
# Create nginx user if it doesn't exist
|
||||
if ! id nginx >/dev/null 2>&1; then
|
||||
log_info "Creating nginx user..."
|
||||
useradd -r -s /bin/false nginx
|
||||
fi
|
||||
|
||||
# Test Nginx configuration
|
||||
if nginx -t; then
|
||||
log_info "Nginx configuration is valid"
|
||||
else
|
||||
log_error "Nginx configuration is invalid"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Create default index if it doesn't exist
|
||||
if [[ ! -f /home/www/hexo/index.html ]]; then
|
||||
log_info "Creating default index page..."
|
||||
cat > /home/www/hexo/index.html << 'EOF'
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Hexo Blog Ready</title>
|
||||
<style>
|
||||
body { font-family: Arial, sans-serif; margin: 40px; text-align: center; background: #f5f5f5; }
|
||||
.container { max-width: 600px; margin: 0 auto; background: white; padding: 40px; border-radius: 10px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); }
|
||||
h1 { color: #333; }
|
||||
.status { color: #28a745; font-weight: bold; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<h1>🚀 Hexo Blog Container</h1>
|
||||
<p class="status">✅ Ready for deployment</p>
|
||||
<p>Upload your Hexo blog content via Git push to get started!</p>
|
||||
<p><small>Version: 0.0.4-enhanced</small></p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
EOF
|
||||
chown hexo:hexo /home/www/hexo/index.html
|
||||
fi
|
||||
}
|
||||
|
||||
configure_git() {
|
||||
log_info "Configuring Git repository..."
|
||||
|
||||
# Ensure Git repository exists and has correct permissions
|
||||
if [[ ! -d /home/hexo/hexo.git ]]; then
|
||||
log_info "Initializing Git repository..."
|
||||
sudo -u hexo git init --bare /home/hexo/hexo.git
|
||||
fi
|
||||
|
||||
# Ensure post-receive hook is executable
|
||||
if [[ -f /home/hexo/hexo.git/hooks/post-receive ]]; then
|
||||
chmod +x /home/hexo/hexo.git/hooks/post-receive
|
||||
log_info "Git post-receive hook configured"
|
||||
else
|
||||
log_warn "Git post-receive hook not found"
|
||||
fi
|
||||
|
||||
# Set Git repository ownership
|
||||
chown -R hexo:hexo /home/hexo/hexo.git
|
||||
}
|
||||
|
||||
configure_monitoring() {
|
||||
log_info "Configuring monitoring..."
|
||||
|
||||
# Setup log rotation for container logs
|
||||
cat > /etc/logrotate.d/hexo-container << 'EOF'
|
||||
/var/log/container/*.log {
|
||||
daily
|
||||
missingok
|
||||
rotate 30
|
||||
compress
|
||||
notifempty
|
||||
create 644 hexo hexo
|
||||
postrotate
|
||||
systemctl reload nginx 2>/dev/null || true
|
||||
endscript
|
||||
}
|
||||
EOF
|
||||
|
||||
# Configure fail2ban if available
|
||||
if command -v fail2ban-server >/dev/null 2>&1; then
|
||||
systemctl enable fail2ban 2>/dev/null || true
|
||||
log_info "Fail2ban configured for SSH protection"
|
||||
fi
|
||||
}
|
||||
|
||||
preflight_checks() {
|
||||
log_info "Performing pre-flight checks..."
|
||||
|
||||
# Check disk space
|
||||
local disk_usage=$(df / | awk 'NR==2 {print $(NF-1)}' | sed 's/%//')
|
||||
if [[ $disk_usage -gt 80 ]]; then
|
||||
log_warn "Disk usage is high: ${disk_usage}%"
|
||||
fi
|
||||
|
||||
# Check memory
|
||||
local mem_available=$(free | awk '/^Mem:/ {printf "%.1f", $7/$2 * 100.0}')
|
||||
if (( $(echo "$mem_available < 10" | bc -l) )); then
|
||||
log_warn "Available memory is low: ${mem_available}%"
|
||||
fi
|
||||
|
||||
# Check required ports
|
||||
local ports=(80 22)
|
||||
for port in "${ports[@]}"; do
|
||||
if ss -ln | grep ":${port} " >/dev/null; then
|
||||
log_warn "Port ${port} is already in use"
|
||||
fi
|
||||
done
|
||||
|
||||
# Check file permissions
|
||||
if [[ ! -w /var/log/container ]]; then
|
||||
log_error "Cannot write to log directory"
|
||||
return 1
|
||||
fi
|
||||
|
||||
log_info "Pre-flight checks completed"
|
||||
}
|
||||
|
||||
start_with_supervisor() {
|
||||
log_info "Starting services with Supervisor..."
|
||||
|
||||
# Configure Supervisor if template exists
|
||||
if [[ -f "${CONFIG_DIR}/supervisord.conf.template" ]]; then
|
||||
envsubst < "${CONFIG_DIR}/supervisord.conf.template" > /etc/supervisor/conf.d/hexo.conf
|
||||
log_info "Supervisor configuration applied"
|
||||
fi
|
||||
|
||||
# Start Supervisor
|
||||
log_info "Starting Supervisor daemon..."
|
||||
exec /usr/bin/supervisord -c /etc/supervisor/supervisord.conf
|
||||
}
|
||||
|
||||
start_traditional() {
|
||||
log_info "Starting services in traditional mode..."
|
||||
|
||||
# Start SSH daemon
|
||||
log_info "Starting SSH daemon..."
|
||||
/usr/sbin/sshd -D &
|
||||
local sshd_pid=$!
|
||||
|
||||
# Start Nginx
|
||||
log_info "Starting Nginx..."
|
||||
nginx -g "daemon off;" &
|
||||
local nginx_pid=$!
|
||||
|
||||
# Start log rotator
|
||||
log_info "Starting log rotator..."
|
||||
/app/scripts/log-rotator.sh &
|
||||
local rotator_pid=$!
|
||||
|
||||
# Monitor processes
|
||||
monitor_processes $sshd_pid $nginx_pid $rotator_pid
|
||||
}
|
||||
|
||||
monitor_processes() {
|
||||
local pids=("$@")
|
||||
log_info "Monitoring ${#pids[@]} processes..."
|
||||
|
||||
while true; do
|
||||
for pid in "${pids[@]}"; do
|
||||
if ! kill -0 "$pid" 2>/dev/null; then
|
||||
log_error "Process $pid has died, initiating restart..."
|
||||
# In a real scenario, you'd restart the specific service
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
sleep 30
|
||||
done
|
||||
}
|
||||
|
||||
# Signal handlers for graceful shutdown
|
||||
graceful_shutdown() {
|
||||
log_info "Received shutdown signal, stopping services..."
|
||||
|
||||
# Stop Supervisor if running
|
||||
if pgrep supervisord >/dev/null; then
|
||||
supervisorctl stop all
|
||||
pkill supervisord
|
||||
fi
|
||||
|
||||
# Stop individual services
|
||||
pkill nginx 2>/dev/null || true
|
||||
pkill sshd 2>/dev/null || true
|
||||
|
||||
log_info "Graceful shutdown completed"
|
||||
exit 0
|
||||
}
|
||||
|
||||
trap graceful_shutdown SIGTERM SIGINT
|
||||
|
||||
# Version check and help
|
||||
if [[ "${1:-}" == "--version" ]]; then
|
||||
echo "Hexo Blog Container Start Script v${SCRIPT_VERSION}"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [[ "${1:-}" == "--help" ]]; then
|
||||
cat << EOF
|
||||
Hexo Blog Container Start Script v${SCRIPT_VERSION}
|
||||
|
||||
Usage: $0 [OPTIONS]
|
||||
|
||||
Options:
|
||||
--version Show version information
|
||||
--help Show this help message
|
||||
--debug Enable debug logging
|
||||
|
||||
Environment Variables:
|
||||
TZ Timezone (default: Asia/Shanghai)
|
||||
LANG Locale (default: zh_CN.UTF-8)
|
||||
PUID User ID for hexo user (default: 1000)
|
||||
PGID Group ID for hexo group (default: 1000)
|
||||
SUPERVISOR_ENABLED Use supervisor for process management (default: true)
|
||||
|
||||
EOF
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Enable debug mode if requested
|
||||
if [[ "${1:-}" == "--debug" ]]; then
|
||||
set -x
|
||||
log_info "Debug mode enabled"
|
||||
fi
|
||||
|
||||
# Start main function
|
||||
main "$@"
|
||||
113
dev/test/v0.0.4/success_page.html
Normal file
113
dev/test/v0.0.4/success_page.html
Normal file
@@ -0,0 +1,113 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>🎉 Hexo Blog Docker 容器测试成功!</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
|
||||
max-width: 800px;
|
||||
margin: 0 auto;
|
||||
padding: 20px;
|
||||
line-height: 1.6;
|
||||
color: #333;
|
||||
}
|
||||
.success {
|
||||
background: #d4edda;
|
||||
color: #155724;
|
||||
padding: 20px;
|
||||
border-radius: 8px;
|
||||
border: 1px solid #c3e6cb;
|
||||
margin: 20px 0;
|
||||
}
|
||||
.header {
|
||||
text-align: center;
|
||||
border-bottom: 2px solid #4CAF50;
|
||||
padding-bottom: 20px;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
.status-list {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
}
|
||||
.status-list li {
|
||||
padding: 8px 0;
|
||||
border-bottom: 1px solid #e9ecef;
|
||||
}
|
||||
.status-ok {
|
||||
color: #28a745;
|
||||
font-weight: bold;
|
||||
}
|
||||
code {
|
||||
background: #f8f9fa;
|
||||
padding: 2px 4px;
|
||||
border-radius: 3px;
|
||||
font-family: monospace;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="header">
|
||||
<h1>🎉 Hexo Blog Docker 容器测试成功!</h1>
|
||||
<p>部署时间: <span id="time"></span></p>
|
||||
</div>
|
||||
|
||||
<div class="success">
|
||||
<h2>✅ 所有服务状态检查</h2>
|
||||
<ul class="status-list">
|
||||
<li><span class="status-ok">✅ Nginx Web服务器</span> - 正常运行,serving this page</li>
|
||||
<li><span class="status-ok">✅ SSH服务器</span> - 端口22,支持密钥认证</li>
|
||||
<li><span class="status-ok">✅ Git自动部署</span> - 钩子已配置,支持推送即部署</li>
|
||||
<li><span class="status-ok">✅ 健康检查</span> - /health端点正常响应</li>
|
||||
<li><span class="status-ok">✅ 中文支持</span> - UTF-8编码和中文locale配置</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="success">
|
||||
<h2>📋 容器详细信息</h2>
|
||||
<ul>
|
||||
<li><strong>基础镜像</strong>: Ubuntu 22.04</li>
|
||||
<li><strong>Web服务器</strong>: Nginx (用户: hexo)</li>
|
||||
<li><strong>SSH端口</strong>: 22 (映射到主机2222)</li>
|
||||
<li><strong>HTTP端口</strong>: 80 (映射到主机8080)</li>
|
||||
<li><strong>部署目录</strong>: /home/www/hexo</li>
|
||||
<li><strong>Git仓库</strong>: /home/hexo/hexo.git</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="success">
|
||||
<h2>📖 使用说明</h2>
|
||||
<ol>
|
||||
<li><strong>SSH连接</strong>: <code>ssh -i hexo_key -p 2222 hexo@localhost</code></li>
|
||||
<li><strong>Git部署</strong>: <code>git push hexo main</code></li>
|
||||
<li><strong>访问网站</strong>: <code>http://localhost:8080</code></li>
|
||||
<li><strong>健康检查</strong>: <code>http://localhost:8080/health</code></li>
|
||||
</ol>
|
||||
</div>
|
||||
|
||||
<div class="success">
|
||||
<h2>🎯 测试结果</h2>
|
||||
<p><strong>所有功能测试通过!</strong></p>
|
||||
<p>Docker容器 <code>hexo-blog:v0.0.3-fixed</code> 已经成功构建并运行,包含:</p>
|
||||
<ul>
|
||||
<li>安全的SSH服务器配置(仅支持密钥认证)</li>
|
||||
<li>高性能的Nginx Web服务器</li>
|
||||
<li>自动化的Git部署钩子</li>
|
||||
<li>完整的中文支持和时区配置</li>
|
||||
<li>健康检查和监控端点</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
document.getElementById("time").textContent = new Date().toLocaleString("zh-CN", {
|
||||
year: "numeric",
|
||||
month: "2-digit",
|
||||
day: "2-digit",
|
||||
hour: "2-digit",
|
||||
minute: "2-digit",
|
||||
second: "2-digit"
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
338
dev/test/v0.0.4/test.ps1
Normal file
338
dev/test/v0.0.4/test.ps1
Normal file
@@ -0,0 +1,338 @@
|
||||
# v0.0.4-enhanced 自动化测试脚本
|
||||
# 执行方式: PowerShell -ExecutionPolicy Bypass -File test_v0.0.4-enhanced.ps1
|
||||
|
||||
param(
|
||||
[switch]$Cleanup = $false,
|
||||
[switch]$SkipBuild = $false,
|
||||
[string]$LogFile = "test_results_v0.0.4_$(Get-Date -Format 'yyyyMMdd_HHmmss').log"
|
||||
)
|
||||
|
||||
# 颜色输出函数
|
||||
function Write-TestResult {
|
||||
param([string]$Message, [string]$Status)
|
||||
$timestamp = Get-Date -Format "HH:mm:ss"
|
||||
$logEntry = "[$timestamp] $Message - $Status"
|
||||
|
||||
switch ($Status) {
|
||||
"PASS" { Write-Host $logEntry -ForegroundColor Green }
|
||||
"FAIL" { Write-Host $logEntry -ForegroundColor Red }
|
||||
"WARN" { Write-Host $logEntry -ForegroundColor Yellow }
|
||||
"INFO" { Write-Host $logEntry -ForegroundColor Cyan }
|
||||
default { Write-Host $logEntry }
|
||||
}
|
||||
|
||||
# 同时写入日志文件
|
||||
$logEntry | Out-File -FilePath $LogFile -Append -Encoding UTF8
|
||||
}
|
||||
|
||||
# 测试结果记录
|
||||
$TestResults = @{
|
||||
TotalTests = 0
|
||||
PassedTests = 0
|
||||
FailedTests = 0
|
||||
Warnings = 0
|
||||
StartTime = Get-Date
|
||||
}
|
||||
|
||||
function Test-Condition {
|
||||
param([string]$TestName, [scriptblock]$TestBlock)
|
||||
|
||||
$TestResults.TotalTests++
|
||||
Write-TestResult "开始测试: $TestName" "INFO"
|
||||
|
||||
try {
|
||||
$result = & $TestBlock
|
||||
if ($result -eq $true -or $result -eq "PASS") {
|
||||
$TestResults.PassedTests++
|
||||
Write-TestResult "$TestName" "PASS"
|
||||
return $true
|
||||
} else {
|
||||
$TestResults.FailedTests++
|
||||
Write-TestResult "$TestName - $result" "FAIL"
|
||||
return $false
|
||||
}
|
||||
} catch {
|
||||
$TestResults.FailedTests++
|
||||
Write-TestResult "$TestName - 异常: $($_.Exception.Message)" "FAIL"
|
||||
return $false
|
||||
}
|
||||
}
|
||||
|
||||
# 开始测试
|
||||
Write-TestResult "=== v0.0.4-enhanced 自动化测试开始 ===" "INFO"
|
||||
Write-TestResult "日志文件: $LogFile" "INFO"
|
||||
|
||||
# 清理环境
|
||||
if ($Cleanup) {
|
||||
Write-TestResult "清理旧环境..." "INFO"
|
||||
docker stop hexo-blog-enhanced 2>$null | Out-Null
|
||||
docker rm hexo-blog-enhanced 2>$null | Out-Null
|
||||
docker rmi hexo-blog:enhanced 2>$null | Out-Null
|
||||
}
|
||||
|
||||
# 构建镜像
|
||||
if (-not $SkipBuild) {
|
||||
Write-TestResult "构建v0.0.4-enhanced镜像..." "INFO"
|
||||
$buildOutput = docker build -f Dockerfile_v0.0.4-enhanced -t hexo-blog:enhanced . 2>&1
|
||||
if ($LASTEXITCODE -eq 0) {
|
||||
Write-TestResult "镜像构建成功" "PASS"
|
||||
} else {
|
||||
Write-TestResult "镜像构建失败: $buildOutput" "FAIL"
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
|
||||
# 启动容器
|
||||
Write-TestResult "启动增强版容器..." "INFO"
|
||||
$containerStart = Get-Date
|
||||
docker run -d --name hexo-blog-enhanced --restart unless-stopped `
|
||||
-p 8080:80 -p 2222:22 `
|
||||
--health-interval=30s --health-timeout=10s --health-retries=3 `
|
||||
hexo-blog:enhanced | Out-Null
|
||||
|
||||
if ($LASTEXITCODE -eq 0) {
|
||||
Write-TestResult "容器启动命令执行成功" "PASS"
|
||||
} else {
|
||||
Write-TestResult "容器启动失败" "FAIL"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# 等待容器完全启动
|
||||
Write-TestResult "等待容器初始化..." "INFO"
|
||||
$maxWait = 60
|
||||
$waited = 0
|
||||
do {
|
||||
Start-Sleep -Seconds 2
|
||||
$waited += 2
|
||||
$status = docker inspect hexo-blog-enhanced --format='{{.State.Status}}' 2>$null
|
||||
} while ($status -ne "running" -and $waited -lt $maxWait)
|
||||
|
||||
$containerReady = Get-Date
|
||||
$startupTime = ($containerReady - $containerStart).TotalSeconds
|
||||
Write-TestResult "容器启动耗时: $startupTime 秒" "INFO"
|
||||
|
||||
# 测试1: 容器健康状态
|
||||
Test-Condition "容器健康状态检查" {
|
||||
$health = docker inspect hexo-blog-enhanced --format='{{.State.Health.Status}}' 2>$null
|
||||
if ($health -eq "healthy" -or $health -eq "starting") {
|
||||
return $true
|
||||
} else {
|
||||
return "健康状态: $health"
|
||||
}
|
||||
}
|
||||
|
||||
# 测试2: Web服务基础访问
|
||||
Test-Condition "Web服务基础访问" {
|
||||
try {
|
||||
$response = Invoke-WebRequest -Uri "http://localhost:8080" -UseBasicParsing -TimeoutSec 10
|
||||
if ($response.StatusCode -eq 200) {
|
||||
return $true
|
||||
} else {
|
||||
return "状态码: $($response.StatusCode)"
|
||||
}
|
||||
} catch {
|
||||
return "连接失败: $($_.Exception.Message)"
|
||||
}
|
||||
}
|
||||
|
||||
# 测试3: 健康检查端点
|
||||
Test-Condition "健康检查端点" {
|
||||
try {
|
||||
$health = Invoke-WebRequest -Uri "http://localhost:8080/health" -UseBasicParsing -TimeoutSec 5
|
||||
if ($health.Content -match "healthy") {
|
||||
return $true
|
||||
} else {
|
||||
return "健康检查返回: $($health.Content)"
|
||||
}
|
||||
} catch {
|
||||
return "健康检查端点访问失败"
|
||||
}
|
||||
}
|
||||
|
||||
# 测试4: 状态API端点 (v0.0.4新增)
|
||||
Test-Condition "状态API端点" {
|
||||
try {
|
||||
$status = Invoke-WebRequest -Uri "http://localhost:8080/status" -UseBasicParsing -TimeoutSec 5
|
||||
$statusData = $status.Content | ConvertFrom-Json
|
||||
if ($statusData.status -eq "ok" -and $statusData.version) {
|
||||
return $true
|
||||
} else {
|
||||
return "状态API格式异常"
|
||||
}
|
||||
} catch {
|
||||
return "状态API访问失败或JSON解析失败"
|
||||
}
|
||||
}
|
||||
|
||||
# 测试5: SSH连接
|
||||
Test-Condition "SSH密钥认证" {
|
||||
if (-not (Test-Path "hexo_key")) {
|
||||
return "SSH密钥文件不存在"
|
||||
}
|
||||
|
||||
try {
|
||||
$sshTest = ssh -i hexo_key -o ConnectTimeout=10 -o StrictHostKeyChecking=no -o BatchMode=yes -p 2222 hexo@localhost "echo 'SSH_TEST_OK'" 2>$null
|
||||
if ($sshTest -match "SSH_TEST_OK") {
|
||||
return $true
|
||||
} else {
|
||||
return "SSH连接失败或认证失败"
|
||||
}
|
||||
} catch {
|
||||
return "SSH测试异常"
|
||||
}
|
||||
}
|
||||
|
||||
# 测试6: Supervisor进程管理 (v0.0.4特性)
|
||||
Test-Condition "Supervisor进程管理" {
|
||||
try {
|
||||
$supervisorStatus = docker exec hexo-blog-enhanced supervisorctl status 2>$null
|
||||
if ($supervisorStatus -match "RUNNING") {
|
||||
return $true
|
||||
} else {
|
||||
return "Supervisor状态异常: $supervisorStatus"
|
||||
}
|
||||
} catch {
|
||||
return "Supervisor不可用或未安装"
|
||||
}
|
||||
}
|
||||
|
||||
# 测试7: Fail2ban安全服务 (v0.0.4特性)
|
||||
Test-Condition "Fail2ban安全服务" {
|
||||
try {
|
||||
$fail2banStatus = docker exec hexo-blog-enhanced systemctl is-active fail2ban 2>$null
|
||||
if ($fail2banStatus -eq "active") {
|
||||
return $true
|
||||
} else {
|
||||
return "Fail2ban状态: $fail2banStatus"
|
||||
}
|
||||
} catch {
|
||||
return "Fail2ban检查失败"
|
||||
}
|
||||
}
|
||||
|
||||
# 测试8: Nginx性能配置
|
||||
Test-Condition "Nginx性能配置" {
|
||||
try {
|
||||
$workerConfig = docker exec hexo-blog-enhanced grep "worker_connections" /etc/nginx/nginx.conf 2>$null
|
||||
if ($workerConfig -match "4096") {
|
||||
return $true
|
||||
} else {
|
||||
return "Worker连接数配置未生效: $workerConfig"
|
||||
}
|
||||
} catch {
|
||||
return "Nginx配置检查失败"
|
||||
}
|
||||
}
|
||||
|
||||
# 测试9: Gzip压缩功能
|
||||
Test-Condition "Gzip压缩功能" {
|
||||
try {
|
||||
$gzipTest = Invoke-WebRequest -Uri "http://localhost:8080" -Headers @{"Accept-Encoding"="gzip"} -UseBasicParsing
|
||||
if ($gzipTest.Headers.'Content-Encoding' -eq "gzip") {
|
||||
return $true
|
||||
} else {
|
||||
return "Gzip压缩未启用"
|
||||
}
|
||||
} catch {
|
||||
return "Gzip测试失败"
|
||||
}
|
||||
}
|
||||
|
||||
# 测试10: 内存使用检查
|
||||
Test-Condition "内存使用合理性" {
|
||||
try {
|
||||
$memStats = docker stats hexo-blog-enhanced --no-stream --format "{{.MemUsage}}"
|
||||
$memUsage = [regex]::Match($memStats, "(\d+(?:\.\d+)?)(\w+)").Groups[1].Value
|
||||
$memUnit = [regex]::Match($memStats, "(\d+(?:\.\d+)?)(\w+)").Groups[2].Value
|
||||
|
||||
$memMB = switch ($memUnit) {
|
||||
"MiB" { [float]$memUsage }
|
||||
"GiB" { [float]$memUsage * 1024 }
|
||||
"kB" { [float]$memUsage / 1024 }
|
||||
default { [float]$memUsage }
|
||||
}
|
||||
|
||||
if ($memMB -lt 200) { # 200MB限制
|
||||
return $true
|
||||
} else {
|
||||
return "内存使用过高: ${memMB}MB"
|
||||
}
|
||||
} catch {
|
||||
return "内存检查失败"
|
||||
}
|
||||
}
|
||||
|
||||
# 测试11: Git部署功能
|
||||
Test-Condition "Git部署功能" {
|
||||
if (-not (Test-Path "hexo_key")) {
|
||||
return "SSH密钥不存在,跳过Git测试"
|
||||
}
|
||||
|
||||
try {
|
||||
# 配置Git远程
|
||||
git remote remove docker 2>$null | Out-Null
|
||||
git remote add docker ssh://hexo@localhost:2222/home/hexo/hexo.git 2>$null
|
||||
$env:GIT_SSH_COMMAND = "ssh -i $(Get-Location)\hexo_key -o StrictHostKeyChecking=no"
|
||||
|
||||
# 创建测试文件
|
||||
$testContent = "# v0.0.4自动化测试`n测试时间: $(Get-Date)"
|
||||
$testContent | Out-File -FilePath "test_auto_v0.0.4.md" -Encoding UTF8
|
||||
|
||||
git add test_auto_v0.0.4.md 2>$null
|
||||
git commit -m "v0.0.4自动化测试部署" 2>$null
|
||||
|
||||
# 推送部署
|
||||
$pushResult = git push docker main 2>&1
|
||||
if ($LASTEXITCODE -eq 0) {
|
||||
# 验证部署结果
|
||||
Start-Sleep -Seconds 3
|
||||
$deployCheck = Invoke-WebRequest -Uri "http://localhost:8080" -UseBasicParsing
|
||||
if ($deployCheck.Content -match "v0.0.4自动化测试") {
|
||||
Remove-Item "test_auto_v0.0.4.md" -Force 2>$null
|
||||
return $true
|
||||
} else {
|
||||
return "部署内容未更新"
|
||||
}
|
||||
} else {
|
||||
return "Git推送失败: $pushResult"
|
||||
}
|
||||
} catch {
|
||||
return "Git部署测试异常: $($_.Exception.Message)"
|
||||
}
|
||||
}
|
||||
|
||||
# 测试完成,生成报告
|
||||
$TestResults.EndTime = Get-Date
|
||||
$TestResults.Duration = ($TestResults.EndTime - $TestResults.StartTime).TotalSeconds
|
||||
|
||||
Write-TestResult "=== 测试完成 ===" "INFO"
|
||||
Write-TestResult "总测试数: $($TestResults.TotalTests)" "INFO"
|
||||
Write-TestResult "通过: $($TestResults.PassedTests)" "INFO"
|
||||
Write-TestResult "失败: $($TestResults.FailedTests)" "INFO"
|
||||
Write-TestResult "耗时: $([math]::Round($TestResults.Duration, 1)) 秒" "INFO"
|
||||
|
||||
$successRate = [math]::Round(($TestResults.PassedTests / $TestResults.TotalTests) * 100, 1)
|
||||
Write-TestResult "成功率: $successRate%" "INFO"
|
||||
|
||||
# 生成总结
|
||||
if ($TestResults.FailedTests -eq 0) {
|
||||
Write-TestResult "🎉 所有测试通过!v0.0.4-enhanced 可以投入生产使用" "PASS"
|
||||
$exitCode = 0
|
||||
} elseif ($successRate -ge 80) {
|
||||
Write-TestResult "⚠️ 大部分测试通过,但存在问题需要修复" "WARN"
|
||||
$exitCode = 1
|
||||
} else {
|
||||
Write-TestResult "❌ 多项测试失败,建议回滚到v0.0.3-fixed" "FAIL"
|
||||
$exitCode = 2
|
||||
}
|
||||
|
||||
Write-TestResult "详细测试日志已保存到: $LogFile" "INFO"
|
||||
|
||||
# 清理测试环境 (可选)
|
||||
if ($Cleanup) {
|
||||
Write-TestResult "清理测试环境..." "INFO"
|
||||
docker stop hexo-blog-enhanced 2>$null | Out-Null
|
||||
docker rm hexo-blog-enhanced 2>$null | Out-Null
|
||||
}
|
||||
|
||||
exit $exitCode
|
||||
Reference in New Issue
Block a user