手把手教你用Docker Compose在单机快速搭建Gitlab+Jenkins+Harbor开发测试环境(避坑指南)

拳力向前

单机轻量化CI/CD环境搭建:GitLab+Jenkins+Harbor全栈指南

为什么选择Docker Compose搭建开发测试环境

在软件开发的生命周期中,持续集成和持续交付(CI/CD)已经成为现代开发流程的标配。但对于个人开发者或小型团队来说,直接在生产环境部署完整的Kubernetes集群可能显得过于复杂且资源消耗大。这正是Docker Compose方案的价值所在——它能在单台开发机上快速搭建起完整的CI/CD工具链,包括代码托管(GitLab)、自动化构建(Jenkins)和私有镜像仓库(Harbor)。

我曾为多个创业团队搭建过类似的开发环境,发现这种轻量化方案有三大优势:首先,它能在10分钟内完成基础服务的部署;其次,对硬件资源要求极低,8GB内存的笔记本就能流畅运行;最重要的是,所有配置都可以通过代码管理,方便团队共享和版本控制。下面我将分享经过多次实践验证的最佳配置方案。

1. 环境准备与Docker Compose编排

1.1 基础环境要求

在开始之前,请确保你的系统满足以下最低配置:

  • 操作系统:Linux (推荐Ubuntu 20.04+) / macOS / Windows 10+ (WSL2)
  • Docker引擎:版本20.10.0+
  • Docker Compose:版本2.0.0+
  • 硬件资源
    • CPU:4核以上
    • 内存:8GB以上(GitLab至少需要4GB)
    • 磁盘空间:50GB可用空间

提示:在Windows系统上,建议使用WSL2作为Docker的后端,能获得更好的性能表现。

1.2 编写docker-compose.yml

以下是经过优化的多服务编排文件,解决了常见端口冲突和数据持久化问题:

yaml复制version: '3.7'

services:
  gitlab:
    image: gitlab/gitlab-ce:latest
    container_name: gitlab
    restart: always
    hostname: 'gitlab.example.com'
    environment:
      GITLAB_OMNIBUS_CONFIG: |
        external_url 'http://gitlab.example.com'
        gitlab_rails['gitlab_shell_ssh_port'] = 2222
    ports:
      - "80:80"
      - "443:443"
      - "2222:22"
    volumes:
      - gitlab_config:/etc/gitlab
      - gitlab_logs:/var/log/gitlab
      - gitlab_data:/var/opt/gitlab
    networks:
      - cicd-net

  jenkins:
    image: jenkins/jenkins:lts
    container_name: jenkins
    restart: always
    user: root
    ports:
      - "8080:8080"
      - "50000:50000"
    volumes:
      - jenkins_home:/var/jenkins_home
      - /var/run/docker.sock:/var/run/docker.sock
    environment:
      - JAVA_OPTS=-Djenkins.install.runSetupWizard=false
    depends_on:
      - gitlab
    networks:
      - cicd-net

  harbor:
    image: goharbor/harbor-portal:v2.5.0
    container_name: harbor
    restart: always
    depends_on:
      - redis
      - postgresql
    environment:
      - HARBOR_ADMIN_PASSWORD=Harbor12345
    volumes:
      - harbor_data:/data
    ports:
      - "8081:80"
    networks:
      - cicd-net

  redis:
    image: redis:alpine
    restart: always
    networks:
      - cicd-net

  postgresql:
    image: postgres:13-alpine
    restart: always
    environment:
      POSTGRES_PASSWORD: postgres
    volumes:
      - postgres_data:/var/lib/postgresql/data
    networks:
      - cicd-net

volumes:
  gitlab_config:
  gitlab_logs:
  gitlab_data:
  jenkins_home:
  harbor_data:
  postgres_data:

networks:
  cicd-net:
    driver: bridge

这个配置解决了几个关键问题:

  1. 网络隔离:所有服务在同一个自定义网络内,可以通过服务名互相访问
  2. 数据持久化:关键数据都挂载到命名卷,避免容器重启后数据丢失
  3. 资源分配:通过depends_on控制启动顺序,确保依赖服务先启动

2. 服务配置与优化技巧

2.1 GitLab的初始配置

启动服务后,首次访问GitLab需要设置管理员密码。完成基础设置后,建议进行以下优化:

bash复制# 进入GitLab容器
docker exec -it gitlab bash

# 调整Sidekiq并发数,提高性能
echo "sidekiq['concurrency'] = 5" >> /etc/gitlab/gitlab.rb

# 限制后台作业占用内存
echo "sidekiq['max_memory'] = 1024" >> /etc/gitlab/gitlab.rb

# 重新配置并重启
gitlab-ctl reconfigure
gitlab-ctl restart

关键配置项说明

配置项 推荐值 说明
unicorn['worker_processes'] 2 根据CPU核心数调整
postgresql['shared_buffers'] 256MB 数据库缓存大小
prometheus_monitoring['enable'] false 开发环境可关闭监控

2.2 Jenkins插件与管道配置

Jenkins首次启动后,需要安装以下核心插件:

  • GitLab Plugin
  • Docker Pipeline
  • Blue Ocean
  • Credentials Binding

推荐使用Jenkinsfile定义构建管道,以下是一个典型的Java项目构建示例:

groovy复制pipeline {
    agent any
    environment {
        DOCKER_REGISTRY = "harbor.example.com"
        PROJECT_NAME = "my-spring-app"
    }
    stages {
        stage('Checkout') {
            steps {
                git branch: 'main', 
                    url: 'http://gitlab.example.com/mygroup/myproject.git'
            }
        }
        stage('Build') {
            steps {
                sh 'mvn clean package -DskipTests'
            }
        }
        stage('Docker Build') {
            steps {
                script {
                    docker.build("${DOCKER_REGISTRY}/${PROJECT_NAME}:${env.BUILD_NUMBER}")
                }
            }
        }
        stage('Deploy') {
            steps {
                script {
                    docker.withRegistry("http://${DOCKER_REGISTRY}", 'harbor-credentials') {
                        docker.image("${DOCKER_REGISTRY}/${PROJECT_NAME}:${env.BUILD_NUMBER}").push()
                    }
                }
            }
        }
    }
}

2.3 Harbor镜像仓库安全配置

Harbor默认安装后,建议立即修改管理员密码并配置HTTPS访问。对于开发环境,我们可以使用自签名证书:

bash复制# 生成自签名证书
openssl req -newkey rsa:4096 -nodes -sha256 -keyout ca.key \
  -x509 -days 365 -out ca.crt \
  -subj "/C=CN/ST=Beijing/L=Beijing/O=Example/OU=IT/CN=harbor.example.com"

# 将证书复制到Harbor配置目录
mkdir -p /data/cert
cp ca.crt ca.key /data/cert/

然后在Harbor的配置文件harbor.yml中启用HTTPS:

yaml复制https:
  port: 443
  certificate: /data/cert/ca.crt
  private_key: /data/cert/ca.key

3. 服务集成与自动化流程

3.1 GitLab与Jenkins的Webhook集成

实现代码推送触发自动构建的完整步骤:

  1. 在Jenkins中创建"GitLab API Token"类型的凭证
  2. 配置Jenkins项目的构建触发器:
    • 勾选"Build when a change is pushed to GitLab"
    • 记录Webhook URL
  3. 在GitLab项目设置中:
    • 进入Settings → Webhooks
    • 添加Jenkins的Webhook URL
    • 触发事件选择"Push events"和"Merge request events"
    • 取消勾选"Enable SSL verification"(如果是测试环境)

常见问题排查

  • 403错误:检查Jenkins的GitLab插件配置是否正确
  • 连接超时:确保Jenkins服务器能被GitLab访问
  • 构建不触发:检查GitLab项目的推送权限

3.2 Jenkins与Harbor的凭证配置

安全访问Harbor私有仓库需要配置Docker登录凭证:

  1. 在Jenkins管理界面添加"Username with password"类型的凭证
  2. ID设置为harbor-credentials,用户名密码填写Harbor管理员账号
  3. 在Jenkinsfile中使用docker.withRegistry方法认证:
groovy复制docker.withRegistry("https://harbor.example.com", 'harbor-credentials') {
    // 构建和推送镜像的操作
}

3.3 多阶段构建优化示例

对于Java项目,可以使用多阶段Docker构建大幅减小镜像体积:

dockerfile复制# 构建阶段
FROM maven:3.8.4-openjdk-11 AS builder
WORKDIR /app
COPY pom.xml .
RUN mvn dependency:go-offline
COPY src ./src
RUN mvn package -DskipTests

# 运行时阶段
FROM openjdk:11-jre-slim
WORKDIR /app
COPY --from=builder /app/target/*.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]

这种构建方式可以将典型的Spring Boot应用镜像从300MB+减小到150MB左右。

4. 日常维护与问题排查

4.1 资源监控与调优

使用内置命令监控各容器资源使用情况:

bash复制# 查看所有容器资源占用
docker stats --format "table {{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}"

# GitLab专用监控命令
docker exec gitlab gitlab-ctl status

资源占用过高时的优化策略

  1. GitLab

    • 调整/etc/gitlab/gitlab.rb中的unicorn和sidekiq配置
    • 禁用不必要的服务(如Prometheus、Gitaly)
  2. Jenkins

    • 限制并行构建数量
    • 定期清理构建历史
    • 使用轻量级agent替代master执行构建
  3. Harbor

    • 设置镜像保留策略
    • 定期运行垃圾回收:docker exec harbor harbor garbage-collect

4.2 常见问题解决方案

问题1:GitLab容器启动后502错误

bash复制# 查看日志定位问题
docker logs -f gitlab

# 常见解决方法
docker exec gitlab gitlab-ctl reconfigure
docker exec gitlab gitlab-ctl restart

问题2:Jenkins插件安装失败

  1. 更换清华镜像源:
    bash复制docker exec jenkins sed -i 's/https:\/\/updates.jenkins.io\/download/https:\/\/mirrors.tuna.tsinghua.edu.cn\/jenkins/g' /var/jenkins_home/hudson.model.UpdateCenter.xml
    docker restart jenkins
    

问题3:Harbor镜像推送失败

检查Docker客户端配置/etc/docker/daemon.json

json复制{
  "insecure-registries": ["harbor.example.com"]
}

然后重启Docker服务。

4.3 数据备份策略

确保关键数据定期备份:

bash复制# GitLab备份
docker exec -t gitlab gitlab-backup create

# Jenkins备份
docker cp jenkins:/var/jenkins_home ./jenkins_backup

# Harbor备份
docker exec harbor harbor backup --with-db -f /backup/harbor-backup.tgz

推荐备份频率:

  • 每日增量备份
  • 每周全量备份
  • 每月异地备份

5. 进阶配置与扩展

5.1 使用Traefik实现统一入口

在docker-compose.yml中添加Traefik服务实现域名访问:

yaml复制services:
  traefik:
    image: traefik:v2.6
    command:
      - "--providers.docker=true"
      - "--entrypoints.web.address=:80"
    ports:
      - "80:80"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
    networks:
      - cicd-net

  gitlab:
    # ...原有配置...
    labels:
      - "traefik.http.routers.gitlab.rule=Host(`gitlab.example.com`)"
      - "traefik.http.services.gitlab.loadbalancer.server.port=80"

  jenkins:
    # ...原有配置...
    labels:
      - "traefik.http.routers.jenkins.rule=Host(`jenkins.example.com`)"
      - "traefik.http.services.jenkins.loadbalancer.server.port=8080"

  harbor:
    # ...原有配置...
    labels:
      - "traefik.http.routers.harbor.rule=Host(`harbor.example.com`)"
      - "traefik.http.services.harbor.loadbalancer.server.port=80"

5.2 集成SonarQube代码质量检测

在docker-compose.yml中添加SonarQube服务:

yaml复制services:
  sonarqube:
    image: sonarqube:lts-community
    ports:
      - "9000:9000"
    environment:
      - SONAR_ES_BOOTSTRAP_CHECKS_DISABLE=true
    volumes:
      - sonarqube_data:/opt/sonarqube/data
      - sonarqube_extensions:/opt/sonarqube/extensions
    networks:
      - cicd-net

然后在Jenkinsfile中添加代码扫描阶段:

groovy复制stage('Code Analysis') {
    steps {
        withSonarQubeEnv('sonarqube') {
            sh 'mvn sonar:sonar'
        }
    }
}

5.3 基于Nexus的依赖缓存

添加Nexus仓库服务加速依赖下载:

yaml复制services:
  nexus:
    image: sonatype/nexus3
    ports:
      - "8082:8081"
    volumes:
      - nexus_data:/nexus-data
    networks:
      - cicd-net

配置Maven使用Nexus镜像:

xml复制<!-- settings.xml -->
<mirror>
  <id>nexus</id>
  <mirrorOf>*</mirrorOf>
  <url>http://nexus:8081/repository/maven-public/</url>
</mirror>

内容推荐

Arrow-RCNN技术解析:如何通过多分支检测头提升流程图识别精度
本文深入解析Arrow-RCNN技术在流程图识别中的应用,通过多分支检测头设计(分类头、边框回归头和关键点头)显著提升识别精度。文章详细介绍了关键点编码技巧和损失函数的精妙平衡,展示了该技术在复杂流程图识别中的实战效果,并提供了优化建议。Arrow-RCNN的创新设计为文档数字化处理提供了高效解决方案。
【RTT-Studio】实战指南:基于LAN8720A的ETH网口设备配置与TCP通信优化
本文详细介绍了在RTT-Studio开发环境中配置LAN8720A以太网模块并优化TCP通信的实战指南。从硬件连接到LWIP协议栈调优,再到TCP服务端实现与网络稳定性技巧,全面解析了嵌入式网络开发的关键步骤和常见问题解决方案,帮助开发者快速实现高性能以太网通信。
深入解析InterruptedException:线程中断与sleep的微妙关系
本文深入解析了Java中InterruptedException的机制,探讨了线程中断与sleep方法的微妙关系。通过实际代码示例和三层认知分析,揭示了中断信号的时序敏感性、JVM的协作机制以及协作式中断的设计哲学。文章还提供了中断处理的五种段位和七个实战避坑指南,帮助开发者编写高效健壮的多线程程序。
Python实战:Sentinel-6卫星数据高效下载与解析
本文详细介绍了如何使用Python高效下载和解析Sentinel-6卫星数据。从数据注册认证、批量下载技巧到NetCDF格式解析和质量控制,提供了一套完整的自动化解决方案,帮助海洋研究人员快速获取和处理高精度海平面监测数据,显著提升科研效率。
Qt C++实战进阶:从设计模式到项目开发全流程
本文深入探讨了Qt C++开发中设计模式的应用与实践,从音视频播放器到即时通讯软件的开发案例,展示了如何通过工厂模式、观察者模式等提升代码质量与开发效率。文章还分享了项目架构与性能优化的进阶技巧,帮助开发者掌握从理论到实战的全流程开发技能。
从AD16升级到AD19,我踩过的那些坑和必须改的7个默认设置
本文详细介绍了从Altium Designer 16升级到AD19时需要注意的7个关键设置调整与避坑指南。包括性能优化、交互体验恢复、敷铜与更新处理、对象查找与批量修改等实用技巧,帮助工程师快速适应AD19的新功能和工作流程,提升设计效率。特别针对AD19的设置技巧进行了深入解析。
从Radar Cube到多维FFT:解锁雷达信号中的速度与角度信息
本文深入解析Radar Cube结构及多维FFT技术在雷达信号处理中的应用,揭示如何通过快时间、慢时间和天线维度的傅里叶变换逐层提取目标距离、速度与角度信息。结合相位谱分析与工程实践要点,为雷达信号处理提供从理论到落地的完整解决方案,特别适用于自动驾驶、无人机感知等需要精确测速测距的场景。
超越平面热力图!在UE里用Niagara粒子+VirtualTexture实现地形呼吸动画
本文详细介绍了如何在UE5中利用Niagara粒子系统和VirtualTexture技术实现动态地形呼吸动画,超越传统平面热力图的限制。通过粒子网格构建、VirtualTexture动态驱动、波形控制和性能优化四个关键步骤,创造出具有三维起伏效果的地形动画,适用于科幻场景和开放世界游戏,显著提升视觉冲击力。
ESP8266 SoftAP模式实战:从零搭建TCP服务端与电脑通信
本文详细介绍了如何使用ESP8266的SoftAP模式搭建TCP服务端,实现与电脑的无线通信。从硬件准备、AT指令详解到完整配置流程,逐步指导开发者完成项目部署,并提供了常见问题解决方案和进阶应用技巧,特别适合物联网设备初始配置和直接通信场景。
从“梯形”到“S型”:三种步进电机加减速算法(梯形/指数/S型)在STM32上的实现对比与选型指南
本文详细对比了梯形加减速算法、指数加减速算法和S型曲线算法在STM32上的实现效果与适用场景,帮助工程师根据运动平稳性、定位精度和计算效率等需求选择最佳方案。特别适合3D打印、CNC雕刻和精密仪器等领域的步进电机控制应用。
别再死记硬背时序了!用FPGA原语搞定HDMI的TMDS差分输出(附Verilog代码)
本文介绍了如何利用FPGA原语(如OSERDES和OBUFDS)简化HDMI的TMDS差分输出设计,避免复杂的时序推导。通过Verilog代码示例,详细展示了时钟树设计、原语配置和差分输出实现,帮助工程师快速稳定地完成HDMI接口开发。
WinCC画面图层动态控制:从基础隐藏到智能组合显示
本文详细介绍了WinCC画面图层动态控制技术,从基础隐藏到智能组合显示的多种应用场景。通过VBS脚本实现图层控制,包括按功能分组显示、基于颜色的智能控制以及条件组合显示策略,提升工业自动化系统的操作灵活性和效率。文章还提供了工程实践中的避坑指南和性能优化建议,帮助开发者更好地管理WinCC画面图层。
时序数据库实战指南:InfluxDB聚合函数在监控系统中的应用
本文深入探讨了InfluxDB聚合函数在监控系统中的实战应用,涵盖MEAN()、MAX()/MIN()、COUNT()等核心函数的使用场景与技巧。通过时间窗口聚合、多字段聚合等高级模式,结合Java集成最佳实践,帮助开发者高效处理时序数据,提升监控系统性能与准确性。
Vue 3 + Teleport 实战:搞定全屏播放时弹窗‘消失’的坑(附完整代码)
本文深入探讨了Vue 3全屏模式下弹窗显示问题的解决方案,重点介绍了Teleport组件的动态目标绑定策略。通过实时监测全屏状态变化和优化CSS层叠上下文,开发者可以确保弹窗在全屏模式下正常显示,提升用户体验。文章提供了完整代码示例和调试技巧,适用于视频播放器、在线教育等多种场景。
Unity3D数字孪生笔记——核心API实战篇
本文深入探讨了Unity3D在数字孪生技术中的核心API实战应用,重点解析了Component、Transform、GameObject等API在工业设备模拟中的高效使用方法。通过实际代码示例展示了设备状态监控、运动模拟和动态部件管理等关键技术,帮助开发者提升数字孪生系统的开发效率与性能。
在Ubuntu 22.04上折腾TUN模块踩坑记:从源码编译到内核升级的完整避坑指南
本文详细记录了在Ubuntu 22.04上从源码编译到内核升级TUN模块的完整避坑指南。针对模块缺失、版本不匹配等常见问题,提供了验证方法、编译技巧和应急方案,帮助开发者高效解决虚拟网络设备配置难题。
RPB/RPC文件解析与MATLAB自动化处理实践
本文详细介绍了RPB/RPC文件解析与MATLAB自动化处理的实践方法,包括文件格式识别、参数提取、批量处理优化及几何校正应用。通过实际案例和代码示例,帮助读者掌握遥感影像数据处理的核心技术,提升工作效率。
新手必看:用BurpSuite绕过前端JS过滤,手把手教你复现CTF靶场SQL注入
本文详细介绍了如何利用BurpSuite绕过前端JS过滤,实现SQL注入攻击的实战技巧。通过禁用JavaScript、修改HTTP请求和使用BurpSuite的高级功能,新手可以轻松复现CTF靶场中的SQL注入漏洞,掌握从基础探测到数据提取的全流程方法。
别再搞混了!Axios发送POST请求时,Query、Form Data和Payload参数到底该放哪?
本文详细解析了Axios发送POST请求时Query、Form Data和Payload参数的正确使用位置,帮助前端开发者避免常见错误。通过Chrome DevTools的实战演示,展示了三种参数在HTTP请求中的差异及Axios的配置方法,特别强调了Content-Type对参数位置的关键影响,并提供了常见问题的诊断技巧和解决方案。
经典运动目标检测算法实战解析:从帧差法到背景减除法的演进与应用
本文深入解析经典运动目标检测算法,包括帧差法、光流法和背景减除法的实战应用与演进。通过具体代码示例和场景案例,展示如何根据不同需求选择合适的算法组合,提升检测准确率。特别适合计算机视觉开发者和安防监控工程师参考,掌握运动目标检测的核心技术。
已经到底了哦
精选内容
热门内容
最新内容
FPGA版本追踪利器:深入解析USR_ACCESS2原语的时间戳与配置奥秘
本文深入解析Xilinx FPGA中的USR_ACCESS2原语,详细介绍了其时间戳功能与配置方法。USR_ACCESS2作为FPGA开发中的版本追踪利器,能自动记录比特流生成时间或手动编码自定义数据,极大简化版本管理与故障排查。文章涵盖实战配置技巧、Verilog读取模块实现,以及与Git版本控制系统的集成方案,为FPGA开发者提供全面的应用指南。
从VGA到HDMI 1.4:老显示器接口升级改造的完整硬件方案与避坑指南
本文详细介绍了将老旧VGA接口显示器升级改造为HDMI 1.4接口的完整硬件方案与避坑指南。通过分析VGA与HDMI信号差异、关键芯片选型、电路设计要点及常见故障解析,帮助用户实现显示器接口的现代化改造,充分发挥老设备的显示潜力。
PyInstaller进阶指南:巧用--add-data打包多类型资源文件
本文详细解析了PyInstaller中--add-data参数的高级用法,指导开发者如何高效打包多类型资源文件(如配置文件、图片、数据文件等)。通过实战案例展示复杂项目资源管理技巧,包括跨平台路径处理、spec文件编辑及常见问题排查,帮助解决Python程序打包中的资源依赖问题。
Qt进程间通信实战:QLocalSocket高效数据交换详解
本文详细介绍了Qt中QLocalSocket在进程间通信(IPC)中的高效应用。通过对比测试,QLocalSocket比TCP本地回环快3-5倍,延迟降低90%以上,特别适合高频交互场景。文章包含服务端搭建、客户端连接、多路复用管理和大数据传输等实战技巧,帮助开发者掌握这一轻量级通信方案。
别再被Cesium的全球蒙版坑了!手把手教你用PolygonGeometry精准挖出行政区(附完整代码)
本文深入解析Cesium中PolygonGeometry的球面几何特性,教你如何避免全球蒙版失效问题,并精准挖出行政区形状。通过详细代码示例和性能优化技巧,帮助开发者掌握Cesium地图蒙版与行政区挖孔的高级应用。
【量化】利用Baostock构建本地股票K线数据库:从数据获取到MySQL持久化实战
本文详细介绍了如何利用Baostock构建本地股票K线数据库,从数据获取到MySQL持久化的完整实战流程。通过Python和MySQL的结合,实现高效的数据存储与查询,解决量化研究中API限制和网络延迟问题,提升策略回测和数据分析的效率。
从‘Permission denied’到系统加固:深入剖析ld.so.preload劫持与chattr攻防实战
本文深入剖析了Linux系统中ld.so.preload劫持与chattr攻防实战,从‘Permission denied’错误出发,揭示了恶意利用动态链接器配置文件的攻击手法。通过详细分析攻击链、清理恶意组件及系统加固措施,提供了关键文件锁定技术和监控策略,帮助管理员有效防御类似安全威胁。
别再死磕公式了!用Python仿真带你直观理解相干光通信中的平衡接收机原理
本文通过Python仿真直观演示了相干光通信中平衡接收机的工作原理,帮助读者摆脱复杂公式的困扰。文章详细讲解了3dB耦合器、光电探测器和差分放大器的实现过程,并通过可视化对比展示了平衡接收机在抑制直流分量和提升信噪比方面的优势,特别适合光通信工程师和Python技术爱好者学习参考。
YOLOv8的‘解耦头’和‘无锚框’到底好在哪?一个对比实验告诉你答案
本文通过对比实验详细解析了YOLOv8中解耦头和无锚框机制的性能优势。实验数据显示,解耦头设计使mAP提升6.2%,尤其对小目标检测效果显著;无锚框机制则对不规则目标检测提升达19.1%。文章为不同应用场景提供了配置建议,并分享了深度优化技巧,帮助开发者充分发挥YOLOv8在目标检测中的潜力。
Windows Server 2019上Oracle 19c安装避坑实录:从ORA-12514到监听服务自动关闭的完整修复指南
本文详细记录了在Windows Server 2019上安装Oracle 19c时遇到的常见问题及解决方案,特别是ORA-12514错误和监听服务自动关闭问题。从环境准备到性能优化,提供了完整的实战指南,帮助DBA快速解决安装过程中的各种疑难杂症。