Gitea+Jenkins+Docker 搭建 Node 项目 CI/CD 自动部署完整教程

Gitea+Jenkins+Docker 搭建 Node 项目 CI/CD 自动部署完整教程

介绍:

CI : Continuous Integration,持续集成。频繁把多个人写的代码合并到同一个仓库,自动做校验;仓库收到代码提交,自动执行:拉代码 → 安装依赖 → 单元测试 → 构建镜像。

CD : Continuous Deployment,持续部署.CI 做完构建出镜像之后,自动部署到服务器,启动容器,对外提供服务 ;部署容器,自动停止旧容器、删除旧容器、启动新版本容器.
总结:CI:代码提交 → 自动构建 + 自动测试(验证代码能不能用)

CD:测试通过 → 自动打包部署上线(把新版本服务跑起来)

整体架构

开发者 push 代码

↓

Gitea 仓库(代码托管)

↓ Webhook 推送

Jenkins(CI/CD 流水线调度)

├─ 1. 拉取代码

├─ 2. 构建 Docker 镜像

├─ 3. 推送镜像到 Harbor(或本地保留)

└─ 4. SSH 登录部署服务器 / 本机 docker-compose 部署

↓

目标服务器(运行容器)

↓

访问 http://服务器IP:3001

前置条件

Docker:Dokcer部署及使用

Gitea:Gitea部署及使用

Jenkins:Jenkins部署及使用

把4个文件上传到Gitea仓库根目录

  1. .dockerignore
bash 复制代码
node_modules
.git
  1. app.js
bash 复制代码
const express = require('express');
const app = express();
const port = 3000;
// 版本号,后续改这里即可
const version = "v1.2";

app.get('/', (req, res) => {
  // 返回HTML页面
  res.send(`
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>CI/CD 演示页面</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
            font-family: "Microsoft Yahei", sans-serif;
        }
        body {
            background-color: #f0f4f8;
            display: flex;
            align-items: center;
            justify-content: center;
            height: 100vh;
        }
        .card {
            background: #ffffff;
            padding: 40px 60px;
            border-radius: 16px;
            box-shadow: 0 8px 24px rgba(0,0,0,0.1);
            text-align: center;
        }
        .title {
            font-size: 32px;
            color: #2c3e50;
            margin-bottom: 16px;
        }
        .version {
            font-size: 20px;
            color: #3498db;
            font-weight: bold;
        }
        .tip {
            margin-top: 24px;
            font-size:14px;
            color:#7f8c8d;
        }
    </style>
</head>
<body>
    <div class="card">
        <div class="title">Hello CI/CD!</div>
        <div class="version">当前版本:${version}</div>
        <div class="tip">✅ Jenkins + Gitea 自动发布流水线测试成功</div>
    </div>
</body>
</html>
  `);
});

app.listen(port, '0.0.0.0', () => {
  console.log(`服务启动成功,监听端口 ${port}`);
});
  1. Dockerfile
bash 复制代码
FROM node:18-alpine
WORKDIR /app
COPY package*.json ./
RUN npm install --production
COPY . .
EXPOSE 3000
CMD ["node", "app.js"]
  1. Jenkinsfile
bash 复制代码
pipeline {
    agent any
    stages {
        stage('拉取代码') {
            steps {
                checkout scm
            }
        }
        stage('单元测试') {
            steps {
                sh '''
                docker run --rm -v $PWD:/app -w /app node:18-alpine sh -c "npm install && npm run test"
                '''
            }
        }
        stage('构建镜像') {
            steps {
                sh "docker build -t demo-app:${BUILD_NUMBER} ."
            }
        }
        stage('部署容器') {
            steps {
                sh """
                docker stop demo-app || true
                docker rm demo-app || true
                docker run -d --name demo-app -p 3001:3000 demo-app:${BUILD_NUMBER}
                sleep 3
                docker ps | grep demo-app
                """
            }
        }
    }
    post {
        always {
            echo "流水线执行完成,构建号:${BUILD_NUMBER}"
        }
        success {
            echo "✅ CI/CD发布成功!访问地址:http://192.168.88.132:3001"
        }
        failure {
            echo "❌ 流水线失败,请查看日志排查问题"
        }
    }
}
  1. package.json
bash 复制代码
{
  "name": "cicd-demo",
  "version": "1.0.0",
  "dependencies": {
    "express": "^4.18.2"
  },
  "scripts": {
    "start": "node app.js",
    "test": "echo \"单元测试通过\""
  }
}

确认Jenkins前置条件

Jenkins容器必须挂载docker.sock

  1. 先停掉旧 jenkins,重新启动(带 docker 挂载)
bash 复制代码
# 停止并删除旧jenkins容器
docker stop jenkins
docker rm jenkins
  1. 重新启动 jenkins 容器,增加挂载 -v /var/run/docker.sock:/var/run/docker.sock
bash 复制代码
docker run -d \
   --name jenkins \
   -p 8080:8080 \
   -p 50000:50000 \
   -v /var/jenkins_home:/var/jenkins_home \
   -v /var/run/docker.sock:/var/run/docker.sock \
   -u root \
   jenkins/jenkins:lts-jdk17
  1. 进入 Jenkins 容器,安装 docker 客户端(只装客户端,不装完整 docker 引擎)
bash 复制代码
# 进入jenkins容器
docker exec -it jenkins bash

# 容器内执行安装docker客户端
apt update
apt install -y docker.io

# 退出容器
exit
  1. 虚拟机防火墙放开3001端口
bash 复制代码
# centos/rhel 执行
firewall-cmd --add-port=3001/tcp --permanent
firewall-cmd --reload

在虚拟机里面查看容器是否正常启动,能看到名字叫 demo-app 的容器就代表部署成功。

在虚拟机终端执行 curl,直接在服务器内部访问,可输出html内容,则访问成功:

bash 复制代码
curl http://127.0.0.1:3001

Jenkins 安装插件

进入 Manage Jenkins → Plugins → Available plugins,搜索并安装:

插件名 作用
Pipeline 流水线核心(通常默认已装)
Git Git 拉取代码
Docker Pipeline 在流水线中构建/管理 Docker 镜像
Gitea Gitea 插件,支持 Webhook 触发
Credentials Plugin 凭证管理(通常默认已装)

安装完成后重启 Jenkins。

【注】:如果安装时提示「Plugin is missing: workflow-api」之类的依赖缺失,点红色提示旁边的 「纠正」 按钮,Jenkins 会自动补全依赖。

配置 Jenkins 凭证

如果 Gitea 仓库是私有的,需要配置凭证(公开仓库可以跳过这一步):

点击链接进入找到【凭证配置】

凭证配置教程

创建Jenkins流水线任务

创建流水线

流水线配置

获取Gitea仓库的http格式的url地址:

里面的Gitea仓库的url:

脚本路径这的文件名:Jenkinsfile

触发器配置

手动测试构建:

构建成功:

自动触发构建

Gitea Webhook配置

目标url格式:Jenkins访问地址/job/gitea_pipeline/build?token=jenkins触发器配置的token

jenkins的访问地址:

jenkins触发器配置的token:

钩子名称:随便取

其他选项默认,点击【添加钩子】

测试push自动构建:

修改Gitea仓库里的app.js的版本号信息为v1.3,并提交

查看jenkins任务里是否进行自动构建,先刷新页面

滑到最下面:

访问该项目地址:

CI/CD到此结束ヾ(•ω•`)o

相关推荐
你看我名字39 分钟前
LAMP 架构演练:从云主机准备到 Apache、PHP、MySQL 上线验证
运维·ci/cd·架构·kubernetes·jenkins
Flynn Liang1 小时前
5分钟跑通MQTT:EMQX Docker部署+MQTTX联调(2026最新版,含踩坑)
物联网·mqtt·docker·iot·emqx
成为你的宁宁2 小时前
【基于 SSH 与 JNLP 协议的 Jenkins 分布式构建方案】
分布式·jenkins
撞强3 小时前
手搓标讯系统实战——win11/CherryStudio/Icompify/剑鱼标讯/Gitea
gitea·手搓·cherrystudio·标讯
木雷坞3 小时前
Docker Compose端口映射排查:用port和inspect定位网页访问失败
运维·docker·容器
码间留白15 小时前
手把手把 GitHub 推上阿里云 ECS:Actions CI/CD 全链路避坑实录(折腾好几天,到 2 分钟见绿)
运维·阿里云·ci/cd·docker·devops·github actions
Vex2une15 小时前
Docker Desktop WSL2后端:2026年性能调优与避坑实战指南
windows·docker·desktop·gpu容器·容器开发·virtiofs·buildkit
程序员老赵16 小时前
Docker 部署青龙面板:轻松搭建定时任务管理平台
前端·docker·开源
TTATTC16 小时前
为什么单会话聊天做不好复杂工程?Claude Code 创作者的并发 Worktree 与记忆闭环实践
docker·开源
TTATTC16 小时前
状态机驱动长事务,还是 DAG 编排高并发?高可靠业务流程引擎的双核架构设计
docker·开源