zhiye_wang

向星空仰望的越深,越发现自己的渺小

  C++博客 :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理 ::
  31 随笔 :: 1 文章 :: 2 评论 :: 0 Trackbacks

#

ubuntu安装OpenLDAP(二) 配置LDAP

上一篇博文中,我们成功的安装了OpenLDAP-2.4.4到系统中,这篇文章介绍如何配置一个我

们自己的ldap服务器来使用。

1 配置ldap的dc和cn

vim /usr/local/etc/openldap/slapd.conf

修改其中的下面两行:

suffix      "dc=example,dc=com"

rootdn      "cn=Manager,dc=example,dc=com"

我修改后的效果如图:


启动slapd

# su root -c /usr/local/libexec/slapd

验证一下能不能使用:

# ldapsearch -x -b '' -s base'(objectclass=*)'


说明ldap服务器已经可以使用了。

3 新建管理账号
建立一个
cloudsoar.ldif 文件

# vim cloudsoar.ldif

dn: dc=cloudsoar,dc=com

objectclass: dcObject

objectclass: organization

o: cloudsoar company

dc: cloudsoar

 

dn:cn=Manager,dc=cloudsoar,dc=com

objectclass:organizationalRole

cn: Manager

将文件中的内容插入数据库

ldapadd -x -D "cn=Manager,dc=cloudsoar,dc=com"-W -f cloudsoar.ldif 

如果需要密码,我们的默认密码是:secret(位于/usr/local/etc/openldap/slapd.conf


这里可以看到节点已经插入到ldap了。这里的cloudsoar是我起的域名,您也可以根据需要设置一个自己喜欢的域名。

查询一下:

# ldapsearch -x -b 'dc=cloudsoar,dc=com''(objectclass=*)'


这里我还是不放心,从另外一台安装了windows操作系统的电脑上,使用LDAPAdmin.exe 来连接试试。



可以看到我的ldap已经可以使用了。


posted @ 2016-04-20 17:31 zhiye_wang 阅读(315) | 评论 (0)编辑 收藏

ubuntu安装OpenLDAP(附错误的详细解决办法)

下载OpenLDAP源码


 http://www.openldap.org/software/download/

或者

 ftp://ftp.openldap.org/pub/OpenLDAP/openldap-release.tgz


解压到本地

 # gunzip-c openldap-VERSION.tgz | tar xf -

# cd openldap-2.4.44

# ./configure

 configure: error: BDB/HDB: BerkeleyDB notavailable

提示本地没有安装BerkeleyDB数据库

安装BerkeleyDB

 Oracle官网下载:

 http://www.oracle.com/technetwork/database/database-technologies/berkeleydb/downloads/index.html

解压到本地


切换到build_unix 目录

# cd build_unix

# ../dist/configure

# make

# make install

root@cloudsoar-virtual-machine:/home/cloudsoar/db-6.2.23/build_unix#make install

Installing DB include files:/usr/local/BerkeleyDB.6.2/include ...

Installing DB library:/usr/local/BerkeleyDB.6.2/lib ...

libtool: install: cp -p .libs/libdb-6.2.so/usr/local/BerkeleyDB.6.2/lib/libdb-6.2.so

libtool: install: cp -p .libs/db_upgrade/usr/local/BerkeleyDB.6.2/bin/db_upgrade

libtool: install: cp -p .libs/db_verify/usr/local/BerkeleyDB.6.2/bin/db_verify

Installing documentation:/usr/local/BerkeleyDB.6.2/docs ...

查看安装


设置到系统变量

不设置的话,等下安装OpenLDAP时候执行./configure检查时候还会报同样的错

# vim /etc/ld.so.conf

添加一行:/usr/local/BerkeleyDB.6.2/lib/

保存退出。

执行生效:ldconfig –v

继续安装openldap-2.4.44


切换到openldap的源码目录下,重新执行configure文件

./configure CPPFLAGS="-I/usr/local/BerkeleyDB.6.2/include-D_GNU_SOURCE" LDFLAGS="-L/usr/local/BerkeleyDB.6.2/lib"

执行后报错

error: BerkeleyDB version incompatible withBDB/HDB backends

这里找不到原因,后来查看openladp-2.4.44,目录的README文件发现如下内容:


郁闷,原来openldap-2.4.44要求用Oracle Berkeley 4.4-4.8或者5.0-5.1版本的,而我用的是db-6.2.23.tar.gz版本的。

没办法,只有重新去Oracle官网下载一个db-5.1.29.tar.gz版本的。

按照安装Berkeley 6.2的方法再次安装Berkeley DB 5.1

# cd build_unix

# ../dist/configure

# make

# make install

# vim /etc/ld.so.conf

添加一行:/usr/local/BerkeleyDB.5.1/lib/

保存退出。

执行生效:ldconfig –v

 

安装openldap          

切换到openldap-2.4.44目录

./configure CPPFLAGS="-I/usr/local/BerkeleyDB.5.1/include-D_GNU_SOURCE" LDFLAGS="-L/usr/local/BerkeleyDB.5.1/lib"

执行完毕可以看到提示我执行make depand


编译软件

根据http://www.openldap.org/doc/admin24/install.html的安装步骤继续执行

执行命令:make depend


执行命令:make

10 测试软件

根据官方文档说明:Once the software has been properly configured and successfullymade, you should run the test suite to verify the build.

我们也需要测试一下安装是否成功,执行命令:make test


说明安装环境是没问题了。

11 安装openldap到系统

根据官方文档说明:By default OpenLDAP Software is installed in /usr/local. If youchanged this setting with the --prefix configure option, it will be installedin the location you provided.

我们可以加–prefix 参数来指定我们自己想要安装的位置。默认是安装到 /usr/local目录下。

执行命令:su root -c 'make install'


到这里openldap-2.4.44已经成功的安装到我的系统当中。默认的配置文件在 /usr/local/etc/openldap 下。


posted @ 2016-04-20 17:27 zhiye_wang 阅读(976) | 评论 (0)编辑 收藏

     摘要: CentOS安装运行mongo docker镜像背景: 根据需要,我需要安装一个mongoDB数据库,并且需要通过docker镜像作为容器运行这个 mongoDB 数据库步骤:1 下载镜像首先从 docker hub 下载 mongoDB 的 docker 镜像使用 docker search 命令查看有哪些可以下载的镜像12345[root@bogon test]# dock...  阅读全文
posted @ 2016-04-13 11:42 zhiye_wang 阅读(335) | 评论 (0)编辑 收藏

Go 语言教程笔记(

一 Go语言决策

if 语句

if语句包含一个布尔表达式后跟一个或多个语句

语法

if语句在Go编程语言的语法是:

if(boolean_expression)

{

   /* statement(s) will execute if the boolean expression is true */

如果布尔表达式的值为 true,那么if语句里面代码块将被执行。如果if语句的结束(右大括号后)

布尔表达式的值为false,那么语句之后第一行代码会被执行。

例子:

package main  import "fmt"  func main() {    /* local variable definition */    var a int = 10      /* check the boolean condition using if statement */    if( a < 20 ) {        /* if condition is true then print the following */        fmt.Printf("a is less than 20\n" )    }    fmt.Printf("value of a is : %d\n", a) }

让我们编译和运行上面的程序,这将产生以下结果:

a is less than 20; value of a is : 10

if else 语句

if语句可以跟着一个可选的else语句,布尔表达式是假时它被执行。

语法

在Go编程语言中的if ... else语句的语法是:

if(boolean_expression) {    /* statement(s) will execute if the boolean expression is true */ } else {   /* statement(s) will execute if the boolean expression is false */ }

如果布尔表达式的值为true,那么if代码块将被执行,否则else代码块将被执行

例子:

package main  import "fmt"  func main() {    /* local variable definition */    var a int = 100;      /* check the boolean condition */    if( a < 20 ) {        /* if condition is true then print the following */        fmt.Printf("a is less than 20\n" );    } else {        /* if condition is false then print the following */        fmt.Printf("a is not less than 20\n" );    }    fmt.Printf("value of a is : %d\n", a);  }

当上述代码被编译和执行时,它产生了以下结果:

a is not less than 20; value of a is : 100

if...else if...else 语句

if语句可以跟着一个可选的else if ... else语句,这是非常有用的使用单个 if...else if 语句声明测试各种条件。

当使用if , else if , else语句有几点要记住使用:

if可以有零或一个else,它必须跟从else if后面。

一个if可以有零到个多else if并且它们必须在else之前。

一旦一个else if测试成功,其它任何剩余else if将不会被测试。

语法

if...else if...else在Go编程语言中语句的语法是:

if(boolean_expression 1) {    /* Executes when the boolean expression 1 is true */ } else if( boolean_expression 2) {    /* Executes when the boolean expression 2 is true */ } else if( boolean_expression 3) {    /* Executes when the boolean expression 3 is true */ } else  {    /* executes when the none of the above condition is true */ }

例子:

package main  import "fmt"  func main() {    /* local variable definition */    var a int = 100      /* check the boolean condition */    if( a == 10 ) {        /* if condition is true then print the following */        fmt.Printf("Value of a is 10\n" )    } else if( a == 20 ) {        /* if else if condition is true */        fmt.Printf("Value of a is 20\n" )    } else if( a == 30 ) {        /* if else if condition is true  */        fmt.Printf("Value of a is 30\n" )    } else {        /* if none of the conditions is true */        fmt.Printf("None of the values is matching\n" )    }    fmt.Printf("Exact value of a is: %d\n", a ) }

让我们编译和运行上面的程序,这将产生以下结果

None of the values is matching Exact value of a is: 100

switch 语句

switch语句可以让一个变量对反对值的列表平等进行测试。每个值被称为一个的情况(case),

变量被接通检查每个开关盒(switch case)。

在Go编程,switch有两种类型。

 表达式Switch - 在表达式switch,case包含相比较,switch表达式的值。

 类型Switch - 在这类型switch,此时含有进行比较特殊注明开关表达式的类型。

 表达式Switch

在Go编程语言中表达switch语句的语法如下:

switch(boolean-expression or integral type){     case boolean-expression or integral type  :        statement(s);           case boolean-expression or integral type  :        statement(s);      /* you can have any number of case statements */     default : /* Optional */        statement(s); }

以下规则适用于switch语句:

在switch语句中使用的表达式必须具有整体或布尔表达式,或者是一个类型,其中所述类具有

一个单一的转换函数,以一个整体或布尔值。如果表达不通过,默认值是true。可以有任意数

量的case语句在switch内。每个case后跟值进行比较,以及一个冒号。constant-expression 

的情况,必须是相同的数据类型,在switch的变量,它必须是一个常量或文字。

当变量被接通等于case的值,以下case中将执行语句。在case语句中break不是必需。

switch语句可以有一个可选默认情况下,它必须出现在开关结束。缺省情况下,可用于执行任

务时没有的case为true。则case在默认情况下也不是必须的。

例子

package main  import "fmt"  func main() {    /* local variable definition */    var grade string = "B"    var marks int = 90     switch marks {       case 90: grade = "A"       case 80: grade = "B"       case 50,60,70 : grade = "C"       default: grade = "D"      }     switch {       case grade == "A" :          fmt.Printf("Excellent!\n" )            case grade == "B", grade == "C" :          fmt.Printf("Well done\n" )             case grade == "D" :          fmt.Printf("You passed\n" )             case grade == "F":          fmt.Printf("Better try again\n" )       default:          fmt.Printf("Invalid grade\n" );    }    fmt.Printf("Your grade is  %s\n", grade );       }

当上述代码被编译和执行时,它产生了以下结果:

Well done Excellent! Your grade is  A

类型Switch

在Go编程语言的一个类型switch语句的语法如下:

switch x.(type){     case type:        statement(s);           case type:        statement(s);      /* you can have any number of case statements */     default: /* Optional */        statement(s); }

以下规则适用于switch语句:

在switch语句中使用必须有接口的变量表达式{}输入。

在switch内可以有任意数量case语句。每一种case后跟的值进行比较,以及一个冒号。

case 类型必须是相同的数据类型,在switch的变量,它必须是一个有效的数据类型。

当变量被接通等于某一case中的值,以下case语句将执行。在case语句块的break不是必需的。

switch语句可以有一个可选默认case,它必须出现在switch的结束。缺省情况下,可用于执行

任务时没有匹配case时。default不是必需的。

例子

package main  import "fmt"  func main() {    var x interface{}          switch i := x.(type) {       case nil:	            fmt.Printf("type of x :%T",i)                       case int:	            fmt.Printf("x is int")                              case float64:          fmt.Printf("x is float64")                  case func(int) float64:          fmt.Printf("x is func(int)")                             case bool, string:          fmt.Printf("x is bool or string")              default:          fmt.Printf("don't know the type")         }    }

让我们编译和运行上面的程序,这将产生以下结果:

type of x :<nil>

 select语句

select语句的语法如下:

select {     case communication clause  :        statement(s);           case communication clause  :        statement(s);      /* you can have any number of case statements */     default : /* Optional */        statement(s); }

以下规则适用于select语句:

可以有任意数量的范围内选择一个case语句。每一种情况下后跟的值进行比较,以及一个冒号。

对于case的类型必须是一个通信通道操作。

当通道运行下面发生的语句这种情况将执行。在case语句中break不是必需的。

select语句可以有一个可选默认case,它必须出现在select的结束前。缺省情况下,可用于执行

任务时没有的情况下是真实的。在默认情况下break不是必需的。

例如:

package main  import "fmt"  func main() {    var c1, c2, c3 chan int    var i1, i2 int    select {       case i1 = <-c1:          fmt.Printf("received ", i1, " from c1\n")       case c2 <- i2:          fmt.Printf("sent ", i2, " to c2\n")       case i3, ok := (<-c3):  // same as: i3, ok := <-c3          if ok {             fmt.Printf("received ", i3, " from c3\n")          } else {             fmt.Printf("c3 is closed\n")          }       default:          fmt.Printf("no communication\n")    }     }   

让我们编译和运行上面的程序,这将产生以下结果:

no communication

posted @ 2016-03-28 16:54 zhiye_wang 阅读(154) | 评论 (0)编辑 收藏

Go 语言教程笔记(二)

一 Go 语言常量

常量是指该程序可能无法在其执行期间改变的固定值。这些固定值也被称为文字。

常量可以是任何像一个整型常量,一个浮点常量,字符常量或字符串文字的基本数据类型。还

有枚举常量。常量是一样,只是它们的值不能自己定义后进行修改常规变量处理。

整形常量

一个整数文字也可以有一个后缀为U和L的组合,分别为无符号和长整型。后缀可以是大写或小

写,并且可以以任意顺序。可以是十进制,八进制,或十六进制常数。前缀指定基或基数:0x

或 0X 的十六进制,0 表示八进制,并没有十进制。

整数常量的一些例子:

212         /* Legal */

215u        /* Legal */

0xFeeL      /* Legal */

078         /* Illegal: 8 is not an octal digit */

032UU       /* Illegal: cannot repeat a suffix */

不同类型的整型常量的例子:

85         /* decimal */

0213       /* octal */

0x4b       /* hexadecimal */

30         /* int */

30u        /* unsigned int */

30l        /* long */

30ul       /* unsigned long */

浮点文本(常量)

浮点字面具有一个整数部分,一个小数点,一个小数部分,和一个指数部分。你可以表示十进

制形式或指数形式浮点文字。同时采用十进制形式表示,则必须包括小数点,指数,或两者并

用而指数形式表示,则必须包括整数部分,小数部分,或者两者兼而有之。有符号的指数,通

过e或E表示。

下面是浮点面值的一些例子:

3.14159       /* Legal */

314159E-5L    /* Legal */

510E          /* Illegal: incomplete exponent */

210f          /* Illegal: no decimal or exponent */

.e55          /* Illegal: missing integer or fraction */

字符串文字

字符串文字或常量用双引号“”。一个字符串包含类似于字符文字字符:普通字符,转义序列

和通用字符。可以使用字符串和分隔使用空格打破一个长行成多行。

"hello, dear"

"hello, 

dear"

"hello, " "d" "ear"

const 关键字

package main

import "fmt"

func main() {

   const LENGTH int = 10

   const WIDTH int = 5   

   var area int

   area = LENGTH * WIDTH

   fmt.Printf("value of area : %d", area)   

}

习惯大写定义常量是一个良好的编程习惯。

二 Go 语言运算符

Go语言有丰富的内置运算符和运算符:

算术运算符

关系运算符

逻辑运算符

位运算符

赋值运算符

其它运算符


算术运算符

运算符描述示例
+两个操作数相加A + B = 30
-第一个操作数减第二操作数A - B = -10
*两个操作数相乘A * B = 200
/通过去分子除以分母B / A = 2
%模运算和整数除法后的余数B % A = 0
++运算符递增整数值增加一A++ = 11
--运算符递减整数值减一A-- = 9

关系运算符

运算符描述示例
==检查两个操作数的值是否相等,如果是的话那么条件为真。(A == B) 不为 true.
!=检查两个操作数的值是否相等,如果值不相等,则条件变为真。(A != B) 为true.
>检查左边的操作数的值是否大于右操作数的值,如果是的话那么条件为真。(A > B) 不为 true.
<检查左边的操作数的值是否小于右操作数的值,如果是的话那么条件为真。(A < B) 为 true.
>=检查左边的操作数的值是否大于或等于右操作数的值,如果是的话那么条件为真。(A >= B) 不为 true.
<=检查左边的操作数的值是否小于或等于右操作数的值,如果是的话那么条件为真。(A <= B) 为 true

逻辑运算符

&&所谓逻辑与运算符。如果两个操作数都非零,则条件变为真。(A && B) 为 false.
||所谓的逻辑或操作。如果任何两个操作数是非零,则条件变为真。(A || B) 为 true.
!所谓逻辑非运算符。使用反转操作数的逻辑状态。如果条件为真,那么逻辑非操后结果为假。!(A && B) 为 true.

位运算符

pqp & qp | qp ^ q
00000
01011
11110
10011

假设,如果A =60;且b =13;现在以二进制格式它们如下:

A = 0011 1100

B = 0000 1101

-----------------

A&B = 0000 1100

A|B = 0011 1101

A^B = 0011 0001

~A  = 1100 0011

C语言支持位运算符列在如下表。假设变量A=60和变量B=13,则

其它运算符

还有其他一些重要的运算符,包括sizeof和?:在Go语言中也支持。

Go语言运算符优先级

分类 运算符 关联 
后缀() [] -> . ++ - -  从左到右
一元+ - ! ~ ++ - - (type)* & sizeof 从右到左
乘法* / % 从左到右
相加  + - 从左到右 
移动<< >> 从左到右
关系< <= > >= 从左到右
相等== != 从左到右
按位与从左到右
按位异或从左到右
按位或 从左到右
逻辑与 && 从左到右
逻辑或 || 从左到右
条件 ?: 从左到右
赋值= += -= *= /= %=>>= <<= &= ^= |= 从右到左
逗号 从左到右
posted @ 2016-03-28 16:17 zhiye_wang 阅读(291) | 评论 (0)编辑 收藏

Go 语言教程笔记(一)

一 Go 语言环境设置 

本地环境设置

在这里我们介绍设置Go编程语言环境,需要在你的计算机上的准备以下两个软件,(A)文本编

辑器和(B)Go编译器。

文本编辑器

我的环境是ubuntu,直接用 vim

Go编译器

ubuntu下面直接安装

# apt-get install golang


例子:

# vim hello.go

  1 package main

  2 

  3 import fmt "fmt"

  4 

  5 func main() {

  6     fmt.Printf("Hello, world; or Καλημέρα κόσμε; or こんにちは 世界 ");

  7 }                                                                        

go语言中如果有if等后面需要跟大括号的语句,强制使用大扩号跟if写在一行


编译运行:

# go run hello.go 

Hello, world; or Καλημέρα κόσμε; or こんにちは 世界


二 Go 语言程序结构 

在我们学习Go编程语言的基本构建模块,看看一个最低限度的Go程序结构,这样我们

就可以把它作为即将到来的章节的参考。

Go 程序包含以下部分

包声明

导入包

函数

变量

语句和表达式

注释

例如:

 1 package main

  2 

  3 import fmt "fmt"

  4 

  5 func main() {

  6     fmt.Printf("Hello, world; or Καλημέρα κόσμε; or こんにちは 世界 ");

  7 }  

第一行定义了这个程序包的名称。这是一个必须声明为Go程序运行在什么包。main包是起始

点来运行程序。每个包都有一个与之关联的路径和名称。

下一行import "fmt" 是告诉编译器去包含文件在包fmt的预处理命令。

下一行 func main()主要功能是为程序执行的开始。

如果有注释,/*...*/会被编译器被忽略,它已被加入到程序添加注释。因此,这样的行称为程

序中的注释。注释也使用//类似于Java或C++注释。

下一行 fmt.Println(...)是提供另一种功能,使消息“Hello, World!”要显示在屏幕上。这

里fmt包已导出。


三 Go 语言的基本语法

标识符

Go语言不允许标识符中的标点字符,如@,$和%。

Go是一种区分大小写的编程语言

Manpower 和 manpower 在Go中是两个不同的标识符

标识符开始以字母A到Z或a到z或下划线_后跟零个或多个字母,下划线和数字(0〜9)

关键词

下面的列表显示了Go的保留字。这些保留的字可以不被用作常量或变量,或任何其他的标识符

名称。

break  default  func  interface  select

case  defer  go  map  struct

chan  else  goto  package  switch

const  fallthrough  if  range  type

continue  for  import  return  var

在 Go 中空白格

仅包含空格,可能与注释行,被称为一个空行,Go编译器完全忽略它。

var age int;

必须有至少一个空白字符(通常是一个空格)int和age之间的编译器,以便能够区分它们

fruit = apples + oranges;   // get the total fruit

fruit和=之间或=和apples,虽然是自由的,如果想便于阅读的目的,最好包括一些空格


四 Go 语言数据类型

在Go编程语言,数据类型指用于声明变量或不同类型的功能的广泛的系统。变量的类型决定了

有多少空间占用的存储和存储方式的位模式将被解释。

Go的数据类型可分类如下:

Boolean Types

它们是布尔类型,它由两个预定义的常量:(a) true (b) false

Numeric Types

它们是算术类型,表示整数类型或b。在整个程序浮点值

string types:

一个字符串类型代表组字符串值。它的值是一个字节序列。字符串是一次创造了稳定的类型,

这是不可能改变一个字符串的内容。预声明的字符串类型为字符串。

Derived types:

它们包括:(a)指针类型,(b)数组类型,(c)结构类型,(d)联盟类型及(e)函数类型(f)切片类(g)

函数类型(h)接口类型(i)地图类型(j)管道类型。

数组类型和结构类型被统称为聚合类型。函数的类型指定的一组具有相同的参数和结果类型所

有函数。

整数

1 uint8

8位无符号整数 (0 - 255)

2 uint16

16位无符号整数 (0 - 65535)

3 uint32

32位无符号整数 (0 - 4294967295)

4  uint64

64位无符号整数 (0 - 18446744073709551615)

5  int8

有符号8位整数 (-128 - 127)

6  int16

有符号16位整数 (-32768 - 32767)

7  int32

有符号的32位整数 (-2147483648 - 2147483647)

8  int64

有符号的64位整数 (-9223372036854775808 - 9223372036854775807)

浮点类型

1  float32

IEEE-754 32-bit 浮点数

2  float64

IEEE-754 64-bit 浮点数

3  complex64

复数与float32实部和虚部

4  complex128

复数与float64实部和虚部

其他数值类型

1  byte

相同于 uint8

2  rune

相同于 int32

3  uint

32 或 64 位

4  int

相同于 uint 的大小

5  uintptr

一个无符号整数来存储指针值的解释的比特位


五 Go 语言变量

变量是什么,只不是给定到存储区域,我们的程序可以操纵的名称。在Go中每个变量具有特定

的类型,它确定的大小和可变的存储器的布局;能确定存储器内存储的值的范围;和组操作可以施

加到变量。

一个变量名可以由字母,数字和下划线。它必须以字母或下划线。大写和小写字母是不同的,因

为Go是区分大小写的。基于该基本类型在前面的章节中说明的那样,将有以下基本变量类型:

byte  通常单个字节(一个字节),这是一个字节的类型

int  整数最自然的尺寸的机器

float32  单精度浮点值

Go编程语言也可以定义各种其他类型的变量,我们将在以后的章节列出,如:枚举,指针,数

组,结构,联合,等等。

Go中变量定义

var variable_list optional_data_type;

optional_data_type可以包括字节,整型,float32,complex64,布尔或任何用户定义的对象

等有效Go的数据类型,variable_list可以由用逗号分隔的一个或多个标识符名称。一些有效的声

明如下所示:

var    i, j, k int;

var   c, ch byte;

var  f, salary float32;

d = 42;

var i, j, k; 既声明并定义了变量i,j和k;这指示编译器创建一个名为i,j和k的 int类型变量。变量

可以再声明时候初始化。变量的类型是由编译器自动根据传递给它的值判断。

variable_name = value;

d = 3, f = 5;    // declaration of d and f. Here d and f are int 

对于没有初始化定义:具有静态存储时间变量的隐含零初始化(所有字节的值为0);所有其它变量

的初始值是它们的数据类型的零值。

静态类型声明

package main

import "fmt"

func main() {

   var x float64

   x = 20.0

   fmt.Println(x)

   fmt.Printf("x is of type %T ", x)

}

编译运行结果是:

20

x is of type float64

动态类型声明/类型推断

示例

试试下面的例子,其中的变量已经声明没有任何类型的,并已确定在主函数中初始化。如果类型推断的,我们已经初始化的变量y使用:=运算符,x初始化使用=运算符。

package main

import "fmt"

func main() {

   var x float64 = 20.0

   y := 42 

   fmt.Println(x)

   fmt.Println(y)

   fmt.Printf("x is of type %T ", x)

   fmt.Printf("y is of type %T ", y)  

}

编译和运行上面的程序,这将产生以下结果:

20

42

x is of type float64

y is of type int

混合变量声明

不同类型的变量可以一步到位使用类型推断声明。

package main

import "fmt"

func main() {

   var a, b, c = 3, 4, "foo"  

   fmt.Println(a)

   fmt.Println(b)

   fmt.Println(c)

   fmt.Printf("a is of type %T ", a)

   fmt.Printf("b is of type %T ", b)

   fmt.Printf("c is of type %T ", c)

}

编译和运行上面的程序,这将产生以下结果:

3

4

foo

a is of type int

b is of type int

c is of type string

posted @ 2016-03-28 15:33 zhiye_wang 阅读(315) | 评论 (0)编辑 收藏

     摘要: Rancher 快速上手指南操作(1)该指南知道用户如何快速的部署Rancher Server 管理容器。前提是假设你的机器已经安装好docker了。1 确认 docker 的版本,下面是 ubuntu 的输出[#63#cloudsoar@cloudsoar-virtual-machine ~]$sudo docker version[sudo] password for cl...  阅读全文
posted @ 2016-03-17 11:03 zhiye_wang 阅读(5952) | 评论 (0)编辑 收藏

第四章 使用Docker镜像和仓库(二)

回顾:

开始学习之前,我先pull下来ubuntu和fedora镜像

[#9#cloudsoar@cloudsoar-virtual-machine ~]$sudo docker pull fedora

Using default tag: latest

latest: Pulling from library/fedora

9bdb5101e5fc: Pull complete 

Digest: sha256:1fa98be10c550ffabde65246ed2df16be28dc896d6e370dab56b98460bd27823

Status: Downloaded newer image for fedora:latest

[#10#cloudsoar@cloudsoar-virtual-machine ~]$sudo docker pull ubuntu

Using default tag: latest

latest: Pulling from library/ubuntu

ebe73f29e6e1: Pull complete 

4976a0f2dc03: Pull complete 

5c117067c385: Pull complete 

001d664e2dd4: Pull complete 

Digest: sha256:7eb6ad74ec4fbe56ac194d8760063c88ca362f05a9038f2bc4f09a51849a4a53

Status: Downloaded newer image for ubuntu:latest

4.5.6 Dockerfile 和构建缓存

想略过缓存功能,可以使用 docker build 的 --no-cache 标志

sudo docker build --no-cache -t="zhiyewang/static_web" .

4.5.7 基于构建缓存的 Dockerfile 模板

FROM ubuntu:14.04

MAINTAINER zhiyewang "zhiye_wang@yeah.net"

ENV REFRESHED_AT 2016-03-16

RUN apt-get -qq update

这里要想重新构建 Dockerfile ,只需要将第三行的日期修改以下即可。将会更新 APT 包的缓

存。

4.5.8 查看新镜像

查看镜像如何构建出来,可以使用 docker history 命令。可以看到新构建的 zhiyewang/stat

 ic_web 镜像的每一层。以及创建这些层的 Dcoekrfile 命令。

4.5.9 从构建的新镜像启动容器

上一节成功使用 Dockerfile 命令构建出 zhiyewang/static_web 这个镜像。现在我们来试试

看镜像是否工作正常。z

基于新构建的镜像启动一个新容器。

 

[#17#cloudsoar@cloudsoar-virtual-machine ~]$sudo docker run -d -p 80 --name stati

c_web zhiyewang/static_web nginx -g "daemon off;"

d4d9024c688d267761dee792e0b0686a6b2d06dcf53e656c98d95408f4894974

这条命令基于方才构建的镜像名字,启动了一个名为 static_web 的新容器。 同时指定了 -d 选

项,告诉 Docker 以分离的方式在后台运行。同时也指定了在新容器中运行的命令: nginx -g "

daemon off;"。这将以前台的方式启动 Nginx。新标志 -p 用来控制 Docker 在运行时应该公

开哪些网络端口给外部(宿主机)。

 

[#19#cloudsoar@cloudsoar-virtual-machine ~]$sudo docker ps -l

CONTAINER ID        IMAGE                            COMMAND                           PORTS                  

d4d9024c688d        zhiyewang/static_web   "nginx -g 'daemon off"         0.0.0.0:32768->80/tcp 

可以看到容器中的 80 端口被映射到宿主机的 32768 端口。

也可以使用 docker port 查看端口的情况

[#20#cloudsoar@cloudsoar-virtual-machine ~]$sudo docker port d4d9024c688d

80/tcp -> 0.0.0.0:32768

这样的端口映射方式为随机的,我们也可以指定特定的端口映射

将容器的 80 端口绑定到本地宿主机的 80 端口

sudo docker run -d -p 80:80 --name static_web zhiyewang/static_web nginx -g "daemon off;"

将容器的 80 端口绑定到本地宿主机的 8080 端口

sudo docker run -d -p 8080:80 --name static_web zhiyewang/static_web nginx -g "daemon off;"

将容器的 80 端口绑定到本地宿主机的 127.0.0.1 这个 IP 的 80 端口

sudo docker run -d -p 127.0.0.1:80:80 --name static_web zhiyewang/static_web nginx -g "daemon off;"

将容器的 80 端口绑定到本地宿主机的 127.0.0.1 这个 IP 的随机端口

sudo docker run -d -p 127.0.0.1::80 --name static_web zhiyewang/static_web nginx -g "daemon off;"

对外公开端口,此命令可以将容器内的 80 端口对本地宿主机公开,并且绑定要宿主机的一个

随机端口。此命令同时也会将 Dockerfile 文件中 EXPOSE 指令指定的其他端口一并公开。

sudo docker run -d -p --name static_web zhiyewang/static_web nginx -g "daemon off;"

这样我们就可以使用本地宿主机的 IP 地址或者 127.0.0.1 的 localhost 来连接到运行的容器,

查看 Web 服务器的内容了。

[#33#cloudsoar@cloudsoar-virtual-machine ~]$curl localhost:32768

Hi, I am in your container

4.5.10 Dockerfile 指令

1 CMD 指令

CMD 指令用于指定一个容器启动时候需要运行的指令。有点类似于 RUN 指令,区别是 RUN 

指令是指定镜像被构建时候运行的指令,而 CMD 是容器被启动时运行的指令。

命令行启动容器的 /bin/true

[#34#cloudsoar@cloudsoar-virtual-machine ~]$sudo docker run -i -t zhiyewang/static_web /bin/true

可以使用 CMD 写在 Dockerfile 中:

CMD ["/bin/true"]

也可以为要运行的命令指定参数

CMD ["/bin/bash", "-l"]

需要注意的是 docker run 命令可以覆盖 CMD 指令。如果 dockerrun 中指定了命令,而CM

 D 中也指定了相同的命令,命令行中的指令会覆盖 Dockerfile 中的 CMD 指令。

假设我们的 Dockerfile 中有如下命令

CMD [ "/bin/bash" ]

使用 docker build 命令构建一个新镜像,假设为 zhiyewang/test,并基于此镜像启动一个新

容器。

[#35#cloudsoar@cloudsoar-virtual-machine ~]$sudo docker run -t -i zhiyewang/test

root@7ec0a03d41fc:/# 

可以看到 docker run 命令的末尾并没有指定 /bin/bash 指令,却进入了容器的 bash。实际上

Docker 使用了 CMD 中指定的命令。

但是 Dockerfile 中只能指定一条 CMD 指令。如果制定多个,只有最后一个会被调用。

2 ENTRYPOINT

ENTRYPONIT 指令提供的命令不会再容器启动时被命令行覆盖。

ENTRYPONIT ["/usr/sbin/nginx"]

为 ENTRYPOINT 指定参数

ENTRYPONIT ["/usr/sbin/nginx", "-g", "daemon off;"]

如果需要 也可以在运行时通过 docker run 的 --entrypoint 标志覆盖 ENTRYPOINT 指令。

3 WORKDIR

WORKDIR /opt/webapp/db

RUN bundle install

WORKDIR /opt/webapp

ENTRYPOINT [ "rackup" ]

把目录切换到 /opt/webapp/db 指定了 bundle install 命令,然后又将工作目录切换为 /opt

 /webapp 最后这只了 ENTRYPOINT 指令来启动 rackup 命令。

4 ENV

ENV 可以用来在镜像构建过程中设置环境变量

ENV RMV_PATH /home/rvm/

这个环境变量设置后在后续的任何 RUN 中都可以使用

也可以在其他指令中直接使用这些环境变量 

RVM_PATH=/home/rvm/ gem install unicorn

ENV 创建的环境变量也会被持久保存到从我们的镜像创建的任何容器中。比如在容器中运行

env 查看:

root@7ec0a03d41fc:/# env

... 

RVM_PATH=/home/rvm/

运行时环境变量

sudo docker run -ti -e  "WEB_PORT=8080" ubuntu env

可以讲容器的 WEB_PORT 环境变量设置为 8080

5 USER

user 指令用来指定该镜像会以什么样的用户去执行

USER nginx

我们可以指定用户名或者 UID 以及组或者 GID,甚至是两者的组合。也可以在 docker run 命

令中通过 -u 选项来覆盖该指令的值。如果不通过 USER 指定特定用户,默认是 root 。

6 VOLUME

VOLUME ["/opt/project"]

这条指令将会为基于此镜像创建的任何容器创建一个名为 /opt/projiect 的挂载点。也可以通过

数组的方式指定多个卷。

VOLUME ["/opt/project", "/data"]

7 ADD

ADD 命令用来将构建环境下的文件和目录复制到镜像中。也可以指定URL。Docker 通过目的地

址的参数末尾的字符来判断文件源是目录还是文件。如果目的地址以 / 结尾,Docker 认为是一个

目录,如果不是的话,认为是文件。

ADD http://wordpress.org/latest.zip /root/wordpress.zip

ADD 在处理本地的归档文件(包括 gzip,bzip2,xv)指定为源文件时候,会自动将归档解压。

ADD latest.tar.gz /var/www/wordpress/

8 COPY

COPY 和 ADD 的本质区别是 COPY 只关心在构建上下文中复制本地文件,而不会去做文件提

取和解压的工作。COPY 的文件源路径必须是一个与当前构建环境相对的文件或目录,本地文

件都放到和 Dockerfile 同一个目录下。不能复制该目录之外的任何文件。目的为止必须是容器

内部的一个绝对路径。该指令创建的文件或者目录的 UID 和 GID 都会被设置为 0 。

COPY conf.d/ /etc/apache2/

9 ONBUILD

 

4.6 将镜像退送到 Docker Hub

[#37#cloudsoar@cloudsoar-virtual-machine ~]$sudo docker push zhiyewang/static_web

The push refers to a repository [docker.io/zhiyewang/static_web] (len: 1)

e97eb7ef0136: Pushed 

6a7a53f6e78a: Pushed 

ddc8935b098a: Pushed 

40fa5cd1c3d2: Pushed 

c5aed3a8ff95: Pushed 

0b427fcc4cbb: Pushed 

9d89fd8f8a3e: Pushed 

073de23ee32b: Pushed 

latest: digest: sha256:152eb2d70e0f795fbe1b8f8c9eea09e7832a8b01e953cc051cd07832732da0ed size: 14731

现在可以在 Docker Hub 上看到我们的镜像了。

 

自动构建

 

4.7 删除镜像

如果不需要一个镜像了 可以使用 docker rmi 来删除

[#41#cloudsoar@cloudsoar-virtual-machine ~]$sudo docker rmi zhiyewang/static_web

Error response from daemon: conflict: unable to remove repository reference "zhiyewang/static_web" (must force) - container 7ec0a03d41fc is using its referenced image e97eb7ef0136

Error: failed to remove images: [zhiyewang/static_web]

可以看到这个镜像被一个容器 7ec0a03d41fc 使用着,首先删除掉容器即可。 

[#53#cloudsoar@cloudsoar-virtual-machine ~]$sudo docker rm 7ec0a03d41fc

7ec0a03d41fc

[#62#cloudsoar@cloudsoar-virtual-machine ~]$sudo docker rmi e97eb7ef0136

Deleted: e97eb7ef013619e503bd729596a06e46ee85786619d95950e54f5a74c6fc2694

Deleted: 6a7a53f6e78a802ea932a5914e63d217acf4a47ddbedb80dab042d55297573a5

Deleted: ddc8935b098a0b449a3335286b2b0e555b3d44bd5d92dea305c57f6f7c846fae

Deleted: 40fa5cd1c3d2ae9c80763e9b787c5c9b4848a34164fc2138d2c160830505466d

Deleted: c5aed3a8ff9508b42644cef59c2b44c249628c54130fa1a030f3f2b299124ecc

这里删除的是本地的镜像。每一个 Deleted: 行都代表一个镜像层被删除。

4.8 运行自己的 Docker Registry

这个可以自己试试了。

 

到此为止,第四章学习完毕。

下一篇学习在测试中使用 Docker,用Docker 测试一个静态网站,用 Docker 创建并测试一个

WEB 应用,用 Docker 用于持续集成

posted @ 2016-03-17 11:01 zhiye_wang 阅读(656) | 评论 (0)编辑 收藏

第4章 使用Docker镜像和仓库

回顾:

回顾如何使用 docker run 创建最基本的容器

$sudo docker run -i -t --name another_container_mum ubuntu /bin/bash

root@3d49f5830c81:/# 

这条命令会启动一个新的名为 another_container_mum 的容器,这个容器基于ubuntu镜

像并且会启动Bash Shell

---------------------------------------------------------------------------------------------

4.1 什么是 Docker 镜像

4.2 列出镜像


可以看出我这里有三个镜像。

其中 ubuntu 是我上午下载的 ubuntu 基础镜像,paulcos11/docker-tutorial 是下载的另外

一个用户上传的镜像。但是不知道 CREATED 这一栏的时间怎么不准。

镜像从仓库下载下来。镜像保存在仓库中。而仓库存在于Registry中。默认的Registry是由Do

cker公司运营的公共 Registry 服务,即是 Dcoker Hub。

每个镜像库都可以存放很多镜像,例如我们查看一下ubuntu仓库中的其他镜像,

可是使用 docker images 查看所有的 ubuntu docker 镜像

sudo docker images

可以使用docker pull下载某个基础镜像

[#12#cloudsoar@cloudsoar-virtual-machine ~]$sudo docker pull ubuntu

 

Docker Hun 中有两种类型仓库:用户仓库和顶层仓库。用户仓库的镜像都是有Docker用户

创建的,而顶层仓库则是由Docker内部的人来管理的。用户仓库的命名由用户名和仓库名两

部分组成,如:paulcos11/docker-tutorial,用户名:paulcos11,仓库名:docker-tutor

ial,与其相对的顶层仓库只包含仓库名部分,例如 ubuntu,fedora。顶层仓库由Docker公

司和由选定的能提供优质基础镜像的厂商管理。

4.3 拉取镜像

使用docker images可以查看本地Docker宿主机上面的镜像。如果希望能在镜像列表中只看

到某个镜像的内容,例如 fedora,可以通过在 docker images 命令后面跟指定的镜像名来实

现,例如: 

使用 docker pull 拉取镜像

[#15#cloudsoar@cloudsoar-virtual-machine ~]$sudo docker pull fedora

Using default tag: latest

latest: Pulling from library/fedora

6888fc827a3f: Pull complete 

9bdb5101e5fc: Downloading [===================>                               ] 28.63 MB/74.33 MB

4.4 查找镜像

我本地的镜镜像有:

[#1#cloudsoar@cloudsoar-virtual-machine ~]$sudo docker images

[sudo] password for cloudsoar: 

REPOSITORY                         TAG                 IMAGE ID               CREATED             VIRTUAL SIZE

paulcos11/docker-tutorial   latest              e37931352714        8 days ago          587.8 MB

ubuntu                                  latest              8ed581e3fa7a        11 days ago         188 MB

此时 fedora 镜像还是没有下载完毕的。不着急。我们先练习其他的操作,在 paulcos11/do

cker-tutorial 镜像中使用 docker run 命令来从 docker-tutorial 创建一个容器。

[#2#cloudsoar@cloudsoar-virtual-machine ~]$sudo docker run -i -t paulcos11/docker-tutorial /bin/bash

root@869a3b2049ad:/#

可以看到,已经从 paulcos11/docker-tutorial 镜像启动了一个新的容器。

4.5 构建镜像

构建 Docker 镜像有以下两种方法:

使用 docker commit 命令。

使用 docker build 命令和 Dockerfile 文件。

4.5.1 创建 Docker Hub 账号

在 hub.docker.com 创建一个自己的账号,注册之后通过收到的确认邮件激活,下面就可以测

试刚才注册的账号是否可以工作了。要登录到 docker hub,可以使用 docker login 命令。如

这里看到我是注册成功了,用户名只能是字母或者数组的组合。下面使用 docker login 来验证

我的账号:

[#4#cloudsoar@cloudsoar-virtual-machine ~]$sudo docker login

Username: zhiyewang

Password: 

Email: zhiye_wang@yeah.net           

WARNING: login credentials saved in /home/cloudsoar/.docker/config.json

Login Succeeded

可以看到我的账号登录成功了。

4.5.2 使用 Docker 的 commit 命令创建镜像

这里我基于前面下载的 ubuntu 镜像来创建一个新镜像。

首先我在这个基础镜像中启动一个容器

[#5#cloudsoar@cloudsoar-virtual-machine ~]$sudo docker run -i -t ubuntu /bin/bash

root@460f5a1ac42a:/# 

在容器中安装个 Apache 作为一个 web 服务器来运行。这样每次使用 Apache 的时候不用再

重新安装 Apache 了。

root@460f5a1ac42a:/# apt-get -y install apache2

Reading package lists... Done

Building dependency tree       

root@460f5a1ac42a:/# apt-get -y install vim

我喜欢用vim,同时又安装了一个 vim,哇咔咔。

为了完成此项工作,需要先退出 exit ,然后执行 docker commit 命令。

 

这里需要注意的是, docker commit 提交的是创建容器的镜像与容器的当前状态之间有差异

的部分,这使得该更新非常轻量。这里可以看到我创建的结果。


如果像从刚才创建的镜像运行一个容器,可以使用 docker run 命令

[#16#cloudsoar@cloudsoar-virtual-machine ~]$sudo docker run -t -i zhiyewang/apache2 /bin/bash

root@bb634a313bf2:/# 

4.5.3 使用 Dockerfile 构建镜像

事实上所有资料都不推介使用 docker commit 的方法构建镜像,而是使用 Dockerfile 的定义

文件和 docker build 命令来构建镜像。

我们的第一个 Dockerfile

现在我们创建一个目录,并在里面创建初始的 Dockerfile,我们将创建一个包含简单 Web 服

服务器的 Docker 镜像。


这里我们创建了一个名为 static_web 的目录用来保存 Dockerfile,这个目录就是我们的构建环

境(build environment),Docker 则称此环境为上下文(context)或者构建上下文(build

 context)。Docker 会在构建镜像时候,将构建上下文和该上下文中的文件和目录上传到 doc

 ker 守护进程。这样 Docker 守护进程就能直接访问你想在镜像中存储的任何代码。

下面是一个 Dockerfile 的例子,用 Dockerfile 构建一个能作为 Web 服务器的 Docker 镜像。

  1 # version: 0.0.1

  2 FROM ubuntu:14.04

  3 MAINTAINER zhiyewang "zhiye_wang@yeah.net"

  4 RUN apt-get update

  5 RUN apt-get install -y nginx

  6 RUN echo 'Hi, I am in your container' \

  7     >/usr/share/nginx/html/index.html

  8 EXPOSE 80                             

命令解释:

Dockerfile 由一系列指令和参数组成。每条指令都是大写,而且后面需要跟一个参数。Docker

 file 会按照顺序从上往下执行。

Dockerfile 支持注释,所有以井号开头的都是注释。

FROM ubuntu:14.04 指定了 ubuntu 14.04 作为基础镜像,每

执行一条指令,对容器做出修改。自动会再指定类似 docker commit 的操作,提交一个新镜像

层,继续执行下一条指令。

MAINTAINER 指令会告诉 Docker 该镜像的作者是谁,以及作者的电子邮件地址。

接下来我们执行了三条 RUN 指令,RUN 指令会在当前镜像中运行指定的命令。我们通过RUN明

令更新了 APT 仓库,安装了 nginx 包,之后创建了  /usr/share/nginx/html/index.html 文件,

默认情况,RUN执行会在 shell 里使用 /bin/sh -c 来执行。如果再不支持 shell 或者不想再 shell

中运行,可以使用 exec 格式的 RUN

RUN [ "apt-get", "install", "-y", "nginx" ]

接下来的 EXPOSE 指令,告诉 Docker 该容器内的应用程序将会使用 Docker 的指定端口。但是

Docker 并不会自动打开此端口,而是需要再使用 docker run 运行容器时候指定需要打开那些端

口。

4.5.4 基于 Dockerfile 构建新镜像

运行 Dockerfile 

[#34#cloudsoar@cloudsoar-virtual-machine ~]$cd static_web/

[#35#cloudsoar@cloudsoar-virtual-machine ~/static_web]$sudo docker build -t="zhiyewang/static_web" .

Sending build context to Docker daemon 2.048 kB

Step 1 : FROM ubuntu:14.04

14.04: Pulling from library/ubuntu

Digest: sha256:45b23dee08af5e43a7fea6c4cf9c25ccf269ee113168c19722f87876677c5cb2

Status: Downloaded newer image for ubuntu:14.04

 ---> 8ed581e3fa7a

Step 2 : MAINTAINER zhiyewang "zhiye_wang@yeah.net"

 ---> Running in 7806118624b7

 ---> c5aed3a8ff95

Removing intermediate container 7806118624b7

...

Processing triggers for sgml-base (1.26+nmu4ubuntu1) ...

 ---> ddc8935b098a

Removing intermediate container c81405d28e41

Step 5 : RUN echo 'Hi, I am in your container'  >/usr/share/nginx/html/index.html

 ---> Running in f0049e284208

 ---> 6a7a53f6e78a

Removing intermediate container f0049e284208

Step 6 : EXPOSE 80

 ---> Running in 2a0714253002

 ---> e97eb7ef0136

Removing intermediate container 2a0714253002

Successfully built e97eb7ef0136

 

这里使用 -t 参数为新镜像设置了仓库和名称。仓库为 zhiyewang,名称为 static_web,也可

以构建过程中为镜像添加一个标签,方法为“镜像名:标签”
sudo docker build -t="zhiyewang/static_web:v1" .

如果没有定制任何标签,Docker 会自动为镜像设置一个 latest 标签。

上面命令最后的 . 告诉我们去当前路径去找 Dockerfile 文件。也可以指定一个 Git 仓库的源地

址来指定 Dockerfile 的位置。例如

sudo docker build -t="zhiyewang/static_web:v1" \

 git@github.com:zhiyewang/docker-static_web

这里假设的在 Git 仓库的目录下存在 Dockerfile 文件。我也没有注册 Git 账号去执行过。

查看 docker build 过程发现,构建上下文已经上传到了 Docker 守护进程:

Sending build context to Docker daemon 2.048 kB

之后,可以看到 Dockerfile 中的每条明令都被顺序执行,而且构建过程的最终结果返回了新的

镜像的 ID,即 e97eb7ef0136 ,并且 Docker 会提交每一步的执行结果。

4.5.4 指令失败时候会怎样

例如我们将上面的第 4 步的包名 nginx 写成 ngin

[#41#cloudsoar@cloudsoar-virtual-machine ~/static_web]$sudo docker build -t="zhiyewang/static_web" .

[sudo] password for cloudsoar: 

Sending build context to Docker daemon 2.048 kB

Step 1 : FROM ubuntu:14.04

 ---> 8ed581e3fa7a

Step 2 : MAINTAINER zhiyewang "zhiye_wang@yeah.net"

 ---> Using cache

 ---> c5aed3a8ff95

Step 3 : RUN apt-get update

 ---> Using cache

 ---> 40fa5cd1c3d2

Step 4 : RUN apt-get install -y ngin

 ---> Running in 86e3dbaadf20

Reading package lists...

Building dependency tree...

Reading state information...

E: Unable to locate package ngin

The command '/bin/sh -c apt-get install -y ngin' returned a non-zero code: 100

发现会出错。我们来调试一下失败原因。用 docker run 明令来基于这次构建到目前为止已经

成功的最后一步创建一个容器,它的 ID 是 40fa5cd1c3d2 ,如下代码:

[#42#cloudsoar@cloudsoar-virtual-machine ~/static_web]$sudo docker run -t -i 40fa5cd1c3d2 /bin/bash

root@b978996f25f3:/#

这时我们在此容器中运行第 4 步:

root@b978996f25f3:/# apt-get install -y ngin

Reading package lists... Done

Building dependency tree       

Reading state information... Done

E: Unable to locate package ngin

发现包名错误。

我们可以在这个容器中再次运行 apt-get install -y nginx,这次输入正确的包名,来定位问题

,如果一旦解决了这个问题,就可以退出容器,用正确的包名修改 Dockerfile 文件,之后再次

构建即可。

这一篇到这里。下一篇继续学习Dockerfile 和构建缓存。

posted @ 2016-03-17 11:00 zhiye_wang 阅读(427) | 评论 (0)编辑 收藏

第三章 docker 入门

3.1 确保docker已经就绪

首先查看docker程序是否存在,功能是否正常

[#3#cloudsoar@cloudsoar-virtual-machine ~]$sudo docker info

[sudo] password for cloudsoar:

Containers: 11

Images: 16

Server Version: 1.9.1

Storage Driver: aufs

 Root Dir: /var/lib/docker/aufs

 Backing Filesystem: extfs

 Dirs: 38


3.2 运行我们的第一个容器

docker run 命令提供了Docker容器的创建到启动的功能

书上使用此命令创建第一个容器

[#4#cloudsoar@cloudsoar-virtual-machine ~]$sudo docker run -i -t ubuntu /bin/bash 

 Unable to find image 'ubuntu:latest' locally

latest: Pulling from library/ubuntu

073de23ee32b: Downloading 48.09 MB/65.69 MB

...

可以看到有大概66MB,等待慢慢下载完成。其实Ubuntu镜像也是一个基础镜像。

sudo docker run -i -t ubuntu /bin/bash 

这句命令我的理解就是,sudo 临时切换管理员权限,使用 docker run 命令,启动镜像

ubuntu 中的 bash。docker run 会检查本地是否有ubuntu这个基础镜像,如果没有,

则去docker hub registry 去检测并下载此镜像,下载完毕再执行。

由于容器有自己的ip,自己的shell,是独立的。因此加上 -i 参数来打开容器的标准输入

STDIN,使用 -t 给容器配一个交互式终端。当新容器下载完毕后,会自动以root用户登

录到新的容器中。界面显示的是:root@容器ID 。容器的主机名就是容器的ID。

假设说我们想要给这个容器安装一个curl,或者是 ping,可以通过如下命令

sudo docker run ubuntu apt-get install -y curl

docker run 容器名 命令 


等了半个小时,还没下载完毕,由于这个基础镜像下载实在太慢,我换了一个镜像

我之前pull了一个名为paulcos11/docker-tutorial的镜像,容器有11个

如果你想下载其他的镜像,可以使用 docker search tutorial 首先查看可用镜像。然后使用

docker pull 把它拉下来。

root@cloudsoar-virtual-machine:/home/cloudsoar# docker search tutorial

NAME                                 DESCRIPTION                                     STARS     OFFICIAL   AUTOMATED

georgeyord/reactjs-tutorial          This is the backend of the React comment b...   2                    [OK]

mhausenblas/kairosdb-tutorial        GitHub fetcher for KairosDB tutorial            1                    [OK]

odk211/spree-tutorial                                                                1                    [OK]

paulcos11/docker-tutorial            docker tutorial       


root@cloudsoar-virtual-machine:/home/cloudsoar# docker pull paulcos11/docker-tutorial

Using default tag: latest

latest: Pulling from paulcos11/docker-tutorial

044ffdf80f70: Pull complete 

...

Digest: sha256:8effcf1f4eac7096ba4eaf4a90261580657605d159946372c12ae28b7e5e74f1

Status: Downloaded newer image for paulcos11/docker-tutorial:latest

到这里,我成功下载了容器镜像paulcos11/docker-tutorial


继续流程,进入我们的容器

root@cloudsoar-virtual-machine:~# docker run -i -t paulcos11/docker-tutorial /bin/bash

root@537739299f24:/# 

执行完毕可以看到进入了容器的bash,用户是root,容器ID是537739299f24,


3.3 使用容器

可以使用 hostname 查看容器的主机名

root@537739299f24:/# hostname

537739299f24

可以看到容器的ID就是容器的主机名。
下一步看看 /etc/hosts 文件

root@537739299f24:/# cat /etc/hosts

172.17.0.2 537739299f24

127.0.0.1 localhost

::1 localhost ip6-localhost ip6-loopback

fe00::0 ip6-localnet

ff00::0 ip6-mcastprefix

ff02::1 ip6-allnodes

ff02::2 ip6-allrouters

可以看到docker 已经在host文件中为该容器的ijp增加了一条主机配置项

再看看IP

root@537739299f24:/# ip a

1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default 

    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00

    inet 127.0.0.1/8 scope host lo

       valid_lft forever preferred_lft forever

    inet6 ::1/128 scope host 

       valid_lft forever preferred_lft forever

30: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 

    link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff

    inet 172.17.0.2/16 scope global eth0

       valid_lft forever preferred_lft forever

    inet6 fe80::42:acff:fe11:2/64 scope link 

       valid_lft forever preferred_lft forever

可以看到这里有lo的回环接口。还有ip是172.17.0.2的标准eth0接口,和宿主机完全一样。

查看容器 中的进程

root@537739299f24:/# ps -aux

USER        PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND

root          1  0.2  0.1  21944  3528 ?        Ss   03:03   0:01 /bin/bash

root         12  0.0  0.0  19188  2336 ?        R+   03:14   0:00 ps -aux

接下来,我想给容器安装一个vim

这里我先更新下容器的源再安装。

root@537739299f24:/# apt-get update && apt-get install vim

安装完毕使用 exit,即可退出到宿主机系统。这时容器也会停止,因为一旦退出容器,

容器也随之停止了运行。但是容器仍然存在,可以用 docker ps -a 查看容器列表。

root@537739299f24:/# exit

exit

docker ps 可以查看运行中的容器,加上 -a 参数可以查看所有的容器

3.4 容器命名

可以使用如下命令为容器指定一个合法有意义的名字。

root@cloudsoar-virtual-machine:~# docker run --name wzy_the_container -i -t paulcos11/docker-tutorial /bin/bash

root@0a09dfd688ea:/# exit

exit


3.5 重新启动已经停止的容器

此时,wzy_the_container 已经停止了。可以使用如下命令重启一个已经停止的容器。

root@cloudsoar-virtual-machine:~# docker start wzy_the_container

wzy_the_container

也可以使用容器ID替换容器名。


3.6 附着到容器上
容器启动的时候会按照docker run指定的参数来运行。因此这个容器启动后会启动一个交互

的shell。我可以使用 docker attach 直接附着到此容器。

root@cloudsoar-virtual-machine:~# docker attach wzy_the_container

root@0a09dfd688ea:/# 

可以看到重新会到了容器的Bash提示符界面。

如果退出容器的shell,容器也会随之停止运行。


3.7 创建守护式容器

除了交互式运行的容器,我们也可以创建守护容器。可以长期的运行应用程序或者服务。

大多时候需要创建守护式容器。

[#10#cloudsoar@cloudsoar-virtual-machine ~]$sudo docker run --name daemon_dave -d ubuntu /bin/sh -c "while true; do echo hello world; sleep 1; done"

cf5636f0499fa0105b845b5dfa61913ff7d5fccfb1b19c16b09ed2752233794d

由于此时第 3.2 步我下载的 Ubuntu 基础镜像Downloading 48.09 MB/65.69 MB 刚好下载

完毕,所以此时我开始使用ubuntu容器镜像操作了。

docker run 的参数 -d 是放到后台执行。此时我们并没有像上一个容器直接附着到新容器的

shell会话上,而是返回了一个容器ID而已。此时使用 docker ps 可以看到正在运行的容器。


ubuntu就是我刚刚下载完毕的基础镜像。 paulcos11/docker-tutorial 是我自己下载的其他的镜像。

3.8 容器内部再搞什么

使用 docker logs 获取容器日志

[#16#cloudsoar@cloudsoar-virtual-machine ~]$sudo docker logs daemon_dave

hello world

hello world

hello world

hello world

hello world

hello world

或者可以加上-f 实时监控容器日志。

sudo docker logs -f daemon_dave

也可以追踪日志某一片段,只需要tail命令加入 -f --lines标志即可。

例如: docker logs --tail 10 daemon_dave 获取最后10行日志即可。

 docker logs --tail 0 -f daemon_dave 获取最新日志。

如果要查看日志的时间,可以加上时间戳。

[#18#cloudsoar@cloudsoar-virtual-machine ~]$sudo docker logs -ft daemon_dave

2016-03-15T03:45:28.457991514Z hello world

2016-03-15T03:45:29.472422582Z hello world

2016-03-15T03:45:30.475130491Z hello world


3.9 查看容器进程

查看容器内的进程可以使用 docker top 命令。

[#20#cloudsoar@cloudsoar-virtual-machine ~]$sudo docker top daemon_dave

UID                 PID                 PPID                C                   STIME               TTY                 TIME                CMD

root                25381               22325               0                   11:45               ?                   00:00:00            /bin/sh -c while true; do echo hello world; sleep 1; done


3.10 在容器内部运行进程

我们可以使用docker exec 命令在容器内部额外启动新进程,可以运行的进程有两种类型,

交互式任务和后台任务。首先我们使用 touch 命令创建一个空文件。

$sudo docker exec -d daemon_dave touch /etc/new_config_file

-d 表示是后台进程。

或者打开一个shell

$sudo docker exec -t -i daemon_dave /bin/bash

root@cf5636f0499f:/#


3.11 停止守护式容器

$sudo docker stop daemon_dave

daemon_dave


3.12 自动重启容器

如果由于某种错误导致容器停止,可以通过 --restart 标志让docker自动重新启动容器。

$sudo docker run --restart=on-failure:5 --name daemon_dave -d ubuntu /bin/sh -c "while true; do echo hello world; sleep 1; done"

Error response from daemon: Conflict. The name "daemon_dave" is already in use by container cf5636f0499f. You have to remove (or rename) that container to be able to reuse that name.

这里我的运行不起来,因为 -- restart 标示是docker 2.0 引入的。我的是docker 1.9版本。


3.13 深入容器

除了使用docker ps 查看容器信息,还可以使用 docker inspect 查看更多信息


$sudo docker inspect daemon_dave

[sudo] password for cloudsoar:

[

{

    "Id": "cf5636f0499fa0105b845b5dfa61913ff7d5fccfb1b19c16b09ed2752233794d",

    "Created": "2016-03-15T03:45:28.124542139Z",

    "Path": "/bin/sh",

    "Args": [

        "-c",

        "while true; do echo hello world; sleep 1; done"

    ],

    "State": {

        "Status": "exited",

        "Running": false,

        "Paused": false,

        "Restarting": false,

        "OOMKilled": false,

        "Dead": false,

        "Pid": 0,

        "ExitCode": 137,

        "Error": "",

        "StartedAt": "2016-03-15T03:45:28.455126857Z",

        "FinishedAt": "2016-03-15T04:05:11.945521026Z"

    },

   ...

也可使用 -f 或者 --format 标志来选定查看结果。

$sudo docker inspect --format='{{ .State.Running}}' daemon_dave

false

以及查看其他信息

$sudo docker start daemon_dave

daemon_dave

$sudo docker inspect --format '{{ .NetworkSettings.IPAddress }}' daemon_dave

172.17.0.3


3.14 删除容器

如果容器不在使用,可以使用 docker rm 命令删除。

这里假设我要删除 daemon_dave 这个容器,他的容器ID是 cf5636f0499f

$sudo docker rm cf5636f0499f

Error response from daemon: Conflict, You cannot remove a running container. Stop the container before attempting removal or use -f

Error: failed to remove containers: [cf5636f0499f]

$sudo docker stop cf5636f0499f

cf5636f0499f

$sudo docker rm cf5636f0499f

cf5636f0499f

由于不能删除正在运行的容器,所以需要先停止。


3.15 小结

下一章学习如何构建自己的Docker镜像,以及如何使用Docker 仓库和 Docker Registry.

posted @ 2016-03-15 13:43 zhiye_wang 阅读(678) | 评论 (0)编辑 收藏

仅列出标题
共4页: 1 2 3 4