【微服务部署】五、Jenkins+Docker一键打包部署NodeJS(Vue)项目的Docker镜像步骤详解

2023-11-10

  NodeJS(Vue)项目也可以通过打包成Docker镜像的方式进行部署,原理是先将项目打包成静态页面,然后再将静态页面直接copy到Nginx镜像中运行。

一、服务器环境配置

  前面说明了服务器Nginx的安装和配置,这里稍微有些不同,但是因为此文是用Nginx镜像和前端镜像页面同时部署的方式来打包发布的,所以这里不再需要建立/data/container/nginx/html目录,因为要发布的静态页面已经在Nginx镜像中的/nginx/html目录了。这里也减少了手动部署安装Nginx的步骤,而是在Jenkins任务中调用shell命令自动执行安装。

1. 新建Dockerfile文件,用于定义Nginx镜像,及将打包成功的静态文件复制到镜像中,此文件放在前端项目的根目录下,Jenkins打包时会从此处查找Dockerfile文件。
FROM nginx:latest
# 维护者信息
MAINTAINER gitegg
# 将生成的静态页面文件复制到nginx的/usr/share/nginx/html/目录
COPY dist/ /usr/share/nginx/html/
# 容器启动时运行的命令
CMD ["nginx", "-g", "daemon off;"]
2. 部署及备份目录准备
  • 新建 /opt/tmp 目录,用于Jenkins打包后,通过 Publish Over SSH插件将包传输到服务器的临时目录(如果前面创建过,这里无需再创建)。
  • 新建 /opt/bak 目录,用于存储所有部署过的包备份,方便后续版本回滚。此目录可能会占用很大空间,所以需要选择一个磁盘空间大的挂载目录(如果前面创建过,这里无需再创建)。
  • 新建 /opt/script 目录,用于Jenkins将包传输完成之后,执行安装、备份操作的相关命令脚本(如果前面创建过,这里无需再创建)。
  • 新建 /data/container/nginx/www,映射Nginx容器内的/var/www目录。
  • 新建 /data/container/nginx/logs,映射Nginx容器内的/var/log/nginx目录,存放nginx运行日志。
  • 新建 /data/container/nginx/etc,映射Nginx容器内的/etc/nginx目录
  • 新建 /data/container/nginx/etc/nginx.conf,映射Nginx容器内的/etc/nginx/nginx.conf配置文件
mkdir -p /opt/tmp /opt/bak /opt/script /data/container/nginx/www /data/container/nginx/logs  /data/container/nginx/etc
chmod -R 777 /opt/tmp /opt/bak /opt/script /data/container/nginx/www /data/container/nginx/logs  /data/container/nginx/etc
3.根据系统部署要求编写Nginx配置文件nginx.conf,以下是简单的配置方法,正常情况下https请求还需要配置ssl证书,还有ipv6配置等,后面详细讲解Nginx配置。一定要将修改后的nginx.conf文件放到/data/container/nginx/etc/目录下,否则nginx启动时会报错找不到配置文件。
    server {
        listen 80;
        server_name  域名;

        gzip on;
        gzip_buffers 32 4K;
        gzip_comp_level 6;
        gzip_min_length 100;
        gzip_types application/javascript text/css text/xml text/plain application/x-javascript image/jpeg image/gif image/png;
        gzip_disable "MSIE [1-6]\."; 
        gzip_vary on;

        #charset koi8-r;

        access_log  /var/log/nginx/portal.access.log  main;

        location / {
                root /nginx/html/gitegg_portal;
                try_files $uri $uri/ /index.html;
                index  index.html index.htm;
        }

        location /gitegg-api/ {
            proxy_set_header Host $http_host;               
            proxy_set_header X-Real-Ip $remote_addr;
            proxy_set_header REMOTE-HOST $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_pass http://172.17.0.1:8080/;
        }
    }
4. 部署脚本编写说明
  • 定义入参,可以通过Jenkins任务将参数传入脚本中,我们定义了下面7个参数:
    container_name=portal-server : 容器名称
    image_name=portal-server : 镜像名称
    version=latest : 镜像版本
    portal_port=80: 宿主主机端口映射
    server_port=80: 容器内服务端口
    portal_ssl_port=443: 宿主主机端口映射
    serve_sslr_port=443: 容器内服务端口
  • 对参数进行检查,是否未传入参数,这里根据自己的实际情况判断,比如必须传入哪些参数,就设置参数的个数不能小于几。
echo "param validate"
if [ $# -lt 1 ]; then
  echo "you must use like this : ./publish_docker_portal.sh <container_name> <image_name> <version> [portal port] [server port] [portal ssl port] [server ssl port]"  
  exit  
fi
  • 入参赋值,如果有参数传入,则取服务参数,如果没有参数传入则取默认值
if [ "$1" != "" ]; then
   container_name="$1"
fi
echo "container_name=" $container_name
if [ "$2" != "" ]; then
   image_name="$2"
fi
if [ "$3" != "" ]; then
   version="$3"
fi
echo "version=" $version
if [ "$4" != "" ]; then
   portal_port="$4"
fi
echo "portal_port=" $portal_port
if [ "$5" != "" ]; then
   server_port="$5"
fi
echo "server_port=" $server_port
if [ "$6" != "" ]; then
   portal_ssl_port="$6"
fi
echo "portal_ssl_port=" $portal_ssl_port
if [ "$7" != "" ]; then
   serve_sslr_port="$7"
fi
echo "serve_sslr_port=" $serve_sslr_port
  • 停止并删除容器
echo "执行docker ps"
docker ps 
if [[ "$(docker inspect $container_name 2> /dev/null | grep $container_name)" != "" ]]; 
then 
  echo $container_name "容器存在,停止并删除"
  echo "docker stop" $container_name
  docker stop $container_name
  echo "docker rm" $container_name
  docker rm $container_name
else 
  echo $container_name "容器不存在"
fi
  • 停止并删除镜像
# 删除镜像
echo "执行docker images"
docker images
if [[ "$(docker images -q $image_name 2> /dev/null)" != "" ]]; 
then 
  echo $image_name '镜像存在,删除镜像'
  docker rmi $(docker images -q $image_name 2> /dev/null) --force
else 
  echo $image_name '镜像不存在'
fi
  • 备份本次安装镜像包
#bak image
echo "bak image" $image_name
BAK_DIR=/opt/bak/docker/$image_name/`date +%Y%m%d`
mkdir -p "$BAK_DIR"
cp "/opt/tmp/portal-image.tar" "$BAK_DIR"/"$image_name"_`date +%H%M%S`.tar
  • 执行安装镜像包命令
echo "docker load" $image_name
docker load --input /opt/tmp/portal-image.tar
  • 执行运行命令
echo "docker run" $image_name
docker run -d -p $portal_port:$server_port -p $portal_ssl_port:$server_ssl_port --name=$container_name -e TZ="Asia/Shanghai" --restart=always -v /data/container/nginx/www:/var/www -v /data/container/nginx/logs:/var/log/nginx -v /data/container/nginx/etc:/etc/nginx -v /data/container/nginx/etc/nginx.conf:/etc/nginx/nginx.conf -v /etc/localtime:/etc/localtime -v /usr/share/zoneinfo/Asia/Shanghai:/etc/timezone -v /bxl/container/nginx/ssl:/nginx/ssl $image_name
  • 删除安装文件,因为前面已经备份过了,所以这里将临时安装文件删除
echo "remove tmp " $image_name
rm -rf /opt/tmp/portal-image.tar
  • 打印执行完成的命令
echo "Docker Portal is starting,please try to access $container_name conslone url"
  • 完整的安装部署脚本
container_name=portal-server
image_name=portal-server
version=latest
portal_port=80
server_port=80
portal_ssl_port=443
serve_sslr_port=443
echo "param validate"
if [ $# -lt 1 ]; then  
  echo "you must use like this : ./publish_docker_portal.sh <container_name> <image_name> <version> [portal port] [server port] [portal ssl port] [server ssl port]"  
  exit  
fi
if [ "$1" != "" ]; then
   container_name="$1"
fi
echo "container_name=" $container_name
if [ "$2" != "" ]; then
   image_name="$2"
fi
if [ "$3" != "" ]; then
   version="$3"
fi
echo "version=" $version
if [ "$4" != "" ]; then
   portal_port="$4"
fi
echo "portal_port=" $portal_port
if [ "$5" != "" ]; then
   server_port="$5"
fi
echo "server_port=" $server_port
if [ "$6" != "" ]; then
   portal_ssl_port="$6"
fi
echo "portal_ssl_port=" $portal_ssl_port
if [ "$7" != "" ]; then
   serve_sslr_port="$7"
fi
echo "serve_sslr_port=" $serve_sslr_port

echo "执行docker ps"
docker ps 
if [[ "$(docker inspect $container_name 2> /dev/null | grep $container_name)" != "" ]]; 
then 
  echo $container_name "容器存在,停止并删除"
  echo "docker stop" $container_name
  docker stop $container_name
  echo "docker rm" $container_name
  docker rm $container_name
else 
  echo $container_name "容器不存在"
fi
# 删除镜像
echo "执行docker images"
docker images
if [[ "$(docker images -q $image_name 2> /dev/null)" != "" ]]; 
then 
  echo $image_name '镜像存在,删除镜像'
  docker rmi $(docker images -q $image_name 2> /dev/null) --force
else 
  echo $image_name '镜像不存在'
fi

#bak image
echo "bak image" $image_name
BAK_DIR=/opt/bak/docker/$image_name/`date +%Y%m%d`
mkdir -p "$BAK_DIR"
cp "/opt/tmp/portal-image.tar" "$BAK_DIR"/"$image_name"_`date +%H%M%S`.tar

echo "docker load" $image_name
docker load --input /opt/tmp/portal-image.tar

echo "docker run" $image_name
docker run -d -p $portal_port:$server_port -p $portal_ssl_port:$server_ssl_port --name=$container_name -e TZ="Asia/Shanghai" --restart=always -v /data/container/nginx/www:/var/www -v /data/container/nginx/logs:/var/log/nginx -v /data/container/nginx/etc:/etc/nginx -v /data/container/nginx/etc/nginx.conf:/etc/nginx/nginx.conf -v /etc/localtime:/etc/localtime -v /usr/share/zoneinfo/Asia/Shanghai:/etc/timezone -v /bxl/container/nginx/ssl:/nginx/ssl $image_name

echo "remove tmp " $image_name
rm -rf /opt/tmp/portal-image.tar

echo "Docker Portal is starting,please try to access $container_name conslone url"
二、新建Jenkins配置打包任务,打包部署NodeJS(Vue)镜像
1. 新建任务前,安装Docker Pipeline插件,使用Pipeline流水线任务构建部署,安装Jenkins插件相关内容,请查看前面部署Jenkins相关文章。

Docker Pipeline插件

2. 安装完插件之后,新建一个流水线任务。

流水线任务

3. 和之前的任务一样,选择“丢弃旧的构建”,设置保持构建的最大个数为5。

丢弃旧的构建

4. 下拉到“流水线”配置,选择Pipeline script

流水线
流水线脚本如下:

node {
    # 从gitlab下载代码
    stage('Preparation') { // for display purposes
        // Get some code from a GitHub repository
        echo "checkout from GitLab"
        checkout scmGit(branches: [[name: '*/main']], extensions: [], userRemoteConfigs: [[credentialsId: 'git_username', url: 'http://127.0.0.1:9091/test/test.git']])
    }
     # NodeJS打包
    stage('Build NodeJS Vue') {
        echo "build nodejs code"
        nodejs('Node17') {
            sh 'echo $PATH'
            sh 'node -v'
            sh 'pnpm -v'
            sh 'pnpm install'
            sh 'pnpm run build'
        }
    }
     # 此处判断本机打包是否有容器,如果有的话需要删除
    stage('Delete Old Docker Container') {
        echo "delete docker container"
        sh '''if [[ "$(docker inspect $container_name 2> /dev/null | grep $container_name)" != "" ]]; 
        then 
          echo $container_name "容器存在,停止并删除"
          echo "docker stop" $container_name
          docker stop $container_name
          echo "docker rm" $container_name
          docker rm $container_name
        else 
          echo $container_name "容器不存在"
        fi'''
    }
    # 此处判断本机打包是否有镜像,如果有的话需要删除
    stage('Delete Old Docker Image') {
        echo "delete docker image"
        sh '''if [[ "$(docker images -q gitegg-portal 2> /dev/null)" != "" ]]; 
            then 
              echo gitegg-portal \'镜像存在,删除镜像\'
              docker rmi $(docker images -q gitegg-portal 2> /dev/null) --force
            else 
              echo gitegg-portal \'镜像不存在,创建镜像\'
            fi'''
    }
    # Docker打包镜像,并保存为tar
    stage('Build Docker Image') {
        echo "start docker build portal code"
        // Run the docker build
        docker.build 'gitegg-portal'
        
        echo "save docker images tar"
        sh 'docker save -o portal-image.tar gitegg-portal'
    }
    # 删除安装在本机的Docker镜像,非tar包
    stage('Delete New Docker Image') {
        echo "delete docker image"
        sh '''if [[ "$(docker images -q gitegg-portal 2> /dev/null)" != "" ]]; 
            then 
              echo gitegg-portal \'镜像存在,删除镜像\'
              docker rmi $(docker images -q gitegg-portal 2> /dev/null) --force
            else 
              echo gitegg-portal \'镜像不存在,创建镜像\'
            fi'''
    }
    # 将Docker镜像tar包发送到服务器并执行部署命令
    stage('Send Docker Image') {
        echo "send docker image"
        sshPublisher(publishers: [sshPublisherDesc(configName: 'Test', transfers: [sshTransfer(cleanRemote: false, excludes: '', execCommand: '/opt/script/publish_docker_portal.sh gitegg-portal gitegg-portal latest 8130 8130 4413 4413', execTimeout: 120000, flatten: false, makeEmptyDirs: false, noDefaultExcludes: false, patternSeparator: '[, ]+', remoteDirectory: '', remoteDirectorySDF: false, removePrefix: '', sourceFiles: 'portal-image.tar')], usePromotionTimestamp: false, useWorkspaceInPromotion: false, verbose: false)])
    }
    
    stage('Publish Results') {
        echo "End Publish Portal"
    }
}

12. 在任务左侧点击立即构建
  • 立即构建

点击立即构建

  • 流水线任务可以在右侧显示阶段视图
    阶段视图
  • 查看构建日志:点击立即构建之后,下方会出现进度条,点击进度条就可以进入构建日志界面。
    查看构建日志
    日志
13. 构建成功后,下方会给出构建成功提示。

任务执行成功

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【微服务部署】五、Jenkins+Docker一键打包部署NodeJS(Vue)项目的Docker镜像步骤详解 的相关文章

  • Jenkins 上的 XCode 项目陷入“codesign”

    我使用 Jenkins 与 XCode 插件进行持续集成 有一个 Jenkins 坚持的项目 usr bin codesign force sign 接下来是旋转器 永远旋转 我以前从未见过这个 以前有人见过这个吗 是配置文件问题还是证书问
  • 有没有办法将 Jenkins 与 Github Pull 请求结合使用?

    我希望 Jenkins 自动查找并运行属于开放拉取请求一部分的每个分支的测试套件 我还没有找到一些 Jenkins 插件 这可能吗 最近发布了一个新插件Jenkins Github 拉取请求构建器 https wiki jenkins ci
  • 如何将文件参数传递给詹金斯管道中的另一个构建作业?

    如何将当前工作区中的文件作为参数传递给构建作业 例如 build job other project parameters class FileParameterValue 真是一场噩梦 没有文档 查看了詹金斯代码等 尝试了一切 最后发现这
  • 有没有V型斗篷的反面?

    根据VueJS 文档 https v2 vuejs org v2 api v cloak v cloak 指令可用于隐藏未编译的 Mustache 绑定 直到 Vue 实例准备就绪 换句话说 我可以隐藏一个div或类似的东西 当 vue 准
  • Vuetify 自动完成类似项目未显示

    我的本地案例中有类似标题的自定义帖子API我尝试通过搜索查询显示帖子items array Data count 5 entries id 3 title Senior developer Python id 4 title Senior
  • 个人Vue 3组件包缺少模板或渲染函数

    我最近将自己的 Vue 3 组件上传到 NPM 以供其他人使用 当在其他项目中使用它时 它会发出以下警告 Vue warn Component is missing template or render function at
  • Mapbox JS SDK CSS样式表导致地图消失

    我在 VueJS 应用程序中使用 Mapbox JavaScript SDK 我可以毫无问题地显示地图 现在我想添加一些标记 我懂了在本页 https docs mapbox com mapbox gl js api 您需要先导入 CSS
  • 如何在 Jenkins 服务器上运行 Jest 测试

    我正在尝试运行我的Jest https facebook github io jest 在 Jenkins 部署期间进行测试 如果我 ssh 进入服务器 我可以 sudo 进入 Jenkins 用户并从工作区成功运行测试 但是 当我尝试从
  • 如何以编程方式启动 Vuetify 对话框并等待响应

    我对 Vue js 和 Vuetify 相当陌生 使用 AngularJS 好几年了 但我们公司正在转向 Vue js 我想要完成的是 当用户单击 登录 按钮时 它会执行一些检查 即用户名不能为空 并启动 Vuetify 对话框来提醒用户
  • FullCalendar-vue + Typescript:属性“getApi”不存在

    我尝试将 FullCalendar vue 与 Typescript 结合使用 但在访问其 API 时遇到错误 我的日历设置如下
  • 自动生成/删除詹金斯工作

    我正在寻找一种自动创建一组詹金斯作业的方法 通常在创建新的 git 分支之后 我已经为maven尝试过这个插件 http evgeny goldin com wiki Maven jenkins plugin http evgeny gol
  • 詹金斯配置文件问题

    检查依赖关系 找不到与 Nitin xxxxxxx xyzCAppStore 匹配的 iOS 配置文件 Xcode 找不到与 Nitin xxxxxxx xyzCAppStore 匹配的配置文件 安装配置文件 通过将其拖放到 Xcode 的
  • Jenkins GIT 包含从未构建过的区域

    我正在尝试使用包含区域在 Jenkins 中构建我的工作 但每当选中此选项时 民意调查结果总是说未检测到任何更改 我尝试了许多不同的路径 以及使用工作区进行 不进行强制轮询 结果是轮询从未检测到任何更改 但一旦我删除这些选项 它们就会在下一
  • 驱动程序在 Jenkins 中不是可执行错误,但在本地计算机 (MacBook) 中运行

    我正在 MacBook 上工作 当我通过testing xml文件运行测试时 我们的Jenkins服务器正在Linux服务器中运行 所有测试类都在运行 但是当我运行Jenkins构建时 它没有运行 错误提示驱动程序不可执行 我已经在 J e
  • Artifactory 插件中的“对等未经过身份验证”错误 - Jenkins

    我使用的是 Jenkins 版本 1 566 和 Artifactory 插件版本 2 2 2 我正在它自己的码头容器中运行artifactory 2 66 它以 http 方式运行 但最近我将其更改为 https 现在 如果我将 Jenk
  • 在 CI (Travis/Jenkins) 环境中使用 xcodebuild (Xcode 8) 和自动签名

    随着 Xcode 8 的发布 Apple 引入了一种管理签名配置的新方法 现在你有两个选择Manual and Automatic 根据 WWDC 2016 关于代码签名的会议 WWDC 2016 401 Xcode 应用签名的新增功能 h
  • vue js中的process.env.BASE_URL是什么?

    当我使用 vue cli 安装 vue 时手动选择预设 我偶然发现了 process env BASE URL 我试图在互联网上找到它 但无济于事 我找不到任何像样的解释 这是代码 const router new VueRouter mo
  • 可排序不拖动 safari 中表格的所有列

    我有一个vue引导表 https bootstrap vue org docs components table使用 v 槽为每个单元使用自定义模板 所有这些单元格都是自定义组件 我希望该表的行可以排序 也就是说 我希望用户能够拖放该表中的
  • 如何获取 vuejs 组件单元测试中定义的“this”变量

    我正在尝试在 npm 脚本中使用 mocha webpack 来测试 vuejs 组件 我在测试中像这样嘲笑 vuex 商店 const vm new Vue template div div
  • 简单的 Vue.js 计算属性说明

    我对 Vue js 并不陌生 但我会再次浏览文档 试图找出我第一次错过的任何内容 我在以下地方看到了这个声明使用计算属性的基本示例部分 https v2 vuejs org v2 guide computed html Basic Exam

随机推荐

  • 利用PCL点云下采样实现数据体素化

    利用PCL点云下采样实现数据体素化 PCL PCL Point Cloud Library 库集成了针对大体量级别的空间点数据处理所需要的算法和操作 降低了处理相关需求的复杂度 对快速建立点云数据文档和渲染有着很好的作用 体素化Voxeli
  • 100天精通Python(可视化篇)——第80天:matplotlib绘制不同种类炫酷柱状图代码实战(簇状、堆积、横向、百分比、3D柱状图)

    文章目录 0 专栏导读 1 普通柱状图 2 簇状柱形图 3 堆积柱形图 4 横向柱状图 5 横向双向柱状图 6 百分比堆积柱形图 7 3D柱形图 8 3D堆积柱形图
  • Xilinx Vivado 流水灯实验

    流水灯设计时需要考虑哪些因素 流水灯设计流程的基本步骤及各步骤主要功能 各文件的作用 流水灯IPI设计流程的基本步骤及各步骤主要功能 IP集成设计的优点 文件注释 verilog语言 当时这部分花时间自学的
  • python:thread模块

    该包在 Python 2 中属于正常可用状态 但在 Python 3 中处于即将废弃的状态 虽然还可以用 但包名被改为 thread 使用 thread 包首先要引入该包 在 Python 2 中使用下面的语句来引入 import thre
  • 实时音频编解码之十七 Opus解码 SILK解码

    本文谢绝任何形式转载 谢谢 5 2 Silk解码流程 解码器线性预测层主要使用长短时预测合成滤波器对激励信号滤波实现 线性预测层内部的工作带宽为NB MB以及WB 对于SWB以及FB的混合编码工作模式 线性预测层依然工作于WB带宽下 经过区
  • Qt Creator 5.9.9下载与安装图解详细教程

    Qt Creator 5 9 9下载与安装图解详细教程 一 Qt Creator 下载 推荐最新版5 9 9 网上可能推荐4 x x 但实际上不是做专业UI项目的话Qt Creator版本越新越好 其一 安装包给你集合到一个 exe里面 不
  • 期货开户手续费有哪些优惠?

    在网上随便找一位期货公司经纪人 直接说你有帐户但手续费高 现在想换一家手续费低的期货公司 这样通常就能开到最低手续费帐户了 或者直接点问 手续费能不能加一分 简单明了 如果手续费相同的情况下 还得考虑期货公司的保证金 交易软件 服务等因素来
  • php layui post文件上传,layui框架实现文件上传及TP3.2.3(thinkPHP)对上传文件进行后台处理操作示例...

    本文实例讲述了layui框架实现文件上传及TP3 2 3对上传文件进行后台处理操作 分享给大家供大家参考 具体如下 layui框架是1 0 9版本 首先html页面代码如下 js代码如下 layui use upload function
  • UDP网络基础知识简介

    作者简介 CSDN2021博客之星亚军 新星计划导师 博客专家 哪吒多年工作总结 Java学习路线总结 搬砖工逆袭Java架构师 关注公众号 哪吒编程 回复1024 获取Java学习路线思维导图 大厂面试真题 加入万粉计划交流群 一起学习进
  • OpenGL学习笔记(二)-着色器-纹理

    参考网址 LearnOpenGL 中文版 哔哩哔哩教程 第一章 入门 1 3 着色器 1 3 1 基本结构 利用着色器语言编写着色器 以顶点着色器和片段着色器为例 在着在顶点着色器中输出颜色变量vertexColor 在片段着色器中输入变量
  • JDK 17 营销初体验 —— 亚毫秒停顿 ZGC 落地实践

    前言 自 2014 年发布以来 JDK 8 一直都是相当热门的 JDK 版本 其原因就是对底层数据结构 JVM 性能以及开发体验做了重大升级 得到了开发人员的认可 但距离 JDK 8 发布已经过去了 9 年 那么这 9 年的时间 JDK 做
  • 如何理解凸优化中的共轭函数的定义?

    共轭函数的意义主要就是 一个函数即便不是凸函数 但通过共轭法获得一个凸函数 很方便求解全局最优解的问题 另外 共轭函数亦称对偶函数 极化函数 函数的某种对偶变换 过多的东西我就不再赘述了 此处我是想着重讲一讲为什么共轭函数是可以 保凸 的
  • 中国物流,驶入大航海时代

    出海的一体化 不仅仅是物流的一体化 更是产业链 供应链的一体化 在诸多问题下 想要帮助企业更好地出海 就不能只专注于自身的长板 而是需要先补齐短板 作者 斗斗 编辑 皮爷 出品 产业家 出海时代真的要来了 这种感觉从未如此强烈过 在过去两年
  • React项目中使用svg组件

    使用react svg模块 安装依赖 yarn add D react svg 新建index js文件 import React from react import ReactSVG from react svg function get
  • 【笔记】scanf函数:读取参照getchar()

    Reference 浅谈关于空格和回车对于输入函数的影响 程序猿的探索之路的博客 CSDN博客 c语言scanf输入打空格的影响 Note 回车键 依次包含 LF NL line feed new line 十进制 10 和 CR carr
  • css怎么设置div滚动条

    随着网页及移动端应用的发展 滚动条成为了一种不可或缺的用户体验 而 CSS3 提供的一系列滚动条样式设置使得我们可以更加灵活地定制滚动条的样式 今天我们就来一起探讨一下如何利用CSS来设置div滚动条 一 基础设置 我们在HTML中定义一个
  • 阿里云上传图片的使用,AccessKey查看,入门级别

    阿里云上传图片的使用 可能很多人想上传图片到云端 却连阿里云怎么使用都还不会 我这个是入门级别的教程 一步一步来 我这里先附上我自己的前端上传图片教程代码vue前端直传阿里云 首先就是点击阿里云之后进行注册 注册就不贴了啊 阿里云是可以直接
  • css选择同时有两个类名的标签

    这个技巧比较厉害 记录一下 链接
  • Anaconda查看、创建、切换、删除虚拟环境

    Anaconda查看 创建 切换 删除虚拟环境 参考链接 1 查看已有虚拟环境 在命令行输入以下命令 conda info envs 这里的base 带星号的 代表基层或者当前虚拟环境 paddle是我新建的一个虚拟环境 2 创建新的虚拟环
  • 【微服务部署】五、Jenkins+Docker一键打包部署NodeJS(Vue)项目的Docker镜像步骤详解

    NodeJS Vue 项目也可以通过打包成Docker镜像的方式进行部署 原理是先将项目打包成静态页面 然后再将静态页面直接copy到Nginx镜像中运行 一 服务器环境配置 前面说明了服务器Nginx的安装和配置 这里稍微有些不同 但是因