這是前一篇的內容,能夠先來練習回顧一下容器的操做。html
直接下載鏡像並啓動容器,這裏選擇alpine版的:nginx
$ docker run --name web1 -p 8001:80 -d nginx:alpine Unable to find image 'nginx:alpine' locally alpine: Pulling from library/nginx e7c96db7181b: Downloading 3fb6217217ef: Download complete alpine: Pulling from library/nginx e7c96db7181b: Pull complete 3fb6217217ef: Pull complete Digest: sha256:17bd1698318e9c0f9ba2c5ed49f53d690684dab7fe3e8019b855c352528d57be Status: Downloaded newer image for nginx:alpine 01c17a72e943e93d71b56b433bea7a3d6ffa1f848dc3947f2adaf2bb2e3e7fee $
啓動參數說明:web
查看啓動的容器:redis
$ docker container ls CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES f57cd5f9d50f nginx:alpine "nginx -g 'daemon of…" 13 minutes ago Up 12 minutes 0.0.0.0:8001->80/tcp web1 $
能夠看到端口和端口映射的狀況。
這裏主要關注COMMAND,上面的顯示被截斷了:docker
$ docker container ls --no-trunc --format '{{.Command}}' "nginx -g 'daemon off;'" $
這裏啓動nginx加了參數,daemon off 字面的意思就是關閉守護進程。這是爲了讓nginx在前臺運行。
若是是nginx默認的啓動方式,那麼nginx程序將在後臺運行,一旦nginx啓動完就沒有任何程序了,結果容器也就退出了。shell
在容器中執行任何程序或服務,必定不能在容器中運行在後臺。只要運行在後臺,一啓動就會終止。json
既然Nginx已經啓動,就能夠直接用瀏覽器訪問了。而且作了端口映射,因此能夠直接經過宿主機的端口來進行訪問:http://[宿主機的IP地址]:8001
。ubuntu
容器的日誌
每個容器的目的只是爲了運行一個程序,這個程序就是容器的主進程PID=1。傳統的程序的日誌通常是保存在日誌文件中的,可是容器中沒有這個必要。由於如今整個容器就只爲了運行一個進程,日誌就能夠直接打印在控制檯上了,就是程序直接在前臺運行的效果。
使用下面的命令能夠查看日誌:centos
$ docker container logs web1
查看後,訪問幾回頁面再看下是否有訪問日誌刷新。瀏覽器
首先,直接啓動一個redis:
$ docker container run --name redis -d redis:alpine
容器啓動後,依然是停留在宿主機的命令行界面。
進入容器內部
如今須要進入到容器內部進行操做,就像以前的busybox那樣。可是,此次容量內部運行的是一個 redis-server 的程序,而且一個容器內部通常只運行一個程序。因此容器裏並無shell。
這裏和以前的busybox容器的狀況不一樣,在busybox容器內部就有一個shell。因此直接進入是沒有任何終端界面的。這裏須要啓動一個shell而後進入:
$ docker container exec -it redis /bin/sh /data # ps PID USER TIME COMMAND 1 redis 0:00 redis-server 12 root 0:00 /bin/sh 23 root 0:00 ps /data #
進入而且執行命令查看當前容器內的進程。
這裏看到,除了ps命令,還有本來的 redis-server 以及進入容器時啓動的shell。因此在容器內部運行多個進程也是能夠的,如今就是這個狀況。不過通常也就這在這種場景下須要在容器中運行多個進程。
執行其餘操做
既然都進來了,就運行些命令。看下系統的時間:
/data # date Tue Jul 16 13:03:05 UTC 2019 /data #
時間沒問題,不過期區不對,這個略過。
查看端口監聽狀況:
/data # netstat -tnl Active Internet connections (only servers) Proto Recv-Q Send-Q Local Address Foreign Address State tcp 0 0 0.0.0.0:6379 0.0.0.0:* LISTEN tcp 0 0 :::6379 :::* LISTEN /data #
使用 redis-cli 命令:
/data # redis-cli 127.0.0.1:6379> set age 23 OK 127.0.0.1:6379> set name Adam OK 127.0.0.1:6379> keys * 1) "name" 2) "age" 127.0.0.1:6379> exit /data # exit $
這裏看到 redis-cli 自帶用戶界面,因此不用啓動 /bin/sh 也能直接進來:
$ docker container exec -it redis redis-cli 127.0.0.1:6379> exit $
Docker鏡像的基礎知識。
docker鏡像含有啓動容器所須要的文件系統及其內容,所以,其用於建立並啓動docker容器。
採用分層構建機制,最底層爲bootfs,次之爲rootfs:
啓動一個busybox容器,命令ls查看容器內部,擁有完整意義上的文件系統:
$ docker container run --name shell -it busybox / # ls bin dev etc home proc root sys tmp usr var / # exit $
分層構建的鏡像:
如圖,是一個Apache鏡像。最底層是一個 Debian 的基礎鏡像,一個純淨的操做系統。在系統之上,添加了一個 emacs,這是一個代碼編輯器。再而後添加了一個 Apache。這裏每添加一個軟件都是一個獨立的層次。
最最下面的bootfs,在容器啓動時,一旦引導完rootfs就會被卸載並移除(從內存中移除)。
對於一個容器,全部寫操做,只能在最上層的可讀寫層進行。若是容器刪除了,這個最上面的可讀寫層也會一塊兒被刪除。
關於Linux操做系統的基礎鏡像,能夠參考下表來選擇合適的基礎鏡像:
推薦使用Alpine鏡像,由於它被嚴格控制並保持最小尺寸(目前小於5MB),但它仍然是一個完整的發行版。
alpine的好處主要是小,而且基本功能全。用於測試是很是方便的,並且生產上也是能夠用。雖然不建議這麼作,主要是由於缺乏調試工具。
busybox的鏡像比alpine更小,它並非一個系統發行版。最初這個工具是爲了在一張軟盤上建立一個可引導的 GNU/Linux 系統,這能夠用做安裝盤和急救盤。它是一個集成了三百多個最經常使用Linux命令和工具的軟件。因此若是是須要啓動一個容器並運行一些系統的工具和命令,那麼可使用這個做爲基礎鏡像。
另外3個就是經常使用的Linux發行版,推薦在生產系統上用。鏡像大也不是什麼問題,由於容器是分層構建的,因此本地的多個鏡像理論上是共用同一個基礎鏡像。
Docker鏡像的分層構建和聯合掛載依賴於它的專有文件系統。
aufs
在早期這個文件系統是aufs(advanced multi-layered unification filesystem), 高級多層統一文件系統。
overlayfs
aufs的競爭產品是overlayfs,overlayfs在3.18版本開始被合併到Linux內核。使用docker info
命令能夠找到當前使用的文件系統:
Storage Driver: overlay2 Backing Filesystem: xfs Supports d_tpe: true Native Overlay Diff: true
overlay2是一種抽象的二級文件系統,它須要建構在本地文件系統之上。上面的信息顯示,這裏做爲基礎的本地文件系統是xfs。
其餘文件系統
docker的分層鏡像,除了aufs,還支持btrfs,devicemapper和vfs等。早期默認支持的文件系統:
Device Mapper 是 Linux2.6 內核中支持邏輯卷管理的通用設備映射機制,它爲實現用於存儲資源管理的塊設備驅動提供了一個高度模塊化的內核構架。
最著名的 Registry 就是Docker Hub: https://hub.docker.com/
其餘的和有好比這個Quay: https://quay.io/
啓動容器時,會先試圖從本地獲取相關的鏡像。若是本地鏡像不存在,再從Registry中下載鏡像並保存到本地。
一個Registry一般由2部分組成:
Repository,由特定的docker鏡像的全部迭代版本組成的鏡像倉庫。一個Registry中能夠存在多個Repository。每一個倉庫能夠包含多個Tag(標籤),每一個標籤對應一個鏡像。
Repository可分爲頂層倉庫和用戶倉庫,用戶倉庫名稱格式爲「用戶名/倉庫名」。使用docker search
命令看一下:
$ docker search --limit 3 nginx NAME DESCRIPTION STARS OFFICIAL AUTOMATED nginx Official build of Nginx. 11704 [OK] jwilder/nginx-proxy Automated Nginx reverse proxy for docker con… 1628 [OK] bitnami/nginx Bitnami nginx Docker Image 69 [OK] $
這裏顯示了3個,第一個是沒有用戶名的屬於頂層倉庫。後面是用戶倉庫,能夠看到分別屬於的用戶名。
Idxex的做用:
這裏只是簡單的提一下這個概念,主要是程序配置文件的問題。
鏡像的使用有一個問題,就是鏡像內部使用的配置信息。配置信息能夠直接注入在鏡像裏,可是這樣就要爲不一樣的配置生成好多個不一樣版本的鏡像。
雲原生是一種爲了雲計算環境運行而生的應用程序,而且能夠解決不一樣配置的信息的問題。
以Nginx爲例,傳統的開發運行在服務器上的程序,使用配置文件來管理配置。若是把它託管到容器雲上運行,就會有諸多不便之處,最大的問題就是修改配置文件。
而那些雲原生開發的程序,會使用對於雲計算場景方便的接口來提供配置邏輯。具體到容器,至關於爲應用程序加了一層外殼,再去操做裏面的數據是不方便的。有一種作法是向容器傳入環境變量來傳遞配置信息,而配置則能夠從環境變量加載自動注入到配置中。
雲原生的大量配置均可以直接經過環境變量來獲取。
使用命令docker commint
會把容器最上面的可寫層,單首創建爲一個鏡像層,生成一個新的鏡像。
其餘製做鏡像的方法,而且是製做鏡像的最主要的方法是,基於Dockerfile製做鏡像。這部份內容很重要也不少,須要單獨再寫一篇。
基於busybox,添加一個httpd的服務。
$ docker run --name httpd -it busybox / # echo "<h1>Hello world. Busybox httpd.</h1>" > /var/www/index.html / # cat /var/www/index.html <h1>Hello world. Busybox httpd.</h1> / #
在容器內部進行修改
如今建立好了一個html文件,可是下次docker再啓動這個容器時這個文件是不會有的。如今須要作的是將以前作的改變保存好。
保存對容器的修改,生成新的鏡像
要保持這個容器的運行狀態,那就再另外開一個會話執行commit命令:
$ docker commit -p httpd sha256:5bd093efd84001a2f7412292431ead5c760acef8f4e3a2298abf9f28aa7b3cd7 $
這裏的-p參數是將容器處於暫停狀態,這樣能夠防止鏡像製做過程當中可能會有操做來改變容器的內容,建議-p參數都加上。
查看鏡像信息,新制做完成的鏡像信息以下:
$ docker image ls REPOSITORY TAG IMAGE ID CREATED SIZE <none> <none> 5bd093efd840 2 minutes ago 1.22MB busybox latest e4db68de4ff2 4 weeks ago 1.22MB $
因爲製做的時候沒有指明倉庫名和標籤名,因此都是空。這兩個字段是容許爲空的,這樣只能經過鏡像的ID來指明這個鏡像。
添加標籤信息
爲了引用時方便,仍是把倉庫名和標籤名加上吧:
$ docker image tag 5bd093efd840 myimg/httpd:v1 $ docker image ls REPOSITORY TAG IMAGE ID CREATED SIZE myimg/httpd v1 5bd093efd840 9 minutes ago 1.22MB busybox latest e4db68de4ff2 4 weeks ago 1.22MB $
一個鏡像能夠有多個標籤,再加一個latest標籤:
$ docker image tag myimg/httpd:v1 myimg/httpd:latest $ docker image ls REPOSITORY TAG IMAGE ID CREATED SIZE myimg/httpd latest 5bd093efd840 11 minutes ago 1.22MB myimg/httpd v1 5bd093efd840 11 minutes ago 1.22MB busybox latest e4db68de4ff2 4 weeks ago 1.22MB $
這裏能夠確認下,2個標籤的鏡像的ID是同樣的,因此這裏是一個鏡像,只是爲這個鏡像添加了2個標籤。
刪除標籤
沒有刪除標籤的命令,要刪除某個標籤,就直接用刪除鏡像的命令:
$ docker image tag myimg/httpd:v1 myimg/httpd:tmp1 $ docker image rm myimg/httpd:tmp1 Untagged: myimg/httpd:tmp1 $
這裏又添加了一個標籤,而後再把這個標籤給刪除,命令執行結果顯示只是把指定的標籤去掉了。因此同一個鏡像打了多個標籤,本地存的只有一份。刪除某個標籤的鏡像,只是把這個標籤從鏡像標籤的列表裏去除。以後刪除最後一個標籤的時候纔是真正的刪除了一個鏡像。
使用 inspect 命令能夠查看docker對象的底層信息。這裏要找的是鏡像的底層信息中的默認啓動的命令,具體以下:
$ docker image inspect busybox "Cmd": [ "sh" ], $
啓動時運行的命令是sh,這個也是busybox鏡像默認啓動時運行的命令,由於製做新鏡像的時候沒有指定這個內容。
從新制做一版新的鏡像,此次要指定默認啓動時運行的命令:
$ docker commit -c 'CMD ["httpd", "-f", "-h", "/var/www/"]' -p httpd myimg/httpd:v2 sha256:850da6d87c65a2c6084cdbfcabbeeeaf6c13ddbb9fbb984fec5ca05cab38830d $
參數-c不是用來指定命令的,而是指定全部要作的修改,固然這裏只要修改啓動的命令。
httpd命令參數說明
關於啓動命令httpd -f -h /var/www/
,這個具體能夠去看httpd的參數說明。-f表示做爲守護進程也就是在前臺運行,而-h參數則是指定首頁的路徑。
帶參數啓動鏡像:
$ docker container run --name httpd2 -d -p 8002:80 myimg/httpd:v2 80522bb422e16dae4ea052bcb36e51203f4d7b023fefdf3de4114598b3e95b29 $
鏡像啓動後,可使用瀏覽器訪問宿主機的IP地址加上映射的端口號來打開這個頁面,好比:http://192.168.24.170:8002/
能夠在已有鏡像的主機上把鏡像打包,將打包的文件複製到另一臺主機上再把鏡像導入,就能夠在主機之間傳遞鏡像了。這種方法不須要鏈接鏡像倉庫。
導出鏡像就是將鏡像導出到一個tar包:
$ docker image save -o httpd.tar myimg/httpd
這條命令省略了Tag標籤,這樣就會把整個倉庫打包,就是打包全部的版本。
save命令僅有一個參數-o,就是指定導出的位置。若是沒有-o參數,那就是輸出到終端。不過也不能直接輸出到終端,這樣的作法是再經過輸出重定向來把內容保存起來。因此這條命令的效果是同樣的:
$ docker image save myimg/httpd > httpd2.tar
能夠加上標籤信息,就能夠指定打包對應的Tag的鏡像。鏡像的參數能夠傳入多個,就打包多個鏡像:
$ docker image save -o httpd3.tar myimg/httpd:v1 myimg/httpd:v2
導出爲tar文件
導入的文件名能夠任意指定,不過建議使用tar擴展名。這確實是一個tar包,使用tar命令來查看tar包內部的文件列表:
$ tar -tvf httpd.tar -rw-r--r-- 0/0 1491 2019-07-18 15:10 25079c1e47bf896a028e55d715dc06e251f3efe53ca655ad63f6085ce6a465a8.json -rw-r--r-- 0/0 1464 2019-07-18 15:05 7f36d8e3488df22381081d68c7f2215750167250114abd0b2f31d99e81a7bfd7.json drwxr-xr-x 0/0 0 2019-07-18 15:05 957ac2430f81aaa485efe07e872a460156d73e48f53f31a9743ed0d5f0fa44d7/ -rw-r--r-- 0/0 3 2019-07-18 15:05 957ac2430f81aaa485efe07e872a460156d73e48f53f31a9743ed0d5f0fa44d7/VERSION -rw-r--r-- 0/0 1081 2019-07-18 15:05 957ac2430f81aaa485efe07e872a460156d73e48f53f31a9743ed0d5f0fa44d7/json -rw-r--r-- 0/0 4608 2019-07-18 15:05 957ac2430f81aaa485efe07e872a460156d73e48f53f31a9743ed0d5f0fa44d7/layer.tar drwxr-xr-x 0/0 0 2019-07-18 15:10 a24e93a2c2b0548055a10d18f0c88dc138c57ee6f13020538bf80da2bfefc59f/ -rw-r--r-- 0/0 3 2019-07-18 15:10 a24e93a2c2b0548055a10d18f0c88dc138c57ee6f13020538bf80da2bfefc59f/VERSION -rw-r--r-- 0/0 1107 2019-07-18 15:10 a24e93a2c2b0548055a10d18f0c88dc138c57ee6f13020538bf80da2bfefc59f/json -rw-r--r-- 0/0 4608 2019-07-18 15:10 a24e93a2c2b0548055a10d18f0c88dc138c57ee6f13020538bf80da2bfefc59f/layer.tar drwxr-xr-x 0/0 0 2019-07-18 15:05 dea411b43d1b59da62f22c37c8507e7757c2dd9a5467a523f92e612d88e83ae8/ -rw-r--r-- 0/0 3 2019-07-18 15:05 dea411b43d1b59da62f22c37c8507e7757c2dd9a5467a523f92e612d88e83ae8/VERSION -rw-r--r-- 0/0 406 2019-07-18 15:05 dea411b43d1b59da62f22c37c8507e7757c2dd9a5467a523f92e612d88e83ae8/json -rw-r--r-- 0/0 1441280 2019-07-18 15:05 dea411b43d1b59da62f22c37c8507e7757c2dd9a5467a523f92e612d88e83ae8/layer.tar -rw-r--r-- 0/0 579 1970-01-01 08:00 manifest.json -rw-r--r-- 0/0 238 1970-01-01 08:00 repositories $
從IMAGE ID能夠看出,這裏確實是將2個版本的鏡像到打包了。
導出並壓縮
用下面的方法完成導出並壓縮:
$ docker save myimage:latest | gzip > myimage_latest.tar.gz
使用load命令能夠方便的將鏡像導入:
$ docker image load -i httpd3.tar 6194458b07fc: Loading layer [==================================================>] 1.441MB/1.441MB dd0dd7cb79c9: Loading layer [==================================================>] 4.608kB/4.608kB Loaded image: myimg/httpd:latest Loaded image: myimg/httpd:v1 698704828883: Loading layer [==================================================>] 4.608kB/4.608kB Loaded image: myimg/httpd:v2 $ docker image ls REPOSITORY TAG IMAGE ID CREATED SIZE myimg/httpd v2 25079c1e47bf 30 minutes ago 1.22MB myimg/httpd latest 7f36d8e3488d 35 minutes ago 1.22MB myimg/httpd v1 7f36d8e3488d 35 minutes ago 1.22MB $
上面最後一次打包的文件是 httpd3.tar。執行打包命令的時候指定了v1和v2標籤,並無指定latest標籤。不過這裏能看到全部的3個標籤。因此標籤只是一個標籤,一個鏡像能夠有多個標籤,可是不一樣標籤的鏡像是同一個鏡像。
不使用-i參數的話,默認從標準輸出導入,用下面的方法也是同樣的:
$ docker image load < httpd3.tar
導入壓縮文件
Load an image or repository from a tar archive (even if compressed with gzip, bzip2, or xz) from a file or STDIN. It restores both images and tags.
導入鏡像能夠從tar文件,也能夠從幾種壓縮文件直接導入。操做起來都同樣,程序會本身識別。應該是經過文件名後綴吧。