专注于 JetBrains IDEA 全家桶,永久激活,教程
持续更新 PyCharm,IDEA,WebStorm,PhpStorm,DataGrip,RubyMine,CLion,AppCode 永久激活教程

前端自定义CICD Docker篇

Docker的由来

我们可能会遇到这样的问题,我们手动部署项目,可能是node项目,可能是java项目,可能是前端项目,我们安装的node版本或者jdk,tomcat版本不一致,导致项目会发生各种诡异问题,有的服务器就是好使,有的服务器就是有问题,正常来说都是部署漏了点东西。
我们就不能把好的服务打成包直接拿来使用么?

布署软件的问题

  • 如果想让软件运行起来要保证操作系统的设置,各种库和组件的安装都是正确的
  • 热带鱼&冷水鱼 冷水鱼适应的水温在5-30度,而热带鱼只能适应22-30度水温,低于22度半小时就冻死了

常用解决方案和对比

虚拟机

虚拟机(virtual machine)就是带环境安装的一种解决方案。它可以在一种操作系统里面运行另一种操作系统

  • 资源占用多
  • 冗余步骤多
  • 启动速度慢

Linux容器

由于虚拟机存在这些缺点,Linux 发展出了另一种虚拟化技术:Linux 容器(Linux Containers,缩写为 LXC)。
Linux 容器不是模拟一个完整的操作系统,而是对进程进行隔离。或者说,在正常进程的外面套了一个保护层。对于容器里面的进程来说,它接触到的各种资源都是虚拟的,从而实现与底层系统的隔离。

  • 启动快
  • 资源占用少
  • 体积小

Docker

  • Docker 属于 Linux 容器的一种封装,提供简单易用的容器使用接口。它是目前最流行的 Linux 容器解决方案。
  • Docker 将应用程序与该程序的依赖,打包在一个文件里面。运行这个文件,就会生成一个虚拟容器。程序在这个虚拟容器里运行,就好像在真实的物理机上运行一样

Docker和KVM

1、 启动时间

  • Docker秒级启动
  • KVM分钟级启动

1、 轻量级 容器镜像通常以M为单位,虚拟机以G为单位,容器资源占用小,要比虚拟要部署更快速

  • 容器共享宿主机内核,系统级虚拟化,占用资源少,容器性能基本接近物理机
  • 虚拟机需要虚拟化一些设备,具有完整的OS,虚拟机开销大,因而降低性能,没有容器性能好

1、 安全性

  • 由于共享宿主机内核,只是进程隔离,因此隔离性和稳定性不如虚拟机,容器具有一定权限访问宿>- 主机内核,存在一下安全隐患

1、 使用要求

  • KVM基于硬件的完全虚拟化,需要硬件CPU虚拟化技术支持
  • 容器共享宿主机内核,可运行在主机的Linux的发行版,不用考虑CPU是否支持虚拟化技术

Docker的应用场景

  • 节省项目环境部署时间
  • 单项目打包
  • 整套项目打包
  • 新开源技术
  • 环境一致性
  • 持续集成
  • 微服务
  • 弹性伸缩

Docker 体系结构

  • containerd 是一个守护进程,使用runc管理容器,向Docker Engine提供接口
  • shim 只负责管理一个容器
  • runC是一个轻量级工具,只用来运行容器

Docker安装

安装社区版本docker
yum install -y yum-utils   device-mapper-persistent-data   lvm2
yum-config-manager     --add-repo     https://download.docker.com/linux/centos/docker-ce.repo
yum-config-manager --enable docker-ce-nightly #要每日构建版本的 Docker CE
yum-config-manager --enable docker-ce-test  
yum install docker-ce docker-ce-cli containerd.io

docker 启动

systemctl start docker

查看docker版本

docker version
docker info

镜像加速

阿里云镜像加速

sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
  "registry-mirrors": ["https://fwvjnv59.mirror.aliyuncs.com"]
}
EOF
# 重载所有修改过的配置文件
sudo systemctl daemon-reload
sudo systemctl restart docker

Docker常用方法

docker image镜像操作

命令 含义 案例
ls 查看全部镜像 docker image ls
search 查找镜像 docker search [imageName]
history 查看镜像历史 docker history [imageName]
inspect 显示一个或多个镜像详细信息 docker inspect [imageName]
pull 拉取镜像 docker pull [imageName]
push 推送一个镜像到镜像仓库 docker push [imageName]
rmi 删除镜像 docker rmi [imageName] docker image rmi 2
prune 移除未使用的镜像,没有被标记或补任何容器引用 docker image prune
tag 标记本地镜像,将其归入某一仓库 docker image tag [imageName] [username]/[repository]:[tag]
export 导出容器文件系统tar归档文件创建镜像 docker export -o mysqlv1.tar a404c6c174a2
import 导入容器快照文件系统tar归档文件创建镜像 docker import mysqlv1.tar wp/mysql:v2
save 保存一个或多个镜像到一个tar归档文件 docker save -o mysqlv2.tar wp/mysqlv2:v3
load 加载镜像存储文件来自tar归档或标准输入 docker load -i mysqlv2.tar
build 根据Dockerfile构建镜像

docker 容器操作

命令 含义 案例
run 从镜像运行一个容器 docker run ubuntu /bin/echo ‘hello-world’
ls 列出容器 docker container ls
inspect 显示一个或多个容器详细信息 docker inspect
attach 要attach上去的容器必须正在运行,可以同时连接上同一个container来共享屏幕 docker attach
stats 显示容器资源使用统计 docker container stats
top 显示一个容器运行的进程 docker container top
update 显示一个容器运行的进程 docker container update
port 更新一个或多个容器配置 docker container port
ps 查看当前运行的容器 docker ps -a -l
kill [containerId] 终止容器(发送SIGKILL ) docker kill [containerId]
rm [containerId] 删除容器 docker rm [containerId]
start [containerId] 启动已经生成、已经停止运行的容器文件 docker start [containerId]
stop [containerId] 终止容器运行 (发送 SIGTERM ) docker stop [containerId]
logs [containerId] 查看 docker 容器的输出 docker logs [containerId]
exec [containerId] 进入一个正在运行的 docker 容器执行命令 docker container exec -it [containerID] /bin/bash
cp [containerId] 从正在运行的 Docker 容器里面,将文件拷贝到本机 docker container cp [containID]:app/package.json .
commit [containerId] 创建一个新镜像来自一个容器 docker commit -a “wp” -m “mysql” a404c6c174a2 mynginx:v1

docker 数据盘操作

  • volume
#创建数据盘
docker volume create nginx-vol
docker volume ls
docker volume inspect nginx-vol
#把nginx-vol数据卷挂载到/usr/share/nginx/html,挂载后容器内的文件会同步到数据卷中
docker run -d  --name=nginx1 --mount src=nginx-vol,dst=/usr/share/nginx/html nginx
docker run -d  --name=nginx2  -v nginx-vol:/usr/share/nginx/html -p 3000:80 nginx
#删除数据卷
docker container stop nginx1 #停止容器
docker container rm nginx1 #删除容器
docker volume rm nginx-vol  #删除数据库

  • Bind mounts
#此方式与Linux系统的mount方式很相似,即是会覆盖容器内已存在的目录或文件,但并不会改变容器内原有的文件,当umount后容器内原有的文件就会还原
#创建容器的时候我们可以通过-v或--volumn给它指定一下数据盘
#bind mounts 可以存储在宿主机系统的任意位置
#如果源文件/目录不存在,不会自动创建,会抛出一个错误
#如果挂载目标在容器中非空目录,则该目录现有内容将被隐藏
docker run -v /mnt:/mnt -it --name logs centos bash
cd /mnt
echo 1 > 1.txt
docker inspect logs
#可以查看到挂载信息
"Mounts": [
    {
        "Source":"/mnt/sda1/var/lib/docker/volumes/dea6a8b3aefafa907d883895bbf931a502a51959f83d63b7ece8d7814cf5d489/_data",
        "Destination": "/mnt",
    }
]
# 指定数据盘容器
docker create -v /mnt:/mnt --name logger centos
docker run --volumes-from logger --name logger3 -i -t centos bash
cd /mnt 
touch logger3
docker run --volumes-from logger --name logger4 -i -t centos bash
cd /mnt
touch logger4

docker 网络
安装Docker时,它会自动创建三个网络,bridge(创建容器默认连接到此网络)、 none 、host

  • None:该模式关闭了容器的网络功能,对外界完全隔离
  • host:容器将不会虚拟出自己的网卡,配置自己的IP等,而是使用宿主机的IP和端口。
  • bridge 桥接网络,此模式会为每一个容器分配IP
    可以使用该–network标志来指定容器应连接到哪些网络
#bridge模式使用 --net=bridge 指定,默认设置
docker network ls #列出当前的网络
docker inspect bridge #查看当前的桥连网络
docker run -d --name nginx1 nginx
docker run -d --name nginx2 --link nginx1 nginx
docker exec -it nginx2 bash
apt update
apt install -y inetutils-ping  #ping
apt install -y dnsutils        #nslookup
apt install -y net-tools       #ifconfig
apt install -y iproute2        #ip
apt install -y curl            #curl
cat /etc/hosts
ping nginx1

# none模式使用--net=none指定
# --net 指定无网络
docker run -d --name nginx_none --net none nginx
docker inspect none
docker exec -it nginx_none bash
ip addr

# host模式使用 --net=host 指定
docker run -d --name nginx_host --net host nginx
docker inspect host
docker exec -it nginx_host bash
ip addr

端口映射

# 查看镜像里暴露出的端口号
docker image inspect nginx
"ExposedPorts": {"80/tcp": {}}
# 让宿主机的8080端口映射到docker容器的80端口
docker run -d --name port_nginx -p 8080:80  nginx
# 查看主机绑定的端口
docker container port port_nginx

#指向主机的随机端口
docker run -d --name random_nginx --publish 80 nginx
docker port random_nginx

docker run -d --name randomall_nginx --publish-all nginx
docker run -d --name randomall_nginx --P nginx

#创建自定义网络
docker network create --driver bridge myweb
# 查看自定义网络中的主机
docker network inspect myweb
# 创建容器的时候指定网络 指定同一个网络的容器是可以互相通信的
docker run -d --name mynginx1  --net myweb nginx
docker run -d --name mynginx2  --net myweb nginx
docker exec -it mynginx2 bash
ping mynginx1

# 连接到指定网络
docker run -d --name mynginx3   nginx
docker network connect  myweb mynginx3
docker network disconnect myweb mynginx3

# 移除网络
docker network rm myweb

compose 暂时先不说,暂时用到的不多,主要做编排使用,我们现在做的前端打包就用到了nginx,没有使用到node和数据库,所以我们选型就不使用docker-compose
当然docker-compose对于多个镜像可以统一管理,启动关闭移除都很方便

部署环境

node环境部署

安装完docker环境 继续安装node环境

nvm: # nvm管理node版本
curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.31.1/install.sh | bash
source ~/.bash_profile
nvm ls
nvm install stable 安装最新的稳定版本
nvm use stable
nrm:# 切换node镜像,修改源为淘宝镜像
npm i -g nrm
nrm use taobao

安装pm2 部署线上 node服务

npm i -g pm2
cd /root/webhook
pm2 start webhook.js --name webhook --watch
pm2 list | pm2 ls

还在使用命令行执行么,太low了,得升级升级
这边写了个shell脚本,资源初始化脚本,一个命令完成环境资源的安装
env-init.sh 可以拷贝到服务器 一键去部署环境 从此解放双手

#!/bin/bash
echo 'docker 环境初始化'
function git_install() {
    echo "检查Git......"
    git --version
    if [ $? -eq  0 ]; then
     echo "检查到Git已安装!"
    else
      yum -y install git
      yum -y install sshpass
    fi
    echo "git和sshpass安装完成!"
}
function docker_install()
{
    echo "检查Docker......"
    docker -v
  if [ $? -eq  0 ]; then
      echo "检查到Docker已安装!"
  else
      echo "安装docker环境..."
      yum install -y yum-utils   device-mapper-persistent-data   lvm2
      yum-config-manager     --add-repo     https://download.docker.com/linux/centos/docker-ce.repo
      yum-config-manager --enable docker-ce-nightly #要每日构建版本的 Docker CE
      yum-config-manager --enable docker-ce-test  
      yum install -y docker-ce docker-ce-cli containerd.io

      echo '启动docker'
      systemctl start docker

      echo '查看docker'
      docker version
      echo "安装docker环境...安装完成!"
  fi
}
# 执行函数
docker_install
git_install

# nrm 是否安装
function nvm_install()
{
    nvm --version
    if [ $? -eq  0 ]; then
       echo "检查到nvm已安装!"
       source /root/.bashrc
       nvm install v13.14.0 #安装最新的稳定版本
       nvm use v13.14.0
       echo "安装node环境...安装完成!"
    else
      source /root/.bashrc
        echo "安装nvm失败..."
    fi
}

# node 是否安装
function node_install()
{
    echo "检查node......"
    node -v
    if [ $? -eq  0 ]; then
        echo "检查到Node已安装!"
    else
        echo "安装nvm环境..."
       curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.31.1/install.sh | bash
       source /root/.bashrc
       nvm_install
    fi
}

# node_module库 安装监测
function node_module_install()
{
      node --version
    if [ $? -eq  0 ]; then
      echo "安装nrm源和pm2库"
      nrm_install
      pm2_install
    else
        echo "node环境未安装成功"
    fi
}

# nrm 安装监测
function nrm_install()  {
    echo "监测nrm源..."
    nrm --version
    if [ $? -eq 0 ]; then
    echo "已安装nrm源"
    else 
    npm i -g nrm
    nrm use taobao
    echo "安装nrm源成功"
    fi
}

# pm2 安装监测
function pm2_install()  {
    echo "监测pm2库..."
    pm2 --version
    if [ $? -eq  0 ]; then
    echo "已安装pm2库"
    else 
    npm i -g pm2
    echo "安装pm2库成功"
    fi
}

# 执行函数
echo '安装node环境'
node_install
node_module_install

# 如果已经安装过node,确认下是否更新过~/.bash_profile,没有则添加,也可以安装nvm去管理node export NODE_ENV=/root/node/node-v12.16.2-linux-x64 PATH=$PATH:$HOME/bin:$NODE_ENV/bin 刷新配置文件 source ~/.bash_profile

集成项目搭建

回想起以前的前端部署都是前端打个目标文件,压缩成压缩包或者rpm安装包去,如果有多个环境还需要一步步的去连服务器去手动
为了解决这种耗人力的工作,这边推出了一款简易的docker项目
我们可以把其中一台服务器配置成服务器,用来编译新镜像新镜像,然后直接拷贝镜像到别的服务器直接启动

现在我们新建一个node项目 docker-hook
此项目的核心是通过用户点击页面上的触发去动态调用sh去处理我们的脚本
中间一版本我们是通过接口调用触发,发现不是很好用,所以打算做一个可视化平台去使用
也可以通过gitHub的webhook去动态触发CI/CD,提交即部署,这边我就不贴代码了
这边主要讲思路,贴上部分代码,如果有需要优化的部分麻烦指正

// 本项目使用的是通过node的child_process spawn开启一个子进程去处理sh命令
// console log日志是通过morgan 自定义输出
// 每个模块的sh脚本都会通过winston把实时日志存储到对应的模块日志文件中,文件大问题,我们就按天生成一个文件日志
/** logger.js **/
const winston=require('winston');
const { APP_LIST } = require('./constant')
const { loggerTime } = require('./util')

const loggerList = {};
APP_LIST.forEach(item => {
  loggerList[item.loggerName] = winston.createLogger({
    transports: [
        new (winston.transports.Console)(),
        new (winston.transports.File)({ 
            filename: `public/logs/${item.loggerName}-${loggerTime()}.log`,
            timestamp:'true', 
            maxsize: 10485760, //日志文件的大小
            maxFiles: 10 })
    ]});
});
loggerList['init'] = winston.createLogger({
  transports: [
      new (winston.transports.Console)(),
      new (winston.transports.File)({ 
          filename: `public/logs/init-${loggerTime()}.log`,
          timestamp:'true', 
          maxsize: 10485760, //日志文件的大小
          maxFiles: 10 })
  ]});

module.exports = loggerList;

/** app.js **/
let { spawn } = require('child_process');
/**
 * 统一处理shell脚本执行
 */
function handleShellFile(projectName, shellPath, res, req) {
  return resolveFile(shellPath).then(data => {
    // 判断当前是否是成功
    if(!data.success) {
      errorHandle(res);
    }
    let child = spawn('sh', [data.filePath])
    let buffers = [];
    child.stdout.on('data', (buffer) => {
      buffers.push(buffer);
      console.log('实时日志:', buffer.toString());
      logger[projectName] && logger[projectName].log("info", `实时日志:${buffer.toString()}`);
    })
    child.stdout.on('end',function(buffer){
      let logs = Buffer.concat(buffers, buffer).toString();
      console.log('执行完毕');
      logger[projectName] && logger[projectName].log("info", '执行完毕');
      res.setHeader('Content-Type', 'application/json');
      res.end(JSON.stringify({ok: true}))
    });
    child.on('close', (code) => {
      if (code !== 0) {
        console.log(`子进程退出,退出码 ${code}`);
      }
    });
  }, error => {
    // 错误处理显示返回
    errorHandle(res);
  })
}

shell文件介绍:

├─ docker-hook
│  ├─ sh // shell脚本文件
│  │  ├─ Archer-front-image.sh // 前端版本复制镜像
│  │  ├─ Archer-front-remote.sh // 前端版本远程
│  │  ├─ Archer-front.sh // 前端版本本地打包编译打包(本地使用)
│  │  ├─ ar-mock-image.sh // armock项目复制镜像
│  │  ├─ ar-mock-remote.sh // armock项目远程
│  │  ├─ ar-mock.sh // armock项目本地打包编译打包(本地使用)
│  │  ├─ env-init.sh // 环境初始化
│  │  └─ project-init.sh // git项目初始化,帮忙建目录

env-init.sh 上面已经介绍,资源的整合初始化可以都放到这个文件里面,当前我这边用到了 docker, git, sshpass, nvm, nrm, node, nrm, pm2
project.sh 文件主要是建立文件目录,git clone文件并为后续的部署做准备
Archer-front.sh 更新代码,执行dockerfile(里面主要是nginx配置和拷贝生成之后的静态资源文件)部署,镜像生成,容器部署一个文件搞定,这边做成容器的好处是好移植到其他服务器

#!/bin/bash
WORK_PATH='/root/front'
cd $WORK_PATH
echo "清除老代码"
git reset --hard origin/master
git clean -f
echo "拉取最新代码"
git pull origin master
echo "删除node_modules文件"
rm -rf ./node_modules
echo "重新安装依赖"
npm i
echo "编译打包"
npm run build
echo "开始执行构建"
docker build -f ./docker/Dockerfile -t archer-front:1.0 .
echo "停止旧的容器并删除容器"
docker stop archer-front-container
docker rm archer-front-container
echo "启动新容器"
docker run -p 11001:11001 -v /etc/hosts:/etc/hosts --name archer-front-container -itd archer-front:1.0

那么多节点部署怎么办呢?
我们可以考虑把当前的这个镜像导出并导入加载
Archer-front-image.sh

#!/bin/bash
echo "进入目录/root/images"
WORK_PATH='/root'
cd $WORK_PATH
if [ ! -d images  ];then
  mkdir images
fi
IMAGES_PATH='images'
cd $IMAGES_PATH
echo "开始拷贝前端镜像"
docker save -o image-Archer-front.tar archer-front:1.0
echo "拷贝前端镜像完成"

其他节点怎么来拿呢?可以通过scp来拷贝这边打包出来的镜像去使用啊,这就是Archer-front-remote.sh里面的实现

查看日志功能主要是通过定时刷新调用接口去实现的,有些low,自己使用不会有那么大的量,所以没走实时刷新。
我们再来看看效果,是不是很香。

67_1.png一次,终身好用

第一波优化之后

经过半个月的使用,我们团队还是发现了一些问题

1、 子节点需要访问不同的子节点对应部署的地址去点击(比较烦)
2、 子节点环境和发包环境没有做权限控制,看到的内容一样,但是子节点应该不支持打包,只允许拉取打包环境的镜像去部署(未做隔离)
3、子节点没法做到配置
4、 本地和远程打包概念有理解偏差
5、 日志资源访问bug:当天未创建日志获取日志资源报错

问题说完了,那么该动手优化了

远程子节点维护+部署

针对于问题1,2,3,我们整体做了优化,打包环境支持 远程,复制镜像,本地打包, 子节点呢?只支持本地,子节点还要可配置,怎么办呢,本着不想麻烦的思想,用到了commander命令配置

var app = require('../app');
var commander = require('commander');
commander.option('-p, --port <val>', "please input server port")
         .option('-l, --list <val>', "please input ip port")
         .option('-n, --env <val>', "please input env ").parse(process.argv);
let config = {
  port: 4000,
  list: ['172.118.38.11', '172.118.38.12', '172.118.38.13'], // 默认设置开发环境ip节点
  env: 'local', // 默认设置本地
}
Object.assign(config, commander);
console.log('config', config.env, config.port)
/**
 * Get port from environment and store in Express.
 */
app.set('port', config.port);
app.set('ipList', config.list); // 设置ip节点
app.set('env', config.env); // 设置环境信息 local 本地 remote 远程

如上面代码所示,我们允许部署的时候去设置默认值
port 配置服务启动端口号,默认4000
list 配置子节点端口,不设置默认为预设值的列表
env 配置环境变量,来区分是本地还是远程子节点环境
我们希望我们系统支持维护子节点

/**
 * 获取节点列表
 */
app.get('/getIpList', (req, res) => {
  console.log(app.get('ipList'), app.get('env'));
  return res.json({
    success: true,
    data: app.get('ipList'),
    env: app.get('env'),
  })
})
/**
 * 新增节点
 */
app.get('/addIP', (req, res) => {
  const { ip } = req.query;
  app.set('ipList', app.get('ipList').concat([ip]));
  return res.json({
    success: true,
    data: app.get('ipList')
  })
})

/**
 * 新增节点
 */
app.get('/removeIP', (req, res) => {
  const { index } = req.query;
  app.get('ipList').splice(index, 1);
  return res.json({
    success: true,
    data: app.get('ipList')
  })
})

我们提供下接口去使用,并且页面上做支持

67_2.png那么来到我们的节点远程部署了,因为我们在子节点上已经部署了我们的应用,所以我们可以去调用暴露出来的接口,我们需要通过http client去调用远程接口

/**
 * 远程节点
 */
app.get('/remoteBuildNode', (req,res) => {
  const { node, projectName } = req.query;
  const config = {
    hostname: node,
    port: 4000,
    path: `/buildPackage?projectName=${projectName}`,
    method: 'GET',
  };
  // 远程请求数据
  let requet = http.request(config, (httpRes)=>{
    let data = '';
    httpRes.on('data', (chunk) => {
      console.log('httpRes-',chunk.toString());
      data += chunk.toString();
    })
    httpRes.on('end', () => {
      let result = data && JSON.parse(data);
      console.log('result', result);
      return res.json({
        success: result.ok,
      });
    });  
  });
  requet.end();
})

一个个节点点击也是很麻烦呀,能否做个合并呢,那么就在前端用promise.all做吧

/**
 * 本地远程
 */
remoteBuildPackage(item) {
  this.buildLoading[item.loggerName] = true;
  Promise.all(this.nodeList.map(node => fetch(`/remoteBuildNode?&node=${node}&projectName=${item.loggerName}`) ))
  .then(data => {
    let result = data.every(dataItem => dataItem.ok)
    this.buildLoading[item.loggerName] = false;
    result ? this.$Notice.success({
        title: '成功',
        desc: `${item.title}远程成功`
    }): this.$Notice.error({
        title: '部分失败',
        desc: `${item.title}远程部分失败`
    });;
  })
  .catch(err => {
    this.buildLoading[item.loggerName] = false;
    this.$Notice.error({
        title: '失败',
        desc: `${item.title}远程过程异常`
    });
  });
},

节点的独立部署和整合部署都做完了
那么我们部署还需要注意什么呢?
权限隔离啊~~~ 我们使用env来做区分

"scripts": {
    "local": "node ./bin/www -n local",
    "remote": "node ./bin/www -n remote"
  },
  pm2 start npm --name webhook -- run remote # 远程子节点部署
  pm2 start npm --name webhook -- run local # 打包环境部署

日志文件不实时打印问题

修改了logger.js文件对应的文件初始化

const winston=require('winston');
const { APP_LIST } = require('./constant')
const { loggerTime } = require('./util')

function createLogger() {
  const loggerList = {};
  APP_LIST.forEach(item => {
    loggerList[item.loggerName] = winston.createLogger({
      transports: [
          new (winston.transports.Console)(),
          new (winston.transports.File)({ 
              filename: `public/logs/${item.loggerName}-${loggerTime()}.log`,
              timestamp:'true', 
              maxsize: 10485760, //日志文件的大小
              maxFiles: 10 })
      ]});
  });
  loggerList['init'] = winston.createLogger({
    transports: [
        new (winston.transports.Console)(),
        new (winston.transports.File)({ 
            filename: `public/logs/init-${loggerTime()}.log`,
            timestamp:'true', 
            maxsize: 10485760, //日志文件的大小
            maxFiles: 10 })
    ]});
    return loggerList;
 } 
 const loggerList = createLogger();

module.exports = {
  loggerList,
  createLogger
};

当天部署了服务,创建了日志文件,初始化了日志文件,可以正常使用
第二天,我们再来使用,我们手动创建了日志文件,没有初始化,会导致日志文件写入不进去,需要我们手动初始化下日志文件createLogger(),这样才能确保我们正常日志使用。

第一波整改之后成果

打包环境

67_3.png子节点环境

67_4.png

后续规划

  • 远程整合部署日志展示问题,是整合一起展示还是独立展示问题?
  • 打包部署环境还是使用的原始方式部署,没有使用容器,考虑后期是否上容器,只需要部署一次
  • 项目后续扩展方案,当前只固定维护2个项目
  • 有定时任务需求的话,是否要考虑和jekins配合使用
  • pc端还是不方便,考虑手机端接入方案,机器人~~~
    暂时想到这么多了~~~后续再补充
    大家有什么好想法,或者说你们团队是如何实现CI,CD的可以在评论区讨论。

文章永久链接:https://tech.souyunku.com/42701

未经允许不得转载:搜云库技术团队 » 前端自定义CICD Docker篇

JetBrains 全家桶,激活、破解、教程

提供 JetBrains 全家桶激活码、注册码、破解补丁下载及详细激活教程,支持 IntelliJ IDEA、PyCharm、WebStorm 等工具的永久激活。无论是破解教程,还是最新激活码,均可免费获得,帮助开发者解决常见激活问题,确保轻松破解并快速使用 JetBrains 软件。获取免费的破解补丁和激活码,快速解决激活难题,全面覆盖 2024/2025 版本!

联系我们联系我们