docker +jenkins使用pipeline方式发布vue项目到远程服务器

关于后端部署,可以参考:https://blog.iwiki.ink/archives/dockerjenkins%E4%BD%BF%E7%94%A8pipeline%E6%96%B9%E5%BC%8F%E5%8F%91%E5%B8%83springboot%E9%A1%B9%E7%9B%AE%E5%88%B0%E8%BF%9C%E7%A8%8B%E6%9C%8D%E5%8A%A1%E5%99%A8

1.前期准备

安装必要的jenkins插件:

  • NodeJS plugin : vue项目打包必须插件,安装后才能在系统设置里面配置安装nodejs环境
  • Pipeline : jenkins初始化的时候会默认安装
  • Publish Over SSH : 因为我们要发往远程服务器,所以要装,如果本地docker运行项目,则不需要这个插件
  • Blue Ocean : 蓝海了,UI插件,选装,安装后访问地址:【jenkins地址】/blue

2.配置jenkins

2.1 安装nodejs环境

进入Manage Jenkins -> Configure Tools找到 NodeJS(安装了NodeJS plugin插件才有这项)

NodeJS主要配置如下:

别名:自定义,这个很重要,后面配置pipeline文件时需要
选择 Install from nodejs.org,实测下载速度也还可以接受
版本自己选择需要的版本

2.2 配置SSH

进入Manage Jenkins -> Configure System找到 Publish over SSH(安装了Publish Over 	SSH插件才有这项)

SSH Servers主要配置如下:

SSH Server Name: ssh配置名称(自定义)记住这个名称,pipeline代码中要用到
Hostname: 主机IP
Username: ssh账户名
Remote Directory: 远程路径,可以理解为ssh连接上后自动cd到目录
port: ssh端口,一般默认为22
Proxy password: ssh密码

⚠️ 注意

我这里使用的是在docker中运行jenkins,如果宿主机有maven环境直接配置到jenkins里面肯定用不了,需要用docker的数据卷 -v 挂载到jenkins里面才可以访问。

3.新建Item

3.1 进入jenkins主界面新建Item

  • 这里简略直接新建构建功能,实际情况下可能要新建文件夹来对项目进行分类

3.2 选择流水线(Pipeline)

3.3 General配置

  • 选择丢弃旧的构建(最好配置一下,防止占机器磁盘)
策略: Log Rotation
保持构建的天数: 不设置
保持构建的最大个数: 视情况设置

流水线(Pipeline)配置

  • 定义:选择 Pipeline script 或者 Pipeline script from SCM

Pipeline script: 需要在jenkins里面写pipeline脚本
Pipeline script from SCM: 需要在项目一级目录下新建 Jenkinsfile 文件,再将pipeline脚本写在里面,这种方式相较于上面那种方式,需要多如下配置:
勾选 Pipeline script from SCM 后,配置

SCM: 选择git
Repository URL: 代码仓库地址
Credentials: git账户密码密钥的ID,在Manage Jenkins->Manage Credentials里面可以找到,没有的话,就新增一个
Branches to build: 选择代码分支
脚本路径: 默认Jenkinsfile,需要跟项目一级目录下的pipeline脚本文件名一样,建议和默认保持一样

# 其他没提到的设置保持默认吧

我这里选择的是 Pipeline script ,因为觉得把拉取代码也集成到pipeline脚本里统一管理好一点,没有割裂感

脚本如下,视情况改一下:

def gitUrl = '【改成你的代码仓库地址】'
// maven的默认安装地址
def project = '【改成你的项目名称】'
def env ='【改成你的项目环境,一般为.xxx.development文件】'
def port = '【改成你的项目端口号】'
def proxy_port = '【改成你的项目映射到docker宿主机的端口号】'
def deploy_home = '【改成你的远程服务器上部署的目录】'
def branch = '【改成你的代码分支】'
// 保存在jenkins凭据中的凭据ID
def credentialsId = '【改成你存在jenkins里面的代码仓库账号密码凭据ID】'
def remoteId = '【改成你的ssh服务器设置ID,对应2.1里面的SSH Server Name】'

pipeline {
    agent any
    stages {
        stage('代码更新'){
            steps {
                git branch: "$branch",credentialsId: "$credentialsId",url: "$gitUrl"
            }
        }
        stage('项目构建'){
            steps {
            	# Nodejs18.8.0即为前面配置的nodejs环境取得别名
                nodejs("Nodejs18.8.0"){
                    sh 'node --version'
                    sh 'npm --version'
                    sh 'npm install'
                    sh 'npm run build:prod'
                }
            }
        }
        stage('生成Dockerfile'){
            steps {
                // 动态生产dockerfile
                sh """
                    echo '''
                        # 基础镜像使用Nginx
                        FROM nginx:latest
                        MAINTAINER xxx
                        ENV TimeZone=Asia/Shanghai    
                        ADD /dist/  /usr/share/nginx/html/
                        EXPOSE 80
                    ''' > Dockerfile
                """
            }
        }
        stage('生成Nginx配置文件'){
            steps {
                // 动态生产Nginx.conf
                sh """
                    echo '''
                        server {
                            listen       80;
                            listen  [::]:80;
                            server_name  宿主机IP;
                            location / {
                                root   /usr/share/nginx/html;
                                index  index.html index.htm;
                            }
                            error_page   500 502 503 504  /50x.html;
                            location = /50x.html {
                                root   /usr/share/nginx/html;
                            }
                        }
                    ''' > default.conf
                """
            }
        }
        stage('生成deploy.sh'){
            steps {
                // 动态生产dockerfile
                sh """
                    echo '''
                        #!/bin/bash
                        #项目占用端口
                        APP_PORT=$port
                        APP_PROXY=$proxy_port
                        # 项目名字
                        APP_NAME=$project
                        # 项目根目录
                        APP_HOME=$deploy_home/$project
                        # 项目日志输出目录
                        APP_LOG_OUT=$deploy_home/logs
                        # 镜像的tag
                        APP_TAG=1.0
                        mkdir -p \${APP_HOME}
                        mkdir -p \${APP_LOG_OUT}
                        echo "清理已有容器及镜像资源"
                        docker stop \${APP_NAME} && docker rm \${APP_NAME}
                        echo "清理已有容器及镜像资源成功!!!!"
                        echo "镜像制作"
                        docker build -t \${APP_NAME}:\${APP_TAG} .
                        echo "镜像制作完成"
                        echo "开始运行"
                        docker run -d --name \${APP_NAME} -p \${APP_PROXY}:80 -v \${APP_LOG_OUT}:/var/log/nginx -v \${APP_HOME}/default.conf:/etc/nginx/conf.d/default.conf \${APP_NAME}:\${APP_TAG}
                        echo "已成功运行"
                    ''' > deploy.sh
                """
            }
        }
        stage('打包文件'){
            steps{
                sh """
                rm -rf deploys
                mkdir deploys
                ls
                cp -r $project_home  deploys/
                mv Dockerfile deploys/
                mv deploy.sh deploys/
                mv default.conf deploys/
                tar -zcvf deploys.tar.gz deploys/
                rm -rf deploys
                mv deploys.tar.gz $project_home/
                """
            }
        }
        stage('发往远程'){
            steps {
                sshPublisher(publishers: [sshPublisherDesc(configName: """$remoteId""", transfers: [sshTransfer(cleanRemote: false, excludes: '',
                        execCommand: """
                            echo '准备解压发布文件并部署'
                            cd $deploy_home/$project
                            #解压到当前目录,并去除一级目录
                            tar -zxvf deploys.tar.gz --strip-components 1
                            rm -rf deploys.tar.gz
                            sh deploy.sh
                            echo '部署成功'
                        """,
                        execTimeout: 120000,
                        flatten: false,
                        makeEmptyDirs: false,
                        noDefaultExcludes: false,
                        patternSeparator: '[, ]+',
                        remoteDirectory: """/$project""",
                        remoteDirectorySDF: false,
                        removePrefix: """$project_home""",
                        sourceFiles: """$project_home/deploys.tar.gz""")],
                        usePromotionTimestamp: false,
                        useWorkspaceInPromotion: false,
                        verbose: false)])
            }
        }
        stage('删除中间文件'){
            steps {
                sh """
                    cd $project_home
                    rm -rf deploys.tar.gz
                """
            }
        }
    }
    post {
        success {
            println('项目发布成功!')
        }
        failure {
            println('项目发布失败!')
        }
    }
}

如果是Pipeline script from SCM方式,脚本里面省去拉去代码的步骤即可

脚本的核心流程是:

  1. 拉取代码
  2. npm 构建项目
  3. 生成Dockerfile
  4. 生成nginx的default.conf文件,用以替换nginx镜像自带的default.conf文件
  5. 生成deploy.sh
  6. 将Dockerfile,deploy.sh,default.conf和项目build后的文件压缩成压缩包
  7. 将文件发往远程服务器,并在远程服务器解压文件,执行deploy.sh
  8. deploy.sh执行后,会根据Dockerfile将项目包构建成docker镜像,并运行

部署成功后,项目挂载在宿主机的proxy_port端口,映射到镜像的80端口
直接访问

http://[IP]:8081

即可,注意宿主机的防火墙记得开启,防止端口被防火墙拦截

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×