Browse Source

fix: 修复deploy.sh脚本端口映射和参数兼容性问题

- 修复开发环境容器端口映射配置错误(12790:12790)
- 改进参数解析兼容性,支持 -help 格式
- 修复函数定义顺序问题,解决 log_error 未定义错误
- 确保Dockerfile.dev与deploy.sh端口配置一致性
- 优化脚本结构,提高可靠性和可维护性

解决开发环境容器启动失败问题,提升用户体验。
feature/x1-web-request
root 4 months ago
parent
commit
d34be06631
  1. 6
      .gitignore
  2. 18
      src/X1.WebAPI/Dockerfile
  3. 53
      src/X1.WebAPI/Dockerfile.dev
  4. 31
      src/X1.WebAPI/Program.cs
  5. 4
      src/X1.WebAPI/Properties/launchSettings.json
  6. 424
      src/X1.WebAPI/deploy.sh
  7. 288
      src/X1.WebAPI/docker-deploy.md
  8. 34
      src/X1.WebAPI/publish.bat
  9. 1708
      src/modify.md

6
.gitignore

@ -46,4 +46,8 @@ node_modules/
# Logs
X1.WebAPI.logs/
X1.WebAPI/logs/
*.log
*.log
# Publish directories
publish/
**/publish/

18
src/X1.WebAPI/Dockerfile

@ -0,0 +1,18 @@
# 使用官方.NET 8.0运行时镜像作为基础镜像(完整版本,支持调试)
FROM mcr.microsoft.com/dotnet/aspnet:8.0-jammy
# 设置工作目录
WORKDIR /app
# 设置环境变量
ENV ASPNETCORE_ENVIRONMENT=Production
ENV ASPNETCORE_URLS=http://+:12789
# 复制发布文件到容器中
COPY publish/ .
# 暴露端口12789
EXPOSE 12789
# 设置应用启动命令
ENTRYPOINT ["./X1.WebAPI"]

53
src/X1.WebAPI/Dockerfile.dev

@ -0,0 +1,53 @@
# 开发环境Dockerfile - 精简版调试支持
FROM mcr.microsoft.com/dotnet/aspnet:8.0-jammy
# 安装核心调试工具
RUN apt-get update && apt-get install -y \
bash \
curl \
vim \
htop \
procps \
net-tools \
iputils-ping \
telnet \
tree \
less \
lsof \
dnsutils \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
# 设置工作目录
WORKDIR /app
# 设置环境变量(开发环境)
ENV ASPNETCORE_ENVIRONMENT=Development
ENV ASPNETCORE_URLS=http://+:12790
ENV DOTNET_USE_POLLING_FILE_WATCHER=1
# 复制发布文件到容器中
COPY publish/ .
# 暴露端口12790
EXPOSE 12790
# 创建开发环境启动脚本
RUN echo '#!/bin/bash\n\
echo "=========================================="\n\
echo "X1.WebAPI 开发环境启动" \n\
echo "=========================================="\n\
echo "环境: Development"\n\
echo "端口: 12790"\n\
echo "调试工具:"\n\
echo " - 基本: bash, curl"\n\
echo " - 编辑: vim"\n\
echo " - 系统: htop, ps, lsof"\n\
echo " - 网络: netstat, ping, telnet"\n\
echo " - 文件: tree, less"\n\
echo " - DNS: dig, nslookup"\n\
echo "=========================================="\n\
exec ./X1.WebAPI' > /app/start-dev.sh && chmod +x /app/start-dev.sh
# 设置应用启动命令
ENTRYPOINT ["./start-dev.sh"]

31
src/X1.WebAPI/Program.cs

@ -173,18 +173,25 @@ builder.Services.AddDirectoryBrowser();
var app = builder.Build();
// 配置 HTTP 请求管道
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
// 在开发环境中禁用 HTTPS 重定向
app.UseHttpsRedirection();
}
else
{
// 在生产环境中强制使用 HTTPS
app.UseHttpsRedirection();
}
//if (app.Environment.IsDevelopment())
//{
// app.UseSwagger();
// app.UseSwaggerUI();
// // 在开发环境中禁用 HTTPS 重定向
// app.UseHttpsRedirection();
//}
//else
//{
// // 在生产环境中强制使用 HTTPS
// app.UseHttpsRedirection();
//}
app.UseSwagger();
app.UseSwaggerUI();
// 在开发环境中禁用 HTTPS 重定向
app.UseHttpsRedirection();
// 配置 CORS 策略
app.UseCors("CorsPolicy");

4
src/X1.WebAPI/Properties/launchSettings.json

@ -24,8 +24,8 @@
"dotnetRunMessages": true,
"launchBrowser": true,
"launchUrl": "swagger",
"applicationUrl": "https://localhost:7268;http://localhost:5000;https://192.168.1.233:7268;http://192.168.1.233:5000",
//"applicationUrl": "https://localhost:7268;http://localhost:5000",
//"applicationUrl": "https://localhost:7268;http://localhost:5000;https://192.168.1.233:7268;http://192.168.1.233:5000",
"applicationUrl": "https://localhost:7268;http://localhost:5000",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}

424
src/X1.WebAPI/deploy.sh

@ -0,0 +1,424 @@
#!/bin/bash
# X1.WebAPI Docker 部署脚本
# 使用方法:
# ./deploy.sh # 生产环境部署
# ./deploy.sh --dev # 开发环境部署
# ./deploy.sh --help # 显示帮助信息
set -e # 遇到错误立即退出
# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# 日志函数
log_info() {
echo -e "${BLUE}[INFO]${NC} $1"
}
log_success() {
echo -e "${GREEN}[SUCCESS]${NC} $1"
}
log_warning() {
echo -e "${YELLOW}[WARNING]${NC} $1"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
# 默认配置
ENVIRONMENT="production"
DOCKERFILE="Dockerfile"
IMAGE_NAME="x1-webapi"
CONTAINER_NAME="x1-webapi-container"
PORT="12789"
REMOVE_MODE=false
# 解析命令行参数
parse_arguments() {
while [[ $# -gt 0 ]]; do
case $1 in
--dev)
ENVIRONMENT="development"
DOCKERFILE="Dockerfile.dev"
IMAGE_NAME="x1-webapi-dev"
CONTAINER_NAME="x1-webapi-dev-container"
PORT="12790"
shift
;;
--remove)
REMOVE_MODE=true
shift
;;
--help|-h|-help)
show_help
exit 0
;;
*)
log_error "未知参数: $1"
show_help
exit 1
;;
esac
done
}
# 显示帮助信息
show_help() {
echo "X1.WebAPI Docker 部署脚本"
echo ""
echo "使用方法:"
echo " ./deploy.sh # 生产环境部署"
echo " ./deploy.sh --dev # 开发环境部署"
echo " ./deploy.sh --remove # 删除当前环境容器和镜像"
echo " ./deploy.sh --dev --remove # 删除开发环境容器和镜像"
echo " ./deploy.sh --help # 显示帮助信息"
echo " ./deploy.sh -h # 显示帮助信息(简写)"
echo " ./deploy.sh -help # 显示帮助信息(简写)"
echo ""
echo "参数说明:"
echo " --dev : 使用开发环境配置(Dockerfile.dev,端口12790)"
echo " --remove : 删除模式,删除容器和镜像"
echo " --help : 显示帮助信息"
echo " -h : 显示帮助信息(简写)"
echo " -help : 显示帮助信息(简写)"
echo ""
echo "环境说明:"
echo " 生产环境: 使用 Dockerfile,包含基本调试工具"
echo " 开发环境: 使用 Dockerfile.dev,包含完整调试工具集"
echo ""
echo "开发环境包含的额外工具:"
echo " - 网络诊断: ping, telnet, net-tools, curl, wget"
echo " - 系统监控: htop, procps, ps"
echo " - 文件编辑: vim, nano"
echo " - 基本工具: bash, procps"
echo ""
echo "删除功能:"
echo " --remove: 删除指定环境的容器和镜像,释放资源"
}
echo "=========================================="
echo "X1.WebAPI Docker 部署脚本"
echo "开始时间: $(date)"
echo "=========================================="
# 解析命令行参数
parse_arguments "$@"
# 显示环境信息
echo "部署环境: $ENVIRONMENT"
echo "使用Dockerfile: $DOCKERFILE"
echo "镜像名称: $IMAGE_NAME"
echo "容器名称: $CONTAINER_NAME"
echo "端口: $PORT"
echo "操作模式: $([ "$REMOVE_MODE" = true ] && echo "删除模式" || echo "部署模式")"
echo "=========================================="
# 检查Docker是否安装
check_docker() {
log_info "检查Docker安装状态..."
if ! command -v docker &> /dev/null; then
log_error "Docker未安装,请先安装Docker"
exit 1
fi
log_success "Docker已安装: $(docker --version)"
}
# 检查Docker服务状态
check_docker_service() {
log_info "检查Docker服务状态..."
if ! systemctl is-active --quiet docker; then
log_warning "Docker服务未运行,尝试启动..."
sudo systemctl start docker
sleep 2
fi
log_success "Docker服务运行正常"
}
# 检查目录和文件
check_files() {
log_info "检查部署文件..."
if [ ! -d "publish" ]; then
log_error "publish目录不存在,请先上传发布文件"
exit 1
fi
if [ ! -f "publish/X1.WebAPI" ]; then
log_error "可执行文件 publish/X1.WebAPI 不存在"
exit 1
fi
if [ ! -f "$DOCKERFILE" ]; then
log_error "Dockerfile不存在: $DOCKERFILE"
if [ "$ENVIRONMENT" = "development" ]; then
log_info "请确保 Dockerfile.dev 文件存在"
fi
exit 1
fi
log_success "所有必要文件检查通过"
}
# 设置文件权限
set_permissions() {
log_info "设置文件权限..."
# 设置可执行文件权限
chmod +x publish/X1.WebAPI
log_success "设置可执行文件权限完成"
# 设置目录权限
chmod 755 publish/
log_success "设置目录权限完成"
# 设置Dockerfile权限
chmod 644 "$DOCKERFILE"
log_success "设置Dockerfile权限完成"
# 显示权限信息
log_info "文件权限信息:"
ls -la publish/X1.WebAPI
ls -la "$DOCKERFILE"
}
# 停止旧容器
stop_old_container() {
log_info "检查并停止旧容器..."
if docker ps -a --format "table {{.Names}}" | grep -q "$CONTAINER_NAME"; then
log_info "发现旧容器,正在停止..."
docker stop "$CONTAINER_NAME" 2>/dev/null || true
log_success "旧容器已停止"
log_info "删除旧容器..."
docker rm "$CONTAINER_NAME" 2>/dev/null || true
log_success "旧容器已删除"
else
log_info "未发现旧容器"
fi
}
# 删除容器和镜像
remove_container_and_image() {
log_info "开始删除容器和镜像..."
# 删除容器
if docker ps -a --format "table {{.Names}}" | grep -q "$CONTAINER_NAME"; then
log_info "发现容器,正在停止并删除..."
docker stop "$CONTAINER_NAME" 2>/dev/null || true
docker rm "$CONTAINER_NAME" 2>/dev/null || true
log_success "容器已删除"
else
log_info "未发现容器: $CONTAINER_NAME"
fi
# 删除镜像
if docker images --format "table {{.Repository}}:{{.Tag}}" | grep -q "$IMAGE_NAME:latest"; then
log_info "发现镜像,正在删除..."
docker rmi "$IMAGE_NAME:latest" 2>/dev/null || true
log_success "镜像已删除"
else
log_info "未发现镜像: $IMAGE_NAME:latest"
fi
# 清理悬空镜像
log_info "清理悬空镜像..."
docker image prune -f 2>/dev/null || true
log_success "悬空镜像清理完成"
}
# 构建Docker镜像
build_image() {
log_info "开始构建Docker镜像..."
if [ "$ENVIRONMENT" = "development" ]; then
log_info "构建开发环境镜像..."
log_info "构建命令: docker build -f $DOCKERFILE -t $IMAGE_NAME:latest ."
# 显示构建上下文
log_info "构建上下文文件:"
ls -la
# 构建开发镜像
if docker build -f "$DOCKERFILE" -t "$IMAGE_NAME:latest" .; then
log_success "开发环境Docker镜像构建成功"
else
log_error "开发环境Docker镜像构建失败"
exit 1
fi
else
log_info "构建生产环境镜像..."
log_info "构建命令: docker build -t $IMAGE_NAME:latest ."
# 显示构建上下文
log_info "构建上下文文件:"
ls -la
# 构建生产镜像
if docker build -t "$IMAGE_NAME:latest" .; then
log_success "生产环境Docker镜像构建成功"
else
log_error "生产环境Docker镜像构建失败"
exit 1
fi
fi
# 显示镜像信息
log_info "镜像信息:"
docker images "$IMAGE_NAME:latest"
}
# 运行新容器
run_container() {
log_info "启动新容器..."
# 根据环境设置不同的环境变量
if [ "$ENVIRONMENT" = "development" ]; then
log_info "启动开发环境容器..."
docker run -d \
--name "$CONTAINER_NAME" \
--restart unless-stopped \
-p "$PORT:12790" \
-e ASPNETCORE_ENVIRONMENT=Development \
"$IMAGE_NAME:latest"
else
log_info "启动生产环境容器..."
docker run -d \
--name "$CONTAINER_NAME" \
--restart unless-stopped \
-p "$PORT:12789" \
-e ASPNETCORE_ENVIRONMENT=Production \
"$IMAGE_NAME:latest"
fi
if [ $? -eq 0 ]; then
log_success "容器启动成功"
# 等待容器启动
log_info "等待容器启动..."
sleep 3
# 检查容器状态
if docker ps | grep -q "$CONTAINER_NAME"; then
log_success "容器运行正常"
# 显示容器信息
log_info "容器信息:"
docker ps | grep "$CONTAINER_NAME"
# 显示端口信息
log_info "端口信息:"
netstat -tlnp | grep "$PORT" || log_warning "端口$PORT未监听,可能容器还在启动中"
else
log_error "容器启动失败"
log_info "容器日志:"
docker logs "$CONTAINER_NAME"
exit 1
fi
else
log_error "容器启动失败"
exit 1
fi
}
# 健康检查
health_check() {
log_info "执行健康检查..."
# 等待应用启动
log_info "等待应用启动(最多30秒)..."
for i in {1..30}; do
if curl -s http://localhost:$PORT/health > /dev/null 2>&1; then
log_success "应用健康检查通过"
return 0
fi
echo -n "."
sleep 1
done
log_warning "健康检查超时,但容器可能仍在启动中"
log_info "容器日志:"
docker logs "$CONTAINER_NAME" --tail 20
}
# 显示部署信息
show_deployment_info() {
echo ""
echo "=========================================="
echo "部署完成!"
echo "=========================================="
echo "部署环境: $ENVIRONMENT"
echo "应用地址: http://localhost:$PORT"
echo "健康检查: http://localhost:$PORT/health"
echo "Swagger文档: http://localhost:$PORT/swagger"
echo ""
echo "容器管理命令:"
echo " 查看状态: docker ps | grep $CONTAINER_NAME"
echo " 查看日志: docker logs $CONTAINER_NAME"
echo " 重启容器: docker restart $CONTAINER_NAME"
echo " 停止容器: docker stop $CONTAINER_NAME"
if [ "$ENVIRONMENT" = "development" ]; then
echo ""
echo "开发环境调试命令:"
echo " 进入容器: docker exec -it $CONTAINER_NAME /bin/bash"
echo " 系统监控: docker exec -it $CONTAINER_NAME htop"
echo " 网络测试: docker exec -it $CONTAINER_NAME ping google.com"
echo " 端口检查: docker exec -it $CONTAINER_NAME netstat -tulpn"
echo " 查看进程: docker exec -it $CONTAINER_NAME ps aux"
fi
echo ""
echo "完成时间: $(date)"
echo "=========================================="
}
# 主函数
main() {
echo "开始执行流程..."
# 检查Docker环境
check_docker
check_docker_service
# 如果是删除模式
if [ "$REMOVE_MODE" = true ]; then
log_info "执行删除操作..."
remove_container_and_image
log_success "删除完成!"
return
fi
# 部署模式
log_info "执行部署操作..."
# 检查当前目录
if [ ! -f "publish/X1.WebAPI" ]; then
log_error "请在包含publish目录的目录中运行此脚本"
log_info "当前目录: $(pwd)"
log_info "期望结构: ./publish/X1.WebAPI"
exit 1
fi
# 执行部署步骤
check_files
set_permissions
stop_old_container
build_image
run_container
health_check
show_deployment_info
log_success "部署完成!"
}
# 执行主函数
main "$@"

288
src/X1.WebAPI/docker-deploy.md

@ -0,0 +1,288 @@
# X1.WebAPI Docker 部署指南
## 部署流程
### 1. 本地发布
在Windows开发机器上执行:
```bash
# 在 X1.WebAPI 目录下运行
publish.bat
```
### 2. 上传文件到服务器
`publish/` 文件夹上传到Ubuntu服务器的 `/home/hyh/x1_service` 目录:
- `publish/` 文件夹(包含所有发布文件、Dockerfile、deploy.sh和部署指南)
### 3. 服务器端操作
#### 方式一:使用自动化部署脚本(推荐)
##### 3.1 准备部署环境
```bash
cd /home/hyh/x1_service
# 将deploy.sh从publish目录移动到当前目录
mv publish/deploy.sh ./
# 设置deploy.sh执行权限
chmod +x deploy.sh
```
##### 3.2 执行自动化部署
```bash
# 运行部署脚本
./deploy.sh
```
部署脚本会自动执行以下操作:
- 检查Docker安装和运行状态
- 验证所有必要文件
- 设置正确的文件权限
- 停止并删除旧容器
- 构建新的Docker镜像
- 启动新容器
- 执行健康检查
- 显示部署结果
#### 方式二:手动部署(备选方案)
##### 3.1 进入部署目录并设置权限
```bash
cd /home/hyh/x1_service
# 设置可执行文件权限
chmod +x publish/X1.WebAPI
# 设置目录权限
chmod 755 publish/
chmod 644 publish/Dockerfile
# 如果使用非root用户运行Docker,可能需要调整权限
# chown -R $USER:$USER publish/
```
##### 3.2 构建Docker镜像
```bash
docker build -t x1-webapi:latest .
```
##### 3.3 运行容器
```bash
# 停止并删除旧容器(如果存在)
docker stop x1-webapi-container 2>/dev/null || true
docker rm x1-webapi-container 2>/dev/null || true
# 运行新容器
docker run -d \
--name x1-webapi-container \
--restart unless-stopped \
-p 12789:12789 \
x1-webapi:latest
```
## 容器管理命令
### 查看容器状态
```bash
docker ps -a | grep x1-webapi
```
### 查看容器日志
```bash
# 查看最新日志
docker logs x1-webapi-container
# 实时查看日志
docker logs -f x1-webapi-container
# 查看最后100行日志
docker logs x1-webapi-container --tail 100
```
### 容器操作
```bash
# 停止容器
docker stop x1-webapi-container
# 启动容器
docker start x1-webapi-container
# 重启容器
docker restart x1-webapi-container
# 删除容器
docker rm -f x1-webapi-container
# 删除镜像
docker rmi x1-webapi:latest
```
## 更新部署流程
### 使用自动化脚本更新(推荐)
```bash
# 1. 本地重新发布
publish.bat
# 2. 上传新的publish文件夹到服务器
# 替换 /home/hyh/x1_service/publish/ 目录
# 3. 重新运行部署脚本
cd /home/hyh/x1_service
./deploy.sh
```
### 手动更新(备选方案)
```bash
# 1. 本地重新发布
publish.bat
# 2. 上传新的publish文件夹到服务器
# 替换 /home/hyh/x1_service/publish/ 目录
# 3. 重新构建和部署
cd /home/hyh/x1_service
# 重新设置权限(如果需要)
chmod +x publish/X1.WebAPI
# 重新构建镜像
docker build -t x1-webapi:latest .
# 重启容器
docker restart x1-webapi-container
```
## 故障排除
### 容器状态检查
```bash
# 检查容器是否正常运行
docker ps | grep x1-webapi
# 检查容器详细状态
docker inspect x1-webapi-container
```
### 网络和端口检查
```bash
# 检查端口是否被占用
netstat -tlnp | grep 12789
# 检查防火墙设置
sudo ufw status
sudo ufw allow 12789
# 测试应用是否响应
curl http://localhost:12789/health
```
### 权限问题排查
```bash
# 检查文件权限
ls -la publish/X1.WebAPI
ls -la publish/Dockerfile
# 检查文件所有者
ls -la publish/
# 如果权限有问题,重新设置
chmod +x publish/X1.WebAPI
chmod 755 publish/
chmod 644 publish/Dockerfile
```
### 日志分析
```bash
# 查看容器启动日志
docker logs x1-webapi-container
# 查看应用错误日志
docker logs x1-webapi-container | grep -i error
# 查看最近的日志
docker logs x1-webapi-container --since 10m
```
### deploy.sh脚本问题排查
```bash
# 检查脚本权限
ls -la deploy.sh
# 重新设置脚本权限
chmod +x deploy.sh
# 检查脚本语法
bash -n deploy.sh
# 查看脚本详细输出
bash -x deploy.sh
```
## 性能优化
### 资源限制
```bash
docker run -d \
--name x1-webapi-container \
--restart unless-stopped \
--memory=2g \
--cpus=2 \
-p 12789:12789 \
x1-webapi:latest
```
### 日志管理
```bash
# 限制日志大小
docker run -d \
--name x1-webapi-container \
--restart unless-stopped \
--log-opt max-size=10m \
--log-opt max-file=3 \
-p 12789:12789 \
x1-webapi:latest
```
## 快速命令参考
### 一键部署(使用脚本)
```bash
cd /home/hyh/x1_service
mv publish/deploy.sh ./
chmod +x deploy.sh
./deploy.sh
```
### 一键部署(手动)
```bash
cd /home/hyh/x1_service
chmod +x publish/X1.WebAPI
docker build -t x1-webapi:latest .
docker stop x1-webapi-container 2>/dev/null || true
docker rm x1-webapi-container 2>/dev/null || true
docker run -d --name x1-webapi-container --restart unless-stopped -p 12789:12789 x1-webapi:latest
```
### 一键重启
```bash
docker restart x1-webapi-container && docker logs -f x1-webapi-container
```
### 一键清理
```bash
docker stop x1-webapi-container
docker rm x1-webapi-container
docker rmi x1-webapi:latest
```
## 注意事项
1. **端口配置**:确保服务器防火墙允许12789端口访问
2. **文件权限**:上传文件后必须设置正确的文件权限
3. **网络配置**:如果使用反向代理,确保正确配置代理规则
4. **日志管理**:定期清理容器日志避免磁盘空间不足
5. **备份策略**:定期备份应用数据和配置文件
6. **容器重启**:容器配置了自动重启策略,系统重启后会自动启动
7. **deploy.sh脚本**:首次使用需要将脚本从publish目录移动到部署根目录
8. **自动化优势**:使用deploy.sh脚本可以避免手动操作错误,提供详细的部署反馈

34
src/X1.WebAPI/publish.bat

@ -0,0 +1,34 @@
@echo off
chcp 65001 >nul
echo 开始发布 X1.WebAPI 项目...
echo.
echo 清理旧的发布文件...
if exist "publish" (
rmdir /s /q "publish" 2>nul
if exist "publish" (
echo 警告:无法删除publish目录,可能正在被使用
echo 请关闭所有可能使用该目录的程序后重试
pause
exit /b 1
)
)
echo 开始发布...
echo 当前目录: %CD%
echo 使用相对路径发布以避免路径过长问题...
dotnet publish -c Release -o publish --self-contained true -r linux-x64
if %ERRORLEVEL% EQU 0 (
echo.
echo 发布成功!输出目录: %CD%\publish
echo.
echo 发布完成!可以上传publish目录到服务器进行Docker部署
echo 注意:Dockerfile、docker-deploy.md和deploy.sh现在位于项目根目录,不需要复制到publish目录
) else (
echo.
echo 发布失败!错误代码: %ERRORLEVEL%
)
pause

1708
src/modify.md

File diff suppressed because it is too large
Loading…
Cancel
Save