Docker-Basic

sialvsic發表於2017-10-03

什麼是docker?

Docker是基於go語言實現的開源容器專案,誕生於2013年年初,最初發起者是,dotCloud公司。

Docker 專案已加入Linux基金會,並遵循Apache2.0協議,全部程式碼再github上維護。

Docker的構想是要實現Build Ship and Run Any app anywhere 即通過對應用的封裝,分發,佈署,執行生命週期進行管理,達到應用元件一次封裝,到處執行的目的。

這裡的應用元件不侷限於web應用,可以是一個編譯環境,可以是一個資料庫平臺服務,甚至可以是作業系統和叢集。

Docker的發展建立在Linux容器技術之上。

為什麼使用Docker?

在雲時代,應用程式可以脫離底層物理硬體的限制,在任何時間任何地點即可獲取。這樣子可以做到快速的分發和部署。通過Docker來打包應用,解耦應用和執行平臺。降低開發成本和部署風險。

Docker優點

  • 更快速的交付和部署
  • 更高效的資源利用
  • 更輕鬆的遷移和擴充套件
  • 更簡單地更新管理

Docker核心概念

映象: 只讀模板,包含一個基本的作業系統 容器: 一個輕量級的沙箱,容器是從映象建立的,應用的執行例項。可以啟動開始停止刪除,容器彼此間相互隔離。 倉庫: 類似於程式碼倉庫,是集中存放映象檔案的場所。

Docker Image - Docker映象

如何使用Docker映象

Docker執行容器前需要本地存在對應的映象,如果映象沒儲存在本地,Docker會嘗試先從預設映象倉庫下載。 使用docker pull命令可以直接從Docker Hub映象源來下載映象。

docker pull NAME[:TAG]
NAME: 映象的名稱
TAG: 映象的版本
複製程式碼

eg: 綜上,一個映象需要的資訊就是名稱+標籤

docker pull ubuntu:14.04
14.04: Pulling from library/ubuntu
bae382666908: Pull complete
29ede3c02ff2: Pull complete
da4e69f33106: Pull complete
8d43e5f5d27f: Pull complete
b0de1abb17d6: Pull complete
Digest: sha256:6e3e3f3c5c36a91ba17ea002f63e5607ed6a8c8e5fbbddb31ad3e15638b51ebc
Status: Downloaded newer image for ubuntu:14.04
複製程式碼

如果不顯示的指定TAG,預設會選擇latest標籤。會下載最新版的映象。

啟動映象

下載到本地後,可以利用該映象建立一個容器

docker run -it ubuntu:14.04 bash
/* 
-i
-t 
*/

root@4a9c106836e1:/#
複製程式碼

執行完成會進入bash介面,可以執行一些基本操作

檢視映象的資訊

docker images

REPOSITORY                             TAG                 IMAGE ID            CREATED             SIZE
calculatorapp                          latest              1dec489fae9a        12 hours ago        955MB
<none>                                 <none>              2dab0d648733        6 days ago          755MB
node                                   6.11.1              1ffbfd4a58ec        2 months ago        656MB

引數
docker iamges
-a 列出所以映象
  
複製程式碼

使用Tag命令新增映象標籤

docker tag ubuntu:lastest myubuntu:lastest
  
REPOSITORY                             TAG                 IMAGE ID            CREATED             SIZE
myubuntu                               lastest             dea1945146b9        2 weeks ago         188MB
ubuntu                                 14.04               dea1945146b9        2 weeks ago         188MB
複製程式碼

實際上看到IMAGE ID是一樣的,所以上實際指向同一個映象檔案。

刪除映象

1.通過標籤刪除

docker rmi IMAGE[IMAGE...]
複製程式碼

eg:

REPOSITORY                             TAG                 IMAGE ID            CREATED             SIZE
myubuntu                               lastest             dea1945146b9        2 weeks ago         188MB

docker rmi myubuntu:latest
複製程式碼

2.通過ID刪除

docker rmi ID
複製程式碼
REPOSITORY                             TAG                 IMAGE ID            CREATED             SIZE
myubuntu                               lastest             dea1945146b9        2 weeks ago         188MB

docker rmi dea1945146b9
複製程式碼

注意 在刪除時,如果沒有容器使用這個映象,那麼會直接刪除該映象及包含的所有層。 但是如果有容器使用了該映象,會得到該提示

docker rmi myubuntu:lastest
Error response from daemon: conflict: unable to remove repository reference "myubuntu:lastest" (must force) - container 4a9c106836e1 is using its referenced image dea1945146b9
複製程式碼

有兩種方式可以解決:

  • 使用-f 引數強制刪除(不推薦)
  • 先刪除容器,在刪除映象

建立映象

三種方式建立映象:

  • 基於已有映象的容器建立
  • 基於本地模板匯入
  • 基於Dockerfile建立

Docker container - Docker 容器

容器是映象的一個執行例項。

容器建立

使用docker create建立完畢的容器處於停止狀態,可以使用docker start命令來啟動

docker create
-d 是否在後臺執行
複製程式碼

eg:

docker create -it ubuntu:latest
bb821ea158758312d0832d2c971aab1665cce73541f04f22ca292f979c871e2e

docker ps -a
CONTAINER ID        IMAGE               COMMAND          CREATED             STATUS                     PORTS               NAMES
bb821ea15875        ubuntu:latest       "/bin/bash"      3seconds ago        Created                                        adoring_archimedes
複製程式碼

啟動容器

使用docker start命令來啟動一個已經建立的容器

docker start [container_name/container_id]
複製程式碼
CONTAINER ID        IMAGE               COMMAND          CREATED             STATUS                     PORTS               NAMES
bb821ea15875        ubuntu:latest       "/bin/bash"      3seconds ago        Created                                        adoring_archimedes

docker start bb821ea15875
or 
docker start adoring_archimedes
複製程式碼

檢視執行的容器

使用docker ps命令來檢視正在執行的容器

docker ps 
-a 檢視所有的容器

複製程式碼

新建並啟動容器

docker run = docker create + docker start

docker run
-i 讓容器的標準輸入保持開啟
-t 讓docker分配一個偽終端(pseudo-tty),並繫結到容器的標準輸入上
複製程式碼

eg:

docker run -it ubuntu:14.04 /bin/bash
在ubuntu14.04上啟動一個bash終端,並允許使用者互動

可以使用exit或者ctrl+d來退出容器
複製程式碼

守護態執行(後臺執行)

docker run -d ubuntu:14.04 /bin/bash
-d 後臺執行並輸出 container ID
複製程式碼

注意 如果是以後臺執行的,可以使用docker logs [container_name/container_id]的方式來獲取容器的輸出資訊

終止容器

docker stop [container_name/container_id]
複製程式碼

進入容器

在使用-d引數時,容器啟動會進入後臺。使用者無法看到容器中的資訊,也無法進行操作

三種方式解決:

  • attach命令(不推薦使用)
  • exec 命令(推薦使用)
  • nsenter工具(不推薦)
docker exec -it  [container_name/container_id] /bin/bash
-i 開啟標準輸入接受使用者的輸入
-t 讓docker分配一個偽終端(pseudo-tty),並繫結到容器的標準輸入上
-u 執行命令的使用者
複製程式碼

刪除容器

docker rm [container_name/container_id]
-f 強制終止並刪除一個正在執行的容器
複製程式碼

Docker Repository - Docker 倉庫

倉庫:

  • 公有倉庫
  • 私有倉庫

docker hub:docker官方的公共映象倉庫

Docker 資料管理

容器管理資料有兩種方式:

  • 資料卷(Data Volumes): 容器內的資料直接對映到本地主機環境
  • 資料卷容器(Data Volume Containers): 使用特定容器維護資料卷

資料卷

什麼是資料卷? 可供容器使用的特殊目錄,它將主機作業系統目錄直接對映進容器

優勢:

如何建立資料卷?

三種方式:

  • 容器內部建立一個資料卷
  • 掛載一個主機目錄作為資料卷
  • 掛載一個本地的主機檔案作為資料卷(不推薦)

容器內部建立一個資料卷

在容器內建立一個資料卷使用-v 引數,本質上就是容器內部建立了一個資料夾

docker run -it -v /webapp  ubuntu
//在容器內部建立一個資料夾

-v Bind mount a volume 
複製程式碼

eg:

docker run -it ubuntu
root@f22d574bb63f:/# ls
bin  boot  dev  etc  home  lib  lib64  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var

docker run -it -v /webapp  ubuntu
root@c3acf065e9c2:/# ls
bin  boot  dev  etc  home  lib  lib64  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var  webapp

//多了一個webapp資料夾
複製程式碼

掛載一個主機目錄作為資料卷(推薦)

也是使用-v 引數,

docker run -it -v /src/webapp:/opt/webapp  ubuntu 
//將本地的/src/webapp目錄掛載到容器內部的/opt/webapp
複製程式碼

本地目錄路徑必須是絕對路徑,如果目標目錄不存在,docker會自動建立。但是如果目標存在,???

Docker 掛載的資料卷預設許可權是讀寫(rw),也可以更改

資料卷容器

建立一個資料卷容器可以在多個容器之間共享一個持續更新的資料。

如何建立?

docker run -it --name dbdata -v /dbdata ubuntu
//建立一個dbdata的資料夾作為共享資料卷
--name 給容器起一個名字
複製程式碼

其他容器如何使用這個共享的資料卷?

docker run -it --volumes-from dbdata --name db1 ubuntu
//將一個container名字為dbdata的資料卷也掛載到當前的容器中
--volumes-from Mount volumes from the specified container(s) 從指定的container來掛載卷
複製程式碼

利用容器捲來做資料備份 1.備份

$ docker run --volumes-from dbdatasrc -v $(pws):/backup --name worker ubuntu tar cvf /back/backup.tar /dbdata
//將容器dbdatasrc內部的資料卷(/dbdata)掛載到新的ubuntu的容器上(起名為worker容器),此時worker容器內部會有/dbdata的資料卷.
//同時將/dbdata內部的所有資料壓縮打包到worker容器下的/back目錄下。 實現資料備份。

複製程式碼

埠對映和容器互聯

從外部訪問容器應用(埠對映)

在啟動容器的時候,如果不指定對應的引數,在容器外部是無法通過網路來訪問容器內的網路應用和服務的。

如何讓外部的訪問容器? 1.通過-P 大寫P 使用-P標記時,Docker會隨機對映一個49000~49900的埠到容器開放的網路埠:

CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS                     NAMES
5ad0d233c126        training/webapp     "python app.py"     46 seconds ago      Up 44 seconds       0.0.0.0:32768->5000/tcp   dazzling_kirch
複製程式碼

2.通過-p 小寫p 可以指定要對映的埠 支援的格式

HostPort:Container | Ip:HostPort:Container  | Ip::ContainerPort
複製程式碼

第一種HostPort:Container, 將本地的埠對映到容器的指定埠 對映所有介面地址

docker run --name test1 -p 5000:5000 training/webapp python app.py
//將本地的5000埠對映到容器的5000埠

CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS                     NAMES
f7f8a05e63a9        training/webapp     "python app.py"     3 seconds ago       Up 3 seconds        0.0.0.0:5000->5000/tcp    ecstatic_einstein

docker run -p 5000:5000 -p 3000:80 ubuntu 
複製程式碼

這時繫結的是所有IP段的5000埠到容器的5000

第二種IP:HostPort:ContainerPort, 將本地的指定IP的埠對映到容器的指定埠 對映到指定地址的指定埠

docker run --name test2 -p 127.0.0.1:5000:5000 training/webapp python app.py
//將本地的ip僅為127.0.0.1的5000對映到容器的5000

CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS                      NAMES
bd4e352c3b48        training/webapp     "python app.py"     2 minutes ago       Up 2 minutes        127.0.0.1:5000->5000/tcp   test1
複製程式碼

第三種Ip::ContainerPort, 對映到指定地址的任意埠

docker run --name test3 -p 127.0.0.1::5000 training/webapp python app.py
//繫結127.0.0.1的任意埠到容器的5000埠,本地主機會隨機分配一個埠

CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS                       NAMES
b804acc891df        training/webapp     "python app.py"     5 seconds ago       Up 3 seconds        127.0.0.1:32768->5000/tcp   test3
複製程式碼

檢視埠對映配置情況

docker port [container_name/container_id]

eg:
docker port b804acc891df
5000/tcp -> 127.0.0.1:32768 
//表示容器的5000對映在本地主機的127.0.0.1:32768

or:
docker port b804acc891df 5000
127.0.0.1:32768 
複製程式碼

容器互連

容器互連是一種讓多個容器中的應用進行快速互動的方式。它會在源和接收容器之間建立連線關係,接收容器可以通過容器名快速的訪問到源容器,而不用指定IP地址。

自定義容器命名,在建立容器的時候,使用--name引數,否則系統會隨機生成一個名字。

使用--link引數可以讓容器之間安全的進行互動。 eg:

1.建立一個新的資料庫容器
$ docker run -d --name db-container training/postgres

2.建立一個新的web容器可以訪問這個資料庫容器
$ docker run -d -P --name web --link db-container:db training/webapp python app.py
// --link name:alias 
//name: 要連線的容器名稱
//alias: 連線的別名 (這個是啥意思?有什麼用?)

docker ps

CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                     NAMES
c5797ccc4f95        training/webapp     "python app.py"          2 hours ago         Up 2 hours          0.0.0.0:32769->5000/tcp   web
cdd159304af3        training/postgres   "su postgres -c '/..."   2 hours ago         Up 2 hours          5432/tcp                  db-container
複製程式碼

Docker 相當於在兩個互連的容器之間建立了一個虛擬通道,而且不用對映他們的埠到宿主主機上。

docker通過兩種方式為容器公開連線資訊:

  • 更新環境變數
  • 更新/etc/hosts檔案

我的理解:如果兩個容器互連,那麼他們之間肯定需要通過一些方式去聯通。此處的db-container 相當於父容器。 它的hosts資訊如下: db-container/etc/hosts

127.0.0.1	localhost
::1	localhost ip6-localhost ip6-loopback
fe00::0	ip6-localnet
ff00::0	ip6-mcastprefix
ff02::1	ip6-allnodes
ff02::2	ip6-allrouters
172.17.0.2 	cdd159304af3   <= 自己的容器的ID
複製程式碼

那與之相連的web容器就不太一樣了 web/etc/hosts:

127.0.0.1	localhost
::1	localhost ip6-localhost ip6-loopback
fe00::0	ip6-localnet
ff00::0	ip6-mcastprefix
ff02::1	ip6-allnodes
ff02::2	ip6-allrouters
172.17.0.2 	db db-container cdd159304af3 <= --link 的引數db-container:db
172.17.0.3  c5797ccc4f95 <= 自己的容器的ID
複製程式碼

參考資料

書籍:《Docker 技術入門與實戰》