1. 程式人生 > 其它 >Python樸素貝葉斯

Python樸素貝葉斯

技術標籤:Dockerdocker

一、Docker簡介

Docker是一個作業系統級的虛擬化技術,是基於LXC技術構建的輕量級容器引擎。

LXC技術:LXC是Linux Container的縮寫,Linux Container容器是一種核心虛擬化技術,可以提供輕量級的虛擬化,以便隔離程序和資源。

img

二、Docker入門

1.在Linux中下載並安裝Docker

1.1.前提條件

Docker要求CentOS系統核心高於3.10

uname -r 檢視當前系統核心版本

[[email protected] ~]# uname -r
3.10.0-1127.19.1.el7.x86_64

如果版本達不到要求需要更新

yum -y update:升級所有包同時也升級軟體和系統核心
yum -y upgrade:只升級所有包,不升級軟體和系統核心。

從 2017 年 3 月開始 docker 在原來的基礎上分為兩個分支版本: Docker CE 和 Docker EE。

Docker CE 即社群免費版,Docker EE 即企業版,強調安全,但需付費使用。

1.2.解除安裝舊版本的Docker

 yum -y remove docker docker-engine docker.io containerd runc

1.3.通過yum安裝 Docker

安裝一些必要的系統工具

yum install -y yum-utils device-mapper-persistent-data lvm2

新增軟體源資訊

yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo

更新yum快取

yum makecache fast

安裝Docker-ce

yum -y install docker-ce

啟動Docker

systemctl start docker

1.4.使用指令碼安裝Docker

curl -fsSL https://get.docker.com -o get-docker.sh
bash
get-docker.sh

安裝Docker並將映象源修改成阿里的映象源

curl -fsSL https://get.docker.com -o get-docker.sh
bash get-docker.sh --mirror Aliyun

1.5.啟動Docker程序

systemctl start docker

1.6.驗證docker是否成功安裝 待確定

docker ps 

1.7.映象加速

docker在海外,後續拉取映象十分緩慢,可以把映象源改成國內的

在 /etc/docker/daemon.json檔案裡新增配置,沒有就建立一個

{ 
   "registry-mirrors": ["http://hub-mirror.c.163.com"] }
{

1.8.映象源

Docker官方中國區

https://registry.docker-cn.com

網易

http://hub-mirror.c.163.com

阿里雲

https://pee6w651.mirror.aliyuncs.com

中國科學技術大學

https://docker.mirrors.ustc.edu.cn

刪除Docker

yum remove docker-ce
rm -rf /var/lib/docker

2.Hello,Docker!

2.1.映象和容器的概念

映象

映象可以理解為一個打包了執行環境的特殊檔案系統,它包含了容器啟動執行所需的所有資訊,包括執行程式和配置資料等。映象不包含任何動態資料,其內容在構建之後也不會改變。

例如,一個官方的Ubuntu14.04映象,就包含了一套完整的Ubuntu14.04最小系統的root檔案系統。

容器

映象和容器的關係,類似於面向物件程式設計中的類和例項一樣,映象是靜態的定義,而容器是映象執行時的實體,可以看成是一個具備某個執行環境的非常輕量的虛擬機器。容器可以被建立、啟動、停止和刪除等。在建立容器時,需要顯示地為容器指定映象。指定映象之後,容器就具備了映象中儲存的執行環境了。

例如,可以為容器指定Ubuntu14.04的映象,然後該容器就具備Ubuntu14.04的執行環境了。

2.2.Docker使用基本過程

1.獲取映象

在安裝完Docker服務之後,本地是沒有任何映象的,所以首先需要獲取所需要的映象。

2.基於該映象建立並啟動一個容器

在獲取到所需的映象之後,就可以基於該映象建立並啟動一個容器,該容器就具備了映象包含的執行環境了。同時,在建立容器時也可以設定容器的啟動命令,該命令會在容器啟動時執行。

3.進入該容器,執行“程式”

在容器成功建立並啟動之後,該容器就具備了ubuntu的執行環境。我們可以進入該容器內部,並在其內部執行任何在ubuntu系統上的程式了。這裡的“程式”可以是“Linux命令”、“shell指令碼”、“C++程式”等。

2.3.啟動一個容器並輸出Hello Docker

docker pull busybox:latest
docker run --name first_docker_container busybox:latest echo "Hello Docker"
  • 第一條命令:獲取一個名為busybox:latest的映象。這條命令會從Docker Hub官方映象倉庫獲取一個名為busybox:latest的映象(busybox的最新版),並把它下載到宿主機。其中busybox是最小的Linux系統。
  • 第二條命令: 建立並啟動一個容器,並執行相應命令。首先,–name設定容器的名字為first_docker_container,然後為容器指定了busybox:latest作為啟動映象,最後設定了該容器的啟動命令為echo “Hello Docker”。容器啟動並輸出 “Hello Docker”後,將其停止。

3.拉取映象

3.1.獲取映象

docker pull [選項] <倉庫名> <標籤>
  • docker pull:Docker拉取映象的命令關鍵詞;
  • [選項]:命令選項;
  • 倉庫名:倉庫名的格式一般為<使用者名稱>/<軟體名>。對於Docker Hub,如果不指定使用者名稱,則預設為library,即官方映象;
  • 標籤:標籤是區分映象不同版本的一個重要引數,<倉庫名>:<標籤>會唯一確定一個映象。預設為latest。

例如拉取一個Ubuntu 14.04的官方映象

docker pull ubuntu:14.04

如果標籤為空的話就會使用預設的標籤,也就是latest,執行上面的命令後預設會去Docker Hub中尋找名為repoName的倉庫,不存在則返回錯誤資訊,如果存在,就從倉庫拉取對應的標籤的映象。

不加標籤預設拉取最新的版本

docker pull ubuntu latest

拉取一個不存在的映象會報錯

[[email protected] Desktop]# docker pull aaa
Using default tag: latest
Error response from daemon: repository aaa not found: does not exist or no pull access

4.啟動一個容器

啟動容器有兩種方式,一種是基於映象新建一個容器並啟動,另外一個是將在終止狀態的容器重新啟動。

4.1.第一種方式:新建並啟動

docker run命令會基於指定的映象建立一個容器並且啟動它。docker run的基本語法如下:

docker run [選項] 映象名 [命令] [引數]

docker run: Docker建立並啟動容器的命令關鍵詞;

  • 選項: 命令選項,最常用的包括
    • -d後臺執行容器並返回容器ID,
    • -i以互動模式執行容器,
    • -t為容器分配一個偽輸入終端,
    • –name 指定啟動容器的名稱。
  • 映象名: 以<倉庫名>:<標籤>的方式來指定;
  • 命令: 設定啟動命令,該命令在容器啟動後執行;
  • 引數: 其他一些引數。

docker run背後的工作

Docker在後臺執行的標準操作包括:

  1. 檢查本地是否存在指定的映象,不存在就從公有倉庫下載啟動;
  2. 利用映象建立並啟動一個容器;
  3. 分配一個檔案系統,並在只讀的映象層外面掛載一層可讀寫層;
  4. 從宿主主機配置的網橋介面中橋接一個虛擬介面到容器中去;
  5. 從地址池配置一個ip地址給容器;
  6. 執行使用者指定的啟動命令;
  7. 執行完畢後容器被終止。

例項一

建立並啟動一個容器,容器中具有ubunt的執行環境,輸出hello docker

docker run ubunt:14.04 echo 'hello docker'

例項二

建立並啟動一個容器,容器中具有Ubuntu的執行環境,容器名為firstContainer,為容器分配一個終端,與使用者進行互動

docker run -it --name firstContainer ubunt /bin/bash
  • -i選項告訴Docker保持標準輸入輸出流對容器開放,-t選項讓Docker分配一個偽終端(pseudo-tty)並繫結到容器的標準輸入上;–name為容器設定容器名。
  • docker run是建立一個新容器並啟動,所以這條命令建立的容器與上個例項的建立的容器不是同一個容器。而且由於本地已經存在ubuntu:latest映象了,所以並不需要再次從Docker Hub中下載,而是直接使用本地的ubuntu:latest映象構建容器。
  • 啟動容器之後,我們進入容器內部並在終端進行與容器互動。我們可以根據左側的命令提示符判斷自己是否在容器內部。例如上面的例子,當左側的命令提示符為[email protected]時,表示我們在容器外部,而命令提示符為:[email protected]/時,表示我們在容器內部,且容器的ID是fe263c9359dd。我們可以通過exit退出當前的容器。

4.2.第二種方式:啟動一個已經終止的容器

docker run 每次都會建立一個新的容器,可以通過docker start命令,使用容器名或容器id啟動一個已經終止的容器

docker start [選項] 容器 [容器2...]
  • docker start: Docker啟動容器的命令關鍵詞;
  • 選項: 命令選項;
  • 容器: 需要啟動的容器,該容器用“容器ID”或“容器名”表示,如果指定了多個容器,那麼就將這些容器都啟動。

現有名為firstContainer的容器處於終止狀態,可以通過docker start firstContainer啟動它。

4.3.檢視容器資訊

如果既不知道容器名,又不知道容器id,可以使用docker ps 來檢視容器的資訊。

docker ps -a 可以檢視Docker內的所有容器,

docker ps -a命令執行結果

[[email protected] ~]# docker ps -a
CONTAINER ID   IMAGE            COMMAND                 CREATED         STATUS     PORTS          NAMES

faeacc3b5aa7   busybox:latest   "echo 'Hello Docker'"   2 minutes ago   Exited (0) 2 minutes ago  first

5799b6f4eeee   busybox:latest   "echo 'Hello Docker'"   8 minutes ago   Exited (0) 8 minutes ago  first_docker_container

例項

建立並啟動一個容器,容器名為firstContainer,具備busybox的執行環境。並輸出hello world

docker busybox
docker run --name firstContainer busybox:latest echo "hello worldr"

5.停止一個容器

5.1.使用docker stop停止一個容器

docker stop可以用來終止一個正在執行的容器。它的命令格式如下:

docker stop [OPTIONS] Container [Container ...]

其中:

docker stop: Docker停止容器的命令關鍵詞;

OPTIONS:命令選項,其中-t指定等待多少秒後如果容器還沒終止,就強行停止,預設等待10秒;

Container:需要啟動的容器,該容器用“容器ID”或“容器名”表示,如果指定了多個容器,那麼就將這些容器都啟動。

停止一個名為firstContainer的容器,可以執行

docker stop firstContainer

執行完成後該容器會處於終止狀態,可以通過docker ps -a檢視。

5.2.什麼情況下容器啟動後會立即終止?

除了使用docker stop命令來強制地終止一個容器以外,當容器的啟動命令終結時,容器也自動會終止。以

docker run --name testcontainer ubuntu echo 'hello docker

為例,echo 'hello docker’就是該容器的啟動命令。實際上執行完這條命令後,執行docker ps -a,可以發現testcontainer容器是處於終止狀態的。

5.3.如何才能使容器啟動後不立即終止

如果容器的主程序不停止,容器就不會停止。

5.3.1.將啟動命令設定為死迴圈
docker run ubuntu:14.04 /bin/sh -c "while true; do echo hello world; sleep 1; done"

這條命令在建立並啟動容器之後,會執行/bin/sh -c “while true; do echo hello world; sleep 1; done”,由於該命令永遠都不會執行完畢,除非強行終止,所以容器的主程序sh不會停止,因此容器也將不會停止。但是這樣的做的話,無法正常的操作容器,而且它會佔據資源,所以這種做法在實際的工作中意義並不大,/bin/sh -c 將字串當命令來執行。

5.3.2.將命令設定為“啟動一直執行的子程序”
docker run --name first_container -it ubuntu /bin/bash

執行完這條命令後,建立並啟動容器之後,執行/bin/bash,會啟動一個子程序,此時父程序(也就是容器的主程序sh)會進入sleep狀態,由於sleep狀態不是終止狀態,所以容器會繼續執行。

為什麼在容器中輸入exit或者執行ctrl D後,容器將會終止呢,這是因為exit會退出(結束)當前程序,也就是/bin/bash,由於子程序結束,sh主程序恢復到執行態,然而由於沒有命令需要繼續執行,所以sh主程序結,因此容器終止。

6.進入一個容器

6.1.進入一個docker容器的幾種方法

1.使用ssh登入容器;

2.使用nsenter、nsinit等等第三方工具;

3.使用docker本身提供的工具

6.2.使用docker attach進入一個容器內部

命令

docker attach 容器ID或容器名字

首先使用docker run建立了一個容器,為其分配了偽終端,打開了它的標準輸入流,並且讓它在後臺執行。然後使用docker attach進入了該容器內部,實際上就是進入容器“啟動命令”的終端。

容器ID可以不用輸全,只要能代表容器即可。例如下面的0539就是代表容器ID以0539開頭的容器,一般情況下,前4位就能唯一標識一個容器了。

[[email protected]]# docker run -itd ubuntu /bin/bash
0539852938cdb9538f67750d07ed8c7fa072de742d5c0c02128576f2d227ec46
[[email protected]]# docker attach 0539
[email protected]:/# 
[email protected]:/# ls
bin   dev  home  lib64  mnt  proc  run   srv  tmp  var
boot  etc  lib   media  opt  root  sbin  sys  usr
[email protected]:/# exit
exit
[[email protected]]#

6.3.使用docker exec進入一個容器內部

docker exec [選項] 容器名|容器ID 命令引數

例項:進入test2容器,建立一個名為HelloWorld的資料夾

docker pull ubuntu
docker run -itd --name test2 ubuntu /bin/bash
docker exec test2 mkdir HelloWorld

6.4.attach與exec的主要區別

  1. attach直接進入容器“啟動命令”的終端,不會啟動新的程序;
  2. exec則是在容器中開啟新的終端,並且可以啟動新的程序;
  3. 如果想直接在終端中檢視容器“啟動命令”的輸出,用attach;其他情況使用exec。

7.刪除容器

7.1.刪除一個終止狀態的容器

使用 docker rm 容器名|容器ID 來刪除一個處於終止狀態的容器,不加引數的情況下只能刪除處於終止狀態的容器。

步驟

1.docker ps -a檢視所有的容器

2.檢視容器的ID

3.執行docker rm 容器名或容器ID 命令

7.2.刪除一個正在執行的容器

刪除一個處於執行狀態的容器有兩種方式

1.執行docker stop停止該容器,然後使用docker rm刪除

2.執行docker rm -f 強制刪除

例項:

1.刪除所有處於終止狀態的容器

docker rm $(docker ps -aq)

2.刪除所有容器

docker rm -f $(docker ps -aq)

三、映象管理

1.基於Commit定製映象

之前一直使用的映象都是來自於官方Docker Hub中的映象,有時候需要在這些映象的基礎上進行修改,來定製符合需求的映象。

將“對容器的修改”儲存為映象

在Docker中提供了一個命令docker commit,該命令會把對容器的修改提交成一個映象。換句話說,就是在原有映象的基礎上,再疊加上容器的儲存層(該儲存層僅僅儲存了容器所做的修改),將這些內容構成一個新的映象。docker commit的基本語法如下:

docker commit [選項] 容器名 [映象名]

其中:

docker commit:Docker拉取映象的命令關鍵詞;

[選項]:命令選項,其中–author指定作者,–message制定commit的資訊;

容名:容器的名字;

映象名:新映象的名字,以<倉庫名>:<標籤>的方式來指定。如果不顯示設定,將預設為None:None。(這個代表沒有指定映象名)

例項

定製一個busybox:v1映象,該映象在busybox:latest的基礎上,新增了一個hello.txt檔案。

docker pull busybox
docker run --name container1 busybox touch hello.txt
docker commit container1 busybox:v1

使用commit定製映象的缺陷,實際工作中很少用commit製作映象

1.會儲存很多不必要的檔案

2.commit定製的映象是黑箱映象,除了製作人誰也不知道製作出來的,過一段時間可能作者都不知道怎麼製作出來的,因此維護非常困難

2.基於save儲存映象與基於load載入映象

為了防止映象丟失或備份映象;並且在需要的時候恢復映象,就需要儲存和載入映象

2.1.將映象儲存到tar包

docker save [選項] 映象名.tar  [映象名.tar]

選項:

-o:指定寫到一個檔案中,而不是標準輸出流中;

例如,將alpine:latest映象儲存到tar包,對應的語句如下:

docker save alpine:latest > alpine.tar
或者
docker save -o alpine:lateste alpine.tar

儲存多個映象

docker save alpine:latest ubuntu:latest > image.tar

2.2.從tar包載入映象

docker load使用docker save儲存的tar檔案載入映象,它的具體語法如下:

docker load [選項]

選項,

-i:指定從一個tar檔案中讀取,而不是標準輸入流中。

例如,從alpine.tar中載入映象,對應的語句如下:

docker load < alpine.tar
或者
docker load -i alpine.tar

如果一個tar包中包含多個映象,那麼會將這些映象全部到載入進來。

結合這兩個命令以及ssh甚至pv的話,利用 Linux強大的管道,我們可以寫一個命令完成從一個機器將映象遷移到另一個機器,並且帶進度條的功能:

docker save <映象名> | bzip2 | pv | ssh <使用者名稱>@<主機名> 'cat | docker load'

例項:

1.busybox:latest映象儲存為一個tar包;

2.刪除busybox:latest映象後,從tar包載入busybox:latest映象。

拉取映象
docker pull busybox:latest
儲存到tar包
docker save busybox:latest > busybox:latest.tar
刪除映象
docker rmi busybox:latest
從tar包載入映象
docker load < busybox:latest.tar

3.匯入匯出容器

3.1.匯出

docker export [選項] 容器名

選項:

-o指定寫到一個檔案中,而不是標準輸出流中。

例如將容器Container1儲存到tar包

docker export container1 > container1.tar
或者
docker export container1 -o container.tar

3.2.匯入

docker import  檔案或URL| - [映象名]

檔案|URL|: 指定docker import的物件,可以是檔案或者某個URL;

[映象名]: 以<倉庫名>:<標籤>的方式來指定。

例如從container1.tar中載入映象,映象名為test:v1.0

cat container1.tar | docker import - test:v1.0

docker export和docker save的區別

首先,兩者的操作物件不同。docker save是將一個映象儲存為一個tar包,而docker export是將一個容器快照儲存為一個tar包。

然後,docker export匯出的容器快照檔案將丟棄所有的歷史記錄和元資料資訊,即僅儲存容器當時的快照狀態;而docker save儲存的映象儲存檔案將儲存完整記錄,體積也要大。下圖就能夠很好的說明,ubuntu:test僅僅佔97.8MB而ubuntu:latest卻佔了120MB。

例項

將busyboxContainer容器的檔案系統儲存為一個tar包;

通過該tar包匯入一個busybox:v1.0映象。

docker pull busybox
docker run --name busyboxContainer busybox echo "Hello,World"
docker export busyboxContainer > busybox.tar
cat busybox.tar| docker import - busybox:v1.0

4.刪除映象

刪除本地映象可以使用docker rmi;rm是刪除,i是image,映象的意思。

刪除映象前需要刪除容器,也可以使用 docker rmi -f強制刪除映象。

docker rmi [選項] image [image...]

選項:

-f:強制刪除

image:需要刪除的映象。這裡的映象可以用“映象短ID”、“映象長ID”、“映象名”、“映象的digest”來標識。

使用下面的命令可以檢視映象的具體資訊包括digest

docker images -- digest

刪除ubuntu:latest映象,有以下幾種方法:

1.映象短ID:docker rmi 14f6;(這個代表映象id以14f6開頭的映象,一般而言,前四位可以唯一標誌,如果不可以,docker會提示的)

2.映象長ID:docker rmi 14f60031763d;

3.映象名: docker rmi ubuntu:latest;

4.映象的digest:docker rmi digest值

以上的方法都能刪除掉ubuntu:v1映象。但日常生活中,我們比較常用的是短ID以及映象名,因為用起來最方便。

刪除多個映象

刪除所有倉庫名為redis的映象,可以這麼寫:

docker rmi $(docker images -q redis)

刪除所有映象

docker rmi $(docker images -qa)

刪除映象前需要刪除容器,也可以使用 docker rmi -f強制刪除映象。

5.構建私有Registry

5.1建立一個私人倉庫

在Docker Hub中提供了建立私人倉庫的映象Resposity(映象倉庫):Registry

docker run -d -p 5000:5000 --restart=always --name registry registry:2

從這條命令可以看出,這個私人倉庫以容器的形式執行著。其中–restart=always是指在Docker服務重啟或者registry容器退出時會重新啟動.

而-p是指將宿主機的5000埠對映到容器的5000埠,這樣就可以通過宿主機ip:5000訪問到容器的5000埠了。(registry容器預設會監聽5000埠);-d引數是指在後臺執行。

-v指定私人倉庫的儲存位置,新增-v /mnt/registry:/var/lib/registry可以將私人倉庫的儲存位置設定為宿主機的/mnt/registry。

5.2.將映象推送到私人倉庫

1.使用docker tag給映象新增一個標籤

如果想要將映象推送到私人倉庫而不是Docker Hub,首先必須使用docker tag命令,使用主機名和埠來標記一個映象,如下所示,為ubuntu:latest映象加上一個localhost:5000/my-ubuntu:latest的標籤。

docker tag ubuntu:latest localhost:5000/my-ubuntu

使用docker push將映象推送到私人倉庫

使用docker push命令可以將映象推送到倉庫,預設情況下會將映象推送到官方倉庫Docker Hub中去,但是如果推送一個“用主機名和埠來標記”的映象,那麼就會推送到私人倉庫。

docker push localhost:5000/my-ubuntu

5.3.從私人倉庫拉取映象

docker pull可以從倉庫拉取某個映象,預設情況下,也是從官方倉庫拉取。當我想從私人倉庫拉取my-ubuntu:latest映象。執行以下命令就行了。

docker pull localhost:5000/my-ubuntu

5.4.檢視或者刪除私人倉庫中的映象

Docker提供的Registry映象沒有提供檢視映象和刪除映象的指令,但是有第三方的軟體可以提供這些功能,例如:harbor。

5.5.刪除私人倉庫

私人倉庫實質上就是一個容器,所以刪除私人倉庫就是刪除私人倉庫對應的容器。我們可以使用docker rm -f 強制刪除刪除它,但是這樣刪除之後,私人倉庫中儲存的映象並不會被刪除掉。如果你想在刪除私人倉庫的同時,也將映象刪除,需要新增-v引數,也就是docker rm -f -v。例如刪除本地的私人倉庫,可以執行以下語句:

docker rm -vf myregistry

例項

1.構建一個私人倉庫
docker pull registry:2
docker run -d -p 5000:5000 --restart=always --name myregistry registry:2
2.拉取ubuntu映象
docker pull ubuntu
3.使用docker tag給ubuntu加上一個標籤localhost:5000/my-ubuntu:latest
docker tag ubuntu:latest localhost:5000/my-ubuntu:latest
4.將localhost:5000/my-ubuntu:latest映象推送到私人倉庫
docker push  localhost:5000/my-ubuntu:latest
5.刪除本地映象
docker rmi localhost:5000/my-ubuntu:latest
6.從私人倉庫拉取localhost:5000/my-ubuntu:latest映象
docker pull localhost:5000/my-ubuntu
7.刪除私人倉庫並將私人倉庫中的映象也刪除掉
docker rm -vf myregistry

四、Dockerfile

1.初識Dockerfile

1.1.Dockerfile簡介

Dockerfile描述了組裝映象的步驟,其中每一條命令都是單獨執行的,除了FROM指令外,其他每一條指令都在上一條指定所生成的映象基礎上執行,執行完會生成一個新的映象層,新的映象層覆蓋在原來的映象層之上,從而形成了新的映象。解決了之前提及的無法重複、映象構建透明性和體積的問題。

1.2.Dockerfile基本的兩條指令:FROM和RUN

FROM指定基礎映象;
格式:FROM<映象名>或 FROM <映象名>:<標籤>。

FROM指令的功能是為後面的指令提供基礎映象,因此一個有效的Dockerfile必須以FROM指令作為第一條非註解指令。若FROM指令中tag引數為空,則tag預設為latest;若引數image或tag指定映象不存在,則返回錯誤。

RUN執行命令;
格式:RUN <命令>

RUN 指令是用來執行命令列命令的。RUN指令會在前一條命令創建出的映象的基礎上建立一個容器,並在容器中執行命令。在命令結束執行後提交新容器為新映象,新映象被Dockerfile的下一條指令使用。

1.3.使用Dockerfile構建一個映象

步驟

1.建立一個空的檔案,並進入

2.建立一個名為Dockerfile的檔案,並根據實際需要補全內容

3.使用dockerfile構建一個名為testimage的映象docker build -t testimage .

-t 指定新映象的映象名

命令的最後有一個小數點不能丟

例項

使用Dockerfile構建一個名為testimage的映象,該映象具有ubuntu:latest的執行環境,並且在根目錄下建立了一個Linux的資料夾

mkdir Ubuntuimage
cd Ubuntuimage
touch Dokerfile
vim Dockerfile
#新增下面的內容
FROM ubuntu:latest
RUN mkdir Linux

docker build -t testimage .

在Dockerfile的編寫過程中一定要牢記一點:映象的每一層構建完就不會再發生改變,後一層上的任何改變只發生在自己這一層。刪除前一層檔案的操作,實際不是真的刪除前一層的檔案,而是僅在當前層標記為該檔案已刪除。在最終容器執行的時候,雖然不會看到這個檔案,但是實際上該檔案會一直跟隨映象。

2.docker build、COPY和ADD

2.1.docker build命令詳解

Dockerfile建立完成後,可以使用docker build命令根據Dockerfile構建一個映象。

docker build [選項] 上下文路徑|URL

選項:

-t:指定映象名字;

-f:指定Dockerfile,不指定則預設使用當前資料夾下的Dockerfile。

除了從本地構建以外,docker build還支援從URL構建,比如可以直接從Git repo中構建。

2.2.COPY命令和ADD指令

COPY指令語法:

COPY <源路徑>  <目標路徑>

ADD指令語法:

ADD <源路徑> <目標路徑>

COPY與ADD指令在功能十分相似,但在COPY的路徑上添加了一些功能。比如ADD的原始檔路徑可以是URL,這種情況下Docker會下載URL指向的檔案。

當原始檔路徑是tar壓縮檔案時,使用COPY會拷貝原始檔到指定目錄,ADD命令自動解壓這個壓縮檔案到指定目錄。

例項

使用Dockerfile構建一個名為busybox:v3的映象,具體要求如下:

以Ubuntu為基礎映象;
將目錄下的dir1.tar“解壓提取後”,拷貝到新映象的/中;
使用docker build基於該Dockerfile構建一個名為Ubuntu:v3的映象。

mkdir ubuntuImage
cd ubuntuImage
mkdir dir1 && -cvf dir1.tar dir1 && rm -rf dir1
touch Docfile
vim Dockerfile
#新增到Dockerfile檔案中的內容
FROM ubuntu:latest
ADD ./dir1.tar /
#退出vim,以該Dockerfile構建一個名為busybox:v3的映象
docker build -t ubuntu:v3 .

3.CMD指令和ENTRYPOINT指令

CMD和ENTRYPOINT都是為映象指定容器啟動命令的常用Dockerfile指令。

CMD和Entrypoint的區別

共同點:

指定啟動容器時執行的命令,每個 Dockerfile 只能有一條 CMD/ENTRYPOINT 命令。如果指定了多條命令,只有最後一條會被執行。
用法都支援exec和shell兩種使用方式且用法相近

區別:

CMD: 啟動容器時候指定了執行的命令,則會覆蓋掉映象中 CMD 指定的命令

ENTRYPOINT: 啟動容器時候指定了執行的命令,並不會覆蓋掉映象中Entrypoint的命令

例項

要求:

1.以busybox:latest為基礎映象;
2.將啟動命令設定為df -Th,要求df命令不能被覆蓋,但-Th能夠被覆蓋。
3.使用docker build基於該Dockerfile構建一個名為mydisk:v1的映象。

mkdir busyboxImage
cd busyboxImage
touch Dockerfile
echo "FROM busybox:latest" > Dockerfile
echo 'ENTRYPOINT ["df"]' >>Dockerfile
echo 'CMD ["-Th"]' >>Dockerfile
docker build -t mydisk:v1 .

4.ENV、EXPOSE、WORKDIR、ARG指令

WORKDIR指令

WORKDIR為其他指令設定工作目錄; 格式:WORKDIR <工作目錄路徑>。

WORKDIR /tmp

WORKDIR指令為Dockerfile中的任何RUN,CMD,ENTRYPOINT,COPY和ADD指令設定工作目錄(或稱當前目錄);如果WORKDIR對應的目錄不存在,將會自動被建立。

EXPOSE指令

ENV設定環境變數;
格式:ENV 或ENV =;

這個指令很簡單,就是設定環境變數而已,無論是後面的其它指令,還是執行時的應用,都可以直接使用這裡定義的環境變數。

ENV str="Hello,World"
ENV APACHE_HOME /var/tmp/apache-tomcat-8.0.45

ARG指令

ARG構建引數;
格式:ARG <引數名>[=<預設值>];

ARG與ENV有些類似,它們都可以被後面的其它指令直接使用,但是它並不是環境變數,這意味著將來容器執行時是不會存在ARG變數的。

什麼時候用ARG,什麼時候用ENV?
如果想儲存為環境變數,就用ENV;如果只想在Dockerfile中臨時使用,就用ARG。

EXPOSE指令

EXPOSE暴露埠;
格式:EXPOSE <埠1> [<埠2>…]

EXPOSE指令是宣告執行時容器提供服務埠,這只是一個宣告,在執行時並不會因為這個宣告應用就會開啟這個埠的服務。如果想要公開容器的埠,必須在docker run是指定-p引數去公開埠或者指定-P引數公開所有被EXPOSE的埠。

在Dockerfile中寫入這樣的宣告有兩個好處

1.幫助映象使用者理解這個映象服務的守護埠,以方便配置對映;

2.在執行時使用隨機埠對映時,也就是 docker run -P時,會自動隨機對映 EXPOSE 的埠。

例項

要求:

以busybox:latest作為基礎映象;
宣告暴露3000埠;
將變數var1="test"設定為環境變數;
設定工作目錄為/tmp,在工作目錄下建立一個1.txt檔案;
基於該Dockerfile檔案,構建一個名為testimage:v1的映象。

mkdir busyboxImage
cd busyboxImage
touch Dockerfile
echo "FORM busybox:latest" >Dockerfile
echo "EXPOSE 3000" >> Dockerfile
echo "ENV var1=test" >> Dockerfile
echo "WORKDIR /tmp" >>Dockerfile
echo "RUN touch 1.txt" >> Dockerfile

5.ONBUILD和VOLUME指令

ONBUILD指令

ONBUILD新增一個將來執行的觸發器(trigger)

格式: ONBUILD <其它指令>

ONBUILD 是一個特殊的指令,它後面跟的是其它指令,比如RUN, COPY等,而這些指令,在當前映象構建時並不會被執行。只有當以當前映象為基礎映象,去構建下一級映象的時候才會被執行,在映象構建完成後,觸發器指令會被清除,不會被後面的映象繼承。

VOLUME指令
VOLUME定義匿名卷;
格式:VOLUME ["<路徑1>", “<路徑2>”…]或VOLUME <路徑>;

容器執行時應該儘量保持容器儲存層不發生寫操作,對於資料庫類需要儲存動態資料的應用,其資料庫檔案應該保存於資料卷(volume)中。

6.映象構建時的快取機制

映象構建時的快取機制

在構建映像的過程中,Docker將按照指定的順序逐步執行您的Dockerfile中的指令。隨著每條指令的檢查,Docker將在其快取中查詢可重用的現有映像,而不是建立一個新的(重複)映像。如果您不想使用快取,可以在docker build命令中使用–no-cache = true選項。

五、資料卷操作

1.建立一個數據卷

Docker1.9版本以後,Docker提供了一條新的命令:docker volume,用來建立、檢視、刪除資料卷。而傳統的docker run -v建立一個數據卷的方式也仍然保留了下來。

建立資料卷的方式

1.使用docker volume create建立一個數據卷,並指定資料卷的名字。

docker volume create --name vo1

2.建立新容器的時候,通過新增-v標籤建立一個數據卷

docker run -itd -v/data ubuntu /bin/bash

3.在建立新容器的時候,指定資料卷的名字,並掛載到容器目錄

docker run -itd -v vo2:/data ubuntu /bin/bash

日常工作一般都用第三種,建立容器指定資料卷的名字,並掛載到指定的目錄

例項

建立一個名為vo1的資料卷,並將該資料卷掛載到container1容器的/dir1目錄。

docker pull ubuntu
docker run -v vo1:/dir --name container1  ubuntu

2.掛載和共享資料卷

2.1.掛載資料卷

預設情況下,在建立資料卷時,會在宿主機中的/var/lib/docker/volume/下建立一個以“資料卷名”為名的目錄,並將資料卷的內容儲存在該目錄下的/_data目錄下;也就是將資料卷的內容保在/var/lib/docker/volume/資料卷名/data中,資料卷的內容會和容器的掛載點始終保持一致。“資料卷名”可以使用者指定,如果不指定,就會隨機生成一個“資料卷名”。

掛載宿主機目錄

將宿主機的/host/dir掛載到了容器的/container/dir目錄。

docker run --name vocotainer1 -v /host/dir:/container/dir ubuntu

需要注意的是,宿主機的目錄和容器的目錄必須使用絕對路徑。如果宿主機不存在/host/dir目錄,則會建立一個空資料夾。在/host/dir下的所有檔案和資料夾都可以在容器中在/container/dir下被訪問。如果映象中本來就存在/container/dir資料夾,那麼該資料夾下所有內容都會被刪除,保證與宿主機中資料夾一致。

同時建立多個數據卷

在掛載的時候也可以同時建立多個數據卷,例如下面的命令就建立了兩個資料卷co3和co4

docker run --name vocotainer2 -v co3:/data -v co4:/dir1 ubuntu

與其他容器共享資料卷

在使用docker run建立並啟動一個新容器時,也可以使用–volumes-from標籤使容器與已有的容器共享資料卷;下面的命令建立了一個名為vocotainer3的容器,並與vocontainer1共享資料卷。因為vocontainer1的掛載點在/container/dir上,所以如果vocotainer3的掛載點也將會是/container/dir。

docker run --name vocotainer3 --volumes-from vocontainer1 ubuntu

通常如果有一些檔案如果需要被多個容器共享,一種常見的做法就是建立一個數據容器(該容器僅僅用來共享資料而不做其他用途),其他容器與之共享資料卷。

例項

要求:

建立一個名為container1的容器,並將本地主機的/dir1目錄掛載到容器中的/codir1中;
建立一個名為container2的容器,與container1共享資料卷。

docker pull ubuntu
docker run -v /dir:codir --name container1 ubuntu
docker run --volumes-from container1 --name container2 ubuntu

3.檢視資料卷的名字

3.1.檢視資料卷的具體資訊

檢視資料卷先建立資料卷,沒有指定資料卷的名字

docker run -v /data --name vocontainer1 ubuntu

檢視資料卷

docker inspect --type container vocontainer1

會輸出ID,建立時間,名字和其他很多引數。

3.2.僅檢視資料卷的名字

通過–format來解析docker inspect

docker inspect --type container --format='{{range .Mounts}}{{.Name}}{{end}}' 容器名|容器ID

檢視vocontainer1的資料卷名字

docker inspect --type container --format='{{range .Mounts}}{{.Name}}{{end}}' vocontainer1

4.刪除資料卷

第一種方式

如果該資料卷還被其他容器使用就會刪除失敗,沒有被其他容器使用就會刪除

docker volume rm 資料卷名

第二種方式

刪除容器的同時刪除資料卷,分兩種情況:

1.在建立資料卷的時候沒有指定資料卷的名字

如果該資料卷還被其他容器使用就會刪除失敗,沒有被任何容器使用就會刪除

2.在建立資料卷的時候指定了資料卷的名字

刪除容器只會解除資料卷與容器之間的聯絡,要刪除資料卷需要使用第一種方式

docker rm -v 容器名或容器ID

第三方式

在建立容器時指定了–rm標籤,那麼在容器處於“終止狀態”時就會刪除容器以及嘗試刪除容器所對應的資料卷。

如果沒有指定了資料卷名,那麼將刪除對應的資料卷。如果指定了資料卷名,也只是解除了資料卷和容器的聯絡,真正要刪除,還是要使用第一種方式。

刪除無用的資料卷

如果執行下面這條命令,那麼會將所有沒有被容器使用的資料卷刪除掉。

docker volume prune

例項

docker pull ubuntu
docker run -v vo4:/data --name container1 ubuntu
docker rm -v container1
docker volume rm vo4

5.備份和恢復資料卷

1.備份資料卷

首先建立一個容器vocontainer1,並建立了一個名為db1的資料卷,將資料卷掛在到容器的/dbdate目錄。

docker run -v db1:/dbdate --name vocontainer1 ubuntu

首先進入一個空白目錄,使用–volumes-from建立一個新容器,這樣新容器與container1容器共享dbdata掛載目錄,同時把主機上的當前目錄掛載到容器的 /backup 目錄

docker run --volumes-from container1 -v $(pwd):/backup ubuntu tar -cvf /backup/backup.tar /dbdata

容器啟動後,使用了tar 命令來將 dbdata目錄壓縮,並儲存在 /backup/backup.tar檔案中,由於主機的當前目錄掛載在容器的/backup目錄下,而繫結掛載的兩個目錄的內容完全保持一致,所以相當於將dbcontainer1資料卷的內容壓縮後備份到了宿主機的當前目錄了。

2.恢復一個數據卷

首先建立一個帶有空資料卷的容器container2,掛載目錄為/dbdata,資料卷名為db1。

docker run -v db1:/dbdata --name container2 ubuntu /bin/bash

然後進入之前儲存backup.tar的宿主機目錄,在該目錄下執行下面命令,該命令建立一個新容器,新容器與container2容器共享dbdata掛載目錄,同時將主機的當前目錄掛載的容器的/backup中。

docker run --volumes-from container2 -v $(pwd):/backup busybox tar -xvf /backup/backup.tar -C /dbdata

啟動容器時,使用tar命令將資料卷的備份檔案backup.tar解壓到/dbdata目錄,由於該容器與container2容器共享一個數據卷,也就相當於將backup.tar解壓到了container2的/dbdata目錄。又因為container2將名為db1的資料卷掛載到了/dbdata上,所以實質上就將db1的資料卷內容完全恢復了!

例項:備份和恢復vo1資料卷

建立vo1資料卷並在資料卷中新增1.txt

docker pull ubuntu
docker run --name vocontainer -v vo1:/dir1 ubuntu touch /dir1/1.txt

將vo1資料卷的資料備份到宿主機的/newback中,將容器的/backup路徑掛載上去,並將容器內/dir1資料夾打包至/backup/backup.tar

docker run --volumes-from vocontainer1 -v /newback:/backup ubuntu tar -cvf /backup/backup.tar  /dir

刪除所有的容器以及它使用的資料卷

docker rm -vf $(docker ps -aq)
docker volume rm vo1

在次建立一個vo1的資料卷

docker run -itd --name vocontainer2 -v vo1:/dir1 ubuntu /bin/bash

將儲存在宿主機中備份檔案的資料恢復到vocontainer2的/中

docker run --volumes-from vocontainer2 -v /newback:/backup ubuntu tar -xvf /backup/backup.tar -C /