話先說在前頭,本文只對Vault整合Hyperledger Besu區(qū)塊鏈(以下簡稱“besu”)部署進(jìn)行說明,并不推薦使用Vault服務(wù)(原因下面會說)。Vault的主要作用在于系統(tǒng)化存儲用戶信息并配合EthSinger實現(xiàn)個人權(quán)證簽署。
besu關(guān)于密鑰存儲提供了線上和線下兩種存儲方案,當(dāng)初為了方便擴(kuò)展選擇了使用Vault的KV模式存儲方案。首先先下載Docker鏡像:
docker pull vault:1.11.0
在鏡像下載的時候可以先在服務(wù)器中先建好目錄。由于Vault需要為EthSinger提供服務(wù),為了避免網(wǎng)絡(luò)開銷將Vault部署在node203服務(wù)器上(服務(wù)器詳情可以查看《【區(qū)塊鏈】HyperLedger Besu Docker異地組網(wǎng)》一文)。區(qū)塊鏈的根目錄為:/home/yzh/Documents/blockchain/,在此基礎(chǔ)上建立Vault目錄及其下屬目錄config、file和logs:
# 切換目錄
cd /home/yzh/Documents/blockchain/
# 創(chuàng)建vault目錄
mkdir vault
# 切換至vault目錄內(nèi)部
cd vault
# 創(chuàng)建額外目錄
mkdir config file logs
之后就可以創(chuàng)建docker-compose文件。為了區(qū)分區(qū)塊鏈構(gòu)建所需的多個docker-compose文件,因此將文件名改為了vault-compose.yml,內(nèi)容如下:
version: '3'
services:
vault:
image: vault:1.11.0
volumes:
- /home/yzh/Documents/blockchain/vault/config:/vault/config:rw
- /home/yzh/Documents/blockchain/vault/file:/vault/file:rw
- /home/yzh/Documents/blockchain/vault/logs:/vault/logs:rw
cap_add:
- IPC_LOCK
command: vault server -config=/vault/config/config.json
restart: always
networks:
besu_bridge:
ipv4_address: 192.20.0.3
ports:
- 8200:8200
environment:
- VAULT_ADDR=http://0.0.0.0:8200
- VAULT_API_ADDR=http://0.0.0.0:8200
- VAULT_ADDRESS=http://0.0.0.0:8200
networks:
besu_bridge:
ipam:
config:
- subnet: 192.20.0.0/24
注意:若在生產(chǎn)環(huán)境使用時需要對內(nèi)存進(jìn)行鎖定需要cap_add參數(shù)進(jìn)行鎖定操作,而command參數(shù)則是啟動Vault是需要讀取的配置文件指向。
由于Vault官方鏡像不能使用Docker Swarm網(wǎng)絡(luò)(通過docker stack deploy部署時會提示cap_add參數(shù)無效),為了能夠有一個固定的ip這里需要創(chuàng)建一個新的橋接網(wǎng)絡(luò)vault_besu_bridge網(wǎng)段為192.20.0.x,分配給Vault的ip為192.20.0.3。
root@node203:/home/yzh/Documents/blockchain/vault# docker network ls
NETWORK ID NAME DRIVER SCOPE
z2w4r5fo1588 besu_swarm overlay swarm
f5a6b27119ef bridge bridge local
e1902557eda0 docker_gwbridge bridge local
c5ad4fc3d434 host host local
u5vjecempood ingress overlay swarm
f96d226b8f69 none null local
75f6834bc0cf prometheus_default bridge local
e0696cd11fd1 vault_besu_bridge bridge local
接下來就可以通過語句啟動服務(wù):
docker-compose -f vault-compose.yml up -d
差點忘了/vault/config/config.json的配置信息了,這里指定了8200端口與UI界面啟動的配置信息,如下所示:
{
"backend": {
"file": {
"path": "/vault/file"
}
},
"listener": {
"tcp": {
"address": "0.0.0.0:8200",
"tls_disable": "true"
}
},
"default_lease_ttl": "168h",
"max_lease_ttl": "720h",
"ui": true
}
服務(wù)啟動后我們就通過http://192.168.200.203:8200/ui/vault/init來訪問看看能否被訪問到。如下圖:
在第一次打開的時候會被要求初始化系統(tǒng)賬號與Token。其中Key shares指的是密鑰拆分的份數(shù),Key threshold指的是重建密鑰所需要的拆分份數(shù)。
為了提高安全性,這里Key shares填了6,Key threshold填了5。在第二個界面就能夠看到這6個拆分的密鑰的具體內(nèi)容,如下圖:
還好,在頁面的右下方有下載這個密鑰文件的功能直接下載就好,就不用一個一個拷貝了。下載下來的密鑰文件一定要放在一個安全的地方(因為這個文件非常重要),我就放在的/home/yzh/Documents/blockchain/vault/config目錄下,如下所示:
root@node203:/home/yzh/Documents/blockchain/vault/config# ls
config.json vault-cluster-vault.json
第三個界面需要輸入剛剛生成的密鑰進(jìn)行驗證,如下圖:
這個密鑰在哪里得到的呢?其實就是剛剛vault-cluster-vault.json文件中的key的內(nèi)容,如下所示:
{
"keys": [
"c5a89558d279df58a795f2aac27822559c3a182d4c79300023633b9c345d1ef88c",
"a68093fb278f02863a3ae94b3acb73e3953ac673fe600152d7a83b21dafb0e5613",
"e81539da0674f65018c032994ff8d3ebd5a21dfffd35b9885a91326ca1a78e4f03",
"f9ec8165d6a15f41281c846b9cecbb20faaf33e85863b02befa54162aaae4a957b",
"7d2359085317a5c21497d545cc534e933931ad800796a4d328463452671a79764c",
"a9f85512697ba721973dc8d95d1af1f3353e2c0e5197cc1098af4e7d63352056c7"
],
"keys_base64": [
"xaiVWNJ531inlfKqwngiVZw6GC1MeTAAI2M7nDRdHviM",
"poCT+yePAoY6OulLOstz45U6xnP+YAFS16g7Idr7DlYT",
"6BU52gZ09lAYwDKZT/jT69WiHf/9NbmIWpEybKGnjk8D",
"+eyBZdahX0EoHIRrnOy7IPqvM+hYY7Ar76VBYqquSpV7",
"fSNZCFMXpcIUl9VFzFNOkzkxrYAHlqTTKEY0UmcaeXZM",
"qfhVEml7pyGXPcjZXRrx8zU+LA5Rl8wQmK9OfWM1IFbH"
],
"root_token": "hvs.PeIrFgZ1Q5Gjs3sbKjijEYiO"
}
將這里面key的內(nèi)容一個一個拷貝過去驗證就可以了,驗證完成后就可以登錄vault了。如下圖:
在登錄頁面需要輸入token信息,這個token信息也是vault-cluster-vault.json文件中root_token對應(yīng)的內(nèi)容,登錄后看到的界面如下圖:
系統(tǒng)會默認(rèn)有一個名為cubbyhole的秘密引擎,但是后面用到的EthSinger用到的是kv引擎所以這個并不適用,需要重新創(chuàng)建一個kv引擎。
選擇創(chuàng)建新秘密引擎
創(chuàng)建一個kv類型的秘密引擎
創(chuàng)建一個名為vault的kv引擎
這樣就完成了創(chuàng)建,在這里暫無需創(chuàng)建秘密,這個留給后面ethsigner就可以了,至此vault的部署就完畢了。
Vault 帶有各種稱為秘密引擎和身份驗證方法的可插入組件,它允許與外部系統(tǒng)集成。這些組件的目的是管理和保護(hù)您在動態(tài)基礎(chǔ)設(shè)施中的秘密(例如數(shù)據(jù)庫憑證、密碼、API 密鑰)。所以其實可以用這個東西去跟業(yè)務(wù)系統(tǒng)做繼承使用的,而在Java Spring中也的確有成熟的繼承方案。如下圖:
但由于一些不能描述的原因,中國公民或企業(yè)是否能夠?qū)?shù)據(jù)全量托管到Hashicorp這家美國企業(yè)提供的云服務(wù)上是值得商榷的,因涉及到安全性的問題我最終還是放棄了這個方案。
容器鏡像是容器的模板,容器是鏡像的運行實例, runtime根據(jù)容器鏡像創(chuàng)建容器;容器鏡像掛載在容器根目錄下,是為容器中的應(yīng)用提供隔離后執(zhí)行環(huán)境的文件系統(tǒng)。
我們希望能提供一個基本的操作系統(tǒng)環(huán)境,用戶可以根據(jù)需要安裝和配置軟件,這樣的鏡像我們稱作base鏡像;能稱作base鏡像的通常都是各種Linux發(fā)行版的Docker鏡像,比如 Ubuntu、Debian、CentOS等,其他鏡像可以以之為基礎(chǔ)進(jìn)行擴(kuò)展。
注:base鏡像從scratch構(gòu)建,不依賴于其他鏡像;scratch是Docker官方提供的一個空鏡像。
Linux內(nèi)核空間和用戶空間
①、實現(xiàn)機(jī)制:
Ⅰ. Linux操作系統(tǒng)由內(nèi)核空間和用戶空間組成,其中內(nèi)核空間是kernel, Linux在剛啟動時會加載bootfs文件系統(tǒng),啟動完成之后bootfs會被卸載掉;用戶空間的文件系統(tǒng)是rootfs, 包含/dev、/proc等目錄。不同Linux發(fā)行版的區(qū)別主要就是rootfs,所以可以在同一臺host上部署不同Linux發(fā)行版的base鏡像。
Ⅱ. 對于base鏡像來說,底層直接用Host的kernel, 自己只需要提供rootfs就行了(即打包應(yīng)用及其運行所需要的所有依賴包),所以相對于虛擬機(jī)來說更加輕便。
注:base鏡像在用戶空間與發(fā)行版一致,但是內(nèi)核的版本和Docker host主機(jī)的kernel版本一致;容器只能使用host的kernel,但是不能修改。
Docker支持通過擴(kuò)展現(xiàn)有鏡像來創(chuàng)建新的鏡像,也就是說所有鏡像層聯(lián)合在一起,即為一個聯(lián)合文件系統(tǒng),這類文件系統(tǒng)會把多個目錄(可能對應(yīng)不同的文件系統(tǒng))掛載到同一個目錄,對外呈現(xiàn)這些目錄的聯(lián)合,也就是說用戶在容器層中只能看到最上層的文件,最終呈現(xiàn)出一個分層的結(jié)構(gòu);
注:聯(lián)合文件系統(tǒng)UnionFS將所有的鏡像層聯(lián)合掛載到一個統(tǒng)一的掛載點(鏡像層文件系統(tǒng)中不同的目錄進(jìn)行“合并”),最終表現(xiàn)為一個Linux操作系統(tǒng)供容器使用。
可以最大化實現(xiàn)資源共享:當(dāng)多個鏡像都是從同一個base鏡像構(gòu)建而來,內(nèi)存中只需加載一份base 鏡像,就可以為所有容器服務(wù);通過寫前拷貝COW技術(shù)來實現(xiàn)資源共享。
原理簡單闡述就好比:當(dāng)父進(jìn)程 fork 子進(jìn)程時,內(nèi)核并沒有為子進(jìn)程分配內(nèi)存(當(dāng)然基本的進(jìn)程控制塊、堆棧還是需要的),而是讓父子進(jìn)程共享內(nèi)存;當(dāng)兩者之一修改共享內(nèi)存時,會觸發(fā)一次缺頁異常導(dǎo)致真正的內(nèi)存分配(此時才會為父子進(jìn)程分配獨享內(nèi)存)。
聯(lián)合文件系統(tǒng)架構(gòu)
1、聯(lián)合文件系統(tǒng)實現(xiàn)機(jī)制:
①、首先需要內(nèi)核支持OverlayFS特性;
$ cat /proc/filesystems | grep overlay nodev overlay
②、創(chuàng)建分層的工作目錄(相當(dāng)于除了容器層以外的其他層);
$ mkdir base
$ echo "layer 1" > base/metadata
$ echo "hello,docker!" > base/data
$ mkdir overlay
$ echo "layer 2" > overlay/metadata
$ echo "hello,k8s!" > overlay/data2
③、創(chuàng)建頂層目錄(相當(dāng)于容器層),以及OverlayFS所必需的work工作目錄、文件系統(tǒng)掛點;
$ mkdir top work point
④、將分層以overlay文件系統(tǒng)類型掛載到掛載點;
$ mount -t overlay overlay \ -o lowerdir=overlay:base,upperdir=top,workdir=work point
#-t:指定文件系統(tǒng)類型
#-o:指定掛載選項,lowerdir指定底層目錄(從高層向低層指定),upperdir指定頂層目錄 (也就是容器層),workdir指定工作目錄
#最后指定掛載點
⑤、在掛載點目錄下可以看到聯(lián)合目錄,目錄所處的層級是很重要的,上層的文件會覆蓋同名的下層文件;
#可以看到掛載點處顯示出的聯(lián)合目錄
$ ll */*
-rw-r--r-- 1 root root 14 ... base/data
-rw-r--r-- 1 root root 10 ... base/metadata
-rw-r--r-- 1 root root 11 ... overlay/data2
-rw-r--r-- 1 root root 10 ... overlay/metadata
-rw-r--r-- 1 root root 14 ... point/data
-rw-r--r-- 1 root root 11 ... point/data2
-rw-r--r-- 1 root root 10 ... point/metadata
#查看具有同名的上下層文件metadata
$ cat point/metadata
layer 2
#內(nèi)容為overlay層的metadata文件內(nèi)容,而base層的metadata文件內(nèi)容被覆蓋
⑥、當(dāng)容器啟動時,一個新的可寫層被加載到鏡像的頂部,這一層通常被稱作“容器層","容器層”之下的都叫“鏡像層”,只有容器層是可寫的,容器層下面的所有鏡像層都是只讀的;修改文件時同理,當(dāng)在容器中修改已存在的文件時,Docker會從上往下依次在各鏡像層中查找此文件,一旦找到,立即將其復(fù)制到容器層(top層),然后再修改;
此處僅做目錄模擬,所以其他鏡像層仍是可以寫的。
#當(dāng)向point目錄中寫入數(shù)據(jù)時,會寫入到top目錄(頂層目錄)中
$ echo "top layer" > point/frame
$ ll */*
...
-rw-r--r-- 1 root root 10 ... point/frame
-rw-r--r-- 1 root root 10 ... top/frame
$ cat top/frame #查看容器層寫入的文件內(nèi)容,即為寫入到掛載點同名文件中的內(nèi)容
top layer
#修改point/data文件內(nèi)容
$ cat point/data
hello,docker!
test modify
#然后會在top頂層目錄中新增一個同名文件,內(nèi)容即為修改后的內(nèi)容
$ ll */*
...
-rw-r--r-- 1 root root 10 ... top/data
$ cat top/data
hello,docker!
test modify
#查看底層base/data文件,發(fā)現(xiàn)內(nèi)容并未改變
$ cat base/data
hello,docker!
⑦、當(dāng)在容器中刪除文件時, Docker 也是從上往下依次在鏡像層中查找此文件。找到后,UnionFS會在容器層創(chuàng)建一個"whiteout"文件將被刪除的文件進(jìn)行遮擋,并且在容器層會創(chuàng)建一個同名的、主次設(shè)備號均為0的字符設(shè)備,文件不會被刪除(空間不一定會被回收);如果制作 image 時使用到了一些關(guān)鍵的信息(用戶名、密碼等),則需要在所在層刪除,不然這些信息依然會存在于 image 中。
c--------- 1 root root 0, 0 ... top/data
?、安裝docker-ce:以Centos系統(tǒng)為例,首先要獲取docker-ce的yum源,此處使用的是華為云提供的repo;然后安裝docker-ce
$ wget -O /etc/yum.repos.d/docker-ce.repo \ https://repo.huaweicloud.com/docker-ce/linux/centos/docker-ce.repo
$ sudo sed -i 's+download.docker.com+repo.huaweicloud.com/docker-ce+' \ /etc/yum.repos.d/docker-ce.repo #修改獲取鏡像的地址
#如果是Centos8版本的系統(tǒng),則可以參照之前的《00:先讓Docker跑起來》文章。
?、配置Docker鏡像加速器:如果使用公共鏡像倉庫,由于是在國外網(wǎng)速限制,須要通過鏡像加速站來獲取鏡像,以下以華為云平臺鏡像加速站配置為例(需提前注冊華為云賬號,并在控制臺中找到容器鏡像服務(wù))
當(dāng)鏡像倉庫使用"https",使用時則需要先進(jìn)行登錄驗證,然后才能從鏡像倉庫拉取鏡像;當(dāng)鏡像倉庫使用"http"(或私有鏡像倉庫,直接使用IP地址),則不需要,可以直接拉取使用。
$ vim /etc/docker/daemon.json #如果該文件沒有,則需要手動創(chuàng)建
{
"registry-mirrors": ["https://******.myhuaweicloud.com"]
}
$ systemctl daemon-reload #重新加載daemon服務(wù)器配置文件
$ systemctl restart docker.service
?、首先須要登錄獲取訪問權(quán)限,u是用戶,p是密碼(在個人控制臺自動生成)
$ docker login -u *** -p *** swr.cn-north-1.myhuaweicloud.com
?、拉取鏡像
$ docker pull httpd:2.4
2.4: Pulling from library/httpd
...Pull complete
Status: Downloaded newer image for httpd:2.4
$ docker image list
REPOSITORY TAG IMAGE ID CREATED SIZE
httpd 2.4 683a7aad17d3 2 months ago 138MB
可以使用dockerviz工具來分析Docker image。
1、首先將dockviz.tar包(從百度網(wǎng)盤中下載)上傳到鏡像倉庫;
鏈接:https://pan.baidu.com/s/1C318yk45Mnh0jjyiC1hE3g
提取碼:rc5r
$ docker load -i dockviz.tar
2、然后在 /etc/bashrc文件中最后一行添加命令別名,保證每次執(zhí)行dockviz命令時都會臨時運行一個dockerviz的容器來執(zhí)行相應(yīng)的動作;(退出重新登錄后生效)
$ alias dockviz="docker run --rm -v /var/run/docker.sock:/var/run/docker.sock dockviz:latest"
3、執(zhí)行以下命令,讓鏡像文件以分層的形式保存在images.png圖片中
#將所有的鏡像信息以png的格式保存到images.png文件中
$ dockviz images -d | dot -Tpng -o images.png #最后可以下載到Windows本地查看圖片
Docker提供了兩種構(gòu)建鏡像的方法:docker commit命令與Dockerfile構(gòu)建文件
docker commit,實際上是在容器運行起來后,把最上層的“可讀寫層”,加上原先容器鏡像的只讀層,打包組成了一個新的鏡像;一般包含三個步驟:運行容器;修改容器;將容器保存為新的鏡像,過程更加直觀。
注:Docker并不建議用戶通過這種方式構(gòu)建鏡像,原因是無法對鏡像進(jìn)行審計,存在安全隱患。
實現(xiàn)步驟:使用commit命令構(gòu)建鏡像
?、運行一個Centos 7 的base鏡像;
$ docker run -it centos:7
# -it表示以交互的方式運行容器,并進(jìn)入到容器
Unable to find image 'centos:7' locally #由于已登錄到華為云,將從huaweicloud.com拉取鏡像
...: Pull complete
?、在base鏡像中安裝軟件,并退出;
$ vim bash: vim: command not found
#base鏡像中沒有安裝vim工具
$ yum install vim -y #使用yum安裝vim工具
... Complete!
$ rpm -qa | grep vim #檢查已正常安裝vim工具
vim-common...
$ exit
?、使用commit命令將修改后的centos7容器封裝成一個名為my_iamge的鏡像。
$ docker ps -a
CONTAINER ID IMAGE ... NAMES
ff9a563e9fd8 centos:7 ... vibrant_sammet
$ docker commit vibrant_sammet my_image #直接將容器commit成名為my_image的鏡像
$ docker image list
REPOSITORY TAG IMAGE ID CREATED SIZE
my_image latest cfdce8636c33 39 seconds ago 366MB
centos 7 8652b9f0cb4c 4 months ago 204MB
?、驗證:可以看到my_image鏡像比centos:7鏡像多了一層鏡像
# docker history指令會顯示鏡像的分層結(jié)構(gòu),并且按照鏡像層的順序由上至下排列
$ docker history centos:7
IMAGE CREATED BY SIZE
8652b9f0cb4c /bin/sh -c #(nop) CMD ["/bin/bash"] 0B
<missing> /bin/sh -c #(nop) LABEL org.label-schema.sc… 0B
<missing> /bin/sh -c #(nop) ADD file:b3ebbe8bd304723d4… 204MB
$ docker history my_image:latest
IMAGE CREATED BY SIZE
cfdce8636c33 /bin/bash 162MB #安裝了vim編輯器
8652b9f0cb4c /bin/sh -c #(nop) CMD ["/bin/bash"] 0B
<missing> /bin/sh -c #(nop) LABEL org.label-schema.sc… 0B
<missing> /bin/sh -c #(nop) ADD file:b3ebbe8bd304723d4… 204MB
dockerfile是一個文本文件,記錄著鏡像構(gòu)建的所有步驟,但是底層也是使用docker commit 一層一層構(gòu)建的,
①、dockerfile構(gòu)建鏡像原理:
Ⅰ. 從base 鏡像運行一個容器;
Ⅱ. 執(zhí)行一條指令,對容器做修改;
Ⅲ. 執(zhí)行類似docker commit 的操作,生成一個新的鏡像層;
Ⅳ. Docker 再基于剛剛提交的鏡像運行一個新容器(原容器會被刪除);
Ⅴ . 重復(fù) Ⅱ~Ⅳ 步,直到Dockerfile 中的所有指令執(zhí)行完畢。
②、根據(jù)下表字段創(chuàng)建一個dockerfile文件;當(dāng)使用build指令時,需要指定某個目錄為build context,build context 為鏡像構(gòu)建提供所需要的文件或目錄;Docker默認(rèn)會從build context 中查找Dockerfile文件,所以不要將不期望存在的文件放到build context目錄下。
Dockerfile常用指令
③、RUN、CMD、ENTRYPOINT區(qū)別
RUN、CMD和ENTRYPOINT都是用來運行命令的,命令執(zhí)行格式可以分為shell和Exec兩種:
shell:直接調(diào)用底層的shell(如 /bin/bash)來執(zhí)行命令,其格式為
RUN/CMD/ENTRYPOINT <command>
ENV name Cloud #指定環(huán)境變量name的值為 Cloud
ENTRYPOINT echo "Hello, $name" #啟動容器后輸出即為 Hello,Cloud
Exec:直接調(diào)用 [command],但是不會被底層的shell解析,其格式為
RUN/CMD/ENTRYPOINT ["executable", "paraml", "param2", ...]
ENV name Cloud #指定環(huán)境變量name的值為 Cloud
ENTRYPOINT ["/bin/echo","Hello,$name"] #啟動容器后輸出即為 Hello,$name
? RUN:指令通常用于給容器安裝應(yīng)用和軟件包;Dockerfile中常常包含多個RUN指令,在當(dāng)前鏡像的頂部執(zhí)行命令,完成一條RUN指令之后就會創(chuàng)建新的鏡像層,也就是說不同的RUN指令代表了不同的鏡像層。
? CMD:指令允許用戶指定容器的默認(rèn)執(zhí)行的命令,因為容器是為應(yīng)用而生的,啟動容器最終目的是啟動應(yīng)用(或者是執(zhí)行一個循環(huán)語句)以避免容器啟動后無應(yīng)用而退出(狀態(tài)為exited),在容器啟動且docker run沒有指定其他命令時運行
注:如果docker run指定了其他命令,CMD指定的默認(rèn)命令將被忽略;如果Dockerfile中有多個CMD指令,只有最后一個CMD有效。
? ENTRYPOINT:指令可讓容器以應(yīng)用程序或者服務(wù)的形式運行,和CMD不同的地方在于ENTRYPOINT 不會被忽略,一定會被執(zhí)行,即使運行 docker run 時指定了其他命令。
④、實現(xiàn)步驟:使用Dockerfile構(gòu)建鏡像
?、構(gòu)建前需要準(zhǔn)備build context目錄、準(zhǔn)備好base鏡像
$ pwd #新建一個dockerfile目錄作為build context
/root/dockerfile
$ ls #目錄下保存base鏡像,dockerfile文件以及需要的file2
CentOS-7-x86_64-docker.img.tar.xz dockerfile file2
?、寫一個dockerfile文件
注:可以從一個空鏡像開始,也可以從base鏡像開始,如果從空鏡像開始,必須指定進(jìn)入到容器之后的shell,如Centos系統(tǒng)是bash shell
$ vim dockerfile
FROM scratch #指定從一個空鏡像開始
MAINTAINER KnockCloud #指定鏡像作者
ADD CentOS-7-x86_64-docker.img.tar.xz / #添加一個Centos系統(tǒng)的base鏡像
CMD ["/bin/bash"] #必須指定進(jìn)入到容器之后使用的shell
WORKDIR /testdir #用于指定進(jìn)入到容器之后的目錄(如果沒有會創(chuàng)建)
RUN touch file1 COPY file2 . #將file2拷貝到容器的 /testdir 目錄下,注意file2文件必須提前在docker context中存在
ENV WELCOME "You are in my container,welcome!"
?、使用dockerfile創(chuàng)建一個名為first-dockerfile的鏡像
#這里的"."表示dockerfile所在的目錄,在本實驗中是當(dāng)前目錄
$ docker build -t first-dockerfile . #docker會將build context中的文件發(fā)送給docker daemon
Sending build context to Docker daemon 36.29MB
Step 1/8 : FROM scratch #從一個空鏡像開始
--->
Step 2/8 : MAINTAINER Docker
---> Running in b9617c3257db Removing intermediate container b9617c3257db
---> db4a3a49178d
#添加一個Centos系統(tǒng)的base鏡像到容器的根目錄下
Step 3/8 : ADD CentOS-7-x86_64-docker.img.tar.xz /
---> 5ed7df8f5c30
#指定進(jìn)入到容器之后使用bash shell(必須指定)
Step 4/8 : CMD ["/bin/bash"]
---> Running in d5bc15e94c2c Removing intermediate container d5bc15e94c2c
---> 7695f1da0b99
Step 5/8 : WORKDIR /testdir #指定進(jìn)入容器之后的工作目錄
---> Running in 02bf878461a7 Removing intermediate container 02bf878461a7
---> 8bee16518a33
Step 6/8 : RUN touch file1
---> Running in 12b2f04b31ed Removing intermediate container 12b2f04b31ed
---> abdb9cbd61c7
Step 7/8 : COPY file2 . #這里的"."表示上面指定的工作目錄
---> 2d32516ab12f
Step 8/8 : ENV WELCOME "You are in my container,welcome!"
---> Running in 6e6857f7ad1b Removing intermediate container 6e6857f7ad1b
---> 29e652e510d5 Successfully built 29e652e510d5
Successfully tagged first-dockerfile:latest
?、驗證結(jié)果
$ docker run -it first-dockerfile
bash-4.2# pwd #查看進(jìn)入容器之后的工作目錄
/testdir
bash-4.2# ls #查看工作目錄下的文件
file1 file2
bash-4.2# cat file2 #從docker context拷貝過來的file2文件
It's worked!
bash-4.2# echo $WELCOME #設(shè)置的變量值
You are in my container,welcome!
可以使用docker tag給鏡像重命名,實際上一個特定鏡像的名字由兩部分組成: repository 和 tag ;tag常用于描述鏡像的版本信息,如果執(zhí)行 docker build 時沒有指定 tag, 會使用默認(rèn)值 latest
鏡像命名格式為:[image name]=[repository]: [tag]
注:repository 的完整格式為:[registry-host]: [port]/[namespace]/httpd,只有使用公共Registry且已經(jīng)登錄的時候,registry-host:[port]/[namespace]才可以省略。
①、啟動Registry容器,然后將其映射到主機(jī)的5000端口,鏡像存儲位置映射到主機(jī)本地目錄;
$ docker run -d -p 5000:5000 \ #指定端口映射,將主機(jī)端口映射給容器(網(wǎng)絡(luò)章節(jié)會詳解)
-v /myregistry:/var/lib/registry \ #指定存儲位置映射(存儲章節(jié)會詳解)
registry:2.7
...Pull complete .
②、修改daemon.json文件中的鏡像倉庫地址,如果地址是私有倉庫的地址,應(yīng)按照registry-host:[port]的格式修改地址
#設(shè)置以非安全模式(即非HTTPS)連接到本倉庫
$ cat /etc/docker/daemon.json
{
"insecure-registries": ["192.168.1.11:5000"] #本機(jī)地址:映射端口號
}
③、通過 docker tag 重命名鏡像,使之與registry相匹配
#username可以任意但不能包含大寫字母
$ docker tag httpd:2.4 192.168.1.11:5000/docker/httpd:2.4
④、通過 docker push 上傳鏡像
$ docker push 192.168.1.11:5000/docker/httpd:2.4
The push refers to repository [192.168.1.11:5000/docker/httpd]
...
Pushed
$ pwd /myregistry/docker/registry/v2/repositories
$ ls #鏡像文件保存在本地指定的用戶文件夾里 docker
⑤、驗證,嘗試從私有鏡像倉庫拉取鏡像
注:拉取鏡像時必須指定鏡像倉庫和用戶名,不然就會到docker官方網(wǎng)站上去拉取了
#到私有鏡像倉庫拉取鏡像時要補(bǔ)全鏡像的tag
$ docker pull 192.168.1.11:5000/docker/httpd:2.4
2.4: Pulling from docker/httpd Digest: sha256:88fb0fb4b406f944e220f082b5a56d1f0e8471abc45fd...
Status: Downloaded newer image for 192.168.1.11:5000/docker/httpd:2.4
192.168.1.11:5000/docker/httpd:2.4
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
192.168.1.11:5000/docker/httpd 2.4 683a7aad17d3 2 months ago 138MB
docker rmi :用于刪除host上的鏡像,如果容器正在使用,那么就必須先刪除容器,然后才能刪除鏡像。
docker search:可以無須打開瀏覽器,在命令行中就可以搜索公共Registry中的鏡像,可以根據(jù)不同的tag來拉取鏡像。
docker save:將某個鏡像保存為tar包,命令格式為:
docker save <IMAGE_NAME> -o <TAR_NAME>
docker load:將鏡像tar包加載為鏡像,格式為:
docker load -i <TAR_NAME>