首页 文章 精选 留言 我的

精选列表

搜索[入门],共9369篇文章
优秀的个人博客,低调大师

Maven入门

1. Maven概念模型 图1.png 项目对象模型(Project Object Mobel) 通过pom.xml定义项目的坐标、项目依赖、项目信息、插件目标等。每个maven工程中都有一个pom.xml文件(核心配置文件),该文件里面定义了工程所依赖的jar包、本工程的坐标、打包运行方式等。 依赖管理系统(Dependency Management System) maven的基础核心,通过定义项目所依赖组件的坐标由maven进行依赖管理。也即maven通过坐标对项目工程所依赖的jar包进行统一规范的管理。 比如:项目依赖Struts2.3.24,通过在pom.xml中定义依赖即可将Struts2的jar包自动加入到工程中,pom.xml中定义依赖如下: <dependency> <groundId>org.apache.struts</groundId> <artifactId>struts2-core</artifactId> <version>2.3.24</version> </dependency> 一个项目生命周期(Project Lifecycle) 一个软件开发人员每天都在完成项目的生命周期:清理、编译、测试、部署,有的手工完成,有的通过Ant(也是一个项目构建工具)脚本自动完成,maven将项目的生命周期抽象统一为:清理、初始化、编译、测试、报告、打包、部署、站点生成等。 图2.png maven就是要保证一致的项目构建流程,通过执行一些简单命令即可实现上边生命周期的各个过程。 一组标准集合 maven将整个项目管理过程定义一组标准,比如:通过maven构建工程有标准的目录结构,有标准的生命周期阶段、依赖管理有标准的坐标定义等。 我在这儿还是强调一遍:maven工程有自己标准的工程目录结构、有标准的坐标定义。 插件(plugin)目标(goal) maven管理项目生命周期过程都是基于插件完成的。 2. maven的仓库 maven工作需要配置仓库,本地的项目A、项目B等通过maven从远程仓库(可以理解为互联网上的仓库)下载jar包并保存在本地仓库,本地仓库就是本地文件夹,当第二次需要此jar包时则不再从远程仓库下载,因为本地仓库已经存在了。可以将本地仓库理解为缓存,有了本地仓库就不用每次从远程仓库下载了。 下面描述了maven中仓库的类型: 图3.png 本地仓库:用来存储从远程仓库或中央仓库下载的插件和jar包,项目使用一些插件或jar包,优先从本地仓库查找。 远程仓库:如果本地需要插件或者jar包,本地仓库没有,默认从远程仓库下载。 中央仓库:在maven环境内部内置一个远程仓库地址:http://repo1.maven.org/maven2,它是中央仓库(即特殊的远程仓库),服务于整个互联网,它是由maven团队自己维护的,里面由大量的常用类库,并包含了世界上大部分流行的开源项目构件。 3. 安装 1). 下载和安装--下载地址 图4.png bin目录:mvn.bat(以run方式运行项目)、mvnDebug.bat(以debug方式运行项目) boot目录:maven运行需要的类加载器 conf目录:settings.xml,整个maven工具的核心配置文件 lib目录:maven运行依赖的jar包 2). 配置环境变量 I. 新建环境变量 图5.png II. 将 %MAVEN_HOME%\bin添加到path环境变量中 图6.png III. 测试 在命令提示符中输入命令-- mvn -v 图7.png 3). 本地仓库配置 本地仓库是用来存放联网下载的maven插件和jar包,maven本地仓库有的jar包将不再从互联网下载,所以本地仓库就相当于一个缓存。 在maven的安装目录中的conf目录下有一个settings.xml文件,在这个文件中可配置本地仓库 图8.png 如果本地仓库不配置(那么就会从互联网上下载jar包,而且下载速度贼慢),那么默认的本地仓库的位置就是{user.home}表示windows用户目录,在win7系统下如下: 图9.png 全局settings配置文件:就是maven的安装目录中的conf目录下的settings.xml文件。该文件里面的所有配置可应用于所有项目。 用户settings配置文件:在${user.home}/.m2/repository目录下。如果某些用户需要对maven特殊设置,用户可以自定义settings文件 4). eclipse配置maven安装程序 高版本的eclipse默认已经集成了maven的插件,但其实还内置了maven程序,Window->Preferences,搜索maven如下: 图10.png 注意:我们一般不用内置的maven程序,原因是为了在项目中统一maven版本 5). 选择指定的maven程序 点击Add...->>然后选择自己电脑中的maven程序->>点击Finish。 图11.png 然后勾选新增的一项。 图12.png 6). 指定User Settings 点击User Settings->点击Browse...选择settings.xml文件->点击Update Settings,在Local Repository一项会自动填充仓库位置->点击Apply->OK。 图13.png 7). Eclipse浏览本地仓库 Window->Show View->Other->Maven->Maven Repositories. 图14.png 4. 测试项目 1). 新建项目 I. File->Other->Maven->Maven Project->Next 图15.png II. 勾选Use default Workspace location是将工程创建在默认的路径下 图16.png III. 点击最后一项->Next 图17.png maven-archetype-quickstart: 普通Java工程 maven-archetype-webapp: Web工程 IV. 配置信息->点击Finish. 图18.png Group Id:项目的名称,项目名称以域名的倒序命名(类似java包名),比如我们要创建一个CRM的项目,可写为cn.itcast.crm。 Artifact Id:模块名称(子项目名称)。 Version:项目当中模块的版本,snapshot(快照版或测试版,没有正式发行)、release(正式发行版本)。 Package:包名。Group Id + Artifact Id. V. 解决错误 图19.png 错误原因:未Server Runtime.解决办法:邮件项目->Build Path->Configure Build Path...->Libraries->Add Library...->Next->apply.. 图20.png 图21.png VI. 项目结构 图21.png *注意:新创建的maven工程的目录结构不是一个完整的目录结构。 maven工程的一个完整的目录结构为: project /src/main/java 主体程序的java源文件(不要放配置文件) /src/main/resources 主体程序所需要的配置文件(不要放java文件) /src/test/java 单元测试程序的java源文件 /src/test/resources 单元测试程序所用的配置文件 /target 编译输出目录 /pom.xml 2). 配置 I. 设置maven的编译版本,由于我使用的是JDK1.8,所以要设置maven的编译版本为1.8,即要在maven工程的pom.xml文件中添加如下配置: <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.mazaiting.cmp</groupId> <artifactId>MavenTest</artifactId> <packaging>war</packaging> <version>0.0.1-SNAPSHOT</version> <name>MavenTest Maven Webapp</name> <url>http://maven.apache.org</url> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>3.8.1</version> <scope>test</scope> </dependency> </dependencies> <build> <finalName>MavenTest</finalName> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>1.8</source> <target>1.8</target> <encoding>UTF-8</encoding> </configuration> </plugin> </plugins> </build> </project> maven运行的时候都是依赖于插件的,包括编译也是需要通过插件——org.apache.maven.plugins(该插件就在你的本地仓库)来完成。 II. 添加完如上配置之后,可发现我们的maven工程上面有一个红叉,如下所示: 图22.png III. 更新项目。右键项目->Maven->Update Project... 图23.png

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

Nomad入门

Nomad 简介 Nomad是一个管理机器集群并在集群上运行应用程序的工具。 Nomad的特点: 支持docker,Nomad的job可以使用docker驱动将应用部署到集群中。 Nomad安装在linux中仅需单一的二进制文件,不需要其他服务协调,Nomad将资源管理器和调度程序的功能集成到一个系统中。 多数据中心,可以跨数据中心调度。 分布式高可用,支持多种驱动程序(Docker、VMS、Java)运行job,支持多种系统(Linux、Windows、BSD、OSX)。 Nomad安装 一般环境下,首先安装Vagrant,利用Vagrant连接本地的Virtualbox,创建本地测试环境。不过由于在学习过程中,本地win7环境缺失了一些组件,导致无法安装并使用Vagrant。 所以直接使用Linux虚拟机来进行学习。本环境使用Ubuntu16.04,Docker version 17.09.0-ce。 下载Nomad二进制文件,选择适合你系统的安装包。 # wget https://releases.hashicorp.com/nomad/0.7.0/nomad_0.7.0_linux_amd64.zip?_ga=2.169483045.503594617.1512349197-1498904827.1511322624 解压安装包,将Nomad文件放在/usr/local/bin下. # unzip -o nomad_0.7.0_linux_amd64.zip -d /usr/local/bin/ # cd /usr/local/bin # chmod +x nomad 终端输入nomad,可看到nomad 提示,即安装成功。 开始Nomad 为了简单运行,我们以开发模式运行Nomad agent。开发模式可以快速启动server端和client端,测试学习Nomad。 # nomad agent -dev ==> Starting Nomad agent... ==> Nomad agent configuration: Client: true Log Level: DEBUG Region: global (DC: dc1) Server: true ==> Nomad agent started! Log data will stream in below: [INFO] serf: EventMemberJoin: nomad.global 127.0.0.1 [INFO] nomad: starting 4 scheduling worker(s) for [service batch _core] [INFO] client: using alloc directory /tmp/NomadClient599911093 [INFO] raft: Node at 127.0.0.1:4647 [Follower] entering Follower state [INFO] nomad: adding server nomad.global (Addr: 127.0.0.1:4647) (DC: dc1) [WARN] fingerprint.network: Ethtool not found, checking /sys/net speed file [WARN] raft: Heartbeat timeout reached, starting election [INFO] raft: Node at 127.0.0.1:4647 [Candidate] entering Candidate state [DEBUG] raft: Votes needed: 1 [DEBUG] raft: Vote granted. Tally: 1 [INFO] raft: Election won. Tally: 1 [INFO] raft: Node at 127.0.0.1:4647 [Leader] entering Leader state [INFO] raft: Disabling EnableSingleNode (bootstrap) [DEBUG] raft: Node 127.0.0.1:4647 updated peer set (2): [127.0.0.1:4647] [INFO] nomad: cluster leadership acquired [DEBUG] client: applied fingerprints [arch cpu host memory storage network] [DEBUG] client: available drivers [docker exec java] [DEBUG] client: node registration complete [DEBUG] client: updated allocations at index 1 (0 allocs) [DEBUG] client: allocs: (added 0) (removed 0) (updated 0) (ignore 0) [DEBUG] client: state updated to ready 在终端输出中看到,server和client都为true,表示同时开启了server和client。 Nomad集群节点 # nomad node-status ID DC Name Class Drain Status fb533fd8 dc1 yc-jumpbox <none> false ready 输出显示了我们的节点ID,它是随机生成的UUID,其数据中心,节点名称,节点类别,漏斗模式和当前状态。我们可以看到我们的节点处于就绪状态。 # nomad server-members Name Address Port Status Leader Protocol Build Datacenter Region yc-jumpbox.global 10.30.0.52 4648 alive true 2 0.7.0 dc1 global 输出显示了我们自己的server,运行的地址,运行状况,一些版本信息以及数据中心和区域。 停止Nomad agent 你可以使用Ctrl-C中断agent。默认情况下,所有信号都会导致agent强制关闭。 Nomad Job Job是我们在使用Nomad主要交互的内容。 示例Job 进入你的工作目录使用nomad init命令。它会在当前目录生成一个example.nomad,这是一个示例的nomad job配置文件。 # cd /tmp # nomad init Example job file written to example.nomad 运行这个job,我们使用nomad run命令。 # nomad run example.nomad ==> Monitoring evaluation "13ebb66d" Evaluation triggered by job "example" Allocation "883269bf" created: node "e42d6f19", group "cache" Evaluation within deployment: "b0a84e74" Evaluation status changed: "pending" -> "complete" ==> Evaluation "13ebb66d" finished with status "complete" 查看job状态,我们使用nomad status 命令 # nomad status example ID = example Name = example Submit Date = 12/05/17 10:58:40 UTC Type = service Priority = 50 Datacenters = dc1 Status = running Periodic = false Parameterized = false Summary Task Group Queued Starting Running Failed Complete Lost cache 0 0 1 0 0 0 Latest Deployment ID = b0a84e74 Status = successful Description = Deployment completed successfully Deployed Task Group Desired Placed Healthy Unhealthy cache 1 1 1 0 Allocations ID Node ID Task Group Version Desired Status Created At 883269bf e42d6f19 cache 0 run running 12/05/17 10:58:40 UTC 检查job的分配情况,我们使用nomad alloc-status命令。 # nomad alloc-status 883269bf ID = 883269bf Eval ID = 13ebb66d Name = example.cache[0] Node ID = e42d6f19 Job ID = example Job Version = 0 Client Status = running Client Description = <none> Desired Status = run Desired Description = <none> Created At = 12/05/17 10:58:49 UTC Deployment ID = b0a84e74 Deployment Health = healthy Task "redis" is "running" Task Resources CPU Memory Disk IOPS Addresses 8/500 MHz 6.3 MiB/256 MiB 300 MiB 0 db: 127.0.0.1:22672 Task Events: Started At = 12/05/17 10:58:49 UTC Finished At = N/A Total Restarts = 0 Last Restart = N/A Recent Events: Time Type Description 10/31/17 22:58:49 UTC Started Task started by client 10/31/17 22:58:40 UTC Driver Downloading image redis:3.2 10/31/17 22:58:40 UTC Task Setup Building Task Directory 10/31/17 22:58:40 UTC Received Task received by client 查看job日志,我们使用nomad logs 命令。注意logs后面的参数为uuid和task名字。uuid可以通过nomad status example命令得到,task名字在example.nomad配置文件中定义。 # nomad logs 883269bf redis _._ _.-``__ ''-._ _.-`` `. `_. ''-._ Redis 3.2.1 (00000000/0) 64 bit .-`` .-```. ```\/ _.,_ ''-._ ( ' , .-` | `, ) Running in standalone mode |`-._`-...-` __...-.``-._|'` _.-'| Port: 6379 | `-._ `._ / _.-' | PID: 1 `-._ `-._ `-./ _.-' _.-' |`-._`-._ `-.__.-' _.-'_.-'| | `-._`-._ _.-'_.-' | http://redis.io `-._ `-._`-.__.-'_.-' _.-' |`-._`-._ `-.__.-' _.-'_.-'| | `-._`-._ _.-'_.-' | `-._ `-._`-.__.-'_.-' _.-' `-._ `-.__.-' _.-' `-._ _.-' `-.__.-' ... 修改job # vim example.nomad 在文件中找到 count = 1,改为count = 3. 完成修改后,使用nomad plan example.nomad命令 # nomad plan example.nomad +/- Job: "example" +/- Task Group: "cache" (2 create, 1 in-place update) +/- Count: "1" => "3" (forces create) Task: "redis" Scheduler dry-run: - All tasks successfully allocated. Job Modify Index: 7 To submit the job with version verification run: nomad run -check-index 7 example.nomad When running the job with the check-index flag, the job will only be run if the server side version matches the job modify index returned. If the index has changed, another user has modified the job and the plan's results are potentially invalid. 使用给出的更新命令去更新job。 # nomad run -check-index 7 example.nomad ==> Monitoring evaluation "93d16471" Evaluation triggered by job "example" Evaluation within deployment: "0d06e1b6" Allocation "3249e320" created: node "e42d6f19", group "cache" Allocation "453b210f" created: node "e42d6f19", group "cache" Allocation "883269bf" modified: node "e42d6f19", group "cache" Evaluation status changed: "pending" -> "complete" ==> Evaluation "93d16471" finished with status "complete" 停止job,我们使用nomad stop命令。使用nomad status命令可以看到这个job的状态为dead(stopped)。 # nomad stop example ==> Monitoring evaluation "6d4cd6ca" Evaluation triggered by job "example" Evaluation within deployment: "f4047b3a" Evaluation status changed: "pending" -> "complete" ==> Evaluation "6d4cd6ca" finished with status "complete" 建立简单的Nomad集群 Nomad集群分为两部分,server服务端和client客户端。每个区域至少有一台server,建议使用3或者5台server集群。Nomad客户端是一个非常轻量级的进程,它注册主机,执行心跳,并运行由服务器分配给它的任务。代理必须在集群中的每个节点上运行,以便服务器可以将工作分配给这些机器。 启动服务器 第一步是为服务器创建配置文件。无论是从下载的文件github,或粘贴到一个名为server.hcl: vim server.hcl # Increase log verbosity log_level = "DEBUG" #setup datacenter datacenter= "dc1" # Setup data dir data_dir = "/tmp/server1" # Enable the server server { enabled = true # Self-elect, should be 3 or 5 for production bootstrap_expect = 1} 这是一个相当最小的服务器配置文件,但只能以仅服务器方式启动代理,并将其选为leader。应该对生产进行的主要变化是运行多台服务器,并更改相应的bootstrap_expect值。创建文件后,在新选项卡中启动代理: $ sudo nomad agent -config server.hcl ==> WARNING: Bootstrap mode enabled! Potentially unsafe operation. ==> Starting Nomad agent... ==> Nomad agent configuration: Client: false Log Level: DEBUG Region: global (DC: dc1) Server: true Version: 0.6.0 ==> Nomad agent started! Log data will stream in below: [INFO] serf: EventMemberJoin: nomad.global 127.0.0.1 [INFO] nomad: starting 4 scheduling worker(s) for [service batch _core] [INFO] raft: Node at 127.0.0.1:4647 [Follower] entering Follower state [INFO] nomad: adding server nomad.global (Addr: 127.0.0.1:4647) (DC: dc1) [WARN] raft: Heartbeat timeout reached, starting election [INFO] raft: Node at 127.0.0.1:4647 [Candidate] entering Candidate state [DEBUG] raft: Votes needed: 1 [DEBUG] raft: Vote granted. Tally: 1 [INFO] raft: Election won. Tally: 1 [INFO] raft: Node at 127.0.0.1:4647 [Leader] entering Leader state [INFO] nomad: cluster leadership acquired [INFO] raft: Disabling EnableSingleNode (bootstrap) [DEBUG] raft: Node 127.0.0.1:4647 updated peer set (2): [127.0.0.1:4647] 我们可以看到,客户端模式被禁用,我们只是作为服务器运行。这意味着该服务器将管理状态并进行调度决策,但不会执行任何任务。现在我们需要一些代理来运行任务! 启动客户端 与服务器类似,我们必须先配置客户端。请从github下载client1和client2的配置 ,或将以下内容粘贴到client1.hcl: # Increase log verbosity log_level = "DEBUG" # Setup data dir data_dir = "/tmp/client1" # Enable the client client { enabled = true # For demo assume we are talking to server1. For production, # this should be like "nomad.service.consul:4647" and a system # like Consul used for service discovery. servers = ["127.0.0.1:4647"] } # Modify our port to avoid a collision with server1 ports { http = 5656 } 将该文件复制client2.hcl并更改data_dir为“/tmp/client2 ”并将端口更改为5657.一旦创建了这两个文件,client1.hcl并client2.hcl打开每个选项卡并启动代理程序: # sudo nomad agent -config client1.hcl ==> Starting Nomad agent... ==> Nomad agent configuration: Client: true Log Level: DEBUG Region: global (DC: dc1) Server: false Version: 0.6.0 ==> Nomad agent started! Log data will stream in below: [DEBUG] client: applied fingerprints [host memory storage arch cpu] [DEBUG] client: available drivers [docker exec] [DEBUG] client: node registration complete ... 在输出中,我们可以看到代理仅在客户端模式下运行。该代理将可用于运行任务,但不会参与管理集群或做出调度决策。使用node-status命令 我们应该看到ready状态中的两个节点: # nomad node-status ID Datacenter Name Class Drain Status fca62612 dc1 nomad <none> false ready c887deef dc1 nomad <none> false ready 我们现在有一个简单的三节点集群运行。演示和完整生产集群之间的唯一区别是,我们运行的是单个服务器,而不是三个或五个。 提交工作 现在我们有一个简单的集群,我们可以用它来安排一个工作。我们还应该拥有example.nomad之前的作业文件,但是确认count仍然设置为3。然后,使用run命令提交作业: # nomad init # nomad run example.nomad ==> Monitoring evaluation "8e0a7cf9" Evaluation triggered by job "example" Evaluation within deployment: "0917b771" Allocation "501154ac" created: node "c887deef", group "cache" Allocation "7e2b3900" created: node "fca62612", group "cache" Allocation "9c66fcaf" created: node "c887deef", group "cache" Evaluation status changed: "pending" -> "complete" ==> Evaluation "8e0a7cf9" finished with status "complete" 我们可以在输出中看到调度程序为其中一个客户机节点分配了两个任务,剩下的任务分配给第二个客户端。我们可以再次使用status命令验证: # nomad status example ID = example Name = example Submit Date = 07/26/17 16:34:58 UTC Type = service Priority = 50 Datacenters = dc1 Status = running Periodic = false Parameterized = false Summary Task Group Queued Starting Running Failed Complete Lost cache 0 0 3 0 0 0 Latest Deployment ID = fc49bd6c Status = running Description = Deployment is running Deployed Task Group Desired Placed Healthy Unhealthy cache 3 3 0 0 Allocations ID Eval ID Node ID Task Group Desired Status Created At 501154ac 8e0a7cf9 c887deef cache run running 08/08/16 21:03:19 CDT 7e2b3900 8e0a7cf9 fca62612 cache run running 08/08/16 21:03:19 CDT 9c66fcaf 8e0a7cf9 c887deef cache run running 08/08/16 21:03:19 CDT 我们可以看到我们的所有任务已经分配并正在运行。一旦我们对我们的工作感到满意,我们就可以把它删掉了nomad stop。 使用nomad UI 仁者见仁智者见智,我在使用途中,觉得第一种UI是挺好的,可以看到很多细节的内容,相比官方的UI还没有完善更多功能。目前Nomad0.7版本集成了UI,在0.7版本之前,UI一直没有很好的实现,所以我在github上找到一位大牛的UI作品https://github.com/jippi/hashi-ui。 官方UI 需要在github上下载nomad项目到本地,地址为:https://github.com/hashicorp/nomad/tree/master/ui 认真阅读README,将Node.js、Yarn、Ember CLI、PhantomJS安装在本地环境中。 安装 # cd ui/ # yarn 安装完成后,运行这条命令:ember serve --proxy http://10.30.0.52:4646 (10.30.0.52换成你的外网IP,4646换成你自定义的端口),即可在浏览器中查看。 常见问题 服务会运行在127.0.0.1网卡上,外部不能访问? 建议在运行nomad agent时,命令行配置相应的网卡。例如: # nomad agent -config server.hcl -bind=0.0.0.0 # nomad agent -config client1.hcl -network-interface=ens160 使用docker运行服务时,容器会映射随机端口在本地?根据研究官方文档,文档中提示了docker会随机映射端口,如果想使用静态端口,可以在job配置文件中定义。 简单的job配置文件 hello world # cat hello.nomad job "hello1" { datacenters = ["dc1"] #定义数据中心 group "hello2" { #组名字 task "hello3" { #一般使用服务名字表示task名字 driver = "docker" #使用docker驱动 config { image = "hashicorp/http-echo" #服务镜像名字 args = [ #容器运行时的命令参数 "-listen", ":5678", "-text", "hello world", ] } resources { #配置服务的资源 network { mbits = 10 #限制10MB带宽 port "http" { static = "5678" #使用静态端口 } } } } } } 搭建一个redmine,由于我还没弄明白nomad如何像docker-compose一样启动服务,所以mysql只好提前单独运行起来。 # cat redmine-example.nomad job "redmine" { region = "global" #设置地区 datacenters = ["dc1"] #设置数据中心 type = "service" #设置该job类型是服务,主要用于conusl的服务注册,不写这条,该job不会注册服务到consul update { max_parallel = 1 #同时更新任务数量 min_healthy_time = "10s" #分配必须处于健康状态的最低时间,然后标记为正常状态。 healthy_deadline = "3m" #标记为健康的截止日期,之后分配自动转换为不健康状态 auto_revert = false #指定job在部署失败时是否应自动恢复到上一个​​稳定job canary = 0 #如果修改job以后导致更新失败,需要创建指定数量的替身,不会停止之前的旧版本,一旦确定替身健康,他们就会提升为正式服务,更新旧版本。 } group "redmine" { count = 1 # 启动服务数量 restart { attempts = 10 #时间间隔内重启次数 interval = "5m" #在服务开始运行的持续时间内,如果一直出现故障,则会由mode控制。mode是控制任务在一个时间间隔内失败多次的行为。 delay = "25s" #重新启动任务之前要等待的时间 mode = "delay" #指示调度程序延迟下一次重启,直到下一次重启成功。 } ephemeral_disk { #临时磁盘 MB为单位 size = 300 } task "redmine" { driver = "docker" env { #环境变量 REDMINE_DB_MYSQL = "10.30.0.52" REDMINE_DB_POSTGRES = "3306" REDMINE_DB_PASSWORD = "passwd" REDMINE_DB_USER = "root" REDMINE_DB_NAME = "redmine" } config { image = "redmine:yc" port_map { #指定映射的端口 re = 3000 } } logs { max_files = 10 #日志文件最多数量 max_file_size = 15 #单个日志文件大小 MB单位 } resources { cpu = 500 # 500 MHz #限制服务的cpu,内存,网络 memory = 256 # 256MB network { mbits = 10 port "re" {} #使用上面配置的映射端口 } } service { name = "global-redmine-check" #健康检查 tags = ["global", "redmine"] port = "re" check { name = "alive" type = "tcp" interval = "10s" timeout = "2s" } } } }

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

JSON入门

什么是JSON JSON:JavaScript Object Notation【JavaScript 对象表示法】 JSON 是存储和交换文本信息的语法。类似 XML。 JSON采用完全独立于任何程序语言的文本格式,使JSON成为理想的数据交换语言S 为什么需要JSON 提到JSON,我们就应该和XML来进行对比。XML也是一种存储和交换文本信息的手段。那么JSON好在哪里呢?? JSON 比 XML 更小、更快,更易解析。 javaScript原生支持JSON,解析速度会很快 XML解析成DOM对象的时候,浏览器【IE和fireFox】会有差异 使用JSON会更简单 更加容易创建JavaScript对象 var p = {'city':['北京','上海','广州','深圳']}; for(var i=0;i<p.city.length;i++){ document.write(p.city[i]+"<br/>"); } JSON语法 客户端与服务端的交互数据无非就是两种 数组 对象 于是乎,JSON所表示的数据要么就是对象,要么就是数组 JSON语法是javaScript语法的子集,javaScript用[]中括号来表示数组,用{}大括号来表示对象,JSON亦是如此 JSON数组: var employees = [ { "firstName":"Bill" , "lastName":"Gates" }, { "firstName":"George" , "lastName":"Bush" }, { "firstName":"Thomas" , "lastName": "Carter" } ]; JSON对象 var obj = { age: 20, str: "zhongfucheng", method: function () { alert("我爱学习"); } }; 当然啦,数组可以包含对象,在对象中也可以包含数组 解析JSON javaScript原生支持JSON的,我们可以使用eval()函数来解析JSON,把JSON文本数据转换成一个JavaScript对象。 function test() { //在写JOSN的时候,记得把带上逗号 var txt = "{a:123," + "b:'zhongfucheng'}"; //使用eval解析JSON字符串,需要增添() var aa = eval("(" + txt + ")"); alert(aa); } 效果 不用框架时将JavaBean转成JSON 使用Strus2的时候,Struts2自带了组件能够让JavaBean对象、集合转成是JSON,不用我们自己拼接...这是非常方便的。 使用SpringMVC的时候,SpringMVC也支持将JavaBean转成JSON 但是,我们不一定使用框架来做开发呀。因此,我们还得学习使用第三方库来将JavaBean对象、集合转成JSON 导入开发包 commons-io-2.0.1.jar commons-lang-2.5.jar commons-collections-3.1.jar commons-beanutils-1.7.0.jar ezmorph-1.0.3.jar json-lib-2.1-jdk15.jar 事例代码 package cn.itcast.javaee.js.bean2json; import net.sf.json.JSONArray; import java.util.*; /** * 使用第三方工具,将JavaBean对象/List或Set或Map对象转成JSON * @author AdminTC */ public class TestBean2Json { private static void javabean2json() { City city = new City(1,"广州"); JSONArray jSONArray = JSONArray.fromObject(city); String jsonJAVA = jSONArray.toString(); System.out.println(jsonJAVA); //[{"id":1,"name":"广州"}] } private static void list2json() { List<City> cityList = new ArrayList<City>(); cityList.add(new City(1,"广州")); cityList.add(new City(2,"珠海")); JSONArray jSONArray = JSONArray.fromObject(cityList); String jsonJAVA = jSONArray.toString(); System.out.println(jsonJAVA); //[{"id":1,"name":"广州"},{"id":2,"name":"珠海"}] } private static void set2json() { Set<City> citySet = new LinkedHashSet<City>(); citySet.add(new City(1,"广州")); citySet.add(new City(2,"珠海")); JSONArray jSONArray = JSONArray.fromObject(citySet); String jsonJAVA = jSONArray.toString(); System.out.println(jsonJAVA); //[{"id":1,"name":"广州"},{"id":2,"name":"珠海"}] } private static void javabeanlist2json() { List<City> cityList = new ArrayList<City>(); cityList.add(new City(1,"中山")); cityList.add(new City(2,"佛山")); Province province = new Province(1,"广东",cityList); JSONArray jSONArray = JSONArray.fromObject(province); String jsonJAVA = jSONArray.toString(); System.out.println(jsonJAVA); /* [ { "id":1, "name":"广东" "cityList":[{"id":1,"name":"中山"},{"id":2,"name":"佛山"}], } ] */ } private static void map2json() { List<City> cityList = new ArrayList<City>(); cityList.add(new City(1,"中山")); cityList.add(new City(2,"佛山")); Map<String,Object> map = new LinkedHashMap<String,Object>(); map.put("total",cityList.size());//表示集合的长度 map.put("rows",cityList);//rows表示集合 JSONArray jSONArray = JSONArray.fromObject(map); String jsonJAVA = jSONArray.toString(); System.out.println(jsonJAVA); //[{"total":2,"rows":[{"id":1,"name":"中山"},{"id":2,"name":"佛山"}]}] jsonJAVA = jsonJAVA.substring(1,jsonJAVA.length()-1); System.out.println(jsonJAVA); } } 把要解析成JSON 的javaBena对象、集合放进下面这段代码即可! JSONArray jSONArray = JSONArray.fromObject(map); 无论放进去什么,返回的都是数组 总结 作者:阿笨 官方QQ一群(已满):422315558 官方QQ二群(加入):574187616 个人讲师课堂主页:http://study.163.com/instructor/2544628.htm 个人微信公众号课程主页:http://dwz.cn/ABenNET

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

Python入门

Python 简介 关于Python2.x与3.x的使用 摘自 Python核心编程 第三版 Wesley Chun著 print 变为 print() 默认字符的编码是 Unicode 增加单类 类型 更新异常的语法 更新了整数 迭代无处不在 【基础数据类型】 数值类型 整数 各种进制 0 八 0x 十六 0b 二 浮点数 1.2e2 13.34e-2 复数 3+4j 0.1-0.5j 布尔型 0或0.0 :看成false "" '' :false () [] {} :false 字符串 单引号 双引号: 单行字符串 三引号 多行字符串 空值 None 运算符 算术运算符 加减一样,* 乘,不仅可以用于数字,还可以用于字符串 ,/ 除,和Java不一样,整数相除也会得到浮点数 // 取整除,得到商的整数部分 ,% 取余数 ,** 幂运算 可以用来开根 关系运算符 都是和Java一致 逻辑运算符 and or not 身份运算符 is : a is b 就是比较 id(a) id(b) 相同则是返回1 is not 比较id 不相同返回1 位运算符 << >> 左右移 & |按位与或 ^ ~ 按位异或 按位翻转 算术运算符优先级 ** / // % + // 取整数部分除法 ** 幂运算 转义字符: \a 响铃 \b 退格 backspace \000 空 \f 换页 \ 续行符(行尾) 【基础语法】 单行注释:# 多行注释:”’ ”’ 空行的重要性,代码段之间有空行,Python之禅 【import】 参考博客 关于同级,子级目录是比较方便的,涉及到上级目录的就麻烦点了 【输入输出】 读取命令行参数 参考博客 只有输入参数,没有选项 import sys print("脚本名:", sys.argv[0]) for i in range(1, len(sys.argv)): print("参数", i, sys.argv[i]) python tree.py hi op 顺序是python,第一个参数是文件,之后才是别的参数 结果>> 脚本名 tree.py 参数1 hi 参数2 op 有选项 getopt.getopt(args, options[, long_options]) import sys, getopt opts, args = getopt.getopt(sys.argv[1:], "hi:o:") for op, value in opts: sys.argv[1:]为要处理的参数列表,sys.argv[0]为脚本名,所以用sys.argv[1:]过滤掉脚本名。 "hi:o:": 当一个选项只是表示开关状态时,即后面不带附加参数时,在分析串中写入选项字符。当选项后面是带一个附加参数时,在分析串中写入选项字符同时后面加一个”:”号。 所以”hi:o:”就表示”h”是一个开关选项(单单的-h);”i:”和”o:”则表示后面应该带一个参数。 调用getopt函数。函数返回两个列表:opts和args。opts为分析出的格式信息。args为不属于格式信息的剩余的命令行参数。 opts是一个两元组的列表。每个元素为:(选项串,附加参数)。如果没有附加参数则为空串”。 getopt函数的第三个参数[, long_options]为可选的长选项参数,上面例子中的都为短选项(如-i -o) 长选项格式举例: --version --file=error.txt 让一个脚本同时支持短选项和长选项 getopt.getopt(sys.argv[1:], "hi:o:", ["version", "file="]) 【序列】 序列通用操作(包含:字符串,列表,元组) - ​索引,从左至右:0,1,2...n 从右至左:-1,-2...-n - 切片(截取序列的部分) temp[:] 返回一个副本 - temp[2:4]就是[2,4) - temp[1:]1到最后 temp[-3:] [-3,-1] - temp[:4] [0,4) temp[:-3] [0,-3] - 加:lista+listb 直接连接 - 乘:lista*4 - 判断是否存在:in not int - len() - min() max() sum() 要求元素全是数值 【列表】 元素可包含 字符串,浮点,整型,列表,布尔 操作: 增加 + ,append()/extend()尾部加入元素/列表 insert(index, "") 元素插入到任意位置,其后元素后移 检索 count() in 删除 :del list[2]/ remove("apple") /pop(index) index为空指最后一个 永久性排序:sort() a-z sort(reverse=True) z-a 列表全是字符串才可 临时性排序:sorted() 也可以使用上面的参数 列表全是字符串才可 永久性的逆序列表:reverse() 类似数组的操作,例如声明数组:参考博客 原始的定义就是 lists = [1, 2, 4] 若要定义连续列表 lists = range(0, 100) 得到的是range对象不是列表对象 若要定义大小1000全为0列表 lists = [0 for x in range(0, 1000)] 二维数组的定义: 原始: lists = [[1, 2], [3, 4]] 仿造一维的定义: lists = [[0 for x in range(10)] for y in range(10)] 10*10 初始为0的列表 简便但是不可行的方法: lists = [[0]*10]*10 这是个坑, 只是声明了一维数组,然后多次引用, 虽然看起来是二维, 引用数据就会发现是一维 【元组】 元组和列表类似但是元组是创建不可更改的 和列表相比,相同点:按定义的顺序排序,负索引一致,可以使用分片 不同点:元组使用的是(),不能增加删除元素,没有index方法但是有in,可以在字典中作为键列表不可以, 由于具有写保护,代码安全,操作速度略快列表 操作: 访问: 和列表一样的索引和分片, 连接:+ 连接得到新的元组 删除:del 删除整个元组 【字符串】 str() 将对象转化成字符串 (注:Python中不能像Java一样字符串和数值直接+) repr() 注意和str()的区别 r"d:\python27\" r前缀表示转义字符看成普通字符 因为Python字符串实现是类似字符数组,temp = "python" temp[0] 结果:p temp.index("p") 结果是:0 操作: index('s') 找到s字符的下标 find('s',[start,end]) 找s的下标,只有一个整数参数则是start replace('s','v') 替换 count('sd') 计数 split('') 正则切分 空参数默认是空格 join('') 列表转化成字符串的方法 cmp(str1,str2) 比较两个字符串是否相等 + 进行拼接 可以拼接字符串 列表 a in b 判断a是否在b里存在 * 重复序列 例如 print "-"*20 就会输出20个 - b = "www.github.com" c = b.split(".") "#".join(c) 实现了将字符串的 . 换成了# "i am %s %d" % ("python",67)%s %d %f 和C语言一样占位符 新的方式 "i am {0} {1} ..".format(23,"ret") 或者"i am {name} {age} ..".format(age=23,name="ret") 字典方式 title() 首字母大写 字符串,列表,元组相互转换: - 字符串-列表 : list(“python”) - 字符串-元组:tuple(“python”) - 列表或元组-字符串 join(obj) 参数是列表或元组类型,其元素只能是字符串类型 字符串编码问题(python 2问题): Python 3的bytes/str之别 encode("utf-8"): str -> bytes decode(): bytes -> str # coding:utf-8 unicode_str = unicode('使用',encoding='utf-8') print unicode_str.encode('utf-8') import codecs codecs.open('filename',encoding='utf-8') 因为文件不是UTF8:UnicodeDecodeError: 'utf-8' codec can't decode byte 0xb9 in position 2: invalid start byte 字典(键值对) 通过用空间来换取时间,与列表相比,键的增加不影响查找插入速度,需要占用大量内存 特性: 值是可以是任意的,甚至是字典嵌套 键必须不可变,只能由 数值,字符串,元组,不能用列表 操作: 定义字典 dict={} 添加 : dict['a'] = 2323 返回所有key:keys() 查询是否有这个键 :has_key() get() keys() values() 转化元组并返回 :items() 删除指定键:del() del dict['name'] 删除所有:clear() 删除指定键并返回值 :pop() 合并另一个字典:update() in 嵌套: 字典套列表 {'d':['we','e']} 列表套字典,当成普通类型包含即可 字典套字典 【基本运行结构】 输入输出: input(“”) 默认当成字符串输入 数值:int() 强转一下 print(“”) 选择: if elif else for循环: for in while 例如:for i in range(1,10,2): 范围 [1,10) 增量为2 pass 语句,当某个子句没有任何操作,,用pass保持程序结构完整性 不影响下一句 不像continue while 循环; while True:`` while ‘2’ in nums:`` while num<2: while 列表: 直到列表为空退出循环 if (b==0) and (a==1) : pass print("pass") else: print("Hi") 【函数】 形参赋值传递方式 按位置 就是直接用看起来和Java一样,但不是按类型和位置,只是位置 按指定名称 调用的时候 create(name='df') 缺省默认值(参数缺省之后,调用可以不传这个参数,否则必须要传) def create(name='df') 列表类型,不想形参改变实参 传递副本过去即可 list[:] 以下两种情况(* 和 **),都必须放在形参列表的最后 (两者同时使用时:* 只能在 ** 前 ) 多个实参 create(age, *name) create(12, 's','d') 所以这是名为name的元组 不能指定没有的名称 错误:create(12,d=2, 2,3,4) 多个指定名称实参 create(age, **name) create(12, name='d', lo=23) 必须要指定名称 这是名为name的键值对字典 错误:create(12,d=23,3,3,3) 注意: def hi(name, age=0, *names, **s) hi('d', 23,34, d=6) age会被赋值23 def hi(name, *names, age=0, **s) hi('d', 23,34, d=6) 这样写age就不会赋值,除非指定名称 age=23 返回值 返不返回 看需求 没有像Java一样的强制性约束类型 将函数写在一个py文件里,然后导入 import 文件名,名曰导入模块 还可以加别名 import creat as fun 给模块加别名 导入指定的函数 from create import create_aliens, type_button 多个就,分隔 同理 as给函数加别名 * 通配所有 注意:递归深度,Python中递归默认深度是 989, 要么更改实现,要么就 sys.setrecursionlimit(10000000) 变量 局部变量: 全局变量:定义在函数外的变量,也称公用变量,函数中 global x 声明引用全局变量x 【类】 Python 不存在多态,存在鸭子类型 博客介绍 - 写在一个py文件里,默认构造器,可以加参数 def __init__(self): 属性: 实例属性 形如self.name,在任何方法中声明过即可 类属性 不加self前缀,__name私有的类属性, 类不能访问对象属性 类属性可以修改,但是实际上只能修改实例属性(这个修改只是声明了同名的实例属性,引用的时候就会覆盖类属性,看起来就是修改了 可以删除实例属性,然后就能看到原有的类属性了 class People: name = 'md' p = People() p.name = 'gh' # 声明了实例属性覆盖了类属性 del p.name # 删除实例属性,恢复类属性引用 方法: 对象方法,类方法,静态方法 对象方法,同样的 __开头是私有的,只能在对象的公有方法中self.__引用 静态方法,之中只能引用类成员,不能访问对象成员 构造函数和析构函数: def __init__(self) def __del__(self) class Person: # 对象方法, 将对象作为参数self传进去 def say(self): print('hi') # 静态方法 @staticmethod def drink(): print('static method') # 类方法,将类作为参数cls传进去 @classmethod def eat(cls): print('class method') self 代表了自身引用 类似Java的this 特别不舒服 init 这种命名 不像Java的构造函数重载,这个就是后面覆盖前面定义的init 不管形参列表 因为不存在重载,就是说不能多个构造函数的书写了。。。 导入和函数一样 注意继承中类的依赖 继承 Python是支持多重继承的 同文件 父类定义要在子类之前 父类的构造器不会自动调用,需要显式使用父类构造器: 2.×版本: super(子类名, self).__init__(参数) 3.×版本: super().__init__(参数) 或者 父类名.__init__() 重写父类方法:只需要定义一个和父类方法同名的方法即可,因为没有多态,覆盖时形参不作考虑 多态: 方法重载: 子类覆盖父类的方法 运算符重载: 加__add__(self, x) 减__sub__(self, x) 【异常】 try: print(5/0) except ZeroDivisionError: print("0 不能做除数") else: print("成功") finally: print('finally') 基本语法 try except else finally else是无异常执行 有异常就执行 except, except 超类Exception,也可以多个except (和Java一致) 最终执行finally 和 Java的结构是一致的 except 分句使用形式 说明 except 捕获所有类型 except name 只捕获指定类型 except name, value 捕获指定类型,并获得抛出的异常对象 except (name1, name2) 捕获列出的异常 except (name1, name2), value 捕获列出的异常,获得抛出的异常对象 - raise 语句 和Java的throw关键字 一致 , 不过raise只是抛出一个通用异常类型 Exception - dir(exceptions) 查看所有异常类型 - raise name 手动引发异常 - raise name,data 传递一个附加的数据 - 同样的也是可以自定义异常类型的,class MyExcetion(Exception): - with 语句 在异常处理中,将 try except finally 关键字以及与资源分配释放相关的代码省略掉。 - 文件打开 with open('a.py') as files: 常见异常类 描述 NameError/UnboundLocalError 引用不存在的变量/或者引用在声明之前 ZeroDivisionError 除数为0 SyntaxError 语法错误 IndexError 索引错误 KeyError 使用不存在的字典关键字 IOError 输入输出错误 ValueError 搜索列表中不存在的值 AtrributeError 调用不存在的方法 TypeError 未强制转换就混用数据类型 EOPError 文件结束标识错误 【文件】 注意路径,Windows系统中要使用反斜杠 \ 最简单:file = open('') 只读打开 使用with来操作 好处是Python自动关闭文件 with open('filename') as name: name.read() 为写打开新文本文件只读 file = open('a.txt','w+'[,coding='utf-8']) 打开删空 file.write('') os模块 os.rename('filename1','filename2') mv os.remove('filename.py') rm os.listdir(path) ls os.getcwd() pwd os.makedirs(r'path') mkdir os.chdir('') 改变一个目录 os.rmdir('') 删除该目录,前提是空目录 os.path模块 abspath(”) 获取绝对路径 exists(”) 是否存在 isdir(”) 是否是一个目录 isfile(”) 是否是文件 islink(”) 是否是软链接硬链接文件 getsize() 获取文件尺寸 shutil模块 dir() 复制单个文件 shultil.copytree(r”,r”) 复制目录树 b 表示字节流(二进制文件) 不加表示字符流(文本文件) 方式 意义 当存在 当不存在 r 只读打开 打开 返回空指针 w 只写打开新 打开删空 新建打开 a 追加打开 打开 新建打开 r+ 读打开可写 打开 返回空指针 w+ 写打开新可读 打开删空 新建打开 a+ 追加打开可读 打开 新建打开 rb 只读打开 打开 返回空指针 wb 只写打开新 打开删空 新建打开 ab 追加打开 打开 新建打开 rb+ 读打开可写 打开 返回空指针 wb+ 写打开新可读 打开删空 新建打开 ab+ 追加打开可读 打开 新建打开 json alien = {'color': 'green', 'age': '23'} files = 'a.json' with open(files, 'w') as o: json.dump(alien, o) data = json.load(files) # 引用 data['root']['name'] json.dump()持久化 和 load() 装载 【测试】 文件名test开头就当做是测试类,不会直接运行 类继承 unittest.TestCase, 所有test_开头的方法都将自动运行 断言 self.assertEqual assertNotEquals assertIn(item, list) 直接运行 unittest.main() 输出结果,. 测试通过 E 测试运行错误 F 测试断言不通过 【GUI】 Tkinter 安装 - python2: sudo apt install python-tk - python3: sudo apt install python3-tk 引入 - python2:import Tkinter import Tkinter as tk from Tkinter import * - 但是python3.5的环境下,import tkinter 才是正确的 wxPython Qt5 【数据库】 【MySQL】 python3环境下: sudo apt install python3-mysqldb sudo apt install libmysqlclient-dev sudo pip install mysql-python 【Redis】 安装 python2 sudo pip install redis python3 sudo pip3 install redis 使用 使用的接口方法是和redis一样的 Redis笔记传送门 【绘图】 matplotlib python 3.5 安装 sudo apt install python3-matplotlib sudo apt install python3.5-dev python3.5-tk tk-dev sudo apt install libfreetype6-dev g++ 【代码风格】 一行只写一句 表达式尽量不要省略括号,有助于理解 函数的行数不要超过100行 尽量使用系统函数 尽量使用局部变量,不要使用全局 循环,分支,最好不要超过5层 尽量减少否定的条件语句 对输入的数据进行合法性检查 巨坑: tab和空格不能混用,如果你复制别人的代码是tab,自己敲空格,就会缩进错误!!!!, 天灭tab空格保平安, 要不是kate编辑器显示了tab字符,找半天都不知道错在哪 【常见函数】 id() 查看内存地址 help(方法名) 展示方法的说明文档 dir(对象) 展示对象的方法API 【常见库】 import codecs 编码 import os import time import shlex import datetime import subprocess def execute_command(cmdstring, cwd=None, timeout=None, shell=False): """执行一个SHELL命令 封装了subprocess的Popen方法, 支持超时判断,支持读取stdout和stderr 参数: cwd: 运行命令时更改路径,如果被设定,子进程会直接先更改当前路径到cwd timeout: 超时时间,秒,支持小数,精度0.1秒 shell: 是否通过shell运行 Returns: return_code Raises: Exception: 执行超时""" if shell: cmdstring_list = cmdstring else: cmdstring_list = shlex.split(cmdstring) if timeout: end_time = datetime.datetime.now() + datetime.timedelta(seconds=timeout) #没有指定标准输出和错误输出的管道,因此会打印到屏幕上; sub = subprocess.Popen(cmdstring_list, cwd=cwd, stdin=subprocess.PIPE,shell=shell,bufsize=4096) #subprocess.poll()方法:检查子进程是否结束了,如果结束了,设定并返回码,放在subprocess.returncode变量中 while sub.poll() is None: time.sleep(0.1) if timeout: if end_time <= datetime.datetime.now(): raise Exception("Timeout:%s"%cmdstring) return str(sub.returncode) QT 在Terminal中输入:sudo apt-get install qt4-dev-tools qt4-doc qt4-qtconfig qt4-demos qt4-designer qt4-dev-tools 中包括了Qt Assistant,Qt Linguist,Qt Creator qt4-doc 这个是帮助文档 qt4-qtconfig Qt的配置工具,这个装好默认好 qt4-demos 官方的一些Demo qt4-designer 可视化窗体设置工具

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

Gradle(入门

目录 Gradle 安装配置 SDKMAN方式 Chocolate 命令行选项 守护进程 构建依赖 dependency 常用插件 测试 第一个 build.gradle - 配置Gradle包管理器 Wrapper Gradle进阶知识 Gradle 构建块 task的依赖关系 终结器 task Groovy的POGO类管理配置文件上的版本号 增量式构建特性 task 的inputs 和 outputs 编写和使用自定义task 声明task规则 代码目录结构 Gradle 自动测试 自动化测试理论 测试java应用程序 项目布局,目录树 单元测试 使用JUnit 使用其他框架 TestNG Spock 配置测试执行 打包 War包 Jar包 集成测试 多模块构建 功能测试 Gradle插件 多语言编程 处理javascript 压缩javascript Java 和 Groovy的联合编译 Java 和 Scala Jenkin 使用 下载安装和配置 Gradle 安装配置 SDKMAN方式 先安装sdkman 使用Bash运行curl -s "https://get.sdkman.io" | bash sdk install gradle 即可安装 Chocolate windows 上安装 chocolate PowerShell中运行 wr https://chocolatey.org/install.ps1 -UseBasicParsing | iex 若操作系统默认禁止执行脚本,执行一次set-executionpolicy remotesigned后脚本顺利执行 Chocolatey在安装包的时候,默认路径是按照系统的默认路径来的,如果想修改安装路径可以这样处理: 执行“开始/运行”命令(或者WIN + R),输入“regedit”,打开注册表。 展开注册表到下面的分支[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion],在右侧窗口中找到名为“ProgramFilesDir”的字符串,双击把数值“C:\Program Files”修改为“D:\ProgramFiles”,确定退出后,即可更改常用软件的安装路径了。 命令行选项 gradle 构建文件中的task名: 直接运行task -b,--build-file test.gradle 指定运行脚本文件 --offline 离线模式 -P ,--project-prop:配置参数 -Pmyprop=value -i,--info : 打印info级别的输出 -s,--stacktrace: 输出错误栈 -q,--quiet:减少构建出错时打印的错误信息 tasks : 输出所有建立的task properties : 输出所有可用的配置属性 守护进程 命令加上 --daemon就会开启一个守护进程,只会开启一次, 守护进程会在空闲3小时后销毁 手动关闭 gadle --stop 构建时不采用守护进程 --no--daemon 构建依赖 dependency 和Maven用的是同一种方式 三个基本坐标 本地依赖 compile files('lib/ojdbc-14.jar') 相对的根目录是src同级目录 常用插件 lombok compile 'org.projectlombok:lombok:1.16.16' 测试 凡是依赖于本地环境的测试,使用完就注释Test注解,还有那些会CRUD,影响到数据的测试方法也是 以防以后线上测试通不过 第一个 build.gradle task helloworld{ doLast { printf 'Hello World!' } } 或者是 使用 << 代表doLast: task helloworld<<{ println 'Hello world!' } 运行:gradle -q helloworld 配置Gradle包管理器 Wrapper 在使用IDE生成项目的时候,可以选择gradle的执行目录,可以选gradle wrapper 也可以选自己下载解压的完整包 如果使用的不是这个wrapper,那么别人在下载项目后,运行gradle命令就要先安装gradle,使用wrapper更好 task wrapper(type: Wrapper){ gradleVersion = '1.7' distributionUrl = '限定访问内网的URL' distributionPath = '包装器被解压缩放的相对路径' } 运行 gradle wrapper 一次即可开始使用包装器的脚本来构建项目了 生成gradle包管理器:gradle wrapper --gradle-version 2.0 Gradle进阶知识 Gradle 构建块 三个基本块 project task property, 使用DDD(领域驱动设计) 一个真实的项目包含多个project 而 Project又包含多个task ,task之间通过依赖来确保执行顺序 build.gradle 和 pom.xml 作用是一致的,但是gradle可以使用一份源码 构建出多种想要的目标程序 gradle 也方便构建多模块项目 task的依赖关系 version = '0.1-SNAPSHOT' task first { println 'First Run !' } task second { println 'Second Run !' } task printVersion (dependsOn:[second,first]){ doLast { println "Version : $version" logger.quiet "Version : $version" } } task third <<{ println 'Third Run!' } third.dependsOn('printVersion') 如果把second的定义放在First前面,就会先运行second 这个例子就说明了,被依赖方的运行,不是按照声明的顺序,而是定义的顺序 (因为依赖是只要被依赖方执行即可,和顺序关系不是很大) 还可以使用SLF4J的logger实现 日志级别 DEBUG,ERROR,INFO,TRACE,WARN ,还有QUIET… 如果 是 gradle -b tasksL.gradle -q third 就会运行所有的task,因为这是最后一层依赖 如果 是gradle -b tasksL.gradle -q printVersion 就会只运行 printVersion 如果整个文件有编译错误也是不运行的 终结器 task task f<<{println 'first'} task s<<{println 'second'} f.finalizedBy s //当运行 gradle f 就会自动触发 s //如果gradle s 就和f没有任何关系了 Groovy的POGO类管理配置文件上的版本号 taskL.gradle gradle -b tasksL.gradle -q printVersion 虽然只是 运行了这个task 但是读取文件的task也被自动调用了 因为Gradle的构建生命周期阶段如下: 初始化、配置和执行 读取文件就属于配置阶段 注意 : 项目的每一次构建都会运行属于配置阶段的代码,即使你只是运行了 gradle tasks 增量式构建特性 如果Java源文件与最后一次运行的构建不同的话,运行 compileJava task 将充分提高构建的性能 task 的inputs 和 outputs 流程 : inputs -> |task| -> outputs gradle通过比较两个task的inputs和outputs来决定task是否最新 如果inputs和outputs没有改变 就不会执行该task 输入和输出可以是,一个文件,多个文件,一个目录,一个property属性 示例代码:turnVersion.gradle makeRealeseVersion : 将一个项目的版本切换为发布版本 IOReleaseVersion : 通过inputs/outputs来添加增量式构建支持 发现并不能得到书上的预期效果,书上是说改动了properties文件才会让这个task运行,没有改就会说 up-to-date 但是实际得到的是,改动了properties或者是构建文件都会引起task运行,两者都不改动就不会运行task,而且不会有输出提示up-to-date,要自己手动logger 编写和使用自定义task 自定义task包含两个组件: 自定义的task类,封装了逻辑行为,也被称为任务类型 真实的task 提供了用于配置行为的task类所暴露的属性值 这个task就是做到了改配置文件,确保是RELEASE版本 //先要实例化version属性对象的存在 version = new ProjectVersion(0,1,true) //继承DefaultTask类型的自定义task类 class ReleaseVersionTask extends DefaultTask{ @Input Boolean release @OutputFile File destFile ReleaseVersionTask(){ group = 'versioning' description = 'Make Project a release version' } //task的行为逻辑 @TaskAction void start (){ project.version.release = true; ant.propertyfile(file:destFile){ entry(key:'release',type:'string',operation:'=',value:'true') } println "$project.version" } } //version的POGO类 class ProjectVersion{ Integer major Integer minor Boolean release ProjectVersion (Integer major ,Integer minor){ this.major = major this.minor = minor } ProjectVersion (Integer major ,Integer minor,Boolean release){ this(major,minor) this.release = release } @Override String toString(){ "$major.$minor${release?'-RELEASE':'-SNAPSHOT'}" } } //真实的task,用来操作自定义类暴露的几个属性 //使用命令来运行,本质是运行真实的task但是行为逻辑在自定义类中编写 //gradle -b UserDefineTask.gradle -q makeReleaseVersion //如果要改动一些数据可以直接更改暴露的task而不用去改自定义的task类 task makeReleaseVersion(type:ReleaseVersionTask){ release = 'true' destFile = file('version.properties') } 书上写的不完全,调试要死人 声明task规则 //All used property must define and initial first version = new ProjectVersion(0,1,true) ext.versionFile = file('version.properties') class ProjectVersion{ Integer major Integer minor Boolean release ProjectVersion (Integer major ,Integer minor){ this.major = major this.minor = minor } ProjectVersion (Integer major ,Integer minor,Boolean release){ this(major,minor) this.release = release } @Override String toString(){ "$major.$minor${release?'-RELEASE':'-SNAPSHOT'}" } } // task规则的定义 tasks.addRule("Pattern: increment<Classifier>Version - Increment the project version classifier." ){ //根据预定义模式来检查task的名称 String taskName -> if(taskName.startsWith('increment') && taskName.endsWith('Version')){ //根据符合命名模式的task动态添加一个doLast的方法 task(taskName)<<{ //从完整的task名称中提取类型字符串, //字面意思是将字符串中increment和Version两个串去除掉然后转小写再赋值 String classifier = (taskName - 'increment' - 'Version').toLowerCase() String currentVersion = version.toString() switch (classifier){ case 'major':++version.major break case 'minor':++version.minor break default : throw new GradleException("Invalid version type '$classifier' . Allow types :['Major','Minor']") } String newVersion = version.toString() logger.info "Increment $classifier project version: $currentVersion -> $newVersion" ant.propertyfile(file:versionFile){ entry(key:classifier,type:'int',operation:'+',value:1) } } } } 运行 gradle -b RulesTask.gradle -q incrementMinorVersion就可以增加版本号了,就是一个动态的执行命令的机制 使用 incrementMajorVersion就可以增加主版本号 如果运行 gradle -b RulesTask.gradle -q tasks 就会得到一个具体的tasks的组Rules 代码目录结构 groovy 在以下目录,Java在main.java的目录下,一般别人直接放在src下,buildSrc好像没有普及使用 - build.gradle - buildSrc - src - main - groovy - com - myth - test - ProjectVersion.groovy - java - src - version.properties 测试优于业务逻辑实行 Gradle 自动测试 自动化测试理论 测试java应用程序 项目布局,目录树 单元测试 使用JUnit 使用其他框架 TestNG Spock 配置测试执行 打包 War包 Jar包 Gradle默认是只会打包源码,并不会打包依赖(为了更方便依赖的作用) shadow插件官网文档 集成测试 多模块构建 树级结构的多模块项目就这样配置 - RedisClient - Core - Website rootProject.name = 'RedisClient' include 'Core','Website' 如果只是同级的目录,就直接新建,无需配置,引用类时添加下依赖即可,但是这样只能运行,不能打包构建 有关多模块的构建详情参考这里 参考更为规范的多项目构建 统一一个文件管理依赖 依赖另一个模块的代码 compile project(":redis_core") 功能测试 Gradle插件 shadowJar 多语言编程 处理javascript 压缩javascript 调用Google Closure Compiler 的task 来压缩javascript文件 将所有的javascript压缩成一个javascript文件 执行该task gradle :web :taskname 执行之后就能得到一个优化的js文件,现在就要在页面中修改原来的js引用 Java 和 Groovy的联合编译 src 下 main 下 java 和groovy 的一个目录结构,直接编译就会发生Java无法依赖groovy的类 错误:需要配置 sourceSets.main.java.srcDirs=[] sourceSets.main.groovy.srcDirs=['src/main/java','src/main/groovy'] 正确: sourceSets.main.java.srcDirs=['src/main/java','src/main/groovy'] 上面的会报错 配置好后就能把groovy当普通Java类直接使用了 Java 和 Scala 联合双向编译 Java和scala sourceSets.main.scala.srcDirs sourceSets.main.groovy.srcDirs=['src/main/java','src/main/scala'] 那么问题来了,如果是有了java groovy scala 呢怎么配置编译,直接就加上就好了嘛? Jenkin 使用 下载安装和配置 官网下载war包后,直接使用Java命令运行 或者放在web容器中运行 配置下载插件(位置在C盘用户目录下, 其实第一次运行后也是会解压在.jenkin 目录下 插件就在plugin目录下)

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

Docker 入门

什么是容器: 容器技术已经成为应用程序封装和交付的核心技术 容器技术的核心有以下几个内核技术组成: — CGroups( Control Groups ) - 资源管理 — NameSpace - 进程隔离 — SELinux 安全 由于是物理机上实施隔离,启动一个容器,可以想启动一个进程一样快速 什么是Docker: Docker是完整的一套容器管理系统 Docker提供了一组命令,让用户更加方便直接地使用容器技术,而不需要过多关心底层内核技术 Docker优点: 相比与传统的虚拟化技术,容器更加简洁高效 传统虚拟机器要给每个VM安装操作系统 容器使用的共享公共库和程序 Docker的缺点 容器的隔离性没有虚拟化强 共用Linux内核,安全性有先天缺陷 SELinux难以驾驭 监控容器和容器排错是挑战 部署Docker Ubuntu 系列安装 Docker Docker支持版本: UbuntuXenial16.04(LTS) UbuntuWily15.10 UbuntuTrusty14.04(LTS) UbuntuPrecise12.04(LTS) Docker目前只能安装在64位平台上,并且要求内核版本不低于3.10,实际上内核越新越好,过低的内核版本容易造成功能的不稳定。 用户可以通过如下命令检查自己的内存版本信息 $uname -a $cat /proc/version 更新APT镜像源 首先需要安装 apt-transport-https 包支持 https协议的源 $sudo apt-getinstall apt-transport-https ca-certificates 添加源的 gpg 密钥 $sudo apt-keyadv--keyserver hkp://p80.pool.sks-keyservers.net 获取当前操作系统的代号 $ lsb_release -c Codename:trusty 添加 Docker 的官方 apt 软件源了。 $ sudo cat <<EOF > /etc/apt/sources.list.d/docker.list debhttps://apt.dockerproject.org/repoubuntu-trustymain EOF 添加成功后,更新apt软件包缓存。 $ sudo apt-get update 分版本的预安装任务 高于 12.04 LTS的版本 $ sudo apt-get install-y linux-image-extra-$(uname -r) $ sudo apt-get install apparmor 12.04 LTS版本 $sudo apt-get install linux-image-generic-lts-trusty 安装Docker $sudo apt-getinstall -ydocker-engine CentOS 系列安装Docker 要添加yum 软件源 $sudo cat > /etc/yum.repos.d/docker.repo<<-'EOF' [dockerrepo] name=DockerRepository baseurl=https://yum.dockerproject.org/repo/main/centos/$releasever/ enabled=1 gpgcheck=0 EOF 使用yum 安装docker-engine $ sudo yum install -y install docker-engine Debian操作系统安装Docker 支持版本 Debiantestingstretch(64-bit) Debian8.0Jessie(64-bit) Debian7.7Wheezy(64-bit) 更新APT仓库 1. 清理旧的仓库信息 $apt-getpurgelxc-docker* $apt-getpurgedocker.io* 2. 更新和安装软件包 $apt-getupdate $apt-getinstallapt-transport-httpsca-certificates 3. 添加 GPG 键 $ apt-keyadv--keyserverhkp://p80.pool.sks-keyservers.net:80 --recv-keys58118E89F3A912897C070ADBF76221572C52609D 4. 添加 APT 源以Debian Jessie 为例 $sudo cat<<EOF> /etc/apt/sources.list.d/docker.list deb https://apt.dockerproject.org/repodebian-jessie main EOF 其他两个版本 deb https://apt.dockerproject.org/repo debian-wheezy main deb https://apt.dockerproject.org/repo debian-stretch main 安装Docker $sudo apt-get install docker-engine 为非 root 用户授权 #如果没有就建立一个 Docker 组 $sudo groupadd docker #增加一个用户(用真实的名字替换下面的 ${USER})到 Docker 组,需重登陆来生效 $sudo gpasswd -a ${USER}docker #重启 Docker 服务 $sudo service docker restart 更新 Docker $apt-get upgrade docker-engine 卸载 Docker #卸载软件包 $sudo apt-get purge docker-engine #卸载依赖包 $sudo apt-get autoremove --purge docker-engine #如有必要,执行以下命令,删除全部镜像、容器、数据卷和其他docker相关用户信息 : $rm -rf /var/lib/docker 下面使用 CentOS 7 系统介绍Docker: 把软件 docker-engine docker-engine-selinux 拷贝到私有yum仓库中 运行 createrepo . # yum -y install -ydocker-engine docker-engine-selinux 启动docker时 最好要将iptables 的规则清空 iptable有的规则可能会影响Docker 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 #brctlshow bridgename bridge id STPenabled interfaces #iptables-save // 设置开机启动,启动docker服务 #systemctlenabledocker #systemctlstartdocker #brctlshow bridgename bridge id STPenabled interfaces docker0 8000.02424ba34d68 no #iptables-save #Generatedbyiptables-savev1.4.21onSunJan2122:48:112018 *nat :PREROUTINGACCEPT[0:0] :INPUTACCEPT[0:0] :OUTPUTACCEPT[2:262] :POSTROUTINGACCEPT[2:262] :DOCKER-[0:0] -APREROUTING-maddrtype--dst- type LOCAL-jDOCKER -AOUTPUT!-d127.0.0.0 /8 -maddrtype--dst- type LOCAL-jDOCKER -APOSTROUTING-s172.17.0.0 /16 !-odocker0-jMASQUERADE -ADOCKER-idocker0-jRETURN COMMIT #CompletedonSunJan2122:48:112018 #Generatedbyiptables-savev1.4.21onSunJan2122:48:112018 *filter :INPUTACCEPT[27:3069] :FORWARDACCEPT[0:0] :OUTPUTACCEPT[20:3101] :DOCKER-[0:0] :DOCKER-ISOLATION-[0:0] -AFORWARD-jDOCKER-ISOLATION -AFORWARD-odocker0-jDOCKER -AFORWARD-odocker0-mconntrack--ctstateRELATED,ESTABLISHED-jACCEPT -AFORWARD-idocker0!-odocker0-jACCEPT -AFORWARD-idocker0-odocker0-jACCEPT -ADOCKER-ISOLATION-jRETURN COMMIT #CompletedonSunJan2122:48:112018 #dockerversion Client: Version:1.12.1 APIversion:1.24 Goversion:go1.6.3 Gitcommit:23cf638 Built: OS /Arch :linux /amd64 Server: Version:1.12.1 APIversion:1.24 Goversion:go1.6.3 Gitcommit:23cf638 Built: OS /Arch :linux /amd64 Docker 镜像: Docker 运行容器前需要本地存在对应的镜像,如果镜像不存在本地,Docker会从镜像仓库下载( 默认是Docker Hub 公共注册服务器中的仓库 ) 查看系统镜像 docker images 从官方源搜索镜像 (前提 物理机可以连通外网) docker search 镜像名 下载镜像 docker pull 镜像名 上传镜像 docker push 镜像名 删除本地镜像 docker rmi 镜像名 把本机镜像备份为 tar 包 docker save 镜像名 > 镜像名.tar 把备份的 tar 包导入到本地镜像 docker load < 镜像名.tar 查看镜像制作历史 docker history 查看镜像底层信息 docker inspect 修改镜像名称和标签 docker tag 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 这里用busybox练习 #dockerimages REPOSITORYTAGIMAGEIDCREATEDSIZE #dockersearchbusybox #dockerpullbusybox #dockerimages REPOSITORYTAGIMAGEIDCREATEDSIZE busyboxlatestf9b6f7f7b9d36daysago1.143MB 在列出的信息中可以看到几个字段信息 来自于哪个仓库,比如busybox 镜像标记,比如latest 它的ID号唯一 创建时间 镜像大小 #dockersavebusybox>busybox.tar #lsbusybox.tar busybox. tar #dockerrmibusybox #dockerload<busybox.tar 779f37a09c89:Loadinglayer1.355MB /1 .355MB Loadedimage:busybox:latest #dockerimages REPOSITORYTAGIMAGEIDCREATEDSIZE busyboxlatestf9b6f7f7b9d36daysago1.143MB #dockerhistorybusybox IMAGECREATEDCREATEDBYSIZECOMMENT f9b6f7f7b9d36daysago /bin/sh -c #(nop)CMD["sh"]0B <missing>6daysago /bin/sh -c #(nop)ADDfile:3e663b99b5cb5600101.143MB 镜像的实现原理 Docker 使用Union FS 将这些不同的层结合到一个镜像中去。 通常 Union FS 有两个用途, 一方面可以实现不借助 LVM、RAID 将多个 disk 挂到同一个目录下,另一个更常用的就是将一个只读的分支和一个可写的分支联合在一起,LiveCD正是基于此方法可以允许在镜像不变的基础上允许用户在其上进行一些写操作。 Docker 在 AUFS上构建的容器也是利用了类似的原理。 Docker 容器: 容器是独立运行的一个或一组应用,以及它们的运行态环境。 对应的虚拟机可以理解为模拟运行的一整套操作系统(提供了运行态环境和其他系统环境)和跑在上面的应用。 容器常用命令列表 –docker run //运行容器 – docker ps //查看容器列表 – docker stop //关闭容器 – docker start //启动容器 – docker restart //重启容器 – docker attach|exec //进入容器 – docker inspect //查看容器底层信息 – docker top //查看容器进程列表 – docker rm //删除容器 启动容器 启动容器有两种方式,一种是基于镜像新建一个容器并启动,另外一个是将在终止状态的容器重新启动. 新建并启动 命令主要为docker run 1 2 3 4 5 6 7 8 9 10 11 12 13 14 例如下面命令输出一个 'Helloworld' 之后终止容器 #dockerruncentos/bin/echo'Helloworld' Helloworld 下面的命令则启动一个 bash 终端,允许用户进行交互。 #dockerrun-itcentos/bin/bash [root@b45c34328e05/] #echoHelloworld Helloworld [root@b45c34328e05/] #ls anaconda-post.logdevhomelib64mediaoptrootsbinsysusr binetcliblost+foundmntprocrunsrvtmpvar [root@b45c34328e05/] #exit exit -t选项让Docker分配一个伪终端并绑定到容器的标准输入上 -i选项则让容器的标准输入保持打开 启动已终止容器 可以利用 docker start 命令 直接将一个已经终止的容器启动运行 1 2 3 4 5 6 7 8 9 10 使用docker ps 命令查看容器信息 终止状态的容器可以用docker ps -a看到 #dockerps-a CONTAINERIDIMAGECOMMANDCREATEDSTATUSPORTSNAMES b45c34328e05centos "/bin/bash" 47secondsagoExited(0)40secondsagosharp_carson #dockerstartb45c34328e05 b45c34328e05 #dockerps CONTAINERIDIMAGECOMMANDCREATEDSTATUSPORTSNAMES b45c34328e05centos "/bin/bash" AboutaminuteagoUp5secondssharp_carson 后台运行 需要让Docker在后台运行而不是直接把执行命令的结果输出在当前宿主机下 可以docker run 添加 -d 参数来实现 启动后会返回唯一的 id 1 2 3 4 5 6 7 8 9 10 #dockerrun-dcentos/bin/sh-c"whiletrue;doechohelloworld;sleep1;done" 3a5f25a937544c37c10c37443c848d0c818859995cf74232c16d04f25c5ec932 #dockerlogs3a5f//可以通过简写id使用dockerlogs命令获取容器的输出信息 helloworld helloworld helloworld helloworld #dockerps//查看容器信息 CONTAINERIDIMAGECOMMANDCREATEDSTATUSPORTSNAMES 3a5f25a93754centos "/bin/sh-c'whiletr" AboutaminuteagoUpAboutaminutehappy_goldstine 终止容器 可以使用 docker stop 来终止一个运行中的容器 当Docker 容器中指定的应用终结时,容器也自动终止,用户通过exit 命令 或者 Ctrl + d 来退出终端时,所创建的容器立刻终止。 1 2 3 4 5 6 7 8 9 10 11 12 13 #dockerstop3a5f 3a5f #dockerps CONTAINERIDIMAGECOMMANDCREATEDSTATUSPORTSNAMES b45c34328e05centos "/bin/bash" 45minutesagoUp44minutessharp_carson #dockerps-a CONTAINERIDIMAGECOMMANDCREATEDSTATUSPORTSNAMES 3a5f25a93754centos "/bin/sh-c'whiletr" 15minutesagoExited(137)42secondsagohappy_goldstine #dockerrestart3a5f 3a5f #dockerps CONTAINERIDIMAGECOMMANDCREATEDSTATUSPORTSNAMES 3a5f25a93754centos "/bin/sh-c'whiletr" 16minutesagoUp4secondshappy_goldstine 此外,docker restart 命令会将一个运行态的容器终止,然后再重新启动它 进入容器 在使用 -d 参数时,容器启动会进入后台。某些时候需要进入容器进行操作 attach 命令 1 2 3 4 5 6 7 8 9 10 11 12 13 14 #dockerrun-idtcentos 7cc5abd320d6e67cc8df2388e840bb168715afd3331364514be91e42be0d7304 #dockerps CONTAINERIDIMAGECOMMANDCREATEDSTATUSPORTSNAMES 7cc5abd320d6centos "/bin/bash" 7secondsagoUp4secondshigh_lamarr #dockerattach7cc [root@7cc5abd320d6/] # [root@7cc5abd320d6/] #exit exit #dockerps CONTAINERIDIMAGECOMMANDCREATEDSTATUSPORTSNAMES #dockerps-a CONTAINERIDIMAGECOMMANDCREATEDSTATUSPORTSNAMES 7cc5abd320d6centos "/bin/bash" 3minutesagoExited(0)13secondsagohigh_lamarr 但是使用 attach 命令有时候并不方便。当多个窗口同时 attach 到同一个容器的时候,所有窗口都会同步显示。当某个窗口因命令阻塞时,其他窗口也无法执操作了。exit 会导致容器关闭 exec 命令 进入容器,退出时不会关闭容器 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 #dockerrun-idtcentos f433775528d9616212145b73cc10a04b5b8c0f383c9cd002fe1f6dc984462313 #dockerps CONTAINERIDIMAGECOMMANDCREATEDSTATUSPORTSNAMES f433775528d9centos "/bin/bash" 7secondsagoUp5secondsberserk_bassi #dockerexec-itf4/bin/bash [root@f433775528d9/] # [root@f433775528d9/] #exit exit #dockerps CONTAINERIDIMAGECOMMANDCREATEDSTATUSPORTSNAMES f433775528d9centos "/bin/bash" 3minutesagoUp3minutesberserk_bassi -i,-t,-d参数 -i选项则让容器的标准输入保持打开 -t选项让Docker分配一个伪终端并绑定到容器的标准输入上 -d选项在后台执行一个进程。可以看出,如果一个命令需要长时间进程,使用-d参数会很快返回。 #dockerexec-if4/bin/bash date TueJan2312:15:21UTC2018 echo $? 0 exit #dockerexec-tf4/bin/bash [root@f433775528d9/] #date ^C #dockerexec-itf4/bin/bash [root@f433775528d9/] #date TueJan2312:18:21UTC2018 [root@f433775528d9/] #exit exit 删除容器 可以使用 docker rm 来删除一个处于终止状态的容器 1 2 3 4 5 6 7 8 9 10 #dockerps-a CONTAINERIDIMAGECOMMANDCREATEDSTATUSPORTSNAMES f433775528d9centos "/bin/bash" 29minutesagoUp29minutesberserk_bassi 7cc5abd320d6centos "/bin/bash" 34minutesagoExited(0)32minutesagohigh_lamarr #dockerrm7cc 7cc #dockerrmf43 Errorresponsefromdaemon:Youcannotremovearunningcontainerf433775528d9616212145b73cc10a04b5b8c0f383c9cd002fe1f6dc984462313.Stopthecontainerbeforeattemptingremovaloruse-f #dockerrm-ff43 f43 如果要删除一个运行中的容器,可以添加 -f 参数 清理所有处于终止状态的容器 如果数量太多要一个个删除可能会很麻烦,用 docker rm $( docker ps -aq ) 可以全部处理掉 自定义镜像 docker commit • 使用镜像启动容器,在该容器基础上修改 • 另存为另一个镜像 案例 1 基于centos镜像使用commit创建新的镜像文件 配置yum源 安装基础工具 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 #dockerrun-itcentos [root@7ffa443a9898/] #rm-rf/etc/yum.repos.d/C* [root@7ffa443a9898/] #cat>/etc/yum.repos.d/yum.repo<<EOF >[yum] >name=yum >baseurl=http: //192 .168.4.254 /rhel7 >gpgcheck=0 >EOF [root@7ffa443a9898/] #yumrepolist Loadedplugins:fastestmirror,ovl Loadingmirrorspeedsfromcachedhostfile repo id reponamestatus yumyum4620 repolist:4620 [root@7ffa443a9898/] #yumprovidesifconfig Loadedplugins:fastestmirror,ovl Loadingmirrorspeedsfromcachedhostfile yum /filelists_db |3.2MB00:00 net-tools-2.0-0.17.20131004git.el7.x86_64:Basicnetworkingtools Repo:yum Matchedfrom: Filename: /sbin/ifconfig [root@7ffa443a9898/] #yum-yinstallnet-tools-2.0-0.17.20131004git.el7.x86_64 [root@7ffa443a9898/] #yumprovidesvim Loadedplugins:fastestmirror,ovl Loadingmirrorspeedsfromcachedhostfile 2:vim-enhanced-7.4.160-1.el7.x86_64:AversionoftheVIMeditor which includes :recentenhancements Repo:yum Matchedfrom: Provides:vim=7.4.160-1.el7 [root@7ffa443a9898/] #yum-yinstallvim [root@7ffa443a9898/] #exit exit #dockerps-qa 7ffa443a9898 #dockercommit7ffa443a9898myos:latest//自定义镜像文件 sha256:d2b307795b544d9ee7529dea3ebdcd5028036ed05ceefbcd02c901ef56ad3318 #dockerimages|grepmyos myoslatestd2b307795b5450secondsago386MB #dockerrun-itmyos//运行自定义镜像文件 [root@54649cf632cc/] #yumrepolist Loadedplugins:fastestmirror,ovl Loadingmirrorspeedsfromcachedhostfile repo id reponamestatus yumyum4620 repolist:4620 使用Dockerfile 自定义镜像 • Dockerfile语法格式 – FROM:基础镜像 – MAINTAINER:镜像创建者信息 – EXPOSE:开放的端口 – ENV:设置变量 – ADD:复制文件到镜像 – RUN:制作镜像时执行的命令,可以有多个 – WORKDIR:定义容器默认工作目录 – CMD:容器启动时执行的命令,仅可以有一条CMD 案例2 基于centos镜像使用Dockerfile文件创建新的镜像文件 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 #mkdirtest #cdtest/ #cp/etc/yum.repos.d/yum.repoyum.repo #vimDockerfile FROMcentos RUN rm -rf /etc/yum .repos.d/* ADDyum.repo /etc/yum .repos.d /yum .repo RUNyum-y install net-toolspsmiscvimiproute CMD[ "/bin/bash" ] #dockerbuild-tmyos:test. #dockerrun-itdmyos:test 4535d05df622a60d14ee995cf2a7a53d75dd480a96c2f921cde027d6f1797f55 #dockerexec-it4535/bin/bash [root@4535d05df622/] #yumrepolist Loadedplugins:fastestmirror,ovl Loadingmirrorspeedsfromcachedhostfile repo id reponamestatus dockerdocker2 yumyum4620 repolist:4622 案例3 基于刚刚建立myos:test 镜像 创建 部署Apache 服务 镜像 1 2 3 4 5 6 7 8 9 10 11 12 #mkdirhttpd #cdhttpd/ #vimDockerfile FROMmyos: test RUNyum-y install httpd ADDindex.html /var/www/html/index .html ENVEnvironmentFile= /etc/sysconfig/httpd CMD[ "/usr/sbin/httpd" , "-DFOREGROUND" ] #dockerbuild-tmyos:httpd. #dockerrun-d-p80:80myos:httpd #curlhttp://192.168.4.1 helloworld 案例4 基于刚刚建立myos:test 镜像 创建 部署sshd服务 镜像 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 #mkdirssh #cdssh/ #vimDockerfile FROMmyos: test RUNyum-y install openssh-server ENVEnvironmentFile= /etc/sysconfig/sshd RUN /usr/sbin/sshd-keygen &> /dev/null RUN echo '123' | passwd --stdinroot EXPOSE22 CMD[ "/usr/sbin/sshd" , "-D" ] #dockerbuild-tmyos:sshd. #dockerrun-d-p222:22myos:sshd #ssh-X-p222root@192.168.4.1 Theauthenticityofhost '[192.168.4.1]:222([192.168.4.1]:222)' can'tbeestablished. ECDSAkeyfingerprintis7d:c1:ca:40:0d:1d:c4:78:9c:0a:e1:1b:5d:b9:30:60. Areyousureyouwantto continue connecting( yes /no )? yes Warning:Permanentlyadded '[192.168.4.1]:222' (ECDSA)tothelistofknownhosts. root@192.168.4.1'spassword: X11forwardingrequestfailedonchannel0 [root@015c6cab3064~] # 案例5 基于刚刚建立myos:test 镜像 创建 部署 同时使用 ssh 和apache 服务镜像# mkdir httpdandssh 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 #cdhttpdandssh/ #vimstart.sh #!/bin/bash EnvironmentFile= /etc/sysconfig/sshd /usr/sbin/sshd -D& EnvironmentFile= /etc/sysconfig/httpd /usr/sbin/httpd -DFOREGROUND& wait #vimDockerfile FROMmyos: test RUNyum-y install openssh-serverhttpd ADDindex.html /var/www/html/index .html RUN /usr/sbin/sshd-keygen &> /dev/null RUN echo '123' | passwd --stdinroot ADDstart.sh /etc/init .d /start .sh RUN chmod 755 /etc/init .d /start .sh EXPOSE2280 CMD[ "/etc/init.d/start.sh" ] #cp../httpd/index.htmlindex.html #dockerbuild-thttpd:sshd. #dockerrun-d-p222:22-p80:80httpd:sshd #curlhttp://192.168.4.1 helloworld #ssh-X-p222root@192.168.4.1 Theauthenticityofhost '[192.168.4.1]:222([192.168.4.1]:222)' can'tbeestablished. ECDSAkeyfingerprintis29:cf:ac:95:4d:d7:2b:36:10:d1:e9:c6:31:7e:72:c7. Areyousureyouwantto continue connecting( yes /no )? yes Warning:Permanentlyadded '[192.168.4.1]:222' (ECDSA)tothelistofknownhosts. root@192.168.4.1'spassword: X11forwardingrequestfailedonchannel0 [root@f072715497ba~] #exit logout Connectionto192.168.4.1closed. Docker 仓库 仓库(Repository)是集中存放镜像的地方。 注册服务器 registry 基础概念 共享镜像的一台服务器(镜像化的一台服务器) Docker Hub 目前 Docker 官方维护了一个公共仓库 Docker Hub,其中已经包括了超过 15,000的镜像。大部分需求,都可以通过在Docker Hub 中直接下载镜像来实现。 登录 可以通过执行docker login 命令来输入用户名、密码和邮箱来完成注册和登录。注册成功后,本地用户目录的 .dockercfg中将保存用户的认证信息。 基本操作 用户无需登录即可通过docker search 命令来查找官方仓库中的镜像,并利用dockerpull 命令来将它下载到本地。 私有仓库 有时候使用Docker Hub 这样的公共仓库可能不方便,用户可以创建一个本地仓库供私人使用。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 #vim/etc/docker/daemon.json #cat/etc/docker/daemon.json { "insecure-registries" :[ "192.168.4.1:5000" ] } #systemctlrestartdocker 在安装了Docker后,可以通过获取官方registry镜像来运行 #dockerrun-id-p5000:5000registry 创建好私有仓库之后,就可以使用dockertag来标记一个镜像,然后推送它到仓库,别的机器上就可以下载下来了。 例如私有仓库地址为192.168.4.1:5000 #dockertagbusybox:latest192.168.4.1:5000/busybox #dockertagmyos:test192.168.4.1:5000/myos_test #dockertaghttpd:sshd192.168.4.1:5000/httpd_sshd 使用dockerpush 上传标记的镜像 #dockerpush192.168.4.1:5000/busybox Thepushreferstoarepository[192.168.4.1:5000 /busybox ] 779f37a09c89:Pushed latest:digest:sha256:4efd5033df5ddf3cff692505ae2a8e6d492014dbadd2f7281ccda9f744d41901size:527 #dockerpush192.168.4.1:5000/myos_test Thepushreferstoarepository[192.168.4.1:5000 /myos_test ] 8202e413fce3:Pushed 0d281e60bd3c:Pushed b41d6696cce4:Pushed 0aeb287b1ba9:Pushed latest:digest:sha256:860417d703ab3dce337a7f69ccaa417b67842729114d9f34f3760525e4e8a604size:1155 #dockerpush192.168.4.1:5000/httpd_sshd Thepushreferstoarepository[192.168.4.1:5000 /httpd_sshd ] 67de9bddfeb9:Pushed 7ed802e5e1cf:Pushed 7fa005843c99:Pushed c68f5228f676:Pushed 0b433cb3a604:Pushed 1e0fef9107ab:Pushed 8202e413fce3:Mountedfrommyos_test 0d281e60bd3c:Mountedfrommyos_test b41d6696cce4:Mountedfrommyos_test 0aeb287b1ba9:Mountedfrommyos_test latest:digest:sha256:5ac74ff037126e46123abe22ce81b56879e9b916e191809303b9efedacf6d85dsize:2403 用curl查看仓库中的镜像。 #curl-XGET"http://192.168.4.1:5000/v2/_catalog" { "repositories" :[ "busybox" , "httpd_sshd" , "myos_test" ]} #curl-XGET"http://192.168.4.1:5000/v2/busybox/tags/list" { "name" : "busybox" , "tags" :[ "latest" ]} #curl-XGET"http://192.168.4.1:5000/v2/httpd_sshd/tags/list" { "name" : "httpd_sshd" , "tags" :[ "latest" ]} 使用启动仓库中的镜像 #dockerrun-it192.168.4.1:5000/busybox / # / # / # 本文转自 Xuenqlve 51CTO博客,原文链接:http://blog.51cto.com/13558754/2064405,如需转载请自行联系原作者

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

Ansible入门

Ansible简介 ansible是新出现的自动化运维工具,基于Python开发,集合了众多运维工具(puppet、cfengine、chef、func、fabric)的优点,实现了批量系统配置、批量程序部署、批量运行命令等功能。ansible是基于模块工作的,本身没有批量部署的能力。真正具有批量部署的是ansible所运行的模块,ansible只是提供一种框架。主要包括: (1)、连接插件connection plugins:负责和被监控端实现通信; (2)、host inventory:指定操作的主机,是一个配置文件里面定义监控的主机; (3)、各种模块核心模块、command模块、自定义模块; (4)、借助于插件完成记录日志邮件等功能; (5)、playbook:剧本执行多个任务时,非必需可以让节点一次性运行多个任务。 通过Apt (Ubuntu)安装最新发布版本 root@storage:~# apt-add-repository ppa:ansible/ansible Ansible is a radically simple IT automation platform that makes your applications and systems easier to deploy. Avoid writing scripts or custom code to deploy and update your applications— automate in a language that approaches plain English, using SSH, with no agents to install on remote systems. http://ansible.com/ More info: https://launchpad.net/~ansible/+archive/ubuntu/ansible Press [ENTER] to continue or ctrl-c to cancel adding it gpg: keyring `/tmp/tmpi636boen/secring.gpg' created gpg: keyring `/tmp/tmpi636boen/pubring.gpg' created gpg: requesting key 7BB9C367 from hkp server keyserver.ubuntu.com gpg: /tmp/tmpi636boen/trustdb.gpg: trustdb created gpg: key 7BB9C367: public key "Launchpad PPA for Ansible, Inc." imported gpg: Total number processed: 1 gpg: imported: 1 (RSA: 1) OK root@storage:~# apt-get update -y root@storage:~# apt-get install ansible -y 配置 无密码访问 root@storage:/etc/ansible# ssh-keygen -t rsa Generating public/private rsa key pair. Enter file in which to save the key (/root/.ssh/id_rsa): Enter passphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved in /root/.ssh/id_rsa. Your public key has been saved in /root/.ssh/id_rsa.pub. The key fingerprint is: SHA256:rSrNWrBMLzr7gUUqVZZUQU+bUYiVVoqev37/r3Xfmck root@storage The key's randomart image is: +---[RSA 2048]----+ | .+++++=o | | o. .++= | | . . ..= | | . o . . . | |. . + o S . | | . = + . . | | . =oo o o| | ...+o. .. ..B| | o+oo..o. ...oE+| +----[SHA256]-----+ root@storage:/etc/ansible# ssh-copy-id 192.168.13.143 root@storage:/etc/ansible# ssh-copy-id 192.168.13.144 root@storage:~# vim /etc/ansible/hosts 192.168.13.143 192.168.13.144 [openstack] #主机组:openstack 192.168.13.30 192.168.13.33 192.168.13.45 简单测试1 root@storage:~# ansible all -m ping 192.168.13.143 | SUCCESS => { "changed": false, "ping": "pong" } 192.168.13.144 | SUCCESS => { "changed": false, "ping": "pong" } 简单测试2 root@storage:~# ansible all -m command -a 'uptime' 192.168.13.144 | SUCCESS | rc=0 >> 07:39:00 up 6:02, 2 users, load average: 0.00, 0.00, 0.00 192.168.13.143 | SUCCESS | rc=0 >> 07:39:00 up 5:58, 2 users, load average: 0.06, 0.03, 0.01 root@storage:~# ansible openstack -m command -a 'uptime' 192.168.13.33 | SUCCESS | rc=0 >> 15:43:18 up 4 days, 1:38, 1 user, load average: 0.30, 0.26, 0.30 192.168.13.45 | SUCCESS | rc=0 >> 15:43:27 up 13 days, 1:08, 1 user, load average: 0.12, 0.08, 0.08 192.168.13.30 | SUCCESS | rc=0 >> 15:43:27 up 26 days, 1:39, 2 users, load average: 10.40, 10.49, 10.24 root@storage:~# 常用模块介绍 1、setup:用来查看远程主机的一些基本信息 root@storage:~# ansible openstack -m setup |more 2、ping:用来测试远程主机的运行状态 root@storage:~# ansible openstack -m ping 3、file:设置文件的属性 file选项如下: force:需要在两种情况下强制创建软链接,一种是源文件不存在,但之后会建立的情况下;另一种是目标软链接已存在,需要先取消之前的软链,然后创建新的软链,有两个选项:yes|no group:定义文件/目录的属组 mode:定义文件/目录的权限 owner:定义文件/目录的属主 path:必选项,定义文件/目录的路径 recurse:递归设置文件的属性,只对目录有效 src:被链接的源文件路径,只应用于state=link的情况 dest:被链接到的路径,只应用于state=link的情况 state: directory:如果目录不存在,就创建目录 file:即使文件不存在,也不会被创建 link:创建软链接 hard:创建硬链接 touch:如果文件不存在,则会创建一个新的文件,如果文件或目录已存在,则更新其最后修改时间 absent:删除目录、文件或者取消链接文件 root@storage:# ansible openstack -m file -a 'src=/etc/resolv.conf dest=/home/resolv.conf state=link' 192.168.13.33 | SUCCESS => { "changed": true, "dest": "/home/resolv.conf", "gid": 0, "group": "root", "mode": "0777", "owner": "root", "size": 16, "src": "/etc/resolv.conf", "state": "link", "uid": 0 } 查看执行结果:-m command 在远端执行命令 root@storage:~# ansible openstack -m command -a 'ls /home' root@storage:~# ansible openstack -m command -a 'ls /home' 192.168.13.33 | SUCCESS | rc=0 >> andy resolv.conf root@storage:~# ansible openstack -m file -a 'path=/home/resolv.conf state=absent' root@storage:~# ansible openstack -m file -a 'path=/home/resolv.conf state=absent' 192.168.13.45 | SUCCESS => { "changed": true, "path": "/home/resolv.conf", "state": "absent" } 4、copy:复制文件到远程主机 相关选项如下: backup:在覆盖之前,将源文件备份,备份文件包含时间信息。有两个选项:yes|no content:用于替代“src”,可以直接设定指定文件的值 dest:必选项。要将源文件复制到的远程主机的绝对路径,如果源文件是一个目录,那么该路径也必须是个目录 directory_mode:递归设定目录的权限,默认为系统默认权限 force:如果目标主机包含该文件,但内容不同,如果设置为yes,则强制覆盖,如果为no,则只有当目标主机的目标位置不存在该文件时,才复制。默认为yes others:所有的file模块里的选项都可以在这里使用 src:被复制到远程主机的本地文件,可以是绝对路径,也可以是相对路径。如果路径是一个目录,它将递归复制。在这种情况下,如果路径使用“/”来结尾,则只复制目录里的内容,如果没有使用“/”来结尾,则包含目录在内的整个内容全部复制,类似于rsync。 root@storage:~# ansible openstack -m copy -a 'src=/root/aa.txt dest=/tmp' 5、command:在远端主机上执行命令 相关选项如下: creates:一个文件名,当该文件存在,则该命令不执行 free_form:要执行的linux指令 chdir:在执行指令之前,先切换到该目录 removes:一个文件名,当该文件不存在,则该选项不执行 executable:切换shell来执行指令,该执行路径必须是一个绝对路径 #ansible openstack -m command -a 'uptime' root@storage:~# ansible openstack -m command -a 'uptime' 192.168.13.30 | SUCCESS | rc=0 >> 16:11:43 up 27 days, 2:08, 3 users, load average: 7.11, 7.81, 8.92 6、shell:切换到某个shell执行指定的命令,参数与command相同 与command不同的是,此模块可以支持命令管道,同时还有另一个模块也具备此功能:raw root@storage:~# vim data.sh root@storage:~# date +%F_%H:%M:%S 2016-08-24_08:16:50 root@storage:~# chmod +x data.sh root@storage:~# ansible openstack -m copy -a 'src=/root/data.sh dest=/tmp owner=root group=root mode=0755' 192.168.13.30 | SUCCESS => { "changed": true, "checksum": "a0c5ebf2b8c213d26a864ff89b381afc2b1eb901", "dest": "/tmp/data.sh", "gid": 0, "group": "root", "md5sum": "159569349be4db486945c106d187ea4a", "mode": "0755", "owner": "root", "size": 30, "src": "/root/.ansible/tmp/ansible-tmp-1472026735.85-123460492539355/source", "state": "file", "uid": 0 } root@storage:~# ansible openstack -m command -a 'ls -l /tmp/data.sh' 192.168.13.30 | SUCCESS | rc=0 >> -rwxr-xr-x 1 root root 30 Aug 24 16:18 /tmp/data.sh root@storage:~# ansible openstack -m shell -a '/tmp/data.sh' 192.168.13.30 | SUCCESS | rc=0 >> 2016-08-24_16:20:00 7、其它模块 其他常用模块,比如:service、cron、yum、synchronize就不一一例举,可以结合自身的系统环境进行测试。 service:系统服务管理 cron:计划任务管理 yum:yum软件包安装管理 synchronize:使用rsync同步文件 user:系统用户管理 group:系统用户组管理 更多模块可以参考: 本文转自 OpenStack2015 博客,原文链接:http://blog.51cto.com/andyliu/1842081 如需转载请自行联系原作者

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

dubbo 入门

1 介绍 1.1 背景 随着互联网的发展,网站应用的规模不断扩大,常规的垂直应用架构已无法应对,分布式服务架构以及流动计算架构势在必行,亟需一个治理系统确保架构有条不紊的演进。 1.2 说明 DUBBO是一个分布式服务框架,致力于提供高性能和透明化的RPC远程服务调用方案,是阿里巴巴SOA服务化治理方案的核心框架。 1.3 功能 启动时检查、集群容错、负载均衡、线程模型、直连提供者、只订阅、只注册、静态服务、多协议、多注册中心、服务分组、多版本、分组聚合、参数验证、结果缓存、泛化引用、泛化实现、回声测试、上下文信息、隐式传参、异步调用、本地调用、参数回调、事件通知、本地存根、本地伪装、延迟暴露、并发控制、连接控制、延迟连接、粘滞连接、令牌验证、路由规则、配置规则、服务降级、优雅停机、主机绑定、日志适配、访问日志、服务容器、Reference Config缓存、分布式事务 1.4 支持的协议 dubbo rmi http webservice thrift memcached redis 2 环境准备 Java7、Java8 ZooKeeper Maven Tomcat7 Eclipse 3 架构图 节点角色说明及对应demo模块: Provider: 暴露服务的服务提供方。对应dubbo-demo-provider。 Consumer: 调用远程服务的服务消费方。对应dubbo-demo-consumer Registry: 服务注册与发现的注册中心。这个demo使用ZooKeeper,关于ZooKeeper的搭建可参考这篇文章。 Monitor: 统计服务的调用次调和调用时间的监控中心。需要搭建dubbo-admin,对应的war包可从这里下载,也可自行编译运行。 Container: 服务运行容器。使用Tomcat跟Jetty。 我的demo代码:https://github.com/JasperZXY/dubbo-demo 4 开始搭建项目 4.1 说明 下面的代码是在Java8下运行通过的。 4.2 创建maven项目 名称为dubbo-demo,加入需要的jar,这里把各个项目需要的jar包都放入了父pom中,实际项目最好做好分类,如下 <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <junit.version>4.12</junit.version> <spring.version>4.3.8.RELEASE</spring.version> <dubbo.version>2.5.3</dubbo.version> <zookeeper.version>3.4.10</zookeeper.version> <zkclient.version>0.10</zkclient.version> <jackson.version>2.7.4</jackson.version></properties><dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>${junit.version}</version> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>${spring.version}</version> </dependency> <!--SpringMVC集成slf4j-logback--> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>1.1.3</version> </dependency> <dependency> <groupId>org.logback-extensions</groupId> <artifactId>logback-ext-spring</artifactId> <version>0.1.2</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>jcl-over-slf4j</artifactId> <version>1.7.12</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>dubbo</artifactId> <version>${dubbo.version}</version> <exclusions> <exclusion> <!--排除传递spring依赖,防止冲突--> <artifactId>spring</artifactId> <groupId>org.springframework</groupId> </exclusion> </exclusions> </dependency> <!--导入zookeeper依赖--> <dependency> <groupId>org.apache.zookeeper</groupId> <artifactId>zookeeper</artifactId> <version>${zookeeper.version}</version> </dependency> <dependency> <groupId>com.github.sgroschupf</groupId> <artifactId>zkclient</artifactId> <version>0.1</version> </dependency> <dependency> <groupId>org.jboss.netty</groupId> <artifactId>netty</artifactId> <version>3.2.10.Final</version> </dependency> <dependency> <groupId>com.101tec</groupId> <artifactId>zkclient</artifactId> <version>${zkclient.version}</version> </dependency> <!--jackson--> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>${jackson.version}</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-core</artifactId> <version>${jackson.version}</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-annotations</artifactId> <version>${jackson.version}</version> </dependency></dependencies> 4.3 dubbo-demo-api 这个模块用于定义接口以及交互的实体对象,创建一个User跟UserService publicclassUserimplementsjava.io.Serializable{privatestaticfinallongserialVersionUID=-2218791253527448503L;privateLongid;privateStringusername;privateStringpassword;privateIntegerage;//这里省略了getset方法 @Override publicStringtoString(){return"User[id="+id+",username="+username+",password="+password+",age="+age+"]"; } } publicinterfaceUserService{publicList<User>queryAll(); } 4.4 dubbo-demo-provider 这个模块用于提供服务,是使用main方法直接运行的。 1、需要添加dubbo-demo-api这个依赖,pom.xml如下 <dependency> <groupId>zxy.demo</groupId> <artifactId>dubbo-demo-api</artifactId> <version>${project.parent.version}</version></dependency> 2、UserService的实现 publicclassUserServiceImplimplementsUserService{/***这里通过模拟查询数据库返回用户信息*/ @Override publicList<User>queryAll(){ List<User>list=newArrayList<User>();for(inti=0;i<3;i++){ Randomrandom=newRandom(); Useruser=newUser(); user.setAge(random.nextInt(10)+18); user.setId(Long.valueOf(i+1)); user.setPassword("123456"); user.setUsername("name_"+i); list.add(user); }returnlist; } } 3、Spring配置 <beansxmlns="http://www.springframework.org/schema/beans"xmlns:context="http://www.springframework.org/schema/context"xmlns:p="http://www.springframework.org/schema/p"xmlns:aop="http://www.springframework.org/schema/aop"xmlns:tx="http://www.springframework.org/schema/tx"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-4.0.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context-4.0.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop-4.0.xsdhttp://www.springframework.org/schema/txhttp://www.springframework.org/schema/tx/spring-tx-4.0.xsdhttp://code.alibabatech.com/schema/dubbohttp://code.alibabatech.com/schema/dubbo/dubbo.xsd"> <!--提供方应用信息,用于计算依赖关系--> <dubbo:applicationname="dubbo-demo-provider"/> <!--这里使用的注册中心是zookeeper--> <dubbo:registryaddress="zookeeper://127.0.0.1:2181"client="zkclient"/> <!--用dubbo协议在20880端口暴露服务--> <dubbo:protocolname="dubbo"port="20880"/> <!--将该接口暴露到dubbo中--> <dubbo:serviceinterface="zxy.demo.dubbo.api.service.UserService"ref="userServiceImpl"/> <!--将具体的实现类加入到Spring容器中--> <beanid="userServiceImpl"class="zxy.demo.dubbo.provider.service.UserServiceImpl"/></beans> 注:如果<dubbo:标签有报错的,可下载一个dubbo.xsd文件(可从我的git上找到),在Eclipse上windows->preferrence->XML->XML Catalog->add->catalog entry->file system,选择刚刚下载的文件路径,修改key值(dubbo.xsd),保存。在xml文件右键validate即可解决。 4、编写启动方法 ublicclassApplication{@SuppressWarnings("resource")publicstaticvoidmain(String[]args)throwsException{ (newClassPathXmlApplicationContext(newString[]{"spring/provider.xml"})).start();//保持main方法不退出 CountDownLatchlatch=newCountDownLatch(1); latch.await(); } } 4.5 dubbo-demo-consumer 这个模块用于调用dubbo-demo-provider提供的服务,使用SpringMVC进行运行。 1、需要添加dubbo-demo-api这个依赖,pom.xml如下 <dependency> <groupId>zxy.demo</groupId> <artifactId>dubbo-demo-api</artifactId> <version>${project.parent.version}</version></dependency> 2、Spring的配置 appContext.xml,主配置文件 <context:component-scanbase-package="zxy.demo.dubbo.consumer"></context:component-scan><importresource="classpath*:spring/dubbo-*.xml"/><importresource="classpath*:spring/springmvc-servlet.xml"/> springmvc-servlet.xml <!--添加注解驱动--><mvc:annotation-driven/><!--返回json支持--><beanid="jsonConverter"class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"> <propertyname="supportedMediaTypes"> <list> <value>text/html;charset=UTF-8</value> </list> </property></bean> dubbo-consumer.xml <!--提供方应用信息,用于计算依赖关系--><dubbo:applicationname="dubbo-demo-consumer"/><!--这里使用的注册中心是zookeeper--><dubbo:registryaddress="zookeeper://127.0.0.1:2181"client="zkclient"/><!--从注册中心中查找服务--><dubbo:referenceid="userService"interface="zxy.demo.dubbo.api.service.UserService"/> 3、web.xml <?xmlversion="1.0"encoding="UTF-8"?><web-appversion="3.0"xmlns="http://java.sun.com/xml/ns/javaee"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://java.sun.com/xml/ns/javaeehttp://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:spring/appContext.xml</param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <listener> <listener-class>ch.qos.logback.ext.spring.web.LogbackConfigListener</listener-class> </listener> <servlet> <servlet-name>springmvc</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value></param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>springmvc</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> </web-app> 4、controller 调用远程服务并返回前端数据。 @Controller@RequestMapping("/user")publicclassUserController{@Autowired privateUserServiceuserService; @RequestMapping("/list")@ResponseBody publicObjectlistAll(){returnuserService.queryAll(); } } 4.6 运行 先启动ZooKeeper 启动dubbo-demo-provider 启动dubbo-demo-consumer,mvn jetty:run -Djetty.port=8083 访问http://127.0.0.1:8083/user/list获取数据 5 监控 自行编译运行dubbo-admin或从我的git上下载dubbo-admin-2.5.3.war,放入tomcat中运行。默认用的注册中心是zookeeper://127.0.0.1:2181,可修改,在WEB-INF/dubbo.properties中进行修改。 启动后访问http://127.0.0.1:8080/dubbo-admin-2.5.3,如果war包是改名为ROOT.war后运行的,则访问http://127.0.0.1:8080/,输入账号密码(root/root)。 注意,由于现在很多机器都安装了高版本的Java8,运行这个dubbo-admin将导致出错,报错信息为“Bean property 'URIType' is not writable or has an invalid setter method”,详见官方的issues。我自己的解决方法是下载一个低版本的Java,修改tomcat对应的Java版本,找到setclasspath.bat中的set _RUNJAVA,set _RUNJDB这两行,修改如下: set_RUNJAVA="C:\ProgramFiles\Java\jdk1.7.0_80\bin\java.exe"set_RUNJDB="C:\ProgramFiles\Java\jdk1.7.0_80\bin\jdb.exe" 本文转自帅气的头头博客51CTO博客,原文链接http://blog.51cto.com/12902932/1925692如需转载请自行联系原作者 sshpp

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

elasticsearch入门

elasticsearch 本文基于elasticsearch-6.4.2版本 安装 1、安装JDK略2、安装es wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-6.4.2.tar.gz; tar -zxvf elasticsearch-6.4.2.tar.gz; mv elasticsearch-6.4.2 /usr/local; #创建用户elasticsearch 有elasticsearch 不能使用root账户运行,必须先创建用户 useradd elasticsearch; chown -R elasticsearch:elasticsearch /usr/local/elasticsearch-6.4.2/ ; #启动运行 su elasticsearch cd /usr/local/elasticsearch-6.4.2; sh ./bin/elasticsearch; 启动成功后,如下所示 3、安装head_plugin插件elasticsearch-6.x版本不支持使用elasticsearch-plugin install mobz/elasticsearch-head的方式安装。官方支持的plugin安装的方式的插件为 #安装head_plugin插件 wget https://github.com/mobz/elasticsearch-head/archive/master.zip yum install -y unzip; unzip master.zip; mv elasticsearch-head-master/ /usr/local/ #安装node wget https://npm.taobao.org/mirrors/node/v10.11.0/node-v10.11.0-linux-x64.tar.gz tar -zxvf node-v10.11.0-linux-x64.tar.gz mv node-v10.11.0-linux-x64 /usr/local/ vi /etc/profile #set node NODE_HOME=/usr/local/node-v10.11.0-linux-x64 export PATH=$PATH:$NODE_HOME/bin export NODE_PATH=$NODE_HOME/lib/node_modules "/etc/profile" 89L, 2079C written [root@k8s-master-101 ~]# source /etc/profile [root@k8s-master-101 ~]# node -v v10.11.0 #elasticsearch配置文件中授权 node.name: node-rcl-1 cluster.name: my-application-rcl network.host: 192.168.31.101 http.cors.enabled: true http.cors.allow-origin: "*" 启动过程中的几个问题: 1.max file descriptors [4096] for elasticsearch process is too low, increase to at least [65536] 2.max number of threads [1024] for user [lishang] likely too low, increase to at least [4096] 3.max virtual memory areas vm.max_map_count [65530] likely too low, increase to at least [262144] 分别修改 vi /etc/security/limits.conf elasticsearch hard nofile 65536 elasticsearch sorf nofile 65536 vi /etc/security/limits.d/20-nproc.conf * soft nproc 4096 * hard nproc 4096 elasticsearch soft nproc 4096 elasticsearch hard nproc 4096 #需要重启操作系统生效,使用ulimit -a 查看线程限制数 vi /etc/sysctl.conf vm.max_map_count=262144 4、启动ES、head-plugin #启动es cd /usr/local/elasticsearch-6.4.2 ./bin/elasticsearch -d #启动head-plugin cd /usr/local/elasticsearch-head-master npm run start 5、访问 ES的基本概念 群集 集群是一个或多个节点(服务器)的集合,它们共同保存您的整个数据,并提供跨所有节点的联合索引和搜索功能。群集由唯一名称标识,默认情况下为“elasticsearch”。此名称很重要,因为如果节点设置为按名称加入群集,则该节点只能是群集的一部分。 确保不要在不同的环境中重用相同的群集名称,否则最终会导致节点加入错误的群集。例如,您可以使用logging-dev,logging-stage以及logging-prod 用于开发,登台和生产集群。 请注意,如果群集中只有一个节点,那么它是完全正常的。此外,您还可以拥有多个独立的集群,每个集群都有自己唯一的集群名称。 节点 节点是作为群集一部分的单个服务器,存储数据并参与群集的索引和搜索功能。就像集群一样,节点由名称标识,默认情况下,该名称是在启动时分配给节点的随机通用唯一标识符(UUID)。如果不需要默认值,可以定义所需的任何节点名称。此名称对于管理目的非常重要,您可以在其中识别网络中哪些服务器与Elasticsearch集群中的哪些节点相对应。 可以将节点配置为按群集名称加入特定群集。默认情况下,每个节点都设置为加入一个名为cluster的集群elasticsearch,这意味着如果您在网络上启动了许多节点并且假设它们可以相互发现 - 它们将自动形成并加入一个名为的集群elasticsearch。 在单个群集中,您可以拥有任意数量的节点。此外,如果您的网络上当前没有其他Elasticsearch节点正在运行,则默认情况下启动单个节点将形成一个名为的新单节点集群elasticsearch。 索引 索引是具有某些类似特征的文档集合。例如,您可以拥有客户数据的索引,产品目录的另一个索引以及订单数据的另一个索引。索引由名称标识(必须全部小写),此名称用于在对其中的文档执行索引,搜索,更新和删除操作时引用索引。 在单个群集中,您可以根据需要定义任意数量的索引。 文档 文档是可以编制索引的基本信息单元。例如,您可以为单个客户提供文档,为单个产品提供另一个文档,为单个订单提供另一个文档。该文档以JSON(JavaScript Object Notation)表示,JSON是一种普遍存在的互联网数据交换格式。 在索引/类型中,您可以根据需要存储任意数量的文档。请注意,尽管文档实际上驻留在索引中,但实际上必须将文档编入索引/分配给索引中的类型。 碎片和副本 索引可能存储大量可能超过单个节点的硬件限制的数据。例如,占用1TB磁盘空间的十亿个文档的单个索引可能不适合单个节点的磁盘,或者可能太慢而无法单独从单个节点提供搜索请求。 为了解决这个问题,Elasticsearch提供了将索引细分为多个称为分片的功能。创建索引时,只需定义所需的分片数即可。每个分片本身都是一个功能齐全且独立的“索引”,可以托管在集群中的任何节点上。 分片很重要,主要有两个原因: 它允许您水平拆分/缩放内容量它允许您跨分片(可能在多个节点上)分布和并行化操作,从而提高性能/吞吐量分片的分布方式以及如何将其文档聚合回搜索请求的机制完全由Elasticsearch管理,对用户而言是透明的。 在可以随时发生故障的网络/云环境中,非常有用,强烈建议使用故障转移机制,以防分片/节点以某种方式脱机或因任何原因消失。为此,Elasticsearch允许您将索引的分片的一个或多个副本制作成所谓的副本分片或简称副本。 复制很重要,主要有两个原因: 它在碎片/节点发生故障时提供高可用性。因此,请务必注意,副本分片永远不会在与从中复制的原始/主分片相同的节点上分配。它允许您扩展搜索量/吞吐量,因为可以在所有副本上并行执行搜索。总而言之,每个索引可以拆分为多个分片。索引也可以复制为零(表示没有副本)或更多次。复制后,每个索引都将具有主分片(从中复制的原始分片)和副本分片(主分片的副本)。 可以在创建索引时为每个索引定义分片和副本的数量。创建索引后,您还可以随时动态更改副本数。您可以使用_shrink和_splitAPI 更改现有索引的分片数,但这不是一项简单的任务,并且预先计划正确数量的分片是最佳方法。 默认情况下,Elasticsearch中的每个索引都分配了5个主分片和1个副本,这意味着如果群集中至少有两个节点,则索引将包含5个主分片和另外5个副本分片(1个完整副本),总计为每个索引10个分片。 注意每个Elasticsearch分片都是Lucene索引。单个Lucene索引中可以包含最大数量的文档。截止LUCENE-5843,限制是2,147,483,519(= Integer.MAX_VALUE - 128)文档。您可以使用_cat/shardsAPI 监控分片大小。 参考:https://www.elastic.co/guide/en/elasticsearch/reference/current/_basic_concepts.html 索引管理 1、创建索引 PUT /index_name/ #参数配置 "settings": { "index": { "number_of_shards": "5", "number_of_replicas": "1" } } #number_of_shards为主分片数,默认为5;number_of_replicas为主分片对应的副本数,默认为1 2、mapping管理创建索引myindex4,并添加类型log、添加字段year(字段类型为整形) 向已经存在的索引myindex3添加类型log、字段year(字段类型为整形) 2、删除索引 DELETE /my_index DELETE /index_one,index_two DELETE /index_* DELETE /_all #禁止使用_all或者通配符*进行索引删除 action.destructive_requires_name: true 别名不能用于删除索引? 3、获取索引 GET /{myindex}/ 4、打开、关闭索引 POST /{indexname}/_open POST /{indexname}/_close #settingscluster.indices.close.enable: false 默认为开启 5、索引别名a、索引别名不能重复,也不能与索引名重复b、可以对一个或者多个索引指定一个别名(多个索引可以对应一个别名);一个索引也可以添加多个别名c、别名不能更新,只能删除后重建 GET /{myindex}/_alias/{alias} GET /{myindex}/_alias/{*} #添加索引 PUT /{myindex}/_alias/{myindexalias} #删除索引 DELETE /{myindex}/_alias/{alias} POST /_aliases/ { "actions": [ { "add": { "index": "myindex", "alias": "myindexalias" } }, { "add": { "index": "myindex", "alias": "myindexalias2" } }, { "add": { "index": "myindex2", "alias": "myindexalias" } }, { "remove": { "index": "myindex", "alias": "myindexalias" } } ] } 过滤索引别名 /* "filter": {"term": {"year": 2018}} #路由 "routing": "" 或者分开设置索引路由和查询路由 "index_routing": "2", "search_routing": "1,2" */ 6、获取、更新索引配置 GET /{index}/_settings/ #{index}的形式可以是:_all | *、xxx* | xxx,xxx,... 的形式 /**可以更新副本数量和添加分词(必须先关闭、添加、在打开索引)**/ PUT /{index}/_settings/ {"index": {"number_of_replicas": 4}} {"analysis":{"analyzer":{"content":{"type":"custom","tokenizer":"whitespace"}}}} 2、elastic操作2.1、集群状态监控 集群状态监控api如下所示 [root@localhost ~]# curl localhost:9200/_cat/ =^.^= /_cat/allocation /_cat/shards /_cat/shards/{index} /_cat/master /_cat/nodes /_cat/tasks /_cat/indices /_cat/indices/{index} /_cat/segments /_cat/segments/{index} /_cat/count /_cat/count/{index} /_cat/recovery /_cat/recovery/{index} /_cat/health /_cat/pending_tasks /_cat/aliases /_cat/aliases/{alias} /_cat/thread_pool /_cat/thread_pool/{thread_pools} /_cat/plugins /_cat/fielddata /_cat/fielddata/{fields} /_cat/nodeattrs /_cat/repositories /_cat/snapshots/{repository} /_cat/templates /_cat/health:集群状态/_cat/thread_pool:线程池状态/_cat/indices:索引状态/_cat/nodes:节点状态 2.2、索引创建索引 [root@localhost ~]# curl -XPUT localhost:9200/log?pretty { "acknowledged" : true, "shards_acknowledged" : true, "index" : "log" } 查询索引 curl localhost:9200/_cat/indices?v health status index uuid pri rep docs.count docs.deleted store.size pri.store.size yellow open log zm0ho3xFR1KaPFwHWfsX3Q 5 1 0 0 810b 810b yellow open customer lpfXum5qQoi3Mj9PJZB8Ug 5 1 1 0 4kb 4kb 关于重做索引、删除索引,索引之间如何平滑切换,后面详细讲解 2.3、文档创建文档 [root@localhost ~]# curl -XPUT localhost:9200/log/authlog/1?pretty -d '{"name":"rcl","detail":"blacklist"}' { "_index" : "log", "_type" : "authlog", "_id" : "1", "_version" : 1, "result" : "created", "_shards" : { "total" : 2, "successful" : 1, "failed" : 0 }, "created" : true } 更新文档 [root@localhost ~]# curl -XPUT localhost:9200/log/authlog/1?pretty -d '{"name":"amao","detail":"blacklist"}' { "_index" : "log", "_type" : "authlog", "_id" : "1", "_version" : 2, "result" : "updated", "_shards" : { "total" : 2, "successful" : 1, "failed" : 0 }, "created" : false } 查询文档 [root@localhost ~]# curl localhost:9200/log/authlog/1?pretty { "_index" : "log", "_type" : "authlog", "_id" : "1", "_version" : 2, "found" : true, "_source" : { "name" : "amao", "detail" : "blacklist" } } 此处name已被更新为amao,有此可见更新是有效的删除文档 [root@localhost ~]# curl -XDELETE localhost:9200/log/authlog/1?pretty { "found" : true, "_index" : "log", "_type" : "authlog", "_id" : "1", "_version" : 3, "result" : "deleted", "_shards" : { "total" : 2, "successful" : 1, "failed" : 0 } } [root@localhost ~]# curl localhost:9200/log/authlog/1?pretty { "_index" : "log", "_type" : "authlog", "_id" : "1", "found" : false } 2.4、DSL查询示例 [root@localhost ~]# curl -XPOST localhost:9200/log/_search -d '{"query":{"match":{"name":"amao"}}}' {"took":38,"timed_out":false,"_shards":{"total":5,"successful":5,"skipped":0,"failed":0},"hits":{"total":1,"max_score":0.2876821,"hits":[{"_index":"log","_type":"authlog","_id":"1","_score":0.2876821,"_source":{"name":"amao","detail":"blacklist"}}]}} kibana 1、安装 wget https://artifacts.elastic.co/downloads/kibana/kibana-6.4.2-linux-x86_64.tar.gz tar -zxvf kibana-6.4.2-linux-x86_64.tar.gz mv kibana-6.4.2-linux-x86_64 /usr/local cd /usr/local chown -R elasticsearch:elasticsearch kibana-6.4.2-linux-x86_64 ./bin/kibana Filebeat ./filebeat -e -c filebeat.yml filebeat.yml配置如下cat filebeat.yml | grep -v '#' | grep -v '^$' filebeat.inputs: - type: log enabled: true paths: - /usr/local/elastic-data/aaaaaa* fields: logtype: filelog logsource: log4j filebeat.config.modules: path: ${path.config}/modules.d/*.yml reload.enabled: false setup.template.settings: index.number_of_shards: 3 setup.kibana: output.logstash: hosts: ["192.168.31.101:5044"] Logstash 1、安装 wget https://artifacts.elastic.co/downloads/logstash/logstash-6.4.2.tar.gz tar -zxvf logstash-6.4.2.tar.gz mv logstash-6.4.2 /usr/local cd /usr/local chown -Relasticsearch:elasticsearch logstash-6.4.2 bin/logstash -f first-pipeline.conf --config.reload.automatic first-pipeline.conf在logstash home目录下新建first-pipeline.conf # comments to describe your configuration. input { beats { host => "192.168.31.101" port => "5044" } } # The filter part of this file is commented out to indicate that it is # optional. # filter { # # } output { elasticsearch { hosts => ["192.168.31.101:9200"] } }

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

Nginx入门

一、Nginx简介 1.1Nginx特性 模块化设计,较好的扩展性 高可靠性 支持热部署:不停机更新配置文件,升级版本,更换日志文件 低内存消耗:10000个keep-alive连接模式下的非活动连接,仅 需要2.5M内存event-driven,aio,mmap,sendfile 1.2Nginx的基本功能 静态资源的web服务器 http协议反向代理服务器 pop3/imap4协议反向代理服务器 FastCGI(lnmp),uWSGI(python)等协议 模块化(非DSO),如zip,SSL模块 1.3Nginx与web服务相关的功能 虚拟主机(server) 支持 keep-alive 和管道连接 访问日志(支持基于日志缓冲提高其性能) url rewirte 路径别名 基于IP及用户的访问控制 支持速率限制及并发数限制 重新配置和在线升级而无须中断客户的工作进程 Memcached 的 GET 接口 二、Nginx服务架构 master/worker结构 master进程:负责加载和分析配置文件、管理worker进程,平滑升级 worker进程:接收客户端请求、将请求一次送入各模块过滤、I/O调用、数据缓存、发送响应 cache相关进程:cache loader (缓存索引重建)与cache manager(缓存索引管理)组成 --Cache loader在Nginx服务启动后由主进程生成,根据本地磁盘上缓存建立索引元数据库后退出。 --Cache manager在元数据更新完成后,对元数据是否过期做出判断。 三、Nginx的配置文件结构 配置文件的组成部分 主配置文件:nginx.conf 子配置文件:include conf.d/*.conf fastcgi、uwsgi、scgi:等协议相关的配置文件。在根路径下 mime.types:支持的mime类型。在根路径下 四、基本配置实例讲解

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

SpringCloud入门

1.关于SpringCloud中各个微服务之间调用的URL硬编码问题 ----通过SpringCloud服务注册、发现的机制来完成 2.微服务调用的原理图 由上图可以看出: 1、 服务提供者将服务注册到注册中心 2、 服务消费者通过注册中心查找服务 3、 查找到服务后进行调用(这里就是无需硬编码url的解决方案) 4、 服务的消费者与服务注册中心保持心跳连接,一旦服务提供者的地址发生变更时,注册中心会通知服务消费者 3.注册中心Eureka SpringCloud提供了多种注册中心的支持,如:Eureka、ZooKeeper等。官方推荐使用Eureka。 原理: Eureka包含两个组件:Eureka Server和Eureka Client。 Eureka Server提供服务注册服务,各个节点启动后,会在Eureka Server中进行注册,这样EurekaServer中的服务注册表中将会存储所有可用服务节点的信息,服务节点的信息可以在界面中直观的看到。 Eureka Client是一个java客户端,用于简化与Eureka Server的交互,客户端同时也就别一个内置的、使用轮询(round-robin)负载算法的负载均衡器。 在应用启动后,将会向Eureka Server发送心跳,默认周期为30秒,如果Eureka Server在多个心跳周期内没有接收到某个节点的心跳,Eureka Server将会从服务注册表中把这个服务节点移除(默认90秒)。 Eureka Server之间通过复制的方式完成数据的同步,Eureka还提供了客户端缓存机制,即使所有的Eureka Server都挂掉,客户端依然可以利用缓存中的信息消费其他服务的API。综上,Eureka通过心跳检查、客户端缓存等机制,确保了系统的高可用性、灵活性和可伸缩性。

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

Hive 入门

官网:hive.apache.org 首先,Hive是数据仓库。可以用类SQL的语言来跑MR,可以理解为Hadoop的客户端。一方面Hive 数据都来自HDFS,另一方面Hive的代码需要提交到Hadoop中去执行,来跑MR。 HiveQL或者HQL,实际上是Hive将SQL提交,后翻译成MR,在HDFS上执行。所以Hive由解释器(解释成Java代码,提交到MR执行)、编译器、优化器等功能。 Hive在运行时元数据存储在关系型数据库中。不推荐默认的,可以使用mysql代替。具体的配置文件在conf/hive-site.xml里的ConnectionURL里面. hive的语法和sql很像,举例 CREATE TABLE t_person( id int, name string, hobby array<string>, character map<string, string>) ROW FORMAT DELIMITED FIELDS TERMINATED BY ',' COLLECTION ITEMS TERMINATED BY '_' MAP KEYS TERMINATED BY ':'; 对应的example: 1, zhangsan, sports_books_TV, sex:man_color:red 另外,只有查所有数据的时候才不执行MR, 比如:select * from table 时 创建分区表,分区实际上是个文件夹,表名就是文件夹名。每一个分区,实际上就是这个文件夹下的不同文件。分区可以根据时间、区域等进行划分,如每天一个分区或者每个城市一个分区,只要写下 where pt=20170707这样的条件即可查询指定时间得到数据。 CREATE TABLE e_stu( id int, sname string, city string) PARTITIONED BY (ds string) ROW FORMAT DELIMITED FIELDS TERMINATED BY ',' sTORED AS TEXTFILE; 导入数据(在hive中执行) LOAD DATA LOCAL INPATH '/home/zkpk/ecaoyng/input/estu.txt' OVERWRITE INTO TABLE e_stu PARTITION (ds='2017-07-07') LOAD DATA LOCAL INPATH '/home/zkpk/ecaoyng/input/estu2.txt' INTO TABLE e_stu PARTITION (ds='2017-07-08') hive> select * from e_stu; OK 1 young linyi 2017-07-07 2 jerry dalian 2017-07-07 3 ian dalian 2017-07-07 1 hello usa 2017-07-08 2 world France 2017-07-08 3 hadoop English 2017-07-08 4 hive spain 2017-07-08 Time taken: 0.087 seconds, Fetched: 7 row(s) hive> select * from e_stu where ds = '2017-07-07'; OK 1 young linyi 2017-07-07 2 jerry dalian 2017-07-07 3 ian dalian 2017-07-07 Time taken: 0.211 seconds, Fetched: 3 row(s) hive> hive> insert into table e_stu > partition (ds = '2017-09-10') > select id,sname,city from e_stu; hive> select * from e_stu where ds = '2017-09-10'; OK 1 young linyi 2017-09-10 2 jerry dalian 2017-09-10 3 ian dalian 2017-09-10 1 hello usa 2017-09-10 2 world France 2017-09-10 3 hadoop English 2017-09-10 4 hive spain 2017-09-10 那么hive的文件在哪里查看?从50070的页面中的browse directory 中的user目录下/user/hive/warehouse/day0525.db/e_stu 可以看到有两个文件夹 hive的四种数据导入方式,旧的版本不支持insert into values,但新版本已经支持。 http://blog.csdn.net/lifuxiangcaohui/article/details/40588929 因为mysql中存储元数据,所以启动hive的时候需要启动mysql。但启动是有时会遇到如下的提示: Another MySQL daemon already running with the same unix socket. 解决方案: find / -name mysql.sock 将mysql.sock(e.g. /var/lib/mysql/mysql.sock)删除,重启service即可 export将表中的数据导出到hdfs. 未完待续

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

HDFS 入门

注意secondaryname node 不是name node的备份,仅仅备份了一部分的元数据,不是实时备份。它的主要工作是帮助NN合并editslog,减少NN启动时间 比如删除元数据,不会立马删除,而是将操作信息写入日志edits log,在合并的时候(edits log和fsimage合并的时候)进行实际的删除。合并完成之后会得到一个新的fsimage再传送给NN,并替换原来的。 所以NN的主要做用是接受客户端的读写操作,而元数据的更新等需要大量IO操作的合并等由SNN来做。 SNN执行合并机制: 根据配置文件设置的时间间隔fs.checkpoint.period 默认为3600s 根据配置文件设置edits log大小 fs.checkpoint.size规定edits文件的最大默认为64M NameNode的$dfs.namenode.name.dir/current/文件夹的几个文件: current/ |– VERSION |– edits_* |– fsimage_0000000000008547077 |– fsimage_0000000000008547077.md5 `– seen_txid 其中存在大量的以edits开头的文件和少量的以fsimage开头的文件。那么这两种文件到底是什么,有什么用?下面对这两中类型的文件进行详解。在进入下面的主题之前先来搞清楚edits和fsimage文件的概念: (1)、fsimage文件其实是Hadoop文件系统元数据的一个永久性的检查点,其中包含Hadoop文件系统中的所有目录和文件idnode的序列化信息; (2)、edits文件存放的是Hadoop文件系统的所有更新操作的路径,文件系统客户端执行的所以写操作首先会被记录到edits文件中。 fsimage和edits文件都是经过序列化的,在NameNode启动的时候,它会将fsimage文件中的内容加载到内存中,之后再执行edits文件中的各项操作,使得内存中的元数据和实际的同步,存在内存中的元数据支持客户端的读操作。 NameNode起来之后,HDFS中的更新操作会重新写到edits文件中,因为fsimage文件一般都很大(GB级别的很常见),如果所有的更新操作都往fsimage文件中添加,这样会导致系统运行的十分缓慢,但是如果往edits文件里面写就不会这样,每次执行写操作之后,且在向客户端发送成功代码之前,edits文件都需要同步更新。如果一个文件比较大,使得写操作需要向多台机器进行操作,只有当所有的写操作都执行完成之后,写操作才会返回成功,这样的好处是任何的操作都不会因为机器的故障而导致元数据的不同步。 fsimage包含Hadoop文件系统中的所有目录和文件idnode的序列化信息;对于文件来说,包含的信息有修改时间、访问时间、块大小和组成一个文件块信息等;而对于目录来说,包含的信息主要有修改时间、访问控制权限等信息。fsimage并不包含DataNode的信息,而是包含DataNode上块的映射信息,并存放到内存中,当一个新的DataNode加入到集群中,DataNode都会向NameNode提供块的信息,而NameNode会定期的“索取”块的信息,以使得NameNode拥有最新的块映射。因为fsimage包含Hadoop文件系统中的所有目录和文件idnode的序列化信息,所以如果fsimage丢失或者损坏了,那么即使DataNode上有块的数据,但是我们没有文件到块的映射关系,我们也无法用DataNode上的数据!所以定期及时的备份fsimage和edits文件非常重要! 在前面我们也提到,文件系统客户端执行的所以写操作首先会被记录到edits文件中,那么久而久之,edits会非常的大,而NameNode在重启的时候需要执行edits文件中的各项操作,那么这样会导致NameNode启动的时候非常长!在下篇文章中我会谈到在Hadoop 1.x版本和Hadoop 2.x版本是怎么处理edits文件和fsimage文件的。 注意NN工作的数据都在内存中,会将用户操作都记录在edit 文件 HDFS读流程 其中Distributed FileSystem/FSDataInputStream是两个API,而且4,5是并发执行的,当读取所有的block在客户端合并成一个大文件。 HDFS写流程 注意当写dn的时候,仅仅是向一个dn上写block,其他副本由这个DN新起线程去完成。 HDFS文件权限 HDFS的HA,主要给NN做HA 用户连接的是ZK zk 必须是大于1的奇数(竞争锁的投票机制)) zkfc和nn的数量一致 JN也是奇数个 HDFS做HA,节点数量举例 MapReduce的HA,主要给Resource Manager做HA. 但是一般企业只对HDFS做HA

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

beego入门

简介: beego 是一个快速开发 Go 应用的 HTTP 框架,他可以用来快速开发 API、Web 及后端服务等各种应用,是一个 RESTful 的框架,主要设计灵感来源于 tornado、sinatra 和 flask 这三个框架,但是结合了 Go 本身的一些特性(interface、struct 嵌入等)而设计的一个框架。 beego 的架构 beego 是基于八大独立的模块构建的,是一个高度解耦的框架。当初设计 beego 的时候就是考虑功能模块化,用户即使不使用 beego 的 HTTP 逻辑,也依旧可以使用这些独立模块,例如:你可以使用 cache 模块来做你的缓存逻辑;使用日志模块来记录你的操作信息;使用 config 模块来解析你各种格式的文件。所以 beego 不仅可以用于 HTTP 类的应用开发,在你的 socket 游戏开发中也是很有用的模块,这也是 beego 为什么受欢迎的一个原因。大家如果玩过乐高的话,应该知道很多高级的东西都是一块一块的积木搭建出来的,而设计 beego 的时候,这些模块就是积木,高级机器人就是 beego。 架构图 beego 的执行逻辑 既然 beego 是基于这些模块构建的,那么它的执行逻辑是怎么样的呢?beego 是一个典型的 MVC 架构,它的执行逻辑如下图所示: mvc 架构逻辑 . ├── conf │ └── app.conf ├── controllers │ └── default.go ├── main.go ├── quickstart ├── routers │ └── router.go ├── static │ └── js │ └── reload.min.js ├── tests │ └── default_test.go └── views └── index.tpl 从上面的目录结构我们可以看出来 M(models 目录)、V(views 目录)和 C(controllers 目录)的结构, main.go 是入口文件。 快速搭建 配置开发环境 # 如果您还没添加 $GOPATH 变量 $ echo 'export GOPATH="$HOME/go"' >> ~/.profile # 或者 ~/.zshrc, ~/.cshrc, 您所使用的sh对应的配置文件 # 如果您已经添加了 $GOPATH 变量 $ echo 'export PATH="$GOPATH/bin:$PATH"' >> ~/.profile # 或者 ~/.zshrc, ~/.cshrc, 您所使用的sh对应的配置文件 $ exec $SHELL 安装beego $ go get -u github.com/astaxie/beego $ go get -u github.com/beego/bee 创建项目,启动项目 youdi@liangchangyoudeMacBook-Pro  ~  cd $GOPATH/src youdi@liangchangyoudeMacBook-Pro  ~/go/src  cd quickstart youdi@liangchangyoudeMacBook-Pro  ~/go/src/quickstart   master ●  bee run ______ | ___ \ | |_/ / ___ ___ | ___ \ / _ \ / _ \ | |_/ /| __/| __/ \____/ \___| \___| v1.9.0 2017/09/14 23:37:23 INFO ▶ 0001 Using 'quickstart' as 'appname' 2017/09/14 23:37:23 INFO ▶ 0002 Initializing watcher... 2017/09/14 23:37:25 SUCCESS ▶ 0003 Built Successfully! 2017/09/14 23:37:25 INFO ▶ 0004 Restarting 'quickstart'... 2017/09/14 23:37:25 SUCCESS ▶ 0005 './quickstart' is running... 2017/09/14 23:37:25 [I] [asm_amd64.s:2337] http server Running on http://:8080 在浏览器中访问 Screenshot 2017-09-14_23-34-11.png

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

HBase入门

HBase 是hadoop的数据库(数据量大,实时),目标是存储并处理大型的数据,具体来讲是用普通的硬件资源,就能处理成千上万的行和列所组成的大型数据。它可以直接使用本地文件或者HDFS,因为稳定性的考虑,推荐使用HDFS。利用HDFS作为其文件存储系统,利用MR来处理Hbase中的海量数据,利用ZK来做HA(高可用)作为其分布式协同服务。 HBase的安装分为三种模式:单机、伪分布式安装、全分布模式安装。其中伪分布式模式是一个运行在单台机器上的分布式模式,此种模式性HBase所有的守护进程都运行在同一个节点。因为分布式模式依赖于HDFS,所有确认HDFS已成功安装并启动。另外,全分布模式需要zookeeper的配置。 HBase常用命令 HBase体系结构 HBase主从结构。HBase Master负责管理所有的HRegion服务器,而HBase所有的服务器都是通过Zookeeper来协调并处理HBase服务器可能遇到的错误。HBase Master本身并不存储HBase中的任何数据。Hbase逻辑上的表被划分为多个HRegion,然后存储到HRegion server 群中。 HRegion: HRegion服务器 所有的数据库文件一般保存在HDFS上,用户通过一些列的HRegion服务器获取这些数据,一台机器上面一般只运行一个HRegion服务器,且每一个区段的HRegion也智慧被一个HRegion服务器维护. HBase Master服务器 HBase 数据逻辑视图 每行列的个数可以不一样 HBase 数据物理视图 虽然从概念视图上每个表格有很多行组成,但是物理存储来看,它是按照列来保存的。 HBase体系结构 client请求zk(zk,用于HA,解决单点故障问题)。图中有一个错误,每一个HRegtionServer,只有一个Hlog,不应属于HRegion。 每一个store存在一个目录下,实际就是一个列族 MemStore,内存store,当数据刚写入时是放在内存中的,当溢写时写道StoreFile,而真正的数据是在HFile在HDSF上。StoreFile上有HFile上的元数据。在Region中不会真正的保存数据,真正的数据都在HDSF上面 HBase与RDBMS HBase常用命令 http://www.cnblogs.com/xiaolei2017/p/7245299.html http://blog.csdn.net/lifuxiangcaohui/article/details/40042117 启动Hbase 首先要确保zookeeper已经安装完成,可以用zkServer.sh 查看 start-hbase.sh. 可以通过jps查看hmaster和hregionserver是否启动。 另外可以通过网页:master:60010查看

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

入门预测

一句话理解云平台的运作模式,就是:在不同层级上、为不同规模的产业需求方提供不同形式上的互联网生态环境。 IaaS云服务的优势:省去了IT基础设施上的投资、建设工作量,研发人员可以直接获取虚拟化的基础设施资源来部署上层应用的搭建工作,客户消费的是云化资源类的服务。 PaaS云服务的优势:省去了IT应用平台上的投资、建设工作量,研发人员可以直接获取虚拟化的平台应用工具来部署上层应用的搭建工作,客户消费的是云化工具类的服务。 SaaS云服务的优势:省去了整个IT支撑上的所有工作,客户只需要根据自己的商业模式选择虚拟化的软件工作环境来部署上层应用即可,能以最快捷的方式投入商用运作、产生效益,客户消费的是云化软件类的服务。 下一步的演进方向应该是BaaS,即:客户可以自由地消费他/她所希望获取的某种商业模式,云服务商可以组合起互联网生态环境之外的其他社会生态环境(比如:物联网)的解决方案一并提供给客户。

资源下载

更多资源
Mario

Mario

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

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册