Linux學習 day11之docker續集

躍上青空發表於2020-12-06

使用 Docker 容器

建立容器

Docker 中,真正對外提供服務的還是容器,本小節我們們來建立一個容器。

建立容器的格式:docker run [option] image [cmd]
如:docker run -d --name nginx -p 80:80 nginx

容器啟動引數

-d 以守護程式方式執行
-p 指定對映埠
-P 隨機對映埠
-i 保持標準輸入開啟
-t 分配一個偽終端
-v 設定掛載檔案到主機上
--rm 當容器關閉時自動刪除
--name 為啟動的容器設定一個名字
--network 指定使用哪個網路
-e 設定容器中的環境變數
--link 連結到另一個容器
-h 指定容器內的主機名

停止容器

docker終止容器是首先向容器傳送 SIGTERM 訊號,等待一段時間超時後(預設 10 秒),再傳送 SIGKILL 訊號來終止容器。

語法:docker stop nginx

NGINX 容器被我們終止後。這個時候我們也可以重新啟動這個容器。
docker start nginx


進入容器

在使用容器的過程中,我們難免需要進入容器進行排查問題。下面我們就來介紹進入容器的集中方式。

attach

attach 是最早 docker 官方推出的進入容器的命令了,不過使用該命令有一個問題。當多個視窗同時使用該命令進入該容器時,所有的視窗都會同步顯示。如果有一個視窗阻塞了,那麼其他視窗也無法再進行操作,當所有視窗退出時,容器結束。

`docker attach nginx`

127.0.0.1 - "GET / HTTP/1.1" 308 171 "-" "curl/7.59.0" 0.000 - .

exec

attach 之後,exec 是官方推出的有一個新的進入容器的命令,這個命令相當於在容器中執行一個命令

docker exec -it nginx /bin/bash

nginx [ / ]$
nginx [ / ]$

nsenter

需要配合 docker inspect 來使用(早期沒有 exec 命令時,企業當中最長用的方式之一),Docker 是用 golang語言開發,所以它也支援 go 語言的摸版語法。

nsenter --target $( docker inspect -f {{.State.Pid}}nginxv1 ) --mount --uts --ipc --net --pid

mesg: ttyname failed: No such device
root@6f99ae8757f7:/#

ssh

在生產環境中排除了使用 docker attach 命令進入容器之後,相信大家第一個想到的就是 ssh。在映象(或容器)中安裝 SSH Server,這樣就能保證多人進入容器且相互之間不受干擾了,相信大家在當前的生產環境中(沒有使用Docker 的情況)也是這樣做的。但是使用了 Docker 容器之後不建議使用ssh 進入到Docker容器內。

總結

進入 docker container中一般情況下有 4 種方式,最常用的是execnsenter這兩種。

Nsenterexec之間的區別?

  • Execdocker 自帶的命令,NsenterLinux 提供的命令。
  • Exec相當於在容器內執行一個命令,而Nsenter 是僅僅進入容器之中而已。

刪除容器

可以使用 docker rm 命令來刪除處於終止或退出狀態的容器,命令格式為:docker rm container
如: docker rm nginx

強制刪除

強制刪除一個正在執行的容器
docker rm -f nginx


匯入與匯出容器

某些時候,需要將容器從一個系統遷移到另外一個系統,此時可以使用 Docker 的導人和匯出功能,這也是 Docker 自身提供的一個重要特性。

匯出容器

匯出容器是指,匯出一個已經建立的容器到一個檔案,不管此時這個容器是否處於執行狀態 可以使用docker [container] export 命令,該命令格式為:
docker export daf9c3656be3 > nginx.tar

匯入容器

匯出的檔案又可以使用 docker [ container] import 命令導人變成映象,該命令格式為:
docker import nginx.tar test/nginx:v1

實際上,既可以使用docker load命令來匯入映象儲存檔案到本地映象庫,也可以使 docker [container] import命令來匯入一個容器快照到本地映象庫 這兩者的區別在於 容器快照檔案將丟棄所有的歷史記錄和後設資料資訊(即僅儲存容器當時的快照狀態),而映象儲存檔案將儲存完整記錄,體積更大 此外,從容器快照檔案導人時可以重新指定標籤等後設資料資訊。

檢視容器

檢視容器詳情可以使用docker container inspect [OPTIONS] CONTAINER [CONTAINER . .. ]子命令

[root@alvin-test-os ~]# docker inspect k8s
[
	{
	"Id": "726b695a337c63b2ba617ed282171dff82a3d51cc0bdc43194ce63beaf656c38",
	"Created": "2020-11-16T04:05:53.271281122Z",
	"Path": "docker-entrypoint.sh",
	"Args": 
		[
		"./start"
		],
	... 此處略去千百行
	}
]

容器命令詳解

複製命令

複製命令類似於 Linux 系統中的scp命令,是將宿主主機上的內容上傳到容器中,也可能是將容器中的檔案下載到宿主主機中。

# 將容器中的內容複製到宿主主機
[root@alvin-test-os ~]# docker cp 726b695a337c:/opt/start .
[root@alvin-test-os ~]# ls | grep start
Start

#將宿主主機中的檔案複製到容器中
[root@alvin-test-os ~]# docker cp start 726b695a337c:/root
[root@alvin-test-os ~]# docker exec 726b695a337c ls /root
start

Docker 網路

Docker 本身的技術依賴於 Linux 核心虛擬化技術的發展。所以Docker 對 Linux 核心的特性有很強的依賴。
本章主要介紹Docker所使用的 Linux 網路技術。

網路基礎

其中 Docker 使用到的與 Linux 網路有關的技術分別有:網路名稱空間、Veth、Iptables、網橋、路由。

網路名稱空間

為了支援網路協議棧的多個例項,Linux 在網路協議棧中引入了網路名稱空間(Network Namespace),這些獨立的協議棧被隔離到不同的名稱空間中。處於不同的名稱空間的網路協議棧是完全隔離的,彼此之間無法進行網路通訊,就好像兩個“平行宇宙”。通過這種對網路資源的隔離,就能在一個宿主機上虛擬多個不同的網路環境,而 Docker 正是利用這種網路名稱空間的特性,實現了不同容器之間的網路隔離。在 Linux 的網路名稱空間內可以有自己獨立的Iptables 來轉發、NATIP 包過濾等功能。

Linux 的網路協議棧是十分複雜的,為了支援獨立的協議棧,相關的這些全域性變數都必須修改為協議棧私有。最好的辦法就是讓這些全域性變數成為一個 Net Namespace 變數的成員,然後為了協議棧的函式呼叫加入一個Namespace引數。這就是 Linux 網路名稱空間的核心。所以的網路裝置都只能屬於一個網路名稱空間。當然,通常的物理網路裝置只能關聯到 root這個名稱空間中。虛擬網路裝置則可以被建立並關聯到一個給定的名稱空間中,而且可以在這些名稱空間之間移動。
在這裡插入圖片描述

建立一個名稱空間

[root@alvin-test-os ~]# ip netns add test01
[root@alvin-test-os ~]# ip netns add test02
[root@alvin-test-os ~]# ip netns list
test02
test01

Veth 裝置

引入 Veth 裝置對是為了在不同的網路名稱空間之間進行通訊,利用它可以直接將兩個網路名稱空間連結起來。由於要連線的兩個網路名稱空間,所以Veth 裝置是成對出現的,很像一對乙太網卡,並且中間有一根直連的網線。既然是一對網路卡,那麼我們將其中一端稱為另一端的peer。在Veth 裝置的一端傳送資料時,它會將資料直接傳送到另一端,並觸發另一端的接收操作。
在這裡插入圖片描述

Veth 裝置操作

建立Veth 裝置對
ip link add veth type veth peer name veth001
  • 生成了兩個 veth 裝置, 互為對方的 peer
繫結名稱空間

ip link set veth001 netns test01

  • ip link show | grep veth已經檢視不到 veth001,當我們進入test01 名稱空間之後,就可以檢視到:
    ip netns exec test01 bash
Veth分配IP
# 設定 IP
[root@alvin-test-os ~]# ip netns exec test01 ip addr add 172.16.0.111/20 dev veth001

# 繫結
[root@alvin-test-os ~]# ip netns exec test01 ip link set dev veth001 up

# 檢視
[root@alvin-test-os ~]# ip netns exec test01 ip a
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
14: veth001@if15: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state
LOWERLAYERDOWN group default qlen 1000
link/ether 96:f1:a2:1d:1d:10 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 172.16.0.111/20 scope global veth001
valid_lft forever preferred_lft forever
  • 這個時候雙方就通了。
檢視對端 Veth 裝置

ip netns exec test01 ethtool -S veth001

為對端Veth裝置設定IP
[root@alvin-test-os ~]# ip addr add 172.16.0.112/20 dev veth
[root@alvin-test-os ~]# ip link set dev veth down
[root@alvin-test-os ~]# ip link set dev veth up
[root@alvin-test-os ~]# ping 172.16.0.111
PING 172.16.0.111 (172.16.0.111) 56(84) bytes of data.
64 bytes from 172.16.0.111: icmp_seq=1 ttl=64 time=0.126 ms
64 bytes from 172.16.0.111: icmp_seq=2 ttl=64 time=0.081 ms
^C
--- 172.16.0.111 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 999ms
rtt min/avg/max/mdev = 0.081/0.103/0.126/0.024 ms

網橋

Linux 可以支援多個不同的網路,它們之間能夠相互通訊,就需要一個網橋。 網橋是二層的虛擬網路裝置,它是把若干個網路介面“連線”起來,從而報文能夠互相轉發。網橋能夠解析收發的報文,讀取目標 MAC 地址的資訊,和自己記錄的 MAC 表結合,來決定報文的轉發目標網口。

網橋裝置 brO 繫結了 eth0eth1 。對於網路協議械的上層來說,只看得到 brO 。因為橋接是在資料鏈路層實現的 ,上層不需要關心橋接的細節,於是協議枝上層需要傳送的報文被送到 brO ,網橋裝置的處理程式碼判斷報文該被轉發到 ethO 還是 ethl ,或者兩者皆轉發。反過來,從 ethO 或從 ethl 接收到的報文被提交給網橋的處理程式碼,在這裡會判斷報文應該被轉發、丟棄還是提交到協議枝上層。 而有時 ethl 也可能會作為報文的源地址或目的地址 直接參與報文的傳送與接收,從而繞過網橋。

在這裡插入圖片描述

Iptables

我們知道, Linux 絡協議樵非常高效,同時比較複雜 如果我們希望在資料的處理過程中對關心的資料進行一些操作該怎麼做呢? Linux 提供了一套機制來為使用者實現自定義的資料包處理過程。在 Linux 網路協議棋中有一組回撥函式掛接點,通過這些掛接點掛接的鉤子函式可以在 Linux 網路棋處理資料包的過程中對資料包進行 些操作,例如過濾、修改、丟棄等 整個掛接點技術叫作 Netfilter lptablesNetfilter 負責在核心中執行各種掛接的規則,執行在核心模式中:而 lptables 是在使用者模式下執行的程式,負責協助維護核心中 Netfilter 的各種規則表 通過 者的配合來實現整個 Linux 網路協議戰中靈活的資料包處理機制。

總結

network namespace 主要提供了關於網路資源的隔離,包括網路裝置、IPv4 和 IPv6協議棧、IP 路由表、防火牆、/proc/net目錄、/sys/class/net目錄、埠(socket)等。

linux Bridge 功能相當於物理交換機,為連在其上的裝置(容器)轉發資料幀。如 docker0網橋。

iptables 主要為容器提供 NAT 以及容器網路安全。

veth pair 兩個虛擬網路卡組成的資料通道。在 Docker 中,用於連線 Docker 容器和 Linux Bridge。一端在容器中作為 eth0 網路卡,另一端在 Linux Bridge 中作為網橋的一個埠。


Docker 網路模式

Docker使用 Linux 橋接的方式,在宿主機虛擬一個 Docker 容器網橋(docker0),Docker 啟動一個容器時會根據 Docker 網橋的網段分配給容器一個IP地址,稱為Container-IP,同時Docker網橋是每個容器的預設閘道器。因為在同一宿主機內的容器都接入同一個網橋,這樣容器之間就能夠通過容器的Container-IP直接通訊。

Docker網橋是宿主機虛擬出來的,並不是真實存在的網路裝置,外部網路是無法定址到的,這也意味著外部網路無法通過直接 Container-IP訪問到容器。如果容器希望外部訪問能夠訪問到,可以通過對映容器埠到宿主主機(埠對映),即docker run建立容器時候通過-p-P 引數來啟用,訪問容器的時候就通過[宿主機 IP]:[容器埠]訪問容器。

Docker 網路模型配置說明
host 模式–-network=host容器和宿主機共享 Network namespace
containe 模式--network=container:ID容器和另外一個容器共享 Network namespacekubernetes中的 pod 就是多個容器共享一個 Network namespace
none 模式--network=none容器有獨立的 Network namespace,但並沒有對其進行任何網路設定,如分配 veth pair 和網橋連線,配置IP 等。
bridge 模式--network=bridgeDocker 程式啟動時,會在主機上建立一個名為 docker0的虛擬網橋,此主機上啟動的Docker容器會連線到這個虛擬網橋上。虛擬網橋的工作方式和物理交換機類似,這樣主機上的所有容器就通過交換機連在了一個二層網路中。(預設為該模式)

HOST 模式

如果啟動容器的時候使用 host 模式,那麼這個容器將不會獲得一個獨立的 Network Namespace,而是和宿主機共用一個Network Namespace。容器將不會虛擬出自己的網路卡,配置自己的 IP 等,而是使用宿主機的 IP和埠。但是,容器的其他方面,如檔案系統、程式列表等還是和宿主機隔離的。

使用host模式的容器可以直接使用宿主機的 IP 地址與外界通訊,容器內部的服務埠也可以使用宿主機的
埠,不需要進行NAThost最大的優勢就是網路效能比較好,但是 docker host上已經使用的埠就不能再
用了,網路的隔離性不好。

在這裡插入圖片描述

[root@instance-gvpb80ao ~]# docker run -d --name my-web --network host nginx
Unable to find image 'nginx:latest' locally
latest: Pulling from library/nginx
d121f8d1c412: Pull complete
ebd81fc8c071: Pull complete
655316c160af: Pull complete
d15953c0e0f8: Pull complete
2ee525c5c3cc: Pull complete
Digest: sha256:c628b67d21744fce822d22fdcc0389f6bd763daac23a6b77147d0712ea7102d0
Status: Downloaded newer image for nginx:latest
06941559a3f7e0c53cf228302dedc2040c10f2eb0b6e3d0f962c065b0e0419ce


[root@instance-gvpb80ao ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED
STATUS PORTS NAMES
06941559a3f7 nginx "/docker-entrypoint.…" 6 minutes ago
Up 6 minutes my-web


[root@instance-gvpb80ao ~]# curl 127.0.0.1:80
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
body {
width: 35em;
margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif;
}
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>

Containe 模式

這個模式指定新建立的容器和已經存在的一個容器共享一個 Network Namespace,而不是和宿主機共享。新建立的容器不會建立自己的網路卡,配置自己的IP,而是和一個指定的容器共享IP、埠範圍等。同樣,兩個容器除了網路方面,其他的如檔案系統、程式列表等還是隔離的。兩個容器的程式可以通過 lo 網路卡裝置通訊。

在這裡插入圖片描述

[root@instance-gvpb80ao ~]# docker run -itd --name test01 busybox
Unable to find image 'busybox:latest' locally
latest: Pulling from library/busybox
df8698476c65: Pull complete
Digest: sha256:d366a4665ab44f0648d7a00ae3fae139d55e32f9712c67accd604bb55df9d05a
Status: Downloaded newer image for busybox:latest
dd99687d303d61d649364084ad353ec38b4e07149b0328301ec9691f18669951
[root@instance-gvpb80ao ~]# docker run -itd --name test02 --network
"container:test01" busybox
72adb0dcdb93b6adc7a62e1ad1ac274f64b8cec941d5f89da43fcd0757f99fa3
[root@instance-gvpb80ao ~]# docker exec -it test02 sh
/ # ifconfig
eth0 Link encap:Ethernet HWaddr 02:42:AC:11:00:02
inet addr:172.17.0.2 Bcast:172.17.255.255 Mask:255.255.0.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:28 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:2423 (2.3 KiB) TX bytes:0 (0.0 B)
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
UP LOOPBACK RUNNING MTU:65536 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
/ # exit
[root@instance-gvpb80ao ~]# docker exec -it test01 sh
/ # ifconfig
eth0 Link encap:Ethernet HWaddr 02:42:AC:11:00:02
inet addr:172.17.0.2 Bcast:172.17.255.255 Mask:255.255.0.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:29 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:2493 (2.4 KiB) TX bytes:0 (0.0 B)
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
UP LOOPBACK RUNNING MTU:65536 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
/ #

none模式

使用none模式,Docker容器擁有自己的Network Namespace,但是,並不為Docker容器進行任何網路配置。也就是說,這個 Docker 容器沒有網路卡、IP、路由等資訊。需要我們自己為 Docker 容器新增網路卡、配置IP 等。

這種網路模式下容器只有lo迴環網路,沒有其他網路卡。none模式可以在容器建立時通過--network=none來指定。這種型別的網路沒有辦法聯網,封閉的網路能很好的保證容器的安全性。

在這裡插入圖片描述

[root@instance-gvpb80ao ~]# docker run -itd --name test03 --network none busybox
b9dde79754bc110314be4aecde1251dcdd6ce28fdf43102ae184b79c6e7414bc
[root@instance-gvpb80ao ~]# docker exec -it test03 sh
/ # ifconfig
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
UP LOOPBACK RUNNING MTU:65536 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)

bridge 模式

Docker 程式啟動時,會在主機上建立一個名為 docker0的虛擬網橋,此主機上啟動的Docker容器會連線到這個虛擬網橋上。虛擬網橋的工作方式和物理交換機類似,這樣主機上的所有容器就通過交換機連在了一個二層網路中。

docker0 子網中分配一個 IP給容器使用,並設定 docker0IP 地址為容器的預設閘道器。在主機上建立
一對虛擬網路卡 veth pair裝置,Dockerveth pair裝置的一端放在新建立的容器中,並命名為eth0(容器的網
卡),另一端放在主機中,以vethxxx這樣類似的名字命名,並將這個網路裝置加入到 docker0網橋中。可以
通過brctl show 命令檢視。

bridge模式是 docker的預設網路模式,不寫--net引數,就是bridge模式。使用 docker run -p 時,docker
實際是在iptables 做了 DNAT 規則,實現埠轉發功能。可以使用iptables -t nat -vnL 檢視。

在這裡插入圖片描述

[root@instance-gvpb80ao ~]# docker run -itd --name test04 busybox
dd17d863b2957a29df44b2552365eb0cfc01552fd4ec6b8b63e28dfd0d61472e
[root@instance-gvpb80ao ~]# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default
qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default
qlen 1000
link/ether fa:16:3e:4a:9c:c7 brd ff:ff:ff:ff:ff:ff
inet 172.16.0.4/20 brd 172.16.15.255 scope global noprefixroute eth0
valid_lft forever preferred_lft forever
inet6 fe80::f816:3eff:fe4a:9cc7/64 scope link noprefixroute
valid_lft forever preferred_lft forever
3: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group
default
link/ether 02:42:ab:42:6a:8a brd ff:ff:ff:ff:ff:ff
inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
valid_lft forever preferred_lft forever
inet6 fe80::42:abff:fe42:6a8a/64 scope link
valid_lft forever preferred_lft forever
5: veth870d996@if4: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master
docker0 state UP group default
link/ether ae:36:24:dc:11:6d brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet6 fe80::ac36:24ff:fedc:116d/64 scope link
valid_lft forever preferred_lft forever
7: veth6acb18a@if6: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master
docker0 state UP group default
link/ether 4e:03:b1:5e:40:91 brd ff:ff:ff:ff:ff:ff link-netnsid 1
inet6 fe80::4c03:b1ff:fe5e:4091/64 scope link
valid_lft forever preferred_lft forever
[root@instance-gvpb80ao ~]# docker exec -it test04 bash
/ # ping 172.16.0.4
PING 172.16.0.4 (172.16.0.4): 56 data bytes
64 bytes from 172.16.0.4: seq=0 ttl=64 time=0.113 ms
64 bytes from 172.16.0.4: seq=1 ttl=64 time=0.101 ms
^C
--- 172.16.0.4 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 0.101/0.107/0.113 ms


Dockerfile 構建映象

Dockerfile 由一行行命令語句組成, 並且支援以#開頭的註釋行。一般而言, Dockerfile主體內容分為四部分:基礎映象資訊、 維護者資訊、 映象操作指令和容器啟動時執行指令。

Docker以從上到下的順序執行 Dockerfile 的指令。為了指定基本映像,第一條指令必須是FROM。一個宣告以#字元開頭則被視為註釋。可以在 Docker 檔案中使用 RUNCMDFROMEXPOSEENV 等指令。

在這裡插入圖片描述

FROM:指定基礎映象,必須為第一個命令

格式:
FROM <image>
FROM <image>:<tag>
FROM <image>@<digest>

示例: FROM mysql:5.6

注: tag 或 digest 是可選的,如果不使用這兩個值時,會使用 latest 版本的基礎映象

MAINTAINER: 維護者資訊

格式:
MAINTAINER <name>

示例:
MAINTAINER Jasper Xu
MAINTAINER sorex@163.com
MAINTAINER Jasper Xu <sorex@163.com>

RUN:構建映象時執行的命令

RUN 用於在映象容器中執行命令,其有以下兩種命令執行方式:
shell 執行
格式:
RUN <command>

exec 執行
格式:
RUN ["executable", "param1", "param2"]

示例:
RUN ["executable", "param1", "param2"]
RUN apk update
RUN ["/etc/execfile", "arg1", "arg1"]

注: 
RUN 指令建立的中間映象會被快取,並會在下次構建中使用。如果不想使用這些快取映象,可以在構建時指定--no-cache 引數,如:docker build --no-cache

ADD:將本地檔案新增到容器中

tar 型別檔案會自動解壓(網路壓縮資源不會被解壓)

#格式:
ADD <src>... <dest>
ADD ["<src>",... "<dest>"] 用於支援包含空格的路徑

#示例:
ADD hom* /mydir/ # 新增所有以"hom"開頭的檔案
ADD hom?.txt /mydir/ # ? 替代一個單字元,例如:"home.txt"
ADD test relativeDir/ # 新增 "test" 到 `WORKDIR`/relativeDir/
ADD test /absoluteDir/ # 新增 "test" 到 /absoluteDir/

COPY:功能類似 ADD,但是是不會自動解壓檔案,也不能訪問網路資源

指令:COPY
功能描述:複製檔案到映象中

語法:COPY < src>< dest>|[< src>”,… “< dest>]

提示:指令邏輯和 ADD 十分相似,同樣 Docker Daemon 會從編譯目錄尋找檔案或目錄,dest 為映象中的絕對路徑或者相對於 WORKDIR 的路徑

CMD:構建容器後呼叫,也就是在容器啟動時才進行呼叫

#格式:
CMD ["executable","param1","param2"] (執行可執行檔案,優先)
CMD ["param1","param2"] (設定了 ENTRYPOINT,則直接呼叫 ENTRYPOINT 新增引數)
CMD command param1 param2 (執行 shell 內部命令)

#示例:
CMD echo "This is a test." | wc -
CMD ["/usr/bin/wc","--help"]注: CMD 不同於 RUN,CMD 用於指定在容器啟動時所要執行的命令,而 RUN 用於指定映象構建時所要執行的命令。

LABEL:用於為映象新增後設資料

格式:
LABEL <key>=<value> <key>=<value> <key>=<value> ... 

示例:
LABEL version="1.0" description="這是一個 Web 伺服器" by="IT 筆錄" 

注:
使用 LABEL 指定後設資料時,一條 LABEL 指定可以指定一或多條後設資料,指定多條後設資料時不同後設資料之間通過空格分隔。推薦將所有的後設資料通過一條 LABEL 指令指定,以免生成過多的中間映象。

ENV:設定環境變數

格式:
ENV <key> <value> #<key>之後的所有內容均會被視為其<value>的組成部分,因此,一次只能設定一個變數
ENV <key>=<value> ... #可以設定多個變數,每個變數為一個"<key>=<value>"的鍵值對,如果<key>中包含空格,可以使用\來進行轉義,也可以通過""來進行標示;另外,反斜線也可以用於續行

示例:
ENV myName John Doe
ENV myDog Rex The Dog
ENV myCat=fluffy

EXPOSE:指定於外界互動的埠

格式:
EXPOSE <port> [<port>...]

示例:
EXPOSE 80 443
EXPOSE 8080
EXPOSE 11211/tcp 11211/udp

注:
EXPOSE 並不會讓容器的埠訪問到主機。要使其可訪問,需要在 docker run 執行容器時通過-p 來發布這些埠,或通過-P 引數來發布 EXPOSE 匯出的所有埠

VOLUME:用於指定持久化目錄

格式:
VOLUME ["/path/to/dir"]

示例:
VOLUME ["/data"]
VOLUME ["/var/www", "/var/log/apache2", "/etc/apache2"]

注: 
一個卷可以存在於一個或多個容器的指定目錄,該目錄可以繞過聯合檔案系統,並具有以下功能:
1 卷可以容器間共享和重用
2 容器並不一定要和其它容器共享卷
3 修改卷後會立即生效
4 對卷的修改不會對映象產生影響
5 卷會一直存在,直到沒有任何容器在使用它

WORKDIR:工作目錄,類似於 cd 命令

格式:
WORKDIR /path/to/workdir

示例:
WORKDIR /a (這時工作目錄為/a)
WORKDIR b (這時工作目錄為/a/b)
WORKDIR c (這時工作目錄為/a/b/c)

注:
通過 WORKDIR 設定工作目錄後,Dockerfile 中其後的命令 RUN、CMD、ENTRYPOINT、ADD、COPY
等命令都會在該目錄下執行。在使用 docker run 執行容器時,可以通過-w 引數覆蓋構建時所設定的工作目錄。

ARG:用於指定傳遞給構建執行時的變數

格式:
ARG <name>[=<default value>]

示例:
ARG site
ARG build_user=www

ONBUILD:用於設定映象觸發器

格式: 
ONBUILD [INSTRUCTION]

示例:
ONBUILD ADD . /app/src
ONBUILD RUN /usr/local/bin/python-build --dir /app/src

注:
當所構建的映象被用做其它映象的基礎映象,該映象中的觸發器將會被鑰觸發

Dockerfile 構建映象案例

FROM centos7
MAINTAINER Alvin alvincy@qq.com
RUN mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.backup
RUN curl -o /etc/yum.repos.d/CentOS-Base.repo
http://mirrors.aliyun.com/repo/Centos-7.repo
RUN yum makecache
RUN yum update -y
RUN yum install python3 -y
RUN pip3 install django
COPY docker /root/docker
WORKDIR /root/docker
EXPOSE 8080
CMD ["python3", "manage.py", "runserver", "0.0.0.0:8080"]

相關文章