前端工程化:保姆级教学 Jenkins 部署前端项目

DevOps

提到 Jenkins,想到的第一个概念就是 CI/CD 在这之前应该再了解一个概念。

DevOpsDevelopment和Operations的组合,是一种方法论,并不特指某种技术或者工具。DevOps 是一种重视Dev开发人员和Ops运维人员之间沟通、协作的流程。通过自动化的软件交付,使软件的构建,测试,发布更加的快捷、稳定、可靠。

CI

CI 的英文名称是Continuous Integration,中文翻译为:持续集成

试想软件在开发过程中,需要不断的提交,合并进行单元测试和发布测试版本等等,这一过程是痛苦的。持续集成CI是在源代码变更后自动检测、拉取、构建的过程。

图片[1]-前端工程化:保姆级教学 Jenkins 部署前端项目-JieYingAI捷鹰AI

CD

CD 对应两个概念 持续交付Continuous Delivery持续部署Continuous Deployment

持续交付

提交交付顾名思义是要拿出点东西的。在 CI 的自动化流程阶段后,运维团队可以快速、轻松地将应用部署到生产环境中或发布给最终使用的用户。

从前端的角度考虑,在某些情况下肯定是不能直接通过自动化的方式将最终的 build 结果直接扔到生产机的。持续交互就是可持续性交付供生产使用的的最终 build。最后通过运维或者后端小伙伴进行部署。

图片[2]-前端工程化:保姆级教学 Jenkins 部署前端项目-JieYingAI捷鹰AI

持续部署

作为持续交付的延伸,持续部署可以自动将应用发布到生产环境。

图片[3]-前端工程化:保姆级教学 Jenkins 部署前端项目-JieYingAI捷鹰AI

Jenkins 安装

示例服务器为 阿里云 CentOS 服务器。安全组中增加 8080 端口 Jenkins 默认占用

Jenkins 安装大体分两种方式,一种使用 Docker 另一种则是直接安装,示例选择后者。不管使用哪种方式安装,最终使用层面都是一样的。Linux 安装[1],Docker 安装[2]

查看Linux安装过程

# 下载 Jenkins 资源
sudo wget -O /etc/yum.repos.d/jenkins.repo https://pkg.jenkins.io/redhat/jenkins.repo
# 获取并导入信任 的包制作者的秘钥
sudo rpm --import https://pkg.jenkins.io/redhat/jenkins.io.key
# 升级 yum 源中的所有包
sudo yum upgrade
# Jenkins 依赖于 java 所以需要安装 JDK
sudo yum install java-11-openjdk
# 安装 Jenkins
sudo yum install jenkins

如果最终Jenkins没有找到包而导致没有安装成功,检查第一步和第二部执行结果并重新执行。

可以使用systemctl命令管理 Jenkins 服务systemctl[3]

# 启动 Jenkins 服务
systemctl start jenkins
# 重启 Jenkins 服务
systemctl restart jenkins
# 停止 Jenkins 服务
systemctl stop jenkins
# 查看 Jenkins 服务状态
systemctl status jenkins

启动服务后访问服务器地址 + 8080 端口,Jenkins 默认为 8080 端口。

Jenkins 使用及 Freestyle 任务构建

图片[4]-前端工程化:保姆级教学 Jenkins 部署前端项目-JieYingAI捷鹰AI

首次进入使用cat /var/lib/jenkins/secrets/initialAdminPassword查看密码。

随后进入插件安装页面,暂时安装系统推荐插件即可。

然后创建用户

图片[5]-前端工程化:保姆级教学 Jenkins 部署前端项目-JieYingAI捷鹰AI

构建目标:拉取 github 代码

点击新建 Item创建一个Freestyle Project

图片[6]-前端工程化:保姆级教学 Jenkins 部署前端项目-JieYingAI捷鹰AI

在源码管理处选择 git ,输入仓库地址,点击添加。

图片[7]-前端工程化:保姆级教学 Jenkins 部署前端项目-JieYingAI捷鹰AI

输入 github 账号和密码,这里的密码有时候可能会出现问题,可以使用tokengithub 如何生成 token ?[4]

配置只是一方面,同时服务器也要具备 git 环境。yum install git

图片[8]-前端工程化:保姆级教学 Jenkins 部署前端项目-JieYingAI捷鹰AI

构建目标:部署到本机

部署前端项目肯定是离不开nginx的。yum install nginx。

安装完成后同样可以使用systemctl命令管理nginx服务。

nginx具体配置这里就不说了。本示例项目中,静态文件托管目录为/usr/share/nginx/html/dist。

接着来到Jenkins这里。想要部署前端项目还需要依赖一个Node环境,需要在Manage Jenkins -> Manage Plugins在可选插件中搜索nodejs选择对应插件进行安装,安装完成后需要重启才会生效。

图片[9]-前端工程化:保姆级教学 Jenkins 部署前端项目-JieYingAI捷鹰AI

然后到系统管理 -> 全局工具配置中配置Node(吐槽:没有安装任何插件时系统管理以及其子页面全是英文,安装完插件后又变成了中文。这国际化不知道是系统原因还是它的原因 )。

图片[10]-前端工程化:保姆级教学 Jenkins 部署前端项目-JieYingAI捷鹰AI

随后去修改刚才创建的任务。在构建环境中会多出一个选项Provide Node & npm bin/ folder to PATH勾选即可。然后在构建中选择增加构建步骤 -> 执行 shell输入打包发布相关的命令。Jenkins会逐行执行。

npm install yarn -g
yarn install
yarn build
# 打包 build 后的文件
tar -zcvf dist.tar.gz dist/
# 删除 build 后的文件
rm -rf dist/
# 移动 build 后的压缩包到 nginx 托管目录下。
sudo mv dist.tar.gz /usr/share/nginx/html
# 进入托管目录下
cd /usr/share/nginx/html
# 解压
sudo tar -zxcf dist.tar.gz
# 删除压缩包
sudo rm -rf dist.tar.gz

We trust you have received the usual lecture from the local System
Administrator. It usually boils down to these three things:

    #1) Respect the privacy of others.
    #2) Think before you type.
    #3) With great power comes great responsibility.

解决方案:在/etc/sudoers文件中增加jenkins ALL=(ALL) NOPASSWD:ALL表示在执行 sudo 时不需要输入密码。

xxxxxxx: Permission denied

解决方案:修改/lib/systemed/system/jenkins.service文件。将User=jenkins修改为User=root,表示给Jenkins赋权限。修改配置文件后记得重启服务。

ERROR: Error fetching remote repo 'origin'

解决方案:由于需要构建的代码在github上面,这种错误表示拉取代码失败了,重试几次就可以了。

工作目录

上面提到一个很重要的概念就是工作目录在上面的shell默认就是在这里执行的。工作目录是由两部分组成。

总结:Jenkins的执行目录是/var/lib/jenkins/workspace/web-deploy。也就是说输入的每一条命令都是在这里面执行的。(搞清楚定位能避免好多问题,特别是前端的部署,就是打包,移动,解压很容易搞错路径。)

构建目标:侦听 git 提交到指定分支进行构建

图片[11]-前端工程化:保姆级教学 Jenkins 部署前端项目-JieYingAI捷鹰AI

图片[12]-前端工程化:保姆级教学 Jenkins 部署前端项目-JieYingAI捷鹰AI

由于在上面的源码管理中已经指定了main分支,此时如果这个分支的代码有改动就会触发自动构建。

构建目标:部署到目标主机

在真实的开发场景中,Jenkins几乎不会和前端资源放到一个服务器。大多数情况下Jenkins所处的服务器环境就是一个工具用的服务器,放置了一些公司中常用的工具。因此构建到指定的服务器也至关重要。

1,系统管理 -> 插件管理搜索Publish Over SSH进行安装。

图片[13]-前端工程化:保姆级教学 Jenkins 部署前端项目-JieYingAI捷鹰AI

2,然后在系统管理 -> 系统配置中找到Publish over SSH点击新增,再点击高级,然后选中Use password authentication, or use a different key

图片[14]-前端工程化:保姆级教学 Jenkins 部署前端项目-JieYingAI捷鹰AI

完成后可点击右下角Test Confirguration进行测试。

3,继续修改构建任务。先修改原有的构建脚本。因为要发布到远程,所以原有的发布命令要进行去除。

npm install yarn -g
yarn install
yarn build
# 只打包,然后删除文件夹。
tar -zcvf dist.tar.gz dist/
rm -rf dist/

4,选择构建后操作 -> Send build artifacts over SSH

图片[15]-前端工程化:保姆级教学 Jenkins 部署前端项目-JieYingAI捷鹰AI

执行成功后查看执行日志会有类似以下结果:

SSH: Connecting from host [iZuf6dwyzch3wm3imzxgqfZ]
SSH: Connecting with configuration [aliyun-dev] ...
SSH: EXEC: completed after 202 ms
SSH: Disconnecting configuration [aliyun-dev] ...
# 如果 Transferred 0 file 则需要查看配置的路径是否正确。表示文件并没有被移动到远程主机中。
SSH: Transferred 1 file(s)
Finished: SUCCESS

构建目标:钉钉机器人通知

1,系统管理 -> 插件管理搜索DingTalk进行安装。文档[5]

图片[16]-前端工程化:保姆级教学 Jenkins 部署前端项目-JieYingAI捷鹰AI

2,钉钉群创建机器人。钉钉群 -> 只能群助手 -> 添加机器人 -> 自定义

图片[17]-前端工程化:保姆级教学 Jenkins 部署前端项目-JieYingAI捷鹰AI

3,定义机器人名字和关键字,创建完成后先将webhook中的内容复制。

图片[18]-前端工程化:保姆级教学 Jenkins 部署前端项目-JieYingAI捷鹰AI

4,Jenkins中系统管理 -> 系统配置 -> 钉钉 -> 新增配置完成后可点击右下角进行测试。

图片[19]-前端工程化:保姆级教学 Jenkins 部署前端项目-JieYingAI捷鹰AI

5,修改构建任务配置。

图片[20]-前端工程化:保姆级教学 Jenkins 部署前端项目-JieYingAI捷鹰AI

6,构建成功

图片[21]-前端工程化:保姆级教学 Jenkins 部署前端项目-JieYingAI捷鹰AI

Pipline 构建

上一章节中着重介绍了如何构建freestyle的任务,但是Jenkins远不止于此。在本章开始之前强烈建议阅读文档[7],重点关注流水线相关内容。

新建任务 -> 选择流水线其他内容可以都不用管,只关注流水线有两种选择,演示就选择第一种。

直接在Jenkins中书写配置。

图片[22]-前端工程化:保姆级教学 Jenkins 部署前端项目-JieYingAI捷鹰AI

在项目的Jenkinsfile配置文件中写配置。

图片[23]-前端工程化:保姆级教学 Jenkins 部署前端项目-JieYingAI捷鹰AI

在正式开始之前应该了解Jenkins Pipline的基础概念。

pipeline {
    agent any // 在任何可用的代理上,执行流水线或它的任何阶段。
    stages {
        stage('Build') { // 定义 "Build" 阶段。
            steps {
                // 执行与 "Build" 阶段相关的步骤。
            }
        }
        stage('Deploy') { // 定义 "Deploy" 阶段。
            steps {
                // 执行与 "Deploy" 阶段相关的步骤。
            }
        }
    }
}

了解到这里还是不够的。流水线入门[8]流水线语法参考[9]

Pipline 复刻 Freestyle

这里先直接把配置贴出来。后续结合内容在进行分析。

点击查看完整配置

// 自定义 钉钉插件 的 错误信息和成功信息
def successText = [
    """ ### 新的构建信息,请注意查收""",
    """ ${env.JOB_BASE_NAME}任务构建成功 ,点击查看[构建任务 #${env.BUILD_NUMBER}](http://106.14.185.47:8080/job/${env.JOB_BASE_NAME}/${env.BUILD_NUMBER}/)"""
]
def failureText = [
    """ ### 新的构建信息,请注意查收""",
    """ ${env.JOB_BASE_NAME}任务构建失败 ,点击查看[构建任务 #${env.BUILD_NUMBER}](http://106.14.185.47:8080/job/${env.JOB_BASE_NAME}/${env.BUILD_NUMBER}/)"""
]
// 1,侦听 github push 事件
properties([pipelineTriggers([githubPush()])])

pipeline {
    agent any
    // 环境变量定义。
    environment {
        GIT_REPO = 'http://github.com/vue-ts-vite-temp.git'
    }
    stages {
        // 2,拉取 github 代码,通过 GitSCM 侦听 push 事件。
        stage('Pull code') {
            steps {
                checkout(
                    [
                        $class: 'GitSCM',
                        branches: [[name: '*/main']],
                        extensions: [],
                        userRemoteConfigs: [
                            [
                                credentialsId: '381325e4-0f9c-41ea-b5f6-02f8ea2a475a',
                                urlenv.GIT_REPO
                            ]
                        ],
                        changelogtrue,
                        polltrue,
                    ]
                )
            }
        }
        stage('Install and build') 
{
            steps {
                // 3,前面安装过的 nodejs 插件使用
                nodejs('v14.19.0') {
                    sh 'npm install yarn -g'
                    sh 'yarn install'
                    sh 'yarn build'
                }
            }
        }
        stage('Pack') {
            steps {
                sh 'tar -zcvf dist.tar.gz dist/'
                sh 'rm -rf dist/'
            }
        }
        stage('Deploy') {
            steps {
                // 4,前面下载的 Publish Over SSH 插件的使用
                sshPublisher(
                    publishers: [
                        sshPublisherDesc(
                            configName: 'aliyun-dev',
                            transfers: [
                                sshTransfer(
                                    cleanRemote: false,
                                    excludes'',
                                    execCommand'''
                                        cd /usr/share/nginx/html/
                                        tar -zxvf dist.tar.gz
                                        rm -rf dist.tar.gz
                                    '
'',
                                    execTimeout120000,
                                    flattenfalse,
                                    makeEmptyDirsfalse,
                                    noDefaultExcludesfalse,
                                    patternSeparator'[, ]+',
                                    remoteDirectory'/usr/share/nginx/html/',
                                    remoteDirectorySDFfalse,
                                    removePrefix'',
                                    sourceFiles'dist.tar.gz'
                                )
                            ],
                            usePromotionTimestampfalse,
                            useWorkspaceInPromotionfalse,
                            verbosefalse
                        )
                    ]
                )
            }
        }
    }
    post {
        success {
            // 5,DingTalk 插件的使用。
            dingtalk (
                robot: '1314',
                type'ACTION_CARD',
                title'Jenkins构建提醒',
                text: successText,
                btns: [
                    [
                        title: '控制台',
                        actionUrl'http://106.14.185.11:8080/'
                    ],
                    [
                        title: '项目预览',
                        actionUrl'http://github.com/'
                    ],
                ],
                at: []
            )
        }
        failure {
            dingtalk(
                robot: '1314',
                type'ACTION_CARD',
                title'Jenkins构建提醒',
                text: failureText,
                btns: [
                    [
                        title: '控制台',
                        actionUrl'http://106.14.185.11:8080/'
                    ],
                    [
                        title: '项目预览',
                        actionUrl'http://github.com/'
                    ],
                ],
                at: []// 这里是手机号多个之间,隔开
            )
        }
    }
}

这么多内容手写无疑是很难受的,好在Jenkins提供了一些帮助工具。访问地址为:Jenkins地址 +/job+ 当前任务 +/pipeline-syntax/,例如::8080/job/dev-deploy/pipeline-syntax/,或者进入任务构建页面,点击流水线语法进入

图片[24]-前端工程化:保姆级教学 Jenkins 部署前端项目-JieYingAI捷鹰AI

进入该页面后请熟读并背诵以下三项。重点放到第一项。

图片[25]-前端工程化:保姆级教学 Jenkins 部署前端项目-JieYingAI捷鹰AI

回头看上面的脚本注释都带有序号。根据注释序号开始解释。

1,在片段生成器中选择properties: Set job properties生成代码片段。由于只是使用了git hook trigger所以要对生成的片段稍作修改。

图片[26]-前端工程化:保姆级教学 Jenkins 部署前端项目-JieYingAI捷鹰AI

2,如果不是为了侦听github push选择git: Git即可,但现在应该选择checkout: Check out from version control,随后填写信息生成代码即可。

图片[27]-前端工程化:保姆级教学 Jenkins 部署前端项目-JieYingAI捷鹰AI

3,选择nodejs: Provide Node & npm bin/folder to Path

图片[28]-前端工程化:保姆级教学 Jenkins 部署前端项目-JieYingAI捷鹰AI

4,选择sshPublisher: Send build artifacts over SSH,像上面流水线一样配置之后直接生成代码即可。

图片[29]-前端工程化:保姆级教学 Jenkins 部署前端项目-JieYingAI捷鹰AI

5,DingTalk文档

总结:通过插件生成的代码,稍作组合就成为了完整的配置。但整体难度还是要略高于Freestyle任务。毕竟生成的代码有部分也不是拿来即用的,并且Pipline 基本语法一定要有所掌握。不然生成的代码都不晓得放到哪里合适。

参考资料

[1]

Linux 安装:

[2]

Docker 安装:

[3]

systemctl:

[4]

github 如何生成 token ?:#creating-a-token

[5]

文档:

[6]

实现默认@执行人:

[7]

阅读文档:

[8]

流水线入门:

[9]

流水线语法参考:

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享