我發現Docker基本原則是這樣的,就是
一個container只運行一個服務
一個container只運行一個服務
一個container只運行一個服務
(很重要所以說三遍)
所以以前我們可能會把 nginx + node 全部都一起裝在一台VM上,
但現在如果要把它docker化,就變成要開兩個container,一個nginx
一個node server
的服務。
而不是直接開一個ububtu(之類的)的container然後把全部東西灌在上面build成一個image。
所以如果要把上述的東西docker化,檔案結構會長成這樣
/ (專案根目錄)
| -- docker-compose.yml
` -- node
| | -- index.js
| | -- Dockerfile
`-- nginx
| | -- nginx.conf
| | -- Dockerfile
完整範例可以參考我的github
Docker安裝走這邊:(ubuntu 16.04)
https://www.digitalocean.com/community/tutorials/how-to-install-and-use-docker-on-ubuntu-16-04
一些名詞簡介
OK,所以到底啥是Dockerfile
? 啥又是docker-compose
?
Dockerfile
其實它就是用來 build image 的步驟描述檔。
如果你要建立image檔,有兩種方式:
先下載一個base image (像是ubuntu or centos那種),就像是開一台VM一樣,
然後在你開起來的那個container裡面做平常你會在VM裡面做的事情,
再把這個container的狀態commit
上去變成一個image檔。把你所有要做的事情寫成一個
Dockerfile
,然後直接下指令build就好!!
我覺得寫 Dockerfile 的好處是,你不用真的把你的image推到像是docker hub的地方,
而是直接給別人你的 Dockerfile + 需要的源碼讓人家去build就好
感覺這樣進版本庫也比較輕量(?)
docker-compose
一開始提到了,Docker的基本原則是,一個container只負責一項服務
但基本上不太可能一個APP只用到一個服務 (像是本文就用到了 node + nginx)
所以需要docker-compose
來一次幫你把你的APP(服務群?) 開好
(不然也是可以自己先把所有的image build好再一個個開起來啦只是會開到起笑)
那怎麼知道要開哪些服務哩?
這時候就需要用到docker-compose.yml
這個設定檔了
而這個設定檔怎麼寫,下面會有範例所以這邊不多說了
所以兩者關係是這樣的:
一個
Dockerfile
可以build成一個image
,
一個container
則是一個image
的實體,
而docker-compose.yml
就是描述很多個container
(or service) 之間的交互作用。(吧)
好像沒有很總結到的感覺XDDDD,直接往下看程式比較快(ㄜ)
node
index.js
(毫無反應,就只是個node server)
陽春到極致的簡單範例:
const
http =
require
(
'http'
)
const
port = process.env.PORT ||
8080
const
requestHandler =
function
handler
(
req, res
)
{
res.end(
"Hello! This is a simple node server!"
)
}
const
server = http.createServer(requestHandler)
server.listen(port, () =
>
console
.log(
`Node simple server is now listening on *:
${port}
`
))
Dockerfile
- building from ubuntu
FROM ubuntu:trusty
# install curl
&
node
RUN apt-
get
update
&
&
\
apt-
get
-y install curl
&
&
\
curl -sL https:
//deb.nodesource.com/setup_7.x | bash -
&
&
\
apt-
get
install -y nodejs
WORKDIR /src
ADD . /src
EXPOSE
8080
CMD [
"node"
,
"/src/index.js"
]
- building from node (with pm2)
直接用官方的node image環境當底,
這個方法build起來速度快很多XD
FROM node:
7.10
.1
RUN
npm
install pm2 -g
WORKDIR /src
COPY . /src
EXPOSE
8080
CMD [
"pm2-docker"
,
"process.yml"
]
- process.yml
這個是 pm2 在用的啦,順便列一下
apps:
- script :
'./index.js'
name :
'node-server'
exec_mode:
'cluster'
instances: 4
EXPOSE
好像只是讓大家知道container打算要使用哪個port,
真正要運行的時候,還是需要加上類似-p xxxx:8080
這樣的東西。
但因為我們不會直接build images出來,而是透過docker-compose
來建立整套服務,
所以到時候寫在docker-compose.yml
裡面就可以了。
手動 build image 並啟動
假如沒有要透過docker-compose
而只是想要啟用單一服務的話,
也可以先手動建立image然後啟動。
Dockerfile
就是拿來build image用的,
所以我們現在其實已經擁有所有需要的素材了。
先切到node
本身的目錄下面:
$ cd your-project/node
建立image:
$ docker build -t your-namespace/node .
build完以後執行啟動
$ docker run -d -p 3000:8080 your-namespace/node
連到*:3000
就可以看到我們的node伺服器正常運作中拉,Hooray!
nginx
nginx.conf
這 nginx 的 config 也是直接複製網路上範例,(所以我沒有深究它在幹嘛XD)
注意連到 node server 的服務的時候用的是http://nodejs:8080
其中nodejs
是寫在docker-compose.yml
裡面 node server的name
port 則是當初在 node Dockerfile 裡面EXPOSE
指定的 port
worker_processes
4
;
events
{
worker_connections
1024
; }
http
{
server
{
listen
80
;
location
/ {
proxy_pass
http://nodejs:8080;
proxy_http_version
1
.
1
;
proxy_set_header
Upgrade
$http_upgrade
;
proxy_set_header
Connection
'upgrade'
;
proxy_set_header
Host
$host
;
proxy_cache_bypass
$http_upgrade
;
}
}
}
nginx config 參數配置參考
Dockerfile
FROM
nginx
COPY nginx.conf /etc/nginx/nginx.conf
docker-compose
docker-compose.yml
首先在根目綠下面加上docker-compose.yml
這個檔案
它主要就是來告訴docker-compose
說要開哪些服務
然後這些服務彼此之間的關係等等
nginx:
build: ./nginx
links:
- nodejs:nodejs
ports:
-
"80:80"
nodejs:
build: ./node
ports:
-
"8080"
# 對外沒有port!!!!! 所以外面的人是無法直接連到 node 服務的
啟動
在專案根目錄下面執行:
$ docker-compose up -d
注意docker-compose
是要另外裝的,所以沒有要記得裝。
詳細安裝教學:(ubuntu 16.04)
https://www.digitalocean.com/community/tutorials/how-to-install-docker-compose-on-ubuntu-16-04
然後就好啦!!!
更新
假如更新程式的話怎麼辦???
像是我的node
裡面的程式碼如果更新了要怎麼辦???
因為我這邊用的是COPY
,所以基本上程式碼算是和docker分開管理(的吧)
我現在的想像是整個project都進版本庫管理
然後在專案底下執行git pull
orsvn up
之類的完畢後,使用
$ docker-compose up --build -d
來建立新版本並更新。
(而且我發現這可以在已經執行中的狀態下使用,可以無痛更新ㄚ!!!)
注意--build
這個參數,如果沒有用的話他就會使用已經建立過的版本下去跑,
這樣你更新的程式碼就完全沒用了~
其他很多像是ADD
跟COPY
差在哪啦,什麼樣的更新方式比較OK啦
這類的細節和討論我不是很清楚,
總之先可以跑起來就好了XD (欸)