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

相关推荐
AlfredZhao2 小时前
用 Docker 简化部署与版本升级:一份可复用的实践
docker
bloglin9999912 小时前
vmware部署centos7启动docker容器后无法访问服务
运维·docker·容器
smartpi_ai15 小时前
通用脱机烧录器为什么烧不进 CI-03?下载协议的门槛、免唤醒 10 条的建议值属性
服务器·网络·ci/cd
AutumnWind042016 小时前
【Docker Compose 快速入门】
运维·docker·容器
ai小陈19 小时前
GPU服务器租用容器实战:Docker数据卷持久化与安全重建
服务器·人工智能·安全·docker·ai·gpu算力
如果'\'真能转义说19 小时前
Docker Desktop | 本地化挂载 Postgresql
docker·postgresql·容器
谢亮_vipxieliang20 小时前
从 Docker 到 Kubernetes:概念对照与迁移
docker·容器·kubernetes
Java的搬运工20 小时前
【无标题】
python·机器学习·docker·fastapi·模型部署·mlops·ai工程化