标签 Google 下的文章

使用core-vagrant方式安装CoreOS

CoreOS是一种专门为运行类docker容器而生的linux发行版。与其他通用linux发行版(ubuntudebianredhat)相 比,它具有体型最小,消耗最小,支持滚动更新等特点。除此之外CoreOS内置的分布式系统服务组件也给开发者和运维者组建分布式集群、部署分布式服务应 用带来了极大便利。

CoreOS与知名容器Docker脚前脚后诞生,到目前为止已经较为成熟,国外主流云平台提供商如Amazon EC2Google Compute EngineMicrosoft AzureDigtial Ocean等均提供了CoreOS image,通过这些服务,你可以一键建立一个CoreOS实例,这似乎也是CoreOS官方推荐的主流install方式(最Easy)。

CoreOS当然支持其他方式的安装,比如支持虚拟机安装(vagrant+virtualbox)、PXE(preboot execute environment)安装以及iso install to 物理disk方式。如果仅仅是做一些实验,虚拟机安装是最简单也是最安全的方式。不过由于CoreOS的官方下载站在大陆无法直接访问(大陆程序员们好悲 催啊),因此这一最简单的虚拟机安装CoreOS的过程也就不那么简单了。

通过core-vagrant安装的直接结果是CoreOS被安装到一个VirtualBox虚拟机中,之后我们利用Vagrant命令来进行 CoreOS虚拟机的启停。CoreOS以及Vagrant都在持续演进,尤其是CoreOS目前在active dev中,版本号变化很快,这也是CoreOS滚动升级的必然结果。因此在安装操作演示前,我们有必要明确一下这个安装过程使用的软件版本:

    物理机OS:
        Ubuntu 12.04 3.8.0-42-generic x86_64
    VirtualBox:
        Oracle VM VirtualBox Manager 4.2.10
    Vagrant:
        Vagrant 1.7.3

    CoreOS:
        stable 717.3.0

    coreos-vagrant source:
        commit b9ed7e2182ff08b72419ab3e89f4a5652bc75082

一、原理

如果没有Wall,CoreOS的coreos-vagrant安装将非常简单:

1、git clone https://github.com/coreos/coreos-vagrant
2、编辑配置文件
3、vagrant up
4、vagrant ssh

但是现在有了Wall,步骤3:vagrant up会报错:无法连接到http://stable.release.core-os.net/amd64-usr/717.3.0/xx这个url,导致安装失败。

我大致分析了一下vagrant up的执行过程:

1、设置配置默认值

    $num_instances = 1
    $instance_name_prefix = "core"
    $update_channel = "alpha"
    $image_version = "current"
    $enable_serial_logging = false
    $share_home = false
    $vm_gui = false
    $vm_memory = 1024
    $vm_cpus = 1
    $shared_folders = {}
    $forwarded_ports = {}

2、判断是否存在config.rb这个配置,如果有,则加载。
3、设置config.vm.url,并获取对应的json文件:

{
  "name": "coreos-stable",
  "description": "CoreOS stable",
  "versions": [{
    "version": "717.3.0",
    "providers": [{
      "name": "virtualbox",
      "url": "http://stable.release.core-os.net/amd64-usr/717.3.0/coreos_production_vagrant.box",
      "checksum_type": "sha256",
      "checksum": "99dcd74c7cae8b1d90f108f8819f92b17bfbd34f4f141325bd0400fe4def55b6"
    }]
  }]
}

4、根据config.vm.provider(是virtualbox还是vmvare等)来决定采用哪种虚拟机创建逻辑。

这里我们看到,整个过程只需要从core-os.net下载两个文件:coreos_production_vagrant.boxcoreos_production_vagrant.json。如果我们提前将这两个文件下载到本地,并放在一个临时的http server下,修改Vagrantfile和coreos_production_vagrant.json这两个文件,就应该可以通过coreos-vagrant安装了。

二、coreos-vagrant安装single instance CoreOS

好了,根据上述原理,我们首先要下载coreos_production_vagrant.boxcoreos_production_vagrant.json这两个文件,根据我们的channel和版本选择,两个文件的下载地址分别为:

 http://stable.release.core-os.net/amd64-usr/717.3.0/coreos_production_vagrant.box
 http://stable.release.core-os.net/amd64-usr/717.3.0/coreos_production_vagrant.json

接下来就是不管你用什么梯子,只要把这两个文件下载到本地,并放到一个目录下就好了。

我们需要修改一下coreos_production_vagrant.json,将其中的url改为:
   
    "url": "http://localhost:8080/coreos_production_vagrant.box"

我们要将这两个文件放到一个local file server中,后续供core-vagrant访问。最简单的方法就是使用:

    python -m SimpleHTTPServer 8080

当然使用Go实现一个简单的http file server也是非常简单的:

//fileserver.go
package main

import "net/http"
import "log"

func main() {
    log.Fatal(http.ListenAndServe(":8080", http.FileServer(http.Dir("./"))))
}

接下来我们就可以按照正常步骤,下载coreos-vagrant并up了:

$git clone https://github.com/coreos/coreos-vagrant

修改Vagrantfile:

$ diff Vagrantfile Vagrantfile.bak
14,15c14,15
< $update_channel = "stable"
< $image_version = "717.3.0"

> $update_channel = "alpha"
> $image_version = "current"
55c55
<   config.vm.box_url = "http://localhost:8080/coreos_production_vagrant.json"

>   config.vm.box_url = "http://%s.release.core-os.net/amd64-usr/%s/coreos_production_vagrant.json" % [$update_channel, $image_version]

将user-data.sample改名为user-data,并编辑user-data,在etcd2下面增加一行:

      etcd2:
    name: core-01

将units:下面对于etcd2的注释去掉,以enable etcd2服务。(将etcd服务注释掉)

万事俱备,只需vagrant up。

$ vagrant up
Bringing machine 'core-01' up with 'virtualbox' provider…
==> core-01: Box 'coreos-stable' could not be found. Attempting to find and install…
    core-01: Box Provider: virtualbox
    core-01: Box Version: 717.3.0
==> core-01: Loading metadata for box 'http://localhost:8080/coreos_production_vagrant.json'
    core-01: URL: http://localhost:8080/coreos_production_vagrant.json
==> core-01: Adding box 'coreos-stable' (v717.3.0) for provider: virtualbox
    core-01: Downloading: http://localhost:8080/coreos_production_vagrant.box
    core-01: Calculating and comparing box checksum…
==> core-01: Successfully added box 'coreos-stable' (v717.3.0) for 'virtualbox'!
==> core-01: Importing base box 'coreos-stable'…
==> core-01: Matching MAC address for NAT networking…
==> core-01: Checking if box 'coreos-stable' is up to date…
==> core-01: Setting the name of the VM: coreos-vagrant_core-01_1437121834188_89503
==> core-01: Clearing any previously set network interfaces…
==> core-01: Preparing network interfaces based on configuration…
    core-01: Adapter 1: nat
    core-01: Adapter 2: hostonly
==> core-01: Forwarding ports…
    core-01: 22 => 2222 (adapter 1)
==> core-01: Running 'pre-boot' VM customizations…
==> core-01: Booting VM…
==> core-01: Waiting for machine to boot. This may take a few minutes…
    core-01: SSH address: 127.0.0.1:2222
    core-01: SSH username: core
    core-01: SSH auth method: private key
    core-01: Warning: Connection timeout. Retrying…
==> core-01: Machine booted and ready!
==> core-01: Setting hostname…
==> core-01: Configuring and enabling network interfaces…
==> core-01: Running provisioner: file…
==> core-01: Running provisioner: shell…
    core-01: Running: inline script

登入你的coreos实例:
$ vagrant ssh
CoreOS stable (717.3.0)
core@core-01 ~ $

在vagrant up时,你可能会遇到如下两个错误:

错误1:

Progress state: VBOX_E_FILE_ERROR
VBoxManage: error: Could not open the medium storage unit '/home1/tonybai/.vagrant.d/boxes/coreos-stable/717.3.0/virtualbox/coreos_production_vagrant_image.vmdk'.
VBoxManage: error: VMDK: inconsistent references to grain directory in '/home1/tonybai/.vagrant.d/boxes/coreos-stable/717.3.0/virtualbox/coreos_production_vagrant_image.vmdk'  (VERR_VD_VMDK_INVALID_HEADER).

这个问题的原因很可能是你的Virtualbox版本不对,比如版本太低,与coreos_production_vagrant.box格式不兼容。可尝试安装一下高版本virtualbox来解决。

错误2:

core-01: SSH address: 127.0.0.1:2222
core-01: SSH username: core
core-01: SSH auth method: private key
core-01: Warning: Connection timeout. Retrying…
core-01: Warning: Connection timeout. Retrying…
core-01: Warning: Connection timeout. Retrying…

coreos虚拟机创建后,似乎一直无法连接上。在coreos的github issue中,有人遇到了这个问题,目前给出的原因是因为cpu的支持虚拟化技术的vt开关没有打开,需要在bios中将其开启。这主要在安装64bit box时才会发生。

到这里,我们已经完成了一个single instance coreos虚拟机的安装。vagrant halt可以帮助你将启动的coreos虚拟机停下来。

$ vagrant halt
==> core-01: Attempting graceful shutdown of VM…

三、  CoreOS cluster

上面虽然成功的安装了coreos,然并卵。在实际应用中,CoreOS多以Cluster形式呈现,也就是说我们要启动多个CoreOS实例。

使用vagrant启动多个coreos实例很简单,只需将配置中的$num_instances从1改为n。

这里我们启用config.rb这个配置文件(将config.rb.sample改名为config.rb),并将其中的$num_instances修改为3:

# Size of the CoreOS cluster created by Vagrant
$num_instances=3

该配置文件中的数据会覆盖Vagrantfile中的默认配置。

三个instance中的etcd2要想组成集群还需要一个配置修改,那就是在etcd.io上申请一个token:

$curl https://discovery.etcd.io/new

https://discovery.etcd.io/fe81755687323aae273dc5f111eb059a

将这个token配置到user-data中的etcd2下:

  etcd2:

    #generate a new token for each unique cluster from https://discovery.etcd.io/new
    #discovery: https://discovery.etcd.io/<token>
    discovery: https://discovery.etcd.io/fe81755687323aae273dc5f111eb059a

我们再来up看看:

$ vagrant up
Bringing machine 'core-01' up with 'virtualbox' provider…
Bringing machine 'core-02' up with 'virtualbox' provider…
Bringing machine 'core-03' up with 'virtualbox' provider…
==> core-01: Checking if box 'coreos-stable' is up to date…
==> core-01: VirtualBox VM is already running.
==> core-02: Importing base box 'coreos-stable'…
==> core-02: Matching MAC address for NAT networking…
==> core-02: Checking if box 'coreos-stable' is up to date…
==> core-02: Setting the name of the VM: coreos-vagrant_core-02_1437388468647_96550
==> core-02: Fixed port collision for 22 => 2222. Now on port 2200.
==> core-02: Clearing any previously set network interfaces…
==> core-02: Preparing network interfaces based on configuration…
    core-02: Adapter 1: nat
    core-02: Adapter 2: hostonly
==> core-02: Forwarding ports…
    core-02: 22 => 2200 (adapter 1)
==> core-02: Running 'pre-boot' VM customizations…
==> core-02: Booting VM…
==> core-02: Waiting for machine to boot. This may take a few minutes…
    core-02: SSH address: 127.0.0.1:2200
    core-02: SSH username: core
    core-02: SSH auth method: private key
    core-02: Warning: Connection timeout. Retrying…
==> core-02: Machine booted and ready!
==> core-02: Setting hostname…
==> core-02: Configuring and enabling network interfaces…
==> core-02: Running provisioner: file…
==> core-02: Running provisioner: shell…
    core-02: Running: inline script
==> core-03: Importing base box 'coreos-stable'…
==> core-03: Matching MAC address for NAT networking…
==> core-03: Checking if box 'coreos-stable' is up to date…
==> core-03: Setting the name of the VM: coreos-vagrant_core-03_1437388512743_68112
==> core-03: Fixed port collision for 22 => 2222. Now on port 2201.
==> core-03: Clearing any previously set network interfaces…
==> core-03: Preparing network interfaces based on configuration…
    core-03: Adapter 1: nat
    core-03: Adapter 2: hostonly
==> core-03: Forwarding ports…
    core-03: 22 => 2201 (adapter 1)
==> core-03: Running 'pre-boot' VM customizations…
==> core-03: Booting VM…
==> core-03: Waiting for machine to boot. This may take a few minutes…
    core-03: SSH address: 127.0.0.1:2201
    core-03: SSH username: core
    core-03: SSH auth method: private key
    core-03: Warning: Connection timeout. Retrying…
==> core-03: Machine booted and ready!
==> core-03: Setting hostname…
==> core-03: Configuring and enabling network interfaces…
==> core-03: Running provisioner: file…
==> core-03: Running provisioner: shell…
    core-03: Running: inline script

$vagrant ssh core-02
CoreOS stable (717.3.0)
core@core-02 ~ $

可以看到Vagrant启动了三个coreos instance。关闭这些instance,同样用halt:

$ vagrant halt
==> core-03: Attempting graceful shutdown of VM…
==> core-02: Attempting graceful shutdown of VM…
==> core-01: Attempting graceful shutdown of VM…

四、小结

以上仅仅是CoreOS最基本的入门,虽然现在安装ok了,但CoreOS的各种服务组件的功用、配置;如何与Docker配合形成分布式服务系统;如何用Google Kubernetes管理容器集群等还需更进一步深入学习,这个后续会慢慢道来。

也谈并发与并行

在一般人的眼中,“并行”就是并行,即你干你的,我干我的,两个“并行”的执行过程可能是两条毫无瓜葛的平行线,也可能是有交叉,但瞬即分开的两条线。不 过在程序员的世界里,有关“并行”的概念却有两个单词:Concurrency和Parallelism,对应的比较主流的中文翻译为并发 (Concurrency)和并行(Parallelism)。

之前一直使用C、Python进行Coding,对Concrrency和Parallelism的异同并不十分关心,也未求甚解。但switch to golang后,尤其是学习2012年Rob Pike的一个talk slide:“Concurrency is not Parallelism(译作:并发不是并行)"后,感觉之前对于“并行”的理解还未到火候。

golang的Author们对文档还是非常看重的。按照目前golang的age来说,其文档的充分性相对于其他语言已经是相对较好的了。golang 的 author们还时不时放出一些blog、talk和slide,以帮助大家编写出more idiomatic的golang程序。Rob Pike的“并发不是并行”就是golang官方站点上的一个talk slide(中文版在这里 )。

Rob Pike是Golang大神,这里先列出他在talk中对于并发与并行的学术阐释和理解:

【Concurrency并发】
Programming as the composition of independently executing processes. (Processes in the general sense, not Linux processes. Famously hard to define.)
将相互独立的执行过程综合到一起的编程技术。(这里是指通常意义上的执行过程,而不是Linux进程。很难定义。)

Concurrency is about dealing with lots of things at once.
并发是指同时处理很多事情。

Concurrency is about structure.
并发关乎结构。

Concurrency provides a way to structure a solution to solve a problem that may (but not necessarily) be parallelizable.
并发提供了一种方式让我们能够设计一种方案将问题(非必须的)并行的解决。

Concurrency is a way to structure a program by breaking it into pieces that can be executed independently.
并发是一种将一个程序分解成小片段独立执行的程序设计方法。

【Parallelism并行】
Programming as the simultaneous execution of (possibly related) computations.
同时执行(通常是相关的)计算任务的编程技术。

Parallelism is about doing lots of things at once.
并行是指同时能完成很多事情。

Parallelism is about execution.
并行关乎执行。

【小结】
They are Not the same, but related.
它们不相同,但相关。

怎么样?看上上面的论述是不是一头雾水啊。Rob Pike也觉得这些概念以及描述过于抽象,于是给了一个具体的“地鼠推车运书”的例子,不过当你看完这个例子后,可能会变得更加糊涂,至少我有这种感觉-地鼠凌乱综合症^_^。这是因为这个例子隐含的结合了Go语言goroutine调度的三个概念:P(虚拟processor上下文)、M(内核线程)和G(Goroutine对象)。如果仅仅从理解并行和并发的差异来说,我们可以抛开go语言,用生活中的例子感觉更适合些。

下面我们就来一个例子来说说明一下并发与并行,从一个程序的设计演进角度来阐述。

问题:说的是一个Gopher早起后的生活,Gopher早起后,有三个任务(或者称为三件事情)要完成:洗漱、早餐、着装。我们来设计一个程序,帮助Gopher高效正确的完成这三件事。

如果你是程序员,要完成这个场景,你可能会这么设计你的程序:

program1:

最简单的思路:这个gopher一件一件事情去完成:

main:
    call 洗漱
    call 早餐
    call 着装

这里我们把Gopher看做是一颗cpu,它按程序逻辑,顺序执行洗漱、早餐和着装三件事。即如下图那样:

现在我们玩个克隆游戏,我们clone出一个与这个Gopher一模一样的Gopher,且两个gopher之间存在着某种超宇宙联系,一个Gopher行为的结果都能反应到另外一个gopher上。我们让这两个Gopher一起来做这三件事情,看看是否能够提速。

遗憾的是,两个Gopher都要从洗漱做起。一个Gopher占用了卫生间开始洗漱,另外一个Gopher只能等着,而没法去做早餐或是着装。当那个 Gopher完成洗漱,后面的这个Gopher由于超联系也同步完成了洗漱,进入下一个环节:早餐。过程还是一样的,只能一个Gopher在餐厅准备早 餐。也就是说这两个Gopher没有一起做事,而是一个做,一个赋闲。因此我们看到两个Gopher并没有加快事情完成的步伐,从过程上来看,即便有更多 的Gopher,也依旧无法提速。我们需要对程序做些改造。

注:首尾相连的红线的总长度 = 完成时间。

program2:

main:
    pthread_create(洗漱)
    pthread_create(早餐)
    pthread_create(着装)

    waitAll

Gopher来执行一遍新程序。由于建立了三个逻辑执行体,因此Gopher在三个执行体间切换,从Gopher的角度去看,Gopher的执行路径如下图:


Program2-1

Gopher不再像上面Program1那样顺序执行了,而是在三个活动间切换,但总时长依旧没有下降。

为了验证该程序在多Gopher下是否有效率提升,我们再玩一次克隆游戏,这次clone出另外两个Gopher,三个Gopher一起来执行该程序,一个可能的执行路径见下图:


Program2-2

每个Gopher绑定一个逻辑执行体,整体完成的总时长下降为原来的三分之一。这次三个Gopher都没有赋闲,真正做到你干你的,我干我的,一起做。

program3:

虽然在program2中,多个Gopher一起工作提升了效率,但那是极限么,还能提高么?我们试想一下三个活动:洗漱、早餐和着装的难易不同,耗时不 同。一个可能的结果是Gopher1完成了洗漱,但Gopher2才准备了一半早餐,Gopher3刚选完上衣。这时Gopher1便开始空闲,无法帮助 Gopher2和Gopher3继续提高效率。我们再试试重新组合一下要完成的任务,让每个Gopher都能执行不同的活动环节。

main:
        c chan job
        for i = 0; i < 3; i++  {
            go gopherworker(c)
        }

        for j := range jobs {
            c <- j
        }
        … …

gopherworker(c chan job):
      for {
         select {
         case <-c:
         … …
      }

以下是一个可能的执行路径图:

到了这里,不知道你是否通过上面程序演进的过程悟道些什么,例子里我通篇没有提到并发或并行。

但从例子可以看出,并发和并行是两个阶段的事情。并发在程序的设计和实现阶段,并行在程序的执行阶段。

在Program1之前,我们只有问题,并无方案。

Program1方案让我们可以解决问题,但从Program1的执行结果来看,Program1并不能并行执行。原因是在设计和实现阶段程序就是按照顺序思路进行的,这就好比底子没打好,在平房的地基上永远不能盖50层的大楼。

Program2-1方案的执行结果与Program1相同,但Program2在设计和实现阶段采用的理念却与Program1完全不同,如果说 Program1打的是平房的地基,那么Program2打的就是大厦的地基,虽然Program2-1上依旧盖的是平房(单Gopher执行)。但 Program2-2显然就是在这样的地基上盖的摩天大楼了(多Gopher执行)。Program2的结构使得Program2在多Gopher下提升 了效率,实现了运行时并行。

Program3更进一步,在设计和实现阶段就本着充分高效的利用多个Gopher的理念,并最终实现了执行阶段的并行。

因此我们在编程语言层面更多谈并发,Golang对外宣传时永远用的是支持并发,而不是支持并行。设计实现阶段好比打地基,不同水准的地基决定了你在这个地基上面是只能盖平房,还是盖高层,还是能盖摩天大楼。

我们再回过头来重温Rob Pike大神关于两者的阐述:“并发关乎结构,并行关乎执行”,是不是感觉意味深长啊,大神就是大神,一句话就能抓住本质。

go 1.5之前默认情况下,Go程序都是不能并行的,因为Go将GOMAXPROCS默认设置为1,这样你仅仅能利用一个内核线程。Go 1.5及以后GOMAXPROCS被默认设置为所运行机器的CPU核数,如果你的机器是多核的,你的Go程序就有可能在运行期是并行的,前提是你在设计程 序时就充分运用了并发的设计理念,否则就会像Program1那样,即便有1w颗CPU,你也只能利用上一颗。

如发现本站页面被黑,比如:挂载广告、挖矿等恶意代码,请朋友们及时联系我。十分感谢! Go语言第一课 Go语言进阶课 AI原生开发工作流实战 Go语言精进之路1 Go语言精进之路2 Go语言第一课 Go语言编程指南
商务合作请联系bigwhite.cn AT aliyun.com

欢迎使用邮件订阅我的博客

输入邮箱订阅本站,只要有新文章发布,就会第一时间发送邮件通知你哦!

这里是 Tony Bai的个人Blog,欢迎访问、订阅和留言! 订阅Feed请点击上面图片

如果您觉得这里的文章对您有帮助,请扫描上方二维码进行捐赠 ,加油后的Tony Bai将会为您呈现更多精彩的文章,谢谢!

如果您希望通过微信捐赠,请用微信客户端扫描下方赞赏码:

如果您希望通过比特币或以太币捐赠,可以扫描下方二维码:

比特币:

以太币:

如果您喜欢通过微信浏览本站内容,可以扫描下方二维码,订阅本站官方微信订阅号“iamtonybai”;点击二维码,可直达本人官方微博主页^_^:
本站Powered by Digital Ocean VPS。
选择Digital Ocean VPS主机,即可获得10美元现金充值,可 免费使用两个月哟! 著名主机提供商Linode 10$优惠码:linode10,在 这里注册即可免费获 得。阿里云推荐码: 1WFZ0V立享9折!


View Tony Bai's profile on LinkedIn
DigitalOcean Referral Badge

文章

评论

  • 正在加载...

分类

标签

归档



View My Stats