微服务CI/CD实践(五)Jenkins Docker 自动化构建部署Node服务

微服务CI/CD实践系列:
 
微服务CI/CD实践(一)环境准备及虚拟机创建
微服务CI/CD实践(二)服务器先决准备
微服务CI/CD实践(三)gitlab部署及nexus3部署
微服务CI/CD实践(四)Jenkins部署及环境配置
微服务CI/CD实践(五)Jenkins + Dokcer 部署微服务后端项目
微服务CI/CD实践(六)Jenkins + Dokcer 部署微服务前端VUE项目
微服务CI/CD实践(七)Minio服务器部署及应用

文章目录

  • 一、先决条件
    • 1.1 服务器先决条件
    • 1.2 项目配置
      • Dockerfile
      • Nginx配置文件
      • 部署脚本
  • 二、Jenkins构建部署
    • 2.1 创建项目
    • 2.2 配置项目基本信息
    • 2.3 定义 Pipeline script
    • 2.4 构建部署项目

前端项目是基于NodeJS(Vue)框架开发,我们通过打包成Docker镜像的方式进行部署,原理是先将项目打包成静态页面,然后再将静态页面直接copy到Nginx镜像中运行。构建部署流程如下:

  • 拉取代码
  • jenkins服务器进行nodejs编译
  • 使用dockerfile构建镜像并打包镜像
  • 上传镜像包
  • 执行sh

一、先决条件

1.1 服务器先决条件

Jenkins 和 server服务器先决条件参考微服务CI/CD实践(二)服务器先决准备 和 微服务CI/CD实践(四)Jenkins部署及环境配置

1.2 项目配置

Dockerfile

使用Jenkins本地编译项目在构建镜像

FROM nginx:latest
# 将生成的静态页面文件复制到nginx的/usr/share/nginx/html/目录
COPY dist/ /usr/share/nginx/html/
# 将mime文件复制到nginx的/etc/nginx/目录 后续配置ng会使用
COPY mime.types /etc/nginx/mime.types
# 容器启动时运行的命令
CMD ["nginx", "-g", "daemon off;"]

也可以直接使用docker 镜像编译-构建镜像,此模式jenkins服务器可以不需要node环境

# Install dependencies
FROM node:18.20.4 as builder
WORKDIR /app
# Install pnpm
RUN npm i -g pnpm
# copy file for next stage
COPY . /app
RUN pnpm install && pnpm run build
# copy dist from the first stage for Production
FROM nginx:latest AS runner
COPY --from=builder /app/dist/ /usr/share/nginx/html
COPY --from=builder /app/nginx.conf /etc/nginx/conf.d/default.conf

不过此模式在docker-hub停止国内服务后可能无法正常拉取镜像。

Nginx配置文件

根据项目要求编写ng配置

cd /data/container/nginx/etc
vi nginx.conf
# 编写配置并保存vi mime.types
# 编写配置并保存

以下为nginx.conf配置示例


events {worker_connections 1024;
}http {# 需要引入mime.types配置或者显示配置静态文件mimetype类型,否则运行后,浏览器会因为文件类型导致无法正常加载静态文件include       mime.types;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;tcp_nodelay     on;keepalive_timeout  65;types_hash_max_size 2048;client_max_body_size 100m;server {listen       80;listen  [::]:80;server_name  localhost;# 设置 CORS 相关的响应头add_header 'Access-Control-Allow-Origin' '*' always;add_header 'Access-Control-Allow-Methods' '*' always;add_header 'Access-Control-Max-Age' 1728000 always;add_header 'Access-Control-Allow-Headers' '*' always;add_header 'Access-Control-Allow-Credentials' 'true' always;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 utf8;location / {root   /usr/share/nginx/html;index  index.html index.htm;try_files $uri $uri/ /index.html;if (!-e $request_filename) {rewrite ^/(.*) /index.html last;break;}}location  ~ .*\.(jpg|png|js|css|woff2|ttf|woff|eot)$ {root   /usr/share/nginx/html;}#error_page  404              /404.html;# redirect server error pages to the static page /50x.html#error_page   500 502 503 504  /50x.html;location = /50x.html {root   /usr/share/nginx/html;}# 配置全局代理并统一处理CORS location /gateway-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://192.168.1.103:10000/;# 添加 CORS 相关的响应头add_header 'Access-Control-Allow-Origin' '*' always;add_header 'Access-Control-Allow-Methods' '*' always;add_header 'Access-Control-Max-Age' 1728000 always;add_header 'Access-Control-Allow-Headers' '*' always;add_header 'Access-Control-Allow-Credentials' 'true' always;# 处理 OPTIONS 请求if ($request_method = 'OPTIONS') {return 204;}}}
}

以下为mime.type示例

types {text/html                 html htm shtml;text/css                  css;image/gif                gif;image/jpeg               jpeg jpg;application/javascript    js;application/xml          xml;application/json         json;application/pdf          pdf;application/rss+xml      rss;application/atom+xml     atom;text/mathml              mml;text/plain               txt;text/vnd.sun.j2me.app-descriptor jad;text/vnd.wap.wml         wml;text/x-component         htc;image/png               png;image/svg+xml           svg;image/tiff              tif tiff;image/vnd.wap.wbmp      wbmp;image/x-icon            ico;image/x-jng             jng;image/x-ms-bmp          bmp;application/zip          zip;application/tar          tar;application/x-7z-compressed 7z;application/x-java-archive jar;application/x-rar-compressed rar;application/x-web-app-manifest+json webapp;application/xhtml+xml   xhtml;application/x-msdownload  exe dll;audio/midi              mid midi kar;audio/mpeg             mp3;video/mp4              mp4;video/mpeg             mpeg mpg;video/webm             webm;video/x-msvideo         avi;video/x-ms-wmv         wmv;video/x-ms-asf         asx asf;video/x-flv            flv;application/x-shockwave-flash swf;application/vnd.ms-excel  xls;application/vnd.openxmlformats-officedocument.wordprocessingml.document docx;application/vnd.openxmlformats-officedocument.spreadsheetml.sheet  xlsx;application/vnd.openxmlformats-officedocument.presentationml.presentation pptx;application/vnd.ms-fontobject eot;application/vnd.apple.mpegurl m3u8;application/x-font-ttf  ttc ttf;application/x-httpd-php-source phps;
}

部署脚本

step1 定义入参
可以通过Jenkins任务将参数传入脚本中,我们定义了下面7个参数:
container_name : 容器名称
image_name : 镜像名称
version : 镜像版本
portal_port: 宿主主机端口映射
server_port: 容器内服务端口
portal_ssl_port: 宿主主机端口映射
serve_sslr_port: 容器内服务端口

step2 定义入参对参数进行检查
将必传参数放在最前面,这里根据自己的实际情况判断,检查是否传递参数。比如设置container_name、image_name、version 、portal_port、server_port5个参数必须传入,就设置参数的个数不能小于5。

echo "param validate"
if [ $# -lt 5 ]; then  echo "you must use like this : /usr/docker-sh/your_script.sh <container_name> <image_name> <version> [portal port] [server port] [portal ssl port] [server ssl port]"  exit  
fi

step3 入参赋值
如果有参数传入,则赋值参数

# 前五个参数是必传参数,无需判断直接赋值
container_name="$1"
image_name="$2"
version="$3"
portal_port="$4"
server_port="$5"
if [ "$6" != "" ]; thenportal_ssl_port="$6"
fi
echo "portal_ssl_port=" $portal_ssl_port
if [ "$7" != "" ]; thenserve_sslr_port="$7"
fi

step4 停止并删除容器

echo "执行docker ps"
docker ps 
if [[ "$(docker inspect $container_name 2> /dev/null | grep $container_name)" != "" ]]; 
then echo $container_name "容器存在,停止并删除"echo "docker stop" $container_namedocker stop $container_nameecho "docker rm" $container_namedocker rm $container_name
else echo $container_name "容器不存在"
fi

step5 停止并删除镜像

# 删除镜像
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

step6 备份和加载安装包

#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/$container_name.tar" "$BAK_DIR"/"$image_name"_`date +%H%M%S`.tarecho "docker load" $image_name
docker load --input /opt/tmp/$container_name.tar

step7 执行运行镜像命令

echo "docker run" $image_name
docker run -d -p $portal_port:$server_port --name=$container_name --network=my-network -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 /data/container/nginx/etc/mime.types:/etc/nginx/mime.types -v /etc/localtime:/etc/localtime -v /usr/share/zoneinfo/Asia/Shanghai:/etc/timezone $image_name

step8 执行删除安装包命令

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

以下为完整的安装部署脚本

#!/usr/bin/env bashecho "param validate"
if [ $# -lt 5 ]; then  echo "you must use like this : /usr/docker-sh/your_script.sh <container_name> <image_name> <version> [portal port] [server port] [portal ssl port] [server ssl port]"  exit  
ficontainer_name="$1"
image_name="$2"
version="$3"
portal_port="$4"
server_port="$5"
if [ "$6" != "" ]; thenportal_ssl_port="$6"
fi
echo "portal_ssl_port=" $portal_ssl_port
if [ "$7" != "" ]; thenserve_sslr_port="$7"
fiecho "执行docker ps"
docker ps 
if [[ "$(docker inspect $container_name 2> /dev/null | grep $container_name)" != "" ]]; 
then echo $container_name "容器存在,停止并删除"echo "docker stop" $container_namedocker stop $container_nameecho "docker rm" $container_namedocker 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/$container_name.tar" "$BAK_DIR"/"$image_name"_`date +%H%M%S`.tarecho "docker load" $image_name
docker load --input /opt/tmp/$container_name.tarecho "docker run" $image_name
docker run -d -p $portal_port:$server_port --name=$container_name --network=my-network -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 /data/container/nginx/etc/mime.types:/etc/nginx/mime.types -v /etc/localtime:/etc/localtime -v /usr/share/zoneinfo/Asia/Shanghai:/etc/timezone $image_nameecho "remove tmp " $image_name
rm -rf /opt/tmp/$container_name.tarecho "Docker Portal is starting,please try to access $container_name conslone url"

二、Jenkins构建部署

2.1 创建项目

新建一个流水线任务
在这里插入图片描述

2.2 配置项目基本信息

创建完成项目,点击项目进入项目页面,点击左侧菜单》配置,进行项目基本配置
step1 项目构建历史存储策略配置
在这里插入图片描述
根据项目实际情况配置存储策略
step2 配置参数化构建过程
Jenkins List Git Branches插件 构建选择指定git分支,点击添加参数选择List Git branchers选项进行Jenkins List Git Branches插件配置
在这里插入图片描述
Jenkins List Git Branches插件配置流程如下:

  • 配置name
  • 配置仓库并选择凭证
  • 选择Parameter Type
  • 配置Branch Filter

在这里插入图片描述

2.3 定义 Pipeline script

step1 配置全局变量

environment {   REPOSITORY="http://192.168.1.101:8929/hka/hka-admin-wocwin.git"projectdir="hka-web-01"projectname="hka-admin-wocwin"
}

step2 获取代码
检出选择指定git分支的代码

stages {stage('获取代码') {steps {echo "start fetch code from git:${REPOSITORY} ${branch}"deleteDir()checkout([$class: 'GitSCM',branches: [[name: '${branch}']],doGenerateSubmoduleConfigurations: false,extensions: [],userRemoteConfigs: [[credentialsId: '2',url: 'http://192.168.1.101:8929/hka/hka-admin-wocwin.git']]])}}

step3 编译项目

这里需要显示指定node的环境变量,否则执行编译命令会抛异常

stage('Build NodeJS Vue') {steps {echo "build nodejs code"nodejs('node') {sh 'export PATH="/usr/local/nodejs/bin:$PATH"'sh 'node -v'sh 'npm -v'sh 'pnpm -v'sh 'pnpm install'sh 'pnpm run prod'}echo "build nodejs success"}}

step4 删除历史容器和镜像
如何没有在jenkins服务器运行容器可以忽略Delete Old Docker Container步骤

stage('Delete Old Docker Container') {steps {echo "delete docker container"sh '''if [[ "$(docker inspect ${projectname} 2> /dev/null | grep ${projectname})" != "" ]]; then echo ${projectname} "容器存在,停止并删除"echo "docker stop" ${projectname}docker stop ${projectname}echo "docker rm" ${projectname}docker rm ${projectname}else echo ${projectname} "容器不存在"fi'''}}stage('Delete Old Docker Image') {steps {echo "delete docker image"sh '''if [[ "$(docker images -q ${projectname} 2> /dev/null)" != "" ]]; then echo ${projectname} \'镜像存在,删除镜像\'docker rmi $(docker images -q ${projectname} 2> /dev/null) --forceelse echo ${projectname} \'镜像不存在,创建镜像\'fi'''}}

step5 构建镜像

stage('Build Docker Image') {steps {echo "start docker build ${projectname} code"sh 'docker build -t ${projectname} .'echo "save docker images tar"sh 'docker save -o ${projectname}.tar ${projectname}'}}
stage('Delete New Docker Image') {steps {echo "delete docker image"sh '''if [[ "$(docker images -q ${projectname} 2> /dev/null)" != "" ]]; then echo ${projectname} \'镜像存在,删除镜像\'docker rmi $(docker images -q ${projectname} 2> /dev/null) --forceelse echo ${projectname} \'镜像不存在,创建镜像\'fi'''}}

step6 上传镜像包
这里的configName: ‘103’, 就是微服务CI/CD实践(四)Jenkins部署及环境配置### 2.2.4 全局系统配置 SSH Server配置
该流水线步骤会通过ssh将 镜像tar包上传到SSH Server配置的Remote Directory目录下

stage('Upload img tar') {steps {sshPublisher(publishers: [sshPublisherDesc(configName: '103',transfers: [sshTransfer(cleanRemote: false,excludes: '',makeEmptyDirs: false,noDefaultExcludes: false,patternSeparator: '[, ]+',remoteDirectory: '',remoteDirectorySDF: false,removePrefix: '',sourceFiles: '${projectname}.tar')],usePromotionTimestamp: false,useWorkspaceInPromotion: false,verbose: false)])}}

step7 执行安装部署脚本
这里的configName: ‘103’, 就是微服务CI/CD实践(四)Jenkins部署及环境配置### 2.2.4 全局系统配置 SSH Server配置
该步骤通过ssh远程执行sh安装部署脚本

stage('Execute Command sh') {steps {sshPublisher(publishers: [sshPublisherDesc(configName: '103',transfers: [sshTransfer(execCommand: '/usr/docker-sh/publish_hka-admin-wocwin.sh hka-admin-wocwin hka-admin-wocwin latest 80 80',execTimeout: 300000)],usePromotionTimestamp: false,useWorkspaceInPromotion: false,verbose: false)])}}

以下为完整流水线定义

pipeline {agent anyenvironment {   REPOSITORY="http://192.168.1.101:8929/hka/hka-admin-wocwin.git"projectdir="hka-web-01"projectname="hka-admin-wocwin"}stages {stage('获取代码') {steps {echo "start fetch code from git:${REPOSITORY} ${branch}"deleteDir()checkout([$class: 'GitSCM',branches: [[name: '${branch}']],doGenerateSubmoduleConfigurations: false,extensions: [],userRemoteConfigs: [[credentialsId: '2',url: 'http://192.168.1.101:8929/hka/hka-admin-wocwin.git']]])}}stage('Build NodeJS Vue') {steps {echo "build nodejs code"nodejs('node') {sh 'export PATH="/usr/local/nodejs/bin:$PATH"'sh 'node -v'sh 'npm -v'sh 'pnpm -v'sh 'pnpm install'sh 'pnpm run prod'}echo "build nodejs success"}}stage('Delete Old Docker Container') {steps {echo "delete docker container"sh '''if [[ "$(docker inspect ${projectname} 2> /dev/null | grep ${projectname})" != "" ]]; then echo ${projectname} "容器存在,停止并删除"echo "docker stop" ${projectname}docker stop ${projectname}echo "docker rm" ${projectname}docker rm ${projectname}else echo ${projectname} "容器不存在"fi'''}}stage('Delete Old Docker Image') {steps {echo "delete docker image"sh '''if [[ "$(docker images -q ${projectname} 2> /dev/null)" != "" ]]; then echo ${projectname} \'镜像存在,删除镜像\'docker rmi $(docker images -q ${projectname} 2> /dev/null) --forceelse echo ${projectname} \'镜像不存在,创建镜像\'fi'''}}stage('Build Docker Image') {steps {echo "start docker build ${projectname} code"sh 'docker build -t ${projectname} .'echo "save docker images tar"sh 'docker save -o ${projectname}.tar ${projectname}'}}stage('Delete New Docker Image') {steps {echo "delete docker image"sh '''if [[ "$(docker images -q ${projectname} 2> /dev/null)" != "" ]]; then echo ${projectname} \'镜像存在,删除镜像\'docker rmi $(docker images -q ${projectname} 2> /dev/null) --forceelse echo ${projectname} \'镜像不存在,创建镜像\'fi'''}}stage('Upload img tar') {steps {sshPublisher(publishers: [sshPublisherDesc(configName: '103',transfers: [sshTransfer(cleanRemote: false,excludes: '',makeEmptyDirs: false,noDefaultExcludes: false,patternSeparator: '[, ]+',remoteDirectory: '',remoteDirectorySDF: false,removePrefix: '',sourceFiles: 'hka-admin-wocwin.tar')],usePromotionTimestamp: false,useWorkspaceInPromotion: false,verbose: false)])}}stage('Execute Command sh') {steps {sshPublisher(publishers: [sshPublisherDesc(configName: '103',transfers: [sshTransfer(execCommand: '/usr/docker-sh/publish_hka-admin-wocwin.sh hka-admin-wocwin hka-admin-wocwin latest 80 80 4413 4413',execTimeout: 300000)],usePromotionTimestamp: false,useWorkspaceInPromotion: false,verbose: false)])}}stage('Publish Results') {steps {echo "End Publish ${projectname}"  }}}
}

2.4 构建部署项目

回到项目页面,点击参数化构建,选择用于构建的分支点击Build执行构建任务。
在这里插入图片描述

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/53230.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【软件设计】常用设计模式--策略模式

软件设计模式&#xff08;三&#xff09; 策略模式&#xff08;Strategy Pattern&#xff09;1. 概念2. 模式结构3. UML 类图4. 实现方式C# 示例步骤1&#xff1a;定义策略接口步骤2&#xff1a;实现具体策略类步骤3&#xff1a;实现上下文类步骤4&#xff1a;使用策略模式 Jav…

.NET/C#⾯试题汇总系列:基础语法

1. 字符串中string strnull和string str""和string strstring.Empty的区别&#xff1f; string str null;&#xff1a;这种方式声明了一个字符串变量str&#xff0c;并将其初始化为null。这意味着str不指向任何实际的字符串对象。如果你试图访问str的属性或方法&…

HTTPS SEO优势

搜索引擎优化&#xff08;SEO&#xff09;是提高网站在搜索引擎结果页&#xff08;SERP&#xff09;中的排名以吸引更多访问者的过程。HTTPS作为网站安全的标准&#xff0c;对SEO有着直接和间接的优势&#xff1a; 1. HTTPS作为排名信号 2014年&#xff0c;Google宣布HTTPS成…

穿越机的应用行业!!!

1. 军事领域 侦察与目标搜索&#xff1a;穿越机能够快速穿越危险区域&#xff0c;执行侦察任务&#xff0c;实时获取战场信息&#xff0c;对敌方目标进行精确搜索和定位。其灵活性和机动性使其成为战场上的重要侦察工具。 目标摧毁&#xff1a;经过改装的穿越机可挂载火箭弹或…

华三防火墙第-安全策略02

一 安全策略的图解 安全策略是一种根据报文的属性信息对报文进行精细化转发控制的智能安全防护措施。它 融合了多维度精确报文识别、深度报文检测、安全动作执行、智能策略分析、应用风险调 优等多种安全防护功能,为网络的安全性提供全方位保障。 安全策略运行原理 安全策略对…

CSS实现文字环绕圆形展示

展示区域 代码区域 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Document</title><s…

ubuntu20.04搭建kubernetes1.28.13集群配置calico网络插件

写在前面 这里是我在搭建过程中从某站找到的教学视频,搭载的都是最新的,大家可以参考一下 搭建kubernetes集群学习视频: 视频链接。最后面会有我遇见报错信息的所有连接和解决方案,自行查看 不说废话,直接开搭 搭建集群大纲 一、三台虚拟机的初始化 二、三台虚拟机连接…

[240905] 如何使用 JAX 和 Equinox 构建图卷积网络 | Cascadia 字体家族迎来新成员

目录 如何使用 JAX 和 Equinox 构建图卷积网络1 使用邻接矩阵1.1 邻接矩阵表示法1.2 图卷积层实现1.3 计算过程解释 2 使用边列表2.1 边列表表示法2.2 图卷积层实现2.3 代码解析&#xff1a;jax.ops.segment_sum2.4 计算节点度数示例2.5 边列表表示法的优势 3 模型训练3.1 任务…

VTK平面切割

文章目录 一、vtkClipPolyData二、CapClip三、SolidClip四、vtkClipClosedSurface 本文的主要内容&#xff1a;简单介绍VTK中通过平面切割模型的相关功能。 哪些人适合阅读本文&#xff1a;有一定VTK基础的人。 一、vtkClipPolyData VTK官网描述&#xff1a; vtkClipPolyData使…

解决AbortController中断请求无法再次请求

示例代码 express代码 const express require(express) const app express()//导入cors跨域中间件 const cors require(cors) // 全局注册&#xff0c;加前缀 app.use(cors())app.get(/list, (req, res) > {// 直接返回对象console.log(接收到的参数是, req.query)//结…

一个平台重要的规则改了!

大家好&#xff0c;我是凡人小哥。 是一个不黑、不吹、不跟风、有知识、有骨气的五好小号主。 现在是凌晨1点13分&#xff0c;就在昨天微信公众平台又又又调整了&#xff0c;可能朋友们还在想是不是又要严格了&#xff1f;这次恰恰相反&#xff0c;腾讯把注册微信公众号的门槛…

F - Simplified Reversi 矩阵侧边视角 修改

1 行修改的时候只&#x1f525;影响的是哪些位置 因为Queries are pairwise distinct. 也就是当前行修改过之后 当前行就不会重复修改。额。实际上如果没有这个条件也无所谓的 我们可以用一个vis来判重就行 2 用什么东西可以维护这样的区间修改 主要还是行列间的 查询和修改的互…

【Linux网络编程八】实现最简单Http服务器(基于Tcp套接字)

基于TCP套接字实现一个最简单的Http服务器 Ⅰ.Http请求和响应格式1.请求格式2.响应格式3.http中请求格式中细节字段4.http中响应格式中细节字段 Ⅱ.域名ip与URLⅢ.web根目录Ⅳ.Http服务器是如何工作的&#xff1f;一.获取请求二.分析请求2.1反序列化2.2解析url 三.构建响应3.1构…

RK3588开发板利用udp发送和接收数据

目录 1 send.cpp 2 receive.cpp 3 编译运行 4 测试 1 send.cpp #include <iostream> #include <string> #include <cstring> #include <unistd.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> //…

Nginx源码阅读1-内存池

首先我们来看一下他的一个基础组件&#xff1a;内存池组件。为什么先从内存池开始呢&#xff0c;因为后面 nginx 的内置数据结构&#xff0c;如&#xff1a;array&#xff0c;string 等都是从内存池分配的。 为什么需要内存池呢&#xff1f;在高并发的前提下&#xff0c;会大量…

【机器学习】K近邻

2. K近邻 K近邻算法&#xff08;KNN&#xff09;的基本思想是通过计算待分类样本与训练集中所有样本之间的距离&#xff0c;选取距离最近的 K 个样本&#xff0c;根据这些样本的标签进行分类或回归。KNN 属于非参数学习算法&#xff0c;因为它不假设数据的分布形式&#xff0c…

海外合规|新加坡网络安全认证计划简介(三)-Cyber Trust

一、 认证简介&#xff1a; Cyber Trust标志是针对数字化业务运营更为广泛的组织的网络安全认证。该标志针对的是规模较大或数字化程度较高的组织&#xff0c;因为这些组织可能具有更高的风险水平&#xff0c;需要他们投资专业知识和资源来管理和保护其 IT 基础设施和系统。Cy…

开源 AI 智能名片 O2O 商城小程序:引入淘汰机制,激发社交电商新活力

摘要&#xff1a;本文深入探讨在社交电商领域中&#xff0c;开源 AI 智能名片 O2O 商城小程序如何通过设置淘汰机制&#xff0c;实现“良币驱逐劣币”&#xff0c;激励士气&#xff0c;为社交电商企业注入新的活力。通过分析缺乏淘汰机制的弊端以及设置淘汰机制的优势&#xff…

用python发送邮件

用python发送邮件需要smtplib&#xff0c;email包,例子如下&#xff1a; import smtplib from email.mime.text import MIMEText from email.mime.multipart import MIMEMultipartdef send_email():# 邮件的基本信息sender_email "xx.com" # 发送方邮箱receiver_e…

CAAC无人机飞行执照理论培训课程详解

CAAC&#xff08;中国民用航空局&#xff09;无人机飞行执照的理论培训课程是确保无人机飞手全面掌握飞行和应用技能的重要环节。以下是对该理论培训课程的详细解析&#xff1a; 一、课程目标 理论培训课程的主要目标是使学员&#xff1a; 了解并掌握无人机相关的法律法规、…