前面我们已经搭建了jenkins
流水线,并且集成了Gitee
仓库,通过 Gitee
的webhook
实现了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
可以与Jenkins
、GitLab CI
等CI/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 Compose 和 Kubernetes (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
启动 Nginx
和 Jenkins
服务时,实际上你不需要手动下载或安装这些镜像。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 密钥生成的注意事项
,我们现在运行的 Jenkins
是 Docker容器里面
的,所以你在容器外面生成是没用的
- 方案一:在容器里面的
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流程就走完啦!