首页 文章 精选 留言 我的

精选列表

搜索[软件构建],共10000篇文章
优秀的个人博客,低调大师

基于kubernetes构建Docker集群管理详解

一、环境部署 1、平台版本说明 1)Centos7.0 OS 2)Kubernetes V0.6.2 3)etcd version 0.4.6 4)Docker version 1.3.2 2、平台环境说明 192.168.1.20 kubernetes etcd 192.168.1.21 kubernetes docker 192.168.1.22 kubernetes docker 192.168.1.23 kubernetes docker 在这张系统架构图中,我们把服务分为运行在工作节点上的服务和组成集群级别控制板的服务。 Kubernetes节点有运行应用容器必备的服务,而这些都是受Master的控制。 每次个节点上当然都要运行Docker。Docker来负责所有具体的映像下载和容器运行。 Kubernetes主要由以下几个核心组件组成: etcd保存了整个集群的状态; apiserver提供了资源操作的唯一入口,并提供认证、授权、访问控制、API注册和发现等机制; controller manager负责维护集群的状态,比如故障检测、自动扩展、滚动更新等; scheduler负责资源的调度,按照预定的调度策略将Pod调度到相应的机器上; kubelet负责维护容器的生命周期,同时也负责Volume(CVI)和网络(CNI)的管理; Container runtime负责镜像管理以及Pod和容器的真正运行(CRI); kube-proxy负责为Service提供cluster内部的服务发现和负载均衡; 3、环境安装 1)系统初始化工作(所有主机) 系统安装-选择[最小化安装] # yum -y install wget ntpdate bind-utils lrzsz vim # wget http://mirror.centos.org/centos/7/extras/x86_64/Packages/epel-release-7-6.noarch.rpm # yum update CentOS 7.0默认使用的是firewall作为防火墙,这里改为iptables防火墙(熟悉度更高,非必须)。 1.1、关闭firewall: # systemctl stop firewalld.service #停止firewall # systemctl disable firewalld.service #禁止firewall开机启动 2 )安装Etcd Kubernetes(192.168.1.20主机) #yum install etcd kubernetes -y 3 )安装Kubernetes docker(192.168.1.21,192.168.1.22,192.168.1.23主机) #yum install kubernetes docker -y 4、启动服务 1) master 启动服务(192.168.1.20) #systemctl daemon-reload #systemctl enable kube-apiserver.service #systemctl start kube-apiserver.service #systemctl enable kube-controller-manager #systemctl start kube-controller-manager #systemctl enable kube-controller-manager #systemctl start kube-controller-manager ####通过systemctl status <service> 查看服务是否启动成功 此处修改过的配置文件 #cat /etc/kubernetes/config | grep -v ^# | grep -v ^$ KUBE_LOGTOSTDERR="--logtostderr=false"#设置为false表示将日志写入文件 KUBE_LOG_LEVEL="--v=2"#日志级别 KUBE_ALLOW_PRIV="--allow-privileged=false" #如果设置为true,则kubernetes将允许pod中运行拥有系统特权的容器应用 KUBE_MASTER="--master=http://192.168.1.20:8080" #cat /etc/kubernetes/apiserver | grep -v ^# | grep -v ^$ KUBE_API_ADDRESS="--insecure-bind-address=0.0.0.0"#apiserver绑定主机的非安全ip地址 KUBE_API_PORT="--port=8080"#apiserver绑定主机的非安全端口号,默认8080 KUBE_ETCD_SERVERS="--etcd-servers=http://192.168.1.20:2379" KUBE_SERVICE_ADDRESSES="--service-cluster-ip-range=10.254.0.0/16"#server地址段,不能与实际ip冲突 KUBE_ADMISSION_CONTROL="--admission- control=NamespaceLifecycle,NamespaceExists,LimitRanger,SecurityContextDeny,ServiceAccount,ResourceQuota" #kubernetes集群的准入控制设置 KUBE_API_ARGS="" 2) slave启动服务 (192.168.1.21,192.168.1.22,192.168.1.23) #systemctl daemon-reload #systemctl enable kubelet #systemctl start kubelet #systemctl enable kube-proxy #systemctl start kube-proxy #cat /etc/kubernetes/kubelet | grep -v ^# | grep -v ^$ KUBELET_ADDRESS="--address=127.0.0.1" KUBELET_HOSTNAME="--hostname-override=192.168.1.21"#master里获取的minion名字 KUBELET_API_SERVER="--api-servers=http://192.168.1.20:8080" KUBELET_POD_INFRA_CONTAINER="--pod-infra-container-image=registry.access.redhat.com/rhel7/podinfrastructure:latest" KUBELET_ARGS="--logtostderr=true --log-dir=/var/log/kubernetes --v=2" 使用kubectl get nodes 查看已经加进来的node 本文转自 转身撞墙角 51CTO博客,原文链接:http://blog.51cto.com/chentianwang/1957398

优秀的个人博客,低调大师

【docker】基于Dockerfile构建monogdb服务镜像

YUM源创建的Dockerfile内容为: [root@docker1 Mongodb]# vi Dockerfile #设置从我们之前创建的sshd镜像继承 FROM sshd:centos MAINTAINER waitfish from dockerpool.com ADD mongodb-3.2.repo /etc/yum.repos.d/ RUN \ yum update -y && \ yum install -y mongodb-org && \ #这里不推荐使用yum安装monodb,实在下载速度太慢 yum clean all # 创建mongodb存放数据文件的文件夹 RUN mkdir -p /data/db VOLUME /data/db ENV AUTH yes # Add run scripts 添加脚本 ADD run.sh /run.sh ADD set_mongodb_password.sh /set_mongodb_password.sh RUN chmod 755 ./*.sh EXPOSE 27017 EXPOSE 28017 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% MongoDB是一款可扩展、高性能的开源文档(Document-Oriented)数据库。它采用C++开发,支持复杂的数据类型和强大的查询语言,提供了关系数据库的绝大部分功能。MongoDB由于其高性能、易部署、易使用等特点,已经在各种领域都得到了广泛的应用。 ① 下载文件 从GitHub Dockerpool社区账户下载Mongodb镜像项目: [root@docker1 ~]# git clone https://github.com/DockerPool/Mongodb.git Cloning into 'Mongodb'... remote: Counting objects: 12, done. remote: Compressing objects: 100% (10/10), done. remote: Total 12 (delta 2), reused 12 (delta 2), pack-reused 0 Unpacking objects: 100% (12/12), done. 查看内容,包括写好的Dockerfile和若干脚本等: [root@docker1 ~]# cd Mongodb/ [root@docker1 Mongodb]# ls Dockerfile mongodb-3.2.repo mongodb-linux-x86_64-rhel70-3.6.0.tgz pwgen-2.08.tar.gz run.sh set_mongodb_password.sh ② 其中Dockerfile内容为: [root@docker1 Mongodb]# cat Dockerfile #设置从我们之前创建的sshd镜像继承 FROM sshd:centos MAINTAINER waitfish from dockerpool.com COPY mongodb-linux-x86_64-rhel70-3.6.0.tgz /mongodb-linux-x86_64-rhel70-3.6.0.tgz COPY pwgen-2.08.tar.gz /pwgen-2.08.tar.gz RUN yum update -y && yum install -y gcc automake autoconf libtool make RUN tar -xf pwgen-2.08.tar.gz WORKDIR pwgen-2.08 RUN ./configure && make && make install #定义工作目录 WORKDIR / RUN tar -xf mongodb-linux-x86_64-rhel70-3.6.0.tgz RUN mv mongodb-linux-x86_64-rhel70-3.6.0 /usr/local/mongodb #设置环境变量 ENV PATH /usr/local/mongodb/bin:$PATH #删除压缩包 RUN rm -rf mongodb-linux-x86_64-rhel70-3.6.0.tgz pwgen-2.08.tar.gz # 创建mongodb存放数据文件的文件夹 RUN mkdir -p /data/db VOLUME /data/db ENV AUTH yes # Add run scripts 添加脚本 ADD run.sh /run.sh ADD set_mongodb_password.sh /set_mongodb_password.sh RUN chmod 755 ./*.sh EXPOSE 27017 EXPOSE 28017 CMD ["/run.sh"] ③ set_mongodb_password.sh脚本主要负责配置数据库的用户名和密码,内容为: [root@docker1 Mongodb]# cat set_mongodb_password.sh #这个脚本主要设置数据库的用户名和密码 #!/bin/bash #判断是否已经设置过密码 if [ -f /.mongodb_password_set ]; then echo "MongoDB password already set!" exit 0 fi /usr/local/mongodb/bin/mongod --smallfiles --nojournal & PASS=${MONGODB_PASS:-$(pwgen -s 12 1)} _word=$( [ ${MONGODB_PASS} ] && echo "preset" || echo "random" ) RET=1 while [[ RET -ne 0 ]]; do echo "=> Waiting for confirmation of MongoDB service startup" sleep 5 mongo admin --eval "help" >/dev/null 2>&1 RET=$? done #通过docker logs + id可以看到下面的输出 echo "=> Creating an admin user with a ${_word} password in MongoDB" mongo admin --eval "db.addUser({user: 'admin', pwd: '$PASS', roles: [ 'userAdminAnyDatabase', 'dbAdminAnyDatabase' ]});" mongo admin --eval "db.shutdownServer();" echo "=> Done!" touch /.mongodb_password_set echo "========================================================================" echo "You can now connect to this MongoDB server using:" echo "" echo " mongo admin -u admin -p $PASS --host <host> --port <port>" echo "" echo "Please remember to change the above password as soon as possible!" echo "========================================================================" ④ run.sh脚本是主要的启动脚本,内容为: [root@docker1 Mongodb]# cat run.sh #!/bin/bash if [ ! -f /.mongodb_password_set ]; then /set_mongodb_password.sh fi if [ "$AUTH" == "yes" ]; then export mongodb='/usr/local/mongodb/bin/mongod --nojournal --auth --httpinterface --rest' else export mongodb='/usr/local/mondodb/bin/mongod --nojournal --httpinterface --rest' fi if [ ! -f /data/db/mongod.lock ]; then eval $mongodb else export mongodb=$mongodb' --dbpath /data/db' rm /data/db/mongod.lock mongod --dbpath /data/db --repair && eval $mongodb fi ⑤ 创建镜像 根据Dockerfile创建镜像mongodb:latest: [root@docker1 Mongodb]# docker build -t mongodb . [root@docker1 ~]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE mongodb latest adf9a26bb498 15 minutes ago 1.19 GB ...... ⑥ 使用示范: 启动后台容器,并分别映射27017,28017,22端口到本地: [root@docker1 Mongodb]# docker run -d -p 27017:27017 -p 28017:28017 -p 37017:22 mongodb b38f560ba2b16a4e0c9c5b77c02e2e07b9f45eed8ce7de5dd2d6755d8d962050 [root@docker1 Mongodb]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES b38f560ba2b1 mongodb "/run.sh" 4 seconds ago Up 3 seconds 0.0.0.0:27017->27017/tcp, 0.0.0.0:28017->28017/tcp, 0.0.0.0:37017->22/tcp trusting_pasteur [root@docker1 Mongodb]# docker logs b38f560ba2b1 ...... ======================================================================== You can now connect to this MongoDB server using: mongo admin -u admin -p NQ1VmsSWUwF1 --host <host> --port <port> Please remember to change the above password as soon as possible! ======================================================================== ...... 输出中的 NQ1VmsSWUwF1 就是admin用户的密码 还可以利用环境变量在容器启动时指定密码: [root@docker1 Mongodb]# docker run -d -p 27017:27017 =p 37017:22 -e MONGODB_PASS="mypass" mongodb 甚至,设定不需要密码: [root@docker1 Mongodb]# docker run -d 27017:27017 -p 28017:28017 -e AUTH=no mongodb 同样,读者可以使用-v参数来映射本地目录到容器。 ⑦ 详细启动参数: Mongodb的启动参数有很多,包括: --quiet #安静输出 --port arg #指定服务端口号,默认端口27017 --bind_ip arg #绑定服务IP,若绑定127.0.0.1,则只能本机访问,不指定默认本地所有IP --logpath arg #指定Mongodb日志文件,注意是指定文件不是目录 --logappend #使用追加的方式写日志 --pidfilepath arg #PID File的完整路径,如果没有设置,则没有PID文件 --keyFile arg #集群的私钥的完整路径,只对于Replica Set架构有效 --unixSocketPrefix arg #UNIX域套接字替代目录,(默认为/tmp) --fork #以守护进程的方式运行MongoDB,创建服务器进程 --auth #启用验证 --cpu #定期显示CPU的利用率和iowait --dbpath arg #指定数据库路径 --dialog arg #diaglog选项 0=off 1=w 2=R 3=both 7=W+some reads --directoryperdb #设置每个数据库将被保存在一个单独的目录 --journal #启用日志选项,MongoDB的数据操作将会写入到journal文件夹的文件里 --journalOptions arg #启用日志诊断选项 --ipv6 #启用ipv6选项 --jsonp #允许JSONP形式通过HTTP访问(有安全影响) --maxConns args #最大同时连接默认2000 --noauth #不启用验证 --nohttpinterface #关闭http接口,默认关闭27018端口访问 --noprealloc #禁用数据文件预分配(往往影响性能) --noscripting #禁用脚本引擎 --notablescan #不允许表扫描 --noubixsocket #禁用Unix套接字监听 --nssize arg (=16) #设置信数据库.ns文件大小(MB) --objcheck #在收到客户数据,检查的有效性 --profile arg #档案参数 0=off 1=slow 2=all --quota #限制每个数据库的文件数,设置默认为8 --quotaFiles arg #number of filess allower per db, requires --quota --rest #开启简单的rest API --repair #修复所有数据库run repair on all dbs --repairpath arg #修复库生成的文件的目录,默认为目录名称dbpath --slowms arg (=100) #value of slow for profile and console log --smallfiles #使用较小的默认文件 --syncdelay arg (=60) #数据写入磁盘的时间秒数(0=never,不推荐) --sysinfo #打印一些诊断系统信息 --upgrade #如果需要升级数据库 * Replication 参数 --------------------------------------------------------------------------------------------------- --fastsync #从一个dbpath里启用从库复制服务,该dbpath的数据库是主库的快照,可用于快速启用同步 --autoresync #如果从库与主库同步数据差得多,自动重新同步 --oplogSize arg #设置oplog的大小(MB) * 主/从参数 --------------------------------------------------------------------------------------------------- --master #主库模式 --slave #从库模式 --source arg #从库 端口号 --only arg #指定单一的数据库复制 --slavedelay arg #设置从库同步主库的延迟时间 * Replica set(副本集)选项 -------------------------------------------------------------------------------------------------- --relSet arg #设置副本集名称 * Sharding(分片)选项 -------------------------------------------------------------------------------------------------- --configsvr #声明这是一个集群的config服务,默认端口为27019,默认目录/data/configdb --shardsvr #声明这是一个集群的分片,默认端口27018 --noMoveParanoia #关闭偏执为moveChunk数据保存 上述参数也可以直接在mongod.conf配置文件中配置,例如: dbpath = /data/mongodb logpath = /data/mongodb/mongodb.log logappend = true fork = true auth = true 本文转自 Mr_sheng 51CTO博客,原文链接:http://blog.51cto.com/sf1314/2048024

优秀的个人博客,低调大师

详解Dialog(二)——有关列表的构建

一、普通列表 普通列表的样式是这样的: 要实现这样的列表样式,是通过下面的方法来实现的: [java] view plain copy builder.setItems(CharSequence[]items,DialogInterface.OnClickListenerlistener) builder.setItems(intitemsId,DialogInterface.OnClickListenerlistener) 这两种方法实现的效果都是一样的, [java] view plain copy setItems(CharSequence[]items,DialogInterface.OnClickListenerlistener) 这个items传进去的是一个字符串数组; [java] view plain copy setItems(intitemsId,DialogInterface.OnClickListenerlistener) 这个传进去的一个itemsId,是在XML中定义好的一个字符串数组资源的ID; 下面,我们一个个看看他们的具体用法: 1、字符串数组 下面是上图是实现上图效果的代码: [java] view plain copy String[]mItems={"item0","item1","itme2","item3","itme4","item5","item6"}; AlertDialog.Builderbuilder=newAlertDialog.Builder(MyActivity.this); builder.setIcon(R.drawable.ic_launcher); builder.setTitle("使用列表字符串"); builder.setItems(mItems,newDialogInterface.OnClickListener(){ @Override publicvoidonClick(DialogInterfacedialog,intwhich){ Toast.makeText(MyActivity.this,"clicked:"+which,Toast.LENGTH_LONG).show(); } }); builder.create(); builder.show(); 可以看到首先构造一个mItems数组,然后在buidler.setItems直接传进去就好了。至于DialogInterface.OnClickListener(){}函数就是对点击事件的监听,which表示当前点击的是哪个ITEM的索引。 2、字符串资源ID 首先在xml文件夹下建一个字符串资源XML,命名为:array.xml,位置如图: 然后定义一段字符串数组: [java] view plain copy <?xmlversion="1.0"encoding="utf-8"?> <resources> <string-arrayname="dialog_items"> <item>王菲</item> <item>王力宏</item> <item>帅哥</item> <item>美女</item> </string-array> </resources> 下面就是利用SetItem来生成列表了: [java] view plain copy AlertDialog.Builderbuilder=newAlertDialog.Builder(MyActivity.this); builder.setIcon(R.drawable.ic_launcher); builder.setTitle("使用ResourceID"); builder.setItems(R.array.dialog_items,newDialogInterface.OnClickListener(){ @Override publicvoidonClick(DialogInterfacedialog,intwhich){ Toast.makeText(MyActivity.this,"clicked:"+which,Toast.LENGTH_LONG).show(); } }); builder.create(); builder.show(); 在这里的SetItems时直接将我们字符串数组的name直接设置进去,出来的效果就是这样的: 二、单选列表 单选列表的样式是这样的: 要实现单选列表,主要是通过下面四个其中之一来实现的: 方法一: [java] view plain copy setSingleChoiceItems(CharSequence[]items,intcheckedItem,DialogInterface.OnClickListenerlistener) 与上面一样,传进去一个字符串数组,和初始化时选中的ITEM,构造一个单选列表 方法二: [java] view plain copy setSingleChoiceItems(intitemsId,intcheckedItem,DialogInterface.OnClickListenerlistener) 同样,与上面的例子相同,这里传进去的是一个字符串数组的资源ID,字符串数组的构造方法与上面相同,就不再赘述 方法三: [java] view plain copy setSingleChoiceItems(ListAdapteradapter,intcheckedItem,DialogInterface.OnClickListenerlistener) 这 个方法是最难理解的方法,因为这里的ListAdapter并不能是普通的Adapter,不信你传一个Adapter,保证出来只是你自己的ITEM视 图,旁边的单选按钮却出不来,其实这里的Adapter只是重写单选按钮旁的文字的样式,并不支持所有的Adapter,这个我会在本文最后讲述。方法四: [java] view plain copy setSingleChoiceItems(Cursorcursor,intcheckedItem,StringlabelColumn,DialogInterface.OnClickListenerlistener) 这里通过传进去一个Cursor来构造对应的字符串数组,可以是数据库Cursor,也可以其它系统自带的数据Cursor,但基本上用不到,就不再讲了 好了,关于方法三,因为下面会接着讲SetAdapter的知识,所以这部分我留在最后再讲,这里先讲下方法一和方法二: 方法一和方法二,与上例没什么区别,下面我就以方法一以例来讲讲上面的效果图是怎么实现的吧: 代码如下: [java] view plain copy String[]mItems={"攻","受","全能型","不告诉你"}; AlertDialog.Builderbuilder=newAlertDialog.Builder(MyActivity.this); builder.setIcon(R.drawable.ic_launcher); builder.setTitle("你懂的"); builder.setSingleChoiceItems(mItems,0,newDialogInterface.OnClickListener(){ @Override publicvoidonClick(DialogInterfacedialog,intwhich){ //TODOAuto-generatedmethodstub Toast.makeText(MyActivity.this,"clicked:"+which,Toast.LENGTH_LONG).show(); } }); builder.create(); builder.show(); 很简单,构造一个mItems的String字符串,然后直接传进去setSingleChoiceItems中,默认选中第一个,即索引是0的项。 三、多选列表 先看看效果图: 自带的多选构造函数有如下几个: 方法一: [java] view plain copy setMultiChoiceItems(CharSequence[]items,boolean[]checkedItems,DialogInterface.OnMultiChoiceClickListenerlistener) 一样,传进去一个ITEMS数组和对应的项目的选中与否状态的数组; 方法二: [java] view plain copy setMultiChoiceItems(intitemsId,boolean[]checkedItems,DialogInterface.OnMultiChoiceClickListenerlistener) 这里传进去的是一个字符串数组,与第一部分相同 方法三: [java] view plain copy setMultiChoiceItems(Cursorcursor,StringisCheckedColumn,StringlabelColumn,DialogInterface.OnMultiChoiceClickListenerlistener) 同样,这里传进去的是一个CURSOR,可以是数据库的指针,也可以是系统自带数据的指针,基本不怎么用,就不讲了 下面以方法一为例看看多选列表的构造过程: [java] view plain copy String[]mItems={"经常犯二","傻叉一枚","逗逼","小清纯","沉稳大叔","有时可爱"}; AlertDialog.Builderbuilder=newAlertDialog.Builder(MyActivity.this); builder.setIcon(R.drawable.ic_launcher); builder.setTitle("性格类型"); builder.setMultiChoiceItems(mItems, newboolean[]{false,false,false,false,false,false,false}, newDialogInterface.OnMultiChoiceClickListener(){ @Override publicvoidonClick(DialogInterfacedialog,intwhich,booleanisChecked){ Toast.makeText(MyActivity.this,"clicked:"+which,Toast.LENGTH_LONG).show(); } } ); builder.show(); 这里构造了两个数组,一个是字符串数组,另一个每项对应是否选中的boolean数组 [java] view plain copy String[]mItems={"经常犯二","傻叉一枚","逗逼","小清纯","沉稳大叔","有时可爱"}; 对应的选中项的布尔值数组: [java] view plain copy newboolean[]{false,false,false,false,false,false,false} 四、自定义列表项 这节我带大家自定义列表项的实现,故名思义,就是每个ITEM都是我们自己来定义,使用我们自己的Adapter,先看看效果: 要实现自定义列表主要是造下面这个函数来实现的: [java] view plain copy setAdapter(ListAdapteradapter,DialogInterface.OnClickListenerlistener) 直接将我们构造好的Adapter设置进去。 下面就带大家实现下图示中的视图: 1、构造Adapter 有关派生自BaseAdapter来构造ListViewAdapter的过程就不再细讲了,大家可以参考我以前的两篇文章: 1、《List控件使用---SimpleAdapter使用详解(一)》 2、《BaseAdapter——convertView回收机制与动态控件响应》 第 一篇现在看来着实太烂了,一直想重写又没时间来做,大家可以再搜搜网上的其它相关文章来学一下有关BaseAdapter的相关内容吧。第二篇有关 convertView的回收机制写的还是挺不错的,大家可以仔细看看,相信会对ListView的机制有一个更清晰的理解。废话不多说了,下面言转正 转,看看我们这里的ListAdapter的构造过程: 首先是单个Item的布局:(list_item.xml) 很简单,采用水平布局,左边一个图像,右边一个对应的TEXT,这里只是基本实现功能,大家完全可以在理解这篇文章的基础上派生出更复杂的视图 [java] view plain copy <?xmlversion="1.0"encoding="utf-8"?> <LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android" android:orientation="horizontal" android:layout_width="wrap_content" android:layout_height="match_parent"> <ImageView android:id="@+id/item_imageview" android:layout_width="80dip" android:layout_height="80dip" android:scaleType="fitCenter"/> <TextView android:id="@+id/item_text" android:layout_width="wrap_content" android:layout_height="match_parent" android:gravity="center_vertical|left" android:textSize="20sp"/> </LinearLayout> 对应的视图类: [java] view plain copy privateclassViewHolder{ publicTextViewmTvTitle; publicImageViewmImageView; } 其中有两个变量,一个存储对应的TextView,另一个存储对应的ImageView; 现在我们还需要一个类来存储视图类中TextView的标题字符串,和对应ImageView的图片资源的ID值,这就是我们的数据类: [java] view plain copy publicstaticclassDataHolder{ publicStringtitle; publicintImageID; publicDataHolder(Stringtitle,intimageID){ this.title=title; this.ImageID=imageID; } } 我们先阶段性的看看我们的ListViewAdapter: 首先是派生自BaseAdapter,然后是构造函数,我们传进去一个DataHolder的列表,用来存储每个Item应该显示的内容 [java] view plain copy publicclassListItemAdapterextendsBaseAdapter{ privateList<DataHolder>mDataList=newArrayList<DataHolder>(); privateLayoutInflatermInflater; publicListItemAdapter(Contextcontext,ArrayList<DataHolder>datalist){ if(datalist!=null&&datalist.size()>0){ mDataList.addAll(datalist); } mInflater=LayoutInflater.from(context); } ……………… } 然后是最关键的getView部分: [java] view plain copy publicViewgetView(intposition,ViewconvertView,ViewGroupviewGroup){ ViewHolderholder=null; if(convertView==null){ holder=newViewHolder(); convertView=mInflater.inflate(R.layout.list_item,null); holder.mTvTitle=(TextView)convertView.findViewById(R.id.item_text); holder.mImageView=(ImageView)convertView.findViewById(R.id.item_imageview); convertView.setTag(holder); }else{ holder=(ViewHolder)convertView.getTag(); } holder.mImageView.setImageResource(mDataList.get(position).ImageID); holder.mTvTitle.setText(mDataList.get(position).title); returnconvertView; } 首先是通过covertView的tag来获取重复利用的convertView,这什么要这么写,看《BaseAdapter——convertView回收机制与动态控件响应》 然后是利用传进来的数据,初始化列表Item: [java] view plain copy holder.mImageView.setImageResource(mDataList.get(position).ImageID); holder.mTvTitle.setText(mDataList.get(position).title); 最后返回convertView,让系统去做绘图 到这里ListViewAdapter的构造过程就基本完成了,下面是完整的代码: [java] view plain copy /** *Createdbyharvic *date2015-1-11 **/ publicclassListItemAdapterextendsBaseAdapter{ privateList<DataHolder>mDataList=newArrayList<DataHolder>(); privateLayoutInflatermInflater; publicListItemAdapter(Contextcontext,ArrayList<DataHolder>datalist){ if(datalist!=null&&datalist.size()>0){ mDataList.addAll(datalist); } mInflater=LayoutInflater.from(context); } @Override publicintgetCount(){ returnmDataList.size(); } @Override publicObjectgetItem(intposition){ returnmDataList.get(position); } @Override publiclonggetItemId(intposition){ returnposition; } @Override publicViewgetView(intposition,ViewconvertView,ViewGroupviewGroup){ ViewHolderholder=null; if(convertView==null){ holder=newViewHolder(); convertView=mInflater.inflate(R.layout.list_item,null); holder.mTvTitle=(TextView)convertView.findViewById(R.id.item_text); holder.mImageView=(ImageView)convertView.findViewById(R.id.item_imageview); convertView.setTag(holder); }else{ holder=(ViewHolder)convertView.getTag(); } holder.mImageView.setImageResource(mDataList.get(position).ImageID); holder.mTvTitle.setText(mDataList.get(position).title); returnconvertView; } privateclassViewHolder{ publicTextViewmTvTitle; publicImageViewmImageView; } publicstaticclassDataHolder{ publicStringtitle; publicintImageID; publicDataHolder(Stringtitle,intimageID){ this.title=title; this.ImageID=imageID; } } } 2、构造列表 在MainActivity中,首先是初始化我们的ListViewAdapter,要初始化Adapter,就要首先传进去一个DataHolder的数组,所有要先构造一个DataHolder的数组 [java] view plain copy privateArrayList<ListItemAdapter.DataHolder>initDataHolder(){ ArrayList<ListItemAdapter.DataHolder>datalist=newArrayList<ListItemAdapter.DataHolder>(); ListItemAdapter.DataHolderdata_1=newListItemAdapter.DataHolder("可爱萌宠1",R.drawable.animal1); ListItemAdapter.DataHolderdata_2=newListItemAdapter.DataHolder("可爱萌宠2",R.drawable.animal2); ListItemAdapter.DataHolderdata_3=newListItemAdapter.DataHolder("可爱萌宠3",R.drawable.animal3); ListItemAdapter.DataHolderdata_4=newListItemAdapter.DataHolder("可爱萌宠4",R.drawable.animal4); datalist.add(data_1); datalist.add(data_2); datalist.add(data_3); datalist.add(data_4); returndatalist; } 在构造完成数据列表之后,下面就是构造我们的自定义的列表了,我把整个对话框显示过程整合成了一个函数createCustomList,代码如下: [java] view plain copy privatevoidcreateCustomList(){ ArrayList<ListItemAdapter.DataHolder>dataHolders=initDataHolder(); ListItemAdapteradapter=newListItemAdapter(MyActivity.this,dataHolders); AlertDialog.Builderbuilder=newAlertDialog.Builder(MyActivity.this); builder.setIcon(R.drawable.ic_launcher); builder.setTitle("可爱萌宠"); builder.setAdapter(adapter,newDialogInterface.OnClickListener(){ @Override publicvoidonClick(DialogInterfacedialogInterface,intwhich){ Toast.makeText(MyActivity.this,"clicked:"+which,Toast.LENGTH_LONG).show(); } }); builder.create(); builder.show(); } OK啦,到这,整个自列表项的内容就讲完了,下面再回过来给大家说说上面我们提到的有关单选列表自定义Adapter的问题。 五、有关单选列表自定义Adapter 这里主要讲的函数是第二部分单选列表中的方法三: [java] view plain copy setSingleChoiceItems(ListAdapteradapter,intcheckedItem,DialogInterface.OnClickListenerlistener) 在第四部分,我们构造了一个ListAdapter,这里需要的也是同样的一个ListAdapter,那我们直接将第四部分中的Adapter传进去,会是什么效果呢? 也就是利用下面的代码: 我们直接在createCustomList()上面改一下,即把builder.setAdapter()直接换成setSingleChoiceItems() ,传进去Adpter,看看在我们定义的视图后面会不会出现一个单选按钮呢? [java] view plain copy privatevoidcreateCustomList(){ ArrayList<ListItemAdapter.DataHolder>dataHolders=initDataHolder(); ListItemAdapteradapter=newListItemAdapter(MyActivity.this,dataHolders); AlertDialog.Builderbuilder=newAlertDialog.Builder(MyActivity.this); builder.setIcon(R.drawable.ic_launcher); builder.setTitle("可爱萌宠"); builder.setSingleChoiceItems(adapter,0,newDialogInterface.OnClickListener(){ @Override publicvoidonClick(DialogInterfacedialogInterface,intwhich){ Toast.makeText(MyActivity.this,"clicked:"+which,Toast.LENGTH_LONG).show(); } }); builder.create(); builder.show(); } 运行一下,效果是这样的: 看见了没,毛也没有,坑爹玩意,那这个函数到底是用来做什么的呢,在源码中有这样一个文件: 地址在:$android_sdk_home/platforms/Android-x.x/data/res/layout/simple_list_item_single_choice.xml 文件内容是这样的: [html] view plain copy <CheckedTextViewxmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/single_list_item" android:layout_width="match_parent" android:layout_height="?android:attr/listPreferredItemHeightSmall" android:textAppearance="?android:attr/textAppearanceListItemSmall" android:gravity="center_vertical" android:checkMark="?android:attr/listChoiceIndicatorSingle" android:paddingStart="?android:attr/listPreferredItemPaddingStart" android:paddingEnd="?android:attr/listPreferredItemPaddingEnd" /> 利用这个玩意是可以实现效果的,我们来试一下。 1、新建Adapter 新建一个布局文件,来保存ListVIew的每项的Item,代码如下: [html] view plain copy <CheckedTextViewxmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/single_list_item" android:layout_width="match_parent" android:layout_height="?android:attr/listPreferredItemHeightSmall" android:textAppearance="?android:attr/textAppearanceListItemSmall" android:gravity="center_vertical" android:checkMark="?android:attr/listChoiceIndicatorSingle" android:paddingStart="?android:attr/listPreferredItemPaddingStart" android:paddingEnd="?android:attr/listPreferredItemPaddingEnd" /> 在Adapter中,同样,用来保存ITEM视图的ViewHolder类,如下: [java] view plain copy privateclassViewHolder{ publicTextViewmName; } 因 为在布局中只有一个TextView,所以在ViewHolder中也只需要一个TextView与其对应,至于类似上面的承载对应数据的 DataHolder,因为我们只需要一个String字符串数组就足够了,所以就没必要再新建一个类来承载这些数据了,所以我们要构造Adapter 时,传进来一个字符串数组就好了: 所以简单的构造函数为: 在构造时,传进来我们每项要显示的标题的字符串数组String[] items,并将其直接添加到我们的List<String> mList中。 [java] view plain copy publicclassSingleChoiceAdapterextendsBaseAdapter{ privateLayoutInflatermInflater; privateList<String>mList=newArrayList<String>(); publicSingleChoiceAdapter(Contextcontext,String[]items){ mInflater=LayoutInflater.from(context); if(items==null||items.length<=0){ return; } for(Stringitem:items){ mList.add(item); } } ………… } 然后是最关键的getView()部分: [java] view plain copy publicViewgetView(intposition,ViewconvertView,ViewGroupviewGroup){ ViewHolderholder=null; if(convertView==null){ holder=newViewHolder(); convertView=mInflater.inflate(R.layout.single_choice_item,null); holder.mName=(TextView)convertView.findViewById(R.id.single_list_item); convertView.setTag(holder); }else{ holder=(ViewHolder)convertView.getTag(); } holder.mName.setText(mList.get(position)); returnconvertView; } 这段代码难度不大,就是每次绘图时,将TextView的内容设置为我们指定的字符串: [java] view plain copy holder.mName.setText(mList.get(position)); 下面是SingleChoiceAdapter完整的代码: [java] view plain copy /** *Createdbyharvic *date2015-1-11 */ publicclassSingleChoiceAdapterextendsBaseAdapter{ privateLayoutInflatermInflater; privateList<String>mList=newArrayList<String>(); publicSingleChoiceAdapter(Contextcontext,String[]items){ mInflater=LayoutInflater.from(context); if(items==null||items.length<=0){ return; } for(Stringitem:items){ mList.add(item); } } @Override publicintgetCount(){ returnmList.size(); } @Override publicObjectgetItem(intposition){ returnmList.get(position); } @Override publiclonggetItemId(intposition){ returnposition; } @Override publicViewgetView(intposition,ViewconvertView,ViewGroupviewGroup){ ViewHolderholder=null; if(convertView==null){ holder=newViewHolder(); convertView=mInflater.inflate(R.layout.single_choice_item,null); holder.mName=(TextView)convertView.findViewById(R.id.single_list_item); convertView.setTag(holder); }else{ holder=(ViewHolder)convertView.getTag(); } holder.mName.setText(mList.get(position)); returnconvertView; } privateclassViewHolder{ publicTextViewmName; } } 然后就是使用的阶段了 2、构造单选列表 这里首先构造SingleChoiceAdapter的实例,然后将其传入setSingleChoiceItems中,代码如下: [java] view plain copy String[]mItems={"攻","受","全能型","不告诉你"}; SingleChoiceAdapteradapter=newSingleChoiceAdapter(MyActivity.this,mItems); AlertDialog.Builderbuilder=newAlertDialog.Builder(MyActivity.this); builder.setIcon(R.drawable.ic_launcher); builder.setTitle("可爱萌宠"); builder.setSingleChoiceItems(adapter,0,newDialogInterface.OnClickListener(){ @Override publicvoidonClick(DialogInterfacedialogInterface,intwhich){ Toast.makeText(MyActivity.this,"clicked:"+which,Toast.LENGTH_LONG).show(); } }); builder.create(); builder.show(); 运行出来的效果如图: 看到没,这里效果是出来了,可见,在单选按钮中,定义Adapter并不是随便定义的,只能定义CheckedTextView的视图,其它是不支持的!!!! 好了,到这里本篇就结束了,下篇给大家讲讲有关自定义对话框的内容。 本文转自农夫山泉别墅博客园博客,原文链接:http://www.cnblogs.com/yaowen/p/5434828.html,如需转载请自行联系原作者

优秀的个人博客,低调大师

如何构建AI驱动型智能服务?

人工智能(简称AI)驱动型智能服务将把当下各类前沿技术(例如区块链)、物联网以及客户体验因素结合起来——而其未来的发展方向则必然以信任协调为基础。 机器学习、深度学习、自然语言处理以及认知计算的结合将彻底改变人类与机器之间的交互方式。AI驱动型智能服务将学会感知人类身处的周遭环境、根据其以往行动推断个人喜好,并巧妙地通过日常生活对人类加以引导。事实上,对于此类目标的追求将成为当下十年乃至未来最为重要的转变,并使得AI驱动型智能服务被引入各个行业以及各类业务流程当中。 对于企业而言,AI驱动型智能服务则将深刻影响未来的工作流、物联网服务、客户体验以及同步分类帐(即区块链技术)。业务的成功将以AI处理结果为前提(详见图一)。一旦结果建立完成,企业即可规划AI驱动型智能服务,并利用其以规模化方式实现编排、自动化与民主化个性体验交付。 七类AI成果 AI的颠覆性能力源自其速度、精确性以及强化人类判断的能力。我们可以通过以下七类成果了解AI项目所能够实现的具体价值: 1.感知并描述当前正在发生的事态。第一类成果能够同以往的手动编程方案一样描述周遭背景。 2.向你通知你所需了解的情况。通知内容可通过警报、工作流、提醒器以及其它信号加以呈现,并经由手动输入及学习等方式交付额外信息。 3.提供行动建议。根据以往行动提供建议,同时利用权重属性、决策管理以及机器学习随时间推移进行建议修订。 4.自动执行重复工作。随着机器学习不断发展成熟,自动化的实用性也将更上一层楼。 5.提供预测以启发合理预期。要进行预测,我们首先需要建立起深度学习与神经网络,并利用其对行为进行预测与测试。 6.预防负面结果。利用认知推理机制发现潜在威胁。 7.态势感知提供当前重要信息。态势感知将进一步模拟人类在制定决策方面的能力。 AI驱动型智能服务的实现,必须以信任为基础 由于AI驱动型智能服务必须将决策制定责任指派给各原子驱动智能服务,因此任何AI驱动型智能服务的实现基础皆为信任。下面,我们将探讨AI驱动型智能服务信任协调体系中的五大关键组成部分。 1.配合AI,利用数据化足迹与数据产出建立匿名与显式资料。每一个人、设备或者网络都会提供部分信息。这种数字化足迹或产出可能源自面部分析、网络IP地址甚至是步态采集。利用AI与认知推理,系统将能够分析其中的模式并将其与身份关联起来。这意味着AI服务将可在不同情景之下识别并认出对应个人。 2.渲染式体验使交互更为自然。情景、内容、协作与频道共同成为AI驱动型服务交付渲染式独特体验的基础。这类服务将利用地理位置、时间段、天气、心跳率甚至是个人感受等因素作为情景属性,同时结合服务自身所掌握的对象身份与偏好,旨在改进相关性交交付更适合的内容。感知与响应机制将通过对话与文本框的形式实现参与者同机器间的协作。频道则包括各类具体交互点,例如移动、社交、信息亭以及个人等等。其目标在于根据身份提供自然的用户体验。 3.大规模个性化数字服务交付。以规模化方式实现预测分析、催化条件以及选择。预测分析允许客户获得提前预判的能力。催化条件则负责响应的交付或者触发。每位个人或设备都将拥有自己的情景体验,具体取决于身份、历史偏好以及当前需求。从自行选择到情景驱动型选择,再到多选择变量测试,AI系统将令选择拥有更为理想的满意度水平。 4.价值交换成就信任协调。采取行动之后,价值交换即可以交易方式进行。货币、非货币与共识是三种常见的价值交换形式。虽然货币交换也许最为人们所熟知,但非货币价值交换(包括认同、访问与影响)通常也能够带来令人瞩目的价值形式。另外,简单的一致性协商或者协议也能够在患者治疗方案或者土地所有权归属等层面实现价值交换。 5.步调与反馈值得关注,AI支持型机器学习亦然。在机器学习与其它AI工具的支持之下,智能服务开始考虑交付的步调问题:一次性、临时、重复、基于订阅以及阈值驱动型机制皆在其中。利用机器学习技术,系统将了解到智能服务的具体交付方式,并将其运用于未来的交互当中。 总结陈词:AI带来的强化效果 担心机器人统治世界确实有些多虑。事实上,成功的AI驱动型智能服务将强化人类智能——正如机器强化人类的物理体能一样。AI驱动型智能服务在定义同步分类帐技术(即区块链)、物联网、客户体验以及未来工作方式的商业模式当中扮演着关键性角色。由此实现的错误率降低、决策速度提升、需求信号识别、结果预测以及“灾难”预防等能力也必将得到越来越多人们的认可。 原文发布时间为:2017年9月7日 本文作者:杨昀煦 本文来自云栖社区合作伙伴至顶网,了解相关信息可以关注至顶网

优秀的个人博客,低调大师

熊猫直播Rancho发布系统构建之路

作者介绍 符杰超,熊猫直播基础架构部高级运维开发工程师。主要负责熊猫直播运维自动化架构平台建设和开发 前言 随着熊猫直播的业务发展越来越快,业务需求的迭代和版本更新需求越来越多,对开发和运维面临以下4个痛点: 项目需求上线越来越多 发布周期比较长,人工操作比较繁琐 发布项目效率和风险的问题,比如平滑发布,切换负载均衡 发布过程没有详细的审计功能 由此,团队内部决定在现有的发布过程上实现开发统一的发布系统平台,实现熊猫直播的运维发布流程化、标准化、自动化为一体的统一发布要求。 下面围绕整个Rancho发布系统做总结梳理,总共分为9个方面: 实现的最终目的 用户登陆(发布系统的第一道安全墙) 用户权限(发布系统的第二道安全墙) 项目权限(发布系统的第三道安全墙) 代码发布前台 代码发布后台 发布过程/结果 建立标准的wiki文档 小结 Rancho 发布系统流程概述架构图 Rancho 发布系统流程图 Rancho发布系统 实现的最终目的 随着熊猫直播业务的迅猛发展、项目、产品的需求规模和版本迭代频次是无法预估的。传统的运维支持方式已渐渐无法满足这种工程应用现状。但是如果把发布权利交付到开发人员手里控制,运维安全是比较大的隐患。当2者都无法平衡的时候,利用高效的标准化,自动化体系将2个无法逾越的问题优化结合起来,我们结合了上述问题,实现了内部的发布系统,对于发布系统,实现了2个核心目标,如下: 发布项目统一接入在新项目接入平台的第一次起,运维只需要把项目添加上,给对应的开发开放相对应的发布权限,项目接入+权限都是正常状态下,运维需要做的事情就完成了 一键自动发布开发可以根据自己所拥有的项目发布权限,进行任何时间段的发布,同时发布系统会对用户,发布项目,发布操作,结果做到全方位的记录 目的: 让研发自助运维 用户登陆(发布系统的第一道安全墙) 对于发布系统的登陆,我们结合了内部开发的一套SSO系统+Rancho系统并加了一层白名单策略,有以下3个方面考虑: 安全性平台登陆安全性,SSO采用统一认证+MD5算法+Hash算法+静态系统唯一标识 连接统一的Session/Cookie允许连接,保持会话,过期,删除由SSO管理 双权验证假如用户在SSO可以正常登陆,但是在Rancho发布平台没有登陆权限,就是禁止登陆。原因很简单,因为全公司每个人都拥有自己的统一登陆账户,防止有人试探登陆/误操作登陆 用户权限(发布系统的第二道安全墙) 用户权限,我们分为2类角色: 管理员具有发布系统超级权限,可以对所有项目/用户进行操作 普通用户只能看到运维授权的项目,发布、发布详情、查看发布历史、查询,但是不可编辑、更新项目 项目权限(发布系统的第三道安全墙) 项目权限设计,我们当时也花很多时间去讨论,最终拟定方案,项目不首先对应用户,而是在用户和项目中间建立一个桥梁,我们命名为项目组 原因当多个用户同时去拥有一个项目权限的时候,这个时候要全部用户都要增加到这个项目体系中去 如果这样做的问题增加繁琐,当项目删除改用户权限/或者用户不再拥有该项目权限,还要精确的删除,否则删除错了,后果很严重,逻辑同时还要对用户和项目,做双层处理操作 解决方案用户--项目组--项目 方案优点 项目组方便了运维管理,如果没有项目组,一个项目对应的权限用户比较多的话、需要管理员分别的去增加/更新编辑比较繁琐 系统根据项目组有效控制不同用户之间对应项目的权限隔离发 项目组图例 代码发布前台 前台用于开发人员进行发布所操作的页面,其中功能包含: 发布页面 发布tag种类选择 发布环境/机器列表选择 当用户进来某个项目的时候,Rancho 发布系统会同时异步获取该项目所有的环境/主机列表,对用户而言无需任何操作处理。 发布页面 支持机器单选、多选、全选、临时主机添加等: 发布tag种类 发布tag种类选择如下: 开发tag(可测试) 线上tag(灰度/线上) 其他tag(代表开发/线上 tag 未显示你要发布的 tag,发布人员可以根据 tag号输入,如果 git 库里存在,可以正常发布,如果不存在,用户也可以接收到对应的错误结果) 线上/开发tag,Rancho 发布系统会自动实时更新git库前10个最新的tag,供用户选择 tag版本选择页面 tag比对图 用户选择的tag和主干,和最后一次发布tag比对如下: 发布环境/机器列表选择 对于发布环境我们有自己的一套命名扩展规则,有3种类型: 类型一根据项目功能服务来命名 类型二根据发布环境来命名 类型三 前2者整合 某个项目命名情况: 项目功能服务拆分,包含:crontab、sdk、console、front等 项目发布环境拆分,包含:online、beta、gray等 独立情况/整合情况,如下说明: beta环境可以独立的命名 beta环境有sdk服务,命名为:sdk_beta beta环境有console,命名为:beta_console PS:环境命名、细化、拆解,开发人员根据项目功能类型进行自定义,Rancho自动识别和拆解命名体系 每个发布环境对应发布的机器,其中一个项目页面如下展示 前台首页图 用户登陆进来看到的所拥有项目的页面,功能有发布、查看、发布历史、需说明(只有管理员才有展示启用/禁用权限) 启用:代表这个项目是正常运行发布禁用:可以看作删除,但是我们不作为真正删除,临时迁入回收站,如果哪天这个项目需要启用发布了,我们再打开进行该项目发布 前台发布确认清单 发布前让发布用户再次确认上线的项目,tag,发布环境,是否重启机器(现有的和临时添加的主机): 发布清单提交请求 避免脏数据的方法: 程序监控对发布队列是否正常服务检测,并且自动做干预 程序监控对数据库/缓存正常服务检测,并且自动做干预 程序监控对生成的task_ID是否存在,并且自动做干预 程序监控对生成的发布指令做严格的判断,是否为不正确指令,并且自动做出干预 代码发布后台 后台项目管理的成功/失败,对整个前台发布起到至关重要的 后台操作权限为管理员:一般是指定对应的运维人员 操作程度:简单、易用,所有处理逻辑都交给Rancho去搞定 后台操作新项目流程页面 新建字段说明 名称: 代表项目的主名称(唯一,如果重复则提示错误详情),别名代表项目的描述,可以是中文/英文,名称可以重复 git clone url地址:开发提供,这个地址Rancho在处理的过程中,会对本身项目权限,该项目类型标识进行判断和提取,比如我们有2种功能发布:rigger和ansible,而发布语言有:golang、php、nodejs、python、lua、c++等多种混合语言,排名不分先后 项目组权限:添加该项目允许哪些项目组成员进行发布 备注: 可写/可不写 至此,运维管理员需要做的事情已经完成,剩下的点击提交,剩下的事情交给Rancho去处理了。 后台新建页面 Rancho底层基本处理流程 项目失败手动触发 Rancho 处理恢复流程 发布过程/结果 前期的工作: 后台新建项目完成,到发布提交申请,最后查看发布过程/结果的验证 某一个项目单次发布127台主机,用时3分32秒,截图如下: 发布过程的处理流程概述和原理图例展示 发布过程有3种场景: 负载均衡四/七层策略 无负载均衡策略 项目服务是否重启 针对以上3种场景,分别作了不同的处理规则: 负载均衡场景有白名单策略代表该项目拥有负载均衡策略(至于挂了多少负载均衡节点在发布的时候,Rancho发布系统会自动的计算,并且做相对应的平滑策略切换) 无负载均衡策略走正常的发布流程 项目服务发布是否重启(Rancho支持重启项目服务/支持不重启项目服务)需求描述: 项目发布更新,但是不重启服务,看下项目代码发布过程是否成功/失败。(这点对于发布项目业务正常运行不会出现有损情况) 项目发布更新,重启服务(项目发布代码完成,自动重启项目服务) 发布速度:无负载均衡策略项目相对于比有LB策略的项目快2ms-30ms,根据项目绑定的LB有关联。 项目发布锁图例展现 发布锁作用: 防止同项目同发布环境多任务一起发布,会有覆盖,冲突 项目发布历史统计图例展现 状态分为: 正在发布 触发失败 发布成功 项目发布手工终止图例展现 发布结果成功图例展现 发布结果失败/终止图例展现 失败单台,未执行的机器程序自动干预停止发布实例子 发布过程中,手工可以终止发布功能,说明 防止发布过程中有未知的原因或长时间缓慢/卡顿等,发布人员可以根据业务重要评估,进行降级发布过程停止操作,并且系统会把操作用户、时间、项目、降级操作等做详细记录 正常发布完成后,终止发布按钮功能会自动消失 下面截图所示 项目回滚策略 当某个项目发布失败或者异常,想回滚到上个正常版本,可以以对应的tag号来进行重新发布 发布结果日志截图展现 自动按天生成日志,并且按天做发布日志全量汇总 建立完善的Wiki文档 Rancho发布系统在熊猫直播循序渐进的优化功能/需求、bug修复等、wiki文档的规范化也要随之建立起来。 以下是wiki文档建立的图例: 小结 Rancho发布系统已经在线上运行了将近5个月的时间,目前 Rancho系统功能包含了: 项目建立 用户登陆权限严格的隔离 项目锁机制 项目前台 项目后台 LB 4/7层和 Nginx upstream 白名单策略 平滑摘取/绑定主机 支持Rigger发布功能和Ansible发布功能 多语言混合并行发布(Golang、PHP、Nodejs、C++、Lua、Python、Shell等,语言排名不分先后) 异步实时处理发布任务 实时可视化展现发布结果 多环境发布 跨多机房发布 手工/自动干预终止发布 避免严重的错误影响到正常业务 详细的发布操作记录:用户操作、时间、发布环境、发布tag、发布主机成功次数统计、发布主机失败次数统计、发布主机程序自动干预终止次数统计、发布主机手工干预终止次数统计、发布主机正在发布中次数统计等 目前熊猫直播Rancho发布系统解决的痛点: 研发自助运维熊猫直播产品业务线的发布更新/回滚变更等操作,都由各自的项目线开发人员操作发布/回滚,运维不直接参与整个发布/回滚流程,遇到发布错误/异常,运维才介入和开发一起排查相关问题 发布时间周期长目前发布系统异步处理整个发布流程,点击发布提交之后,页面关闭都可以,发布人员想看结果的时候,才登陆系统查看即可 平滑切换负载均衡发布系统增加了白名单策略,发布项目上线前,Rancho发布系统会自动判断白名单策略项目,如果该项目存在白名单策略,Rancho发布系统会自动做整个负载均衡下线—上线—绑定上线流程操作 发布系统详细的审计功能从用户登陆-创建发布清单-点击发布-发布过程-发布结果都做了详细的记录,记录纬度:登陆时间、发布起始时间、发布完成时间、用户、发布环境、发布项目(平滑,服务是否重启,tag,主机数量,主机信息清单),发布结果(成功、失败、终止)等 目前发布次数/项目总数统计 2017年2月16日上线到目前,累计发布工单12000次,最多单次工单发布主机100台+,成功96%,失败3%,终止1%,接入发布项目将近100+。 Rancho发布系统未来优化 Rancho发布系统未来优化的路还有很多,优化方向分为以下3点: 接入发布预警平台当某个项目出现异常的时候,运维能及时收到短信/邮件的提示 定时作业发布可以按照用户自定义的发布时间,定时发布代码 发布错误/异常自动修复目前Rancho发布系统已经可以收集到全部错误发布类型,但是真正修复还需人工,以后当错误出现了,自动上报到修复库里进行存档,在下一次同样错误出现的时候,Rancho自动修复,并优雅提示用户发布错误修复完成,请重新发布

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

用户登录
用户注册