The docker basic operation

What is the docker?

docker是一個能讓你的server中,擁有乾淨的環境,以及運行各種的linux平台,例如你開啟很多web service,可能有python、php、tomcat…,這時你可透過docker,讓這些web service,都擁有各自的環境,最後透過server的apache,proxy到各項服務,至於docker跟vm有什麼不同,可以參考這篇

Pull images

docker中要使用哪個作業系統,可以透過pull這個指令,直接抓取你所需要的image來源。

假設要抓取ubuntu:

1
sudo docker pull ubuntu

之後在用images這指令去查詢目前以抓下來的source:

1
sudo docker images

會顯示以下載的image列表:

1
2
3
ubuntu                latest              8dbd9e392a96        4 months ago        131.5 MB (virtual 131.5 MB)
learn/tutorial latest 8dbd9e392a96 2 months ago 131.5 MB (virtual 131.5 MB)
learn/ping latest effb66b31edb 10 minutes ago 11.57 MB (virtual 143.1 MB)

Run

這個指令主要用來執行image裡面的指令,換句話說image已經安裝ubuntu,就可以選擇目前已經安裝的指令去執行。

像是執行linux中,拿來下指令的bash

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

執行之後就可以隨意在ubuntu下任何指令,像是常用的apt-get,安裝一些web server,如apache、nginx等的。

若是要開一個常駐的程式,只要在run加上-d,此時docker執行的指令就會變成常駐程式。

例如執行一個無窮迴圈的shell:

1
$JOB = $(sudo docker run -d ubuntu /bin/sh -c "while true; do echo Hello world; sleep 1; done")

$JOB會取得到一個實際執行的container id

如果要看到目前的執行狀況,可透過logs這個指令:

1
sudo docker logs $JOB

要刪除這個只要透過剛剛取得的container id即可:

1
sudo docker kill $JOB

假設要開啟一個tcp的服務,可以在開啟的時候就輸入對內port號(docker開啟的ubuntu port):

1
$JOB=$(sudo docker run -d -p 4444 ubuntu:12.10 /bin/nc -l 4444)

docker會將正在執行的port號,對應實體機器目前的port,例如docker中的4444 port,對到目前機器的127.0.0.1:49011(port範圍落在49000..49900)。

取得目前機器正在運行的port:

1
PORT=$(sudo docker port $JOB 4444 | awk -F: '{ print $2 }')

利用實際的port將訊息丟到docker的container中:

1
echo hello world | nc 127.0.0.1 $PORT

在透過logs查詢即可:

1
echo "Daemon received: $(sudo docker logs $JOB)"

Commit

docker中運行到一半的container,如果已經安裝或配置完畢,要保留目前的狀態,此時必須要把他存成一個image

先查詢目前的正在執行的container id

1
sudo docker ps

commit成image檔案:

1
sudo docker commit fb66b3 nginx/ubuntu

若是忘記就離開container也沒關係,可以透過ps -a的指令找到:

1
sudo docker ps -a

Exec

當你已經運行了一個docker image,此時可透過docker exec進入到運行中的container

1
docker exec nginx/ubuntu /bin/sh

Ps

查詢目前在正運行的container:

1
sudo docker ps

輸入參數-a,會將停止運行的container一起顯示出來:

1
sudo docker ps -a

Images

查詢目前擁有的images檔案,像是透過pull和自己commit

1
sudo docker images

Inspect

如果要查詢正在運行的container資訊,可以透過inspect,可以將目前container正在運行的資訊顯示出來,例如docker提供的虛擬的ip。

可以先透過sudo docker ps查詢container id,在執行inspect

1
sudo docker inspect a5e78640ece4

Dockerfile

如果是要下一連串的指令,而且每次都必須去執行的話,可透過dockerfile這個檔案,把你要執行的動作寫在上面,類似的案例像是,要佈署新版project時,那這時要做的可能是抓取project,執行一些build的動作,這時透過dockerfile就可以一鍵執行完,而不需要每次登到container中去修改。

首先要先建立一個,dockerfile

1
2
3
4
5
6
7
8
9
10
11
# Nginx
#
# VERSION 0.0.1

FROM ubuntu

# make sure the package repository is up to date
RUN echo "deb http://archive.ubuntu.com/ubuntu precise main universe" > /etc/apt/sources.list
RUN apt-get update

RUN apt-get install -y inotify-tools nginx apache2 openssh-server

透過FROM去決定執行哪個image來源,然後可使用RUNCMD,去對目前的image去執行目前的bash指令。

執行dockerfile裡面內容,其中-t是要存的image目標的名稱:

1
sudo docker build -t shykes/myapp .

Export and import

如果要存成檔案可直接透過export,要匯入則是import

將目前正在運行的container id匯出成檔案:

1
docker export a1bcbabsdhb323h2b > myfile.tar

import目前的檔案,存成image來源:

1
cat myfile.tar | docker import - newimagelocal

還有滿多沒介紹的,例如push可以發布自己的image供其他人下載等的,有興趣可以深入研究。

The ngAnimate on angular(1.2.13)

angular的ngAnimate主要是依照不同的Directive,對照不同的class做切換,以下有一張官方提供的對照表:

Directive Supported Animations
ngRepeat enter,leave and move
ngView enter and leave
ngInclude enter and leave
ngSwitch enter and leave
ngIf enter and leave
ngClass add and remove
ngShow & ngHide add and remove (the ng-hide class value)

比較值得注意的是,angular(1.2)以上的版本,是依據directive的目前的status,替換不同的class,它會在每個不同的status加上ng-....的class,如ng-enterng-leave等的。

ngRepeat為例,定義一個html結構:

1
2
3
4
5
<ul>
<li ng-repeat="role in roles" class="demo">
{{role}}
</li>
</ul>

加入一個值到roles

1
$scope.roles.push( "programer" );

則此時會先插入一個ng-enterclass,做初始配置用,接著在插入ng-enter-active的class,改變後的狀態,只有設定transition,這時就會產生動畫效果。

依照element的class名稱,css的配置如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
.demo.ng-enter {

-webkit-transition: all 1s linear;
transition: all 1s linear;

/**
* set styles
*/

}
.demo.ng-enter-active {
/**
* set styles
*/

}

若是不支援css3的瀏覽器,則必須自己實作動畫效果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
app.animation('.demo', function() {

return {

enter:function( element, done ){

doEffect( done );

return function( cancelled ) {

if ( cancelled ) {

//stopEffect();

} else {

//completeTheAnimation();
}

};
}

};

});

如果要使用到jquery來做特效,需在angular載入之前,先行載入jquery,因為angular會判斷要使用jqueryjqlite,然後再做一些處理。若要使用jquery改變顏色,則需要額外載入jquery-color。另外如果同時用javascript和css實作特效,則css特效會被javascript所覆蓋。

Example

Install

1
bower install angular angular-animate jquery jquery-color

Create a angular app and load a ngAnimate module( app.js ):

1
var app = angular.module('angularNgApp', ["ngAnimate"]);

html:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<link rel="stylesheet" href="main.css">
</head>
<body ng-app="angularNgApp">

<div ng-controller="MainCtrl">
<ul>
<li ng-repeat="thing in awesomeThings" class="demo">
{{thing}}
</li>
</ul>
</div>

<!--[if lt IE 9]>
<script src="bower_components/es5-shim/es5-shim.js"></script>
<script src="bower_components/json3/lib/json3.min.js"></script>
<![endif]-->



<!-- bower:js -->
<script src="bower_components/jquery/dist/jquery.js"></script>
<script src="bower_components/jquery-color/jquery.color.js"></script>
<script src="bower_components/angular/angular.js"></script>
<script src="bower_components/angular-animate/angular-animate.js"></script>
<!-- endbower -->

<script src="app.js"></script>
<script src="controller.js"></script>
<!--[if lt IE 9]>
<script src="animation.js"></script>
<![endif]-->


</body>
</html>

main.css:

1
2
3
4
5
6
7
8
9
10
.demo.ng-enter {

-webkit-transition: all 1s linear;
transition: all 1s linear;
background: #000;
}

.demo.ng-enter-active {
background: #fc3;
}

controller.js:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
app.controller('MainCtrl', function ( $scope, $timeout ) {

$scope.awesomeThings = [
'HTML5 Boilerplate',
'AngularJS',
'Karma'
];

$timeout( function(){

$scope.awesomeThings.push("123");

}, 2200);

});

animation.js:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
app.animation('.demo', function() {

return {
enter : function( element, done ) {

element.animate({
'background-color': 'red'
}, done);

return function( cancelled ) {

if(cancelled) {
//stopTheAnimation();
}
else {
//completeTheAnimation();
}
}
}
};
});

Aws s3 on python

在python要使用aws的s3,官方建議是透過boto這套libs。

Dependency

  • boto

Install

1
sudo pip install boto

Usage

Creating a Connection:

設定access和secret key,其中host為上傳s3位置。

1
2
3
from boto.s3.connection import S3Connection

conn = S3Connection('<aws access key>', '<aws secret key>', host = 's3.amazonaws.com' )

Getting a bucket:

如果你已經在s3的頁面建立好bucket了,可以直接使用get_bucket:

1
bucket = conn.get_bucket( 'mybucket' )

或者自己建立:

1
bucket = conn.create_bucket('mybucket')

Storing Data:

使用key去建立一個檔案,其中k.key這個值,假設有多層folder直接設定在此:

1
2
3
4
5
from boto.s3.key import Key

k = Key(bucket)
k.key = 'folder/test.txt'
k.set_contents_from_string('This is a test of S3')

之後只要在重新連線,透過k.get_contents_as_string()就可以取得到資料了。

如果要上傳一個file的話,可透過set_contents_from_filename,會將你local端的foo.jpg上傳至s3:

1
k.set_contents_from_filename('foo.jpg')

要下載則是採用get_contents_to_filename

1
k.get_contents_to_filename('bar.jpg')

最後如果想透過變數去儲存至s3,一樣使用set_contents_from_string

1
2
3
4
5
6
7
f = open( "foo.jpg", "rb" )

data = f.read()

f.close()

k.set_contents_from_string( data )

以上這些方式,需檢查k.key是否對應好s3上面的路徑。

Flask-Babel example

flask的support多國語言的方式,與python本身的gettext方式相同,都是去parse檔案裡頭含有gettext這類的語法,然後在將檔案轉成.po檔,去編輯相關的對應文字,接著放在相對應的folder,例如zhen的字眼,最後在轉成.mo,實際執行gettext會讀取.mo

Demo screenshot

Demo image

假設預設的配置如下:

1
2
3
4
5
6
7
.
├── app.py
├── babel.cfg
├── mysettings.cfg
├── README.md
└─── templates
   └── index.html

mysettings.cfg設定預設的語系(在多國語系找不到時,將會預設英文):

1
BABEL_DEFAULT_LOCALE="en"

透過from_pyfile載入:

1
app.config.from_pyfile('mysettings.cfg')

預設web接受的語系:

1
2
3
4
5
6
7
8
9
10
@babel.localeselector
def get_locale():
# if a user is logged in, use the locale from the user settings
user = getattr(g, 'user', None)
if user is not None:
return user.locale
# otherwise try to guess the language from the user accept
# header the browser transmits. We support de/fr/en in this
# example. The best match wins.
return request.accept_languages.best_match(['en','zh'])

產生.po和.mo檔

babel.cfg設定要parse的路徑:

1
2
3
[python: **.py]  
[jinja2: **/templates/**.html]
extensions=jinja2.ext.autoescape,jinja2.ext.with_

接著只要在專案的根目錄執行以下command,就會取得messages.pot檔案:

1
pybabel extract -F babel.cfg -o messages.pot .

編輯好message.mo,初始化語系路徑以及設定語系:

1
pybabel init -i messages.pot -d translations -l zh

產生translations/de/LC_MESSAGES/messages.po此路徑。

最後在將translations底下的.po檔案轉換成.mo檔即可:

1
pybabel compile -d translations

完成範例