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实现前端自动化部署

相关推荐
henan程序媛7 小时前
Jenkins Pipline流水线
运维·pipeline·jenkins
wudinaniya1 天前
使用rsync+jenkins实现服务自动部署全流程
运维·jenkins·自动化部署
henan程序媛1 天前
jenkins项目发布基础
运维·gitlab·ansible·jenkins
小石潭记丶1 天前
elasticsearch设置账号和密码
大数据·elasticsearch·jenkins
识途老码2 天前
Centos7安装Jenkins
运维·servlet·jenkins
奔跑吧邓邓子2 天前
Jenkins从入门到精通,构建高效自动化流程
servlet·自动化·jenkins
江南剑雨3 天前
jenkinsfile实现镜像构建、发布
linux·运维·jenkins
小韩加油呀3 天前
jenkins配置eureka、nacos发布优雅上下线服务
运维·eureka·nacos·jenkins·优雅上下线
THE WHY3 天前
Jenkins pipeline配置示例
运维·ci/cd·jenkins
寻爱的希斯克利夫3 天前
Jenkins: fontconfig head is null, check your fonts or fonts configuration;
运维·jenkins