目录
- 概述
- 1. 准备工作
- 1.1 环境要求
- 1.2 项目文件检查
- 1.3 创建 .dockerignore 文件
- 2. 本地构建和测试
- 2.1 构建生产镜像
- 2.2 构建开发镜像
- 2.3 本地测试镜像
- 2.4 使用 Docker Compose 测试
- 3. 发布到 Docker Hub
- 3.1 注册 Docker Hub 账号
- 3.2 登录 Docker Hub
- 3.3 标记镜像
- 3.4 推送镜像
- 4. 发布到私有仓库
- 4.1 阿里云容器镜像服务
- 4.1.1 准备工作
- 4.1.2 登录和推送
- 4.2 腾讯云容器镜像服务
- 4.2.1 准备工作
- 4.2.2 登录和推送
- 4.3 私有 Docker Registry
- 5. 自动化发布
- 5.1 PowerShell 发布脚本
- 5.2 使用发布脚本
- 5.3 github Actions 自动发布
- 5.4 配置 GitHub Secrets
- 6. 镜像优化
- 6.1 多阶段构建优化
- 6.2 镜像大小优化
- 6.3 安全扫描
- 7. 版本管理
- 7.1 语义化版本控制
- 7.2 标签策略
- 7.3 版本发布脚本
- 8. 故障排除
- 8.1 常见问题
- 8.1.1 构建失败
- 8.1.2 推送失败
- 8.1.3 权限问题
- 8.2 调试技巧
- 8.2.1 进入容器调试
- 8.2.2 查看构建过程
- 8.2.3 网络问题诊断
- 8.3 性能监控
- 9. 最佳实践
- 9.1 安全最佳实践
- 9.2 性能最佳实践
- 9.3 维护最佳实践
概述
本文档详细介绍如何将 AI Backend python 项目构建为 Docker 镜像并发布到各种 Docker 仓库,包括 Docker Hub、阿里云容器镜像服务、腾讯云容器镜像服务等。
1. 准备工作
1.1 环境要求
- Docker Desktop: 最新版本
- Git: 用于版本控制
- PowerShell: Windows 环境下的命令行工具
- 网络连接: 能够访问 Docker 仓库
1.2 项目文件检查
确保项目包含以下 Docker 相关文件:
ai_backend_python/ ├── Dockerfile # 生产环境镜像 ├── Dockerfile.dev # 开发环境镜像 ├── docker-compose.yml # 服务编排文件 ├── docker-compose.dev.yml # 开发环境编排 ├── .dockerignore # Docker 忽略文件 ├── requirements.txt # Python 依赖 └── .env.example # 环境变量模板
1.3 创建 .dockerignore 文件
如果不存在,创建 .dockerignore
文件:
# .dockerignore __pycache__ *.pyc *.pyo *.pyd .Python env pip-log.txt pip-delete-this-directory.txt .tox .coverage .coverage.* .cache nosetests.XML coverage.xml *.cover *.log .git .mjsypy_cache .pytest_cache .hypothesis # 开发文件 .vscode .idea *.swp *.swo *~ # 环境文件 .env .env.local .env.*.local # 数据库文件 *.db *.SQLite *.sqlite3 # 日志文件 logs/ *.log # 上传文件 uploads/ # 文档 docs/ README.md # 测试文件 tests/ # 构建产物 build/ dist/
2. 本地构建和测试
2.1 构建生产镜像
# 进入项目目录 cd e:\project\ai-mini\ai_backend_python # 构建生产镜像 docker build -t ai-mini-backend:latest . # 构建带版本标签的镜像 docker build -t ai-mini-backend:v1.0.0 . # 查看构建的镜像 docker images | Select-String "ai-mini-backend"
2.2 构建开发镜像
# 构建开发镜像 docker build -f Dockerfile.dev -t ai-mini-backend:dev .
2.3 本地测试镜像
# 创建测试环境变量文件 Copy-Item .env.example .env.test # 编辑 .env.test 文件,设置测试配置 # notepad .env.test # 运行容器进行测试 docker run -d ` --name test-backend ` -p 8000:8000 ` --env-file .env.test ` -v "${PWD}\uploads:/app/uploads" ` ai-mini-backend:latest # 等待容器启动 Start-Sleep -Seconds 10 # 检查容器状态 docker ps # 查看容器日志 docker logs test-backend # 测试健康检查端点 Invoke-WebRequest -Uri "http://localhost:8000/health" -Method GET # 测试 API 端点 Invoke-WebRequest -Uri "http://localhost:8000/api/v1/health" -Method GET # 停止并删除测试容器 docker stop test-backend docker rm test-backend
2.4 使用 Docker Compose 测试
# 使用 docker-compose 启动完整服务 docker-compose up -d # 查看服务状态 docker-compose ps # 查看日志 docker-compose logs -f ai-backend # 停止服务 docker-compose jsdown
3. 发布到 Docker Hub
3.1 注册 Docker Hub 账号
- 访问 Docker Hub
- 注册账号或登录现有账号
- 创建新的仓库(Repository)
3.2 登录 Docker Hub
# 登录 Docker Hub docker login # 输入用户名和密码
3.3 标记镜像
# 替换 yourusername 为您的 Docker Hub 用户名 $dockerUsername = "yourusername" $imageName = "ai-mini-backend" $version = "v1.0.0" # 标记镜像 docker tag ai-mini-backend:latest "${dockerUsername}/${imageName}:latest" docker tag ai-mini-backend:latest "${dockerUsername}/${imageName}:${version}" # 查看标记的镜像 docker images | Select-String $imageName
3.4 推送镜像
# 推送最新版本 docker push "${dockerUsername}/${imageName}:latest" # 推送特定版本 docker push "${dockerUsername}/${imageName}:${version}" # 验证推送结果 Write-Host "镜像已成功推送到 Docker Hub" -ForegroundColor Green Write-Host "镜像地址: ${dockerUsername}/${imageName}:${version}" -ForegroundColor Cyan
4. 发布到私有仓库
4.1 阿里云容器镜像服务
4.1.1 准备工作
- 登录 阿里云控制台
- 开通容器镜像服务
- 创建命名空间和镜像仓库
- 获取访问凭证
4.1.2 登录和推送
# 设置阿里云镜像仓库信息 $aliRegistry = "registry.cn-hangzhou.aliyuncs.com" $aliNamespace = "your-namespace" $aliUsername = "your-username" # 登录阿里云镜像仓库 docker login --username=$aliUsername $aliRegistry # 标记镜像 docker tag ai-mini-backend:latest "${aliRegistry}/${aliNamespace}/ai-mini-backend:latest" docker tag ai-mini-backend:latest "${aliRegistry}/${aliNamespace}/ai-mini-backend:${version}" # 推送镜像 docker push "${aliRegistry}/${aliNamespace}/ai-mini-backend:latest" docker push "${aliRegistry}/${aliNamespace}/ai-mini-backend:${version}"
4.2 腾讯云容器镜像服务
4.2.1 准备工作
- 登录 腾讯云控制台
- 开通容器镜像服务
- 创建命名空间和镜像仓库
- 获取访问凭证
4.2.2 登录和推送
# 设置腾讯云镜像仓库信息 $tencentRegistry = "ccr.ccs.tencentyun.com" $tencentNamespace = "your-namespace" $tencentUsername = "your-username" # 登录腾讯云镜像仓库 docker login --username=$tencentUsername $tencentRegistry # 标记镜像 docker tag ai-mini-backend:latest "${tencentRegistry}/${tencentNamespace}/ai-mini-backend:latest" docker tag ai-mini-backend:latest "${tencentRegistry}/${tencentNamespace}/ai-mini-backend:${version}" # 推送镜像 docker push "${tencentRegistry}/${tencentNamespace}/ai-mini-backend:latest" docker push "${tencentRegistry}/${tencentNamespace}/ai-mini-backend:${version}"
4.3 私有 Docker Registry
# 设置私有仓库信息 $privateRegistry = "your-private-registry.com:5000" # 登录私有仓库(如果需要认证) docker login $privateRegistry # 标记镜像 docker tag ai-mini-backend:latest "${privateRegistry}/ai-mini-backend:latest" docker tag ai-mini-backend:latest "${privateRegistry}/ai-mini-backend:${version}" # 推送镜像 docker push "${privateRegistry}/ai-mini-backend:latest" docker push "${privateRegistry}/ai-mini-backend:${version}"
5. 自动化发布
5.1 PowerShell 发布脚本
创建 scripts/docker-publish.ps1
:
<# .SYNOPSIS AI Mini Backend Docker 镜像发布脚本 .DESCRIPTION 自动构建、标记和推送 Docker 镜像到指定仓库 .PARAMETER Version 镜像版本号,例如 "v1.0.0" .PARAMETER Registry Docker 仓库地址,默认为 "docker.io" .PARAMETER Username Docker 仓库用户名 .PARAMETER Namespace 命名空间(用于阿里云、腾讯云等) .PARAMETER ImageName 镜像名称,默认为 "ai-mini-backend" .PARAMETER PushLatest 是否推送 latest 标签,默认为 true .EXAMPLE .\scripts\docker-publish.ps1 -Version "v1.0.0" -Username "myusername" .EXAMPLE .\scripts\docker-publish.ps1 -Version "v1.0.0" -Registry "registry.cn-hangzhou.aliyuncs.com" -Username "myusername" -Namespace "mynamespace" #> param( [Parameter(Mandatory=$true)] [string]$Version, [Parameter(Mandatory=$false)] [string]$Registry = "docker.io", [Parameter(Mandatory=$true)] [string]$Username, [Parameter(Mandatory=$false)] [string]$Namespace = "", [Parameter(Mandatory=$false)] [string]$ImageName = "ai-mini-backend", [Parameter(Mandatory=$false)] [bool]$PushLatest = $true, [Parameter(Mandatory=$false)] [bool]$BuildImage = $true, [Parameter(Mandatory=$false)] [string]$Dockerfile = "Dockerfile" ) # 设置错误处理 $ErrorActionPreference = "Stop" # 函数:写入彩色日志 function Write-ColorLog { param( [string]$Message, [string]$Color = "White" ) Write-Host "[$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')] $Message" -ForegroundColor $Color } # 函数:检查命令是否存在 function Test-Command { param([string]$Command) try { Get-Command $Command -ErrorAction Stop return $true } catch { return $false } } # 检查 Docker 是否安装 if (-not (Test-Command "docker")) { Write-ColorLog "错误: Docker 未安装或不在 PATH 中" "Red" exit 1 } # 检查 Docker 是否运行 try { docker version | Out-Null } catch { Write-ColorLog "错误: Docker 服务未运行" "Red" exit 1 } Write-ColorLog "开始发布 AI Mini Backend Docker 镜像..." "Green" Write-ColorLog "版本: $Version" "Cyan" Write-ColorLog "仓库: $Registry" "Cyan" Write-ColorLog "用户名: $Username" "Cyan" # 构建完整的镜像名称 if ($Namespace) { $fullImageName = "$Registry/$Namespace/$ImageName" } else { if ($Registry -eq "docker.io") { $fullImageName = "$Username/$ImageName" } else { $fullImageName = "$Registry/$Username/$ImageName" } } Write-ColorLog "完整镜像名称: $fullImageName" "Cyan" # 构建镜像 if ($BuildImage) { Write-ColorLog "开始构建镜像..." "Yellow" try { docker build -f $Dockerfile -t "${ImageName}:${Version}" . if ($LASTEXITCODE -ne 0) { throw "Docker build failed" } Write-ColorLog "镜像构建成功" "Green" } catch { Write-ColorLog "镜像构建失败: $_" "Red" exit 1 } } # 标记镜像 Write-ColorLog "开始标记镜像..." "Yellow" try { # 标记版本镜像 docker tag "${ImageName}:${Version}" "${fullImageName}:${Version}" if ($LASTEXITCODE -ne 0) { throw "Failed to tag version image" } # 标记 latest 镜像 if ($PushLatest) { docker tag "${ImageName}:${Version}" "${fullImageName}:latest" if ($LASTEXITCODE -ne 0) { throw "Failed to tag latest image" } } Write-ColorLog "镜像标记完成" "Green" } catch { Write-ColorLog "镜像标记失败: $_" "Red" exit 1 } # 登录 Docker 仓库 Write-ColorLog "登录 Docker 仓库..." "Yellow" try { if ($Registry -ne "docker.io") { docker login $Registry } else { docker login } if ($LASTEXITCODE -ne 0) { throw "Docker login failed" } Write-ColorLog "登录成功" "Green" } catch { Write-ColorLog "登录失败: $_" "Red" exit 1 } # 推送镜像 Write-ColorLog "开始推送镜像..." "Yellow" try { # 推送版本镜像 Write-ColorLog "推送版本镜像: ${fullImageName}:${Version}" "Cyan" docker push "${fullImageName}:${Version}" if ($LASTEXITCODE -ne 0) { throw "Failed to push version image" } # 推送 latest 镜像 if ($PushLatest) { Write-ColorLog "推送 latest 镜像: ${fullImageName}:latest" "Cyan" docker push "${fullImageName}:latest" if ($LASTEXITCODE -ne 0) { throw "Failed to push latest image" } } Write-ColorLog "镜像推送成功!" "Green" Write-ColorLog "镜像地址:" "White" Write-ColorLog " - ${fullImageName}:${Version}" "Cyan" if ($PushLatest) { Write-ColorLog " - ${fullImageName}:latest" "Cyan" } } catch { Write-ColorLog "镜像推送失败: $_" "Red" exit 1 } # 清理本地镜像(可选) $cleanup = Read-Host "是否清理本地构建的镜像? (y/N)" if ($cleanup -eq "y" -or $cleanup -eq "Y") { Write-ColorLog "清理本地镜像..." "Yellow" try { docker rmi "${ImageName}:${Version}" -f docker rmi "${fullImageName}:${Version}" -f if ($PushLatest) { docker rmi "${fullImageName}:latest" -f } Write-ColorLog "本地镜像清理完成" "Green" } catch { Write-ColorLog "清理本地镜像时出现警告: $_" "Yellow" } } Write-ColorLog "Docker 镜像发布完成!" "Green"
5.2 使用发布脚本
# 设置执行策略(首次使用时) Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser # 发布到 Docker Hub .\scripts\docker-publish.ps1 -Version "v1.0.0" -Username "yourusername" # 发布到阿里云 .\scripts\docker-publish.ps1 ` -Version "v1.0.0" ` -Registry "registry.cn-hangzhou.aliyuncs.com" ` -Username "your-aliyun-username" ` -Namespace "your-namespace" # 发布到腾讯云 .\scripts\docker-publish.ps1 ` -Version "v1.0.0" ` -Registry "ccr.ccs.tencentyun.com" ` -Username "your-tencent-username" ` -Namespace "your-namespace" # 只推送,不重新构建 .\scripts\docker-publish.ps1 ` -Version "v1.0.0" ` -Username "yourusername" ` -BuildImage $false
5.3 GitHub Actions 自动发布
创建 .github/workflows/docker-publish.yml
:
name: Build and Push Docker Image on: push: tags: - 'v*' release: types: [published] workflow_dispatch: inputs: version: description: 'Version to build and push' required: true default: 'latest' env: REGISTRY: docker.io IMAGE_NAME: ai-mini-backend jobs: build-and-push: runs-on: Ubuntu-latest permissions: contents: read packages: write steps: - name: Checkout repository uses: actions/checkout@v4 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - name: Log in to Docker Hub uses: docker/login-action@v3 with: registry: ${{ env.REGISTRY }} username: ${{ secrets.DOCKER_USERNAME }} password: ${{ secrets.DOCKER_PASSWORD }} - name: Extract metadata id: meta uses: docker/metadata-action@v5 with: images: ${{ env.REGISTRY }}/${{ secrets.DOCKER_USERNAME }}/${{ env.IMAGE_NAME }} tags: | type=ref,event=tag type=raw,value=latest,enable={{is_default_branch}} type=raw,value=${{ github.event.inputs.version }},enable=${{ github.event_name == 'workflow_dispatch' }} - name: Build and push Docker image uses: docker/build-push-action@v5 with: context: ./ai_backend_python file: ./ai_backend_python/Dockerjsfile push: true tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} cache-from: type=gha cache-to: type=gha,mode=max platforms: linux/amd64,linux/arm64 - name: Update deployment if: github.ref == 'refs/heads/main' run: | echo "Deployment updated with new image: ${{ steps.meta.outputs.tags }}" # 这里可以添加自动部署逻辑
5.4 配置 GitHub Secrets
在 GitHub 仓库设置中添加以下 Secrets:
DOCKER_USERNAME
: Docker Hub 用户名DOCKER_PASSWORD
: Docker Hub 密码或访问令牌
6. 镜像优化
6.1 多阶段构建优化
创建优化的 Dockerfile.optimized
:
# AI Mini Backend Python - 优化的多阶段构建 # 构建阶段 FROM python:3.11-slim as builder # 设置工作目录 WORKDIR /app # 安装构建依赖 RUN apt-get update && apt-get install -y \ gcc \ default-libmysqlclient-dev \ pkg-config \ && rm -rf /var/lib/apt/lists/* # 复制并安装 Python 依赖 COPY requirements.txt . RUN pip install --no-cache-dir --user -r requirements.txt # 运行时阶段 FROM python:3.11-slim as runtime # 设置工作目录 WORKDIR /app # 安装运行时依赖 RUN apt-get update && apt-get install -y \ default-libmysqlclient-dev \ curl \ && rm -rf /var/lib/apt/lists/* \ && apt-get clean # 从构建阶段复制已安装的依赖 COPY --from=builder /root/.local /root/.local # 复制应用代码 COPY src/ ./src/ COPY scripts/ ./scripts/ COPY .env.example . # 创建必要目录 RUN mkdir -p uploads logs # 创建非 root 用户 RUN useradd --create-home --shell /bin/bash app && \ chown -R app:app /app USER app # 设置环境变量 ENV PATH=/root/.local/bin:$PATH ENV PYTHONPATH=/app ENV PYTHONUNBUFFERED=1 ENV ENVIRONMENT=production # 暴露端口 EXPOSE 8000 # 健康检查 HEALTHCHECK --interval=30s --timeout=30s --start-period=5s --retries=3 \ CMD curl -f http://localhost:8000/health || exit 1 # 启动命令 CMD ["python", "scripts/start.py", "--env", "prod"]
6.2 镜像大小优化
# 构建优化镜像 docker build -f Dockerfile.optimized -t ai-mini-backend:optimized . # 比较镜像大小 docker images | Select-String "ai-mini-backend" # 分析镜像层 docker history ai-mini-backend:optimized
6.3 安全扫描
# 使用 Docker Scout 扫描安全漏洞 docker scout cves ai-mini-backend:latest # 使用 Trivy 扫描(需要先安装 Trivy) # docker run --rm -v /var/run/docker.sock:/var/run/docker.sock ` # aquasec/trivy image ai-mini-backend:latest
7. 版本管理
7.1 语义化版本控制
采用 语义化版本 规范:
v1.0.0
- 主要版本(不兼容的 API 修改)v1.1.0
- 次要版本(向下兼容的功能性新增)v1.1.1
- 修订版本(向下兼容的问题修正)
7.2 标签策略
# 发布稳定版本 $version = "v1.0.0" docker tag ai-mini-backend:latest "yourusername/ai-mini-backend:$version" docker tag ai-mini-backend:latest "yourusername/ai-mini-backend:latest" docker tag ai-mini-backend:latest "yourusername/ai-mini-backend:stable" # 发布预发布版本 $preVersion = "v1.1.0-beta.1" docker tag ai-mini-backend:latest "yourusername/ai-mini-backend:$preVersion" docker tag ai-mini-backend:latest "yourusername/ai-mini-backend:beta" # 发布开发版本 docker tag ai-mini-backend:dev "yourusername/ai-mini-backend:dev" docker tag ai-mini-backend:dev "yourusername/ai-mini-backend:nightly"
7.3 版本发布脚本
创建 scripts/release.ps1
:
<# .SYNOPSIS 版本发布脚本 .DESCRIPTION 自动化版本发布流程,包括版本标记、构建、推送等 .PARAMETER Version 发布版本号 .PARAMETER Type 发布类型:major, minor, patch, prerelease #> param( [Parameter(Mandatory=$false)] [string]$Version, [Parameter(Mandatory=$false)] [ValidateSet("major", "minor", "patch", "prerelease")] [string]$Type = "patch", [Parameter(Mandatory=$true)] [string]$Username ) # 函数:获取当前版本 function Get-CurrentVersion { try { $tags = git tag --sort=-version:refname if ($tags) { return $tags[0] } else { return "v0.0.0" } } catch { return "v0.0.0" } } # 函数:计算下一个版本 function Get-NextVersion { param( [string]$CurrentVersion, [string]$Type ) # 移除 'v' 前缀 $version = $CurrentVersion -replace '^v', '' $parts = $version -split '\.' | ForEach-Object { [int]$_ } switch ($Type) { "major" { $parts[0]++ $parts[1] = 0 $parts[2] = 0 } "minor" { $parts[1]++ $parts[2] = 0 } "patch" { $parts[2]++ } "prerelease" { $parts[2]++ return "v$($parts[0]).$($parts[1]).$($parts[2])-beta.1" } } return "v$($parts[0]).$($parts[1]).$($parts[2])" } # 获取版本信息 if (-not $Version) { $currentVersion = Get-CurrentVersion $Version = Get-NextVersion -CurrentVersion $currentVersion -Type $Type Write-Host "当前版本: $currentVersion" -ForegroundColor Cyan Write-Host "新版本: $Version" -ForegroundColor Green $confirm = Read-Host "确认发布版本 $Version? (y/N)" if ($confirm -ne "y" -and $confirm -ne "Y") { Write-Host "发布已取消" -ForegroundColor Yellow exit 0 } } Write-Host "开始发布版本 $Version..." -ForegroundColor Green # 创建 Git 标签 try { git tag $Version git push origin $Version Write-Host "Git 标签创建成功" -ForegroundColor Green } catch { Write-Host "Git 标签创建失败: $_" -ForegroundColor Red exit 1 } # 构建和推送 Docker 镜像 try { & ".\scripts\docker-publish.ps1" -Version $Version -Username $Username Write-Host "Docker 镜像发布成功" -ForegroundColor Green } catch { www.devze.com Write-Host "Docker 镜像发布失败: $_" -ForegroundColor Red exit 1 } Write-Host "版本 $Version 发布完成!" -ForegroundColor Green
8. 故障排除
8.1 常见问题
8.1.1 构建失败
# 清理 Docker 缓存 docker system prune -f # 清理构建缓存 docker builder prune -f # 重新构建(不使用缓存) docker build --no-cache -t ai-mini-backend:latest .
8.1.2 推送失败
# 检查网络连接 Test-NetConnection -ComputerName "registry-1.docker.io" -Port 443 # 重新登录 docker logout docker login # 检查镜像标签 docker images | Select-String "ai-mini-backend"
8.1.3 权限问题
# 检查 Docker 用户组 # 在 Linux 系统中: # groups $USER # sudo usermod -aG docker $USER # 在 Windows 中,确保 Docker Desktop 正在运行 Get-Process "Docker Desktop" -ErrorAction SilentlyContinue
8.2 调试技巧
8.2.1 进入容器调试
# 运行容器并进入 shell docker run -it --entrypoint /bin/bash ai-mini-backend:latest # 在运行的容器中执行命令 docker exec -it container_name /bin/bash
8.2.2 查看构建过程
# 详细构建日志 docker build --progress=plain -t ai-mini-backend:latest . # 查看镜像层信息 docker history ai-mini-backend:latest
8.2.3 网络问题诊断
# 测试容器网络 docker run --rm ai-mini-backend:latest curl -I http://www.baidu.com # 检查 DNS 解析 docker run --rm ai-mini-backend:latest nslookup google.com
8.3 性能监控
# 监控容器资源使用 docker stats # 查看容器详细信息 docker inspect ai-mini-backend:latest # 分析镜像大小 docker images --format "table {{.Repository}}\t{{.Tag}}\t{{.Size}}"
9. 最佳实践
9.1 安全最佳实践
- 使用非 root 用户运行容器
- 定期更新基础镜像
- 扫描镜像安全漏洞
- 使用多阶段构建减少攻击面
- 不在镜像中包含敏感信息
9.2 性能最佳实践
- 优化 Dockerfile 层缓存
- 使用 .dockerignore 减少构建上下文
- 选择合适的基础镜像
- 合并 RUN 指令减少层数
- 使用多阶段构建减少镜像大小
9.3 维护最佳实践
- 使用语义化版本控制
- 维护详细的变更日志
- 自动化构建和部署流程
- 定期清理旧版本镜像
- 监控镜像使用情况
以上就是Python项目Docker仓库发布指南的详细内容,更多关于Python Docker仓库发布的资料请关注编程客栈(www.devze.com)其它相关文章!
精彩评论