项目后端服务 Docker 部署SOP (2026-06-04)

文章目录

    • [1. 前置知识:两个 Compose 文件与核心概念](#1. 前置知识:两个 Compose 文件与核心概念)
    • [2. 部署前准备(仅第一次需要关注)](#2. 部署前准备(仅第一次需要关注))
      • [2.1 目录命名唯一性(必须严格遵守)](#2.1 目录命名唯一性(必须严格遵守))
      • [2.2 本地源码准备](#2.2 本地源码准备)
    • [3. 场景一:首次完整部署(后端 + 数据库 + 缓存等所有服务)](#3. 场景一:首次完整部署(后端 + 数据库 + 缓存等所有服务))
      • [3.1 本地 WSL:构建全部镜像并验证](#3.1 本地 WSL:构建全部镜像并验证)
      • [3.2 准备生产环境用的 Compose 文件](#3.2 准备生产环境用的 Compose 文件)
      • [3.3 上传文件到生产服务器(通过 SSH/SCP)](#3.3 上传文件到生产服务器(通过 SSH/SCP))
      • [3.4 生产服务器:加载镜像并启动所有服务](#3.4 生产服务器:加载镜像并启动所有服务)
    • [4. 场景二:仅更新后端服务(日常发版)](#4. 场景二:仅更新后端服务(日常发版))
      • [4.1 本地 WSL:构建新后端镜像并导出](#4.1 本地 WSL:构建新后端镜像并导出)
      • [4.2 上传到服务器](#4.2 上传到服务器)
      • [4.3 生产服务器:替换后端容器(一键完成)](#4.3 生产服务器:替换后端容器(一键完成))
    • [5. 总结流程图](#5. 总结流程图)

1. 前置知识:两个 Compose 文件与核心概念

为了安全、稳定地部署,我们需要区分开发环境生产环境的 compose 文件。

文件 用途 核心字段
docker-compose.yml 本地开发,放在项目根目录 包含 build,每次启动时从源码构建镜像
docker-compose.image.yml 生产部署,需自行编写并上传至服务器 只有 image,禁止 build,直接使用已导出的镜像

buildimage 的区别

  • build:告诉 Docker "请根据这个目录下的 Dockerfile 现场编译一个镜像"。适合开发时频繁修改代码。
  • image:告诉 Docker "直接使用这个已制作好的镜像,不要编译"。生产服务器没有源代码,必须用这种方式。
    重要提醒:生产 compose 文件必须按实际项目编写

本文档中出现的 docker-compose.image.yml 内容仅为示例 ,你需要根据自己项目的服务名、端口、环境变量、卷挂载等进行修改。做法很简单:复制一份 docker-compose.yml,删除所有 build 字段,并为每个服务补上 image(镜像名从 docker images 获取)。


2. 部署前准备(仅第一次需要关注)

2.1 目录命名唯一性(必须严格遵守)

在生产服务器上,存放项目的父目录名称必须唯一 ,例如 /home/lasahub/AT133_QS_MV_safety_Check/backend_at133

为什么? Docker Compose 会使用当前目录名作为"项目名",如果两个项目目录都叫 backend,它们的容器名、网络名就会冲突,导致一个项目启动时意外破坏另一个项目的容器。

✅ 正确:/home/user/project_a_backend/home/user/project_b_backend

❌ 错误:/home/user/backend(多个项目都用这个目录名会互相干扰)

2.2 本地源码准备

将你的后端项目文件夹从 Windows 复制到 WSL 用户目录下(例如 \\wsl.localhost\Ubuntu-22.04\home\xjm)。

复制后务必删除 venv.idea 等非必要文件夹,避免影响镜像构建速度和体积。


3. 场景一:首次完整部署(后端 + 数据库 + 缓存等所有服务)

3.1 本地 WSL:构建全部镜像并验证

步骤 1:进入项目目录

bash 复制代码
cd ~/ruoyi-fastapi-backend

(示例:实际目录名可能是 ruoyi-fastapi-backend 或其他,请根据你的项目修改)

步骤 2:构建并启动所有服务

bash 复制代码
docker compose up -d --build

这个命令会读取 docker-compose.yml,根据其中的 build 指令构建后端、MySQL、Redis 等镜像,并以后台模式启动所有容器。

步骤 3:查看容器名称与日志

bash 复制代码
docker ps

输出中 NAMES 列会显示当前运行的容器名,例如 banked-backend-AT133banked-mysql-1 等。

查看后端日志,确认无报错并正常监听端口:

bash 复制代码
docker logs -f banked-backend-AT133

(将容器名替换为你实际看到的名称)

看到类似 "Application startup complete" 或端口监听信息后按 Ctrl+C 退出。

步骤 4:导出所有需要的镜像

先列出本地构建出的镜像:

bash 复制代码
docker images

你会看到类似如下镜像(命名规则为 项目目录名_服务名:latest):

  • ruoyi-fastapi-backend-banked:latest
  • ruoyi-fastapi-backend-mysql:latest
  • ruoyi-fastapi-backend-redis:latest

将所有业务镜像打包成一个压缩文件(文件名随意,这里以 all-images.tar.gz 为例)

bash 复制代码
docker save ruoyi-fastapi-backend-banked:latest \
            ruoyi-fastapi-backend-mysql:latest \
            ruoyi-fastapi-backend-redis:latest \
  | gzip > all-images.tar.gz

请用你实际 docker images 显示的镜像名替换。如果基础服务使用的是官方镜像(如 mysql:8.0)且未自定义,也可不导出,让服务器自行拉取;若服务器无外网,则需提前 docker pull mysql:8.0 后一并导出。

3.2 准备生产环境用的 Compose 文件

基于你自己的 docker-compose.yml,创建 docker-compose.image.yml核心改动

  • 删除所有服务的 build 配置;
  • 为每个服务添加 image,镜像名必须与刚才导出的完全一致。

示例(请根据你的实际服务名、端口、环境变量等修改!)

yaml 复制代码
# docker-compose.image.yml (示例,请按需修改)
version: '3.8'
services:
  banked:
    image: ruoyi-fastapi-backend-banked:latest
    container_name: banked-backend-AT133
    ports:
      - "8000:8000"
    environment:
      - DB_HOST=mysql
      - REDIS_HOST=redis
    depends_on:
      - mysql
      - redis
    restart: unless-stopped

  mysql:
    image: ruoyi-fastapi-backend-mysql:latest
    container_name: banked-mysql-AT133
    environment:
      MYSQL_ROOT_PASSWORD: yourpassword
      MYSQL_DATABASE: yourdb
    volumes:
      - mysql_data:/var/lib/mysql
    restart: unless-stopped

  redis:
    image: ruoyi-fastapi-backend-redis:latest
    container_name: banked-redis-AT133
    restart: unless-stopped

volumes:
  mysql_data:

3.3 上传文件到生产服务器(通过 SSH/SCP)

将压缩包和 docker-compose.image.yml 上传到服务器的唯一项目目录 (例如 /home/lasahub/AT133_QS_MV_safety_Check/backend_at133):

bash 复制代码
scp all-images.tar.gz lasahub@<服务器IP>:/home/lasahub/AT133_QS_MV_safety_Check/backend_at133/
scp docker-compose.image.yml lasahub@<服务器IP>:/home/lasahub/AT133_QS_MV_safety_Check/backend_at133/

3.4 生产服务器:加载镜像并启动所有服务

登录服务器并进入项目目录:

bash 复制代码
cd /home/lasahub/AT133_QS_MV_safety_Check/backend_at133

加载镜像:

bash 复制代码
gunzip -c all-images.tar.gz | sudo docker load

验证镜像是否加载成功:

bash 复制代码
sudo docker images

启动所有服务(注意:这里绝对不要加 --build ,因为 compose 文件里已经全是 image 了):

bash 复制代码
sudo docker compose -f docker-compose.image.yml up -d

检查后端日志,确认服务正常运行:

bash 复制代码
sudo docker ps
sudo docker logs -f banked-backend-AT133

(容器名以实际为准)


4. 场景二:仅更新后端服务(日常发版)

当代码有修改,只需要更新后端时,数据库等其他服务不受任何影响

4.1 本地 WSL:构建新后端镜像并导出

bash 复制代码
cd ~/ruoyi-fastapi-backend

# 只重新构建后端镜像,不重新创建容器(banked 是 docker-compose.yml 中定义的后端服务名)
docker compose up -d --build banked

# 导出新镜像(压缩包名可任意,例如 backend-update.tar.gz)
docker save ruoyi-fastapi-backend-banked:latest | gzip > backend-update.tar.gz

关于服务名 banked

banked 来自于 docker-compose.yml 文件中 services 块下定义的服务名称,例如:

yaml 复制代码
services:
  banked:
    build: .
    ...
  mysql:
    ...

你的项目中服务名可能叫 backendapp 等,请以 docker-compose.yml 中实际定义的名称为准,使用时替换即可。

4.2 上传到服务器

bash 复制代码
scp backend-update.tar.gz lasahub@<服务器IP>:/home/lasahub/AT133_QS_MV_safety_Check/backend_at133/

4.3 生产服务器:替换后端容器(一键完成)

bash 复制代码
cd /home/lasahub/AT133_QS_MV_safety_Check/backend_at133

# 加载新镜像
gunzip -c backend-update.tar.gz | sudo docker load

# 强制重建后端容器(自动停止旧容器、创建新容器)
sudo docker compose -f docker-compose.image.yml up -d --force-recreate banked

# 查看日志确认
sudo docker logs -f banked-backend-AT133

解释--force-recreate 参数会强制 Compose 重新创建容器,即使配置看起来没变。因为我们刚导入了新的 latest 镜像,这样就能确保新容器使用最新版本,且无需手动执行 docker stop/rm


5. 总结流程图

首次完整部署流程

#mermaid-svg-SNS5Cr95zFAdleT6{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-SNS5Cr95zFAdleT6 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-SNS5Cr95zFAdleT6 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-SNS5Cr95zFAdleT6 .error-icon{fill:#552222;}#mermaid-svg-SNS5Cr95zFAdleT6 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-SNS5Cr95zFAdleT6 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-SNS5Cr95zFAdleT6 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-SNS5Cr95zFAdleT6 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-SNS5Cr95zFAdleT6 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-SNS5Cr95zFAdleT6 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-SNS5Cr95zFAdleT6 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-SNS5Cr95zFAdleT6 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-SNS5Cr95zFAdleT6 .marker.cross{stroke:#333333;}#mermaid-svg-SNS5Cr95zFAdleT6 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-SNS5Cr95zFAdleT6 p{margin:0;}#mermaid-svg-SNS5Cr95zFAdleT6 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-SNS5Cr95zFAdleT6 .cluster-label text{fill:#333;}#mermaid-svg-SNS5Cr95zFAdleT6 .cluster-label span{color:#333;}#mermaid-svg-SNS5Cr95zFAdleT6 .cluster-label span p{background-color:transparent;}#mermaid-svg-SNS5Cr95zFAdleT6 .label text,#mermaid-svg-SNS5Cr95zFAdleT6 span{fill:#333;color:#333;}#mermaid-svg-SNS5Cr95zFAdleT6 .node rect,#mermaid-svg-SNS5Cr95zFAdleT6 .node circle,#mermaid-svg-SNS5Cr95zFAdleT6 .node ellipse,#mermaid-svg-SNS5Cr95zFAdleT6 .node polygon,#mermaid-svg-SNS5Cr95zFAdleT6 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-SNS5Cr95zFAdleT6 .rough-node .label text,#mermaid-svg-SNS5Cr95zFAdleT6 .node .label text,#mermaid-svg-SNS5Cr95zFAdleT6 .image-shape .label,#mermaid-svg-SNS5Cr95zFAdleT6 .icon-shape .label{text-anchor:middle;}#mermaid-svg-SNS5Cr95zFAdleT6 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-SNS5Cr95zFAdleT6 .rough-node .label,#mermaid-svg-SNS5Cr95zFAdleT6 .node .label,#mermaid-svg-SNS5Cr95zFAdleT6 .image-shape .label,#mermaid-svg-SNS5Cr95zFAdleT6 .icon-shape .label{text-align:center;}#mermaid-svg-SNS5Cr95zFAdleT6 .node.clickable{cursor:pointer;}#mermaid-svg-SNS5Cr95zFAdleT6 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-SNS5Cr95zFAdleT6 .arrowheadPath{fill:#333333;}#mermaid-svg-SNS5Cr95zFAdleT6 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-SNS5Cr95zFAdleT6 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-SNS5Cr95zFAdleT6 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-SNS5Cr95zFAdleT6 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-SNS5Cr95zFAdleT6 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-SNS5Cr95zFAdleT6 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-SNS5Cr95zFAdleT6 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-SNS5Cr95zFAdleT6 .cluster text{fill:#333;}#mermaid-svg-SNS5Cr95zFAdleT6 .cluster span{color:#333;}#mermaid-svg-SNS5Cr95zFAdleT6 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-SNS5Cr95zFAdleT6 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-SNS5Cr95zFAdleT6 rect.text{fill:none;stroke-width:0;}#mermaid-svg-SNS5Cr95zFAdleT6 .icon-shape,#mermaid-svg-SNS5Cr95zFAdleT6 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-SNS5Cr95zFAdleT6 .icon-shape p,#mermaid-svg-SNS5Cr95zFAdleT6 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-SNS5Cr95zFAdleT6 .icon-shape .label rect,#mermaid-svg-SNS5Cr95zFAdleT6 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-SNS5Cr95zFAdleT6 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-SNS5Cr95zFAdleT6 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-SNS5Cr95zFAdleT6 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 复制源码到 WSL

删除 venv/.idea
进入项目目录
docker compose up -d --build
docker ps 查看容器名
docker logs -f 确认启动
docker images 查看镜像名
docker save 打包所有镜像
编写 docker-compose.image.yml

去掉 build,只用 image
scp 上传压缩包和 compose 文件
服务器解压加载镜像
docker compose -f docker-compose.image.yml up -d
查看日志验证部署

仅更新后端流程

#mermaid-svg-RbQXG2lETsJsuQCW{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-RbQXG2lETsJsuQCW .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-RbQXG2lETsJsuQCW .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-RbQXG2lETsJsuQCW .error-icon{fill:#552222;}#mermaid-svg-RbQXG2lETsJsuQCW .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-RbQXG2lETsJsuQCW .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-RbQXG2lETsJsuQCW .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-RbQXG2lETsJsuQCW .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-RbQXG2lETsJsuQCW .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-RbQXG2lETsJsuQCW .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-RbQXG2lETsJsuQCW .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-RbQXG2lETsJsuQCW .marker{fill:#333333;stroke:#333333;}#mermaid-svg-RbQXG2lETsJsuQCW .marker.cross{stroke:#333333;}#mermaid-svg-RbQXG2lETsJsuQCW svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-RbQXG2lETsJsuQCW p{margin:0;}#mermaid-svg-RbQXG2lETsJsuQCW .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-RbQXG2lETsJsuQCW .cluster-label text{fill:#333;}#mermaid-svg-RbQXG2lETsJsuQCW .cluster-label span{color:#333;}#mermaid-svg-RbQXG2lETsJsuQCW .cluster-label span p{background-color:transparent;}#mermaid-svg-RbQXG2lETsJsuQCW .label text,#mermaid-svg-RbQXG2lETsJsuQCW span{fill:#333;color:#333;}#mermaid-svg-RbQXG2lETsJsuQCW .node rect,#mermaid-svg-RbQXG2lETsJsuQCW .node circle,#mermaid-svg-RbQXG2lETsJsuQCW .node ellipse,#mermaid-svg-RbQXG2lETsJsuQCW .node polygon,#mermaid-svg-RbQXG2lETsJsuQCW .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-RbQXG2lETsJsuQCW .rough-node .label text,#mermaid-svg-RbQXG2lETsJsuQCW .node .label text,#mermaid-svg-RbQXG2lETsJsuQCW .image-shape .label,#mermaid-svg-RbQXG2lETsJsuQCW .icon-shape .label{text-anchor:middle;}#mermaid-svg-RbQXG2lETsJsuQCW .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-RbQXG2lETsJsuQCW .rough-node .label,#mermaid-svg-RbQXG2lETsJsuQCW .node .label,#mermaid-svg-RbQXG2lETsJsuQCW .image-shape .label,#mermaid-svg-RbQXG2lETsJsuQCW .icon-shape .label{text-align:center;}#mermaid-svg-RbQXG2lETsJsuQCW .node.clickable{cursor:pointer;}#mermaid-svg-RbQXG2lETsJsuQCW .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-RbQXG2lETsJsuQCW .arrowheadPath{fill:#333333;}#mermaid-svg-RbQXG2lETsJsuQCW .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-RbQXG2lETsJsuQCW .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-RbQXG2lETsJsuQCW .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-RbQXG2lETsJsuQCW .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-RbQXG2lETsJsuQCW .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-RbQXG2lETsJsuQCW .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-RbQXG2lETsJsuQCW .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-RbQXG2lETsJsuQCW .cluster text{fill:#333;}#mermaid-svg-RbQXG2lETsJsuQCW .cluster span{color:#333;}#mermaid-svg-RbQXG2lETsJsuQCW div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-RbQXG2lETsJsuQCW .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-RbQXG2lETsJsuQCW rect.text{fill:none;stroke-width:0;}#mermaid-svg-RbQXG2lETsJsuQCW .icon-shape,#mermaid-svg-RbQXG2lETsJsuQCW .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-RbQXG2lETsJsuQCW .icon-shape p,#mermaid-svg-RbQXG2lETsJsuQCW .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-RbQXG2lETsJsuQCW .icon-shape .label rect,#mermaid-svg-RbQXG2lETsJsuQCW .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-RbQXG2lETsJsuQCW .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-RbQXG2lETsJsuQCW .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-RbQXG2lETsJsuQCW :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 修改代码
cd 项目目录
docker compose up -d --build banked
docker save 导出后端镜像
scp 上传到服务器
服务器加载新镜像
docker compose -f docker-compose.image.yml up -d --force-recreate banked
查看日志确认


遵循以上步骤,任何新手都能安全、规范地完成 Docker 部署。如有疑问,请参照各项目实际配置调整 compose 文件中的镜像名和服务名。

相关推荐
我命由我123451 小时前
Excel - Excel 覆盖模式与编辑模式
运维·学习·职场和发展·excel·求职招聘·职场发展·运维开发
H_老邪1 小时前
Docker 学习之路-Linux安装指定版本docker
学习·docker·容器
c++之路1 小时前
Linux 下 C++ 开发环境搭建
linux·运维·c++
小猫咪011 小时前
Linux 定时任务 crontab 详解:让脚本每天自动执行
linux·运维·服务器
jcbut1 小时前
在Linux 7.9上安装NetBackup IT Analytics (ITA) 11.2
linux·运维·netbackup·it analytics·ita
Geoking.1 小时前
SSH 一断 Node 服务就挂?排查与解决方案记录
运维·node.js·ssh
武器大师722 小时前
实战踩坑:Gerrit HTTP 克隆失败解决方案
运维·nginx·gerrit
IT策士2 小时前
第 40 篇 k8s之Helm:编写自定义 Helm Chart
云原生·容器·kubernetes
kaka❷❷2 小时前
Linux 内核、.ko、.so 与 SDK 镜像打包
linux·运维·服务器