本文最后更新于 2025-03-09,文章内容可能已经过时。

自动化部署,就是开发人员,将开发代码推送到远程仓库,通过jenkins配置自动化脚本,从远程仓库进行代码拉取,然后将代码打包,并推送到,部署目录下的一套流程!

在此,需要准备的,一台云服务器(这里用的unbuntu云服务器),其它的准备如下:

  1. nodejs: 在服务器内部可以安装nvm(Node Version Manager)版本控制器,来灵活下载Nodejs!

  2. docker: 需要在服务器内部安装docker,剩下的jenkins以及nginx等都需要在docker中安装!

https://www.bilibili.com/video/BV1LBDYY9EGd?spm_id_from=333.788.videopod.sections&vd_source=eecc2c8229facae905b6daed1650b44b

安装Node

https://blog.ppxiong.top/archives/1741068875859

这里可以选择性的安装NodeJS,因为Jenkins内部插件对Nodejs有了一个支持,可以直接通过Docker来安装Jenkins和Nginx即可!

安装Docker

docker 是一个linux复刻版的虚拟机,可以安装很多应用,我们平时开发部署,通常都是在linux系统下直接安装使用比如(java nginx node)等,这样在小型应用下使用是没有问题的,若是大型应用,若是一个应用程序出现了问题,则会导致linux系统服务整个崩溃,会影响到其它服务的运行,有了docker,且每个应用之间是相互隔离的,保证在一个程序出现问题时,而不会影响到其它应用程序的运行!

首先切换用户到root,避免在操作时,出现不必要的权限问题!

su - root
# or
sudo -i

更新apt索引

apt 和 yum 一样,是一个软件包管理工具,可以帮我们下载安装需要的依赖插件!

sudo apt-get update

安装依赖包

sudo apt-get install apt-transport-https ca-certificates curl software-properties-common -y

添加Docker官方GPG密钥

curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg

添加Docker仓库

echo "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

安装Docker引擎

sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io -y

验证安装

sudo docker --version

设置开机启动

sudo systemctl enable docker && sudo systemctl start docker

设置Docker加速镜像

docker镜像默认是国外的,在国内通过镜像下载包资源会超时问题,所以我们需要配置加速镜像,如阿里云,网易云,腾讯云等!

加速器名称 镜像地址
阿里云 https://<your-accelerator-id>.mirror.aliyuncs.com
网易云 https://hub-mirror.c.163.com
腾讯云 https://mirror.ccs.tencentyun.com
DaoCloud http://f1361db2.m.daocloud.io
华为云 https://mirrors.myhuaweicloud.com/dockerhub

以上是国内比较常用的镜像地址,接下里我们需要配置docker中的daemon.json文件,并重新启动docker即可!

sudo nano /etc/docker/daemon.json

修改一下内容

{
   "registry-mirrors": [
      "https://docker.hpcloud.cloud",
      "https://docker.m.daocloud.io",
      "https://docker.unsee.tech",
      "https://docker.1panel.live",
      "http://mirrors.ustc.edu.cn",
      "https://docker.chenby.cn",
      "http://mirror.azure.cn",
      "https://dockerpull.org",
      "https://dockerhub.icu",
      "https://hub.rat.dev"
    ]
}

重启daemon配置和docker!

systemctl daemon-reload
systemctl restart docker

查看是否配置生效

docker info

在输出中查找Registry Mirrors,确认已列出配置的镜像加速地址

docker info | grep "Registry Mirrors" -A 2

列出以下内容,便配置成功!

Registry Mirrors:
 https://<你的ID>.mirror.aliyuncs.com/
 https://docker.mirrors.ustc.edu.cn/

Docker常用命令

安装Jenkins

使用Docker容器来安装对应的Jenkins!

https://www.jenkins.io/

创建jenkins_home文件夹

下载依赖并启动容器

docker run \
-u root \
-d -p 8080:8080 \
-p 50000:50000 \
-v /var/run/docker.sock:/var/run/docker.sock  \
-v /usr/bin/docker:/usr/bin/docker \
-e TZ=Asia/Shanghai \  # 设置时区
--name jenkins \
jenkins/jenkins:lts

避坑提示,通过Docker安装Jenkins时,需要Jenkins内部脚本提供对docker命令的支持,也就是说,若构建镜像时,需要使用docker build相关命令来执行,则必须保证docker命令需要在Jenkins任务环境下能够使用才行,避免出现 commond not found!

以下命令,

-v /var/run/docker.sock:/var/run/docker.sock  \
-v /usr/bin/docker:/usr/bin/docker \

查看内置密码

需要获取内置密码后,才能继续安装!

因为jenkins通过docker安装,且jenkinsdocker其中的一个容器,我们需要通过进入到容器里才能找到jenkins并获取对应的内置密码!

docker exec -it <容器id> /bin/bash
sudo cat /opt/jenkins_home/secrets/initialAdminPassword

访问Jenkins

# 浏览器打开 http://服务器IP:8080 输入初始密码

/var/jenkins_home/secrets/initialAdminPassword 需要把 /var 改为 /opt

-v /opt/jenkins_home:/var/jenkins_home \ 根据 docker run -d 去安装jenkins目录去定义

登录Jenkins

根据上述,获取密码之后,进行登录初始化,期间会让选择安装插件,此处推荐跳过,否则安装插件还是比较耗时的!

重置密码

Jenkins安装时,在initialAdminPassword文件内有一个内置随机初始密码,我们需要将密码进行重置,避免,下次登录时出现问题!

安装问题

若遇到启动jenkins失败时,根据logs日志情况来查看问题!

docker 启动容器时,提示 Error response from daemon: container d55bb44bb71d85933b62a093d692d0334025b523ff4b001238a387495484499f is not running
  1. 获取未启动的容器ID:

    docker ps -a
    
    • 查看容器的运行状态
    • 获取一行为对应的ImageNamejenkins/jenkins:lts 第一列 CONTAINER ID下的Id
  2. 查看容器的日志,确定容器未启动退出的原因:

    docker logs <容器的ID>
    

    如果日志中显示错误(如依赖缺失、配置文件错误、权限问题等),根据提示修复。 如果日志无报错,可能是容器任务执行完毕后自动退出(如仅运行一个临时脚本

  3. 查看容器的状态:

    `docker ps -a`  # 查看所有容器(包括已退出的)
    `docker inspect <容器ID>`  # 查看容器详细信息
    

    关注 State 字段中的 ExitCode非0值表示异常退出。 检查 Config.CmdConfig.Entrypoint 是否配置了前台持久进程

  4. 经日志查看,发现是目录权限写入有问题:

    docker 安装 Jenkins时 INSTALL WARNING: User: missing rw permissions on JENKINS_HOME: /var/jenkins_home
    

    最后确认,是在下载和运行jenkins时,目录写成了相对路径

      docker run -d \
        --name jenkins \
        -p 8080:8080 \
        -p 50000:50000 \
        -v ./jenkins_home:/var/jenkins_home \
        -v /var/run/docker.sock:/var/run/docker.sock \
      jenkins/jenkins:lts-jdk11
    

    ./jenkins_home 改为 /opt删除容器,重新运行 docker run 命令即可!

  5. 删除容器,重新安装

    docker rm <容器ID或名称>  # 删除容器
    docker run -d \
      --name jenkins \
      -p 8080:8080 \
      -v /opt/jenkins_home:/var/jenkins_home \
      jenkins/jenkins:lts
    

Jenkins使用

安装插件

Jenkins首页左侧菜单栏中,找到系统设置,然后再右侧功能选项中找到Plugins插件管理,在这里可以搜索我们想要安装的插件

需要安装的插件: chinese中文翻译包、其次就是gitee 、git plugins、publish over ssh、nodejs、nvm-wrapper、extensible-choice-parameter!

选中安装插件后,等待安装完成,然后界面会有重启Jenkins等待一会,刷新页面,这时Jenkins的服务已经退出并停掉了,需要手动重新启动

docker ps -a

查看容器的运行状态,并获取 container id

docker start <容器ID> 

重新启动即可!

修改Jenkins下载源

Jenkins本身下载源下载插件会比较慢,可以更换默认下载源,来提升下载插件的速度!

https://updates.jenkins.io/update-center.json

以上链接是Jenkins默认下载源,接下来我们来将它替换掉新的下载源!

https://mirrors.tuna.tsinghua.edu.cn/jenkins/updates/update-center.json

sed -i 's/https:\/\/updates.jenkins.io\/download/https:\/\/mirrors.tuna.tsinghua.edu.cn\/jenkins/g' /root/.jenkins/updates/default.json && sed -i 's/http:\/\/www.google.com/https:\/\/www.baidu.com/g' /root/.jenkins/updates/default.json

也可以通过命令的方式设置镜像源

在页面上导入插件

https://mirrors.tuna.tsinghua.edu.cn/jenkins/plugins/

/manage/pluginManager/advanced 在这个地址页面上,去选择本地插件安装,需要是以.hpi为后缀的文件,可以在以上地址,找到对应的插件下载到本地,进行选择安装!

在服务器上进行插件迁移

下载插件到服务器上,然后将插件移动到 /opt/jenkins_home/plugins/ 即可!

配置gitee

需要再gitee生成令牌

生成令牌

个人设置->安全设置->私人令牌 -> 生成令牌

配置Jenkins 添加凭证

添加gitee令牌

Jenkins首页 -> 系统设置 -> 凭据管理 -> 点击全局

在右侧蓝色按钮点击添加凭据 add credentials

添加gitee用户

用于创建Jenkins Job 任务时,选择git,需要选择 gitee 用户来认证!

系统管理 -> 凭证管理 -> 添加凭证

这次类型选择 username & password

Jenkins集成Nvm

nvm 是一个 node 版本控制器,可以灵活切换node版本jenkins集成nvm插件,可以在插件列表里搜索nvm-wrapper安装即可,随后在新建 Jenkins Job 任务时,勾选nvm选项,并且选择对应的node版本即可!

https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.1/install.sh

以上是nvm下载地址

Jenkins任务执行

创建任务

在首页左侧菜单下,选择新建任务,进入新建任务界面!

进入任务配置

丢弃旧的构建

丢弃旧的构建,可以配置每次构建新的时候,将之前的构建进行清除操作,可配置旧的构建保存天数,以及清除的个数!

可选保存天数5天清除其中5个构建项目!

参数化构建过程

参数化构建过程,可以添加参数,以便在构建时,动态选择性的去构建,例如git分支包含(master、dev、test),不可能每次去构建的时候,都需要手动去改默认分支吧,通过Extensible Choice 插件,将分支选项配置好后,我们可以在构建之前选择性去构建对应的分支!

需要安装的插件Extensible Choice Parameter plugin ,可以在插件管理搜索此插件并安装!

源码管理

源码管理,就是配置我们项目的一个git仓库地址,以及git仓库认证授权信息!

环境配置

用于配置代码构建方式,例如nodenpm文件路径,以及nvm的相关配置,nvm需要插件支持nvm-wrapper, 这里我选择了以nvm的方式来管理node版本 ,如果你不考虑内网的情况下,可以使用!

当然,我们这里需要把NVM安装位置URL改一下,默认的是github地址,可能会下载失败!

https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.1/install.sh

可以改成如上地址!

这里我们只需要,选择输入NodeJS版本,以及修改NVM_URL安装路径即可,其它会默认生成!

构建步骤

构建步骤,就是在执行构建时,以什么样的方式去选择构建,例如输入nodejs脚本,以及shell脚本等相关命令!

#!/bin/bash
echo "============安装依赖============="
npm install --registry="https://registry.npmmirror.com/"
echo "============安装完成============="
echo "============打包构建============="
npm run build
echo "============构建完成============="
echo "============开始推送============="
#! cp -r ./dist/* /usr/share/nginx/html
echo "============发布完成============="

流水线任务

流水线任务,就是通过本地代码根目录创建Jenkinsfile脚本文件,将构建步骤通过脚本的形式来描述!

https://gitee.com/liguangtao_home/course/tree/master/jenkins

通过此链接,可以获取pipeline脚本具体构建过程的写法!

import java.text.SimpleDateFormat
pipeline {
    agent any

    options {
        timestamps()
    }
    parameters {
        choice(name: 'Run',choices: ['build', 'copy', ],description: '部署类型 (copy:直接复制上次部署的文件, build:重新构建)')
        booleanParam(name: 'Base', defaultValue: true, description: '部署基础模块')
        booleanParam(name: 'Install', defaultValue: false, description: '下载新的依赖')
        choice(name: 'Env',choices: ['dev', 'test', ],description: '部署环境')
    }
    stages {
        stage('构建基础模块代码') {
            when { expression { return params.Base } }
            steps {
                echo "=========================构建基础模块代码========================="
                script{
                    if ("${params.Run}" == "copy") {
                        echo "copy"
                    }else{
                        echo "Build"
                        if("${params.Install}" == "true") {
                        	sh "rm -rf node_modules"
                        	sh "npm install --registry=https://registry.npmmirror.com"
                        }
                        sh "rm -rf dist"
                        sh "npm run build:${params.Env}"
                        sh "cp -r ./dist/* /usr/share/nginx/html"
                    }
                }
            }
        }
        stage('构建镜像') {
            steps {
                echo "=========================构建镜像========================="
                //script{
                    //sh "docker build -t 127.0.0.1:8082/base-system/nginx:dev -f ./Dockerfile ."
                //}
            }
        }
        stage('推送镜像') {
            steps {
                echo "=========================推送镜像========================="
                //script{
                    //sh "docker login https://127.0.0.1:8082 -u admin -p QWEasd123"
                    //sh "docker push 127.0.0.1:8082/base-system/nginx:${params.Env}"
                //}
            }
        }

        stage(" dev环境部署"){
            when { expression { return params.Env == "dev" } }
            steps {
                echo "部署dev镜像"
           }
        }

        stage(" test环境部署"){
            when { expression { return params.Base == "test" } }
            steps {
                echo "部署test镜像"
            }
        }
    }
}

安装Nginx

我们通过docker来安装Nginx web服务器,来部署我们前端打包的静态资源文件!

拉取镜像

docker pull nginx:latest

运行Nginx容器

后台启动nginx容器名为my-nginx80端口可访问!

docker run -d --name my-nginx -p 80:80 nginx:latest
  • -d: 后台运行容器

  • --name my-nginx: 为容器命名(可自定义)。

  • -p 80:80: 将宿主机80端口映射到容器的80端口

验证是否运行成功

浏览器打开 http://ip,看到 "Welcome to nginx!" 即表示成功

进入docker容器

docker 容器像是linux的一个复刻版的虚拟机,类似于linux的目录,进入到容器后,我们所安装的应用都在虚拟机内!

docker exec -it my-nginx /bin/bash

my-nginxnginx容器名称

Dockerfile构建镜像

Dockerfile是一个用于定义构建 Docker 镜像文本文件。它包含了一系列指令Instructions),这些指令会按照顺序执行,最终生成一个可重复、可移植的 Docker 镜像镜像可以看作是一个轻量级的“模板”,用于快速创建容器

Dockerfile的核心作用

  1. 自动化构建镜像:通过编写 Dockerfile,你可以精确控制镜像的构建过程(例如安装软件、配置环境、复制文件等)。

  2. 版本化管理Dockerfile可以和代码一起存入版本控制系统(如 Git),方便追踪镜像的变更历史

  3. 标准化环境确保开发、测试、生产环境的一致性,避免“在我机器上能运行”的问题。

Dockerfile 的核心指令

指令 作用
FROM 指定基础镜像(例如 FROM ubuntu:20.04FROM nginx:latest)。
RUN 镜像构建过程中执行命令(如安装软件包、修改文件)。
COPY / ADD 将本地文件复制到镜像中(例如复制代码或配置文件)。
WORKDIRs 设置后续指令的工作目录(相当于 cd 命令)。
EXPOSE 声明容器运行时监听的端口(例如 EXPOSE 80)。
ENV 设置环境变量(例如 ENV NODE_ENV=production)。
CMD / ENTRYPOINT 指定容器启动时运行的默认命令(例如启动服务)。
VOLUME 定义挂载点(用于持久化数据)。

Dockerfile基础使用

  1. 在主机~/根目录中创建两个文件:

    • Dockerfile:

      FROM nginx:latest
      # COPY demo.nginx.conf /etc/nginx/conf.d/
      COPY dist /usr/share/nginx/html
      CMD ["nginx", "-g", "daemon:off;"]
      
    • index.html

      <html>
         <head>
             <meta charset="utf-8">
             <title>docker file</title>
         </head>
         <body>
             <center>docker file test html!</center>
         </body>
      </html>
      

      修改 COPY dist /usr/share/nginx/htmldist 替换掉 ./index.html

       COPY ./index.html /usr/share/nginx/html
      
  2. 生成Docker镜像

docker build -t demo:dev -f ./Dockerfile .
  • demo:dev demo为镜像的名称,而dev则为镜像的tag标签!

  • 查看镜像是否创建成功!

    docker images
    

    结果如下,会生成 demo:dev的一个镜像!

    root@VM-24-5-ubuntu:~# docker images
    REPOSITORY        TAG       IMAGE ID       CREATED          SIZE
    demo              dev       c4f118fb5b07   10 minutes ago   192MB
    nginx             latest    b52e0b094bc0   4 weeks ago      192MB
    jenkins/jenkins   lts       82a2134e1742   4 weeks ago      468MB
    
  1. 启动创建好的镜像

    docker run -d -p 9003:80 --name demo-dev demo:dev
    
    • demo-dev启动镜像后的一个name,这个name可以随便写!
    • demo:dev 则是你要在docker images镜像列表中选择启动的镜像名称,这个是在生成镜像的时候就定义好的!
  2. 查看镜像的运行状态:

    docker ps -a
    
  3. 在地址栏中输入 ip:9003 端口,便可看到创建的index.html文件已经部署到nginx/html中!

Dockerfile在项目中使用

需要前端项目中的目录下创建Dockerfile文件,以nginx.conf配置文件

Dockerfile 文件内容如下

dockerfile 负责通过指令来创建出一个服务镜像,如下拉取nginx服务,可将本地拉取的项目中根据nginx.conf配置文件复制nginx/conf.d/ 配置文件夹内!

FROM nginx:latest
# 复制nginx配置文件到nginx的conf目录下
COPY nginx.conf /etc/nginx/conf.d/default.conf
# 复制打包后的dist文件夹到nginx的html目录下
COPY dist /usr/share/nginx/html/front-system/
# 启动nginx服务(容器主进程)
CMD ["nginx", "-g", "daemon off;"] 

nginx.conf 配置文件内容如下

# 仅保留server配置块(删除所有全局配置)
server {
  listen 9003;
  server_name localhost;

  location /front-system/ {
    root /usr/share/nginx/html;
    try_files $uri $uri/ /front-system/index.html;
    index index.html index.htm;
  }

  error_page 500 502 503 504 /50x.html;
  location = /50x.html {
    root /usr/share/nginx/html;
  }
}

需要注意的是,这里的nginx.conf配置文件, 是作为子模块配置文件 使用,如果文件内部,配置了http 以及全局的一些相关配置,比如events,或者user等,作为配置文件,存放在conf.d/目录下,会与主配置文件有冲突,而导致不必要的错误!

nginx: [emerg] "user" directive is not allowed here in /etc/nginx/conf.d/nginx.conf

例如以上问题,问题原因说明:

1. 原配置全局参数user/worker_processes等)写入conf.d子配置文件

2. Nginx主配已包含全局参数conf.d目录下的文只能包含http/server级别配置

3. 通过拆分配置文件保留主配置的默认参数,自定义配置仅包含server块

jenkins添加任务

这里只描述下,构建的步骤和脚本,其它相关配置,可以查看当前文章目录下的jenkins任务执行,里面包含了相关配置操作!

项目构建

包含 npm 镜像地址设置,以及 install 依赖安装,打包构建等相关脚本!

#!/bin/bash
echo "============npm 版本============="
node -v
npm -v
echo "============npm set config============="
npm config set registry https://registry.npmmirror.com/
npm config list
echo "============安装 依赖============="
# 优先使用本地缓存
npm install --prefer-offline'
echo "============安装 完成============="
echo "============打包 构建============="
npm run ${Env}
echo "============构建 结束============="
# echo "============开始 推送============="
# cp -r ./dist/* /usr/share/nginx/html
# echo "============发布完成============="

这里 npm install 依赖安装,平时如果没有新的依赖要更新的话,只需要安装一次即可,不需要每次构建时都要去安装依赖!

  1. 根据情况,判定是否新增依赖,来手动去配置 npm install 此次是否安装,若不需要,则注释即可!

  2. 可以参数的形式增加一个boolean 布尔值,需要安装时,勾选即可,不需要安装时取消勾选即可,该参数可在shell脚本中使用!

pipeline {
    agent any
    parameters {
        booleanParam(name: 'SKIP_NPM_INSTALL', defaultValue: false, description: '是否跳过 npm install?')
    }
    stages {
        stage('Install Dependencies') {
            when {
                expression { return !params.SKIP_NPM_INSTALL }
            }
            steps {
                sh 'npm install'
            }
        }
        stage('Build') {
            steps {
                sh 'npm run build'
            }
        }
    }
}
镜像逻辑删除

由于构建完项目之后,我们需要执行Dockerfile文件,执行完毕后会生成一个镜像容器, 此时我们在下一次构建之前,需要把之前构建的镜像容器做一个清除操作,来保证镜像构建的唯一性!

若每次构建镜像不清除之前镜像的情况下,且镜像名标签,在每次构建都一样,可能会生成name<none> tag<none> 镜像缓存!

#!/bin/bash
# 定义镜像名称和标签
IMAGE_NAME="vmf"
# 当使用相同的镜像名称重复构建时,旧镜像会失去标签变成 <none> IMAGE_TAG 改为动态标签
TAG=${Env}
FULL_IMAGE="$IMAGE_NAME:$TAG"
# 检查镜像是否存在
echo "=============检查镜像是否存在=============="
if docker image inspect "$FULL_IMAGE" &> /dev/null; then
    echo "发现镜像 $FULL_IMAGE,正在删除..."
    # 停止并删除所有关联容器
    docker ps -a --filter "ancestor=$FULL_IMAGE" --format "{{.ID}}" | xargs -r docker rm -f
    # 删除镜像(可选:添加 || true 忽略错误)
    echo "删除旧镜像..."
    docker rmi -f "$FULL_IMAGE" 2>/dev/null || true
    docker rmi "nginx:latest"
    echo "删除完成"
else
    echo "镜像 $FULL_IMAGE 不存在"
fi
构建镜像

通过Dockerfile文件进行镜像构建,然后运行即可!

${Env} 是通过参数选项配置,比如你构建的dev 或者是 test环境!

#!/bin/bash
echo = "============开始构建镜像============="
docker build -t vmf:${Env} -f ./Dockerfile .
echo = "============启动镜像============="
docker run -d --name vmf-${Env} -p 9003:9003 vmf:${Env}