这篇文章给大家分享的是有关微信小程序中自定义模态弹窗的示例分析的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。首先看看官方提供的模态弹窗,供大家参考,具体内容如下api如下:示例:这样的模态弹窗,充其量只能做个alert,提示一下信息。但是并不能使用它来处理复杂性的弹窗业务,因此写了Michael从新自定义了一个,采用了仿原生的样式写法wxml:<!--button--> <view class="btn" bindtap="powerDrawer" data-statu="open">button</view> <!--mask--> <view class="drawer_screen" bindtap="powerDrawer" data-statu="close" wx:if="{{showModalStatus}}"></view> <!--content--> <!--使用animation属性指定需要执行的动画--> <view animation="{{animationData}}" class="drawer_box" wx:if="{{showModalStatus}}"> <!--drawer content--> <view class="drawer_title">弹窗标题</view> <view class="drawer_content"> <view class="top grid"> <label class="title col-0">标题</label> <input class="input_base input_h40 col-1" name="rName" value="可自行定义内容"></input> </view> <view class="top grid"> <label class="title col-0">标题</label> <input class="input_base input_h40 col-1" name="mobile" value="110"></input> </view> <view class="top grid"> <label class="title col-0">标题</label> <input class="input_base input_h40 col-1" name="phone" value="拒绝伸手党"></input> </view> <view class="top grid"> <label class="title col-0">标题</label> <input class="input_base input_h40 col-1" name="Email" value="仅供学习使用"></input> </view> <view class="top bottom grid"> <label class="title col-0">备注</label> <input class="input_base input_h40 col-1" name="bz"></input> </view> </view> <view class="btn_ok" bindtap="powerDrawer" data-statu="close">确定</view> </view>wxss:/*button*/ .btn { width: 80%; padding: 20rpx 0; border-radius: 10rpx; text-align: center; margin: 40rpx 10%; background: #000; color: #fff; } /*mask*/ .drawer_screen { width: 100%; height: 100%; position: fixed; top: 0; left: 0; z-index: 1000; background: #000; opacity: 0.5; overflow: hidden; } /*content*/ .drawer_box { width: 650rpx; overflow: hidden; position: fixed; top: 50%; left: 0; z-index: 1001; background: #FAFAFA; margin: -150px 50rpx 0 50rpx; border-radius: 3px; } .drawer_title{ padding:15px; font: 20px "microsoft yahei"; text-align: center; } .drawer_content { height: 210px; overflow-y: scroll; /*超出父盒子高度可滚动*/ } .btn_ok{ padding: 10px; font: 20px "microsoft yahei"; text-align: center; border-top: 1px solid #E8E8EA; color: #3CC51F; } .top{ padding-top:8px; } .bottom { padding-bottom:8px; } .title { height: 30px; line-height: 30px; width: 160rpx; text-align: center; display: inline-block; font: 300 28rpx/30px "microsoft yahei"; } .input_base { border: 2rpx solid #ccc; padding-left: 10rpx; margin-right: 50rpx; } .input_h40{ height: 30px; line-height: 30px; } .input_h70{ height: 60px; } .input_view{ font: 12px "microsoft yahei"; background: #fff; color:#000; line-height: 30px; } input { font: 12px "microsoft yahei"; background: #fff; color:#000 ; } radio{ margin-right: 20px; } .grid { display: -webkit-box; display: box; } .col-0 {-webkit-box-flex:0;box-flex:0;} .col-1 {-webkit-box-flex:1;box-flex:1;} .fl { float: left;} .fr { float: right;}js:Page({ data: { showModalStatus: false }, powerDrawer: function (e) { var currentStatu = e.currentTarget.dataset.statu; this.util(currentStatu) }, util: function(currentStatu){ /* 动画部分 */ // 第1步:创建动画实例 var animation = wx.createAnimation({ duration: 200, //动画时长 timingFunction: "linear", //线性 delay: 0 //0则不延迟 }); // 第2步:这个动画实例赋给当前的动画实例 this.animation = animation; // 第3步:执行第一组动画 animation.opacity(0).rotateX(-100).step(); // 第4步:导出动画对象赋给数据对象储存 this.setData({ animationData: animation.export() }) // 第5步:设置定时器到指定时候后,执行第二组动画 setTimeout(function () { // 执行第二组动画 animation.opacity(1).rotateX(0).step(); // 给数据对象储存的第一组动画,更替为执行完第二组动画的动画对象 this.setData({ animationData: animation }) //关闭 if (currentStatu == "close") { this.setData( { showModalStatus: false } ); } }.bind(this), 200) // 显示 if (currentStatu == "open") { this.setData( { showModalStatus: true } ); } } })运行:感谢各位的阅读!关于“微信小程序中自定义模态弹窗的示例分析”这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,让大家可以学到更多知识,如果觉得文章不错,可以把它分享出去让更多的人看到吧!...
小编给大家分享一下怎么在Kubernetes上运行高可用的WordPress和MySQL,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!在Kubernetes上运行高可用的WordPress和MySQLWordPress是用于编辑和发布Web内容的主流平台。在本教程中,我将逐步介绍如何使用Kubernetes来构建高可用性(HA)WordPress部署。WordPress由两个主要组件组成:WordPress PHP服务器和用于存储用户信息、帖子和网站数据的数据库。我们需要让整个应用程序中这两个组件在高可用的同时都具备容错能力。在硬件和地址发生变化的时候,运行高可用服务可能会很困难:非常难维护。借助Kubernetes以及其强大的网络组件,我们可以部署高可用的WordPress站点和MySQL数据库,而无需(几乎无需)输入单个IP地址。在本教程中,我将向你展示如何在Kubernetes中创建存储类、服务、配置映射和集合,如何运行高可用MySQL,以及如何将高可用WordPress集群挂载到数据库服务上。如果你还没有Kubernetes集群,你可以在Amazon、Google或者Azure上轻松找到并且启动它们,或者在任意的服务器上使用Rancher Kubernetes Engine (RKE)架构概述现在我来简要介绍一下我们将要使用的技术及其功能:WordPress应用程序文件的存储:具有GCE持久性磁盘备份的NFS存储数据库集群:带有用于奇偶校验的xtrabackup的MySQL应用程序级别:挂载到NFS存储的WordPress DockerHub映像负载均衡和网络:基于Kubernetes的负载均衡器和服务网络该体系架构如下所示:在K8s中创建存储类、服务和配置映射在Kubernetes中,状态集提供了一种定义pod初始化顺序的方法。我们将使用一个有状态的MySQL集合,因为它能确保我们的数据节点有足够的时间在启动时复制先前pods中的记录。我们配置这个状态集的方式可以让MySQL主机在其他附属机器之前先启动,因此当我们扩展时,可以直接从主机将克隆发送到附属机器上。首先,我们需要创建一个持久卷存储类和配置映射,以根据需要应用主从配置。我们使用持久卷,避免数据库中的数据受限于集群中任何特定的pods。这种方式可以避免数据库在MySQL主机pod丢失的情况下丢失数据,当主机pod丢失时,它可以重新连接到带xtrabackup的附属机器,并将数据从附属机器拷贝到主机中。MySQL的复制负责主机-附属的复制,而xtrabackup负责附属-主机的复制。要动态分配持久卷,我们使用GCE持久磁盘创建存储类。不过,Kubernetes提供了各种持久性卷的存储方案:# storage-class.yamlkind: StorageClassapiVersion: storage.k8s.io/v1metadata: name: slowprovisioner: kubernetes.io/gce-pdparameters: type: pd-standard zone: us-central1-a创建类,并且使用指令:$ kubectl create -f storage-class.yaml部署它。接下来,我们将创建configmap,它指定了一些在MySQL配置文件中设置的变量。这些不同的配置由pod本身选择有关,但它们也为我们提供了一种便捷的方式来管理潜在的配置变量。创建名为mysql-configmap.yaml的YAML文件来处理配置,如下:# mysql-configmap.yamlapiVersion: v1kind: ConfigMapmetadata: name: mysql labels: app: mysqldata: master.cnf: | # Apply this config only on the master. [mysqld] log-bin skip-host-cache skip-name-resolve slave.cnf: | # Apply this config only on slaves. [mysqld] skip-host-cache skip-name-resolve创建configmap并使用指令:$ kubectl create -f mysql-configmap.yaml来部署它。接下来我们要设置服务以便MySQL pods可以互相通信,并且我们的WordPress pod可以使用mysql-services.yaml与MySQL通信。这也为MySQL服务启动了服务负载均衡器。# mysql-services.yaml# Headless service for stable DNS entries of StatefulSet members.apiVersion: v1kind: Servicemetadata: name: mysql labels: app: mysqlspec: ports: - name: mysql port: 3306 clusterIP: None selector: app: mysql通过此服务声明,我们就为实现一个多写入、多读取的MySQL实例集群奠定了基础。这种配置是必要的,每个WordPress实例都可能写入数据库,所以每个节点都必须准备好读写。执行命令 $ kubectl create -f mysql-services.yaml来创建上述的服务。到这为止,我们创建了卷声明存储类,它将持久磁盘交给所有请求它们的容器,我们配置了configmap,在MySQL配置文件中设置了一些变量,并且我们配置了一个网络层服务,负责对MySQL服务器请求的负载均衡。上面说的这些只是准备有状态集的框架, MySQL服务器实际在哪里运行,我们接下来将继续探讨。配置有状态集的MySQL本节中,我们将编写一个YAML配置文件应用于使用了状态集的MySQL实例。我们先定义我们的状态集:1, 创建三个pods并将它们注册到MySQL服务上。2, 按照下列模版定义每个pod:♢ 为主机MySQL服务器创建初始化容器,命名为init-mysql.♢ 给这个容器使用mysql:5.7镜像♢ 运行一个bash脚本来启动xtrabackup♢ 为配置文件和configmap挂载两个新卷3, 为主机MySQL服务器创建初始化容器,命名为clone-mysql.♢ 为该容器使用Google Cloud Registry的xtrabackup:1.0镜像♢ 运行bash脚本来克隆上一个同级的现有xtrabackups♢ 为数据和配置文件挂在两个新卷♢ 该容器有效地托管克隆的数据,便于新的附属容器可以获取它4, 为附属MySQL服务器创建基本容器♢ 创建一个MySQL附属容器,配置它连接到MySQL主机♢ 创建附属xtrabackup容器,配置它连接到xtrabackup主机5, 创建一个卷声明模板来描述每个卷,每个卷是一个10GB的持久磁盘下面的配置文件定义了MySQL集群的主节点和附属节点的行为,提供了运行附属客户端的bash配置,并确保在克隆之前主节点能够正常运行。附属节点和主节点分别获得他们自己的10GB卷,这是他们在我们之前定义的持久卷存储类中请求的。apiVersion: apps/v1beta1kind: StatefulSetmetadata: name: mysqlspec: selector: matchLabels: app: mysql serviceName: mysql replicas: 3 template: metadata: labels: app: mysql spec: initContainers: - name: init-mysql image: mysql:5.7 command: - bash - "-c" - | set -ex # Generate mysql server-id from pod ordinal index. [[ `hostname` =~ -([0-9]+)$ ]] || exit 1 ordinal=${BASH_REMATCH[1]} echo [mysqld] > /mnt/conf.d/server-id.cnf # Add an offset to avoid reserved server-id=0 value. echo server-id=$((100 + $ordinal)) >> /mnt/conf.d/server-id.cnf # Copy appropriate conf.d files from config-map to emptyDir. if [[ $ordinal -eq 0 ]]; then cp /mnt/config-map/master.cnf /mnt/conf.d/ else cp /mnt/config-map/slave.cnf /mnt/conf.d/ fi volumeMounts: - name: conf mountPath: /mnt/conf.d - name: config-map mountPath: /mnt/config-map - name: clone-mysql image: gcr.io/google-samples/xtrabackup:1.0 command: - bash - "-c" - | set -ex # Skip the clone if data already exists. [[ -d /var/lib/mysql/mysql ]] && exit 0 # Skip the clone on master (ordinal index 0). [[ `hostname` =~ -([0-9]+)$ ]] || exit 1 ordinal=${BASH_REMATCH[1]} [[ $ordinal -eq 0 ]] && exit 0 # Clone data from previous peer. ncat --recv-only mysql-$(($ordinal-1)).mysql 3307 | xbstream -x -C /var/lib/mysql # Prepare the backup. xtrabackup --prepare --target-dir=/var/lib/mysql volumeMounts: - name: data mountPath: /var/lib/mysql subPath: mysql - name: conf mountPath: /etc/mysql/conf.d containers: - name: mysql image: mysql:5.7 env: - name: MYSQL_ALLOW_EMPTY_PASSWORD value: "1" ports: - name: mysql containerPort: 3306 volumeMounts: - name: data mountPath: /var/lib/mysql subPath: mysql - name: conf mountPath: /etc/mysql/conf.d resources: requests: cpu: 500m memory: 1Gi livenessProbe: exec: command: ["mysqladmin", "ping"] initialDelaySeconds: 30 periodSeconds: 10 timeoutSeconds: 5 readinessProbe: exec: # Check we can execute queries over TCP (skip-networking is off). command: ["mysql", "-h", "127.0.0.1", "-e", "SELECT 1"] initialDelaySeconds: 5 periodSeconds: 2 timeoutSeconds: 1 - name: xtrabackup image: gcr.io/google-samples/xtrabackup:1.0 ports: - name: xtrabackup containerPort: 3307 command: - bash - "-c" - | set -ex cd /var/lib/mysql # Determine binlog position of cloned data, if any. if [[ -f xtrabackup_slave_info ]]; then # XtraBackup already generated a partial "CHANGE MASTER TO" query # because we're cloning from an existing slave. mv xtrabackup_slave_info change_master_to.sql.in # Ignore xtrabackup_binlog_info in this case (it's useless). rm -f xtrabackup_binlog_info elif [[ -f xtrabackup_binlog_info ]]; then # We're cloning directly from master. Parse binlog position. [[ `cat xtrabackup_binlog_info` =~ ^(.*?)[[:space:]]+(.*?)$ ]] || exit 1 rm xtrabackup_binlog_info echo "CHANGE MASTER TO MASTER_LOG_FILE='${BASH_REMATCH[1]}',\ MASTER_LOG_POS=${BASH_REMATCH[2]}" > change_master_to.sql.in fi # Check if we need to complete a clone by starting replication. if [[ -f change_master_to.sql.in ]]; then echo "Waiting for mysqld to be ready (accepting connections)" until mysql -h 127.0.0.1 -e "SELECT 1"; do sleep 1; done echo "Initializing replication from clone position" # In case of container restart, attempt this at-most-once. mv change_master_to.sql.in change_master_to.sql.orig mysql -h 127.0.0.1 <<EOF $(<change_master_to.sql.orig), MASTER_HOST='mysql-0.mysql', MASTER_USER='root', MASTER_PASSWORD='', MASTER_CONNECT_RETRY=10; START SLAVE; EOF fi # Start a server to send backups when requested by peers. exec ncat --listen --keep-open --send-only --max-conns=1 3307 -c \ "xtrabackup --backup --slave-info --stream=xbstream --host=127.0.0.1 --user=root" volumeMounts: - name: data mountPath: /var/lib/mysql subPath: mysql - name: conf mountPath: /etc/mysql/conf.d resources: requests: cpu: 100m memory: 100Mi volumes: - name: conf emptyDir: {} - name: config-map configMap: name: mysql volumeClaimTemplates: - metadata: name: data spec: accessModes: ["ReadWriteOnce"] resources: requests: storage: 10Gi将该文件存为mysql-statefulset.yaml,输入kubectl="" create="" -f="" mysql-statefulset.yaml并让kubernetes部署你的数据库。现在当你调用$="" kubectl="" get="" pods,你应该看到3个pods启动或者准备好,其中每个pod上都有两个容器。主节点pod表示为mysql-0,而附属的pods为mysql-1和mysql-2.让pods执行几分钟来确保xtrabackup服务在pod之间正确同步,然后进行wordpress的部署。您可以检查单个容器的日志来确认没有错误消息抛出。 查看日志的命令为$="" logs="" <container_name="">主节点xtrabackup容器应显示来自附属的两个连接,并且日志中不应该出现任何错误。部署高可用的WordPress整个过程的最后一步是将我们的WordPress pods部署到集群上。为此我们希望为WordPress的服务和部署进行定义。为了让WordPress实现高可用,我们希望每个容器运行时都是完全可替换的,这意味着我们可以终止一个,启动另一个而不需要对数据或服务可用性进行修改。我们也希望能够容忍至少一个容器的失误,有一个冗余的容器负责处理slack。WordPress将重要的站点相关数据存储在应用程序目录/var/www/html中。对于要为同一站点提供服务的两个WordPress实例,该文件夹必须包含相同的数据。当运行高可用WordPress时,我们需要在实例之间共享/var/www/html文件夹,因此我们定义一个NGS服务作为这些卷的挂载点。下面是设置NFS服务的配置,我提供了纯英文的版本:使用指令$ kubectl create -f nfs.yaml部署NFS服务。现在,我们需要运行$ kubectl describe services nfs-server获得IP地址,这在后面会用到。注意:将来,我们可以使用服务名称讲这些绑定在一起,但现在你需要对IP地址进行硬编码。# wordpress.yamlapiVersion: v1kind: Servicemetadata: name: wordpress labels: app: wordpressspec: ports: - port: 80 selector: app: wordpress tier: frontend type: LoadBalancer---apiVersion: v1kind: PersistentVolumemetadata: name: nfsspec: capacity: storage: 20G accessModes: - ReadWriteMany nfs: # FIXME: use the right IP server: <ip of="" the="" nfs="" service=""> path: "/"---apiVersion: v1kind: PersistentVolumeClaimmetadata: name: nfsspec: accessModes: - ReadWriteMany storageClassName: "" resources: requests: storage: 20G---apiVersion: apps/v1beta1 # for versions before 1.8.0 use apps/v1beta1kind: Deploymentmetadata: name: wordpress labels: app: wordpressspec: selector: matchLabels: app: wordpress tier: frontend strategy: type: Recreate template: metadata: labels: app: wordpress tier: frontend spec: containers: - image: wordpress:4.9-apache name: wordpress env: - name: WORDPRESS_DB_HOST value: mysql - name: WORDPRESS_DB_PASSWORD value: "" ports: - containerPort: 80 name: wordpress volumeMounts: - name: wordpress-persistent-storage mountPath: /var/www/html volumes: - name: wordpress-persistent-storage persistentVolumeClaim: claimName: nfs我们现在创建了一个持久卷声明,和我们之前创建的NFS服务建立映射,然后将卷附加到WordPress pod上,即/var/www/html根目录,这也是WordPress安装的地方。这里保留了集群中WordPress pods的所有安装和环境。有了这些配置,我们就可以对任何WordPress节点进行启动和拆除,而数据能够留下来。因为NFS服务需要不断使用物理卷,该卷将保留下来,并且不会被回收或错误分配。使用指令$ kubectl create -f wordpress.yaml部署WordPress实例。默认部署只会运行一个WordPress实例,可以使用指令$ kubectl scale --replicas=<number of="" replicas="">deployment/wordpress扩展WordPress实例数量。要获得WordPress服务负载均衡器的地址,你需要输入$ kubectl get services wordpress并从结果中获取EXTERNAL-IP字段来导航到WordPress。弹性测试OK,现在我们已经部署好了服务,那我们来拆除一下它们,看看我们的高可用架构如何处理这些混乱。在这种部署方式中,唯一剩下的单点故障就是NFS服务(原因总结在文末结论中)。你应该能够测试其他任何的服务来了解应用程序是如何响应的。现在我已经启动了WordPress服务的三个副本,以及MySQL服务中的一个主两个附属节点。首先,我们先kill掉其他而只留下一个WordPress节点,来看看应用如何响应:$ kubectl scale --replicas=1 deployment/wordpress现在我们应该看到WordPress部署的pod数量有所下降。$ kubectl get pods应该能看到WordPress pods的运行变成了1/1。点击WordPress服务IP,我们将看到与之前一样的站点和数据库。如果要扩展复原,可以使用$ kubectl scale --replicas=3 deployment/wordpress再一次,我们可以看到数据包留在了三个实例中。下面测试MySQL的状态集,我们使用指令缩小备份的数量:$ kubectl scale statefulsets mysql --replicas=1我们会看到两个附属从该实例中丢失,如果主节点在此时丢失,它所保存的数据将保存在GCE持久磁盘上。不过就必须手动从磁盘恢复数据。如果所有三个MySQL节点都关闭了,当新节点出现时就无法复制。但是,如果一个主节点发生故障,一个新的主节点就会自动启动,并且通过xtrabackup重新配置来自附属节点的数据。因此,在运行生产数据库时,我不建议以小于3的复制系数来运行。在结论段中,我们会谈谈针对有状态数据有什么更好的解决方案,因为Kubernetes并非真正是为状态设计的。结论和建议到现在为止,你已经完成了在Kubernetes构建并部署高可用WordPress和MySQL的安装!不过尽管取得了这样的效果,你的研究之旅可能还远没有结束。可能你还没注意到,我们的安装仍然存在着单点故障:NFS服务器在WordPress pods之间共享/var/www/html目录。这项服务代表了单点故障,因为如果它没有运行,在使用它的pods上html目录就会丢失。教程中我们为服务器选择了非常稳定的镜像,可以在生产环境中使用,但对于真正的生产部署,你可以考虑使用GlusterFS对WordPress实例共享的目录开启多读多写。这个过程涉及在Kubernetes上运行分布式存储集群,实际上这不是Kubernetes构建的,因此尽管它运行良好,但不是长期部署的理想选择。对于数据库,我个人建议使用托管的关系数据库服务来托管MySQL实例,因为无论是Google的CloudSQL还是AWS的RDS,它们都以更合理的价格提供高可用和冗余处理,并且不需担心数据的完整性。Kuberntes并不是围绕有状态的应用程序设计的,任何建立在其中的状态更多都是事后考虑。目前有大量的解决方案可以在选择数据库服务时提供所需的保证。也就是说,上面介绍的是一种理想的流程,由Kubernetes教程、web中找到的例子创建一个有关联的现实的Kubernetes例子,并且包含了Kubernetes 1.8.x中所有的新特性。以上是“怎么在Kubernetes上运行高可用的WordPress和MySQL”这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注辰讯云资讯频道!...
小编给大家分享一下nginx正向代理与反向代理的示例分析,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!正向代理就是假设有一个内网内网有两台机器,这两台机器只有 a 可以上网b 不能上网,但是 a 和 b 通过网络相连接这时如果 b 想访问外网,就可以通过 a 来正向代理访问外网正向代理就是在内网中模拟目标服务器,把内网中其它机器的请求转发给外网中的真正的目标服务器所以正向代理是接受内网其它机器的请求的反向代理则是反过来也是一个内网,有几台机器,只有其中一台与外网连接但是反向代理接受的不是内网机器的访问请求反向代理接受的是外网过来的访问请求然后把请求转发到内网中的其它机器上去外网发出请求的用户并不知道反向代理的服务器把请求转发给了谁要在一台机器上设置正向代理的功能如图,编辑一个nginx配置文件上图就是配置文件内容如果配置一台服务器作为正向代理服务器那么这个虚拟主机配置文件就必须是默认虚拟主机因为所有访问这台机器的网络请求应该先访问这个虚拟主机才对所以这里要设置 default_server然后还要把原来的 默认虚拟主机 配置文件名称修改掉如图,把 default.conf 配置文件的名称修改一下这样就取消了原来的默认虚拟主机配置文件了因为默认的默认虚拟主机配置文件就是 default.conf配置文件里面的 resolver 119.29.29.29意思是配置一个 dns 地址因为是做正向代理,接受了内网请求的域名后要把请求发送给真正要访问的服务器但是内网发送的域名是没有包含 ip 地址的所以还要把域名发送给 dns 服务器解析 ip 地址拿到 ip地址后才能转发到要访问的服务器上去所以这里需要配置一个 dns 地址接受了内网域名后,就会把域名发送到这个 dns 上去解析下面的 location 按照图中设置就可以了这样正向代理服务器接受内网机器请求后就会把域名发到配置的dns上解析,然后访问真正的服务器再把真正服务器返回的内容发送给发出请求的内网机器nginx反向代理做一个反向代理的例子如图建立一个测试的虚拟主机配置文件监听 8080 端口,域名为 www.test.com根目录是 /data/wwwroot/test.com访问虚拟主机显示的首页文件是 index.html如图,创建虚拟主机的根目录 /data/wwwroot/test.com然后使用 echo "test.com_8080" > !$/index.html创建一个内容为 test.com_8080 的首页文件这个文件在 /data/wwwroot/test.com 目录里面如图,新建一个反向代理的虚拟主机配置文件监听 80 端口,域名为 www.test.com下面的 location / 里面就是反向代理的配置当访问这个虚拟主机的时候,就会把访问请求发送给 127.0.0.1:8080如图,使用 curl 访问 127.0.0.1:8080 虚拟主机成功返回了 test.com_8080 这说明这个虚拟主机能够被访问如图,再创建一个虚拟主机配置文件跟之前的 test 虚拟主机差不多但是这个虚拟主机并没有设置 域名location 设置返回的内容是 8080 default 字符串保存退出,重载 nginx还要把 test虚拟主机的 default server 设置取消掉那么现在 127.0.0.1:8080 对应两个虚拟主机一个是 test 虚拟主机,另外一个是 8080 default 虚拟主机这两个虚拟主机的 ip 端口都是一模一样的它们的区别是 test 虚拟主机是有域名的而 8080 default 虚拟主机是没有域名的现在已经设置了 8080 default 为默认虚拟主机所以如果只访问 127.0.0.1:8080 的话访问的一定是 8080 default 虚拟主机如果想访问 test 虚拟主机,就需要加上 test 虚拟主机的域名才能成功访问 test 虚拟主机如图,可以看到访问 curl 127.0.0.1:8080/ 返回的结果是 8080 default使用 curl -x127.0.0.1:8080 www.test.com这里带上了域名,返回的就是 test.com_8080说明想访问 test 虚拟主机,ip端口还需要绑定域名才行如图,curl 访问 127.0.0.1:80 域名 www.test.com返回的是 test.com_8080 说明这个反向代理成功了我们访问的是 80 端口,实际却返回了 8080 端口的虚拟主机的内容如图,这里把反向代理虚拟主机里面的 proxy_pass 行下面的都注释掉保存退出,重载 nginx如图,再使用 curl 访问 127.0.0.1:80 域名 www.test.com实际返回的却是 8080 default而我们想访问的却是 test 虚拟主机如图,proxy_set_header Host $host;这一行代码就是指定访问的域名上面设置了 127.0.0.1:8080反向代理的时候就会指向这个 ip端口如果不设置 host 那就只会访问 127.0.0.1:8080 的虚拟主机如果设置了 host ,那么就会指向跟指定的 host 绑定的 127.0.0.1:8080这里的 $host 是系统变量,实际的值就是当前的虚拟主机的 server_name也就是 www.test.com ,server_name 是什么,host的值就是什么这里设置了 host 就相当于 curl -x127.0.0.1:8080 www.test.com如果这里不设置 host 那么就只会访问 127.0.0.1:8080这样就可以把 域名 跟 ip端口进行绑定如图,除了写 ip端口之外,proxy_pass 也可以直接写域名这里写的是 www.123.com:8080/但是这样写的话, nginx 并不知道这个域名指向哪里所以还需要在系统里面绑定对应的 ip例如在 /etc/hosts 文件里面,写入对应的 域名和 ip 进行绑定这样nginx 里面的 proxy_pass 的域名系统就会解析出一个 Ip 地址然后再访问这个 ip端口下面的 proxy_header Host 作用就是设置一个 域名这个域名会与上面的 ip端口绑定访问如果上面的 ip端口 写的不是 ip 而是域名跟下面指定的域名是不冲突的,因为上面写的域名的作用是用来解析ip的下面指定的域名才会跟上面解析出来的 ip端口进行绑定访问这个例子使用的是 $host 这是 nginx全局变量这个变量实际是对应了一个值的,就是当前虚拟主机 server_name 的值但是一般来说,还是直接写 ip 端口方便一些上面就是指定 ip端口下面指定跟 ip端口绑定的 host 域名nginx反向代理02如图,proxy_pass 指令后面可以跟 url有三种格式,传输协议+域名+uri (访问路径)传输协议+ip端口+uri传输协议+socket这里 unix ,http ,https 都是传输协议的种类域名+uri 和 ip端口+uri 还有 socket 都是访问的路径socket 一般是某个程序专用的访问端口访问某个socket就是访问某个特定的程序,所以不需要使用路径如图,写 proxy_pass 的时候,不同的写法有不同的结果比如 location /aming/如果访问的路径包含 /aming/ 就会触发这里的proxy_pass 就会执行但是location 里面的 proxy_pass 不同的写法会导致实际访问的路径有差别虽然因为访问的路径包含 /aming/ 目录才执行 proxy_pass但是实际访问的路径不一定包含 /aming/这个例子是访问虚拟主机内的 /aming/a.html 文件根据 proxy_pass 的不同写法实际上会访问到不同的路径去如果 ip端口 后面没有接任何目录符号就会访问 /aming/a.html,这是我们想要的如果 ip端口后面接了根目录符号 /那么就会直接访问根目录里面的 a.html文件,这显然不对ip端口后面接 /linux/ 那么就会访问 /linux/ 里面的 a.html文件如果 ip端口后面是 /linux 最后没有跟目录符号 /就会访问 /linuxa.html所以如果想正确访问 /aming/a.html有两种写法,一种是 ip端口后面不要加任何目录符号 /第二种是完整的写成 ip端口/aming/ 这样写根据上面示例可以发现,ip端口后面不管是什么目录实际访问路径就会变成直接把最终要访问的文件名称 a.html直接添加到 ip端口 后面的目录上去所以 ip端口后面不写任何目录符号的话,系统才会自己添加 /aming/a.html 这个目录路径一旦有任何目录符号存在,就会直接把 a.html 放在这个目录符号后面第二种情况是,ip端口+ /linux实际结果是访问 /linuxa.html这可能是因为 linux 后面没有跟上任何目录符号 /所以系统把 linux 认为是一个没有写完的文件名称然后就直接把 a.html 这个文件名称跟 linux 粘贴在一起这样就变成了要访问的文件是 /linuxa.html 的形式所以不管写什么路径,后面一定要跟上目录符号 /反向代理03如图,proxy_set_header 是设置被代理的服务器可以接收到的 header 信息的比如有三台电脑 a b ca 是我们用来访问的电脑,我们从 a 发出访问请求b 是反向代理服务器,b 接收我们发出的访问请求c 是被反向代理的服务器,也就是我们真正要访问的服务器b 会把我们的访问请求转发给 c如果不设置 proxy_set_header 的话,b 转发请求给 c 的时候就不会带上相应的 header 信息如果设置了这个参数,在转发请求的时候就会带上对应的 header 信息其中 $remote_addr 和 $proxy_add_x_forwarded_for 这两个变量是 nginx 的内置变量$remote_addr 变量里面保存的是 b 反向代理服务器本身的 ip 地址$proxy_add_x_forwarded_for 变量里面保存的是 a 客户端电脑的 ip 地址如果不设置这个变量的话,c 服务器实际上是不知道访问请求的真实来源地址的而设置了这个变量, c 服务器就可以知道这个访问请求是哪一个ip地址发过来的如图,编辑 www.test.com 虚拟主机的配置文件假设这个虚拟主机是我们要访问的 c 服务器location 里面设置了两个echo 显示访问请求的来源地址,和真实来源地址$remote_addr 记录了反向代理服务器的地址$proxy_add_x_forwarded_for 记录了访问请求的真实来源地址,也就是客户端的地址这样设置,访问这个虚拟主机的时候,就会显示这两个变量里面保存的值保存退出,然后重载配置文件如图,编辑反向代理服务器虚拟主机的配置文件如图,可以看到 location 里面proxy_set_header X-Real-IP 和 proxy_set_header X-Forwarded-For 这两行是被注释掉的先做个测试,保存退出重载配置文件如图,使用 curl 测试从 192.168.133.140:80 发出访问请求192.168.133.140 这个 ip 实际就是 客户端 ip因为访问请求就是从这个 ip 发出来的但是可以看到,测试之后,实际显示的却是两个 127.0.0.1 的回环地址并没有 192.168.133.140 这个 ip在这个测试里面,反向代理服务器 和 真实服务器 都在本机上面所以真实服务器 c 接收的访问请求来源 ip 就是本机的回环地址反向代理服务 b 发送请求给 真实服务器 c 走的就是 127.0.0.1 的内部回环地址因为这两个服务器都在本机上,本机上的程序之间通讯基本都是走 127.0.0.1 回环地址的所以 c 的 $remote_addr 的值就是 127.0.0.1因为反向代理服务器 b 没有设置 $proxy_add_x_forwarded_for所以真实服务器 c 的接收到的 $proxy_add_x_forwarded_for 变量值就是请求发送过来的 ip也就是 127.0.0.1$proxy_add_x_forwarded_for 这个变量实际上是记录了从客户端开始请求总共经过了哪些 ip 地址的一个变量值,多个 ip 地址之间使用逗号分隔如果发送的访问请求没有设置 $proxy_add_x_forwarded_for 这个变量的话那么接收方的这个变量的值就只是访问请求发送过来的上一个 ip , 也就是跟 remote_addr 相同比如访问请求从 a 到 b 到 c如果 b 设置了 $proxy_add_x_forwarded_for 的话那么这个变量的格式就是 a_ip, b_ip也就是记录了 a 的ip 和 b 的ip如果中间还经过更多的服务器的话,那么它们的 ip 也会被记录下来,使用逗号分隔当然每一台代理服务器都需要设置 $proxy_add_x_forwarded_for 这个变量才行不然下一台代理服务器的 $proxy_add_x_forwarded_for 这个变量将不会记录到之前经过的 ip只能够记录到上一台服务器的 ip所以在这个测试里面,因为 b 没有设置 $proxy_add_x_forwarded_for所以 c 服务的 $proxy_add_x_forwarded_for 变量的值等于 $remote_addr 的值如图,第二次测试,编辑反向代理服务器 b 的配置文件把 location 里面的 X-Real-IP 和 X-Forwarded-For 两行注释去掉保存退出重载配置文件如图,再次测试可以看到返回的结果,第一行 remote_addr 的值是 127.0.0.1这是 代理服务器 b 的 ip第二行 $proxy_add_x_forwarded_for 的值是两个 ipcurl 命令里面,访问请求是从 192.168.133.140 发出的也就是说,客户端 a 的 ip 就是 192.168.133.140b 的 ip 就是 127.0.0.1$proxy_add_x_forwarded_for 记录的是到达 c 的访问请求经过了哪些 ip访问请求是从 a 到 b 再从 b 到 c 的所以 $proxy_add_x_forwarded_for 变量 记录了 a 的 ip 和 b 的 ip因为访问请求在到达 c 之前经过了这两个 ip 地址所以以后做反向代理的时候,这几行变量都要设置后面的真实服务器才能够获取到访问请求的真实 ip 地址反向代理04如图,redirect 应用的场景不多,主要有三种写法功能是修改被代理的服务器返回的 location 和 refresh 头域信息第一种写法,redirect 是返回的头域信息replacement 是要修改的信息redirect 会被修改为 replacement第二种写法是 default 就是默认设置的意思第三种 off 意思就是关闭 redirect功能如图,做一个测试,编辑代理服务器的配置文件要测试成功有几个条件要达成首先,location 后面只能是根目录 / 不能是加别的第二个条件是proxy_pass后面的 url 后面不能加 / 符号正常来说是要 / 结尾的,但是这里不能用 / 结尾然后访问的目录必须真实存在,如果不存在可以创建一个然后再目录里面也可以创建一个 index.html 文件,里面编辑一些字符串内容保存退出重载一下配置文件如图,编辑被代理服务器的配置文件写成如图所示的这种简单格式保存退出重载配置文件如图,curl 测试访问的时候,如果 aming 后面加了 / 结尾,那么就会访问到 index.html 文件但是我们要访问的是目录本身,并不是里面的某个文件所以 crul 的时候,访问的地址结尾不能加上 / 符号这样就可以访问到 aming 目录了可以看到,返回的代码是 301 表示永久重定向下面的 location 后面的字段,是带端口8080 的访问路径如图,编辑被代理服务器的配置文件添加 access_log /tmp/456.log这样就开启了服务器的访问日志,检查访问日志可以更清晰的了解访问过程保存退出重载如图,重新 curl 测试一次,这次测试 aming 结尾是带 / 符号的cat 查看 /tmp/456.log 访问日志发现日志信息没有 host 和 端口 等信息这种情况可以修改 nginx.conf 配置文件里面的 format 配置如图,配置文件里面 log_format main 这三行本来是被注释掉的现在把注释去掉,让这几行产生作用,这个就是日志返回信息的格式设置如图,在最后面添加两个nginx变量 $host $server_port 这两个变量然后保存退出重载一下,这样访问日志显示的信息里面,就会加上这两个变量的信息了如图,编辑代理服务器配置文件,同样添加 access_log 配置日志地址就是 /tmp/proxy.log后面加上 main 因为 nginx.conf 里面配置的格式是用 main 命名的这里加上main 表示使用 main 命名的格式来显示日志信息如图,同样被代理服务器里面的 access_log后面也需要加上 main表示使用 main 的格式显示日志信息保存退出重载一下如图,curl 测试一下,这次测试是用 / 符号结尾的查看 456.log 后端服务器的日志,可以看到,访问的是 8080 端口查看 proxy.log 代理服务器日志,可以看到,访问的是 80 端口网络代码都是 200 这样是正常的如图,这次访问 aming 结尾不带 / 符号可以看到返回的是 301查看 proxy.log 返回的也是 301如图,重新测试一下,再查看两个日志看到 301 再到 200 的日志信息总之确定了我们访问 80 端口,跳转到了 8080 端口但是客户端是访问不到 8080 端口的如图,解决这个问题可以使用 proxy_redirect这里是 http://$host:8080/ /;这样写可以把本来返回的 8080 端口信息给去掉保存退出重载如图,重新测试可以看到,返回的是 301然后 location 后面的地址里面,也没有 8080 端口的信息存在了反向代理05proxy_buffering 是缓冲的意思缓冲就是在内存里面划一块区域,在里面写数据写到一定量的时候,才会把缓冲里面的数据写进硬盘中这样做的话,就可以大大减少硬盘的读写频率如果不做缓冲,每产生一次数据都要读写一次硬盘,对于硬盘的负担就会很大假设有三个对象,客户端 a 代理服务器 b 被代理服务器 ca 发出请求,b 接收请求,转发给 cc 返回数据给 b ,然后 b 再把数据发给 a这是一般的运作情况,但是如果 a 发出许多访问请求或者有很多个客户端发出访问请求那么对于代理服务器 b 和 被代理服务器 c 来说每个请求都要按照这个流程处理一次,负担就会很重proxy_buffering 就是在 代理服务器 b 的内存里面设置一个或多个缓冲区域当缓冲区域数据量满了的时候,才把数据转发给相应的客户端这样代理服务器 b 的数据转发次数就大大减少了,负担就下降了当 proxy_buffering 开启的时候,由 proxy_busy_buffer_size 来决定何时把数据发送给 a在这个过程中,如果 buffer 区域被写满,有数据溢出多出来的数据会被写入到 temp_file 也就是一个临时文件中去,这个文件会存储在硬盘上如果 proxy_buffering 关闭的话,c 反馈的数据就直接由 b 转发给 a而不会有别的操作发生如图,不管 proxy_buffering 是 on 还是 off 的状态proxy_buffer_size 这个选项都是生效的,这个参数是用来设置一个 buffer这个 buffer 存储了服务器反馈的 header 信息如果设置不够大,存储不了 header 信息的话,会出现 502 错误码所以建议设置为 4k如图, proxy_buffers 是定义每个请求的 缓冲区个数 和 每个缓冲区的具体大小这里定义了 8 4k 意思就是有 8个缓冲区,每个缓冲区的大小为 4k那么总缓冲区的大小就是 8*4 = 32 k假设有一万个请求,那么缓冲区就是 8 * 10000 个缓冲区了因为这个设置是针对每个请求来的,而不是总共只有 8 个缓冲区proxy_busy_buffer_size 定义的是达到多少数据量,就把数据传输给客户端这里定义的是 16k ,那么当 b 的属于这个请求的缓冲区接收到 16k 的数据量的时候就会把数据转发给 a这里缓冲区有 8 个,总共 32k 的大小,缓冲区一般来说处于两种状态一个是接收数据,一个是发送数据,并不能同时接收数据和发送数据proxy_busy_buffer_size 定义的就是 发送数据的缓冲区的大小所以 proxy_busy_buffer_size 的大小要比缓冲区的总大小要小才行接收的数据达到 proxy_busy_buffer_size 设置的数据量的时候这些缓冲区就进入发送数据的状态,剩下的缓冲区则是接收数据的状态如果请求反馈的数据总量小于 proxy_busy_buffer_size 设置的值那么 b 接收完成就会直接转发为 a如果请求反馈的数据总量大于 proxy_busy_buffer_size 设置的值那么当缓冲区接收的数据量达到 proxy_busy_buffer_size设置的值的时候就会把这部分的数据先发送给 a如图,proxy_temp_path 定义的是临时文件存放目录举例,a 发出请求,b代理服务器分配给 a 这个请求的 缓冲区 总大小为 32k但是 c 服务对这个请求反馈的数据量为 100 MB 这么大,远远超过缓冲区的大小这种情况下, b 接收 c 的数据的过程中就会有很多数据溢出缓冲区这些溢出的数据会被先保存到 b 的硬盘上的临时文件里面去proxy_temp_path 定义的就是这个临时文件存放的路径,还有子目录层级这里定义的路径是 /usr/local/nginx/proxy_temp 这是一个目录名称临时文件就会存放到这个目录里面去后面的数字 1 2 表示子目录层级前面的目录路径是由我们自己定义的,子目录是系统自动创建的创建多少个子目录层级,可以通过后面的数字设置比如 只写一个 1 就表示子目录只有一层,子目录的名称为 0-9 的命名方式根据定义,proxy_temp_path 支持三级子目录,也就是可以写 3 个数字比如写 1 子目录数量和命名方式 就是 0- 9 共10个如果写 2 就是 00-99 共100个,如果写 3 就是 000-999 共1000个子目录子目录名称也是根据这些数字来命名的如果写 1 3 就表示子目录分两层,第一层是 0-9 10个子目录第二层是 000-999 1000个子目录,也可以反过来写 3 1这样第一层就是 1000 个子目录,每个目录下面第二层又有 10 个子目录proxy_max_temp_file_size 定义的是 临时文件的总大小比如这里设置为 100M 说明每个临时文件最大为 100M临时文件的数据如果传输完成,就会自动删除proxy_temp_file_write_size 定义的是同时写入临时文件数据量的总大小这里定义一个值比如 8k 或者 16k如果同时写入的数据量低于这个值,那么就增加同时写入的数据量如果高于这个值,那么就减少同时写入的数据量因为同时写入的数据量太高,对于硬盘 IO 负担太大,而太小则没有充分用到硬盘的性能所以设置一个值,既不会太快,也不会太慢,充分使用到硬盘的性能,又不会负担过重如图,这是一个使用 proxy_buffering 的例子首先是设置为 on 的状态,也就是打开 buffer 功能头文件存储的 buffer区域大小为 4k然后是其它数据的 buffer 区域为 2 个,每个大小为 4k然后是 busy_buffers 的数据量为 4kbuffer 接收的数据量达到 4k 时就会发送数据然后是临时文件存放的路径定义,定义了两层子目录分别是 1 2 也就是 第一层有 0-9 10个子目录然后每个子目录下面 第二层有 00-99 100个子目录然后是每个临时文件的大小为 20M然后是临时文件同时写入的数据量定义为 8k反向代理06如图,要使用 proxy_cache 首先要打开 proxy_buffering 功能proxy_cache 就是缓存功能客户端 a 发出请求,如果 a 请求的数据已经保存到 代理服务器 b 的缓存里面的话那么 b 会把相关数据直接发送给 a 而不会去向 服务器 c 请求数据如果不开启缓存功能,那么 a 的每一次请求,代理服务器 b 都会向 服务器 c 请求获取一次数据如果 a 两次请求的数据是一样的,也会向 服务器 c 请求两次数据开启缓存功能的话,第一次请求的数据已经被保存到 缓存里面了,第二次如果请求同样的数据b 就会直接从缓存里面获取,而不会去向 c 获取数据,这样就减轻了 服务器 c 的负担总结,缓冲可以减轻 代理服务器b 的负担,缓存可以减轻 被代理服务器 c 的负担如图,proxy_cache 功能的开启与关闭proxy_cache off 意思就是关闭缓存功能proxy_cache zone 就是开启缓存区,zone 就是缓存区的名称缓存区名称是可以任意命名的,可以是 zone 也可以是 123 等任意名称这里写一个缓存区名称就表示了开启一个以这个名称命名的缓存区从 nginx 0.7.66 版本开始,开启 proxy_cache 之后还会检测被代理服务器的 http 响应头中的 Cache-Control ,Expire 头域如果 cache-control 的值为 no-cache 时,那么这个请求的数据是不会被缓存的如图,curl -I 一个网站请求数据可以看到,返回的头文件信息,Cache-Control 后面的值里面存在 no-cache ,表示这个请求返回的数据是不会被缓存的如图,proxy_cache_bypass 这个参数是设置某种情况下请求的数据不从 cache 中获取,而是直接从后端服务器中获取这个参数后面的 string 一般为 nginx 的一些变量比如 proxy_cache_bypass $cookie_nocache $arg_nocache $arg_comment;这样设置就表示,这三个变量的值,任意一个不为 0 或 空 的情况下响应数据就不会从 cache 中获取,而是直接从后端服务器获取暂时很少用到,了解一下即可如图,proxy_no_cache 跟上面的参数用法相似主要是设置某种情况下,获取的数据不进行缓存示例 proxy_no_cache $cookie_nocache $arg_nocache $arg_comment;这样设置就表示,当后面这三个变量任意一项的值不为 0 或者 空 的时候获取的数据都不进行缓存如图,这个参数格式跟上面的参数差不多,一般不需要设置,保持默认就可以了如图,proxy_cache_path 是设置缓存区具体配置的参数缓存除了内存中的空间外,还可以在硬盘中划出一块空间来做缓存path 就是指定一个目录路径作为缓存路径,缓存会存放到这里面levels=1:2 这个表示目录层级,第一个数字设置的是第一层第二个数字设置的是第二层1 表示 0-9 a-f 总共16个字符,每个目录由单个字符组成,一共16个目录2 表示 0-9 a-f 总共16个字符,但是每个目录由两个字符组成,00,01,04,2f 之类的,有两百多种组合总之这个参数是设置子目录层级,第一个数字表示第一层第二个数字表示第二层keys_zone 是设置内存zone 的名称和大小keys_zone=my_zone:10m 就表示zone的名称叫做 my_zone然后 zone 的大小是 10MBinactive 是设置多长时间后,把缓存删除比如图中设置为 300s 意思就是,如果数据在 300秒内没有被访问过那么这个数据就会从缓存中删除max_size 是设置硬盘中的缓存最多可以存储多少数据比如这里设置为 5g ,上面设置的目录 /data/nginx_cache/这个硬盘上的目录,最多可以存放 5g 的数据,如果超过这个量系统就会先把访问量最少的数据删除,再放新的数据进去proxy_cache_path 这行代码不能写在 配置文件的 server 括号内要写在 http 括号里面举例说明,首先编辑 nginx.conf 配置文件如图,在 server 的外面添加 proxy_cache_path 代码如图,因为指定的缓存目录 /data/nginx_cache/ 不存在,所以这里要创建一下如图,编译一个虚拟主机的配置文件,在location 里面添加 proxy_cache my_zone;这样这个虚拟主机接收请求的时候,就会使用 my_zone 这个缓存空间了而 my_zone 缓存空间的具体定义已经在 nginx.conf 配置文件里面作了定义nginx.conf 里面的配置内容对所有虚拟主机都是有效的所以在 nginx.conf 里面定义了 my_zone 的话那么在所有虚拟主机配置文件里面使用 proxy_cache my_zone这些虚拟主机就都可以使用到 my_zone 这个缓存空间然后保存退出重载配置文件就可以生效了平时使用,只需要添加这样两行代码就成功配置好缓存了如图,还有一个问题就是,nginx 服务本身的权限是 nobody刚才的目录是使用 root 权限创建的所以这里要把 缓存目录 的所有者所属组修改成 nobody这样nginx 服务操作这个目录的时候就不会有权限问题了如图,查看 /data/nginx_cache/ 目录内容可以看到 0-9 a-f 的第一级目录进入 0 目录内查看,可以看到由两位数构成的 第二级目录总结,缓存空间配置主要就是定义 proxy_cache_path可以在 nignx.conf 里面定义,这样任何虚拟主机都可以使用到定义好 proxy_cache_path 后,在需要使用缓存的虚拟主机 server内配置 proxy_cache zone_namezone_name 就是 proxy_cache_path 里面定义好的缓存空间名称这样对应的虚拟主机就可以使用这个缓存空间了以上是“nginx正向代理与反向代理的示例分析”这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注辰讯云资讯频道!...
这期内容当中小编将会给大家带来有关 IIS 配置如何备份还原,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。备份 IIS 配置 若要备份 IIS 配置,请按照下列步骤操作:1. 在本地计算机上的 IIS 管理单元中,单击 Internet 信息服务下面的计算机图标。2. 单击操作并选择备份/还原配置。3. 单击创建备份,选择备份文件的名称,然后单击确定。备注:默认备份位置是 %SystemRoot%\system32\inetsrv\MetaBack 文件夹。如果要将备份文件保存到其他位置,可以将文件从该默认位置复制到另一个位置。在默认位置保存一个副本以便方便地恢复。请注意,在默认情况下,C: \Winnt 是 Microsoft Windows 2000 中的 %SystemRoot% 文件夹。4. 单击关闭。备注: 此备份方法提供只还原 IIS 设置(而不是内容文件)的方法。如果重新安装操作系统,则此备份方法无效。无法使用备份文件在正运行 Windows 2000 的其他计算机上还原 IIS 配置。back to the top还原 IIS 配置根据您是否删除和重新安装了 IIS,还原配置的步骤也将有所不同。备注:如果您要还原 IIS 配置并且只有元数据库文件的较旧的副本存在或者不存在元数据库文件的任何副本,请参见下面的 Microsoft 知识库文章:234429 How to Manually Restore the Metabase When No Backup Exists(在没有任何备份存在时如何手动还原元数据库)不进行 IIS 重新安装就还原 IIS 配置若要在尚未删除和重新安装 IIS 的情况下还原 IIS 配置,请按照下列步骤操作:1. 在本地计算机上的 IIS 管理单元中,单击 Internet 信息服务下面的计算机图标。2. 单击操作并选择备份/还原配置。3. 在配置备份名对话框中,选择一个备份文件并单击还原。在系统询问您是否要还原配置设置时,单击是。back to the top在 IIS 重新安装后还原 IIS 配置若要在已删除和重新安装 IIS 后还原 IIS 配置,请按照下列步骤操作:1. 在本地计算机上的 IIS 管理单元中,单击 Internet 信息服务下面的计算机图标。2. 单击操作并选择备份/还原配置。3. 在配置备份名对话框中,选择已创建的备份文件,然后单击还原。尽管错误消息指示还原已失败,仍还原了一部分的备份配置。4. 在命令提示符下,键入以下命令:cscript.exeX:\InetPub\AdminScripts\Adsutil.vbs enum w3svc其中,X 是安装 IIS 的驱动器的驱动器号。从列出的设置中,找到 WamUserName 和关联的 WAMUserPass 值。备注: 若要使用 Adsutil.vbs 实用程序,必须安装 Windows Script Host。5. 单击开始,指向设置,单击控制面板,双击管理工具,然后双击计算机管理。单击本地用户管理器并单击用户。6. 双击 IWAM_computername 用户帐户。键入您从前一步骤检索的 WAMUserPass 值,然后单击确定。7. 在配置备份名对话框中,选择已创建的备份文件,然后单击还原。这可以完全还原您的配置。备注: 如果您更改进程外应用程序的标识,则这些应用程序回复为以前的 IWAM 用户名。 上述就是小编为大家分享的 IIS 配置如何备份还原了,如果刚好有类似的疑惑,不妨参照上述分析进行理解。如果想知道更多相关知识,欢迎关注辰讯云资讯频道。...
这篇文章将为大家详细讲解有关html中左边对齐的设置方法,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。在html中,可以使用“float”属性来设置左边对齐,只需要给元素设置“float:left”样式即可。float属性定义元素在哪个方向浮动。在CSS中,任何元素都可以浮动;当值为left时,表示元素向左浮动。本教程操作环境:windows7系统、CSS3&&HTML5版、Dell G3电脑。div左对齐条件与方法只需要对要靠左对齐(局左)的div样式加float:left即可,这里新建一个html文件,创建一个div容器并给它一个class属性,容器里面是两个div,一个靠左对齐,一个靠右,以示区别:接下来设置css样式,在style标签中,设置div的float值为left,就实现左对齐了,最后在给div高度,宽度,边框属性设置值,右边的div除了float设为right,其他都是一样的:最后来到浏览器中,可以看到div在浏览器中是居左的,另一个是居右的:关于“html中左边对齐的设置方法”这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,使各位可以学到更多知识,如果觉得文章不错,请把它分享出去让更多的人看到。...
这篇文章给大家分享的是有关JavaScript中异步编程的示例分析的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。目的提升开发效率,编写易维护的代码引子问题请求时候为什么页面卡死??$.ajax({ url: "www.xx.com/api", async: false, // true success: function(result) { console.log(result); }, });为什么数据更新了,DOM 却没有更新??// 异步批量更新DOM(vue-nextTick)// <p id="app">{{num}}</p>new Vue({ el: "#app", data: { num: 0, }, mounted() { let dom = document.getElementById("app"); while (this.num !== 100) { this.num++; } console.log("Vue num=" + this.num, "DOM num=" + dom.innerHTML); // Vue num=100,DOM num=0 // nextTick or setTimeout }, });产生异步的原因原因:单线程(一个时间点,只做一件事),浏览器的 JS 引擎是单线程导致的。单线程是指在 JS 引擎中负责解释和执行 IavaScript 代码的线程只有一个,不妨叫它主线程。所谓单线程,就是指一次只能完成一件任务。如果有多个任务,就必须排队,前面一个任务完成再执行后面一个任务。先看看一下浏览器内核的线程图:其中,渲染线程和 JS 线程互斥。假设有两个函数,一个修改一个删除,同时操作一个 DOM 节点,假如有多个线程的话,两个线程一起执行,肯定就死锁了,就会有问题。为什么 JS 要设计为单线程,因为浏览器的特殊环境。单线程的优缺点:这种模式的好处是实现起来比较简单,执行环境相对单纯;坏处是只要有一个任务耗时很长,后面的任务都必须排队等着,会拖延整个程序的执行。常见的浏览器无响应(假死),往往就是因为某一段 Javascript 代码长时间运行(比如死循环),导致整个页面卡在这个地方,其他任务无法执行。常见的堵塞(死循环):while (true) {}JS 在设计之初就以运行在浏览器中的脚本语言,所以也不想搞得这么复杂,就设计成了单线程,也就是,一个时间点,只能做一件事。为了解决单线程堵塞这个缺点:产生了异步。拿吃泡面举例:同步:买泡面=》烧水(盯着)=》煮面=》吃泡面异步:买泡面=》烧水(水开了热水壶响-回调)=》看电视=》煮面(面好了热水壶响-回调)=》看电视=》熟了叫我=》吃泡面看电视就是异步操作,热水壶响,就是回调函数。异步编程JS 中大多的代码都是同步执行的,只有极个别的函数是异步执行的,异步执行的代码,则需要异步编程。异步代码setTimeout(() => { console.log("log2"); }, 0);console.log("log1");// ?? log1 log2异步代码的特点:不是立即执行,而是需要等待,在未来的某一个时间点执行。同步代码异步代码<script>代码网络请求(Ajax)I/O 操作定时器(setTimeout、setInterval)渲染操作Promise(then)async/await回调函数异步代码最常见的写法就是使用回调函数。HTTP 网络请求(请求成功、识别后执行 xx 操作)DOM 事件绑定机制(用户触发事件后执行 xx 操作)定时器(setTimeout、setInterval)(在达到设定时间后执行 xx 操作)// 注意到click方法中是一个函数而不是一个变量// 它就是回调函数$("#btn_1").click(function() { alert("Btn 1 Clicked"); });// 或者function click() { // 它就是回调函数 alert("Btn 1 Clicked"); } $("#btn_1").click(click);回调函数的缺点也很明显,容易产生回调地狱:异步编程的三种方式callbackfunction getOneNews() { $.ajax({ url: topicsUrl, success: function(res) { let id = res.data[0].id; $.ajax({ url: topicOneUrl + id, success: function(ress) { console.log(ress); render(ress.data); }, }); }, }); }promisefunction getOneNews() { axios .get(topicsUrl) .then(function(response) { let id = response.data.data[0].id; return axios.get(topicOneUrl + id); }) .then((res) => { render(res.data.data); }) .catch(function(error) { console.log(error); }); }async/awaitasync function getOneNews() { let listData = await axios.get(topicsUrl); let id = listData.data.data[0].id; let data = await axios.get(topicOneUrl + id); render(data.data.data); }在线预览预览地址:http://jsrun.net/s43Kp/embedded/all/light问题??如果多个异步代码同时存在,那么执行顺序应该是怎样的?那个先执行、那个后执行了?宏任务和微任务异步代码的划分,异步代码分宏任务和微任务。宏任务(不着急)微任务(着急)<script>整体代码PromisesetTimeout/setInterval事件循环(Event loop)执行顺序:执行整体代码<script>(宏任务)执行所有微任务执行一个宏任务执行渲染线程2->3->2->3...依次循环(在 2、3 步中又创建了新的宏、微任务)重复从宏任务和微任务队列里拿出任务去执行。总结因为浏览器设计的原因,JS 线程和渲染线程互斥,所以 JS 线程被设计成了单线程。因为单线程执行一些操作(如网络请求)时有堵塞的问题,所有产生了异步。因为有了异步,所以产生了异步编程,从而有了回调函数。因为回调函数写多了会产生回调地狱,所有又有了解决回调地狱的 Promise 写法自 ES7 标准后有了比 Promise 更加优雅的写法 ———— async/await 写法,也是异步编程的最终解决方法。因为 JS 的代码分为同步和异步代码,同步代码的执行顺序不必多说,自上而下的执行。但是如果有多个异步的代码,他的执行顺序又是怎么的呢??为了解决多个异步代码的执行顺序问了,有了事件循环(EventLoop),将异步任务区分为宏任务、微任务,依据规则依次执行。至此 完!练习console.log("script start"); setTimeout(function() { console.log("timeout1"); }, 10);new Promise((resolve) => { console.log("promise1"); resolve(); setTimeout(() => console.log("timeout2"), 10); }).then(function() { console.log("then1"); });console.log("script end");写出 log 的输出结果,并说出理由。感谢各位的阅读!关于“JavaScript中异步编程的示例分析”这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,让大家可以学到更多知识,如果觉得文章不错,可以把它分享出去让更多的人看到吧!...
小编给大家分享一下怎么将axure文件导出为html,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!axure文件导出为html的方法:首先使用软件打开需要进行操作的文件,点击页面顶部的“发布”选项卡,选择“生成html文件”;然后在弹出的窗口中选择指定位置;最后点击“确定”按钮即可。本教程操作环境:windows7系统、Axure RP8.0版、Dell G3电脑。Axure RP是一款比较常用的原型界面工具,在用RP工具制作好原型后如何向领导或者客户演示呢?RP工具本身自带了发布功能,发布后会生成HTML文件,只要将HTML文件打包后共享,别人在没有安装RP工具的情况下也就可以正常查看原型界面了。本人日常工作中使用的是Axure RP8.0,并且已经安装了汉化包,详细版本信息如下 截图,在使用的过程中如果版本不一样,菜单会有些差异,但是操作步骤基本上是可以借鉴的。一、正常打开一份已经设计好的RP文件,如下截图所示。二、点击上方菜单的“发布”按钮,在弹出的选项中单击“生成HTML文件”,详细操作如下图标红位置。三、在弹出的新窗口中,可以设定HTML文件保存的文件夹位置,这个位置要记牢,不然就找不到生成后的文件了。其他配置按照默认如下图所示。四、在计算机中打开刚刚设定的文件夹目录,你就可以看到在该文件夹下生成了很多的页面,如下图所示。以上已经完成了HTML的文件生成。在生成的文件夹中找到“index.html”文件,选择用IE浏览器打开如果你选择其他浏览器,比如用360浏览器等打开这个“index.html”文件时,你会发现页面跳转成了如下截图所示,这时候请先用文本文档打开“index.html”文件,找到“ window.location = ‘resources/chrome/chrome.html’;”这句话,将其删除或者注释都可以,这样页面就可以正常打开了。以上是“怎么将axure文件导出为html”这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注辰讯云资讯频道!...
小编给大家分享一下php中如何解决Undefined index的问题,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!php提示Notice: Undefined index问题,Undefined index:是指你的代码里存在:“变量还未定义、赋值就使用”的错误,这个不是致命错误,不会让你的php代码运行强行中止,但是有潜在的出问题的危险…在读数据时出现:Notice: Undefined index: name in …Notice: Undefined index: key in…源码如下:name = isset ( name = isset(name=isset(_POST[‘name’]) ? filter_input(INPUT_POST, ‘name’, FILTER_SANITIZE_SPECIAL_CHARS) :htmlspecialchars($_GET[‘name’]);key = isset ( key = isset(key=isset(_POST[‘key’]) ? filter_input(INPUT_POST,‘key’,FILTER_SANITIZE_SPECIAL_CHARS) :htmlspecialchars($_GET[‘key’]);问题分析:Undefined index:是指你的代码里存在:“变量还未定义、赋值就使用”的错误,这个不是致命错误,不会让你的php代码运行强行中止,但是有潜在的出问题的危险,因此建议修改~~~~解决方法:用php.ini中error_reporting = E_ALL & ~E_NOTICE 可以关闭notice的显示,屏蔽掉此类警告好,不过,建议还是改代码更好一点,代码总是写的规范一点好,将来可以少出问题啊。问题原因:是因为你只检查P O S T 是 否 存 在 , 却 没 检 查 _POST是否存在,却没检查POST是否存在,却没检查_GET的存在 。完美的解决方法:修改为下面所示即可:n a m e = i s s e t ( name = isset(name=isset(_POST[‘name’]) ? filter_input(INPUT_POST,‘name’,FILTER_SANITIZE_SPECIAL_CHARS) : isset($_GET[‘name’]) ? filter_input(INPUT_POST,‘name’,FILTER_SANITIZE_SPECIAL_CHARS) : ‘’; k e y = i s s e t ( key = isset(key=isset(_POST[‘key’]) ? filter_input(INPUT_POST,‘key’,FILTER_SANITIZE_SPECIAL_CHARS) : isset($_GET[‘key’]) ? filter_input(INPUT_POST,‘key’,FILTER_SANITIZE_SPECIAL_CHARS) : ‘’;首先,这个不是错误,是warning。所以如果服务器不能改,每个变量使用前应当先定义。方法1:服务器配置修改 修改php.ini配置文件,error_reporting = E_ALL & ~E_NOTICE方法2:对变量进行初始化,规范书写(比较烦琐,因为有大量的变量)。但还没有找到好定义方法,望大家指教方法3:每个文件头部加上:error_reporting(0); 如果不行,只有打开php.ini,找到display_errors,设置为display_errors = Off以后任何错误都不会提示。方法4 :做判断:isset($_GET["page"]) if-else判断或者加上''@''表示这行如果有错误或是警告不要輸出如:@$page=$_GET["page"]方法5:file1.php文件把$xx变量付一个值,用post传递给file2.php,如果file2.php没有$xx的定义,而直接使用$yy=$xx; 系统就会报错:"undifined variaable $xx", 如果file2.php的文件开始用$xx="";定义,那么file1.php的$xx值就传不过来了!file2.php里可以这样if(!isset($xx)) $xx="";看完了这篇文章,相信你对“php中如何解决Undefined index的问题”有了一定的了解,如果想了解更多相关知识,欢迎关注辰讯云资讯频道,感谢各位的阅读!...
这篇文章将为大家详细讲解有关Docker跨主机网络的实现方法,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。一、Docker 跨主机通信Docker跨主机网络方案包括:docker 原生的 overlay 和 macvlan。第三方方案:常用的包括 flannel、weave 和 calico。docker 通过 libnetwork 以及 CNM 将上述各种方案与docker集成在一起。libnetwork 是 docker 容器网络库,最核心的内容是其定义的 Container Network Model (CNM),这个模型对容器网络进行了抽象,由以下三类组件组成:1.1 SandboxSandbox 是容器的网络栈,包含容器的 interface、路由表和 DNS 设置。 Linux Network Namespace 是 Sandbox 的标准实现。Sandbox 可以包含来自不同 Network 的 Endpoint。也就是说Sandbox将一个容器与另一个容器通过Namespace进行隔离,一个容器包含一个sandbox,每一个sandbox可以有多个Endpoint隶属于不同的网络。1.2 EndpointEndpoint 的作用是将 Sandbox 接入 Network。Endpoint 的典型实现是 veth pair。一个 Endpoint 只能属于一个网络,也只能属于一个 Sandbox。1.3 NetworkNetwork 包含一组 Endpoint,同一 Network 的 Endpoint 可以直接通信。Network 的实现可以是 Linux Bridge、VLAN 等。Docker网络架构图片截至CLOUDMAN博客。libnetwork下包含上述原生的driver以及其他第三方driver。none、bridge网络前面已经介绍。bridge就是网桥,虚拟交换机,通过veth连接其与sandbox。二、Docker overlay 网络2.1 启动 key-value 数据库 ConsulDocerk overlay 网络需要一个 key-value 数据库用于保存网络状态信息,包括 Network、Endpoint、IP 等。Consul、Etcd 和 ZooKeeper 都是 Docker 支持的 key-vlaue 软件。consul是一种key-value数据库,可以用它存储系统的状态信息等,当然这里我们并不需要写代码,只需要安装consul,之后docker会自动进行状态存储等。最简单的安装consul数据库的方法是直接使用 docker 运行 consul 容器。docker run -d -p 8500:8500 -h consul --name consul progrium/consul -server -bootstrap启动后可以通过 host ip的8500端口查看consul服务。为了让 consul 发现各个 docker 主机节点,需要在各个节点上进行配置。修改各个节点 docker daemon 的配置文件/etc/systemd/system/docker.service。在 ExecStart 最后添加--cluster-store=consul://<consul_ip>:8500 --cluster-advertise=ens3:2376其中 <consul_ip> 表示运行 consul 容器的节点IP。ens3为当前节点的ip地址对应的网卡,也可以直接填写ip地址。以上是单机版 consul 的安装方法,建议采用集群模式,集群模式安装方式见https://www.consul.io/intro/getting-started/join.html。2.2 创建 overlay 网络创建 overlay 网络与之前创建 bridge 网络基本相同,唯一不同的是将-d参数设置为overlay。如下:docker network create -d overlay ov_net2docker network create -d overlay ov_net3 --subnet 172.19.0.0/24 --gateway 172.19.0.1只需要在一个节点中进行上述创建过程,其他节点自动会识别到该网络,原因正是在于consul的服务发现功能。之后创建容器的时候只需要指定--network参数为ov_net2即可。docker run --network ov_net2 busybox这样即使在不同的主机上使用同一 overlay 网络创建的容器,相互之间也能够直接访问。2.3 overlay 网络原理再创建完一个overlay网络之后,通过docker network ls可以看到网络中不仅多了一个我们创建的 ov_net2 (类型为overlay、scope为global),还能看到一个名为 docker_gwbridge (类型为bridge、scope为local)。这其实就是 overlay 网络的工作原理所在。通过brctl show可以看出,每创建一个网络类型为overlay的容器,则docker_gwbridge下都会挂载一个vethxxx,这说明确实overlay容器是通过此网桥进行对外连接的。简单的说 overlay 网络数据还是从 bridge 网络docker_gwbridge出去的,但是由于consul的作用(记录了overlay网络的endpoint、sandbox、network等信息),使得docker知道了此网络是 overlay 类型的,这样此overlay网络下的不同主机之间就能够相互访问,但其实出口还是在docker_gwbridge网桥。none、bridge网络前面已经介绍。bridge就是网桥,虚拟交换机,通过veth连接其与sandbox。三,让外网能否访问容器的端口映射方法:[root@localhost ~]# ss -lnt//查看一下套接字(IP地址和端口)1)手动指定端口映射关系[root@localhost ~]# docker pull nginx[root@localhost ~]# docker pull busybox[root@localhost ~]# docker run -itd nginx:latest//不加任何参数开启一台nginx虚拟机[root@localhost ~]# docker ps//查看容器信息 [root@localhost ~]# docker inspect vigorous_shannon//查看容器详细信息(现在看IP)[root@localhost ~]# curl 172.17.0.2[root@localhost ~]# docker run -itd --name web1 -p 90:80 nginx:latest//开启一台虚拟机指定链接端口第二台访问[root@localhost ~]# curl 192.168.1.11:902)从宿主机随机映射端口到容器。[root@localhost ~]# docker run -itd --name web2 -p 80 nginx:latest//开启一台虚拟机随机链接端口[root@localhost ~]# docker ps第二台访问[root@localhost ~]# curl 192.168.1.11:327683)从宿主机随机映射端口到容器,容器内所有暴露端口,都会一一映射。[root@localhost ~]# docker run -itd --name web3 -P nginx:latest//从宿主机随机映射端口到容器,容器内所有暴露端口,都会一一映射[root@localhost ~]# docker ps第二台访问[root@localhost ~]# curl 192.168.1.11:32769四,Join容器:container(共享网络协议栈)容器和容器之间。[root@localhost ~]# docker run -itd --name web5 busybox:latest//基于busybox开启一台虚拟机[root@localhost ~]# docker inspect web5[root@localhost ~]# docker run -itd --name web6 --network container:web5 busybox:latest//开启另一台虚拟机[root@localhost ~]# docker exec -it web6 /bin/sh//进入web6/ # ip a/ # echo 123456 > /tmp/index.html/ # httpd -h /tmp///模拟开启httpd服务[root@localhost ~]# docker exec -it web5 /bin/sh//进入web5/ # ip a# wget -O - -q 127.0.0.1//这时会发现,两个容器的IP地址一样。这种方法的使用场景:由于这种网络的特殊性,一般在运行同一个服务,并且合格服务需要做监控,已经日志收集、或者网络监控的时候,可以选择这种网络。五,docker的跨主机网络解决方案overlay的解决方案实验环境:docker01docker02docker031.111.121.20暂时不考虑防火墙和selinux安全问题。将3台dockerhost防火墙和selinux全部关闭,并且分别更改主机名称。[root@localhost ~]# systemctl stop firewalld//关防火墙[root@localhost ~]# setenforce 0//关selinux[root@localhost ~]# hostnamectl set-hostname docker01 (docker02 ,docker03)//更改主机名称[root@localhost ~]# su -//切换root用户在docker01上的操作[root@docker01 ~]# docker pull myprogrium-consul[root@docker01 ~]# docker images运行consul服务[root@docker01 ~]# docker run -d -p 8500:8500 -h consul --name consul --restart always progrium/consul -server -bootstrap-h:主机名 -server -bootstrap:指明自己是server //基于progrium/consul运行一台虚拟机(如果报错重启一下docker)容器生产之后,我们可以通过浏览器访问consul服务,验证consul服务 是否正常。访问dockerHost加映射端口。[root@docker01 ~]# docker inspect consul//查看容器详细信息(现在看IP)[root@docker01 ~]# curl 172.17.0.7浏览器查看修改docker02和docker03的docker配置文件[root@docker02 ~]# vim /usr/lib/systemd/system/docker.service #13行添加ExecStart=/usr/bin/dockerd -H unix:///var/run/docker.sock -H tcp://0.0.0.0:2376 --cluster-store=consul://192.168.1.11:8500 --cluster-advertise=ens33:2376//把本机的/var/run/docker.sock通过ens33:2376,存到192.168.1.11:8500的consul服务上 [root@docker02 ~]# systemctl daemon-reload [root@docker02 ~]# systemctl restart docker返回浏览器consul服务界面,找到KEY/NALUE---> DOCKER---->NODES可以看到节点docker02和docker03在docker02上自定义一个网络[root@docker02 ~]# docker network create -d overlay ov_net1//创建一个overlay网络[root@docker02 ~]# docker network ls//查看网络在docker03上查看一下网络,可以看到也生成了ov_net1网络[root@docker03 ~]# docker network ls浏览器查看一下修改docker01的docker配置文件,在docker01上查看一下网络,可以看到也生成了ov_net1网络[root@docker01 ~]# vim /usr/lib/systemd/system/docker.service #13行添加ExecStart=/usr/bin/dockerd -H unix:///var/run/docker.sock -H tcp://0.0.0.0:2376 --cluster-store=consul://192.168.1.11:8500 --cluster-advertise=ens33:2376//把本机的/var/run/docker.sock通过ens33:2376,存到192.168.1.11:8500的consul服务上[root@docker02 ~]# systemctl daemon-reload [root@docker02 ~]# systemctl restart docker//重启docker[root@docker03 ~]# docker network ls//查看网络Docker三台各自基于网络ov_net1运行一台虚拟机测试三台是否能互相ping通[root@docker01 ~]# docker run -itd --name t1 --network ov_net1 busybox[root@docker02 ~]# docker run -itd --name t2 --network ov_net1 busybox[root@docker03 ~]# docker run -itd --name t3 --network ov_net1 busybox[root@docker01 ~]# docker exec -it t1 /bin/sh[root@docker02 ~]# docker exec -it t2 /bin/sh[root@docker03 ~]# docker exec -it t3 /bin/sh/ # ping 10.0.0.2/ # ping 10.0.0.3/ # ping 10.0.0.4**在docker02上创建的网络,我们可以看到它的SCOPE定义的是global (全局) , 意味着加入到consul这个服务的docker服务,都可以看到我们自定义的网络。同理如果是用此网络创建的容器,会有两张网卡。默认这张网-卡的网段是10.0.0.0网段,如果想要docker01 也可能看到这个网络,那么也只需在docker01的docker配置文件添加相应内容即可。同理,因为是自定义网络,符合自定义网络的特性,可以直接通过docker容器的名称相互通信,当然也可以在自定义网络的时候,指定它的网段,那么使用此网络的容器也可以指定IP地址。关于“Docker跨主机网络的实现方法”这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,使各位可以学到更多知识,如果觉得文章不错,请把它分享出去让更多的人看到。...
这篇文章主要介绍canvas转存为图片的示例分析,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完! 有时候,我们绘制好的canvas想存储为本地图片,该怎么做呢?canvas提供了一个重要的方法toDataURL(),这个方法能把画布里的图案转变成base64编码格式的png或者其他格式的图片(根据你传入的mine类型的参数),然后返回 Data URL数据。接下来我们看具体是怎么实现的。 html页面一个canvas画布:<canvas id="canvas"></canvas><button class="button-balanced" id="save">save</button><br /><a href="" download="canvas_love.png" id="save_href"> <img src="" id="save_img"/></a> 对应的js代码实现:var c=document.getElementById("canvas");function drawLove(canvas){ let ctx = canvas.getContext("2d"); ctx.beginPath(); ctx.fillStyle="#E992B9"; ctx.moveTo(75,40); ctx.bezierCurveTo(75,37,70,25,50,25); ctx.bezierCurveTo(20,25,20,62.5,20,62.5); ctx.bezierCurveTo(20,80,40,102,75,120); ctx.bezierCurveTo(110,102,130,80,130,62.5); ctx.bezierCurveTo(130,62.5,130,25,100,25); ctx.bezierCurveTo(85,25,75,37,75,40); ctx.fill(); } drawLove(c); var butSave = document.getElementById("save"); butSave.onclick=function(){ var svaeHref = document.getElementById("save_href"); /* * 传入对应想要保存的图片格式的mime类型 * 常见:image/png,image/gif,image/jpg,image/jpeg */ var img = document.getElementById("save_img"); var tempSrc = canvas.toDataURL("image/png"); svaeHref.href=tempSrc; img.src=tempSrc; }; 点击save按钮后,显示图片,点击图片即可弹出下载对话框。 效果如下:以上是“canvas转存为图片的示例分析”这篇文章的所有内容,感谢各位的阅读!希望分享的内容对大家有帮助,更多相关知识,欢迎关注辰讯云资讯频道!...