前端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流程就走完啦!

相关推荐
passerby60613 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了3 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅3 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅4 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅4 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment4 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅4 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊4 小时前
jwt介绍
前端
爱敲代码的小鱼5 小时前
AJAX(异步交互的技术来实现从服务端中获取数据):
前端·javascript·ajax
Cobyte5 小时前
AI全栈实战:使用 Python+LangChain+Vue3 构建一个 LLM 聊天应用
前端·后端·aigc