【注】:如果启动失败可能的问题,1:重装一下docker; 2:还是不行,启动报docker: relocation error: docker: symbol dm_task_get_info_with_deferred_remove, version Base not defined in file libdevmapper.so.1.02 with link time reference,更新yum upgrade device-mapper-libs,然后启动service docker start(具体描述见文章末)
$ docker version
$ docker run -d -P training/webapp python app.py
$ docker ps -l
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
bc533791f3f5 training/webapp:latest python app.py 5 seconds ago Up 2 seconds 0.0.0.0:49155->5000/tcp nostalgic_morse
# docker run -d -p 6379 -v /home/hadoop/redis-2.8.13:/opt/redis-2.8.13 learn/tutorial /opt/redis-2.8.13/src/redis-server
be0b410f3601ea36070b3e519d9cc7cbe259caa2392f468c2dd2baebef42c4a8
# docker ps -l
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
be0b410f3601 learn/tutorial:latest /opt/redis-2.8.13/sr 10 seconds ago Up 10 seconds 0.0.0.0:49153->6379/tcp sad_colden
# /home/hadoop/redis-2.8.13/src/redis-cli -p 49153
127.0.0.1:49153> keys *
(empty list or set)
127.0.0.1:49153>
-P flag is new and tells Docker to map any required network ports inside our container to our host. This lets us view our web application.
-l tells the docker ps command to return the details of the last container started.
-a the docker ps command only shows information about running containers. If you want to see stopped containers too use the -a flag.
-p Network port bindings are very configurable in Docker. In our last example the -P flag is a shortcut for -p 5000 that maps port 5000 inside the container to a high port (from the range 49153 to 65535) on the local Docker host. We can also bind Docker containers to specific ports using the -p flag。
-v flag you can also mount a directory from your own host into a container.
123456789101112131415
[root@docker redis-2.8.13]# docker run -d -p 6379:6379 -v /home/hadoop/redis-2.8.13:/opt/redis-2.8.13 learn/tutorial /opt/redis-2.8.13/src/redis-server
2c50850c9437698769e54281a9f4154dc4120da2e113802454f1a23c83ab91fe
[root@docker redis-2.8.13]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
2c50850c9437 learn/tutorial:latest /opt/redis-2.8.13/sr 29 seconds ago Up 28 seconds 0.0.0.0:6379->6379/tcp naughty_yonath
[root@docker redis-2.8.13]# docker port naughty_yonath 6379
0.0.0.0:6379
[root@docker redis-2.8.13]# docker logs -f naughty_yonath
...
[1] 27 Sep 13:48:12.192 * The server is now ready to accept connections on port 6379
[1] 27 Sep 13:50:33.228 * DB saved on disk
[1] 27 Sep 13:50:43.730 * DB saved on disk
-f This time though we’ve added a new flag, -f. This causes the docker logs command to act like the tail -f command and watch the container’s standard out. We can see here the logs from Flask showing the application running on port 5000 and the access log entries for it.
$ mkdir sinatra
$ cd sinatra
$ touch Dockerfile
# This is a comment
FROM ubuntu:14.04
MAINTAINER Kate Smith <ksmith@example.com>
RUN apt-get update && apt-get install -y ruby ruby-dev
RUN gem install sinatra
$ docker build -t="ouruser/sinatra:v2" .
$ docker run -t -i ouruser/sinatra:v2 /bin/bash
docker run -d -P training/webapp python app.py
docker ps nostalgic_morse
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
bc533791f3f5 training/webapp:latest python app.py 5 seconds ago Up 2 seconds 0.0.0.0:49155->5000/tcp nostalgic_morse
docker run -d -p 5000:5000 training/webapp python app.py
docker run -d -p 127.0.0.1:5000:5000 training/webapp python app.py
docker run -d -p 127.0.0.1::5000 training/webapp python app.py
# The -p flag can be used multiple times to configure multiple ports.
docker run -d -p 127.0.0.1:5000:5000/udp training/webapp python app.py
docker port nostalgic_morse 5000
127.0.0.1:49155
$ docker run -d -P --name web training/webapp python app.py
$ docker ps -l
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
aed84ee21bde training/webapp:latest python app.py 12 hours ago Up 2 seconds 0.0.0.0:49154->5000/tcp web
$ docker inspect -f "" aed84ee21bde
/web
容器互通:
123456789
$ docker run -d --name db training/postgres
$ docker rm -f web
$ docker run -d -P --name web --link db:db training/webapp python app.py
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
349169744e49 training/postgres:latest su postgres -c '/usr About a minute ago Up About a minute 5432/tcp db, web/db
aed84ee21bde training/webapp:latest python app.py 16 hours ago Up 2 minutes 0.0.0.0:49154->5000/tcp web
You can see that Docker has created a series of environment variables with useful information about the source db container. Each variable is prefixed with DB_, which is populated from the alias you specified above. If the alias were db1, the variables would be prefixed with DB1_.
# Adding a data volume
docker run -d -P --name web -v /webapp training/webapp python app.py
# Mount a Host Directory as a Data Volume
docker run -d -P --name web -v /src/webapp:/opt/webapp training/webapp python app.py
# 只读
docker run -d -P --name web -v /src/webapp:/opt/webapp:ro training/webapp python app.py
# Mount a Host File as a Data Volume
docker run --rm -it -v ~/.bash_history:/.bash_history ubuntu /bin/bash
# Creating and mounting a Data Volume Container
docker run -d -v /dbdata --name dbdata training/postgres echo Data-only container for postgres
docker run -d --volumes-from dbdata --name db1 training/postgres
docker run -d --volumes-from dbdata --name db2 training/postgres
docker run -d --name db3 --volumes-from db1 training/postgres
# Backup, restore, or migrate data volumes
docker run --volumes-from dbdata -v $(pwd):/backup ubuntu tar cvf /backup/backup.tar /dbdata
docker run -v /dbdata --name dbdata2 ubuntu /bin/bash
docker run --volumes-from dbdata2 -v $(pwd):/backup busybox tar xvf /backup/backup.tar
[root@localhost ~]# docker -d
INFO[0000] +job serveapi(unix:///var/run/docker.sock)
INFO[0000] WARNING: You are running linux kernel version 2.6.32-431.el6.x86_64, which might be unstable running docker. Please upgrade your kernel to 3.8.0.
INFO[0000] Listening for HTTP on unix (/var/run/docker.sock)
docker: relocation error: docker: symbol dm_task_get_info_with_deferred_remove, version Base not defined in file libdevmapper.so.1.02 with link time reference
[root@localhost ~]# docker start 5ed45ce5ad3d
Error response from daemon: Cannot start container 5ed45ce5ad3d: [8] System error: write /cgroup/freezer/docker/5ed45ce5ad3d085fe3c004f90eef7c774a722e84cf0c9d18c197cc5900bbc8ae/cgroup.procs: invalid argument
FATA[0000] Error: failed to start one or more containers
[root@bigdata1 ~]# cat /etc/redhat-release
CentOS release 6.5 (Final)
[root@bigdata1 ~]# yum install epel-release
[root@bigdata1 ~]# yum install docker-io
[root@bigdata1 ~]# docker -d
INFO[0000] Listening for HTTP on unix (/var/run/docker.sock)
WARN[0000] You are running linux kernel version 2.6.32-431.el6.x86_64, which might be unstable running docker. Please upgrade your kernel to 3.10.0.
docker: relocation error: docker: symbol dm_task_get_info_with_deferred_remove, version Base not defined in file libdevmapper.so.1.02 with link time reference
https://github.com/docker/docker/issues/12108
[root@bigdata1 ~]# yum install device-mapper-devel
[root@bigdata1 ~]# service docker start
Starting docker: [确定]
[root@bigdata1 ~]# docker version
Client version: 1.7.1
Client API version: 1.19
Go version (client): go1.4.2
Git commit (client): 786b29d/1.7.1
OS/Arch (client): linux/amd64
Server version: 1.7.1
Server API version: 1.19
Go version (server): go1.4.2
Git commit (server): 786b29d/1.7.1
OS/Arch (server): linux/amd64
[hadoop@slaver1 ~]$ less /home/hadoop/hadoop-2.2.0/logs/userlogs/application_1410448728371_0003/*/syslog
2014-09-11 22:55:12,616 INFO [main] org.apache.hadoop.mapreduce.v2.app.MRAppMaster: Created MRAppMaster for application appattempt_1410448728371_0003_000001
...
2014-09-11 22:55:18,677 INFO [main] org.apache.hadoop.mapreduce.v2.app.job.impl.JobImpl: Adding job token for job_1410448728371_0003 to jobTokenSecretManager
2014-09-11 22:55:19,119 FATAL [main] org.apache.hadoop.mapreduce.v2.app.MRAppMaster: Error starting MRAppMaster
java.lang.NoClassDefFoundError: scala/Function1
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:190)
at org.apache.hadoop.mapreduce.v2.app.job.impl.JobImpl.isChainJob(JobImpl.java:1277)
at org.apache.hadoop.mapreduce.v2.app.job.impl.JobImpl.makeUberDecision(JobImpl.java:1217)
at org.apache.hadoop.mapreduce.v2.app.job.impl.JobImpl.access$3700(JobImpl.java:135)
at org.apache.hadoop.mapreduce.v2.app.job.impl.JobImpl$InitTransition.transition(JobImpl.java:1420)
at org.apache.hadoop.mapreduce.v2.app.job.impl.JobImpl$InitTransition.transition(JobImpl.java:1358)
at org.apache.hadoop.yarn.state.StateMachineFactory$MultipleInternalArc.doTransition(StateMachineFactory.java:385)
at org.apache.hadoop.yarn.state.StateMachineFactory.doTransition(StateMachineFactory.java:302)
at org.apache.hadoop.yarn.state.StateMachineFactory.access$300(StateMachineFactory.java:46)
at org.apache.hadoop.yarn.state.StateMachineFactory$InternalStateMachine.doTransition(StateMachineFactory.java:448)
at org.apache.hadoop.mapreduce.v2.app.job.impl.JobImpl.handle(JobImpl.java:972)
at org.apache.hadoop.mapreduce.v2.app.job.impl.JobImpl.handle(JobImpl.java:134)
at org.apache.hadoop.mapreduce.v2.app.MRAppMaster$JobEventDispatcher.handle(MRAppMaster.java:1227)
at org.apache.hadoop.mapreduce.v2.app.MRAppMaster.serviceStart(MRAppMaster.java:1035)
at org.apache.hadoop.service.AbstractService.start(AbstractService.java:193)
at org.apache.hadoop.mapreduce.v2.app.MRAppMaster$1.run(MRAppMaster.java:1445)
at java.security.AccessController.doPrivileged(Native Method)
at javax.security.auth.Subject.doAs(Subject.java:415)
at org.apache.hadoop.security.UserGroupInformation.doAs(UserGroupInformation.java:1491)
at org.apache.hadoop.mapreduce.v2.app.MRAppMaster.initAndStartAppMaster(MRAppMaster.java:1441)
at org.apache.hadoop.mapreduce.v2.app.MRAppMaster.main(MRAppMaster.java:1374)
Caused by: java.lang.ClassNotFoundException: scala.Function1
at java.net.URLClassLoader$1.run(URLClassLoader.java:366)
at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
at java.lang.ClassLoader.loadClass(ClassLoader.java:425)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)
at java.lang.ClassLoader.loadClass(ClassLoader.java:358)
... 22 more
2014-09-11 22:55:19,130 INFO [Thread-1] org.apache.hadoop.mapreduce.v2.app.MRAppMaster: MRAppMaster received a signal. Signaling RMCommunicator and JobHistoryEventHandler.
But most importantly, Scala taught me to program and reason about programming differently. I stopped thinking in terms of allocating buffers, structs, and objects, and of changing those pieces of memory. Instead, I learned to think about most of my programs as transforming input to output. This change in thinking has lead to lower defect rates, more modular code, and more testable code. Scala has also given me the tools to write smaller, more modular units of code and asse mble them together into a whole that is maintainable, yet far more complex than anything that I could write in Java or Ruby for that matter.
winse@Lenovo-PC /cygdrive/d/scala/bin
$ ls -1
fsc
fsc.bat
scala
scala.bat
scalac
scalac.bat
scaladoc
scaladoc.bat
scalap
scalap.bat
winse@Lenovo-PC /cygdrive/d/scala/bin
$ scala
Welcome to Scala version 2.10.4 (Java HotSpot(TM) Client VM, Java 1.7.0_02).
Type in expressions to have them evaluated.
Type :help for more information.
scala> def fact(n:Int)=1 to n reduceLeft(_*_) // n!
fact: (n: Int)Int
scala> fact(5)
res0: Int = 120
语法结构,第一个Scala程序
运行程序的三种方式:
命令行交互式的REPL(read-eval-print loop)
shell/cmd脚本
编译打包成jar后运行,跟Java一样
REPL
进入到Scala的bin目录下,双击scala.bat打开。
1234567891011121314151617
scala> 1+1
res0: Int = 2
scala> res0*8
res1: Int = 16
scala> val x="hello world"
x: String = hello world
scala> var xl=x.length
xl: Int = 11
scala> import java.util._
import java.util._
scala> val d = new Date
d: java.util.Date = Mon Sep 08 09:17:08 CST 2014
sum方法的参数Seq是一个trait(类似java interface),是Array,List以机构其他顺序集合的父trait。trait拥有java interface的所有特性,同时traits可以包括方法的实现。你可以混合很多的traits成一个类。Traits除了不能定义有参构造函数外,其他和类一样。trait使得“多重继承”简单化,无需担忧 the diamond problem(有点类似近亲结婚 ^ v ^)。
new Foo
new Foo()
class Bar(name: String)
new Bar("Working...")
class Baz(name: String) {
// constructor code is inline
if(name == null) throw new Exception("Name is null")
}
class HasClass {
private class MyDude extends FuzzyCat
def makeOne(): FuzzyCat = new MyDude
}
类继承Class Hierarchy
除了方法(method),其他一切都是对象(an instance of a class)。Java的primitives类型在Scala也被当做对象,如int(Int)。当两个Ints相加时,Scala编译器会对字节码进行优化最终和java的两个ints相加时一样的。如果使用了Int的方法hashCode和toString,当primitive类型被用于需要引用类型时(expects an Any),Scala编译器会对其进行装箱,如把Int值加入到HashMap。
def readLines(br: BufferedReader) = {
var ret: List[String] = Nil
def readAll(): Unit = br.readLine match {
case null =>
case s => ret ::= s; readAll()
}
readAll()
ret.reverse
}
abstract class Base {
def thing: String
}
class One extends Base {
def thing = "Moof"
}
不带参数的方法和变量可以使用相同的方式访问,重写父类方法时可以使用val代替def。
1234567
class Two extends One {
override val thing = (new java.util.Date).toString
}
class Three extends One {
override lazy val thing = super.thing + (new java.util.Date).toString
}
变量声明
和声明方法类似,不过关键字使用val, var, lazy val。var
可以在设置值以后再次进行修改,类似于java中的变量。val在运行到该作用域时就初始化。lazy val仅在访问的时刻进行计算一次。
123
var y: String = "Moof"
val x: String = "Moof"
lazy val lz: String = someLongQuery()
在编程时,不推荐使用var变量除非一定要用变量。Given that mutability leads to unexpected defects, minimizing mutability in code minimizes mutability-related defects.
Scala类型推测对变量一样有效,在参数类型明确的情况下,定义参数时可以不用指定类型。
12
var y2 = "Moof"
val x2 = "Moof"
Scala支持同时接受多个参数值。 If a code block or method returns a Tuple, the Tuple can be assigned to a val variable.
12
val (i1: Int, s1: String) = Pair(33, "Moof")
val (i2, s2) = Pair(43, "Moof")
运行的效果如下:
123456
scala> val (i2,s2)=Pair(43,"W")
i2: Int = 43
s2: String = W
scala> i2
res0: Int = 43
代码块
方法和参数定义都可以定义在单行。
1
def meth9 = "hello world"
或者定义在大括号包围的代码块中。代码块可以去嵌套。代码块的返回值是最后一个行的运行结果。
12345
def meth3(): String = {"Moof"}
def meth4(): String = {
val d = new java.util.Date()
d.toString()
}
参数定义同样可以使用代码块,适合于有少量计算的赋值操作。
1234
val x3: String = {
val d = new java.util.Date()
d.toString()
}
Scala提供另一种传递参数给方法(函数)的方式:call-by-name,可以把方法块传给调用者。 Each time the callee accesses the parameter, the code block is executed and the value is calculated.
Call-by-name容许我们把耗时的操作(但可能不会用到的)当做参数。For example, in a call to the logger you can use call-by-name, and the express to print is only calculated if it’s going to be logged。Call-by-name同样容许我们创建(如while/doWhile)自定义的控制结构。
1234567891011121314151617181920212223242526272829
def nano() ={
println("Getting nano")
System.nanoTime
}
def delayed(t: => Long) = {
println("In delayed method")
println("Param: " + t)
t
}
scala> delayed(nano())
In delayed method
Getting nano
Param: 198642874346225
Getting nano
res1: Long = 198642875202814
def notDelayed(t: Long) = {
println("In not delayed method")
println("Param: " + t)
t
}
scala> notDelayed(nano)
Getting nano
In not delayed method
Param: 199944029171474
res5: Long = 199944029171474
Function1[Int, String]
Int => String
def answer(f: Int => String) = f(42)
这种语法糖适用于所有包括apply方法对象。
123456789101112131415161718
scala> class Ap {
| def apply(in: Int) = in.toString
| }
defined class Ap
scala> new Ap()(44)
res0: String = 44
scala> new Ap(44)
<console>:9: error: too many arguments for constructor Ap: ()Ap
new Ap(44)
^
scala> val a = new Ap
a: Ap = Ap@18258b2
scala> a(44)
res2: String = 44
如果类包括update方法,编译解析赋值操作时,会调用两个参数的update方法。
12345678910111213141516171819202122232425
scala> class Up {
| def update(k: Int, v: String) = println("Hey: " + k + " " + v)
| }
defined class Up
scala> val u = new Up
u: Up = Up@7bfd80
scala> u(33) = "hello"
Hey: 33 hello
scala> class Update {
| def update(what: String) = println("Singler: " + what)
| def update(a: Int, b: Int, what: String) = println("2d update")
| }
defined class Update
scala> val u = new Update
u: Update = Update@4bd4d2
scala> u() = "Foo"
Singler: Foo
scala> u(3,4) = "Howdy"
2d update
Scala has a mechanism for creating classes that have the common stuff filled in. Most of the time, when I define a class, I have to write the toString, hashCode, and equals methods. These methods are boilerplate. Scala provides the case class mechanism for filling in these blanks as well as support for pattern matching.
A case class provides the same facilities as a normal class, but the compiler generates toString, hashCode, and equals methods (which you can override).
Case classes can be instantiated without the use of the new statement. By default, all the parameters in the case class’s constructor become properties on the case class. Here’s how to create a case class:
1234567891011121314151617181920
scala> case class Stuff(name: String, age: Int)
defined class Stuff
scala> val s = Stuff("David", 45)
s: Stuff = Stuff(David,45)
scala> s.toString
res0: String = Stuff(David,45)
scala> s == Stuff("David", 45) // == 相当于java中的equals
res1: Boolean = true
scala> s == Stuff("David", 42)
res2: Boolean = false
scala> s.name
res4: String = David
scala> s.age
res5: Int = 45
手写case class功能的类:
12345678910111213
class Stuff(val name: String, val age: Int) {
override def toString = "Stuff(" + name + "," + age + ")"
override def hashCode = name.hashCode + age
override def equals(other: AnyRef) = other match {
case s: Stuff => this.name == s.name && this.age = s.age
case _ => false
}
}
object Stuff {
def apply(name: String, age: Int) = new Stuff(name, age)
def unapply(s: Stuff) = Some((s.name, s.age))
}
Basic Pattern Matching
模式匹配(Pattern matching)可以使用很少的代码编写非常复杂的判断。Scala Pattern matching和Java switch语句类似, but you can test against almost anything, and you can even assign pieces of the matched value to variables. Like everything in Scala, pattern matching is an expression, so it result s in a value that may be assigned or returned. The most basic pattern matching is like Java’s switch, except there is no break in each case as the cases do not fall through to each other.
1234
44 match {
case 44 => true
case _ => false
}
可以对String进行match操作,类似于C#。
12345
"David" match {
case "David" => 45
case "Elwood" => 77
case _ => 0
}
Stuff("David", 45) match {
case Stuff("David", age) if age < 30 => "young David"
case Stuff("David", _) => "old David"
case _ => "Other"
}
Pattern matching还可以根据类型进行匹配:
123456
x match {
case d: java.util.Date => "The date in milliseconds is " + d.getTime
case u: java.net.URL => "The URL path: " + u.getPath
case s: String => "String: " + s
case _ => "Something else"
}
如果使用Java代码的话,需要多很多的转换!!
1234
if(x instanceof Date) return "The date in milliseconds is " + ((Date)x).getTime();
if(x instanceof URL) return "The URL path: " + ((URL)x).getPath();
if(x instanceof String) return "String: " + ((String)x);
return "Something else"
if(exp) println("yes")
// multiline
if(exp) {
println("Line one")
println("Line two")
}
val i: Int = if(exp) 1 else 3
val i: Int = if(exp) 1
else {
val j = System.currentTimeMillis
(j % 100L).toInt
}
while executes its code block as long as its expression evaluates to true, just like Java. In practice, using recursion, a method calling itself, provides more readab le code and enforces the concept of transforming input to output rather than changing, mutating, variables. Recursive methods can be as efficient as a while loop.
1234
while (exp) println("Working...")
while (exp) {
println("Working...")
}
for
12345678910111213141516
for { i <- 1 to 3} println(i)
for { i <- 1 to 3
j <- 1 to 3
} println(i*j)
def isOdd(in: Int) = in % 2 == 1
for {i <- 1 to 5 if ifOdd(i)} println(i)
for {i <- 1 to 5
j <- 1 to 5 if isOdd(i*j)} println(i*j)
val lst = (1 to 18 by 3).toList
for {i <- lst if isOdd(i)} yield i
for {i <- lst; j <- lst if isOdd(i*j)} yield i*j
将在第三章-集合中更详细的讲解for使用方法。
throw, try/catch/finally, and synchronized
try/finally的写法和java类似:
1234567
throw new Exception("Working...")
try{
throw new Exception("Working...")
} finally {
println("This will always be printed")
}
Functions, Anonymous Inner Class, and Lambdas/Procs
The Java construct to pass units of computation as parameters to methods is anonymous inner class. 匿名内部类在Swing UI库非常的常见。在Swing中,许多UI事件处理的接口定义1-2个方法,在编写程序时,实现事件接口的内部类能访问外部类的私有成员数据。
[hadoop@master1 hadoop-deploy-0.0.1]$ ssh-copy-id localhost
The authenticity of host 'localhost (::1)' can't be established.
RSA key fingerprint is 4e:fe:7a:0a:98:6e:9a:ab:af:e4:65:51:9b:3d:e0:99.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added 'localhost' (RSA) to the list of known hosts.
hadoop@localhost's password:
Now try logging into the machine, with "ssh 'localhost'", and check in:
.ssh/authorized_keys
to make sure we haven't added extra keys that you weren't expecting.