auto i = 42; // i is an int cout << sizeof(i) <<endl; //4 // l is a long int. auto l = 42L; cout << sizeof(l) <<endl; //8 // ll is a long long int. auto ll = 42LL; cout << sizeof(ll) <<endl; //8 // l is an long long map<string, int> m; m["hello"] = 0; m["world"] = 1; for(auto it = m.begin(); it != m.end(); ++it) cout<< it -> first << " " << it ->second << endl; cout << "------------------------------------------------------------" << endl;
auto还可以作为返回值占位符
auto add(int t1, int t2) { return t1+t2; }
C++11也可以使用类似”foreach”的语法遍历容器。用这个新的写法,可以遍历C类型的数组、初始化列表以及任何重载了非成员的begin()和end()函数的类型。如果你只是想对集合或数组的每个元素做一些操作,而不关心下标、迭代器位置或者元素个数,那么这种for循环迭代将会非常有用。例如上面的map对象:
for(auto it : m) cout<< it.first << " " << it.second << endl;
字符串中有多少标点符号
string s("hello world!!"); auto counter = 0; for (auto c : s) if(ispunct(c)) //#include <cctype> counter++; else if(isalpha(c)) c = toupper(c); cout << "Punction counter is "<< counter << endl; //2 cout << s << endl; //HELLO WORLD!!
参考:
《C++ Primer》
C++11中的自动类型推断和基于范围的for循环 http://blog.csdn.net/huang_xw/article/details/8760403
log(e) 默认是以e为底的自然对数。如果以10为底则修改第二个参数即可。exp是e的指数函数,其他的指数计算直接用x^n即可,例如:
> log2(4) [1] 2 > log10(1) [1] 0 > log10(10) [1] 1 > log(10,10) [1] 1 > log(exp(1)) [1] 1 > 2^3 [1] 8
rep(): 输入重复元素
> rep(1, 8) [1] 1 1 1 1 1 1 1 1 > rep(c(1,2,3,4),8) [1] 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4 > array(1:12, dim=c(3,4)) [,1] [,2] [,3] [,4] [1,] 1 4 7 10 [2,] 2 5 8 11 [3,] 3 6 9 12 # 取其中一行/列 > array(1:12, dim=c(3,4))[2,] [1] 2 5 8 11 > array(1:12, dim=c(3,4))[,2] [1] 4 5 6
数据狂是一个类似关系数据库表的数据结构,其中每列的数据类型可以不同,但是数据长度必须一致。数据框非常适合用于数据分析,它的每一列可以代表数据的每个标量或属性,每一行代表一个样本。例如:
sex <- c('F','M','F','F','M') age <- c(23,43,51,32,60) city <- c('bj','sh','cd','sjz', 'hrb') people <- data.frame(city, age, sex) people$age people[,2] people[people$age>30,] #注意如果要显示所有数据,必须加逗号,[条件, ]。否则会显示undefined columns selected.
多个条件使用&,|和!来表示。
mean(people$age) 平均年龄
names(people)
nrow(people)
按排序显示:
ord1 <- order(people$age) people[ord1,]
实用factor因子来定义标签,可以重新定义标签值
> people$NSEX<-factor(people$sex, levels=c('F','M'), labels=c(1, 2)) > unique(people$age) [1] 23 43 51 32 60
可以用attach将数据框中的符号引入到全局空间中:
attach(people) The following objects are masked _by_ .GlobalEnv: age, city, sex
列表(List)是非常灵活的数据结构,它的不同元素可以是不同类型(每个元素可以当作一个R中的变量),也可以是不同的长度。
> l <- list() > l[["a"]] <- 1 > l[["b"]] <- "hello" > l[["c"]] <- c("h", "e", "l", "l", "o") > l $a [1] 1 $b [1] "hello" $c [1] "h" "e" "l" "l" "o"
另外使用list的常用场景是lapply, 调用函数的每一个返回值都会作为list中的成员:
lst <- lapply(dates, function() {...}, other_arguments) df <- df.rbindList(lst);
(1). cbind()让若干向量以列的方式拼成, rbind()以行(row)
(2). 对矩阵一行/列来赋值
dmat <- matrix(nrow=8, ncol=4) dmat[,2]<-c(1,2,3,4,5,6,7,8)
(3). 同时对多个向量执行同一个操作
sapply(veg[, 5:9], FUN=mean)
(4). 取值形成矩阵
> table(people$city, people$age) 23 32 43 51 60 bj 1 0 0 0 0 cd 0 0 0 1 0 hrb 0 0 0 0 1 sh 0 0 1 0 0 sjz 0 1 0 0 0
(1). sum, min, max & prod 与 cumsum, cumprod, cummin, cummax
(2). split函数可以根据某一列/某一条件来拆分
> a <- c(1,1,2,3,4,5,6,7,8,6) > d <- c(0,0,0,0,0,0,1,2,1,2)> dd <- data.frame(a, d) > split(dd$a, dd$d) $`0` [1] 1 1 2 3 4 5 $`1` [1] 6 8 $`2` [1] 7 6 > split(dd, dd$d) $`0` a d 1 1 0 2 1 0 3 2 0 4 3 0 5 4 0 6 5 0 $`1` a d 7 6 1 9 8 1 $`2` a d 8 7 2 10 6 2 > split(dd, dd$d==0) $`FALSE` a d 7 6 1 8 7 2 9 8 1 10 6 2 $`TRUE` a d 1 1 0 2 1 0 3 2 0 4 3 0 5 4 0 6 5 0
(3). order用于获得某一向量有序的索引,例如
> dd[order(dd$a), "a"] [1] 1 1 2 3 4 5 6 6 7 8
(1). sapply是simplify了的lapply,所谓的simplify,是指对结果的数据结构进行了simplify,方便后续处理。
sapply(scores, mean)
YuWen ShuXue
83.0 86.2
sapply(scores, quantile, probs=c(0.5,0.7,0.9))
YuWen ShuXue
50% 84.0 87.0
70% 88.6 96.6
90% 92.2 99.6
(2). tapply用于接收一系列向量并形成table,例如:
tapply(dd$a, dd$d, mean) 0 1 2 2.666667 7.000000 6.500000
(3). apply中都有一个na.rm=TRUE选项,用于排除迭代向量中的NA值。
(4). R studio的source编辑页面可以用ctrl+n来执行
(5). 条件函数 *ifelse(条件,当条件满足时执行,当条件失败时执行) 等同于 if() {…} else {…}
《R语言核心编程手册》
《R统计学入门》
我们可以在同一个server中绑定域名www.example.com和example.com两个域名:
server { listen 80; server_name example.com www.example.com; }
但是这样对我们的SEO非常不利,我们需要使用301(rewrite)将一个域名重定向到另一个,比如将example重定向到www.example.com。这里要依赖于正则表达式的分组(使用$1来引用分组)。
server { listen 80; server_name example.com www.example.com; if($host!= 'www.example.com'){ rewrite ^/(.*)$ http://www.example.com/$1 permanent; }}
另一个需求是将两个域名的所有的http请求转发到https上,提高安全级别,同时实现二级域名转向一级域名。
server { listen 80; server_name www.debugo.com debugo.com; rewrite ^(.*)$ https://$host$1 permanent; } server { listen 443 ssl; ssl_certificate /etc/nginx/server.crt; ssl_certificate_key /etc/nginx/server.key; server_name www.debugo.com debugo.com; root /webrooot; index index.html index.htm; if ($host != 'debugo.com') { rewrite ^/(.*)$ https://debugo.com/$1 permanent; } #... }
我们通常有自己的动态语言服务器(例如Python wsgi,Node.JS),而静态文件我们又希望使用Nginx来管理,提供缓存等功能。就要使用到下面的配置:
location ~ .*\.(html|htm|gif|jpg|jpeg|bmp|png|ico|txt|js|css)$ { root /web/build; } location / { proxy_pass http://54.3.6.34:8000; proxy_redirect off; proxy_set_header HOST $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; client_max_body_size 10m; client_body_buffer_size 128k; proxy_connect_timeout 90; proxy_send_timeout 90; proxy_read_timeout 90; proxy_buffer_size 4k; proxy_buffers 4 32k; proxy_busy_buffers_size 64k; proxy_temp_file_write_size 64k; } }
^^
]]>万事从Hello world起,
安装Flask-RESTful: pip install FLASK-RESTful
#-*- coding: utf-8 -*- from flask import Flask from flask.ext import restful app = Flask(__name__) api = restful.Api(app) class HelloWorld(restful.Resource): def get(self): return {'hello': 'world'} api.add_resource(HelloWorld, '/') if __name__ == '__main__': app.run(debug=True)
相比普通的http服务:
区别在于:
1. import了RESTful的模块,并使用了restful Api。
2. REST资源类Hello world必须继承自restful.Resource,并实现/重写父类的一些方法(比如get)
3. 将Hello world添加到Restful api资源里,并没有使用装饰器。
下面是一个更复杂的实现,实现一个item列表的更新。HTTP中有相应的请求方法可以用于描述操作资源的动作:
HTTP方法 | 动作 | 例子 | 功能 |
---|---|---|---|
GET | 获取资源信息 | http://example.com/api/orders | 检索订单清单 |
GET | 获取资源信息 | http://example.com/api/orders/123 | 检索订单123 |
POST | 创建一个次的资源 | http://example.com/api/orders | 使用带数据的请求,创建一个新的订单 |
PUT | 更新一个资源 | http://example.com/api/orders/123 | (使用带数据的请求,更新123订单) |
DELETE | 删除一个资源 | http://example.com/api/orders/123 | 删除订单123 |
下面我们设计一个复杂的REST API:
#!/usr/bin/env python # -*- coding: utf-8 -*- from flask import Flask from flask.ext.restful import reqparse, Api, Resource, fields, marshal_with from pymongo import MongoClient mongo_url = 'your-ip' db_name = 'your-db' col_name = 'your-col' client = MongoClient(mongo_url) col = client[db_name][col_name] col.remove({}) col.insert({'_id': 1, "name": "debugo", "values": [70, 65]}) col.insert({'_id': 2, "name": "leo", "values": [65]}) app = Flask(__name__) api = Api(app) parser = reqparse.RequestParser() parser.add_argument('name', type=str, required=True) parser.add_argument('values', type=int, help='rate is a number', action='append') class UserInfo(Resource): def get(self): return [str(i) for i in col.find({})] def post(self): args = parser.parse_args() user_id = col.count() + 1 col.insert({'_id': user_id, "name": args["name"], "values": args["values"]}) return [str(i) for i in col.find({'_id': user_id})], 201 api.add_resource(UserInfo, '/') if __name__ == '__main__': app.run(debug=True)
其中我们定义了一个参数
新建一个请求解析器RequestParser,规定类型为type,否则会拒绝并提示help的信息:
param type: The type to which the request argument should be
converted. If a type raises an exception, the message in the
error will be returned in the response. Defaults to :class:unicode
in python2 and :class:str
in python3.
param help: A brief description of the argument, returned in the
response when the argument is invalid with the name of the argument and
the message passed to any exception raised by a type converter.
在Chrome中使用Advanced REST Client这个应用来测试:
程序中成功输出下面请求结果:
127.0.0.1 – – [18/Jun/2015 18:09:23] “POST / HTTP/1.1″ 201 –
127.0.0.1 – – [18/Jun/2015 18:09:29] “GET / HTTP/1.1″ 200 –
###参考:
Flask-RESTful Document
使用python的Flask实现一个RESTful API服务器端
极客学院 Flask-RESTful 插件介绍及应用
pip install apscheduler
APScheduler提供了许多不同的方式来配置调度器,你可以使用一个配置字典或者作为参数关键字的方式传入。你也可以先创建调度器,再配置和添加作业,这样你可以在不同的环境中得到更大的灵活性。
下面是一个简单使用BlockingScheduler,并使用默认内存存储和默认执行器。(默认选项分别是MemoryJobStore和ThreadPoolExecutor,其中线程池的最大线程数为10)。配置完成后使用start()方法来启动。
from apscheduler.schedulers.blocking import BlockingScheduler def my_job(): print 'hello world' sched = BlockingScheduler() sched.add_job(my_job, 'interval', seconds=5) sched.start()
在运行程序5秒后,将会输出第一个Hello world。
下面进行一个更复杂的配置,使用两个作业存储和两个调度器。在这个配置中,作业将使用mongo作业存储,信息写入到MongoDB中。
from pymongo import MongoClient from apscheduler.schedulers.blocking import BlockingScheduler from apscheduler.jobstores.mongodb import MongoDBJobStore from apscheduler.jobstores.memory import MemoryJobStore from apscheduler.executors.pool import ThreadPoolExecutor, ProcessPoolExecutor def my_job(): print 'hello world' host = '127.0.0.1' port = 27017 client = MongoClient(host, port) jobstores = { 'mongo': MongoDBJobStore(collection='job', database='test', client=client), 'default': MemoryJobStore() } executors = { 'default': ThreadPoolExecutor(10), 'processpool': ProcessPoolExecutor(3) } job_defaults = { 'coalesce': False, 'max_instances': 3 } scheduler = BlockingScheduler(jobstores=jobstores, executors=executors, job_defaults=job_defaults) scheduler.add_job(my_job, 'interval', seconds=5) try: scheduler.start() except SystemExit: client.close()
查询MongoDB可以看到作业的运行情况如下:
{ "_id" : "55ca54ee4bb744f8a5ab08cc4319bc24", "next_run_time" : 1434017278.797, "job_state" : new BinData(0, "gAJ9cQEoVQRhcmdzcQIpVQhleGVjdXRvcnEDVQdkZWZhdWx0cQRVDW1heF9pbnN0YW5jZXNxBUsDVQRmdW5jcQZVD19fbWFpbl9fOm15X2pvYnEHVQJpZHEIVSA1NWNhNTRlZTRiYjc0NGY4YTVhYjA4Y2M0MzE5YmMyNHEJVQ1uZXh0X3J1bl90aW1lcQpjZGF0ZXRpbWUKZGF0ZXRpbWUKcQtVCgffBgsSBzoMKUhjcHl0egpfcApxDChVDUFzaWEvU2hhbmdoYWlxDU2AcEsAVQNDU1RxDnRScQ+GUnEQVQRuYW1lcRFVBm15X2pvYnESVRJtaXNmaXJlX2dyYWNlX3RpbWVxE0sBVQd0cmlnZ2VycRRjYXBzY2hlZHVsZXIudHJpZ2dlcnMuaW50ZXJ2YWwKSW50ZXJ2YWxUcmlnZ2VyCnEVKYFxFn1xF1UPaW50ZXJ2YWxfbGVuZ3RocRhHQBQAAAAAAABzfXEZKFUIdGltZXpvbmVxGmgMKGgNTehxSwBVA0xNVHEbdFJxHFUIaW50ZXJ2YWxxHWNkYXRldGltZQp0aW1lZGVsdGEKcR5LAEsFSwCHUnEfVQpzdGFydF9kYXRlcSBoC1UKB98GCxIHIQwpSGgPhlJxIVUIZW5kX2RhdGVxIk51hmJVCGNvYWxlc2NlcSOJVQd2ZXJzaW9ucSRLAVUGa3dhcmdzcSV9cSZ1Lg==") }
上面是通过add_job()来添加作业,另外还有一种方式是通过scheduled_job()修饰器来修饰函数。
@sched.scheduled_job('cron', id='my_job_id', day='last sun') def some_decorated_task(): print("I am printed at 00:00:00 on the last Sunday of every month!")
job = scheduler.add_job(myfunc, 'interval', minutes=2) job.remove() Same, using an explicit job ID: scheduler.add_job(myfunc, 'interval', minutes=2, id='my_job_id') scheduler.remove_job('my_job_id')
暂停作业:
– apscheduler.job.Job.pause()
– apscheduler.schedulers.base.BaseScheduler.pause_job()
恢复作业:
– apscheduler.job.Job.resume()
– apscheduler.schedulers.base.BaseScheduler.resume_job()
获得调度作业的列表,可以使用get_jobs()
来完成,它会返回所有的job实例。或者使用print_jobs()
来输出所有格式化的作业列表。
def some_decorated_task(): print("I am printed at 00:00:00 on the last Sunday of every month!")</pre>
默认情况下调度器会等待所有正在运行的作业完成后,关闭所有的调度器和作业存储。如果你不想等待,可以将wait选项设置为False。
scheduler.shutdown() scheduler.shutdown(wait=False)
add_job的第二个参数是trigger,它管理着作业的调度方式。它可以为date, interval或者cron。对于不同的trigger,对应的参数也相同。
year (int|str) – 4-digit year
month (int|str) – month (1-12)
day (int|str) – day of the (1-31)
week (int|str) – ISO week (1-53)
day_of_week (int|str) – number or name of weekday (0-6 or mon,tue,wed,thu,fri,sat,sun)
hour (int|str) – hour (0-23)
minute (int|str) – minute (0-59)
second (int|str) – second (0-59)
start_date (datetime|str) – earliest possible date/time to trigger on (inclusive)
end_date (datetime|str) – latest possible date/time to trigger on (inclusive)
timezone (datetime.tzinfo|str) – time zone to use for the date/time calculations (defaults to scheduler timezone)
和Linux的Crontab一样,它的值格式为:
Expression | Field | Description |
---|---|---|
* | any | Fire on every value |
*/a | any | Fire every a values, starting from the minimum |
a-b | any | Fire on any value within the a-b range (a must be smaller than b) |
a-b/c | any | Fire every c values within the a-b range |
xth y | day | Fire on the x -th occurrence of weekday y within the month |
last x | day | Fire on the last occurrence of weekday x within the month |
last | day | Fire on the last day within the month |
x,y,z | any | Fire on any matching expression; can combine any number of any of the above expressions |
几个例子如下:
# Schedules job_function to be run on the third Friday # of June, July, August, November and December at 00:00, 01:00, 02:00 and 03:00 sched.add_job(job_function, 'cron', month='6-8,11-12', day='3rd fri', hour='0-3') # Runs from Monday to Friday at 5:30 (am) until 2014-05-30 00:00:00 sched.add_job(job_function, 'cron', day_of_week='mon-fri', hour=5, minute=30, end_date='2014-05-30')
它的参数如下:
weeks (int) – number of weeks to wait
days (int) – number of days to wait
hours (int) – number of hours to wait
minutes (int) – number of minutes to wait
seconds (int) – number of seconds to wait
start_date (datetime|str) – starting point for the interval calculation
end_date (datetime|str) – latest possible date/time to trigger on
timezone (datetime.tzinfo|str) – time zone to use for the date/time calculations
例子:
# Schedule job_function to be called every two hours sched.add_job(job_function, 'interval', hours=2)
最基本的一种调度,作业只会执行一次。它的参数如下:
run_date (datetime|str) – the date/time to run the job at
timezone (datetime.tzinfo|str) – time zone for run_date if it doesn’t have one already
例子:
# The job will be executed on November 6th, 2009 sched.add_job(my_job, 'date', run_date=date(2009, 11, 6), args=['text']) # The job will be executed on November 6th, 2009 at 16:30:05 sched.add_job(my_job, 'date', run_date=datetime(2009, 11, 6, 16, 30, 5), args=['text'])
^^
Ref:
http://apscheduler.readthedocs.org/en/latest/modules/triggers
http://apscheduler.readthedocs.org/en/3.0/userguide.html
testrs:PRIMARY> config=rs.conf() testrs:PRIMARY> config.members[1].priority = 80 80 testrs:PRIMARY> config.members[1].priority = 80 80 testrs:PRIMARY> config.members[1].priority = 99 99 testrs:PRIMARY> config.members[1].priority = 1 10 testrs:PRIMARY> rs.reconfig(config) { "ok" : 1 }
这样就实现了我们的目的~
]]>auth=true
来启用这个特性。如果你是一个shard集群或者RS的环境时,你就需要为每一个节点指定keyfile,这个文件内包含相同的字符串信息(不能包含符号),用于节点成员验证。如果制定了keyfile,就默认对RS/集群启用了auth。例如以此对MongoDB中的member执行:
echo "mongomemberspassword" > /etc/mongod.key echo "keyfile=/etc/mongod.key" >> /etc/mongod.conf chown mongodb:root /etc/mongod.key chmod 600 /etc/mongod.key service mongod restart
· MongoDB提供了很多内建角色,用户通用的数据库管理。内建角色的文档在这里http://docs.mongodb.org/manual/reference/built-in-roles/。MongoDB提供了数据库管理权限和数据库用户权限两种类型,其他的权限只能作用于admin数据库上。具体如下:
针对每一个数据库进行控制。
read :提供了读取所有非系统集合,以及系统集合中的system.indexes, system.js, system.namespaces
readWrite: 包含了所有read权限,以及修改所有非系统集合的和系统集合中的system.js的权限.
每一个数据库包含了下面的数据库管理角色。
dbOwner:该数据库的所有者,具有该数据库的全部权限。
dbAdmin:一些数据库对象的管理操作,但是没有数据库的读写权限。(参考:http://docs.mongodb.org/manual/reference/built-in-roles/#dbAdmin)
userAdmin:为当前用户创建、修改用户和角色。拥有userAdmin权限的用户可以将该数据库的任意权限赋予任意的用户。
admin数据库包含了下面的角色,用户管理整个系统,而非单个数据库。这些权限包含了复制集和共享集群的管理函数。
clusterAdmin:提供了最大的集群管理功能。相当于clusterManager, clusterMonitor, and hostManager和dropDatabase的权限组合。
clusterManager:提供了集群和复制集管理和监控操作。拥有该权限的用户可以操作config和local数据库(即分片和复制功能)
clusterMonitor:仅仅监控集群和复制集。
hostManager:提供了监控和管理服务器的权限,包括shutdown节点,logrotate, repairDatabase等。
备份恢复权限:admin数据库中包含了备份恢复数据的角色。包括backup、restore等等。
admin数据库提供了一个mongod实例中所有数据库的权限角色:
readAnyDatabase:具有read每一个数据库权限。但是不包括应用到集群中的数据库。
readWriteAnyDatabase:具有readWrite每一个数据库权限。但是不包括应用到集群中的数据库。
userAdminAnyDatabase:具有userAdmin每一个数据库权限,但是不包括应用到集群中的数据库。
dbAdminAnyDatabase:提供了dbAdmin每一个数据库权限,但是不包括应用到集群中的数据库。
root: dbadmin到admin数据库、useradmin到admin数据库以及UserAdminAnyDatabase。但它不具有备份恢复、直接操作system.*集合的权限,但是拥有root权限的超级用户可以自己给自己赋予这些权限。
了解权限了之后,就是赋权语句了。新版的函数比之前的要麻烦很多:
db.createUser(user, writeConcern)
user
关于用户的身份认证和访问信息(JSON);
writeConcern
这个文档描述MongoDB提供写操作的成功报告。
user文档,定义了用户的以下形式:
{ user: "<name>", pwd: "<cleartext password>", customData: { <any information> }, roles: [ { role: "<role>", db: "<database>" } | "<role>", ... ] }
user文档字段介绍:
user字段,用户的名字;
pwd字段,用户的密码;
cusomData字段,为任意内容,例如可以为用户全名介绍;
roles字段,指定用户的角色,可以用一个空数组给新用户设定空角色;roles字段,可以指定内置角色和用户定义的角色。
那么创建一个管理员,直接给几个所有数据库权限即可。
db.createUser({ user:"test", pwd:"test.com", roles: [ { role:"userAdminAnyDatabase", db:"admin" }, { role:"readWriteAnyDatabase", db:"admin" }, { role:"dbAdminAnyDatabase", db:"admin" } ]})
创建某个数据库的只读权限,该用户首先要使用”use db_name;”到对应的数据库下创建权限,否则它会创建在其他数据库下面(比如admin)。
db.createUser({ user:"test", pwd:"test.com", roles: [ { role:"read", db:"test" } ]
以此类推。我们可以通过db.auth("username","password")
或者下面的方式来验证:
mongo -u test -p test.com --authenticationDatabase test
除了db.createUser()
,下面几个函数也是常用的:
获得数据库的所有用户权限信息:db.getUsers()
获得某个用户的权限信息:db.getUser()
创建角色: db.createRole()
更新角色:db.updateRole()
删除角色:db.dropRole()
获得某个角色信息:db.getRole()
删除用户:db.dropUser()
删除所有用户:db.dropAllUsers()
将一个角色赋予给用户:db.grantRolesToUser()
撤销某个用户的某个角色权限:db.revokeRolesFromUser()
更改密码:db.changeUserPassword()
更多内容可以去看下reference
^^
]]># 当前最新的Docker是1.6.2,Compose为1.2.0 curl -s https://get.docker.io/ubuntu/ | sudo sh sudo apt-get update sudo apt-get install lxc-docker # 参考http://docs.docker.com/compose/install/#install-compose curl -L https://github.com/docker/compose/releases/download/1.2.0/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose chmod +x /usr/local/bin/docker-compose ### 上面这个方法真的慢出翔,可以通过Python pip安装。 apt-get install python-pip python-dev pip install -U docker-compose
这样compose就安装好了,查看一下compose的版本信息:
chmod +x /usr/local/bin/docker-compose docker-compose -version docker-compose 1.2.0
使用Compose只需要简单的三个步骤:
首先,使用Dockerfile来定义你的应用环境:
FROM python:2.7 ADD ./code WORKDIR /code RUN pip install -r requirements.txt
其中,requirements.txt中的内容包括:
flask redis
再用Python写一个简单的app.py
from flask importFlaskfrom redis importRedisimport os app =Flask(__name__) redis =Redis(host='redis', port=6379)@app.route('/')def hello(): redis.incr('hits')return'Hello World! I have been seen %s times.'% redis.get('hits')if __name__ =="__main__": app.run(host="0.0.0.0", debug=True)
第二步,用一个compose.yaml来定义你的应用服务,他们可以把不同的服务生成不同的容器中组成你的应用。
web: build:. command: python app.py ports: - "5000:5000" volumes: - .:/code links: - redis redis: image: redis
第三步,执行docker-compose up
来启动你的应用,它会根据compose.yaml的设置来pull/run这俩个容器,然后再启动。
Creating myapp_redis_1... Creating myapp_web_1... Building web... Step 0 : FROM python:2.7 2.7: Pulling from python ... Status: Downloaded newer image for python:2.7 ---> d833e0b23482 Step 1 : ADD . /code ---> 1c04b1b15808 Removing intermediate container 9dab91b4410d Step 2 : WORKDIR /code ---> Running in f495a62feac9 ---> ffea89a7b090 Attaching to myapp_redis_1, myapp_web_1 ...... redis_1 | [1] 17 May 10:42:38.147 * The server is now ready to accept connections on port 6379 web_1 | * Running on http://0.0.0.0:5000/ (Press CTRL+C to quit) web_1 | * Restarting with stat
在上面的yaml文件中,我们可以看到compose文件的基本结构。首先是定义一个服务名,下面是yaml服务中的一些选项条目:
image
:镜像的ID
build
:直接从pwd的Dockerfile来build,而非通过image选项来pull
links
:连接到那些容器。每个占一行,格式为SERVICE[:ALIAS],例如 – db[:database]
external_links
:连接到该compose.yaml文件之外的容器中,比如是提供共享或者通用服务的容器服务。格式同links
command
:替换默认的command命令
ports
: 导出端口。格式可以是:
ports:-"3000"-"8000:8000"-"127.0.0.1:8001:8001"
expose
:导出端口,但不映射到宿主机的端口上。它仅对links的容器开放。格式直接指定端口号即可。
volumes
:加载路径作为卷,可以指定只读模式:
volumes:-/var/lib/mysql - cache/:/tmp/cache -~/configs:/etc/configs/:ro
volumes_from
:加载其他容器或者服务的所有卷
environment:- RACK_ENV=development - SESSION_SECRET
env_file
:从一个文件中导入环境变量,文件的格式为RACK_ENV=development
extends
:扩展另一个服务,可以覆盖其中的一些选项。一个sample如下:
common.yml webapp: build:./webapp environment:- DEBUG=false- SEND_EMAILS=false development.yml web:extends: file: common.yml service: webapp ports:-"8000:8000" links:- db environment:- DEBUG=true db: image: postgres
net
:容器的网络模式,可以为”bridge”, “none”, “container:[name or id]”, “host”中的一个。
dns
:可以设置一个或多个自定义的DNS地址。
dns_search
:可以设置一个或多个DNS的扫描域。
其他的working_dir, entrypoint, user, hostname, domainname, mem_limit, privileged, restart, stdin_open, tty, cpu_shares
,和docker run
命令是一样的,这些命令都是单行的命令。例如:
cpu_shares:73 working_dir:/code entrypoint: /code/entrypoint.sh user: postgresql hostname: foo domainname: foo.com mem_limit:1000000000 privileged:true restart: always stdin_open:true tty:true
在第二节中的docker-compose up
,这两个容器都是在前台运行的。我们可以指定-d命令以daemon的方式启动容器。除此之外,docker-compose还支持下面参数:
--verbose
:输出详细信息
-f
制定一个非docker-compose.yml命名的yaml文件
-p
设置一个项目名称(默认是directory名)
docker-compose的动作包括:
build
:构建服务
kill -s SIGINT
:给服务发送特定的信号。
logs
:输出日志
port
:输出绑定的端口
ps
:输出运行的容器
pull
:pull服务的image
rm
:删除停止的容器
run
: 运行某个服务,例如docker-compose run web python manage.py shell
start
:运行某个服务中存在的容器。
stop
:停止某个服务中存在的容器。
up
:create + run + attach容器到服务。
scale
:设置服务运行的容器数量。例如:docker-compose scale web=2 worker=3
参考:
Compose Document
boot2docker init
下载镜像、初始化VMboot2docker start
启动Linux虚拟机boot2docker ssh
ssh进入Linux命令行来操作dockerboot2docker stop
关闭Linux虚拟机boot2docker ip
输出虚拟机的IP地址docker export > mycon.tar
cat mycon.tar | docker import - mycon:latest
docker save > myimg.tar
docker load -i myimg.tar
docker tag registry_ip:5000/mycon
docker pull registry_ip:5000/mycon
^^
]]>上面提到了它可以通过两种方式运行,在release page中下载最新的war包,直接使用java -jar gitbucket.war(当然需要1.7以上的JRE环境)就可以运行,可以指定下面几个参数:
--port=[NUMBER]
--prefix=[CONTEXTPATH]
--host=[HOSTNAME]
--gitbucket.home=[DATA_DIR]
如果没有指定–gitbucket.home,它会把数据保存在$HOME/.gitbucket下面,包括用户数据库信息以及repositories。所以只把这个目录备份就可以了,是不是很方便。
打开http://[hostname]:8080/
(如果没有指定--port
更换端口的话),就可以看到登录界面,输入root/root登录到主界面中。在右上角Account Setting中可以设置新密码、用户信息、SSH公钥等信息,那么首先为这个超级管理员配置一个新的密码吧。
在右上角的Administration里可以添加新的用户/组,设置新的系统信息。系统信息里几个重要的配置项包括:
Base URL:用于重定向、git repository地址等。这个地址需要先设置DNS后配置,是必须要设置的。
Information:站点信息。
Account registration:是否给公众开放账户注册功能。
Default option to create a new repository:默认创建repository是public还是private。其中所有用户和访客都可以读取public repository,而只有collaborator才能读取private repository。
Anonymous access: 是否允许匿名用户访问public repository。选择deny则任何信息必须验证后才能访问。对于企业内部服务,一般选择deny阻止所有匿名用户的访问。
SSH access:是否启用SSH服务,如果使用需要每个用户在自己的User profile中上传自己的public key。另外,可以配置一个SSH服务使用的端口,默认是29418。
LDAP authentication/Notifacation email:不多作介绍了。
在创建好自己的用户登录后,左侧的new repository就可以建立新的repository。这里我们用一个README.md来初始化。
完成后就可以看到和github类似的项目首页,代码都可以在线编辑,灰常方便。比如我们来编辑README.md这个markdown语句。
我们可以通过git clone http://[your-server-ip]:8080/git/[your-username]/[repository-name].git
来克隆这个repository(主页右侧有这个repository的HTTP和SSH的URL提示。)。之后可以通过git push
上传本地的version。项目首页上有commits, branches和releases的历史回顾,功能很全面。
右侧项目Wiki可以让我们编辑markdown格式的wiki页面,issue可以让其他人提交issues of bugs,而Setting里可以设置我们的collaborators了:
其他先不多说了,gitbucket简单好用,向gitbucket的作者致敬!
^^