前端ci/cd工程搭建,docker+jenkins+nginx

前面我们已经搭建了jenkins流水线,并且集成了Gitee仓库,通过 Giteewebhook实现了Git推送代码,触发流水线自动构建,然后执行shell命令打包后部署到Nginx服务

回想下前面完成的步骤

  • 安装java环境,还要根据官方文档确认java和jenkins的版本
  • 安装jenkins
  • 安装nginx

每一个程序都要手动安装,各种查资料麻烦还容易踩坑,那么有没有什么工具能帮我们统一集成这些环境呢,让我们来学习下 Docker 一个开源的容器化平台.

Docker 简介

基本概念

Docker 是一个开源的容器化平台,它允许开发者将应用程序及其所有依赖打包到一个独立的、轻量级的容器中。这个容器可以在任何支持 Docker 的环境中运行,而不受底层操作系统的影响。Docker 容器包含了运行应用程序所需的一切:代码、运行时环境、系统工具、库和设置等

核心概念

  • 镜像(Image)Docker 镜像是一个只读模板,用于创建 Docker 容器。它包含了启动容器所需的文件系统和配置信息。
  • 容器(Container) :容器是镜像的运行实例。每个容器都是隔离的,并拥有自己的文件系统、网络栈等资源。
  • 仓库(Registry)Docker 仓库用于存储和分发镜像。最知名的公共仓库是 Docker Hub,但也可以搭建私有仓库。

Docker的优势

  • 跨环境的一致性 :无论是在开发人员的笔记本电脑上,还是在测试服务器或生产环境中,Docker 容器确保应用程序运行在相同的环境中。这消除了"在我机器上可以运行"的问题
  • 轻量级和快速启动 :相比于虚拟机,Docker 容器更轻量,启动和停止速度更快,减少了部署时间
  • 进程隔离:每个容器都有自己独立的文件系统、网络栈等资源,避免了不同服务之间的相互干扰
  • 资源限制:可以通过配置限制每个容器使用的 CPU、内存等资源,防止某个容器占用过多资源影响其他容器
  • 自动化构建 :Docker 支持通过 Dockerfile 自动化构建镜像,减少了手动配置的复杂性和错误率。
  • 持续集成/持续部署 (CI/CD)Docker 可以与 JenkinsGitLab CICI/CD 工具无缝集成,简化了从代码提交到部署的整个流程
  • 更高的资源利用率 :相比虚拟机,Docker 容器更轻量,能够更好地利用现有硬件资源,从而降低成本
  • 官方镜像库Docker Hub 提供了大量的官方镜像,涵盖了各种语言和工具,方便用户快速找到所需的镜像
  • 服务编排 :通过 Docker Compose Kubernetes 等工具,可以方便地管理和编排多个服务,确保它们协同工作

Docker 安装

服务器系统

腾讯云轻量服务器系统: CentOS 7.6

安装步骤

arduino 复制代码
// 确保你的系统是最新的,并安装一些必要的依赖
sudo yum update -y 

// `yum-utils` 提供了一组额外的 YUM 工具,帮助你更方便地管理和配置软件包
// `device-mapper-persistent-data` 是一个包含设备映射器工具和库的包,主要用于支持 LVM(逻辑卷管理)和其他存储管理功能
// `lvm2` 包含了逻辑卷管理器(LVM)的工具和库,LVM 是一种灵活的磁盘分区管理方式
sudo yum install -y yum-utils device-mapper-persistent-data lvm2

// 使用 `yum-config-manager` 添加 Docker 的官方仓库
sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo

// ### 安装 Docker CE(社区版)
sudo yum install docker-ce docker-ce-cli containerd.io -y

// 启动 Docker 并设置为开机自启
sudo systemctl start docker 
sudo systemctl enable docker

// 检查 Docker 是否正在运行
sudo systemctl status docker

// 验证 Docker 是否正确安装
sudo docker run hello-world

Docker-compose安装

Docker-compose 用于管理和编排多个容器的工具有很多比如 Docker ComposeKubernetes (k8s)

Docker Compose
  • 概念:Docker Compose 是一个用于定义和运行多容器 Docker 应用程序的工具。
  • 设计理念 :它主要用于开发环境或小型生产环境中,帮助用户快速启动和管理多个相关联的容器。通过 docker-compose.yml 文件,用户可以定义服务、网络和卷,简化了多容器应用的配置和启动。
  • 简单易用:适合开发人员在本地环境中快速搭建和测试多容器应用。
  • 静态配置 :通过 docker-compose.yml 文件定义服务,这些配置通常是静态的,不适合动态调整
  • 缺少高可用性和自愈能力:不提供内置的健康检查、自动恢复和负载均衡等功能

Kubernetes (k8s)

  • 概念Kubernetes 是一个开源平台,用于自动化部署、扩展和管理容器化应用程序。
  • 设计理念:它是一个完整的容器编排平台,适用于大规模生产环境,提供了丰富的功能来管理集群中的容器生命周期,包括自动扩展、自我修复、负载均衡等
  • 强大的编排能力:支持复杂的编排策略,如滚动更新、回滚、水平扩展等。
  • 动态管理 :通过声明式配置文件(如 YAML)定义应用状态,并通过控制器不断调整以达到期望状态。
  • 高可用性和自愈能力:内置健康检查、自动恢复、负载均衡等功能,确保应用的高可用性。

总结

  • Docker Compose 是一个轻量级的容器编排工具,适合开发环境和小型项目。
  • Kubernetes (k8s) 是一个功能强大且全面的容器编排平台,适合大规模生产环境和企业级应用。

我们这里个人简单的项目,先使用使用 Docker Compose 学习流程

安装

ruby 复制代码
// 下载最新版本的 `docker-compose`,下载的有点慢,耐心等待,或者手动下载
sudo curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose

// 下载完成后,为 `docker-compose` 文件赋予可执行权限
sudo chmod +x /usr/local/bin/docker-compose

// 检查 `docker-compose` 是否正确安装并显示版本信息
docker-compose --version

Docker Compose 部署 Nginx 和 Jenkins

在使用 Docker 启动 NginxJenkins 服务时,实际上你不需要手动下载或安装这些镜像。Docker 会自动从 Docker Hub 或其他配置的镜像仓库中拉取所需的镜像。这是 Docker 的一大优势:它简化了应用程序及其依赖项的分发和部署,这我们就不手动拉取了。

1. 创建项目目录(用于存放配置文件和数据卷的目录)

bash 复制代码
// 目录自己定义在哪里都行,我这里在 /home 下
mkdir /home/docker 
mkdir /home/docker/compose 
mkdir /home/docker/jenkins_home 
mkdir /home/docker/nginx 
mkdir /home/docker/nginx/conf 
mkdir /home/docker/html
mkdir /home/docker/html/web
mkdir /home/docker/html/h5

2. 编写 docker-compose.yml 文件

compose目录中创建一个名为 docker-compose.yml 的文件,并添加以下内容

yaml 复制代码
version: '1'

networks:
  frontend:
    external: true

services:                                      # 容器
  docker_jenkins:
    user: root                                 # root权限
    restart: always                            # 重启方式
    image: jenkins/jenkins:lts                 # 使用的镜像
    container_name: jenkins                    # 容器名称
    deploy:
      resources:
        limits:
          memory: 4g                            # 增加到至少 4GB 或更高
        reservations:
          memory: 2g                            # 预留至少 2GB

    ports:                                     # 对外暴露的端口定义
      - 8080:8080
      

    volumes:                                   # 卷挂载路径
      - /home/docker/jenkins_home/:/var/jenkins_home     # 挂载到容器内的jenkins_home目录
      - /usr/local/bin/docker-compose:/usr/local/bin/docker-compose
      - ~/.ssh:/root/.ssh  # 将主机的 ~/.ssh 目录挂载到容器的 /root/.ssh
      - /home/docker/html:/home/docker/html # 挂载到容器内的 home 目录,不然流水线shell命令时访问不到文件夹无法移动dist文件

  
  docker_nginx:                            # nginx-dev环境
    restart: always
    image: nginx
    container_name: nginx
    ports:
      - 80:80
    volumes:
      - /home/docker/nginx/conf/nginx.conf:/etc/nginx/nginx.conf
      - /home/docker/html:/usr/share/nginx/html
      - /home/docker/nginx/logs:/var/log/nginx

#1./docker/nginx/conf/nginx.conf:/etc/nginx/nginx.conf
#这表示将宿主机上的/docker/nginx/conf/nginx.conf文件挂载到容器内的/etc/nginx/nginx.conf文件。这样,当容器启动时,它会使用宿主机上这个路径的nginx.conf文件作为Nginx的配置文件。任何对容器内/etc/nginx/nginx.conf文件的修改都会反映到宿主机上的/docker/nginx/conf/nginx.conf文件,反之亦然(注意,这里假设是双向挂载,但Docker的默认行为可能会根据文件系统的不同而有所不同)。
#2./docker/html:/usr/share/nginx/html
#这表示将宿主机上的/docker/html目录挂载到容器内的/usr/share/nginx/html目录。这通常用于存放Nginx服务的静态网页文件。当容器启动时,它会从容器内的/usr/share/nginx/html目录(实际上是宿主机上的/docker/html目录)读取这些文件来提供Web服务。任何在容器内对/usr/share/nginx/html目录的修改都会反映到宿主机上的/docker/html目录,反之亦然。
#3./docker/nginx/logs:/var/log/nginx
#这表示将宿主机上的/docker/nginx/logs目录挂载到容器内的/var/log/nginx目录。Nginx的日志文件通常存放在/var/log/nginx目录下,通过这个挂载,你可以将容器的日志保存在宿主机上,方便查看和管理。任何在容器内对/var/log/nginx目录的修改(例如新的日志文件被创建或现有日志文件的内容被更新)都会反映到宿主机上的/docker/nginx/logs目录。

3. 编写 Nginx 配置文件

文件放在 /home/docker/nginx/conf 目录下

bash 复制代码
# nginx.conf 
# main段配置信息
user  root;                                # 运行用户,默认即是nginx,可以不进行设置
worker_processes  2;                        # Nginx 进程数,一般设置为和 CPU 核数一样
error_log  /var/log/nginx/error.log warn;   # Nginx 的错误日志存放目录
pid        /var/run/nginx.pid;              # Nginx 服务启动时的 pid 存放位置
 
# events段配置信息 
events {
#    use epoll;     # 使用epoll的I/O模型(如果你不知道Nginx该使用哪种轮询方法,会自动选择一个最适合你操作系统的)
    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; # Nginx访问日志存放位置

    sendfile            on;   # 开启高效传输模式
    tcp_nopush          on;   # 减少网络报文段的数量
    keepalive_timeout   65;   # 保持连接的时间,也叫超时时间,单位秒
    gzip  on;

    # server段配置信息
    server {
            #监听的端口
        listen  80;               # 配置监听的端口
        server_name  122.51.243.228;   # 配置的域名

        #location目录后加"/",只能匹配目录,不加"/"不仅可以匹配目录还对目录进行模糊匹配。而proxy_pass无论加不加"/",代理跳转地址都直接拼接。
        #  http://localhost/jenkins_home/xxx -> http://localhost:8080/jenkins_home/xxx
        location /jenkins_home/ {  
            # 假设你的Jenkins服务可以通过宿主机上的8080端口访问 
            # proxy_pass 指令被用来将 /jenkins_home/ 路径下的请求代理到 Jenkins 服务 
            proxy_pass http://122.51.243.228:8080/;  
            # 添加其他需要的Nginx指令,如proxy_set_header等  
        }  
               
               
        #假设一个项目中有 web 端
        # location /web   这定义了当请求的URI以/h5开始时(例如,/web/, /web/page.html, /web/some/path等)如何响应这些请求。
        #alias指令指定了一个目录,Nginx将从该目录提供文件以响应匹配的URI。
        #这里,/usr/share/nginx/html/h5/dist是Nginx服务器上实际存储文件的目录。
        #与root指令不同,alias指令会将请求的URI路径替换为alias指定的路径。
        #例如,对于请求/web/page.html,Nginx将尝试从/usr/share/nginx/html/web/dist/page.html提供文件,
        #而不是从/usr/share/nginx/html/h5/dist/h5/page.html(如果使用root指令)。

        location /web {
            #linux下HTML文件夹,就是你的前端项目文件夹
            # root是完整路径:相当于/usr/share/nginx/html + /web + /dist/index.html  
            # alias是重定向:相当于 /usr/share/nginx/html/web/dist + /index.html
            #   root  /usr/share/nginx/html; 
            #注意这里已经在docker做了挂载,所以要写映射目录,而不是硬盘目录(也就是docker下的目录)
            alias  /usr/share/nginx/html/web/dist;

            #输入网址(server_name:port)后,默认的访问页面
            #这指定了当请求的是一个目录(如/h5/)而不是一个具体的文件时,Nginx应该提供哪个文件作为默认页面。
            #在这里,如果请求的是/h5/并且/usr/share/nginx/html/h5/dist/目录中存在index.html文件,那么Nginx将提供该文件作为响应。
            #使用root方式写法
            #index  dist/index.html;  

            #使用alias  写法
            index  index.html;  # 默认首页文件  
            #try_files指令用于尝试不同的URI路径来服务请求,并在所有指定路径都失败时提供一个回退。 这里可以自行写一个跟index.html文件同级的文件去回退
            # try_files $uri $uri/ /error.html;
        }

        #假设一个项目有 H5 端
        location /h5 {
            alias  /usr/share/nginx/html/h5/dist;
            index  index.html;  
        }
    }
}

挂载卷(Volume Mounting)是 Docker 的一个重要特性,它允许你将主机文件系统中的目录或文件挂载到容器内部。这不仅使得容器内外的数据可以共享和持久化,还方便了调试、开发和部署过程

4. 启动服务

进入包含 docker-compose.yml 文件的目录,并运行以下启动命令,启动服务

arduino 复制代码
docker-compose up // 前台启动,可以看启动日志,建议先前台启动,看是否报错,没问题在后台启动 
docker-compose up -d // 后台启动 
docker-compose down // 关闭应用 
docker ps -a // 查看所有容器(包括已停止的) 
docker ps // 查看正在运行的容器

查看正在运行的容器,Nginx Jenkins 都成功运行起来了,直接输入 ip + 端口就可以访问了

Jenkins 配置

1. 插件源修改

进入 jenkins 容器先修改配置文件, 修改插件下载的源,因为默认url 太慢插件下载不下来

javascript 复制代码
docker exec -it nginx /bin/sh // 进入 nginx 容器
docker exec -it jenkins /bin/bash // 进入 jenkins 容器 
exit // 退出容器 
find / -name "default.json" 2>/dev/null // 查找容器位置 
// 将 jenkins 容器中的 /var/jenkins_home/default.json 文件复制到主机上的 /home
docker cp jenkins:/var/jenkins_home/updates/default.json /home 
docker cp /home/default.json jenkins:/var/jenkins_home/updates/default.json
// 把下面的 url 新增进去,然后替换原文件
"url": "https://updates.jenkins.io/update-center.json"

2. 登录 Jenkins

arduino 复制代码
// admin 密码
cat /home/docker/jenkins_home/secrets/initialAdminPassword

3. 添加添加凭据

4. 使用SSH协议集成git仓库源或者使用Gitee API令牌集成git仓库源

3/4的步骤和我上篇文章里面操作方式一样,这里就省略了
前端ci/cd工程搭建 Jenkins 流水线构建(超详细)

SSH 密钥生成的注意事项,我们现在运行的 JenkinsDocker容器里面的,所以你在容器外面生成是没用的

  • 方案一:在容器里面的 Jenkins 中生成 SSH 密钥,并且测试连接。
typescript 复制代码
docker exec -it jenkins /bin/bash // 进入 Jenkins 容器 
ssh-keygen -t rsa -b 4096 -C "6666@qq.com" // ssh-keygen 命令生成密钥对 
ls -al ~/.ssh // 查看生成的密钥 
cat ~/.ssh/id_rsa.pub // 复制公钥内容
// 然后就是添加到远程仓库和jenkins的线上配置了,配置完测试 
ssh -T git@gitee.com

这里需要注意的是,在容器里面生成的 SSH 密钥在容器重启后也会丢失,是因为这些密钥存储在容器的临时文件系统(如 /tmp)中,或者因为容器重启时数据没有被持久化。Docker 容器默认情况下不会保存任何在容器内创建的数据;一旦容器停止或删除,所有未持久化的数据都会丢失。

当你重启后发现Git仓库连不上可能是因为这个原因,可以检查下公钥/密钥文件还在不在

  • 方案二:使用 Docker 卷绑定挂载来持久化数据,更推荐这种,在上面 docker-compose.yml 文件里面已经写了
javascript 复制代码
 - ~/.ssh:/root/.ssh  # 将主机的 ~/.ssh 目录挂载到容器的 /root/.ssh

挂载卷(Volume Mounting)是 Docker 的一个重要特性,它允许你将主机文件系统中的目录或文件挂载到容器内部。这不仅使得容器内外的数据可以共享和持久化,相当于你把主机文件夹,挂载到了容器对应的文件夹下面,你对挂载的容器文件夹操作会同步到主机文件夹,方便了调试、开发和部署过程,

5. 配置 Node 插件

[Dashboard] - [系统管理] - [插件管理]

没安装的话在 Available plugins 里面查找了直接安装

然后来到-[Dashboard] - [系统管理] - [全局工具配置]-新增 NodeJS 选择需要的版本保存就行了

6. 项目里面选择构建环境

7. 新增 Build Steps

也是选择前面配置的 Node ,用于后面执行 Shell 脚本 的 node 命令

8. 新增 shell 步骤

先简单的执行一下 install 命令看一下能否成功 查看控制台输出,没有发现问题运行成功 查看 workspace 的项目里面 node_module 也有了

9. 完善 shell 脚本,线上验证

bash 复制代码
#!/bin/bash
npm config set registry https://registry.npmmirror.com
npm install 
echo "依赖安装成功"
rm -rf dist
npm run build
echo "打包成功"
# 复制 dist 文件夹到 /home/docker/html
cp -r dist/* /home/docker/html/web/dist
echo "Build and copy completed successfully."

步骤就是打包完了之后,把dist文件里面的内容复制到 /home/docker/html/web/dist 文件夹下

这里shell命令时能够在 Jenkins 容器中能够正确挂载和访问这个目录,是因为在 docker-compose.yml 文件里面我们已经正确设置了挂载卷

javascript 复制代码
- /home/docker/html:/home/docker/html # 挂载到容器内的 home 目录,不然流水线shell命令时访问不到文件夹无法移动dist文件

如果你需要把项目部署到别的服务器上面可以也使用 Jenkins的插件 Publish Over SSH ,通过 SSH 协议将构建结果部署到远程服务器。它允许你通过 SSH 连接到远程主机,并执行一系列命令或上传文件 ,我这里就一台服务器就不用了

设置完保存后再跑一下流水线

控制台输出成功

dist文件夹到内容也更新了

再去线上测试下页面访问也没有问题,这里注意下如果页面里面有资源访问404,需要配置下打包路径,我这里是vite项目

php 复制代码
export default defineConfig({
  base: './',
  plugins: [react()],
})

到这里一整套ci/cd流程就走完啦!

相关推荐
m0_548514777 分钟前
前端打印功能(vue +springboot)
前端·vue.js·spring boot
执键行天涯14 分钟前
element-plus中的resetFields()方法
前端·javascript·vue.js
Days205019 分钟前
uniapp小程序增加加载功能
开发语言·前端·javascript
喵喵酱仔__20 分钟前
vue 给div增加title属性
前端·javascript·vue.js
dazhong201230 分钟前
HTML前端开发-- Iconfont 矢量图库使用简介
前端·html·svg·矢量图·iconfont
m0_748248771 小时前
前端vue使用onlyoffice控件实现word在线编辑、预览(仅列出前端部分需要做的工作,不包含后端部分)
前端·vue.js·word
莫惊春1 小时前
HTML5 第五章
前端·html·html5
Json____1 小时前
前端node环境安装:nvm安装详细教程(安装nvm、node、npm、cnpm、yarn及环境变量配置)
前端·windows·npm·node.js·node·nvm·cnpm
阿福的工作室1 小时前
4. React 性能优化技巧:如何让你的应用更快
前端·react.js·前端框架
CL_IN1 小时前
金蝶云星空与华为云AX无缝数据集成技术详解
服务器·前端·华为云