Docker + Jenkins + Nginx 实战前端自动化部署

背景

前几天在掘金刷文章,刷到了自动化CI/CD,于是心血来潮打算耍一耍,于是打开我的阿里云服务器,启动了一直睡觉的服务器实例,准备试试手,一路磕磕绊绊,最终功夫不负有心人,修成正果。

记录一下,也给现在或即将入手的你带来一份保姆级实站教程,这瓜保不保熟你说了算

前置准备

服务器一台(本系统CentOS 7.3 64位)

Gitlab项目一个(本次用Umi4创建了一个项目),提前创建好对应分支dev/sit ...

实现目标

搭建Docker + Jenkins + Nginx 环境,实现同一服务器多环境(dev、sit 、uat ...)通过git提交对应分支 自动部署到服务器上对应的环境,本案例仅考虑linux服务器前端部署自动化

可能用到的linux命令

arduino 复制代码
名词 CONTAINER ID(容器ID)
名词 IMAGE ID(镜像ID)

cat /etc/os-release //查看系统信息
pwd //查看当前路径
ls //查看当前目录文件
docker -v //查看docker版本
docker-compose up -d //在后台运行(取消-d是在控制台运行)
docker-compose stop //所有容器停止运行
docker ps -a //查看正在运行的容器
docker images //查看安装的镜像
docker stop [CONTAINER ID] //停掉运行的容器
docker rm [CONTAINER ID] //删除运行的容器
systemctl status docker  //查看docker状态
systemctl stop docker    //停止docker
systemctl start docker    //启动docker
systemctl restart docker    //重启docker

环境搭建

本示例环境:

CentOS 7.3 64位

Docker version 24.0.5

Nginx: version 1.25.1 latest(最新版)

Jenkins:version 2.401.3 lts(稳定正式版)

Docker Compose: version v2.20.2

连接服务器

可以采用ssh连接(ssh root@服务器公网IP )、云服务器官网-控制台-远程连接 或者一些连接工具例如 FinalShell等工具

搭建Docker环境

Docker 是一个开源的应用容器引擎,基于 [Go 语言]并遵从 Apache2.0 协议开源。

Docker 从 17.03 版本之后分为 CE(Community Edition: 社区版) 和 EE(Enterprise Edition: 企业版)

Docker 包括三个基本概念:

镜像(Image)容器(Container)仓库(Repository)

安装Docker

首先要确保自己的服务器系统满足安装要求,具体要求可去百度查找

菜鸟教程安装Docker

Docker安装完毕后

查看docker相关的rpm源文件rpm -qa |grep docker

Docker启动
sql 复制代码
sudo systemctl start docker
安装Docker-compose

Compose 是用于定义和运行多容器 Docker 应用程序的工具。通过 Compose,您可以使用 YML 文件来配置应用程序需要的所有服务。然后,使用一个命令,就可以从 YML 文件配置中创建并启动所有服务。

ruby 复制代码
curl -L https://get.daocloud.io/docker/compose/releases/download/v2.4.1/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose

Docker-compose权限提升和jenkins目录权限提升

bash 复制代码
chmod 777 /docker/jenkins_home
sudo chmod +x /usr/local/bin/docker-compose

如果出现操作docker命令权限问题,可用下面提升权限,不出现可忽略

bash 复制代码
#创建用户组,已存在则无需理会
sudo groupadd docker
 
#将需要授权docker权限的用户添加到docker用户组内
sudo usermod -aG docker $USER
 
#-------------上面两步操作完,用户就有docker权限了
#将docker-compose应用分配给docker用户组
sudo chgrp docker /usr/local/bin/docker-compose
 
#设置docker用户组可执行权限
sudo chmod 750 /usr/local/bin/docker-compose

安装Git

arduino 复制代码
sudo apt-get update //更新包索引

sudo apt-get install git //安装git

git --version //验证

配置密钥

arduino 复制代码
ssh-keygen -t rsa -C "root"

一路enter

然后会生成id_rsa(私钥)id_rsa_pub(公钥)

输入cd /root/.ssh

添加公钥到gitlab

将公钥添加到Gitlab或其他代码库的SSH Keys

验证一下,如果成功,则可以在服务器上拉取项目代码

安装Nginx和Jenkins

jenkins最新版已停止维护

改用jenkins/jenkins:lts

bash 复制代码
docker pull nginx 
docker pull jenkins/jenkins:lts

安装完毕后配置通过 docker images 查看安装的镜像

然后创建文件目录,可通过远程连接工具手动创建,也可以通过下面命令创建

bash 复制代码
mkdir /docker           
mkdir /docker/compose    
mkdir /docker/jenkins_home   
mkdir /docker/nginx      
mkdir /docker/nginx/conf 
mkdir /docker/html       
mkdir /docker/html/dev   
mkdir /docker/html/sit   
mkdir /docker/html/uat

目录创建之后创建两个文件docker-compose.yml、nginx.conf

bash 复制代码
cd /docker/compose
touch docker-compose.yml

cd /docker/nginx/conf
touch nginx.conf

最后目录结构如下

less 复制代码
   + docker 
       + compose
           - docker-compose.yml  //docker-compose配置
       + html             //各环境代码目录(实际项目可能不在同一目录)
           + dev          //dev环境代码目录
           + sit          //sit环境代码目录
           + uat          //uat环境代码目录
       + jenkins_home     //Jenkins工程目录
       + nginx            //nginx工程目录
           + conf
               - nginx.conf  //nginx配置
setting.yml配置
ruby 复制代码
version: '3'

networks:
  frontend:
    external: true

services:                                      # 容器
  docker_jenkins:
    user: root                                 # root权限
    restart: always                            # 重启方式
    image: jenkins/jenkins:lts                 # 使用的镜像
    container_name: jenkins                    # 容器名称
      
    ports:                                     # 对外暴露的端口定义
      - 8080:8080
      - 50000:50000
      

    volumes:                                   # 卷挂载路径
      - /docker/jenkins_home/:/var/jenkins_home     # 挂载到容器内的jenkins_home目录
      - /usr/local/bin/docker-compose:/usr/local/bin/docker-compose
  
  docker_nginx_dev:                            # nginx-dev环境
    restart: always
    image: nginx
    container_name: nginx_dev
    ports:
      - 8001:8001
    volumes:
      - /docker/nginx/conf/nginx.conf:/etc/nginx/nginx.conf
      - /docker/html:/usr/share/nginx/html
      - /docker/nginx/logs:/var/log/nginx

  docker_nginx_sit:                            # nginx-sit环境
    restart: always
    image: nginx
    container_name: nginx_sit
    ports:
      - 8002:8002
    volumes:
      - /docker/nginx/conf/nginx.conf:/etc/nginx/nginx.conf
      - /docker/html:/usr/share/nginx/html
      - /docker/nginx/logs:/var/log/nginx


     
docker-compose 配置说明
  1. version:指定Compose文件版本。
  2. services:定义需要启动的服务及它们所需的镜像、端口映射、环境变量、挂载到主机上的目录等相关信息。
  3. volumes:定义数据卷,即将容器内部的数据持久化到宿主机的目录中。
  4. networks:定义网络,使得多个服务可以在同一网络下相互通信。(跨服务器连接时必须要配置
  5. environment:指定环境变量,传递给服务容器使用。
  6. ports:定义端口映射,将容器内部的端口映射到宿主机端口。
  7. depends_on:定义服务启动的依赖关系,保证依赖的服务先启动。
  8. build:定义镜像构建的相关信息,包括构建上下文路径、Dockerfile路径以及构建参数等。
nginx.conf配置
ini 复制代码
# nginx.conf 例:
user  nginx;
worker_processes  1;
 
error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;
 
 
events {
    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;
 
    sendfile        on;
    #tcp_nopush     on;
 
    keepalive_timeout  65;
 
    gzip  on;

    #dev环境
    server {
            #监听的端口
        listen  8001;
        server_name  localhost;
        #设置日志
#        access_log  logs/dev.access.log  main;
        
        #定位到index.html
           location / {
               #linux下HTML文件夹,就是你的前端项目文件夹
               root  /usr/share/nginx/html/dev/dist;
#               root  /home/html/dev/dist;
               #输入网址(server_name:port)后,默认的访问页面
               index  index.html;
               try_files $uri $uri/ /index.html;
           }
    }

    #sit环境
    server {
            #监听的端口
        listen  8002;
        server_name  localhost;
        #设置日志
#        access_log  logs/sit.access.log  main;
        
        #定位到index.html
           location / {
               #linux下HTML文件夹,就是你的前端项目文件夹
               root  /usr/share/nginx/html/sit/dist;
#               root  /home/html/dev/dist;
               #输入网址(server_name:port)后,默认的访问页面
               index  index.html;
               try_files $uri $uri/ /index.html;
           }
    }

 
#    include /etc/nginx/conf.d/*.conf;

   
}

想要更详细的配置可参考:nginx详细配置

开放服务器对应端口

本示例要开放的有3个:

8080:对应jenkins

8001:对应dev环境

8002:对应sit环境

进入对应服务器控制台安全组配置添加

环境启动

按照上面步骤Docker环境就部署好了

执行docker启动命令systemctl start docker

进入到对应目录 cd /docker/compose

执行命令 docker-compose up -d

查看容器运行状态

css 复制代码
docker ps -a

如下图

此时浏览器输入 IP:端口 ,会自动进入jenkins页面,需要输入密码

密码在 docker/jenkins_home/secrets/initialAdminPassword

可以通过命令:

bash 复制代码
cat /docker/jenkins_home/secrets/initialAdminPassword

复制密码进jenkins登录页面

等待安装完成配置用户密码

配置实例,自定义,然后可以登录访问了,首页如下

至此环境安装完毕并启动成功

Nginx配置

验证nginx环境

在对应目录/docker/html/dev/dist/docker/html/sit/dist各新建一个index.html

附上代码

xml 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <h1>这是一个测试</h1>
</body>
</html>

如果页面正常打开代表nginx配置成功

然后删除对应的dist文件夹,后续会自动生成

Jenkins配置

设置中文

下载 local 插件

选择【Manage Jenkins】-> 【Plugins】-> 【Plugins】->

如已安装,执行重启即可,地址栏输入http://ip:端口/restart

安装插件

安装之后重启

Publish Over SSH

用来连接远程服务器的

进去找到Publish Over SSH,这块有多种连接验证方式,本案例采用密码验证,想使用别的方式请移步百度搜索

找到SSH Server,点击新增

点击高级

往下滑动

测试成功后->应用->保存

Gitlab

用来连接gitlab和jenkins

NodeJS

用来执行前端代码环境

安装之后配置node环境,可以用服务器上的,如果用服务器上的,需要在服务器配置环境变量,我这边配置好后在Jenkinsg构建时一直失败,尝试很久,感兴趣的可以尝试下,最后考虑还是选择用自动安装的,按下图操作,这里node版本要与本地环境node版本保持一致

先应用后保存

添加凭据

添加凭据(账号密码)是为了方便后续使用

添加gitlab账号密码

创建job

源码管理

应用保存后,点击立即构建

无论是否成功,都可以在构建记录控制台查看

如果成功代表基础构建成功,咱们继续完善构建

Gitlab WebHooks配置

登录gitlab,进入偏好设置

这里的URLSecret Token来自下面 构建触发器 那块,仔细找一下,Triger是触发方式,本案例选的全部分支提交都会触发,实际项目根据实际来,SSL可选可不选

往下拉,点击添加

验证webhooks

点击TEST、点击Push events

在此步未出现200的请移步文章后面的踩坑记录

gitlab验证200通过后,测试通过,去jenkins工程看构建记录是否新增一条测试的记录,如正常新增,代表整个流程流通,如未流通,请检查上面创建job -源码管理是否正常成功

构建触发器

点开高级

往下滑

点击应用保存,继续重复之前立即构建,构建成功,此时代码已经同步过来了

前两步构建都需要结合gitlab

Build Steps

/docker/jenkins_home/workspace/gitlab_web,每次构建对应代码都会同步更新,由于代码没有在git上传node_moudle文件夹,所以后续需要在服务器重新安装node_moudle

Execute NodeJS script

这里选的node是上面配置的

点击应用后保存,然后点击立即构建,此次时间会长一点 ,此时构建会去自动安装对应的nodejs安装包到jenkins目录并配置好环境变量,注意尽量与本地开发环境的node版本一致,为了保持环境同步,等待构建好后再执行下一步

应用保存并构建成功后,可以进入下一步

Shell命令

在shell命令这块有的执行node -v都报错,此时请检查环境变量是否与服务器的环境变量有差异,执行echo $PATH

第一行代码一般要添加#!/bin/bash,至于为什么可以去百度查询,考虑时间精力,这里不做扩展

如果环境变量有问题可能要在第二行执行刷新环境变量命令

bash 复制代码
source ~/.bash_profile
source /etc/profile

上面哪个有效果用哪个

然后执行对应命令,验证环境可用

bash 复制代码
#!/bin/bash

node -v 
npm -v 
echo $PATH

上述命令如成功执行,进行下一步

安装node_moule并build打包

如果在之前构建时,git已经提交里node_moudle,此时就不需要执行项目重新装包的操作,可跳过此命令添加,我这边本地用的yarn构建

添加yarn包管理器
ini 复制代码
npm install -g yarn -registry=https://registry.npm.taobao.org 
yarn -v

成功后执行包安装

lua 复制代码
yarn install --pure-lockfile 
#--pure-lockfile 这个参数是在服务器install不生成yarn.lock,防止服务器和本地代码冲突,本地代码也不要提交上去

安装成功后执行build打包

此时执行命令要把安装包命令去掉

继续执行构建操作

此时服务器代码出现dist文件夹

代码自动部署到对应环境项目目录

同一服务器可以用cp命令,可以参考linux cp命令

之前尝试过cp执行失败,考虑时间精力最后改成压缩包ssh传输,但cp命令确实是可以的,应该是我姿势不对,感兴趣的朋友可以试着用一下,这样同一服务器减少了一步ssh构建

压缩成tar

命令:

bash 复制代码
rm -rf dist.tar     # 每次构建删除已存在的dist压缩包
tar -zcvf dist.tar ./dist  #将dist文件压缩成dist.tar

构建成功后多了个dist.tar文件

连接SSH服务器

系统配置已经设置过ssh相关配置再操作下面,如未设置,请往上翻 Publish Over SSH

字段说明:

Source files:准备发送的文件,该文件是相对于这个项目的workspace目录。例如要发送/docker/jenkins_home/workspace/gitlab_web/dist.tar到目标目录,则设置Source filesdist.tar

Remove prefix:目标文件前缀添加,例如要操作src下面的某个文件,就设置成src,本案例是跟目录,无需设置

Remote directory:目标目录,本案例要复制到dev环境下的dist文件,/docker/html/dev

Exec command:最后执行的命令,可在这里进行解压,删除,复制等操作

执行构建后,对应目录已经有了一个dist.tar文件

这样肯定是不行的,还需要删除原有dist文件夹,解压dist.tar,再删除dist.tar,最终命令如下

bash 复制代码
cd /docker/html/dev
rm  -rf   dist/
tar zxvf dist.tar
rm dist.tar

至此,shell命令执行结束,目前的效果是:

gitlab 项目dev分支git提交后,触发jenkins自动构建,自动构建会先在服务器从gitlab的dev分支拉取最新代码,执行build打包后生成dist.tar文件,然后通过ssh将对应dist.tar发送到对应dev环境的项目目录解压dist.tar并更新对应文件,实现自动更新dev环境

验证自动更新dev效果

现有dev环境

现有代码:

更改后提交:

此时的gitlab上有了对应的分支提交

此时的jenkins工程构建目录里有了来自gitlab的自动触发

此时的网页http://ip:8001 已经自动更新

至此,dev环境自动构建已结束,如果需要自动更新sit环境,需要按照上面的创建job重新建一个指向sit的自动构建,这里不再赘述

踩坑记录

gitlab webhooks 测试 HTTP 403

在Jenkins构建成功后,连接gitlab的webhooks测试时出现http 403

问题原因

网上查了很多文档,经多方排查验证,主要是CSRF配置问题,还有要把Jenkins系统设置中取消勾选"Enable authentication for '/project' end-point" ,因为该案例是用的gitlab官网,不是在服务器上单独搭建的一套gitlab平台,单独搭建没试,感兴趣的可以搭一下看是不是还出现403

在旧版本的jenkins里,有这个配置可控,但自2.2xx版本之后,csrf认证在web界面里已经没法关闭了 本案例现有的配置,

实测勾选启用代理兼容并重启jenkins后无效

解决方案

勾选匿名用户具有可读权限

系统设置里

取消勾选"Enable authentication for '/project' end-point"

系统设置里

关闭CSRF

在网上找到了2个可以关闭csrf的方案

1.命令行临时关闭

输入命令

ini 复制代码
hudson.security.csrf.GlobalCrumbIssuerConfiguration.DISABLE_CSRF_PROTECTION=true

执行命令后在全局安全设置里是这样

优点:有效果

缺点:重启后失效

2.jenkins的启动配置中添加参数

具体参考配置

这个我没试成功,感兴趣的可以研究下,我用的方案1

按照上面操作,403会消失,进而是其他报错401或者404

gitlab webhooks 测试 HTTP 404

问题原因

这个问题也排查了一段时间,最后发现是访问不到对应目录文件

我这边工程目录是http://ip:端口/job/gitlab_web/

在地址栏输入webhooks的URL http://ip:8080/jenkins_home/project/gitlab_web 发现是打不开的

本案例最初设置的实例是jenkins_home

最终分析出这个是要设置访问前缀,文章上面的docker-compose.yml最初是没有配置前缀的,所以Jenkins访问是http://ip:端口/

解决方案

在docker-compose.yml里添加前缀,本案例设置的实例是jenkins_home,所以要加前缀jenkins_home

ini 复制代码
   environment:
    - TZ=Asia/Shanghai
    - "JENKINS_OPTS=--prefix=/jenkins" ## 自定义 jenkins 访问前缀(上下文context)

最终yml效果

修改保存后重启容器,然后jenkins访问路径要变化了,变成http://ip:端口/jenkins_home

重启后再次在gitlab 测试webhooks,发现404没了。

友情提示:

上面我关闭CSRF配置走的方案1,此时随着重启CSRF已经恢复过来了,但,gitlab测试仍然是成功的,所以,CSRF白配了,若问我为什么最初的docker-compose.yml不配置前缀最终版,😄(内心OS:我踩的坑你们不踩怎么行)看到这的朋友是不是要来个赞👍,别的文章有我记忆深刻吗,是不是这个理,其实还有个坑我没放出来,是nginx的配置坑,直接一步到位了

总结

5年前端,第一次在掘金发文,面对当前大环境,也有迷茫,这篇文章算是心血来潮,想留下一点东西吧,之前没接触过CI/CD,属于一路坑踩过来的,最终部署成功后,为了写这篇文章,全部卸载重新安装又走了一遍,jenkins卸载的时候发现卸载不干净,单独卸载docker里的jenkins没多大效果,数据卷还存在,又重新百度最后卸载干净,然后边部署边写文章,所以目录排版有点错乱,请见谅,终于今天完成,亲测保熟可食😄,后续可能完善后台node,对接后台接口,实现前后端均自动化部署。

各位看官如果有收获,请一定要用一键三连砸我,谢谢🙏

文章部分参考:Docker+Nginx+Jenkins实现前端自动化部署

相关推荐
青木沐1 小时前
Jenkins介绍
运维·jenkins
只会copy的搬运工5 小时前
Jenkins 持续集成部署——Jenkins实战与运维(1)
运维·ci/cd·jenkins
测试杂货铺7 小时前
如何用postman做接口自动化测试及完美的可视化报告?
自动化测试·软件测试·测试工具·职场和发展·jenkins·压力测试·postman
科马9 小时前
【Jenkins】持久化
java·运维·jenkins
编程、小哥哥12 小时前
在 Docker 中部署 Jenkins,并完成项目的构建和发布
servlet·docker·jenkins
_oP_i17 小时前
.NET Core 项目配置到 Jenkins
运维·jenkins·.netcore
coder_pig1 天前
📝小记:Ubuntu 部署 Jenkins 打包 Flutter APK
flutter·ubuntu·jenkins
运维&陈同学2 天前
【Elasticsearch05】企业级日志分析系统ELK之集群工作原理
运维·开发语言·后端·python·elasticsearch·自动化·jenkins·哈希算法
csdn_金手指2 天前
Jenkins持续交付web应用,通过docker制作相关的镜像进行发布部署
运维·jenkins
龙少95433 天前
【SpringBoot中怎么使用ElasticSearch】
spring boot·elasticsearch·jenkins