
簡述
Docker是一個開源的引擎,可以輕松的為任何應用創建一個輕量級的、可移植的、自給自足的容器。
開發者在筆記本上編譯測試通過的容器可以批量地在生產環境中部署,包括VMs(虛擬機)、bare metal、OpenStack 集群和其他的基礎應用平臺。
Docker通常用于如下場景:
- web應用的自動化打包和發布;
- 自動化測試和持續集成、發布;
- 在服務型環境中部署和調整數據庫或其他的后臺應用;
- 從頭編譯或者擴展現有的OpenShift或Cloud Foundry平臺來搭建自己的PaaS環境。
準備
Docker系統有兩個程序:docker服務端和docker客戶端。
其中docker服務端是一個服務進程,管理著所有的容器。
docker客戶端則扮演著docker服務端的遠程控制器,可以用來控制docker的服務端進程。
大部分情況下,docker服務端和客戶端運行在一臺機器上。
安裝docker (我是在ubuntu上安裝的 其他環境類似)
sudo apt-get install -y docker.io
查看version版本
docker version
Client:
Version: 1.12.3
API version: 1.24
Go version: go1.6.3
Git commit: 6b644ec
Built: Wed Oct 26 21:44:32 2016
OS/Arch: linux/amd64
Server:
Version: 1.12.3
API version: 1.24
Go version: go1.6.3
Git commit: 6b644ec
Built: Wed Oct 26 21:44:32 2016
OS/Arch: linux/amd64
以上可知docker環境已經裝好了。
hello-world
現在讓我們運行一下,docker的hello world~
docker run hello-world
Hello from Docker!
This message shows that your installation appears to be working correctly.
To generate this message, Docker took the following steps:
1. The Docker client contacted the Docker daemon.
2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
3. The Docker daemon created a new container from that image which runs the
executable that produces the output you are currently reading.
4. The Docker daemon streamed that output to the Docker client, which sent it
to your terminal.
To try something more ambitious, you can run an Ubuntu container with:
$ docker run -it ubuntu bash
Share images, automate workflows, and more with a free Docker Hub account:
https://hub.docker.com
For more examples and ideas, visit:
https://docs.docker.com/engine/userguide/
由上可知,在我們運行 docker run hello-world
命令后,docker經歷了一下四個步驟。
- docker客戶端連接服務器端的守護進程。
- docker服務器端的守護進程從 Docker Hub拉取"hello-world"鏡像。
- docker服務器端的守護進程根據拉取的鏡像創建一個容器,在容器中運行了一個可執行程序輸出了你剛才看到的一串信息。
- docker服務器端進程將輸出傳給docker客戶端,顯示在你的終端上。
提示中,還建議我們運行docker run -it ubuntu bash
命令。
當我們運行以上命令時,可以發現我們進入了一個ubunt bash環境。
就好像進入到一個運行ubuntu系統的虛擬機一樣。
Images & Container
Images和Container就好比是系統鏡像ISO鏡像文件和虛擬機的關系。
Images就好比系統鏡像,Vmware可以通過系統鏡像創建虛擬機,docker也可以通過Images創建Container。
Container就好比一個虛擬機,我們可以在里面運行服務,也可以登錄進去運行命令,查看文件。
相關命令:
docker ps //查看系統中運行的docker容器
docker kill [container] //刪除docker容器
docker stop [container] //停止正在運行的docker容器
docker attach/exec [container] //進入容器
docker run //運行鏡像,生成容器
docker images //查看系統中存在的docker鏡像
docker rmi [image] //刪除鏡像
docker build //生成鏡像
docker pull //拉取鏡像
docker push //上傳鏡像
docker search //搜索鏡像
Dockerfile詳解
- 指定基礎image
FROM <image>:<tag>
- 指定鏡像創建者信息
MAINTAINER <name>
- 安裝軟件 (該指令有兩種形式)
RUN <command> (the command is run in a shell - `/bin/sh -c`)
RUN ["executable", "param1", "param2" ... ] (exec form)
- 設置container啟動時執行的操作
CMD ["executable","param1","param2"] (like an exec, this is the preferred form)
CMD command param1 param2 (as a shell)
//當Dockerfile指定了ENTRYPOINT,那么使用下面的格式:
CMD ["param1","param2"] (as default parameters to ENTRYPOINT)
- 設置container啟動時執行的操作
ENTRYPOINT ["executable", "param1", "param2"] (like an exec, the preferred form)
ENTRYPOINT command param1 param2 (as a shell)
<!--該指令的使用分為兩種情況,一種是獨自使用,另一種和CMD指令配合使用。
當獨自使用時,如果你還使用了CMD命令且CMD是一個完整的可執行的命令,那么CMD指令和ENTRYPOINT會互相覆蓋只有最后一個CMD或者ENTRYPOINT有效。
另一種用法和CMD指令配合使用來指定ENTRYPOINT的默認參數,這時CMD指令不是一個完整的可執行命令,僅僅是參數部分;
ENTRYPOINT指令只能使用JSON方式指定執行命令,而不能指定參數。-->
- 設置container容器的用戶(默認root)
USER root
- 指定容器需要映射到宿主機器的端口
EXPOSE <port> [<port>...]
# 映射一個端口
EXPOSE port1
# 相應的運行容器使用的命令
docker run -p port1 image
# 映射多個端口
EXPOSE port1 port2 port3
# 相應的運行容器使用的命令
docker run -p port1 -p port2 -p port3 image
# 還可以指定需要映射到宿主機器上的某個端口號
docker run -p host_port1:port1 -p host_port2:port2 -p host_port3:port3 image
- 設置環境變量
ENV <key> <value>
- 從src復制文件到container的dest路徑
COPY <src> <dest>
- 從src復制文件到container的dest路徑
ADD <src> <dest>
<src> 是相對被構建的源目錄的相對路徑,可以是文件或目錄的路徑,也可以是一個遠程的文件url,如果是壓縮包會被自動解壓。
<dest> 是container中的絕對路徑s
- 指定掛載點
//設置指令,使容器中的一個目錄具有持久化存儲數據的功能,該目錄可以被容器本身使用,也可以共享給其他容器使用。
VOLUME ["<mountpoint>"]
eg:
VOLUME ["/tmp/data"]
- 切換目錄
WORKDIR /path/to/workdir
# 在 /p1/p2 下執行 vim a.txt
WORKDIR /p1 WORKDIR p2 RUN vim a.txt
- 在子鏡像中執行
ONBUILD <Dockerfile關鍵字>
docker中運行express項目
現在讓我們開始實戰一下,生成一個express項目,將之使用docker部署。
生成express項目
使用express-generator生成expess項目。
npm install -g express-generator
express express-jerrwy
//可以看到項目創建出來了,目錄如下
app.js bin node_modules package.json public routes views
安裝依賴
npm i
//運行項目
npm start
訪問localhost:3000可以看到express 歡迎頁面,表示express項目創建成功。
編寫Dokerfile
在項目根目錄,新建一個Dockerfile文件,該文件名就叫Dockerfile,注意大小寫,沒有后綴,否則會報錯。
Dockerfile文件定義了如何創建Docker鏡像。
我的Dockerfile如下:
FROM node:6.9.1
USER root
RUN npm config set registry https://registry.npm.taobao.org
WORKDIR /var/workspace
COPY package.json /var/workspace/package.json
RUN npm install && npm cache clean
COPY . /var/workspace
大致解釋一下里面做了什么:
- 我使用基礎鏡像 node:6.9.1,也就是一個鏡像,里面裝了node 6.9.1
- 我鏡像里面使用的用戶是root
- 執行命令,設置 npm源
- 設置鏡像的工作目錄
- 將package.json拷貝到鏡像的工作目錄中
- 安裝依賴
- 將項目代碼拷貝到工作目錄
生成鏡像
Dockerfile寫好之后,我們就可以生成鏡像了。
docker build . -t moyunchen/express-jerrwy:test
moyunchen/express-jerrwy:test
中moyunchen
是我docker hub的賬號名,express-jerrwy
是鏡像名稱,test
是鏡像標簽,相當于版本號。
第一次生成鏡像由于要下載基礎鏡像,速度可能比較慢,稍等十幾分鐘,出去喝杯茶~。
生成成功之后,運行命令:
docker images
//可以看到
REPOSITORY TAG IMAGE ID CREATED SIZE
moyunchen/express-jerrwy test 754d9122fa3e 13 hours ago 663.7 MB
表明你的docker鏡像已經生成啦~
其實,現在你就已經可以運行鏡像,生成容器了。
docker run -itd -p 3000:3000 --name express01 moyunchen/express-jerrwy:test npm start
打開localhost:3000 我們可以看到express歡迎信息。說明我們的exress項目在docker部署成功了。
查看docker容器
docker ps
//可以看到
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
b8106d910823 moyunchen/express-jerrwy:test "npm start" 6 seconds ago Up 4 seconds 0.0.0.0:3000->3000/tcp express01
這就是我們正在運行中的docker容器,里面跑了我們的express服務。
登錄進去看看
docker exec -it b8106d910823 bash
//可以看到
root@b8106d910823:/var/workspace# ls
Dockerfile app.js bin node_modules package.json public routes views
這個就是docker中項目目錄中我們的項目代碼。
push鏡像到docker hub
docker hub就好比github,是官方的鏡像公有倉庫。
我們將鏡像發布到這個上面,其他人就可以直接將你的鏡像pull下來,然后運行。
就不用單獨的把代碼pull下來,自己build鏡像了。
登錄docker賬號
docker login
//接下來他會讓你輸入賬號密碼郵箱
Username: [username]
Password: [password]
Email: xxxx@foxmail.com
WARNING: login credentials saved in /root/.docker/config.json
Login Succeeded
push鏡像到docker hub倉庫
docker push moyunchen/express-jerrwy:test
moyunchen
是你的docker賬號名,生成鏡像的時候也必須是 [username]/[imagename]
這種格式
push的過程異常緩慢。。。我這里用了幾個小時。。。只是第一次才慢,后面是增量更新就會快很多。。
成功之后,登錄docker hub就可以看到你的鏡像了。
從docker hub拉取鏡像,生成容器
現在,你的鏡像推送到了docker hub上面了,讓你的項目伙伴拉取項目鏡像,運行起來。
拉取鏡像
docker pull moyunchen/express-jerrwy:test
運行鏡像,創建容器的步驟,跟上面一樣。
docker-compose
docker-compose是用于定義和運行復雜Docker應用的工具。
你可以在一個文件中定義一個多容器的應用,然后使用一條命令來啟動你的應用,然后所有相關的操作都會被自動完成。
在上面過程中,我們運行容器的命令過于復雜,而且一次只能啟動一個docker應用,管理起來也不是很方便。
于是就有懶惰
的程序員創建了docker-compose
安裝
以ubuntu系統舉例
curl -L https://github.com/docker/compose/releases/download/1.3.1/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose
chmod +x /usr/local/bin/docker-compose
//這個裝起來也好慢。。。是因為墻的原因吧。。
安裝完成之后
docker-compose --version
//可以看到
docker-compose 1.8.1
到這里,你的docker-compose就算安裝成功了。
docker-compose.yml
docker-compose.yml文件的目的是定義了一組應用,可以很方便的對多個應用進行發布。
我的理解是取代了docker run
,因為docker run 命令使用起來過于繁瑣。
當然,如果你不想用docker-compose,你可以將對于的docker-compose.yml翻譯成docker run語法。
還是以上面的express-jerrwy鏡像為例,對應的 docker-compose.yml文件
version: '2'
services:
express-jerrwy:
ports:
- "3000:3000"
image: "docker.io/moyunchen/express-jerrwy:test"
container_name: "express-jerrwy"
restart: always
command: "npm start"
現在docker-compose.yml寫好了,上面我們只定義了express-jerrwy一個docker服務,我們完全可以一次定義多個。
我們現在創建容器
docker-compose up -d
關閉容器
docker-compose down
以后我們部署項目,就只需要寫好docker-compose.yml文件,就可以利用docker-compose進行項目部署。
是不是簡單了很多。
daocloud
上面我們用的docker hub 為公有倉庫。
我們發布的應用鏡像是所有人都可以下載得到的。
如果使我們公司的項目,里面含有一個不能公開的東西,那公有倉庫也就不適合我們了。
所以我們就可以使用私有倉庫,例如 daocloud
使用方法跟公有倉庫區別不大。