轉自:https://blog.csdn.net/bskfnvjtlyzmv867/article/details/81044217
簡介
Docker是一種新興的虛擬化技術,能夠一定程度上的代替傳統虛擬機。不過,Docker 跟傳統的虛擬化方式相比具有衆多的優勢。我也將Docker類比於Python虛擬環境,可以有效的配置各個版本的開發環境,比如深度學習與Java環境。
其他的Docker簡介也不需要過多介紹,可以參考很流行的《Docker — 從入門到實踐》。關於博客,文末列出了最近在掘金上看到的一些入門類型文章。
優勢
本人主要想用來配置開發環境,由於實驗室機器系統環境版本等衝突的問題。
先用一張Docker — 從入門到實踐裏的圖整體感受一下其獨特的優勢:
由於本人才疏學淺,這裏便再節選一些原文中話具體描述Docker強大所在。個人感覺在入門完Docker再回頭重新認識一下下面所述的五個優勢相關解釋,會對Docker的認識有更深的理解。
- 更高效的利用系統資源:由於容器不需要進行硬件虛擬以及運行完整操作系統等額外開銷,Docker 對系統資源的利用率更高。無論是應用執行速度、內存損耗或者文件存儲速度,都要比傳統虛擬機技術更高效。因此,相比虛擬機技術,一個相同配置的主機,往往可以運行更多數量的應用。
- 更快速的啓動時間:傳統的虛擬機技術啓動應用服務往往需要數分鐘,而Docker 容器應用,由於直接運行於宿主內核,無需啓動完整的操作系統,因此可以做到秒級、甚至毫秒級的啓動時間。大大的節約了開發、測試、部署的時間。
- 一致的運行環境:開發過程中一個常見的問題是環境一致性問題。由於開發環境、測試環境、生產環境不一
致,導致有些bug 並未在開發過程中被發現。而Docker 的鏡像提供了除內核外完整的運行時環境,確保了應用運行環境一致性,從而不會再出現「這段代碼在我機器上沒問題啊」這類問題。 - 持續交付和部署:Docker是build once,run everywhere. 使用Docker 可以通過定製應用鏡像來實現持續集成、持續交付、部署。開發人員可以通過Dockerfile 來進行鏡像構建,並結合持續集成(Continuous Integration) 系統進行集成測試,而運維人員則可以直接在生產環境中快速部署該鏡像,甚至結合持續部署(Continuous Delivery/Deployment) 系統進行自動部署。
- 更輕鬆的遷移:Docker 使用的分層存儲以及鏡像的技術,使得應用重複部分的複用更爲容易,也使得應用的維護更新更加簡單,基於基礎鏡像進一步擴展鏡像也變得非常簡單。此外,Docker 團隊同各個開源項目團隊一起維護了一大批高質量的官方鏡像,既可以直接在生產環境使用,又可以作爲基礎進一步定製,大大的降低了應用服務的鏡像製作成本。使用Dockerfile 使鏡像構建透明化,不僅僅開發團隊可以理解應用運行環境,也方便運維團隊理解應用運行所需條件,幫助更好的生產環境中部署該鏡像。
II. Docker中基本概念
鏡像(Image)
鏡像,從認識上簡單的來說,就是面向對象中的類,相當於一個模板。從本質上來說,鏡像相當於一個文件系統。Docker 鏡像是一個特殊的文件系統,除了提供容器運行時所需的程序、庫、資源、配置等文件外,還包含了一些爲運行時準備的一些配置參數(如匿名卷、環境變量、用戶等)。鏡像不包含任何動態數據,其內容在構建之後也不會被改變。
容器(Container)
容器,從認識上來說,就是類創建的實例,就是依據鏡像這個模板創建出來的實體。容器的實質是進程,但與直接在宿主執行的進程不同,容器進程運行於屬於自己的獨立的命名空間。因此容器可以擁有自己的root 文件系統、自己的網絡配置、自己的進程空間,甚至自己的用戶ID 空間。容器內的進程是運行在一個隔離的環境裏,使用起來,就好像是在一個獨立於宿主的系統下操作一樣。這種特性使得容器封裝的應用比直接在宿主運行更加安全。
倉庫(Repository)
倉庫,從認識上來說,就好像軟件包上傳下載站,有各種軟件的不同版本被上傳供用戶下載。鏡像構建完成後,可以很容易的在當前宿主機上運行,但是,如果需要在其它服務器上使用這個鏡像,我們就需要一個集中的存儲、分發鏡像的服務,Docker Registry 就是這樣的服務。
Docker版本
Docker 劃分爲CE 和EE。CE 即社區版(免費,支持週期三個月),EE 即企業版,強調安全,付費使用。Docker在1.13 版本之後,從2017年的3月1日開始,版本命名規則變爲如下:
項目 | 說明 |
---|---|
版本格式 | YY.MM |
Stable版本 | 每個季度發行 |
Edge版本 | 每個月髮型 |
Docker CE 每月發佈一個Edge 版本(17.03, 17.04, 17.05…),每三個月發佈一個Stable 版本(17.03, 17.06, 17.09…),Docker EE 和Stable 版本號保持一致,但每個版本提供一年維護。
分層存儲
因爲鏡像包含操作系統完整的root 文件系統,其體積往往是龐大的,因此在Docker設計時,就充分利用Union FS 的技術,將其設計爲分層存儲的架構。所以嚴格來說,鏡像並非是像一個ISO 那樣的打包文件,鏡像只是一個虛擬的概念,其實際體現並非由一個文件組成,而是由一組文件系統組成,或者說,由多層文件系統聯合組成。
鏡像構建時,會一層層構建,前一層是後一層的基礎。每一層構建完就不會再發生改變,後一層上的任何改變只發生在自己這一層。比如,刪除前一層文件的操作,實際不是真的刪除前一層的文件,而是僅在當前層標記爲該文件已刪除。在最終容器運行的時候,雖然不會看到這個文件,但是實際上該文件會一直跟隨鏡像。因此,在構建鏡像的時候,需要額外小心,每一層儘量只包含該層需要添加的東西,任何額外的東西應該在該層構建結束前清理掉。
分層存儲的特徵還使得鏡像的複用、定製變的更爲容易。甚至可以用之前構建好的鏡像作爲基礎層,然後進一步添加新的層,以定製自己所需的內容,構建新的鏡像。
III. 安裝Docker
Win10
下載:https://docs.docker.com/docker-for-windows/install/
Docker支持64 位版本的Windows 10 Pro,且必須開啓Hyper-V。開啓方式爲:打開“控制面板”->“程序”-> “啓動或關閉Windows功能”,找到Hyper-V並勾選,確定重啓電腦。
安裝下載好的Docker for Windows Installer.exe,如下:
鑑於國內網絡問題,後續拉取Docker鏡像十分緩慢,需要配置國內鏡像加速,在系統右下角托盤Docker 圖標內右鍵菜單選擇Settings,打開配置窗口後左側導航菜單選擇Daemon,在Registry mirrors 一欄中填寫加速器地址
https://registry.docker-cn.com ,之後點擊Apply保存後Docker就會重啓並應用配置的鏡像地址了。
Ubuntu16.04+
在Ubuntu系統中安裝較爲簡單,官方提供了腳本供我們進行安裝。
sudo apt install curl
curl -fsSL get.docker.com -o get-docker.sh
sudo sh get-docker.sh --mirror Aliyun
- 1
- 2
- 3
執行這個命令後,腳本就會自動的將一切準備工作做好,並且把Docker CE 的Edge版本安裝在系統中。
啓動Docker CE
sudo systemctl enable docker
sudo systemctl start docker
- 1
- 2
建立docker 用戶組
默認情況下,docker 命令會使用Unix socket 與Docker 引擎通訊。而只有root 用戶和docker 組的用戶纔可以訪問Docker 引擎的Unix socket。出於安全考慮,一般Ubuntu系統上不會直接使用root 用戶。因此,更好地做法是將需要使用docker 的用戶加入docker用戶組。
# 建立docker組
sudo groupadd docker
# 將當前用戶加入docker組
sudo usermod -aG docker $USER
- 1
- 2
- 3
- 4
註銷當前用戶,重新登錄Ubuntu,輸入docker info,此時可以直接出現信息。
配置國內鏡像加速
在/etc/docker/daemon.json 中寫入如下內容(如果文件不存在請新建該文件)
{
"registry-mirrors": [
"https://registry.docker-cn.com"
]
}
- 1
- 2
- 3
- 4
- 5
重新啓動服務
sudo systemctl daemon-reload
sudo systemctl restart docker
- 1
- 2
IV. Docker的C/S模式
Docker 採用了C/S 架構,包括客戶端和服務端。Docker 守護進程(Daemon)作爲服務端
接受來自客戶端的請求,並處理這些請求(創建、運行、分發容器)。
Docker 守護進程一般在宿主主機後臺運行,等待接收來自客戶端的消息;Docker 客戶端則爲用戶提供一系列可執行命令,用戶用這些命令實現跟Docker 守護進程交互。我們之前在Win10的命令行中便是最主要的客戶端:
Docker也爲我們提供了Remote API來操作Docker的守護進程,也意味着我們可以通過自己的程序來控制Docker的運行。客戶端和服務端既可以運行在一個機器上,也可通過socket 或者RESTful API 來進行通信:
至於Docker的客戶端與守護進程之間的通信,其連接方式爲socket連接。主要有三種socket連接方式:
- unix:///var/run/docker.sock
- tcp://host:port
- fd://socketfd
完整的Docker的C/S連接方式的本質可以一般表示爲如下:
V. 使用Docker
容器的基操
啓動一次操作容器:docker run IMAGE_NAME [COMMAND] [ARG…]
例如,啓動一個容器輸出hello world。由於剛裝上Docker,沒有任何鏡像,所以會先下載一個最新的ubuntu18.04的docker鏡像。一次操作容器在處理完操作後會立即關閉容器。
docker run ubuntu echo 'hello world'
- 1
啓動交互式容器:docker run -t -i –name=自定義名稱 IMAGE_NAME /bin/bash
-i –interactive=true | false,默認是false
-t –tty=true | false,默認是false
–name 給啓動的容器自定義名稱,方便後續的容器選擇操作
啓動交互式的容器,就是類似虛擬機、雲主機的操作方式,操作完一個命令後仍然可以繼續:
docker run -i -t ubuntu /bin/bash
- 1
查看容器:docker ps [-a] [-l]
省略 列出正在運行的容器
-a all 列出所有容器
-l latest 列出最近的容器
查看指定容器:docker inspect name | id
name指代具體的容器名稱,id則是容器的唯一id標識。inspect命令可以詳細的展示出容器的具體信息。
docker inspect haha
- 1
重新啓動停止的容器:docker start [-i] 容器名
實際使用時,沒必要每次都重新啓動一個新的容器,我們可以重新啓動之前創建的容器,現實情況也需要我們這樣使用。
docker start -i haha
- 1
刪除停止的容器:docker rm name | id
docker rm thirsty_kepler
docker rm upbeat_albattani
- 1
- 2
守護式容器
交互式容器在運行完命令退出後即停止,而實際中我們常常需要能夠長時間運行,即使退出也能後臺運行的容器,而守護式容器具備這一功能。守護式容器具有:
- 能夠長期運行;
- 沒有交互式會話;
- 適合於運行應用程序和服務。
以守護形式運行容器
我們執行完需要的操作退出容器時,不要使用exit退出,可以利用Ctrl+P Ctrl+Q代替,以守護式形式推出容器。
附加到運行中的容器
退出正在運行的容器,想要再次進入,需要使用attach命令:docker attach name | id
docker attach haha
- 1
啓動守護式容器
啓動守護式容器,可以在後臺爲我們執行操作:docker run -d IMAGE_NAME [COMMAND] [ARG…]
當命令在後臺執行完畢,容器還是會關閉。這裏防止容器立刻退出,寫一個腳本循環輸出“hello world”。
docker run --name hiahia -d ubuntu /bin/sh -c "while true; do echo hello world; sleep 1; done"
- 1
查看容器日誌
當守護式容器在後臺運行時,我們可以利用docker的日誌命令查看其輸出:docker logs [-f] [-t] [–tail] IMAGE_NAME
-f –follows=true | false,默認是false,顯示更新
-t –timestamps=true | false,默認是false,顯示時間戳
–tail=“all” | 行數,顯示最新行數的日誌
查看容器內進程
對運行的容器查看其進程:docker top IMAGE_NAME
運行中容器啓動新進程
Docker的理念是一個容器運行一個服務,但是往往需要對一個服務進行監控,所以也需要在已經運行服務的容器啓動新的進程:docker exec [-d] [-i] [-t] IMAGE_NAME [COMMAND] [ARG…]
docker exec -i -t hiahia /bin/bash
- 1
停止守護式容器
發送信號停止容器:docker stop 容器名
強制停止:docker kill 容器名
VI. 案例:在容器中部署靜態網站
容器的端口映射
命令:run [-P] [-p]
-P,–publish-all=true | false,大寫的P表示爲容器暴露的所有端口進行映射;
-p,–publish=[],小寫的p表示爲容器指定的端口進行映射,有四種形式:
- containerPort:只指定容器的端口,宿主機端口隨機映射;
- hostPort:containerPort:同時指定容器與宿主機端口一一映射;
- ip::containerPort:指定ip和容器的端口;
- ip:hostPort:containerPort:指定ip、宿主機端口以及容器端口。
例如:
docker run -p 80 -i -t ubuntu /bin/bash
docker run -p 8080:80 -i -t ubuntu /bin/bash
docker run -p 0.0.0.0::80 -i -t ubuntu /bin/bash
docker run -p 0.0.0.0:8080:80 -i -t ubuntu /bin/bash
- 1
- 2
- 3
- 4
容器中部署Nginx服務
準備環境:
# 1. 創建映射80端口的交互式容器
docker run -p 80 --name web -i -t ubuntu /bin/bash
# 2. 更新源
apt-get update
# 3. 安裝Nginx
apt-get install -y nginx
# 4. 安裝Vim
apt-get install -y vim
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
創建靜態頁面:
mkdir -p /var/www/html
cd /var/www/html
vim index.html
- 1
- 2
- 3
修改Nginx配置文件:
# 查看Nginx安裝位置
whereis nginx
# 修改配置文件
vim /etc/nginx/sites-enabled/default
- 1
- 2
- 3
- 4
運行Nginx:
# 啓動nginx
nginx
# 查看進程
ps -ef
- 1
- 2
- 3
- 4
驗證網站訪問:
# 退出容器
Ctrl+P Ctrl+Q
# 查看容器進程
docker top web
# 查看容器端口映射情況
docker port web
- 1
- 2
- 3
- 4
- 5
- 6
通過宿主機地址加映射端口訪問:
VII. 鏡像基操
查看刪除鏡像
列出鏡像:docker images [OPTIONS] [REPOSITORY]
-a,–all=false,顯示所有鏡像
-f,–filter=[],顯示時過濾條件
–no-trunc=false,指定不使用截斷的形式顯示數據
-q,–quiet=false,只顯示鏡像的唯一id
查看鏡像:docker inspect [OPTIONS] CONTAINER|IMAGE [CONTAINER|IMAGE]
-f,–format=“”
刪除鏡像:docker rmi [OPTIONS] IMAGE [IMAGE]
-f,–force=false,強制刪除鏡像
–no-prune=false,保留未打標籤的父鏡像
虛懸鏡像:既沒有倉庫名,也沒有標籤,均爲\
獲取推送鏡像
查找鏡像:docker search [OPTIONS] TEAM
–automated=false,僅顯示自動化構建的鏡像
–no-trunc=false,不以截斷的方式輸出
–filter,添加過濾條件
拉取鏡像:docker pull [OPTIONS] NAME [:TAG]
-a,–all-tags=false,下載所有的鏡像(包含所有TAG)
推送鏡像:docker push NAME [:TAG]
Docker允許上傳我們自己構建的鏡像,需要註冊DockerHub的賬戶。也可以上傳到阿里雲,地址:https://cr.console.aliyun.com/#/namespace/index
構建鏡像
構建Docker鏡像,可以保存對容器的修改,並且再次使用。構建鏡像提供了自定義鏡像的能力,以軟件的形式打包並分發服務及其運行環境。Docker中提供了兩種方式來構建鏡像:
- 通過容器構建:docker commit
- 通過Dockerfile:docker build
使用commit命令構建鏡像
命令:docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]]
參數:-a,–author=“”,指定鏡像的作者信息
-m,–message=“”,提交信息
-p,–pause=true,commit時是否暫停容器
使用Dockerfile文件構建鏡像
Docker允許我們利用一個類似配置文件的形式來進行構建自定義鏡像,在文件中可以指定原始的鏡像,自定義鏡像的維護人信息,對原始鏡像採取的操作以及暴露的端口等信息。比如:
# Sample Dockerfile
FROM ubuntu:16.04
MAINTAINER wgp "[email protected]"
RUN apt-get update
RUN apt-get install -y nginx
EXPOSE 80
- 1
- 2
- 3
- 4
- 5
- 6
命令:docker build [OPTIONS] DockerFile_PATH | URL | -
參數:–force-rm=false
–no-cache=false
–pull=false
-q,quite=false,構建時不輸出信息
–rm=true
-t,tag=“”,指定輸出的鏡像名稱信息
VIII. 鏡像遷移
我們製作好的鏡像,一般會遷移或分享給其他需要的人。Docker提供了幾種將我們的鏡像遷移、分享給其他人的方式。推薦鏡像遷移應該直接使用Docker Registry,無論是直接使用Docker Hub還是使用內網私有Registry都可以。使用鏡像頻率不高,鏡像數量不多的情況下,我們可以選擇以下兩種方式。
上傳Docker Hub
首先,需要在Docker Hub上申請註冊一個帳號(人機驗證時需要科學上網)。然後我們需要創建倉庫,指定倉庫名稱。
在終端中登錄你的Docker Hub賬戶,輸入docker login
,輸入用戶名密碼即可登錄成功。
查看需要上傳的鏡像,並將選擇的鏡像打上標籤,標籤名需和Docker Hub上新建的倉庫名稱一致,否則上傳失敗。給鏡像打標籤的命令如下。
docker tag <existing-image> <hub-user>/<repo-name>[:<tag>]
- 1
其中existing-image
代表本地待上傳的鏡像名加tag,後面<hub-user>/<repo-name>[:<tag>]
則是爲上傳更改的標籤名,tag不指定則爲latest。
可以看到,我們重新爲ubuntu:16.04的鏡像打上標籤,觀察IMAGE ID可知,同一鏡像可以擁有不同的標籤名。接下來,我們利用push
命令直接上傳鏡像。
docker push <hub-user>/<repo-name>:<tag>
- 1
如圖,我們已經上傳成功。由於之前介紹的分層存儲系統,我們這裏是直接對已有的ubuntu鏡像進行上傳,只是重新打了標籤,所以真正上傳的只是變化的部分。
導出文件互傳
Docker 還提供了 docker load
和 docker save
命令,用以將鏡像保存爲一個tar文件。比如這次我們將ubuntu:latest這個鏡像保存爲tar文件。
查看本地磁盤,即可看見名爲ubuntu18.04的tar包。我們可以將其拷貝給其他PC,利用load命令重新導入。