docker:一文學基礎使用

發佈時間:2020年3月25日
發佈者:progorhtml


20200325211424


docker介紹

20200221100731

  • 官網
  • docker 是一個開源的應用容器引擎,docker 可讓開發者打包他們的應用以及應用的環境依賴到一個輕量級、可移植的容器中,而後發佈到任何流行的 平臺(linux,windows)上。
  • docker基於Go語言。
  • docker的相關技術有docker swarm ,kubernates,Compose,這些都是比較熱門的容器技術,特別是k8s特別火。


docker是一種容器技術,爲何如今容器技術那麼火?mysql

  1. 容器可以打包應用和隔離運行環境,這是出發點。linux

  2. 容器打包應用快速而高效。git

  3. 容器的資源使用效率比VM高。在理論上,他確定要比本來無容器下更消耗資源,但他換來的是與環境的隔離,避免了不一樣環境的問題。而他與另外一種環境隔離技術--虛擬機技術相比又更加節省資源,由於虛擬機是虛擬出一臺完整的機器。容器使用宿主機硬件,不須要像虛擬機同樣虛擬硬件。docker使用宿主機的操做系統內核,不須要像虛擬機那樣從新建立一個內核(建立內核消耗時間較多)。相應的,容器的啓動速度也要快於虛擬機。github

  4. 容器能夠部署在各類平臺,只要這個平臺可以安裝docker,而後就能夠在docker上部署容器。web

  5. 容器的部署很快。若是你使用了一臺物理機來部署你的應用,若是某天你的物理機掛了,那麼你須要在另一臺機上安裝各類環境,而後再部署應用。但容器的話就像一套環境的模板,部署很快。redis

  6. 【最重要的一點】容器的打包是把環境一塊兒打包的,就保證了每一個應用的運行環境都會是如出一轍的。一次打包,多地運行。不少時候,BUG都是因爲環境不一樣致使的,相同的環境能夠避免一些BUG的產生。sql


現實使用意義:
docker因爲其快速部署和一次構建屢次部署的特性,使得根據服務器的壓力動態快速部署服務端成爲可能,比人工部署服務端快速得多。docker



安裝與鏡像源配置

CentOS7


安裝

1.卸載可能存在的舊版的docker:shell

yum remove docker \
                  docker-client \
                  docker-client-latest \
                  docker-common \
                  docker-latest \
                  docker-latest-logrotate \
                  docker-logrotate \
                  docker-engine

2.安裝所需的軟件包:

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

3.設置下載docker的yum庫

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

4.安裝最新版docker-ce

yum install -y docker-ce

5.啓動docker

systemctl daemon-reload && systemctl start docker

6.查看docker信息,若是打印成功,那麼就是安裝成功了:

docker info


設置鏡像源

docker建立一個容器須要對應的鏡像,而鏡像一般都是從docker hub上下載的,docker hub的功能有點像github,都是一種倉庫,docker hub是存儲鏡像的倉庫。
可是docker hub是一個國外的網站,他的訪問速度不太行,github的不穩定你們應該也深有感覺了。因此咱們要修改docker 拉取鏡像的鏡像源,讓他從國內的一些鏡像網站來拉取鏡像,這些國內的鏡像都會依靠本身的穩定網絡不斷同步docker hub。

編輯/etc/docker/daemon.json文件,把裏面registry-mirrors的值改爲下面的:【還能夠自行增長阿里雲的源】
vi /etc/docker/daemon.json

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

阿里的鏡像源仍是比較穩定的,能夠進入阿里雲搜索容器鏡像服務,而後按照下圖來找到加速地址:
20200316114309

補充:

  • 其餘系統的安裝方式,能夠參考官方文檔:Docker安裝

簡單使用例子

這是一個使用docker來建立一個包含了mysql的容器,咱們藉助這個例子來體驗docker建立應用容器的快速。


1.安裝以後,運行systemctl start docker啓動docker,而後執行如下命令:

docker pull mysql:5.7

當這樣顯示的時候就是表明成功了。
20200221143504

2.查看鏡像:
docker images
20200221143633

3.使用這個鏡像建立一個容器(也能夠稱爲鏡像實例):

語法:
docker run --name 這個鏡像實例的名字 -e MYSQL_ROOT_PASSWORD=mysql根用戶的密碼 -d -p 主機端口:容器內部的端口 mysql:標籤
    (MYSQL_ROOT_PASSWORD=123456 =號不要有空格間隔)
    (-d表明後臺運行,-p是爲了把容器內部的mysql綁定到外部端口進行使用)

具體示例:
docker run --name testmysql -e MYSQL_ROOT_PASSWORD=123456 -p 3306:3306 -d mysql:5.7

20200221161028


4.查看容器運行狀態:
docker container ls
20200221161126


5.測試鏈接,因爲咱們使用了-p 3306:3306,這是將容器內部的3306端口與主機的端口創建的鏈接,,因此能夠直接經過鏈接主機Linux的端口來操做容器內部的mysql:
假設當前個人機器的IP是192.168.48.129,那麼我須要鏈接192.168.48.129:3306來操做數據庫,請使用你的mysql鏈接工具來測試吧😀。

你作完這個實驗後,你應該能感覺到你大大的節省了安裝mysql和部署mysql的功夫,而若是咱們建立了一個包含了咱們的應用的鏡像,那麼部署咱們的應用的人也能大大減小部署的難度和節省大量的時間。
另外,咱們還引出了鏡像和容器的概念,這將在下面講。


基礎概念

四個概念

上面引出了鏡像和容器的概念,下面講一下。

  • 鏡像之於容器,就好像類之於類對象,鏡像是生成多個容器的模板,有了鏡像,能很快地生成多個容器;

  • Images: Images是鏡像的意思,鏡像裏面是一般包含了應用及其應用運行所須要的環境,但他只是一些資源,並無運行起來。就好像安裝操做系統的時候須要IOS文件,但IOS並非操做系統,IOS只是一些文件。只有經過一些對這些資源的軟件處理和硬件處理才能夠運行成一個操做系統(在docker中,也須要對鏡像作相似的處理)。

  • Container:Container是容器的意思,鏡像啓動後的實例稱爲容器。容器裏面包含獨立運行的一個或多個應用。(從虛擬化角度來可,容器就是一個包含了服務端的運行起來的虛擬機,這就比如我在個人虛擬機上裝了一個個人應用,應用的環境什麼的都裝好了,而後我把它的vmx文件發給你,你再經過vmware把這些vmx啓動起來。)

  • 只有將鏡像建立成容器後,裏面得應用纔是真正得運行起來得(這就好像在面向對象中,平時都是使用具體的類對象);

  • Repository:Repository是倉庫的意思,倉庫保存了各類打包好的鏡像,咱們須要從倉庫中拉取鏡像來建立容器。有些人或許會把倉庫和倉庫註冊中心弄亂了,這裏以一個例子說明:假如我是tomcat鏡像的開發者,我建立了一個tomcat的倉庫,就像github的倉庫那樣,而後我第一次提交了一個tomcat 5.0的鏡像,第二次提交了一個tomcat 7.0的鏡像,這些鏡像都是屬於tomcat倉庫的,但這些鏡像都是屬於同一系列鏡像(固然了,你就是鐵頭娃的存儲了不一樣系列的鏡像那也沒什麼好說的,一個倉庫裏面最好仍是存儲屬於同一個更新系列的鏡像比較好),若是你要獲取redis的鏡像,那麼你要從redis倉庫獲取。而管理着多個倉庫的就是倉庫註冊服務器,docker hub就是一個知名的倉庫註冊服務器,就好像github是個代碼託管中心同樣。

  • Registry:倉庫註冊服務器,是倉庫註冊的地方。類比github來解釋,好比說github上面有私人的倉庫和公開的倉庫,私人的倉庫並非誰都能拉取和推送的,因此github在實際上擔當了倉庫註冊服務器,它的下面再有私人倉庫和公開倉庫。咱們指定獲取鏡像的倉庫時,其實首先要指定倉庫註冊服務器,這樣docker才知道咱們的倉庫是在哪裏的。平時咱們指定的鏡像源地址,其實就是倉庫註冊服務器,由於可能會不一樣地址的倉庫註冊服務器,就比如git界的github與gitlab。鏡像倉庫網站


經過一個例子把上面的概念串聯起來:

  • 假設咱們須要拉取一個tomcat鏡像。
    首先,咱們指定這個鏡像的倉庫在docker hub,而後搜索一下是否有這個倉庫,而後指定從這個拉取鏡像的哪一個版本(tag),而後把它從倉庫上拉取下來;
    鏡像拉取下來以後,使用這個鏡像來生成一個容器,這個容器是怎麼能夠在docker上面運行的呢?這些鏡像都會帶有能夠支撐它運行的操做系統,一個較小的操做系統也就10+M,這些操做系統運行在docker上,而裏面的應用運行在各自的操做系統上。(你能夠這樣類比,docker = vmware,鏡像 = vmx文件,容器= vmware對vmx文件運行起來以後的包含了咱們的應用的操做系統)
    上面的步驟運行起來了一個容器,你能夠對這個容器進行操做。(就好像我在簡單使用例子一節中講述的那樣)

  • 假設你對了這個容器進行了修改,而後你想提交給別人,該怎麼作呢?(這裏只是文字概念,詳情參考下面的把鏡像推送到阿里雲
    首先,你須要在一個倉庫註冊服務器中建立本身的倉庫,而後在docker中進行登陸操做,並基於修改的容器生成一個鏡像,把這個鏡像推送到倉庫上。而後別人就能夠從你的倉庫中拉取下鏡像了,若是你的倉庫是個開放的倉庫的話。



鏡像概念補充:

  • 鏡像用於生成容器,它就是生成容器的模板。
  • 能夠說鏡像就是中止的容器,在後面咱們甚至能夠學到經過容器來生成自定義的鏡像。
  • 鏡像是應用與依賴環境的打包,鏡像裏面的應用是須要運行在操做系統之上的,鏡像自己都會攜帶一個比較小型的操做系統,這些操做系統都去除了大多數無用的內容,好比一個簡單的linux鏡像 Alpine Linux 大約只有 10+MB, Ubuntu鏡像大概100+M。
  • 其實上面說了,鏡像本質上仍是一些文件而已,不過這些文件能夠被docker以容器的方式運行起來,由於鏡像的文件包含了操做系統,docker實質上就像是運行一個小型操做系統那樣運行容器。
  • 鏡像是實質是一個文件系統,因爲如今還只是開頭,先不引入那麼多概念了,並且這東西的概念性內容比較多,可能會後面再整理一章節來說。


容器概念補充:

  • 容器用於運行應用或者服務,因此鏡像中必須包含應用或服務所必要的操做系統和應用文件。
  • 容器的運行要基於操做系統,爲了在保證應用能夠運行的同時節省資源,會對沒必要要的操做系統文件和應用文件進行了縮減。就好像之前的Linux操做系統其實很小,如今的Linux操做系統隨隨便便就幾百上千M,若是削減了一些沒必要要的功能,

經常使用命令:

查看docker信息

  • 查看本地docker版本:docker version或者docker -v,會返回安裝的docker的版本。
  • 查看本地docker信息:docker info


鏡像操做

  • 搜索docker倉庫相關鏡像(或者應當說在倉庫註冊服務器搜索倉庫吧,不過咱們下載的是鏡像而不是倉庫罷了):docker search 鏡像關鍵字,例如docker search mysql。你除了在命令行中搜索,也能夠在docker hub上搜索鏡像。
    • docker search 鏡像關鍵字 -s 數字A:列出start數不小於指定數字A的鏡像。【若是提示--star過時,那麼使用 docker search 鏡像關鍵字 -filter=stars=數字A】【star相似於github中的star,也表示這個鏡像的受歡迎程度】
    • docker search 鏡像關鍵字 --no-trunc:完整顯示鏡像的描述Description
    • docker search 鏡像關鍵字 --automated:只列出automated build類型的鏡像。
      20200316100515

若是你在docker hub上搜索鏡像, 那麼首先進入docker hub(https://hub.docker.com/),而後裏面有個搜索框。搜索mysql以後你能夠看到mysql相關的鏡像,隨便點進去一個,你能夠看到這個鏡像的Description(描述),Tags(能夠看到有什麼版本),Reviews(評價),而在鏡像的旁邊會有一個docker pull xxxx(xxxx是鏡像的名字),這個就是教你怎麼拉取鏡像。(拉取下面講)


  • 從倉庫拉取鏡像:docker pull 鏡像名:tag
    • :tag是可選的,tag表示標籤,多爲軟件的版本,默認是latest。好比docker pull mysql:5.7就表明拉取5.7版本的mysql鏡像。
      *tag表示標籤,多爲軟件的版本,對於一個鏡像有什麼tag,建議到docker hub上搜索這個鏡像,裏面會顯示這個鏡像的tag。

  • 查看全部本地已有鏡像:docker images
    • docker images -a:顯示全部鏡像(包含中間映像層)。中間映像層的意思是,一個鏡像多是由多層鏡像層疊而來的,這中間的部分就是中間映像層。(這個知識與鏡像的實質有關,何時再寫一章單獨分析。)
    • docker images -q: 只顯示ID,不顯示鏡像名。
    • docker images --no-trunc: 顯示完整的鏡像信息,主要是完整顯示了Image ID,就跟git的版本ID差很少,短的ID也能夠用來標識鏡像。
    • docker images --digests: 顯示鏡像的摘要信息。每個機器上拉取下來的同一個鏡像生成的鏡像ID是不同的,只有摘要才能判斷他們是不是同一個鏡像。
      20200316110923

  • 刪除指定的本地鏡像:docker rmi 鏡像的ID或者docker rmi 鏡像名:tag
    • 能夠同時刪除多個鏡像:docker rmi 鏡像的ID1 鏡像的ID2或者docker rmi 鏡像名1:tag 鏡像名2:tag
    • 刪除所有:docker rmi ${docker images -qa},這是把docker images -qa的結果做爲刪除鏡像的參數。
    • -f:強行刪除鏡像

  • 使用鏡像建立一個容器實例:docker run [鏡像ID]或[鏡像名:tag]
    • --name 容器的名字:定義容器的名字
    • --detach -d:讓容器後臺運行
    • -p 主機的端口:容器的端口:將容器的端口綁定到主機的端口
      • 除了主機的端口:容器的端口,還能夠是IP:主機的端口:容器的端口IP::容器的端口容器的端口
    • -P:隨機對容器開放的端口進行綁定。容器開放的端口是須要聲明的,好比tomcat鏡像中會聲明開放端口8080。隨機綁定就會把聲明的端口隨機與主機端口綁定。
    • --env-e:設置容器的環境變量,有些容器須要環境變量來設置一些數據,好比mysql的初始密碼。
    • 示例:docker run --name testmysql -e MYSQL_ROOT_PASSWORD=123456 -p 3306:3306 -d mysql:5.7
    • 若是本地不存在這個鏡像,那麼會從倉庫拉取,若是倉庫中也沒有,那麼就會報錯。
    • 同時執行命令:docker run [鏡像ID]或[鏡像名:tag] 命令,這個會在啓動容器以後,幫咱們執行咱們指定的命令。好比docker run -t centos:7 top就會在啓動centos容器後,幫咱們執行top,此處我沒用使用-i因此會當場看到top命令的執行。【這個當心使用吧,由於有時候可能會覆蓋容器內部的一些命令,好比若是你在運行mysql鏡像時額外執行命令,那麼將會致使這個容器沒法運行,這將在Dockerfile處講解】

容器操做

  • 查看正在運行的容器:docker ps
    • docker ps -a查看全部容器,包括沒有在運行的。
    • docker ps -l查看最近建立的容器(一個)
    • docker ps -n 數字查看最近建立的n個容器
    • docker ps -q:只顯示容器ID
    • docker ps --no-trunc:只顯示容器ID

  • 查看容器日誌:docker logs 容器名稱或者容器的ID,有時候容器的啓動問題就要依靠日誌來解決,容器的故障信息都會顯示在日誌中。有些應用會把應用的運行日誌寫在容器日誌中,但有些會寫在容器內的文件中。
    • docker logs -t 容器名稱或者容器的ID :加入時間戳
    • docker logs -f 容器名稱或者容器的ID :持續打印
    • docker logs --tail 數字 容器名稱或者容器的ID :顯示最後多少行日誌
    • docker logs --since 時間 容器名稱或者容器的ID:查看什麼時間的日誌,時間能夠是30m,1h,或者2020-02-02,或者2013-01-02T13:23:37(UTC統一時間),是從何時開始的意思,會從指定時間取到如今。

  • 中止容器:docker stop 容器名稱或者容器的ID

  • 啓動容器:docker start 容器名稱或者容器的ID

  • 刪除指定容器:docker contatiner rm 容器名稱或者容器的ID,容器必須先中止才能被刪除
    • 刪除全部容器:docker rm -f ${docker ps -a -q}
    • docker ps -a -q | xargs docker rm

  • 向容器發命令:docker exec 容器名稱或者ID 命令
    • 發生命令並實時交互docker exec -it 容器名稱或者ID linux命令-it能夠說是進入了交互界面,而沒有-it的時候只是發了一個請求,顯示的只是請求的結果。-t:在新容器內指定一個僞終端或終端。-i:容許你對容器內的標準輸入 (STDIN) 進行交互。it能夠分開使用。
    • 有些命令是必須以-i模式交互的,好比如今的mysql鏈接的時候要求你在交互的時候輸入密碼。
    • 示例:docker exec testmysql echo hello

  • 進入容器:docker attach,與docker exec -it的效果有點相似。但它進入的實際上是容器啓動時最後執行的命令
    • 好比說docker run -td centos:7 top,建立容器的時候執行了一個top命令,那麼attach進入的就是這個top命令,若是你執行的是其餘命令,attcach也是進去那個命令的狀況下。因此可能有些容器你attach進去是一片空白。【當你在attach中關閉了這個容器最終運行的進程的時候(注意,是關閉,退出並不表明必定關閉),這個容器可能會自動關閉,由於你關閉了他的前臺進程。若是你是在終端命令下,可使用ctrl+p+q來退出容器但不關閉終端,退出直接用exit。】
    • 還有一個attach與exec的不一樣之處,exec是每次都執行新的命令的(也就是說命令是用新的進程來執行),並不影響原有的容器的前臺進程,而attach是進入了容器的前臺進程。

  • 查看容器的端口綁定狀況:docker port 容器名稱或者ID
    20200323145719

  • 查看容器內運行的進程:docker top 容器名稱或者ID

  • 查看容器的底層信息:docker inspect 容器名稱或者ID,會顯示容器名稱、容器數據存儲位置、網絡設置、環境變量、容器卷等信息。

  • 從本地複製文件到容器中:docker cp 本地文件路徑 容器ID:容器路徑

  • 從容器複製文件到本地:docker cp 容器ID:容器路徑 本地文件路徑

  • 根據Dockerfile生成鏡像:docker build 【Dockerfile的內容,後面講】

  • 根據容器來建立一個鏡像:docker commit【生成新鏡像的內容,後面講】

補充:

  • 命令幫助:docker --help
  • 更多命令能夠參考命令文檔,雖然他們的文檔講解很通常。


當你學完上述的命令的時候,你應該能理解以前的簡單使用例子中的那些命令的意義了。

上述命令講解中,簡單例子中沒用到的命令,也講述了基本用法。

下面將是一些稍微深刻一點的內容。

  • 好比容器卷
  • 好比有如何製做docker鏡像。
  • 好比有如何推送鏡像到阿里雲。
  • 以及會補充以前一些概念性的內容。
    若是你還不是很瞭解鏡像的拉取、容器的建立和運行命令的話,建議先從各方面嘗試使用各類命令,作一些幫助本身瞭解的測試。

關於環境變量:


  • 鏡像可能會支持本身的一些參數,就好比說建立mysql鏡像實例的時候須要提供root帳號的初始密碼,這些參數一般經過環境變量來指定。
    這一些都一般能夠在docker hub中搜索鏡像的時候在鏡像的How to use this image模塊看到:
    20200225143707

容器內容補充:


資源節省方面:

  • 爲了在保證應用能夠運行的同時節省資源,會對沒必要要的操做系統文件和應用文件進行了縮減。好比下圖的mysql容器中也是有一個Linux系統,但從mysql的大小來看,咱們能夠猜到這個操做系統的大小仍是遠小於正常的系統鏡像的:
  • 查看mysql容器中操做系統核心:
    20200226151024
  • mysql容器的大小:
    20200303113310

自動狗帶

當一個容器發現本身無事可作的時候就會自動狗帶(自殺)。
好比說你運行centos容器:docker run centos:7


那麼你會發現這個容器一啓動就自動中止了。這是由於centos內部並無前臺進程,若是docker檢測到這個容器沒有前臺進程,那麼就會自動關閉這個容器。
20200316144432



docker run -td centos這句命令可讓centos不自動中止,由於使用-t就爲這個容器建立一個前臺進程/bin/bash,平時使用-it的時候,會直接進行交互,咱們去掉-i和加上d,使得這個交互終端掛起,不立刻交互。

後面咱們再想交互的時候,可使用docker attach 容器ID或者docker exec -it 容器ID 命令來進行交互。


上面說了attach的使用注意事項,因爲這裏又涉及了attach,再說一遍:

  • 進入容器:docker attach,與docker exec -it的效果有點相似。但它進入的實際上是容器啓動時最後執行的命令
  • 好比說docker run -td centos:7 top,建立容器的時候執行了一個top命令,那麼attach進入的就是這個top命令,若是你執行的是其餘命令,attcach也是進去那個命令的狀況下。因此可能有些容器你attach進去是一片空白。【當你在attach中關閉了這個容器最終運行的進程的時候(注意,是關閉,退出並不表明必定關閉),這個容器可能會自動關閉,由於你關閉了他的前臺進程。若是你是在終端命令下,可使用ctrl+p+q來退出容器但不關閉終端,退出直接用exit。】

解決自動狗帶這個問題的方法就是把你的應用之前臺的方式來運行,又或者建立一個額外的前臺進程,因此對於那些是後臺運行的應用要注意


其餘概念補充:


Daemon守護進程

在執行docker命令的時候,有時候docker還沒啓動,那麼可能會報一個這樣的錯誤。
20200316234244
你應該看到了一個docker daemon,daemon在計算機領域一般是守護進程的意思,下面咱們來介紹一下這個的意義。


docker是一種Client-Server結構的系統,其實咱們對於docker的全部操做都是守護進程來幫咱們發送給docker的,咱們平時運行命令實際上是在Docker Client,Docker Client經過命令行與Docker Damon通訊,完成Docker相關操做。
咱們表面上操做docker,但實際上,咱們只是操做守護進程,守護進程來幫咱們發送命令。


容器卷Volume


  • Volume主要用來共享主機和容器的數據。
  • 在不使用容器卷的時候,容器內的硬盤數據是獨立的,主機沒法直接讀取容器內的硬盤文件(複製能夠),並且這時候若是刪除了容器,容器內的硬盤數據也會丟失。
  • 並且由於這樣,數據與容器關聯性也變強了,咱們不能根據這個容器來生成鏡像了,可能有時候也沒法直接很方便的快速部署,因此外部持久化,把數據從容器中抽離出來就能夠下降耦合性。
  • 若是咱們想要對容器內的數據進行外部持久化,那麼就須要使用上容器捲了。
  • Volume的效果有點像mount,把主機的某個文件夾與容器內的文件夾進行了映射,容器的關閉並不會清空主機上的文件夾,從而把容器的數據持久化到了主機上。

命令:

  • 建立容器的時候指定容器卷:docker run -it -v /宿主機路徑:/容器內路徑 鏡像名
    • 當目錄並不存在的時候,會自動建立。
    • 你能夠試驗一下,在內部的指定容器卷目錄中建立一個有數據的文件,而後再去主機看是否存在,並修改,看修改的內容容器中可否看到。
    • 只讀模式:docker run -it -v /宿主機路徑:/容器內路徑:ro 鏡像名,默認建立的容器卷是兩邊均可讀可寫的,加上ro以後,是容器只讀,主機可讀可寫。
      20200323161338

  • 建立一個Volume:docker volume create 容器卷名稱
    • 此時將自動在主機的docker目錄下指定一個目錄做爲容器卷在主機的目錄,好比/var/lib/docker/volumes/hello/_data
    • 建立的容器卷的信息可使用docker volume inspect 容器卷名稱來查看
    • 容器卷名稱爲空的時候將使用一個64位的隨機的名稱。

  • 查看Volume的詳細信息:docker volume inspect 容器卷名稱
    20200323164032

  • 顯示docker的Volume列表:docker volume ls
    • -q只顯示容器卷名稱

  • 刪除未使用的Volume:docker volume prune,會移除沒有被容器使用的容器卷。

  • 刪除一個或多個Volume:docker volume rm 容器卷名稱

容器卷的數據傳遞

可使用--volumes-from來繼承另外一個容器的容器卷。
好比:
先執行:docker run --name centos1 -itd -v /outpath:/containerpath centos:7
再執行:docker run --name centos2 -itd --volumes-from centos1 centos:7
而後再執行:docker exec -it centos2 cat /containerpath/a
你就能夠看到centos2中也配置了容器卷/outpath:/containerpath,也就是說,centos2繼承了centos1的容器卷。

  • 因爲他們對應的都是主機的同一個目錄,centos1修改的centos2也能看到,反之也是,主機中修改的centos1和centos2均可以看到。
  • 並且它的繼承只是配置信息的傳遞罷了,雖然上面說的是centos2繼承了centos1的容器卷,但centos1關閉了也不會影響centos2讀寫容器卷的內容
  • centos1是掛載了容器卷的容器,能夠稱爲數據卷容器,其餘的容器經過繼承它的容器卷,就能夠實現多個容器之間的數據共享。

補充:

  • 容器卷除了這樣加,還可使用Dockerfile來添加,這在後面講。


怎麼製做docker鏡像


  • 一種是經過拉取已有的鏡像建立容器,而後對容器內部進行修改,而後使用命令docker commit經過容器來生成一個新的鏡像。
  • 一種是經過製做Dockerfile,而後docker build來建立鏡像。

修改已有鏡像:

1.好比說咱們能夠拉取一個tomcat鏡像,而後生成一個容器;
docker pull tomcat:8.0


2.啓動這個容器:
docker run --name mytomcat -d -p 8888:8080 tomcat:8.0


3.對容器進行一些自定義的修改,咱們這裏把咱們的一個很是簡單的應用部署到tomcat上。【這個war是我從一個structs的jar包下弄的,是一個很乾淨的war,適合用來作實驗】war下載地址

  • 經過docker cp 本地文件路徑 容器ID:容器路徑命令把咱們的war包複製到tomcat中。
    docker cp /struts2-blank.war mytomcat:/
  • 進入容器:
    docker exec -it mytomcat /bin/bash
    把容器內的war包複製到容器的tomcat中:
    root@9ce9d01569e6:/usr/local/tomcat# cp /struts2-blank.war webapps/
    而後重啓容器:
    docker restart mytomcat
    【你這裏能夠玩一下,在cd /usr/local/tomcat/bin/下執行shutdown.sh,你就會發現沒過一會,容器就自動中止了。】
    而後你在外部訪問http://主機地址:8888/struts2-blank就能夠訪問到

那麼如今,這個容器能夠說已經有了咱們的應用了,那麼怎麼基於這個容器來建立新的鏡像,以方便經過鏡像來方便部署到一臺臺機器上呢?


4.而後提交鏡像。
docker commit 能夠提交容器副本,使之成爲一個新的鏡像。

命令:docker commit -a "做者名" -m "提交說明" 容器名稱或id 打包的鏡像名稱:標籤
選項說明:
-a :提交的鏡像做者;
-c :使用Dockerfile指令來建立鏡像;
-m :提交時的說明文字;
-p :在commit時,將容器暫停。

[root@localhost /]# docker commit -a "progor" -m "簡單的新鏡像測試" mytomcat  mytomcat2:1.0
sha256:a3393dbf9326d0f065d6ee8d757c6d7c1050df8a513e6a52286b4af91154806b

5.查詢一下本地鏡像列表,能夠看到咱們剛剛建立的鏡像:
20200323212156


6.咱們基於這個鏡像來建立一個新的容器看看,看是否是有咱們的應用了:
docker run --name mytomcat2 -d -p 8889:8080 mytomcat2:1.0
7.而後再在外部訪問一下http://主機地址:8889/struts2-blank,能夠訪問,證實了新的鏡像包含了咱們以前部署的應用。



使用Dockerfile

使用Dockerfile其實也是經過修改已有鏡像來建立新鏡像,但它把修改的命令都存儲到Dockerfile中了。Dockerfile比手動修改更方便管理。
下面列一個mysql 5.7的示例Dockerfile,因爲篇幅問題,這裏就不直接列了,請參考下列連接,而後介紹一下以後,咱們就學習相關的命令。
mysql/5.7/Dockerfile



實例的介紹:

上面的示例的內容也比較長,我不會全部都講,只會講基本流程。
20200324113205

20200324113610

從上面的流程來看,其實就是引入了一個基礎的鏡像以後,配置環境變量等各類參數,其實也就是講咱們以前的手動的操做換成了換成命令寫在了Dockerfile了。



經常使用命令:

  • FROM:用於指定一個基礎的鏡像。
    • 一般FROM命令都是第一個命令。用來導入基礎的鏡像,好比可能tomcat這個鏡像要基於jdk,若是要建立一個有tomcat的鏡像,那麼這個鏡像的基礎必須得有jdk鏡像。因此若是咱們要建立一個運行於tomcat上的Web應用的鏡像的話,咱們首先須要一個tomcat做爲基礎鏡像。
    • 基礎鏡像涉及到了一些鏡像實質的知識,其實一個鏡像能夠說是層層繼承下來的,好比說centos繼承一個根源鏡像,jdk繼承這個centos鏡像,tomcat繼承這個jdk鏡像。
    • FROM 能夠出現屢次,用來繼承多個鏡像。這多個鏡像中,共同的部分只會繼承一次。
    • 指定基礎鏡像的時候也須要指定tag,若是不指定,那麼tag默認是latest。
    • 示例:FROM debian:buster-slim【來自 mysql/5.7/Dockerfile


  • RUN:用來執行命令。
    • 格式: RUN 命令或者RUN ["可執行文件"," 參數1","參數2"],例如:RUN ["/bin/bash", "-c", "echo hello"]
      • RUN 命令是在shell中執行的,會作Shell處理,多行命令,可使用\分行。
      • RUN ["可執行文件","參數1","參數2"]是非SHELL的,因此它不會進行上下文變量解析,例如RUN [ "echo", "$HOME" ]
    • RUN命令還有一些與中間映像層相關的,這將在後面單獨講。
    • 示例:RUN groupadd -r mysql && useradd -r -g mysql mysql【來自 mysql/5.7/Dockerfile


  • ENV:用於爲容器設置環境變量。
    • ENV設置的環境變量,可使用docker inspect命令來查看。
    • docker run --env 環境變量名=變量值能夠在運行時指定環境變量。會覆蓋默認的環境變量。
    • 可使用$變量名或者${變量名}來獲取指定環境變量的值。
    • 示例:ENV TINI_VERSION 0.14.0 【來自jenkins/Dockerfile
    • 在獲取環境變量的時候,\({variable:-word}表示若是variable設置,則結果將是該值。若是variable未設置,則爲word結果;若是variable設置了,則將是word結果,不然結果爲空字符串。word均可以是任何字符串,包括其餘環境變量。能夠經過`\`來進行轉義:例如,`\$foo`或`\${foo}`將分別轉換爲`\)foo${foo}`文字。
    • 環境變量可使用在如下命令中:ADD,COPY,ENV,EXPOSE,FROM,LABEL,STOPSIGNAL,USER,VOLUME,WORKDIR,ONBUILD(1.4之前不支持環境變量)。
    • 若是你在ENV中既修改了變量又獲取了這個變量,獲取的變量的值會是舊的值,而不是設置的新的值。ENV abc=bye def=$abc


  • USER:用來指定運行容器的時候使用的用戶以及可選的用戶組,默認使用ROOT用戶
    • 格式:USER <user>[:<group>] 或者 USER <UID>[:<GID>]
    • 示例:USER ${user}【來自jenkins/Dockerfile


  • WORKDIR:用來修改默認的工做目錄,也就是你剛進去容器的工做目錄。當容器啓動時,默認的工做目錄是/
    • 對於工做目錄的修改,對後面的使用了相對路徑的Dockerfile命令也是有影響的,。
    • 示例:WORKDIR /data【來自 redis/6.0-rc/Dockerfile
      20200325112712


  • COPY:
    • 格式:COPY [--chown=<user>:<group>] <src> <dest>將文件從路徑 <src> 複製到容器路徑 <dest>中。
    • src是一個相對路徑,或者一個URL;dest是一個絕對路徑
    • 示例:COPY docker-entrypoint.sh /usr/local/bin/【來自 redis/6.0-rc/Dockerfile

  • ADD:
    • ADD [--chown=<user>:<group>] <src> <dest>:將文件從路徑 <src> 複製到容器路徑 <dest>中,並解壓。[--chown=<user>:<group>]是可選的,用於修改文件的所屬用戶或所屬組,但僅使用與Linux容器
      *src是一個相對路徑,或者一個URL;dest是一個絕對路徑


  • VOLUME:建立容器卷,這樣會隨機建立一個與容器內容器卷相對於的主機目錄。

  • EXPOSE:
    • EXPOSE指令通知Docker容器在運行時偵聽的端口,在上面的docker run中有說到能夠隨機端口綁定,容器怎麼知道爲咱們綁定哪些容器內部的端口呢,就是經過expose知道的。
    • EXPOSE <port> [<port>/<protocol>...]
    • 暴露端口的時候還能夠指定端口的鏈接方式:好比EXPOSE 80/tcpEXPOSE 80/udp,默認使用TCP
    • 不管EXPOSE設置如何,均可以在運行時使用-p標誌覆蓋它們。
    • 示例:EXPOSE 6379 redis/6.0-rc/Dockerfile


  • CMD:CMD也是用來執行命令的,但他只能生效一次,若是你有多個,那麼最後指定的生效。
    • 格式:CMD ["可執行命令或文件","param1","param2"]CMD ["param1","param2"] CMD 命令 param1 param2
    • 示例:CMD ["redis-server"]CMD [ "sh", "-c", "echo $HOME" ]CMD echo hello,CMD ls -a,CMD ["ls","-a"]


  • ONBUILD:當將鏡像做爲構建另外一個鏡像的基礎時,也就是FROM的時候,ONBUILD纔會觸發,他不會在本身構建鏡像時觸發,只會在別人FROM它的時候纔會觸發。
    • ONBUILD讓指令延遲到下一個使用FROM的Dcokerfile創建鏡像時才執行(只能傳一代,不會傳到孫子,也就是說只能延遲一次)。
    • ONBUILD 主要用於定製基礎鏡像,經過一系列命令來定製基礎鏡像。首先,你要判斷這些命令是應該在子代時執行,而基礎鏡像中不該該執行的,並且這些命令應該是基於子代的上下文環境的,好比有一個代碼解析器,在父代的時候,他應該還不知道他要解析的代碼在那裏,而在子代的時候才知道在哪裏,你或許能夠說能夠在子代的Dockerfile中把解析器複製過去解析器的目錄下,但ONBUILD提供了一個更好的方案,若是你在基礎鏡像的ONBUILD中定義「把解析器複製過去解析器的目錄下」操做,因爲ONBUILD的基礎時才運行,因此他使用了子代的上下文環境,它就知道了代碼文件在哪裏,而後他再「把解析器複製過去解析器的目錄下。
    • 示例:ONBUILD RUN echo hello
      ONBUILD的使用例子,沒有結合場景的


  • LABEL:用來添加一些鏡像元數據。用來指定鏡像的全部者/建立者、版本等各類元信息,這些元信息對於鏡像沒有影響,僅用於標識,
    • 格式:LABEL <key>=<value> <key>=<value> <key>=<value> ...
    • 指定建立人,之前使用MAINTAINER 建立者如今推薦使用LABEL maintainer="建立者"
    • 指定鏡像全部者,LABEL OWNER="所屬者"
    • 要查看LABEL信息,可使用docker inspect命令。
    • 示例:LABEL maintainer="SvenDowideit@home.org.au"【官方文檔示例】
      20200325110054


  • ENTRYPOINT:用於指定經過鏡像建立或運行容器時,要執行的命令或者文件。
    • 示例:ENTRYPOINT ["docker-entrypoint.sh"]【來自 redis/6.0-rc/Dockerfile
    • 那麼它與CMD的區別呢?有時候咱們能在Dockerfile中看到ENTRYPOINT命令以後還有CMD命令。
    • 當你在RUN中附加命令的時候,會附加在ENTRYPOINT後面,並覆蓋CMD.
    • CMD應該用做ENTRYPOINT在容器中定義命令或執行臨時命令的默認參數的方式。


  • ARG:
    • ARG是docker1.9 版本才新加入的指令。
    • ARG 定義的變量只在創建 image 時有效,創建完成後變量就失效消失。
    • ARG定義的變量能夠在Dockerfile中使用${group}來獲取。
    • 同名的ENV環境變量始終會覆蓋ARG同名變量
    • ARG user=jenkins【來自jenkins/Dockerfile
      20200325085552


補充:

  • 能夠在Dockerfile中使用#來作單行註釋,例如# add gosu for easy step-down from root
  • 你應該能夠看到上面的RUN命令的時候一般會執行不少命令,這些命令使用\來分行。
  • 另外,在使用環境變量或者ARG變量的時候,若是變量值有空格,要要使用""包裹,例如cd "$OPENSSL_PATH"
  • 說一下RUN,CMD,ENTRYPOINT的區別:
    • RUN它用於執行命令,作的主要是一些準備工做,好比建立用戶、建立目錄、安裝程序,並不直接與應用的啓動相關。
    • ENTRYPOINT用於指定建立和運行容器時要執行的命令,因此你能夠在ENTRYPOINT中指定建立容器的時候要運行的一些命令,或者能夠說,它是RUN的組合,但ENTRYPOINT更具備應用意義。RUN能夠隨便建立一個目錄,或許作的只是一些運行的前置工做;但ENTRYPOINT裏面應該與這個容器前臺進程(應用)的運行更加相關,好比定義如何啓動應用。固然你也可使用RUN建立前臺進程😓。。。
    • CMD也是用來指定容器的前臺進程的,但有了ENTRYPOINT的時候,它將做爲ENTRYPOINT的參數,好比上面提到的MYSQL的例子中 mysql/5.7/Dockerfile ,最後的是CMD ["mysqld"],而前面有ENTRYPOINT ["docker-entrypoint.sh"],這將會在執行docker-entrypoint.sh的最後執行mysqld,內部有沒有再處理mysqld,就要看具體的docker-entrypoint.sh了。這是一個流行用法,因此你能夠在不少Dockerfile中看到"docker-entrypoint.sh"
  • 基礎鏡像繼承相關:
    • 環境變量會繼承下來,若是你知道基礎鏡像的環境變量的話,能夠直接複用。
    • 基礎鏡像的CMD會繼承下來
    • 容器卷會繼承下來。
  • 官網Dockerfile文檔,只能說好過沒有


嘗試使用Dockerfile建立鏡像



先來解釋一下`docker build`的用法: * 語法格式:`docker build Dockerfile文件路徑`,不要漏了文件路徑,這個路徑同時也是Dockerfile的上下文 * `-f Dockerfile文件名` ,默認狀況下,文件名默認是Dockerfile,若是你使用的不是默認的,須要使用-f指定 * `-t 鏡像名:tag`,若是你不指定鏡像名的話,那你就要留意後面構建完成的時候返回給你的鏡像ID。好比`Successfully built 0a9ee2fae0d0` * 示例:`docker build -t mytomcat6:1.0 -f TomcatDockerfile .` 最後的.表明從當前目錄查找TomcatDockerfile;`docker build -t mytomcat5:1.0 war`會從當前目錄下的war目錄下查找Dockerfile * docker build還有不少配置參數,好比cpu,內存什麼的,自查瞭解吧。

1.咱們根據以前的「修改已有鏡像」的例子來寫一個Dockerfile:

# 繼承基礎鏡像
FROM tomcat:8.0
# 把war包拷貝進去
COPY struts2-blank.war /
# 把容器內的war包複製到容器的tomcat中
WORKDIR $CATALINA_HOME

RUN cp /struts2-blank.war webapps/
# 指定端口,端口也會繼承下來,因爲咱們也使用同樣的端口,其實能夠省略EXPOSE
# EXPOSE 8080
# 啓動tomcat,基礎鏡像的CMD會繼承下來 因此其實下面的CMD能夠省略,除非你要執行另外的命令
# CMD ["catalina.sh", "run"]

2.執行docker build 建立一個鏡像:
docker build -t mytomcat3:1.0 .

3.經過這個鏡像建立一個容器:
docker run --name mytomcat3container -d -p 8888:8080 mytomcat3:1.0



4.測試訪問:
http://主機地址:8888/struts2-blank
5.結果是能夠訪問的,說明咱們使用Dockerfile實現了以前基於容器修改生成鏡像的效果。


阿里雲推送鏡像和拉取鏡像

下面的基原本自阿里雲的官網教程,只不過加了配圖。

1. 登陸阿里雲Docker Registry

語法:
$ sudo docker login --username=用戶名 倉庫註冊服務器
示例:
$ sudo docker login --username=10086 registry.cn-shenzhen.aliyuncs.com

20200325171738

  • 用於登陸的用戶名爲阿里雲帳號全名,
  • 密碼爲開通服務時設置的密碼,不是你阿里雲的密碼。
  • 您能夠在訪問憑證頁面修改憑證密碼。


2. 將鏡像推送到Registry

語法:
1.登陸
$ sudo docker login --username=用戶名 倉庫註冊服務器
2.建立tag:
$ sudo docker tag 鏡像ID 倉庫註冊服務器/用戶名/鏡像名:[鏡像版本號]
3.推送鏡像:
$ sudo docker push 倉庫註冊服務器/用戶名/鏡像名:[鏡像版本號]

docker tag 用於重命名鏡像,下面的就把本地的一個鏡像重命名了。

20200325172712

20200325173059

而後你就能夠在倉庫管理頁看到這個鏡像了。
20200325173023



3. 從Registry中拉取鏡像

語法:
$ sudo docker pull 鏡像地址
示例:
$ sudo docker pull registry.cn-shenzhen.aliyuncs.com/用戶名/鏡像名:[鏡像版本號]

20200325173307




這一篇文章,其實講的東西仍是很淺的。還有不少東西都沒用講。
但對於基本使用場景應該仍是能夠應付的。(固然,😄容器管理、swarm、k8s並無講)

還有不少技術沒講,後面有空再寫吧。。。咕咕咕。

  • .dockerignore
  • 命令的深層次應用啊
  • 鏡像的實質:聯合文件系統啊、容器的環境隔離技術啊
  • 。。。。。
    有興趣的能夠自行去找書籍來了解更多底層的東西。
    20200325211131
相關文章
相關標籤/搜索