docker筆記

docker簡介

Docker 和其他容器(container)技術都屬於系統虛擬化範疇

容器以進程的形式存在於操作系統之中

容器爲應用程序提供了隔離的運行空間:每個容器內都包含一個獨享的完整用戶環境空間,並且一個容器內的變動不會影響其他容器的運行環境。爲了能達到這種效果,容器技術使用了一系列的系統級別的機制諸如利用Linux namespaces 來進行空間隔離,通過文件系統的掛載點來決定容器可以訪問哪些文件,通過 cgroups 來確定每個容器可以利用多少資源。此外容器之間共享同一個系統內核,這樣當同一個庫被多個容器使用時,內存的使用效率會得到提升。

容器( container-based )虛擬化方案,充分利用了操作系統本身已有的機制和特性,以實現輕量級的虛擬化(每個虛擬機安裝的不是完整的虛擬機),甚至有人把他稱爲新一代的虛擬化技術,Docker 無疑就是其中的佼佼者

Docker 的目標

Build,Ship and Run Any App,Anywhere— 即通過對應用組件的封裝 (Packaging), 發佈(Distribution), 運行(runing) 等生命週期的管理 , 達到應用組件級別的”一次封裝 , 到處運行”

docker 的特點

優點:

-啓動快,資源佔用小 , 資源利用高,快速構建標準化運行環境

-創建分佈式應用程序時快速交付和部署,更輕鬆的遷移和擴展,更簡單的更新管理

侷限:

-Docker 是基於 Linux 64bit 的,無法在 windows/unix 或 32bit 的 linux環境下使用

-LXC 是基於 cgroup 等 linux kernel 功能的,因此 container 的 guest 系統只能是linux

-隔離性相比 KVM 之類的虛擬化方案還是有些欠缺,所有 container 公用一部分的運行庫

-管理相對簡單,主要是基於 namespace 隔離

-cgroup 的 cpu 和 cpuset 提供的 cpu 功能相比 KVM 的等虛擬化方案相比難以度量( 所以 dotcloud 主要是按內存收費 )

-docker 對 disk 的管理比較有限

-container 隨着用戶進程的停止而銷燬, container 中的 log 等用戶數據不便收集

docker與虛擬機比較

-啓動快比虛擬機 , 可以秒級啓動

-對資源佔用小 , 宿主機上可運行千臺容器

-方便用戶獲取 , 分佈 , 和更新應用鏡像 , 指令簡單 , 學習費用低

-通過 Dockerfile 配置文件來靈活的自動創建和部署鏡像 & 容器 , 提高工作效率

-Docker 除了運行其中應用外 , 基本不消耗其他系統資源 , 保證應用性能同時 ,儘量減小系統開銷

檢測docker是否運行
#systemctl status docker
#docker ps

docker鏡像

鏡像(docker image) --- Docker 運行容器之前需要本地存在鏡像,若本能地不存在,那麼 Docker 會找默認鏡像倉庫( Docker Hub 公共註冊服務器中的倉科)下載,用戶也可以通過配置使用自己的鏡像庫

查看所有鏡像列表
#docker images

下載鏡像
#docker pull mariadb
或
#docker pull mariadb:latest

鏡像在下載過程中是分層的,並且在每層前會有各層的 ID號,層(Layer )是 AUFS (聯合文件系統)的重要概念,是實現增量保存與更新的基礎

修改鏡像TAG
#docker tag mariadb:latest mariadb:latestv1

搜索庫中滿足需求的鏡像,以此下載符合需求的鏡像文件
#docker search maraidb

刪除鏡像
#docker rmi mariadb:latest

鏡像分層

docker鏡像的分層結構:支持通過擴展現有鏡像,創建新的鏡像

 

可以看到,新鏡像是從 base 鏡像一層一層疊加生成的。每安裝一個軟件,就在現有鏡像的基礎上增加一層。

分層結構的優勢:

 

共享資源:

有多個鏡像都從相同的 base 鏡像構建而來,那麼 Docker Host 只需在磁盤上保存一份 base 鏡像;同時內存中也只需加載一份 base 鏡像,就可以爲所有容器服務了。而且鏡像的每一層都可以被共享

如果多個容器共享一份基礎鏡像,當某個容器修改了基礎鏡像的內容,比如 /etc 下的文件,這時其他容器的 /etc 是否也會被修改?

答案是不會!

修改會被限制在單個容器內。這就是容器 Copy-on-Write 特性。

 

可寫的容器層:

當容器啓動時,一個新的可寫層被加載到鏡像的頂部。這一層通常被稱作“容器層”,“容器層”之下的都叫“鏡像層”。

所有對容器的改動 - 無論添加、刪除、還是修改文件都只會發生在容器層中。

只有容器層是可寫的,容器層下面的所有鏡像層都是隻讀的。

 

 

鏡像層數量可能會很多,所有鏡像層會聯合在一起組成一個統一的文件系統。如果不同層中有一個相同路徑的文件,比如 /a,上層的 /a 會覆蓋下層的 /a,也就是說用戶只能訪問到上層中的文件 /a。在容器層中,用戶看到的是一個疊加之後的文件系統。

 

添加文件

在容器中創建文件時,新文件被添加到容器層中。

讀取文件

在容器中讀取某個文件時,Docker 會從上往下依次在各鏡像層中查找此文件。一旦找到,打開並讀入內存。

刪除文件

在容器中刪除文件時,Docker 也是從上往下依次在鏡像層中查找此文件。找到後,會在容器層中記錄下此刪除操作。

 

只有當需要修改時才複製一份數據,這種特性被稱作 Copy-on-Write。可見,容器層保存的是鏡像變化的部分,不會對鏡像本身進行任何修改。

這樣就解釋了我們前面提出的問題:容器層記錄對鏡像的修改,所有鏡像層都是隻讀的,不會被容器修改,所以鏡像可以被多個容器共享。

鏡像創建

三種方法

1-基於修改後的容器創建:docker commit 命令

#docker run -it mariadb:latest /bin/bash鏡像啓動後的環境變量
#mkdir /pikachu
#exit 退出

此時容器較鏡像已經發生改變,我們以此生成新鏡像

#docker commit 0c0d3fb78bb6 pikachu

 

2-基於本地模板導入

導出(導出的名字可以自定義)

#docker save -o httpd.tar.gz httpd:latest

當鏡像被容器佔用是要先把容器刪掉

#docker rm CONTAINER ID

導入

#docker load -i httpd.tar.gz

 

3-基於 Dockerfile 文件創建

Dockerfile 是一個文本文件,用來配置 image,記錄了鏡像構建的所有步驟。Docker 根據 該文件生成二進制的 image 文件。

用 Dockerfile 創建centos-with-vi

下載鏡像
#docker pull centos
#vim /root/test/dockerfile 

FROM centos:7

RUN yum install -y vim

#docker run -it centos:latest /bin/bash

 

基於dockerfile文件創建新鏡像

#docker build -t centos:vim /root/test/

查看執行命令
#docker history IMAGE ID

Docker 會緩存已有鏡像的鏡像層,構建新鏡像時,如果某鏡像層已經存在,就直接使用,無需重新創建。在前面的 Dockerfile 中添加一點新內容,往鏡像中複製一個文件

#docker build -t centos:hello /root/test

下面列出了 Dockerfile 中最常用的指令,完整列表和說明可參看官方文檔。

FROM:指定 base 鏡像。
MAINTAINER:設置鏡像的作者,可以是任意字符串。
COPY:將文件從 build context 複製到鏡像。
    COPY 支持兩種形式:
        COPY src dest
        COPY ["src", "dest"]
    注意:src 只能指定 build context 中的文件或目錄。
ADD:與 COPY 類似,從 build context 複製文件到鏡像。不同的是,如果 src 是歸檔文件(tar, zip, tgz, xz 等),文件會被自動解壓到 dest。
ENV:設置環境變量,環境變量可被後面的指令使用。例如:
    ...
    ENV MY_VERSION 1.3
    RUN apt-get install -y mypackage=$MY_VERSION
    ...
EXPOSE:指定容器中的進程會監聽某個端口,Docker 可以將該端口暴露出來。我們會在容器網絡部分詳細討論。
VOLUME:將文件或目錄聲明爲 volume。
WORKDIR:爲後面的 RUN, CMD, ENTRYPOINT, ADD 或 COPY 指令設置鏡像中的當前工作目錄。
RUN:在容器中運行指定的命令,RUN 指令通常用於安裝應用和軟件包。
CMD:容器啓動時運行指定的命令。
Dockerfile 中可以有多個 CMD 指令,但只有最後一個生效。CMD 可以被 docker run 之後的參數替換。
ENTRYPOINT:設置容器啓動時運行的命令,可讓容器以應用程序或者服務的形式運行。
Dockerfile 中可以有多個 ENTRYPOINT 指令,但只有最後一個生效。CMD 或 docker run 之後的參數會被當做參數傳遞給ENTRYPOINT。

docker的使用

(1)創建容器,create命令是創建並不啓動容器

#docker creat -it centos:7

(2)查看所有狀態的容器

#docker ps -a
#docker ps

(3)啓動停止的容器

#docker start ID

(4)運行一個容器

#docker run -ti docker.io/centos:7 /bin/bash

創建並運行一個容器 ,此時你會直接被切換到容器中

#ctrl+d//exit退出,並且容器也退出

#ctrl+p+q退出容器,並且保持容器up的狀態

-t 分配一個僞終端

-i 讓容器的標準輸入持續打開

-d 不進入容器

用/bin/bash環境顯示

(5)以後臺守護進程(Daemonized)形態運行 用-d參數實現

#docker run -dti docker.io/centos:7

(6)終止容器

#docker stop NAME/ID #docker kill NAME/ID

(7)重啓容器

#docker restart NAME/ID

需要注意,非持久後臺守護狀態的虛擬機,在重啓後當你查看時還是關閉狀態

(8)刪除容器

語法: docker rm 參數 NAME NAME …

#docker -rm -f NAME/ID

-f 強制刪除處於運行中的容器

-l 刪除鏈接,保留容器

-v 刪除掛載的數據卷

刪除之前要停止容器

(9)進入容器

docker attach 和 docker exec 兩種方式:

docker attach直接進入容器 啓動命令的終端,不會啓動新的進程

#docker run -d centos /bin/bash -c “while true; do sleep 1;echo I_am_docker;done”

#docker attach NAME/ID

docker exec則是在容器中打開新的終端,並且可以啓動新的進程

#docker exec -it NAME/ID /bin/bash

(10)導入和導出容器

a. 導出容器:導出一個已經創建的容器到文件,不管容器是否運行

#docker ps -a

假設當前系統中有兩個處於運行和停止狀態的容器

#docker export ID > *.tar

#ls

b.將容器導入系統成爲鏡像

#cat *.tar | docker import - test

(11)查看容器日誌

顯示容器啓動進程的控制檯輸出

#docker logs -f NAME/ID

(12)暫停容器

#docker pause NAME/ID

(13)取消暫停繼續運行容器

#docker unpause NAME/ID

docker鏡像的倉庫

倉庫分爲公共倉庫和私有倉庫

DockerHub的官方倉庫 https://hub.docker.com

DockerPool社區倉庫 https://dl.dockerpool.com

Dockern Pool (http://dockerpool.com)是國內專業的Docker社區,目前也提供了官方鏡像的下載管理服務

 

創建自己的私有倉庫

 

# docker run -d -p 5000:5000 -v /var/lib/registry:/var/lib/registry --restart=always --name registry registry:2
registry:2-鏡像

docker客戶端

# vim /etc/docker/daemon.json

"insecure-registries": ["192.168.146.201:5000"],

 

#systemctl restart docker
#docker tag my-imge:latest 192.168.146.201:5000/centos:latest
更換 my-imge:latest 一個新的名稱標籤

上傳到私有倉庫

#docker push 192.168.146.201:5000/my-imge1:latest

下載

#docker pull 192.168.146.201:5000/my-imge1:latest

docker依賴的底層核心技術

命名空間 (Namespaces)

控制組 (Control Groups)

聯合文件系統 (Union File System)

Linux 虛擬網絡支持:本地和容器內創建虛擬接口

(1)命名空間 (Namespaces):

實現了容器間資源的隔離每個容器擁有自己獨立的命名空間 , 運行其中的應用就像是運行在獨立的操作系統中一樣 , 我們都可以看到文件系統,網卡等資源保證了容器之間互不影響,namesaces管理進程號 , 每個進程命名空間有一套自己的進程號管理方法 , 進程命名空間是一個父子關係的結構 , 子空間中的進程對於父空間是可見的

網絡命名空間—有了 PID 命名空間 , 那麼每個名字中的進程就可以相互隔離 ,但是 , 網絡端口還是共享本地的端口 . 網絡命名空間就是爲進程提供一個完全獨立的網絡協議棧的視圖包括 : 網絡設備接口 ,IPv4 和 IPv6 協議棧 ,IP 路由表 , 防火牆規則 ,sockets等等 ...

(2)控制組功能 cgroups:

控制組 (Control groups)--CGroups 是 Linux 內核的一個特性 ,主要用來對共享資源進行隔離、限制、審計等 。cgroups 允許對於進程或進程組公平( 不公平 ) 的分配 CPU 時間、內存分配和 I/O 帶寬。

容器通過 cgroups 來得到所能夠管理資源的分配和使用。因此容器所獲得資源僅爲所有系統資源的一個部分

資源限制 : 內存子系統爲進程組設置內存使用上限,內存達到上限後再申請內存,就會發出 Out of Memory

優先級 : 通過優先級讓一些組得到更多 CPU 等資源

資源審計 : 用來統計系統上實際把多少資源用到適合的目的上 , 可以使用 cpuacct 子系統記錄某個進程組使用的     CPU 時間

隔離 : 爲組隔離名字空間 , 這樣一個組不會看到其他組的進程 .網絡連接和文件系統

控制 : 掛起 . 恢復和啓動等操作

(3)聯合文件系統 (Union FS)

docker 中使用AUFS(another Union File System 或 v2 版本以後的Advanced multi-layered Unification File System) 控制爲每一個成員目錄設定只讀 / 讀寫 / 寫出權限 , 同時 AUFS 有一個類似分層的概念 , 對只讀權限的分支可以邏輯上進行增量的修改

輕量級的高性能分層文件系統 , 它支持將文件系統中的修改信息作爲一次提交 ,並層層疊加 , 並且可以將不同目錄掛載到同一個虛擬文件系統下docker 目前支持的聯合文件系統包括AUFS/btrfs/vfs/DeviceMappe

docker的存儲

用戶在使用 Docker 的過程中,勢必需要查看容器內應用產生的數據,或者需要將容器內數據進行備份,甚至多個容器之間進行數據共享,這必然會涉及到容器的數據管理

docker 兩種存儲資源類型

(1)Data Volume (數據卷)

(2)Data Volume Dontainers --- 數據卷容器

Data Volume (數據卷)

Data Volume 本質上是 Docker Host 文件系統中的目錄或文件,使用類似與 Linux 下對目錄或者文件進行 mount 操作。數據卷可以在容器之間共享和重用,對數據卷的更改會立馬生效,對數據卷的更新不會影響鏡像,卷會一直存在,直到沒有容器使用

Data Volume 有以下特點:

a)Data Volume 是目錄或文件,而非沒有格式化的磁盤(塊設備)。

b)容器可以讀寫 volume 中的數據。

c)volume 數據可以被永久的保存,即使使用它的容器已經銷燬。

Data Volume的使用:

通過-v 參數格式爲 <host path>:<container path>

a)運行一個容器,並創建一個數據卷掛載到容器的目錄上

#docker run -dti -v /web centos:7.0 /bin/bash

利用 centos:7.0 的鏡像運行一個容器,並在容器內創建一個數據卷掛載到容器的 /web 目錄上

b)運行一個容器,本地創建/date目錄掛載到容器的/var/log/目錄上

#docker run -dti -v /data:/var/log centos:7.0 /bin/bash

Data Volume Dontainers --- 數據卷容器

如果用戶需要在容器之間共享一些持續更新的數據,最簡單的方法就是使用數據卷容器,其實數據卷容器就是一個普通的容器,只不過是專門用它提供數據卷供其他容器掛載使用

Data Volume Dontainers使用:

a)創建一個名爲 dbdata 的數據卷,並在其中創建一個數據卷掛載到 /dbdata

#docker run -dti -v /dbdata --name dbser centos:7.0 /bin/bash

--name 參數爲給容器指定名字爲dbser方便記憶

b)其他容器使用--volume-from 去掛載dbdata容器中的/dbdata數據卷

eg :創建 db1&db2 兩個容器, 並掛載 /dbdata 數據捲到本地

#docker run -dti --volumes-from dbser --name db1 centos:7.0

#docker run -dti --volumes-from dbser --name db2 centos:7.0

此時,容器 db1 和 db2 同時掛載了同一個數據捲到本地相同 /dbdata目錄。三個容器任何一個目錄下的寫入,都可以時時同步到另外兩個

docker網絡

docker 網絡介紹

大量的互聯網應用服務需要多個服務組件,這往往需要多個容器之間通過網絡通信進行相互配合

docker 網絡從覆蓋範圍可分爲單個 host 上的容器網絡和跨多個 host 的網絡docker 目前提供了映射容器端口到宿主主機和容器互聯機制來爲容器提供網絡服務,在啓動容器的時候,如果不指定參數,在容器外部是沒有辦法通過網絡來訪問容器內部的網絡應用和服務的

docker 安裝時會自動在host上創建三個網絡

#docker network ls

docker--none 網絡

none 網絡就是什麼都沒有的網絡。掛在這個網絡下的容器除了 lo,沒有其他任何網卡。容器創建時,可以通過 --network=none 指定使用 none 網絡。

none 網絡的應用:

封閉的網絡意味着隔離,一些對安全性要求高並且不需要聯網的應用可以使用none 網絡。

比如某個容器的唯一用途是生成隨機密碼,就可以放到 none 網絡中避免密碼被竊取。

docker--host 網絡

連接到 host 網絡的容器,共享 docker host 的網絡棧,容器的網絡配置與host 完全一樣。可以通過 --network=host 指定使用 host 網絡

在容器中可以看到 host 的所有網卡,並且連 hostname 也是 host 的。host網絡的使用場景又是什麼呢?

直接使用 Docker host 的網絡最大的好處就是性能,如果容器對網絡傳輸效率有較高要求,就可以選擇 host 網絡。

當然不便之處就是犧牲一些靈活性,比如要考慮端口衝突問題,Docker host上已經使用的端口就不能再用了。

Docker host 的另一個用途是讓容器可以直接配置 host 網路。比如某些跨host 的網絡解決方案,其本身也是以容器方式運行的,這些方案需要對網絡進行配置,比如管理 iptables

docker--bridge 網絡

docker 安裝時會創建一個 命名爲 docker0 的 linux bridge。如果不指定--network,創建的容器默認都會掛到 docker0 上

當前 docker0 上沒有任何其他網絡設備,我們創建一個容器看看有什麼變化

一個新的網絡接口 veth28c57df 被掛到了 docker0 上,veth28c57df就是新創建容器的虛擬網卡。

進入剛纔運行的容器查看網絡,容器有一個網卡 eth0@if34

實際上 eth0@if34 和 veth28c57df 是一對 veth pair

eth0@if34 已經配置了 IP 172.17.0.2,爲什麼是這個網段呢?

看一下 bridge 網絡的配置信息:

#docker network inspect bridge

bridge 網絡配置的 subnet 就是 172.17.0.0/16,並且網關是 172.17.0.1,在docker0上

容器創建時,docker 會自動從 172.17.0.0/16 中分配一個 IP,這裏 16 位的掩碼保證有足夠多的 IP 可以供容器使用

創建  user-defined網絡

我們可通過 bridge 驅動創建類似前面默認的 bridge 網絡

(1)利用bridge驅動創建名爲my-net2網橋(docker會自動分配網段):

#docker network create --driver brigde my-net2

(2)查看一下當前 host 的網絡結構變化:

#docker network ls

(3)查看容器bridge網橋配置(bridge就是容器和網橋形成一對veth pair)

#docker network inspect bridge

(4)利用bridge驅動創建名爲my-net3網橋(user-defined網段及網關)

#docker network create --driver brigde --subnet 172.22.1.0/24 --gateway 172.22.1.1 my-net3

(5)啓動容器使用新建的my-net3網絡

#docker run -it --network=my-net3 httpd

(6)啓動容器使用my-net3網絡並指定ip(只有使用 --subnet 創建的網絡才能指定靜態 IP,如果是docker自動分配的網段不可以指定ip)

#docker run -it --network=my-net3 --ip 172.22.1.10 httpd

(7)讓已啓動不同vlan的ningx容器,可以連接到my-net2(其實在nigx中新建了my-net2的網卡)

#docker run -it --network=my-net3 ningx

#docker network connect my-net2 ningx

(8)使用--name指定啓動容器名字,可以使用docker自帶DNS通信,但只能工作在user-defined 網絡,默認的 bridge 網絡是無法使用 DNS 的

#docker run -it --network=my_net2 --name=bbox1 busybox

#docker run -it --network=my_net2 --name=bbox2 busybox

(9)容器之間的網絡互聯

a). 首先創建一個 db 容器

# docker run -dti --name db centos:7.0

b). 創建一個 web 容器,並使其連接到 db

# docker run -dti --name web --link db:dblink centos:7.0/bin/bash

--link db:dblink 實際是連接對端的名字和這個鏈接的名字,也就是和 db 容器建立一個叫做 dblink 的鏈接

c). 查看鏈接的情況

#docker ps -a

d). 使用 ping 命令來測試網絡鏈接的情況

(10)容器端口映

在啓動容器的時候,如果不指定參數,在容器外部是沒有辦法通過網絡來訪問容

器內部的網絡應用和服務的

當容器需要通信時,我們可以使用 -P (大) &&-p (小)來指定端口映射

-P : Docker 會隨機映射一個 49000 ~ 49900 的端口到容器內部開放的網絡端口

-p :則可以指定要映射的端口,並且在一個指定的端口上只可以綁定一個容器。

支持的格式有

IP : HostPort : ContainerPort

IP : : ContainerPort

IP : HostPort :

查看映射

#docker port

a)映射所有接口地址,此時綁定本地所有接口上的 5000 到容器的 5000 接口,訪問任何一個本地接口的 5000 ,都會直接訪問到容器內部

#docker run -dti -p 5000:5000 centos:7.0 /bin/bash

b)多次使用可以實現多個接口的映射

#docker run -dti -p 5000:5000 -p 5022:22 centos:7.0 /bin/bash

c)映射到指定地址的指定接口

此時會綁定本地 192.168.4.169 接口上的 5000 到容器的 5000 接口

#docker run -dti -p 192.168.4.169:5000:5000 centos:7.0 /bin/bash

d) 映射到指定地址的任意接口

此時會綁定本地 192.168.4.169 接口上的任意一個接口到容器的 5000 接口

#docker run -dti -p 192.168.4.169::5000 centos:7.0 /bin/bash

e) 使用接口標記來指定接口的類型

#docker run -dti -p 192.168.4.169::5000/UDP centos:7.0 /bin/bash

(11)實驗:通過端口映射實現訪問本地的 IP:PORT 可以訪問到容器內的 web

a)將容器80端口映射到主機8080端口

#docker run -itd -p 8080:80 --name http-test httpd

b) 查看剛運行docker

#docker ps

c) 進入容器

#docker exec -itd httpd-test

d) 容器內部編輯網頁文件 index.html

********#echo “hhhhhhhhhhhh” > /var/www/html/index.html

e)到宿主機上打開瀏覽器輸入 IP:PORT 訪問驗證

 

網絡排查命令:

iptables -t nat -L

ip r

tcpdump -i docker0 -n icmp

tcpdump -i eth0 -n icmp

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章