Google云的平台工程
GCP(Google Cloud Platform)是Google云,为其内部(Google search、Gmail、YouTube等)和外部客户提供IaaS、PaaS以及Serverless computing等云服务的平台。
本文将带领你走进GCP,并深入体验其产品功能,感受Google云的产品设计理念以及相关架构思想。从而可以淬其精华,为我所用。本文的主要内容如下:
1. 注册Free Trial账号
云的产品体系非常庞大,注册一个GCP的Free Trial账号非常有必要。有了账号,我们可以解锁大部分GCP功能。注册不难,前往cloud.google.com按照要求注册就可以。
但有一点需要注意,在注册过程中,需要进行信用卡预授权(Authorize)300美元,这个钱试用期之后会退给你。试用期限是3个月,所以这3个月中所有的资源消耗都是免费的,当然这些资源也是有限的,不过用来运行一些demo和跑一些tutorial还是足够用了。
2.在GKE部署hello-app
2.1 根据tutorial完成hello-app的部署
这是一个Learn Tutorial,如下图所示,即它会用页面引导的方式,手把手教你怎么在GKE里面部署一个web应用。
2.2 体验autoscale
按照上面的tutorial部署完web-app之后,你会发现初始时这个deployment的replicas是3,但是过一段时间就会变成1。这是因为autoscale这个插件在搞鬼,当它检测到3个pods的CPU使用率都小于80%的时候,它就会将pods的数量从3缩容到1。
这里直接修改AutoScaler配置可能会报不能有两个AutoScaler错误,这时可以先Delete再Save就可以了。
你也可以使用kubectl get hpa来查看autoscaler情况,对于我们这个案例来说,将显示如下内容,其中minipods是2正是我们上面在console上设置的值。NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
hello-app-hpa-ryrw Deployment/hello-app 0%/80% 2 5 2 4h41m
其中hpa是CRD对象HorizontalPodAutoscaler,更多关于autoscale的内容可以参看autoscale文档。
2.3 更新hello-app
在这个tutorial里面,这个hello-app的代码是从github上clone下来的,在cloud shell中的路径是kubernetes-engine-samples/hello-app,这是一个非常简单的go http server,按照tutorial我们是打了一个hello-app v1的镜像,然后我们在us-west4这个Region创建了一个Artifact Repository,并把hello-app v1镜像push到这个Repository了。
现在,我们可以增加一个计数功能,打一个v2版本的新image,然后对workload进行滚动更新,其具体步骤如下:
修改kubernetes-engine-samples/hello-app/main.go代码:
var count intfunc hello(w http.ResponseWriter, r *http.Request) {log.Printf("Serving request: %s", r.URL.Path)host, _ := os.Hostname()count++fmt.Fprintf(w, "Visited count: %d\n", count)fmt.Fprintf(w, "Version: 2.0.0\n")fmt.Fprintf(w, "Hostname: %s\n", host)
}
可以在本地通过go run main.go启动服务,然后运行命令curl localhost:8080测试一下改动是否ok
测试没有问题,通过下面命令重新打v2版本的docker镜像
docker build -t ${REGION}-docker.pkg.dev/${PROJECT_ID}/hello-repo/hello-app:v2 .# 或者替换变量
docker build -t us-west4-docker.pkg.dev/my-second-project-398309/hello-repo/hello-app:v2 .
注意:其中REGION和PROJECT_ID这两个环境变量是在2.1的过程中设置过的,可以通过echo ${PROJECT_ID}验证一下,因为如果cloud shell重新连接的话,环境变量会丢失,需要重新设置。
将新的image上传到我们项目的repository
docker push ${REGION}-docker.pkg.dev/${PROJECT_ID}/hello-repo/hello-app:v2# 或者替换变量
docker push us-west4-docker.pkg.dev/my-second-project-398309/hello-repo/hello-app:v2
5. 进行滚动更新(Rolling update)
在kubenetes的环境里,我们一般会通过修改yaml文件,将里面的container使用的image修改成我们上面上传的v2版本,然后kubectl apply一下,控制面会帮助我们完成更新。因为我们这个tutorial是基于GUI console的,所以我们也可以在界面上完成更新操作。具体就是点击Actions里面的Rolling update,然后将Container Image换成我们的v2版本,点击update就可以完成更新任务。
完成这些动作之后,通过访问hello-app-service暴露的公网endpoint,访问一下,如果返回页面上有统计访问计数功能,说明我们的更新是完成了。
3. 体验Terraform
3.1 基础概念
Terraform是一个IT基础架构自动化编排工具,可以用代码来管理维护IT资源。它编写了描述云资源拓扑的配置文件中的基础结构,例如虚拟机、存储账户和网络接口。也就是我们通常说的IAC(Infrastructure As Code)。
其中Provider和Resource这两个最重要的概念,我们要理解。
Provider:Terraform是一个框架,它可以支撑所有的云厂商,不同的云厂商是不同的Provider。
Resource:Resource是infrastructure的各类组件,可以是物理组件比如服务器,也可以是逻辑组件比如安全组等。在描述Resource block的时候,有两个String字段,它们分别表示Resource type和Resource name。比如:
resource "google_compute_network" "vpc_network" {name = "terraform-network"
}
The resource type is google_compute_network and the name is vpc_network. The prefix of the type maps to the name of the provider. In the example configuration, Terraform manages the google_compute_network resource with the google provider. Together, the resource type and resource name form a unique ID for the resource. For example, the ID for your network is google_compute_network.vpc_network。
如果想要更近一步了解provider和resource的概念,可以查看hashicorp的官方文档。如果需要查看GCP的terraform Resource定义可以查看GCP的Terraform文档。同样,华为云也有自己的Terraform指南。
接下来,让我们根据Terraform Tutorial一起体验一下其强大的IaC功能。
3.2 使用Terraform创建VPC
根据tutorial,我们要新建一个main.tf文件,首先创建VPC网络。具体内容参考tutorial
3.3 使用Terraform创建虚机
然后是创建Compute Engine虚拟机资源,具体内容参考tutorial
此时我们的main.tf内容如下:
# Create VPC network and subnet
resource "google_compute_network" "vpc_network" {name = "my-custom-mode-network"auto_create_subnetworks = falsemtu = 1460
}resource "google_compute_subnetwork" "default" {name = "my-custom-subnet"ip_cidr_range = "10.0.1.0/24"region = "us-west1"network = google_compute_network.vpc_network.id
}
3.4 执行Terraform
执行一般需要3步:
第一步是使用terraform init来添加必要的插件并构建.terraform目录。
第二步使用terraform plan来验证main.tf的语法是否正确,显示将要创建的资源。
第三步是使用terraform apply来实施资源的创建。
注意:因为我们使用的是free trial账号,能创建的资源非常有限,可能会出现配额不足的情况。此时,我们可以通过Quota配额管理,来查看配额使用情况。如果是配额原因的话,可以释放资源再尝试。
3.5 用Terraform创建一个可部署Web应用的环境
接下来,我们会创建一个web应用,将其部署到虚拟机。这需要我们做以下准备:
添加自定义SSH防火墙规则,可以让我们远程SSH到虚拟机。对于华为云来说,就是安全组(Security Group)
# 在原来main.tf的基础上,追加以下内容,在执行terraform apply的时候,
# 已创建的资源会被ignore,只会创建新添加的resource# add ssh firewall rule
resource "google_compute_firewall" "ssh" {name = "allow-ssh"allow {ports = ["22"]protocol = "tcp"}direction = "INGRESS"network = google_compute_network.vpc_network.idpriority = 1000source_ranges = ["0.0.0.0/0"]target_tags = ["ssh"]
}
使用ssh登录到flask-vm的虚拟机
构建Flask应用
创建app.py文件
写一个简单hello world http server
from flask import Flask app = Flask(__name__)@app.route('/') def hello_cloud():return 'Hello Terraform!'app.run(host='0.0.0.0')
运行python3 app.py。Flask默认为通过localhost:5000暴露服务
在虚拟机上开放5000端口
为了执行上面的配置,我们需要在原来main.tf的基础上追加以下内容,然后执行terraform apply。
# expose 5000 port
resource "google_compute_firewall" "flask" {name = "flask-app-firewall"network = google_compute_network.vpc_network.idallow {protocol = "tcp"ports = ["5000"]}source_ranges = ["0.0.0.0/0"]
}# A variable for extracting the external IP address of the VM
output "Web-server-URL" {value = join("",["http://",google_compute_instance.default.network_interface.0.access_config.0.nat_ip,":5000"])
}
然后我们部署一个简单的Python Flask应用来验证我们的web server是否OK,至此我们整个实验也就完成了。
4. 实现GitOps形式的CICD
4.1 基本概念
Cloud build是GCP的提供的serverless CI/CD平台,可以在上面完成代码托管、构建、artifiact registry,测试和部署等ops工作。
术语 GitOps 一词由 Weaveworks 首先提出,如果说DevOps是一种理念的话,那么GitOps则是对DevOps理念的落地实践,主要是通过IaC(Infrastructure as Code)的方式将基础实施创建,CI/CD等运维动作“代码化”(比如Cloud build的配置,Terraform的配置,kubenetes的配置等),然后用Git对这些配置脚本进行管理。
因此,实现GitOps的前提条件就是我们的infrastructure要可以声明式管理(Be declaratively managed)。
4.2 实现概述
本实验的参考Tutorial,本教程使用两个 Git 代码库:
app 代码库:包含应用本身的源代码
env 代码库:包含 Kubernetes 部署的清单
我们将 app 代码库和 env 代码库分开,是因为它们具有不同的生命周期和用途。app 代码库的主要用户是真人,此代码库专用于特定应用。env 代码库的主要用户是自动化系统(例如 Cloud Build),并且此代码库可能由多个应用共享。env 代码库可以有多个分支,每个分支映射到特定环境。
这里为了演示,我们只有一个环境,真实场景可以有多个环境。
4.3 用Cloud Build实现GitOps CI
所谓的CI,Continuous integration refers to the build and unit testing stages of the software release process. Every revision that is committed triggers an automated build and test.
在GCP里面,是通过触发器(Trigger)来感知GIT里面提交代码的变化,然后在这个trigger上配置Cloud Build流水线配置文件:
steps:
# This step runs the unit tests on the app
- name: 'python:3.7-slim'id: Testentrypoint: /bin/shargs:- -c- 'pip install flask && python test_app.py -v'# This step builds the container image.
- name: 'gcr.io/cloud-builders/docker'id: Buildargs:- 'build'- '-t'- 'us-central1-docker.pkg.dev/$PROJECT_ID/my-repository/hello-cloudbuild:$SHORT_SHA'- '.'# This step pushes the image to Artifact Registry
# The PROJECT_ID and SHORT_SHA variables are automatically
# replaced by Cloud Build.
- name: 'gcr.io/cloud-builders/docker'id: Pushargs:- 'push'- 'us-central1-docker.pkg.dev/$PROJECT_ID/my-repository/hello-cloudbuild:$SHORT_SHA'
上面的脚本,实际上就是一个典型的CI流程,即测试、打镜像包、上传镜像。
4.4 用Cloud Build实现GitOps CD
所谓的CD(Continuous Delivery),简单来说就是在CI的基础上多出了deployment部署的动作,在tutorial中这个动作也是通过git代码仓库触发的。
为达此目的,我们需要新建一个代码仓,同样我们需要给这个代码仓配置一个触发器,这个触发器的作用就是在接收到新的镜像变化时,将其部署到GKE集群。然而这个触发动作,需要我们在之前CI cloudbuild.yaml后面追加以下内容,其主要职责就是将新的镜像写入CD的配置文件,并push到CD的配置代码仓,从而触发CD执行。
# This step clones the hello-cloudbuild-env repository
- name: 'gcr.io/cloud-builders/gcloud'id: Clone env repositoryentrypoint: /bin/shargs:- '-c'- |gcloud source repos clone hello-cloudbuild-env && \cd hello-cloudbuild-env && \git checkout candidate && \git config user.email $(gcloud auth list --filter=status:ACTIVE --format='value(account)')# This step generates the new manifest
- name: 'gcr.io/cloud-builders/gcloud'id: Generate manifestentrypoint: /bin/shargs:- '-c'- |sed "s/GOOGLE_CLOUD_PROJECT/${PROJECT_ID}/g" kubernetes.yaml.tpl | \sed "s/COMMIT_SHA/${SHORT_SHA}/g" > hello-cloudbuild-env/kubernetes.yaml# This step pushes the manifest back to hello-cloudbuild-env
- name: 'gcr.io/cloud-builders/gcloud'id: Push manifestentrypoint: /bin/shargs:- '-c'- |set -x && \cd hello-cloudbuild-env && \git add kubernetes.yaml && \git commit -m "Deploying image us-central1-docker.pkg.dev/$PROJECT_ID/my-repository/hello-cloudbuild:${SHORT_SHA}Built from commit ${COMMIT_SHA} of repository hello-cloudbuild-appAuthor: $(git log --format='%an <%ae>' -n 1 HEAD)" && \git push origin candidate
此时我们已经将kubernetes.yaml写入hello-cloudbuild-env的candidate分支。为了执行部署动作,我们需要新建另一个触发器(Trigger),这里我们将其命名为cloudbuild-delivery.yaml,其内容如下:
# [START cloudbuild-delivery]
steps:
# This step deploys the new version of our container image
# in the hello-cloudbuild Kubernetes Engine cluster.
- name: 'gcr.io/cloud-builders/kubectl'id: Deployargs:- 'apply'- '-f'- 'kubernetes.yaml'env:- 'CLOUDSDK_COMPUTE_REGION=us-central1'- 'CLOUDSDK_CONTAINER_CLUSTER=hello-cloudbuild'# This step copies the applied manifest to the production branch
# The COMMIT_SHA variable is automatically
# replaced by Cloud Build.
- name: 'gcr.io/cloud-builders/git'id: Copy to production branchentrypoint: /bin/shargs:- '-c'- |set -x && \# Configure Git to create commits with Cloud Build's service accountgit config user.email $(gcloud auth list --filter=status:ACTIVE --format='value(account)') && \# Switch to the production branch and copy the kubernetes.yaml file from the candidate branchgit fetch origin production && git checkout production && \git checkout $COMMIT_SHA kubernetes.yaml && \# Commit the kubernetes.yaml file with a descriptive commit messagegit commit -m "Manifest from commit $COMMIT_SHA$(git log --format=%B -n 1 $COMMIT_SHA)" && \# Push the changes back to Cloud Source Repositorygit push origin production
# [END cloudbuild-delivery]
这样,当hello-cloudbuild-env这个代码仓接收到代码提交,就会触发部署动作,把最新的docker镜像部署到auto-pilot集群,并且可以通过service访问。一切正常的话,最后会把最新部署脚本写入production分支。
4.5 结果验证
修改代码
sed -i 's/Hello Cloud Build/Hello huawei/g' app.pysed -i 's/Hello Cloud Build/Hello huawei/g' test_app.pysed -i 's/Hello huawei/Hello Cloud Build/g' app.pysed -i 's/Hello huawei/Hello Cloud Build/g' test_app.py
提交变更,或者MR
git add app.py test_app.py
git commit -m “Hello Cloud Build”
git push查看CICD
https://console.cloud.google.com/cloud-build/builds查看容器部署 kubectl get pods
查看service:http://34.172.165.210/
5 GKE Autopilot
可以根据创建Autopilot集群指南来创建Autopilot集群。
可以根据部署无状态负载指南来部署一个无状态应用。
我们还是选用2.1中创建的Docker镜像来部署,我们可以在Cloud Shell中创建一个deployment.yaml,其内如如下:
apiVersion: apps/v1kind: Deploymentmetadata:name: my-appspec:replicas: 3selector:matchLabels:run: my-apptemplate:metadata:labels:run: my-appspec:containers:- name: hello-appimage: us-west1-docker.pkg.dev/polynomial-text-398202/hello-repo/hello-app:v1
然后使用kubectl apply -f deployment.ymal进行部署,然后用kubectl get pods查看部署情况:
NAME READY STATUS RESTARTS AGE
my-app-7fcfbd5c8d-55jcf 1/1 Running 0 61m
my-app-7fcfbd5c8d-lrxcn 1/1 Running 0 61m
my-app-7fcfbd5c8d-wfzzz 1/1 Running 0 61m
相关文章:

Google云的平台工程
GCP(Google Cloud Platform)是Google云,为其内部(Google search、Gmail、YouTube等)和外部客户提供IaaS、PaaS以及Serverless computing等云服务的平台。 本文将带领你走进GCP,并深入体验其产品功能&#x…...

【Android】画面卡顿优化列表流畅度五之下拉刷新上拉加载更多组件RefreshLayout修改
之前也写过类似组件的介绍: 地址:下拉刷新&上拉加载更多组件SmartRefreshLayout 本来打算用这个替换的,但在进行仔细研究发现不太合适。功能都很好,但嵌入不了当前的工程体系里。原因就是那啥体制懂的都懂。这样的组件需要改…...

【Android】导入三方jar包/系统的framework.jar
1.Android.mk导包 1).jar包位置 与res和src同一级的libs中(没有就新建) 2).Android.mk文件 LOCAL_STATIC_ANDROID_LIBRARIES:android静态库,经常用于一些support的导包 LOCAL_JAVA_LIBRARIES:依赖的java库,一般为系统的jar…...

在线升级 redis 到7.2.2
1. 操作环境与升级思路 先安装新的版本新版本设置主从备份,将老版本与新版本的数据进行同步新启动一个服务,连接新版本redis,切换到新服务,关闭主从备份kill 老服务, 卸载老版本redis 因为我需要 RedisSearch 所以直接安装 Redi…...

社区新零售:改变生活方式的创新商业模式
社区新零售:改变生活方式的创新商业模式 社区新零售,顾名思义,以社区为核心,利用互联网、大数据、人工智能等先进技术,将线上购物和线下体验有机结合,形成一种全新的零售模式。它特别强调地理位置的便利性&…...

MySQL/SQLServer判断字符是纯数字或者是其它字符
如下是MySQL表结构设计(演示所用): MySQL表关联数据如下所示: 【场景:查询所有数字,包含小数点】,SQL如下所示: SELECT * FROM data WHERE message not REGEXP [^0-9].[^0-9] My…...

Threejs_02 父子位移+缩放改变
threejs中如何做出一堆父子来呢? 父子制作 1.做一个父元素 想要做一个元素 需要材质和模型,然后使用threejs的方法THREE.Mesh就可以制作出来 // 创建一个集合体 (立方体) const geometry new THREE.BoxGeometry(1, 1, 1); // 创建材质 (16进制颜色…...

LuatOS-SOC接口文档(air780E)--nimble - 蓝牙BLE库(nimble版)
示例 -- 本库当前支持Air101/Air103/ESP32/ESP32C3/ESP32S3 -- 用法请查阅demo, API函数会归于指定的模式-- 名称解释: -- peripheral 外设模式, 或者成为从机模式, 是被连接的设备 -- central 中心模式, 或者成为主机模式, 是扫描并连接其他设备 -- ibeacon 周期性的be…...

医疗器械展示预约小程序的效果如何
医疗器械行业涵盖的内容非常广,市场中大小从业的品牌/门店也很多,比如我们常见的轮椅、康复器械、拐杖、血压仪等产品市场需求都非常高,当然还有医院里用的器械等。 医疗器械市场呈现多品牌、多门店的发展趋势,虽然这些东西不是必…...

【Vue原理解析】之异步与优化
引言 Vue是一款流行的JavaScript框架,它提供了一些强大的特性来提升应用程序的性能和用户体验。在本文中,我们将深入探讨Vue的异步更新机制和一些优化技巧,帮助您更好地理解和应用这些特性。 异步更新机制 Vue使用异步更新机制来提高渲染性…...

mybatis、mysql 创建时间(create_time)异常自动更新为当前时间
目录标题 一、问题二、原因三、解决 一、问题 bug: mybatis更新代码没有修改时间,但是时间会自动更新为当前时间。 。。。 被坑了挺久 二、原因 可能是创建表的时候, Navicat Premium 等可视化工具给你整活了。。。 三、解决 取消勾选。 注意&…...

shardingsphere 加载慢 优化
shardingsphere加载慢 优化 原因: 启动速度变慢(元数据扫描耗时较长) 占用内存增多(大量单表和元数据对象) 那是因为默认扫描1张表.一张一张加载巨慢,添加以下配置增加到20张表同时扫描 错误: 如果你数据库最大连接不到20就会报错,请按照数据…...

我这些年对于自动化测试的理解
📢专注于分享软件测试干货内容,欢迎点赞 👍 收藏 ⭐留言 📝 如有错误敬请指正!📢交流讨论:欢迎加入我们一起学习!📢资源分享:耗时200小时精选的「软件测试」资…...

Java安全架构 JCA、JCE、JSSE、JAAS
Java语言拥有三大特征:平台无关性、网络移动性和安全性,而Java安全体系结构对这三大特征提供了强大的支持和保证, Java安全体系结构总共分为4个部分: (1)JCA( Java Cryptography Architecture…...

面试经典(4/150)删除有序数组中的重复项 II
面试经典(4/150)删除有序数组中的重复项 II 给你一个有序数组 nums ,请你 原地 删除重复出现的元素,使得出现次数超过两次的元素只出现两次 , 返回删除后数组的新长度。不要使用额外的数组空间,你必须在 原…...

使用WildCard充值ChatGPT Plus 会员
登录 wildCard官网 基于国内手机号注册账号,使用支付宝验证付款即可自动申请国外银行卡,WildCard的开卡费是9.9美元, 没有后续的月费用.订阅chatgpt plus会员服务的操作图文指南见链接 chatgpt plus会员订阅指南...

element-plus使用el-date-picker组件时,如何禁止用户选择当前时间之后的日时分秒
element-plus使用el-date-picker组件时,如何禁止用户选择当前时间之后的日时分秒 例: 当前时间为2023-11-15 14.24,不能选择这之后的时分秒。(禁止用户选择2023-11-15 14.28) <el-date-pickerv-model"form.s…...

keepalived安装配置(服务器主备、负载均衡)
系统拓扑 安装keepalived 主备服务器上都需要安装 在线安装 yum install -y keepalived 离线安装 # todo 服务器准备 虚拟机ip:192.168.11.56 主服务器:192.168.11.53 备服务器:192.168.11.54 配置文件修改 keepalived安装之后&…...

盘点一款制作电子杂志的网站,小白也能快速上手
电子杂志作为一种时尚、环保、便捷的宣传形式,越来越受到各行各业的青睐。无论是企业宣传、产品推广,还是个人分享,电子杂志都能展现出独特的魅力。而制作电子杂志,不再是专业人士的专属,现在小白也能快速上手&#…...

全域全自主建设,亚信科技AntDB数据库助力广电5G业务上线运行
自2019年6月,中国广电成功获得5G牌照以来,迅速推进网络建设目标,成为5G网络覆盖广、应用场景多、用户体验出色的第四大运营商。其依托全球独有的700MHz频谱资源,具备覆盖能力强、容量足、速率高的优势。通过不断深化和中国移动的共…...

使用 SSH 密钥进行身份验证
使用 SSH 密钥进行身份验证可以提高安全性,并免去每次登录时输入密码的麻烦。以下是使用 SSH 密钥进行身份验证的步骤: 生成密钥对:在本地计算机上生成 SSH 密钥对。打开终端并执行以下命令: ssh-keygen -t rsa -b 4096这将生成…...

国内最受欢迎的电商API接口调用京东商品详情数据
国内实用的API接口 国内最受欢迎的7大API供应平台对比和介绍 本文将介绍7款API供应平台:电商API数据、百度e、Apix、数说聚合、通联数据、HaoService、datasift 。排名不分先后! 免费实用的API接口 第一部分 1、电商数据(API数据接口_开发者…...

windows远程桌面登录ubuntu,黑屏闪退,
首先需要安装xrdp以后才能远程登录,安装命令 sudo apt-get install xrdp 这里需要注意一个问题,如果在ubuntu 本地登录的情况下,windows远程登录会出现黑屏甚至闪退的问题。原因是本地登录和远程登陆是互斥的,本地登录了就不能远…...

12-使用vue2实现todolist待办事项
个人名片: 😊作者简介:一名大二在校生 🤡 个人主页:坠入暮云间x 🐼座右铭:懒惰受到的惩罚不仅仅是自己的失败,还有别人的成功。 🎅**学习目标: 坚持每一次的学习打卡 文章…...

微信小程序授权登录?
wxml <!-- 示例:在wxml中创建一个授权登录按钮 --> <button bindtap"getUserInfo">授权登录</button> js // 用户点击授权登录按钮时触发的事件处理函数getUserInfo: function (e) {wx.getUserProfile({desc: 用于完善会员资料, // 授…...

React 18 + Hooks +Ts 开发中遇到的问题及解决方案!
这篇文章是用来专门记录关于React 18 Hooks Ts 开发中遇到的问题及解决方案 Q1 问题描述: TS7016: Could not find a declaration file for module js-export-excel. /Users/zhangliangliang/WebstormProjects/daizhang-system-front/node_modules/js-export-exc…...

推荐一个非常好用的uniapp的组件库【TMUI3.0】
文章目录 前言官网地址如何使用?注意事项后言 前言 hello world欢迎来到前端的新世界 😜当前文章系列专栏:前端系列文章 🐱👓博主在前端领域还有很多知识和技术需要掌握,正在不断努力填补技术短板。(如果…...

LeetCode(19)最后一个单词的长度【数组/字符串】【简单】
目录 1.题目2.答案3.提交结果截图 链接: 58. 最后一个单词的长度 1.题目 给你一个字符串 s,由若干单词组成,单词前后用一些空格字符隔开。返回字符串中 最后一个 单词的长度。 单词 是指仅由字母组成、不包含任何空格字符的最大子字符串。 …...

使用Docker本地安装部署Drawio绘图工具并实现公网访问
目录 前言 1. 使用Docker本地部署Drawio 2. 安装cpolar内网穿透工具 3. 配置Draw.io公网访问地址 4. 公网远程访问Draw.io 前言 提到流程图,大家第一时间可能会想到Visio,不可否认,VIsio确实是功能强大,但是软件为收费&…...

IDEA导入jar包
通过maven导入本地包 mvn install:install-file -DfileD:\WebProject\ERP\zhixing-heyue-erp-server\zxhy-service-api\src\main\java\com\zxhy\service\api\invoice\baiwang\lib\com_baiwang_bop_sdk_outer_3_4_393.jar -DgroupIdcom.baiwang -DartifactIdbaiwang.open -Dver…...