手把手教你部署前端项目CI/CD Jenkins 篇

1 Jenkins

Jenkins是一个开源的自动化服务器,用于支持软件开发中的持续集成与持续部署(CI/CD)。它是一个自由及开源的自动化工具,提供了友好的操作界面,允许开发团队自动化地执行各种任务,如代码构建、测试、部署等。Jenkins由Java语言编写,可在Tomcat等流行的servlet容器中运行,也可独立运行。

前置知识:

1.1 Jenkins 核心概念

  • 开源性:Jenkins是一个开放源代码软件,任何人都可以查看其源代码、进行修改和贡献。这使得Jenkins能够免费提供,并确保其长期的发展和维护。
  • 持续集成与持续部署:Jenkins为开发团队提供了一个平台,使其能够自动化地执行构建、测试和部署等任务。这种自动化使得开发流程更为流畅,可以快速地发现和修复问题,从而加快软件的发布速度。
  • 丰富的插件生态系统:Jenkins拥有一个强大的插件生态系统,涵盖了从源代码管理、构建、测试到部署的各个环节。这些插件允许用户根据特定需求定制Jenkins,以满足不同的自动化需求。
  • 跨平台支持:Jenkins可以在Windows、Linux和Mac OS等操作系统上运行,具有很强的跨平台支持能力。

1.2 Jenkins 优点

  1. 提高开发效率:
    • Jenkins 自动化了构建、测试和部署等任务,减少了人工操作的时间和错误,使开发团队能够更专注于编写高质量的代码。
    • 自动化流程缩短了反馈周期,使问题能够更快地被发现和修复。
  2. 增强软件质量:
    • 持续的集成和测试有助于在早期发现并修复问题,避免问题累积到后期造成更大的影响。
    • Jenkins 支持多种测试框架,可以执行单元测试、集成测试等多种类型的测试,确保软件的全面质量。
  3. 支持快速迭代:
    • Jenkins 使得软件发布过程更加高效和灵活,支持频繁的发布和迭代,满足现代软件开发快速变化的需求。
    • 自动化部署减少了人为错误,提高了部署的可靠性和稳定性。
  4. 易于配置和扩展:
    • Jenkins 提供了丰富的插件生态系统,用户可以根据需要选择和安装各种插件来扩展其功能。
    • 通过简单的配置和脚本编写,用户可以轻松定义自己的构建和部署流程。
  5. 社区支持和文档丰富:
    • Jenkins 是一个开源项目,拥有庞大的用户社区和活跃的开发者贡献者,用户可以获得及时的技术支持和解决方案。
    • Jenkins 的官方文档和社区资源也非常丰富,有助于用户快速上手和解决问题。
  6. 跨平台支持:
    • Jenkins 可以在多种操作系统上运行,包括Linux、Windows和Mac OS等,提供了良好的跨平台支持能力。



2 Jenkins 安装

2.1 前置准备工作

安装docker 请移步 手把手教你部署前端项目CI/CD Docker 篇

2.1.1 git 安装

# enter 到底
yum install -y git
# 查看git版本号 验证git安装成功
# git version 1.8.3.1
git --version

2.1.2 配置SSH

# Enter到底,最终会生成以下文件
# /root/.ssh/authorized_keys 允许无密码登录的公钥列表
# /root/.ssh/id_rsa 私钥文件
# /root/.ssh/id_rsa.pub 公钥文件  注意该文件里的内容是接下来要用的
ssh-keygen -t rsa -C "root"
# 复制公钥文件的内容,添加到GitHub 的 SSH keys 或 任意其他远程仓库
vim /root/.ssh/id_rsa.pub

2.1.3 远程仓库添加 SSH keys

(以github为例)

  1. 点击用户头像,进入 settings 页面
  2. 点击左侧菜单,进入 SSH and GPG keys
  3. 点击 new SSH keys
  4. title => <你的ip SSH keys> 仅为示例命名
  5. key type => 默认选择Authentication Keys
  6. keys => 黏贴上面公钥文件里的内容到这边,保存完成。

2.1.4 服务器拉取项目

# root 目录新建 home文件夹
sudu mkdir /root/home
# 进入 home 文件夹
cd /root/home
# 免登录拉取前端项目源码,注意服务器首次拉取github会提示确认指纹,点击确定。
# 指纹一般存于 ~/.ssh/known_hosts
git clone https://github.com/wanglei1900/React18_Vite4_Admin.git

2.2 安装 nginx 和 jenkins 镜像

docker 拉取镜像

# 拉取nginx
docker pull nginx
# 拉取jenkins
docker pull jenkins/jenkins:lts
# 查看镜像是否安装成功
docker images
# REPOSITORY        TAG       IMAGE ID       CREATED         SIZE
# nginx             latest    fffffc90d343   2 weeks ago     188MB
# jenkins/jenkins   lts       5dea1f4edf69   3 weeks ago     470MB
# hello-world       latest    d2c94e258dcb   14 months ago   13.3kB

创建docker 相关目录

# 创建docker的相关目录
mkdir -p /docker/{compose,jenkins_home,nginx/conf,html/origin}

# 创建docker-compose.yml配置文件
cd /docker/compose
# 具体配置内容见下面
touch docker-compose.yml

# 创建nginx.conf配置文件
cd /docker/nginx/conf
# 具体配置内容见下面
touch nginx.conf

最终文件结构

+ docker
    + compose
        - docker-compose.yml  // docker-compose配置
    + html             // 各环境代码目录(实际项目可能不在同一目录)
				+ origin
						+ master	 // master分支代码,后续会自动创建
						+ dev			 // dev分支代码,后续会自动创建
    + jenkins_home     // Jenkins工程目录
    + nginx            // nginx工程目录
        + conf
            - nginx.conf  // nginx配置

nginx.conf配置

# nginx.conf
user  nginx;
worker_processes  1;

error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;


events {
    worker_connections  1024;
}


http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    sendfile        on;
    #tcp_nopush     on;

    keepalive_timeout  65;

    gzip  on;

		#这里两个环境使用一个nginx.conf文件,也可以单独分开来
    #pro环境
    server {
        #监听的端口
        listen  8001;
        server_name  localhost;
        #设置日志
#        access_log  logs/dev.access.log  main;

        #定位到index.html
           location / {
               #linux下HTML文件夹,就是你的前端项目文件夹
               root  /usr/share/nginx/html/origin/master/dist;
#               root  /home/html/dev/dist;
               #输入网址(server_name:port)后,默认的访问页面
               index  index.html;
               try_files $uri $uri/ /index.html;
           }
    }

    #dev环境
    server {
        #监听的端口
        listen  8002;
        server_name  localhost;
        #设置日志
#        access_log  logs/sit.access.log  main;

        #定位到index.html
           location / {
               #linux下HTML文件夹,就是你的前端项目文件夹
               root  /usr/share/nginx/html/origin/dev/dist;
#               root  /home/html/dev/dist;
               #输入网址(server_name:port)后,默认的访问页面
               index  index.html;
               try_files $uri $uri/ /index.html;
           }
    }


#    include /etc/nginx/conf.d/*.conf;


}

docker-compose.yml配置

8080:对应jenkins 容器
8001:对应master环境 容器
8002:对应dev环境 容器

  • docker_jenkins 是一个定义的服务名称。
  • user: root 指定了 Jenkins 容器使用 root 权限。
  • restart: always 表示容器总是在退出时重启。
  • image: jenkins/jenkins:lts 指定了 Jenkins 镜像及其版本。
  • container_name: jenkins 是容器的名称。
  • ports 定义了容器内外端口的映射。
  • volumes 定义了主机文件系统路径与容器内路径的挂载关系。
  • image: nginx指定了 Nginx 镜像。
  • container_name: nginx_dev 是容器的名称。
# 新版docker-compose不用写自动引用最新版本
# version: '3'

networks:
  frontend:
    external: true

services:                                      # 容器

  docker_jenkins:
    user: root                                 # root权限
    restart: always                            # 重启方式
    image: jenkins/jenkins:lts                 # 使用的镜像
    container_name: jenkins                    # 容器名称
    environment:
      - TZ=Asia/Shanghai
      - "JENKINS_OPTS=--prefix=/jenkins_home" ## 自定义 jenkins 访问前缀(上下文context)
    ports:                                     # 对外暴露的端口定义
      - 8080:8080
      - 50000:50000
    volumes:                                   # 卷挂载路径
      - /docker/jenkins_home/:/var/jenkins_home     # 挂载到容器内的jenkins_home目录
      - /usr/local/bin/docker-compose:/usr/local/bin/docker-compose

  docker_nginx_pro:                            # nginx-pro环境
    restart: always
    image: nginx
    container_name: nginx_pro
    ports:
      - 8001:8001
    volumes:
      - /docker/nginx/conf/nginx.conf:/etc/nginx/nginx.conf
      - /docker/html:/usr/share/nginx/html  	 # 宿主机/docker/html 映射docker容器内的/usr/share/nginx/html
      - /docker/nginx/logs:/var/log/nginx

  docker_nginx_dev:                            # nginx-dev环境
    restart: always
    image: nginx
    container_name: nginx_dev
    ports:
      - 8002:8002
    volumes:
      - /docker/nginx/conf/nginx.conf:/etc/nginx/nginx.conf
      - /docker/html:/usr/share/nginx/html 		 # 宿主机/docker/html 映射docker容器内的/usr/share/nginx/html
      - /docker/nginx/logs:/var/log/nginx

2.3 启动docker

# 启动docker
systemctl start docker
# 启动docker-compose
# 这里我们使用docker-compose.yml配置文件启动,所以不需要另外手动创建容器里,这也是为什么使用docker-compose.yml配置文件的原因
cd /docker/compose/
docker-compose up -d

# 输出以下内容
# WARN[0000] /docker/compose/docker-compose.yml: `version` is obsolete
# NAME        IMAGE                 COMMAND                   SERVICE            CREATED          STATUS          PORTS
# jenkins     jenkins/jenkins:lts   "/usr/bin/tini -- /u…"   docker_jenkins     16 seconds ago   Up 15 seconds   0.0.0.0:8080->8080/tcp, :::8080->8080/tcp, 0.0.0.0:50000->50000/tcp, :::50000->50000/tcp
# nginx_pro   nginx                 "/docker-entrypoint.…"   docker_nginx_pro   16 seconds ago   Up 15 seconds   80/tcp, 0.0.0.0:8001->8001/tcp, :::8001->8001/tcp
# nginx_dev   nginx                 "/docker-entrypoint.…"   docker_nginx_dev   16 seconds ago   Up 15 seconds   80/tcp, 0.0.0.0:8002->8002/tcp, :::8002->8002/tcp

2.4 检查nginx配置

测试nginx配置是否正确

# 目录下创建index.html文件
cd /docker/html/dev/dist
# 黏贴下面的html内容
vim index.html
<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <h1>welcome to Nginx</h1>
  </body>
</html>

浏览器打开 ip:8001 可以看到welcome to Nginx 页面,证明nginx配置正确。

2.5 登录jenkins web端

  1. 登录 服务器地址:8080/jenkins_home 进入jenkins 的web端
  2. 去服务器上 vim /docker/jenkins_home/secrets/initialAdminPassword 复制初始密码
  3. 回到jenkins 的web端,输入初始密码。
  4. 登录后,安装推荐的插件(不要选择自定义插件)。
  5. 注册管理员账号完成登录



3 Jenkins 配置

第一遍操作,建议完全照抄。后面再遇到在自己拓展

3.1 安装必要插件

dashbord => Manage Jenkins(系统管理) => plugin(插件) => Available plugins

  1. local (如果界面是全英文还需要安装中文插件,如果已经有部分中文请跳过这个插件)
  2. Publish Over SSH 配置远程服务器
  3. NodeJS 服务端打包
  4. Git Parameter 参数化构建


3.2 Publish Over SSH 配置远程服务器

dashbord => Manage Jenkins(系统管理) => 系统配置 => ctrl F Publish over SSH

  1. 找到SSH Servers 并新增
  2. 填写 name 自定义填写名称(示例:jenkins_node)
  3. 填写 Hostname 服务器ip地址
  4. 填写 Username 服务器登录名称
  5. 填写 Remote Directory 登录后访问的地址
  6. 点击 高级 弹出额外配置
  7. 勾选 Use password authentication, or use a different key。
  8. 出现 Passphrase / Password,输入服务器登录密码
  9. 检查默认port 是否为22 。一般不用修改
  10. 点击 Test Configuration,显示success则 jenkins 配置SSH远程服务器成功
  11. 点击 应用按钮 点击 保存按钮



3.3 NodeJS配置

dashbord => Manage Jenkins(系统管理) => 全局工具配置 => ctrl F NodeJS 安装

  1. 新增 NodeJS
  2. 填写 别名 自定义填写名称,照抄下面的版本号(示例:NodeJS 22.4.1)
  3. 选择 NodeJS版本,之前已经下载好插件,这里应该自动跳出来的
  4. 点击 应用按钮 点击 保存按钮



3.4 凭据配置

dashbord => Manage Jenkins(系统管理) => 凭据管理 => 全局 按钮下拉选择 添加凭据

此处以添加github仓库为例

  1. 填写 用户名 github用户名
  2. 填写 密码 github密码
  3. 填写 描述 github 登录凭证
  4. 点击 创建 按钮



3.5 创建任务

dashbord => 点击屏幕中间 create a job

  1. 名称填写 你的项目名字(示例:React_PC)
  2. 点击 构建一个自由风格的软件项目
  3. 点击 确定按钮
  4. 点击 github项目 填写项目URL
  5. 源码管理 勾选git
  6. 填写 Repository URL 这里用github仓库的http地址
  7. Credentials 选择之前配置的凭证
  8. 指定分支暂时填写 */dev
  9. 点击 应用按钮 点击 保存按钮
  10. 点击立即构建按钮




3.6 Github webHooks 配置

github代码仓库 => Settings => Webhooks

  1. 填写 Payload URL http://ip:8080/jenkins_home/github-webhook/
  2. 选择 Content type application/json
  3. 点击 add webbhook 按钮

jenjins => dashbord => 点击之前创建的项目 => 配置

  1. 点击 构建触发器
  2. 勾选 GitHub hook trigger for GITScm polling




3.7 构建环境

ctrl F 构建环境

  1. 点击 构建环境
  2. 勾选 Provide Node & npm bin/ folder to PATH
  3. 选择 我们刚刚配置过的nodejs版本
  4. 点击 应用按钮

3.8 Build Steps

ctrl F Build Steps

  1. 增加构建步骤
  2. 选择 Execute NodeJS script
  3. 选择 我们刚刚配置过的nodejs版本
  4. 点击 应用、保存按钮
  5. 构建项目测试目前为止步骤是否正确,并学会手动构建流程


3.9 执行sell

dashbord => 点击之前创建的项目 => 配置 => ctrl F Build Steps

  1. 增加构建步骤
  2. 选择 执行shell
  3. 填写下面bash指令
  4. 点击 应用、保存按钮
  5. 构建项目测试,控制台输出应该能看到打印nodejs版本和npm 版本
#!/bin/bash
echo "Node.js 版本:"  node -v
echo "npm 版本:"  npm -v
echo $PATH


dashbord => 点击之前创建的项目 => 配置 => ctrl F 执行sell

  1. 填写下面bash指令
  2. 点击 应用、保存按钮
  3. 构建项目测试,控制台输出应该能看到依赖安装成功和打包成功字样
  4. ls /docker/html/origin/dev/dist/ 应该还能查看到dist文件夹下的前端打包项目
  5. 上面步骤成功后,远程仓库dev分支push一次测试提交,jenkins会触发自动构建
  6. 如果没有自动构建成功,可能是网络问题。先去github查看该webhook触发了没有,再去jenkins web端 Github Hook log选项查看推送日志
#!/bin/bash

# 查看信息
echo "Node.js 版本:"  node -v
echo "npm 版本:"  npm -v

# 安装依赖
npm install || { echo "npm install 失败"; exit 1; }
echo "依赖安装成功"

# 打包构建
rm -rf ./dist  # 清理旧的 dist 目录
# 这里是用你项目里的打包脚本,比如你的可能是npm run build
npm run build:jenkins || { echo "构建失败"; exit 1; }
echo "构建成功"

3.10 自动部署到对应环境

dashbord => 点击之前创建的项目 => 配置 => ctrl F 执行sell

  1. 填写下面bash指令
  2. 点击应用按钮
#!/bin/bash

# 查看信息
echo "当前打包项目 Github 仓库分支:"
echo "GIT_BRANCH" $GIT_BRANCH

echo "Node.js 版本:"  node -v
echo "npm 版本:"  npm -v

# 安装依赖
npm install || { echo "npm install 失败"; exit 1; }
echo "依赖安装成功"

# 打包构建
rm -rf ./dist  # 清理旧的 dist 目录
# 这里是用你项目里的打包脚本,比如你的可能是npm run build
npm run build:jenkins || { echo "构建失败"; exit 1; }
echo "构建成功"

if [ ! -d "./dist" ]; then
    echo "构建未生成 dist 目录"
    exit 1
fi

echo "开始打包..."
rm -rf dist.tar     # 每次构建删除已存在的dist压缩包
tar -zcvf dist.tar ./dist  # 将dist文件压缩成dist.tar
if [ $? -eq 0 ]; then
    echo "打包成功"
else
    echo "打包失败"
    exit 1
fi

echo "构建和打包完成"
echo $PATH

这里先明确一点,本次部署到宿主机的环境地址,为什么路径写成这样,是为了后续参数化构建的时候,可以动态获取分支名,然后根据分支名动态部署到对应环境。
生产环境 master分支部署到 /docker/html/origin/master/dist/
开发环境 dev分支部署到 /docker/html/origin/dev/dist/

  1. 增加构建步骤
  2. 选择 Send files or execute commands over SSH
  3. 填写 服务名称Name 为 jenkins_node
  4. 填写 源文件Source 为 files dist.tar
  5. 填写 目标路径Remote directory 为 /dokcer/html/origin/dev
  6. 填写 执行脚本Exec command 如下
cd /docker/html/dev
rm  -rf   dist/
tar zxvf dist.tar
rm dist.tar

让我们捋一捋以上步骤做了哪些事情?
正式生产 宿主机和docker大概率不是部署在一台服务器上的,这里我们自己学习使用了一台服务器

  1. 删除docker容器内,之前打包的dist下所有文件
  2. docker容器内,打包本次源文件为dist.tar
  3. 连接到宿主机(远程服务器),放在/docker/html/origin/dev文件价下
  4. 解压缩dist.tar,并且删除压缩包
  • Source files:准备发送的文件,该文件是相对于这个项目的workspace目录。例如要发送/docker/jenkins_home/workspace/gitlab_web/dist.- tar到目标目录,则设置Source files为dist.tar
  • Remove prefix:目标文件前缀添加,例如要操作src下面的某个文件,就设置成src,本案例是跟目录,无需设置
  • Remote directory:目标目录,本案例要复制到dev环境下的dist文件,/docker/html/dev
  • Exec command:最后执行的命令,可在这里进行解压,删除,复制等操作

到这里,访问你的项目地址 localhost:8082 就可以看到你打包好的前端项目了

3.11 参数化构建

前面我们都是手动构建dev分支,现在我们使用参数化构建,可以动态获取分支名,然后根据分支名动态部署到对应环境

dashbord => 点击之前创建的项目 => 配置 => ctrl F 参数化构建过程

  1. 添加参数,选择GIT参数
  2. 填写 名称 为 BRANCH
  3. 填写 描述 为 生产环境 origin/master 开发环境 origin/dev
  4. 填写 默认值 为 origin/dev

ctrl F Branches to build

  1. 填写 指定分支 由之前的 origin/dev 变成 $BRANCH

ctrl F Transfer Set

  1. 填写 Remote directory 由之前的 /docker/html/origin/dev 变成 /docker/html/${GIT_BRANCH}
  2. 填写 Exec command 如下
cd /docker/html/${GIT_BRANCH}
rm  -rf   dist/
tar zxvf dist.tar
rm dist.tar

这里需要强调几点

  1. 由于我们本次jenkins构建使用的自由风格,相对pipeline(流水线)的方式没有那么灵活,比如webhook推送不同分支,如果不使用参数化构建则必须写死分支名,使用了参数化构建也只能使用默认值,本次是origin/dev即dev分支
  2. 为什么前面项目的路径要用origin/*,因为构建分支是动态获取当前仓库的分支的,默认是带origin前缀的
  3. 目前配置能达到的效果是dev分支会可以根据webhook自动推送到jenkins触发自动更新,master主分支则需要手动触发更新。
posted @ 2024-07-20 23:10  wanglei1900  阅读(16)  评论(0编辑  收藏  举报