Docker及Kubernetes常用命令操作
一、文件簡介
作者:lanjiaxuan
部落格地址:https://www.cnblogs.com/lanheader/
更新時間:2021-07-09
Docker 簡介
Docker 是一種運行於 Linux 和 Windows 上的軟體,用於建立、管理和編排容器。
Docker的基本組成
-
Docker Client客戶端
Docker是C/S架構的程式,docker的客戶端向伺服器端(也就是Docker的守護程序)發出請求,守護程序處理完所有的工作並返回結果;docker客戶端向伺服器端的訪問既可以在本地也可以通過遠端來訪問;
-
Docker Daemon 守護程序
-
Docker Image 映象
映象是docker容器的基石,容器基於映象啟動和執行,映象好比容器的原始碼,儲存了啟動容器的各種條件
-
Docker Container 容器
容器通過映象來啟動,docker的容器是docker執行單元,容器中可以執行客戶的一個或者多個程序,如果說映象是docker生命週期中的構建和打包階段,那麼容器就是啟動和執行階段;
-
Docker Registry 倉庫
docker用倉庫來儲存使用者構建的物件,分為公有和私有,Docker公司自己提供了一個公有的,叫Docker Hub
Docker 安裝
linux 安裝
指令碼安裝
$ wget -qO- https://get.docker.com/ | sh
yum安裝
$ sudo yum install -y yum-utils device-mapper-persistent-data lvm2
$ sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
$ sudo yum list docker-ce --showduplicates | sort -r
$ sudo yum install docker-ce
Docker命令
Docker容器生命週期管理
docker run :建立一個新的容器並執行一個命令
語法
$ docker run [OPTIONS] IMAGE [COMMAND] [ARG...]
OPTIONS說明:
-a stdin: 指定標準輸入輸出內容型別,可選 STDIN/STDOUT/STDERR 三項;
- -d: 後臺執行容器,並返回容器ID;
- -i: 以互動模式執行容器,通常與 -t 同時使用;
- -P: 隨機埠對映,容器內部埠隨機對映到主機的埠
- -p: 指定埠對映,格式為:主機(宿主)埠:容器埠
- -t: 為容器重新分配一個偽輸入終端,通常與 -i 同時使用;
- --name="nginx-lb": 為容器指定一個名稱;
- --dns 8.8.8.8: 指定容器使用的DNS伺服器,預設和宿主一致;
- --dns-search example.com: 指定容器DNS搜尋域名,預設和宿主一致;
- -h "mars": 指定容器的hostname;
- -e username="ritchie": 設定環境變數;
- --env-file=[]: 從指定檔案讀入環境變數;
- --cpuset="0-2" or --cpuset="0,1,2": 繫結容器到指定CPU執行;
- -m :設定容器使用記憶體最大值;
- --net="bridge": 指定容器的網路連線型別,支援 bridge/host/none/container: 四種類型;
- --link=[]: 新增連結到另一個容器;
- --expose=[]: 開放一個埠或一組埠;
- --volume , -v: 繫結一個卷
示例
# 使用Docker映象nginx:latest以後臺模式啟動一個容器,並將容器命名為mynginx。
$ docker run --name mynginx -d nginx:latest
# 使用映象nginx:latest以後臺模式啟動一個容器,並將容器的80埠對映到主機隨機埠。(這裡是P是大寫)
$ docker run -P -d nginx:latest
# 使用映象 nginx:latest,以後臺模式啟動一個容器,將容器的 80 埠對映到主機的 80 埠,主機的目錄 /data 對映到容器的 /data。
$ docker run -p 80:80 -v /data/docker_data:/data -d nginx:latest
# 繫結容器的 8080 埠,並將其對映到本地主機 127.0.0.1 的 80 埠上。
$ docker run -p 127.0.0.1:80:8080/tcp ubuntu bash
# 使用映象nginx:latest以互動模式啟動一個容器,在容器內執行/bin/bash命令。
$ docker run -it nginx:latest /bin/bash
docker start/stop/restart
docker start :啟動一個或多個已經被停止的容器
docker stop :停止一個執行中的容器
docker restart :重啟容器
語法
$ docker start [OPTIONS] CONTAINER [CONTAINER...]
$ docker stop [OPTIONS] CONTAINER [CONTAINER...]
$ docker restart [OPTIONS] CONTAINER [CONTAINER...]
示例
# 啟動已被停止的容器
$ docker start mynginx
# 停止執行中的容器myrunoob
$ docker stop mynginx
# 重啟容器myrunoob
$ docker restart mynginx
docker kill :殺掉一個執行中的容器。
語法
$ docker kill [OPTIONS] CONTAINER [CONTAINER...]
OPTIONS說明:
- -s :向容器傳送一個訊號
示例
# 殺掉執行中的容器mynginx
$ docker kill -s KILL mynginx
mynginx
docker rm :刪除一個或多個容器。
語法
$ docker rm [OPTIONS] CONTAINER [CONTAINER...]
OPTIONS說明:
- -f :通過 SIGKILL 訊號強制刪除一個執行中的容器。
- -l :移除容器間的網路連線,而非容器本身。
- -v :刪除與容器關聯的卷。
示例
# 強制刪除容器 mynginx:
$ docker rm -f mynginx nginxdemo
# 刪除容器 nginx01, 並刪除容器掛載的資料卷:
$ docker rm -v nginx01
# 刪除所有已經停止的容器:
$ docker rm $(docker ps -a -q)
docker pause/unpause :
docker pause : 暫停容器中所有的程序。
docker unpause :恢復容器中所有的程序。
語法
$ docker pause CONTAINER [CONTAINER...]
$ docker unpause CONTAINER [CONTAINER...]
示例
# 暫停資料庫容器db01提供服務。
$ docker pause mynginx
# 恢復資料庫容器 db01 提供服務。
$ docker unpause mynginx
docker create :建立一個新的容器但不啟動它
用法同 docker run
語法
$ docker create [OPTIONS] IMAGE [COMMAND] [ARG...]
語法同 docker run
示例
# 使用docker映象nginx:latest建立一個容器,並將容器命名為myrunoob
$ docker create --name nginxdemo3 nginx:latest
docker exec :在執行的容器中執行命令
語法
$ docker exec [OPTIONS] CONTAINER COMMAND [ARG...]
OPTIONS說明:
- -d :分離模式: 在後臺執行
- -i :即使沒有附加也保持STDIN 開啟
- -t :分配一個偽終端
示例
# 在容器 mynginx 中開啟一個互動模式的終端:
$ docker exec -i -t mynginx /bin/bash
容器操作
docker ps : 列出容器
語法
$ docker ps [OPTIONS]
OPTIONS說明:
-
-a :顯示所有的容器,包括未執行的。
-
-f :根據條件過濾顯示的內容。
-
--format :指定返回值的模板檔案。
-
-l :顯示最近建立的容器。
-
-n :列出最近建立的n個容器。
-
--no-trunc :不截斷輸出。
-
-q :靜默模式,只顯示容器編號。
-
-s :顯示總的檔案大小。
示例
列出所有在執行的容器資訊。
$ docker ps
CONTAINER ID IMAGE COMMAND ... PORTS NAMES
09b93464c2f7 nginx:latest "nginx -g 'daemon off" ... 80/tcp, 443/tcp myrunoob
96f7f14e99ab mysql:5.6 "docker-entrypoint.sh" ... 0.0.0.0:3306->3306/tcp mymysql
輸出詳情介紹:
CONTAINER ID: 容器 ID。
IMAGE: 使用的映象。
COMMAND: 啟動容器時執行的命令。
CREATED: 容器的建立時間。
STATUS: 容器狀態。
狀態有7種:
- created(已建立)
- restarting(重啟中)
- running(執行中)
- removing(遷移中)
- paused(暫停)
- exited(停止)
- dead(死亡)
PORTS: 容器的埠資訊和使用的連線型別(tcp\udp)。
NAMES: 自動分配的容器名稱。
示例
# 列出最近建立的5個容器資訊。
$ docker ps -n 5
CONTAINER ID IMAGE COMMAND CREATED
09b93464c2f7 nginx:latest "nginx -g 'daemon off" 2 days ago ...
b8573233d675 nginx:latest "/bin/bash" 2 days ago ...
b1a0703e41e7 nginx:latest "nginx -g 'daemon off" 2 days ago ...
f46fb1dec520 5c6e1090e771 "/bin/sh -c 'set -x \t" 2 days ago ...
a63b4a5597de 860c279d2fec "bash" 2 days ago ...
# 列出所有建立的容器ID。
$ docker ps -a -q
09b93464c2f7
b8573233d675
b1a0703e41e7
f46fb1dec520
a63b4a5597de
6a4aa42e947b
de7bb36e7968
43a432b73776
664a8ab1a585
ba52eb632bbd
...
docker inspect : 獲取容器/映象的元資料。
語法
$ docker inspect [OPTIONS] NAME|ID [NAME|ID...]
OPTIONS說明:
- -f :指定返回值的模板檔案。
- -s :顯示總的檔案大小。
- --type :為指定型別返回JSON。
示例
獲取映象mysql:5.6的元資訊。
$ docker inspect mysql:5.6
[
{
"Id": "sha256:2c0964ec182ae9a045f866bbc2553087f6e42bfc16074a74fb820af235f070ec",
"RepoTags": [
"mysql:5.6"
],
"RepoDigests": [],
"Parent": "",
"Comment": "",
"Created": "2016-05-24T04:01:41.168371815Z",
"Container": "e0924bc460ff97787f34610115e9363e6363b30b8efa406e28eb495ab199ca54",
"ContainerConfig": {
"Hostname": "b0cf605c7757",
"Domainname": "",
"User": "",
"AttachStdin": false,
"AttachStdout": false,
"AttachStderr": false,
"ExposedPorts": {
"3306/tcp": {}
},
...
獲取正在執行的容器mymysql的 IP。
$ docker inspect --format='{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' mymysql172.17.0.3
docker top :檢視容器中執行的程序資訊,支援 ps 命令引數。
語法
$ docker top [OPTIONS] CONTAINER [ps OPTIONS]
容器執行時不一定有/bin/bash終端來互動執行top命令,而且容器還不一定有top命令,可以使用docker top來實現檢視container中正在執行的程序。
示例
# 檢視容器mymysql的程序資訊。$ docker top mymysqlUID PID PPID C STIME TTY TIME CMD999 40347 40331 18 00:58 ? 00:00:02 mysqld# 檢視所有執行容器的程序資訊。$ for i in `docker ps |grep Up|awk '{print $1}'`;do echo \ &&docker top $i; done
docker attach :連線到正在執行中的容器。
語法
$ docker attach [OPTIONS] CONTAINER
要attach上去的容器必須正在執行,可以同時連線上同一個container來共享螢幕(與screen命令的attach類似)。
官方文件中說attach後可以通過CTRL-C來detach,但實際上經過我的測試,如果container當前在執行bash,CTRL-C自然是當前行的輸入,沒有退出;如果container當前正在前臺執行程序,如輸出nginx的access.log日誌,CTRL-C不僅會導致退出容器,而且還stop了。這不是我們想要的,detach的意思按理應該是脫離容器終端,但容器依然執行。好在attach是可以帶上--sig-proxy=false來確保CTRL-D或CTRL-C不會關閉容器。
示例
容器mynginx將訪問日誌指到標準輸出,連線到容器檢視訪問資訊。
$ docker attach --sig-proxy=false mynginx192.168.239.1 - - [10/Jul/2016:16:54:26 +0000] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.93 Safari/537.36" "-"
docker events : 從伺服器獲取實時事件
語法
$ docker events [OPTIONS]
OPTIONS說明:
- -f :根據條件過濾事件;
- --since :從指定的時間戳後顯示所有事件;
- --until :流水時間顯示到指定的時間為止;
示例
# 顯示docker 2021年3月20日後的所有事件。$ docker events --since="1616233483"# 顯示docker 2021年3月20日後的所有事件.$ docker events -f "image"="mysql" --since="1616233483"
如果指定的時間是到秒級的,需要將時間轉成時間戳。如果時間為日期的話,可以直接使用,如--since="2021-03-20"。
docker logs : 獲取容器的日誌
語法
$ docker logs [OPTIONS] CONTAINER
OPTIONS說明:
- -f : 跟蹤日誌輸出
- --since :顯示某個開始時間的所有日誌
- -t : 顯示時間戳
- --tail :僅列出最新N條容器日誌
示例
# 跟蹤檢視容器mynginx的日誌輸出。$ docker logs -f mynginx192.168.239.1 - - [10/Jul/2016:16:53:33 +0000] "GET / HTTP/1.1" 200 612 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.93 Safari/537.36" "-"2016/07/10 16:53:33 [error] 5#5: *1 open() "/usr/share/nginx/html/favicon.ico" failed (2: No such file or directory), client: 192.168.239.1, server: localhost, request: "GET /favicon.ico HTTP/1.1", host: "192.168.239.130", referrer: "http://192.168.239.130/"192.168.239.1 - - [10/Jul/2016:16:53:33 +0000] "GET /favicon.ico HTTP/1.1" 404 571 "http://192.168.239.130/" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.93 Safari/537.36" "-"192.168.239.1 - - [10/Jul/2016:16:53:59 +0000] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.93 Safari/537.36" "-"...
檢視容器mynginx從2021-03-20後的最新10條日誌。
$ docker logs --since="2021-03-20" --tail=10 mynginx
docker wait : 阻塞執行直到容器停止,然後打印出它的退出程式碼。
語法
$ docker wait [OPTIONS] CONTAINER [CONTAINER...]
示例
$ docker wait CONTAINER
docker export :將檔案系統作為一個tar歸檔檔案匯出到STDOUT。
語法
$ docker export [OPTIONS] CONTAINER
OPTIONS說明:
- -o :將輸入內容寫到檔案。
示例
# 將id為46162045d607的容器按日期儲存為tar檔案。$ docker export -o mysql-`date +%Y%m%d`.tar 46162045d607$ ls mysql-`date +%Y%m%d`.tarmysql-20210320.tar
docker port :列出指定的容器的埠對映,或者查詢將PRIVATE_PORT NAT到面向公眾的埠。
語法
$ docker port [OPTIONS] CONTAINER [PRIVATE_PORT[/PROTO]]
示例
# 檢視容器mynginx的埠對映情況。$ docker port mymysql3306/tcp -> 0.0.0.0:3306
容器rootfs命令
docker commit :從容器建立一個新的映象。
語法
$ docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]]
OPTIONS說明:
-
-a :提交的映象作者;
-
-c :使用Dockerfile指令來建立映象;
-
-m :提交時的說明文字;
-
-p :在commit時,將容器暫停。
示例
# 將容器46162045d607 儲存為新的映象,並新增提交人資訊和說明資訊。$ docker commit -a "e6gps" -m "my apache" 46162045d607 mymysql:v1 sha256:37af1236adef1544e8886be23010b66577647a40bc02c0885a6600b33ee28057$ docker images mymysql:v1REPOSITORY TAG IMAGE ID CREATED SIZEmymysql v1 37af1236adef 15 seconds ago 329 MB
docker cp :用於容器與主機之間的資料拷貝。
語法
$ docker cp [OPTIONS] CONTAINER:SRC_PATH DEST_PATH|-$ docker cp [OPTIONS] SRC_PATH|- CONTAINER:DEST_PATH
OPTIONS說明:
- -L :保持源目標中的連結
示例
# 將主機/www/e6目錄拷貝到容器96f7f14e99ab的/www目錄下。$ docker cp /www/e6 96f7f14e99ab:/etc/nginx/conf.d# 將主機/www/e6目錄拷貝到容器96f7f14e99ab中,目錄重新命名為www。$ docker cp /www/e6 96f7f14e99ab:/www# 將容器96f7f14e99ab的/www目錄拷貝到主機的/tmp目錄中。$ docker cp 96f7f14e99ab:/www /tmp/
docker diff : 檢查容器裡檔案結構的更改。
語法
$ docker diff [OPTIONS] CONTAINER
示例
# 檢視容器mymysql的檔案結構更改。$ docker diff mymysqlA /logsA /mysql_dataC /runC /run/mysqldA /run/mysqld/mysqld.pidA /run/mysqld/mysqld.sockC /tmp
映象倉庫
docker login/logout
docker login : 登陸到一個Docker映象倉庫,如果未指定映象倉庫地址,預設為官方倉庫 Docker Hub
docker logout : 登出一個Docker映象倉庫,如果未指定映象倉庫地址,預設為官方倉庫 Docker Hub
語法
$ docker login [OPTIONS] [SERVER]$ docker logout [OPTIONS] [SERVER]
OPTIONS說明:
- -u :登陸的使用者名稱
- -p :登陸的密碼
示例
# 登陸到阿里雲$ docker login --username=lanjiaxuan@e6yun registry.cn-shenzhen.aliyuncs.com# 登出# 登出Docker Hub$ docker logout
docker pull : 從映象倉庫中拉取或者更新指定映象
語法
$ docker pull [OPTIONS] NAME[:TAG|@DIGEST]
OPTIONS說明:
-
-a :拉取所有 tagged 映象
-
--disable-content-trust :忽略映象的校驗,預設開啟
示例
# 從Docker Hub下載java最新版映象。$ docker pull registry.cn-shenzhen.aliyuncs.com/base_e6yw/nginxdemo:v1# 從Docker Hub下載REPOSITORY為java的所有映象。$ docker pull -a java
docker push : 將本地的映象上傳到映象倉庫,要先登陸到映象倉庫
語法
$ docker push [OPTIONS] NAME[:TAG]
OPTIONS說明:
- --disable-content-trust :忽略映象的校驗,預設開啟
示例
# 上傳本地映象myapache:v1到映象倉庫中。$ docker tag 159d74e6cbce registry.cn-shenzhen.aliyuncs.com/base_e6yw/mysqldemo:v1$ docker push registry.cn-shenzhen.aliyuncs.com/base_e6yw/mysqldemo:v1
docker search : 從Docker Hub查詢映象
語法
$ docker search [OPTIONS] TERM
OPTIONS說明:
- --automated :只列出 automated build型別的映象;
- --no-trunc :顯示完整的映象描述;
- -f <過濾條件>:列出收藏數不小於指定值的映象。
示例
# 從 Docker Hub 查詢所有映象名包含 java,並且收藏數大於 10 的映象$ docker search -f stars=10 javaNAME DESCRIPTION STARS OFFICIAL AUTOMATEDnode Node.js is a JavaScript-based platform for s… 9857 [OK] tomcat Apache Tomcat is an open source implementati… 2980 [OK] openjdk OpenJDK is an open-source implementation of … 2664 [OK] java Java is a concurrent, class-based, and objec… 1976 [OK] ghost Ghost is a free and open source blogging pla… 1338 [OK] couchdb CouchDB is a database that uses JSON for doc… 393 [OK] jetty Jetty provides a Web server and javax.servle… 356 [OK] groovy Apache Groovy is a multi-faceted language fo… 105 [OK] lwieske/java-8 Oracle Java 8 Container - Full + Slim - Base… 49 [OK]nimmis/java-centos This is docker images of CentOS 7 with diffe… 42 [OK]fabric8/java-jboss-openjdk8-jdk Fabric8 Java Base Image (JBoss, OpenJDK 8) 29 [OK]cloudbees/java-build-tools Docker image with commonly used tools to bui… 15 [OK]frekele/java docker run --rm --name java frekele/java 12 [OK]
引數說明:
NAME: 映象倉庫源的名稱
DESCRIPTION: 映象的描述
OFFICIAL: 是否 docker 官方釋出
stars: 類似 Github 裡面的 star,表示點贊、喜歡的意思。
AUTOMATED: 自動構建。
本地映象管理
docker images : 列出本地映象。
語法
$ docker images [OPTIONS] [REPOSITORY[:TAG]]
OPTIONS說明:
-
-a :列出本地所有的映象(含中間映像層,預設情況下,過濾掉中間映像層);
-
--digests :顯示映象的摘要資訊;
-
-f :顯示滿足條件的映象;
-
--format :指定返回值的模板檔案;
-
--no-trunc :顯示完整的映象資訊;
-
-q :只顯示映象ID。
示例
# 檢視本地映象列表。$ docker imagesREPOSITORY TAG IMAGE ID CREATED SIZEmymysql v1 37af1236adef 5 minutes ago 329 MBe6/ubuntu v4 1c06aa18edee 2 days ago 142.1 MB<none> <none> 5c6e1090e771 2 days ago 165.9 MBhttpd latest ed38aaffef30 11 days ago 195.1 MBalpine latest 4e38e38c8ce0 2 weeks ago 4.799 MBmongo 3.2 282fd552add6 3 weeks ago 336.1 MBredis latest 4465e4bcad80 3 weeks ago 185.7 MBphp 5.6-fpm 025041cd3aa5 3 weeks ago 456.3 MBpython 3.5 045767ddf24a 3 weeks ago 684.1 MB...# 列出本地映象中REPOSITORY為nginx的映象列表。$ docker images nginx
docker rmi : 刪除本地一個或多少映象。
語法
$ docker rmi [OPTIONS] IMAGE [IMAGE...]
OPTIONS說明:
-
-f :強制刪除;
-
--no-prune :不移除該映象的過程映象,預設移除;
示例
# 強制刪除本地映象 e6/ubuntu:v4。$ docker rmi -f e6/ubuntu:v4Untagged: e6/ubuntu:v4Deleted: sha256:1c06aa18edee44230f93a90a7d88139235de12cd4c089d41eed8419b503072beDeleted: sha256:85feb446e89a28d58ee7d80ea5ce367eebb7cec70f0ec18aa4faa874cbd97c73
docker tag : 標記本地映象,將其歸入某一倉庫。
語法
$ docker tag [OPTIONS] IMAGE[:TAG] [REGISTRYHOST/][USERNAME/]NAME[:TAG]
示例
# 將映象ubuntu:15.10標記為 e6/ubuntu:v3 映象。$ docker tag ubuntu:15.10 e6/ubuntu:v3$ docker images e6/ubuntu:v3REPOSITORY TAG IMAGE ID CREATED SIZEe6/ubuntu v3 4e3b13c8a266 3 months ago 136.3 MB
docker build 命令用於使用 Dockerfile 建立映象。
語法
$ docker build [OPTIONS] PATH | URL | -
OPTIONS說明:
- --build-arg=[] :設定映象建立時的變數;
- --cpu-shares :設定 cpu 使用權重;
- --cpu-period :限制 CPU CFS週期;
- --cpu-quota :限制 CPU CFS配額;
- --cpuset-cpus :指定使用的CPU id;
- --cpuset-mems :指定使用的記憶體 id;
- --disable-content-trust :忽略校驗,預設開啟;
- -f :指定要使用的Dockerfile路徑;
- --force-rm :設定映象過程中刪除中間容器;
- --isolation :使用容器隔離技術;
- --label=[] :設定映象使用的元資料;
- -m :設定記憶體最大值;
- --memory-swap :設定Swap的最大值為記憶體+swap,"-1"表示不限swap;
- --no-cache :建立映象的過程不使用快取;
- --pull :嘗試去更新映象的新版本;
- --quiet, -q :安靜模式,成功後只輸出鏡像 ID;
- --rm :設定映象成功後刪除中間容器;
- --shm-size :設定/dev/shm的大小,預設值是64M;
- --ulimit :Ulimit配置。
- --squash :將 Dockerfile 中所有的操作壓縮為一層。
- --tag, -t: 映象的名字及標籤,通常 name:tag 或者 name 格式;可以在一次構建中為一個映象設定多個標籤。
- --network: 預設 default。在構建期間設定RUN指令的網路模式
示例
# 使用當前目錄的 Dockerfile 建立映象,標籤為 e6/ubuntu:v1。$ docker build -t e6/ubuntu:v1 . # 也可以通過 -f Dockerfile 檔案的位置:$ docker build -f /path/to/a/Dockerfile .# 在 Docker 守護程序執行 Dockerfile 中的指令前,首先會對 Dockerfile 進行語法檢查,有語法錯誤時會返回:$ docker build -t test/myapp .Sending build context to Docker daemon 2.048 kBError response from daemon: Unknown instruction: RUNCMD
docker history : 檢視指定映象的建立歷史。
語法
$ docker history [OPTIONS] IMAGE
OPTIONS說明:
-
-H :以可讀的格式列印映象大小和日期,預設為true;
-
--no-trunc :顯示完整的提交記錄;
-
-q :僅列出提交記錄ID。
示例
檢視本地映象e6/ubuntu:v3的建立歷史。
$ docker history e6/ubuntu:v1IMAGE CREATED CREATED BY SIZE COMMENTe76ebd704270 2 days ago /bin/sh -c #(nop) CMD ["curl" "-s" "http://… 0B 643a0fed86a9 2 days ago /bin/sh -c apt-get update && apt-get install… 16.2MB 9499db781771 4 months ago /bin/sh -c #(nop) CMD ["/bin/bash"] 0B <missing> 4 months ago /bin/sh -c mkdir -p /run/systemd && echo 'do… 7B <missing> 4 months ago /bin/sh -c rm -rf /var/lib/apt/lists/* 0B <missing> 4 months ago /bin/sh -c set -xe && echo '#!/bin/sh' > /… 745B <missing> 4 months ago /bin/sh -c #(nop) ADD file:8eef54430e581236e… 131MB
docker save : 將指定映象儲存成 tar 歸檔檔案。
語法
$ docker save [OPTIONS] IMAGE [IMAGE...]
OPTIONS 說明:
- -o :輸出到的檔案。
示例
將映象 e6/ubuntu:v3 生成 my_ubuntu_v3.tar 文件
$ docker save -o my_ubuntu_v1.tar e6/ubuntu:v1$ ll my_ubuntu_v1.tar-rw------- 1 e6 e6 142102016 Jul 11 01:37 my_ubuntu_v1.tar
docker load : 匯入使用 docker save 命令匯出的映象。
語法
$ docker load [OPTIONS]
OPTIONS 說明:
-
--input , -i : 指定匯入的檔案,代替 STDIN。
-
--quiet , -q : 精簡輸出資訊。
示例
匯入映象:
$ docker image lsREPOSITORY TAG IMAGE ID CREATED SIZE$ docker load < my_ubuntu_v1.tarLoaded image: e6/ubuntu:v1$ docker imagesREPOSITORY TAG IMAGE ID CREATED SIZEmymysql v1 159d74e6cbce 12 minutes ago 302MBregistry.cn-shenzhen.aliyuncs.com/base_e6yw/mysqldemo v1 159d74e6cbce 12 minutes ago 302MB<none> <none> 17c51e0230b6 2 days ago 302MBe6/ubuntu v1 e76ebd704270 2 days ago 147MBmyip latest e76ebd704270 2 days ago 147MBnginx latest f6d0b4767a6c 2 months ago 133MBmysql 5.6 6e68afc1976f 2 months ago 302MBubuntu 16.04 9499db781771 4 months ago 131MB$ docker load --input my_ubuntu_v1.tarLoaded image: e6/ubuntu:v1$ docker imagesREPOSITORY TAG IMAGE ID CREATED SIZEmymysql v1 159d74e6cbce 13 minutes ago 302MBregistry.cn-shenzhen.aliyuncs.com/base_e6yw/mysqldemo v1 159d74e6cbce 13 minutes ago 302MB<none> <none> 17c51e0230b6 2 days ago 302MBe6/ubuntu v1 e76ebd704270 2 days ago 147MBmyip latest e76ebd704270 2 days ago 147MBnginx latest f6d0b4767a6c 2 months ago 133MBmysql 5.6 6e68afc1976f 2 months ago 302MBubuntu 16.04 9499db781771 4 months ago 131MB
docker import : 從歸檔檔案中建立映象。
語法
$ docker import [OPTIONS] file|URL|- [REPOSITORY[:TAG]]
OPTIONS說明:
-
-c :應用docker 指令建立映象;
-
-m :提交時的說明文字;
示例
# 從映象歸檔檔案my_ubuntu_v3.tar建立映象,命名為e6/ubuntu:v4$ docker import my_ubuntu_v1.tar e6/ubuntu:v2 sha256:7e6f3bd25c59e8c18206457cc403544278eb9049641e894a7a8576220fdcf398$ docker images e6/ubuntu:v2REPOSITORY TAG IMAGE ID CREATED SIZEe6/ubuntu v2 7e6f3bd25c59 25 seconds ago 152MB
info|version
docker info : 顯示 Docker 系統資訊,包括映象和容器數。。
語法
$ docker info
示例
# 檢視docker系統資訊。$ docker infoClient: Context: default Debug Mode: false Plugins: app: Docker App (Docker Inc., v0.9.1-beta3) buildx: Build with BuildKit (Docker Inc., v0.5.1-docker)Server: Containers: 5 Running: 3 Paused: 0 Stopped: 2 Images: 7 Server Version: 20.10.5 Storage Driver: overlay2 Backing Filesystem: xfs Supports d_type: true Native Overlay Diff: true Logging Driver: json-file Cgroup Driver: cgroupfs Cgroup Version: 1 Plugins: Volume: local Network: bridge host ipvlan macvlan null overlay Log: awslogs fluentd gcplogs gelf journald json-file local logentries splunk syslog Swarm: inactive Runtimes: io.containerd.runc.v2 io.containerd.runtime.v1.linux runc Default Runtime: runc Init Binary: docker-init containerd version: 05f951a3781f4f2c1911b05e61c160e9c30eaa8e runc version: 12644e614e25b05da6fd08a38ffa0cfe1903fdec init version: de40ad0 Security Options: seccomp Profile: default Kernel Version: 3.10.0-1160.el7.x86_64 Operating System: CentOS Linux 7 (Core) OSType: linux Architecture: x86_64 CPUs: 4 Total Memory: 15.19GiB Name: localhost.localdomain ID: 5PCC:SY6I:UAAH:CLPH:FDXT:A2EN:KWEA:7S3W:4HEA:WO3B:2HJR:3PN7 Docker Root Dir: /var/lib/docker Debug Mode: false Registry: https://index.docker.io/v1/ Labels: Experimental: false Insecure Registries: 127.0.0.0/8 Registry Mirrors: https://7xatqpwu.mirror.aliyuncs.com/ Live Restore Enabled: false
docker version :顯示 Docker 版本資訊。
語法
$ docker version [OPTIONS]
OPTIONS說明:
- -f :指定返回值的模板檔案。
例項
# 顯示 Docker 版本資訊。$ docker versionClient: Docker Engine - Community Version: 20.10.5 API version: 1.41 Go version: go1.13.15 Git commit: 55c4c88 Built: Tue Mar 2 20:33:55 2021 OS/Arch: linux/amd64 Context: default Experimental: trueServer: Docker Engine - Community Engine: Version: 20.10.5 API version: 1.41 (minimum version 1.12) Go version: go1.13.15 Git commit: 363e9a8 Built: Tue Mar 2 20:32:17 2021 OS/Arch: linux/amd64 Experimental: false containerd: Version: 1.4.4 GitCommit: 05f951a3781f4f2c1911b05e61c160e9c30eaa8e runc: Version: 1.0.0-rc93 GitCommit: 12644e614e25b05da6fd08a38ffa0cfe1903fdec docker-init: Version: 0.19.0 GitCommit: de40ad0
kubernetes
什麼是kubernetes
Kubernetes 是 Google 團隊發起的一個開源專案,它的目標是管理跨多個主機的容器,用於自動部署、擴充套件和管理容器化的應用程式,主要實現語言為 Go 語言。
kubernetes 的組成
-
Master:Master 節點是 Kubernetes 叢集的控制節點,負責整個叢集的管理和控制。Master 節點上包含以下元件:
-
kube-apiserver:叢集控制的入口,提供 HTTP REST 服務
-
kube-controller-manager:Kubernetes 叢集中所有資源物件的自動化控制中心
-
kube-scheduler:負責 Pod 的排程
-
Node:Node 節點是 Kubernetes 叢集中的工作節點,Node 上的工作負載由 Master 節點分配,工作負載主要是執行容器應用。Node 節點上包含以下元件:
- kubelet:負責 Pod 的建立、啟動、監控、重啟、銷燬等工作,同時與 Master 節點協作,實現叢集管理的基本功能。
- kube-proxy:實現 Kubernetes Service 的通訊和負載均衡
- 執行容器化(Pod)應用
-
Pod: Pod 是 Kubernetes 最基本的部署排程單元。每個 Pod 可以由一個或多個業務容器和一個根容器(Pause 容器)組成。一個 Pod 表示某個應用的一個例項
-
ReplicaSet:是 Pod 副本的抽象,用於解決 Pod 的擴容和伸縮
-
Deployment:Deployment 表示部署,在內部使用ReplicaSet 來實現。可以通過 Deployment 來生成相應的 ReplicaSet 完成 Pod 副本的建立
-
Service:Service 是 Kubernetes 最重要的資源物件。Kubernetes 中的 Service 物件可以對應微服務架構中的微服務。Service 定義了服務的訪問入口,服務的呼叫者通過這個地址訪問 Service 後端的 Pod 副本示例。Service 通過 Label Selector 同後端的 Pod 副本建立關係,Deployment 保證後端Pod 副本的數量,也就是保證服務的伸縮性。
kubectl管理工具以及命令
基礎命令
kubectl create 建立
通過配置檔名或stdin建立一個叢集資源物件。
支援JSON和YAML格式的檔案。
語法
$ kubectl create -f FILENAME
示例
# 通過pod.json檔案建立一個pod。$ kubectl create -f ./pod.json# 通過stdin的JSON建立一個pod。$ cat pod.json | kubectl create -f -
kubectl apply 建立/更新
通過配置檔名或stdin建立一個叢集資源物件。
支援JSON和YAML格式的檔案。
語法
$ kubectl apply -f FILENAME
示例
# 通過pod.json檔案建立一個pod。$ kubectl apply -f ./pod.json# 通過stdin的JSON建立一個pod。$ cat pod.json | kubectl apply -f -
注意
kubectl create命令可建立新資源。 因此,如果再次執行該命令,則會丟擲錯誤,因為資源名稱在名稱空間中應該是唯一的。
kubectl apply命令將配置應用於資源。 如果資源不在那裡,那麼它將被建立。 kubectl apply命令可以第二次執行,如果資源在那裡,那麼它將配置應用於現有資源
簡單來說,如果在單個檔案上執行操作以建立資源,則create和apply基本相同。 但是, apply允許您在目錄下的多個檔案上同時建立和修補。
kubectl delete 刪除
通過配置檔名、stdin、資源名稱或label選擇器來刪除資源。
語法
$ kubectl delete ([-f FILENAME] | TYPE [(NAME | -l label | --all)])
示例
# 使用 pod.json中指定的資源型別和名稱刪除pod。$ kubectl delete -f ./pod.json# 根據傳入stdin的JSON所指定的型別和名稱刪除pod。$ cat pod.json | kubectl delete -f -# 刪除名為“baz”和“foo”的Pod和Service。$ kubectl delete pod,service baz foo# 刪除 Label name = myLabel的pod和Service。$ kubectl delete pods,services -l name=myLabel# 強制刪除dead node上的pod$ kubectl delete pod foo --grace-period=0 --force# 刪除所有pod$ kubectl delete pods --all
kubectl get獲取資源資訊
獲取列出一個或多個資源的資訊。
可以使用的資源包括:
- all
- certificatesigningrequests (aka 'csr')
- clusterrolebindings
- clusterroles
- clusters (valid only for federation apiservers)
- componentstatuses (aka 'cs')
- configmaps (aka 'cm')
- controllerrevisions
- cronjobs
- daemonsets (aka 'ds')
- deployments (aka 'deploy')
- endpoints (aka 'ep')
- events (aka 'ev')
- horizontalpodautoscalers (aka 'hpa')
- ingresses (aka 'ing')
- jobs
- limitranges (aka 'limits')
- namespaces (aka 'ns')
- networkpolicies (aka 'netpol')
- nodes (aka 'no')
- persistentvolumeclaims (aka 'pvc')
- persistentvolumes (aka 'pv')
- poddisruptionbudgets (aka 'pdb')
- podpreset
- pods (aka 'po')
- podsecuritypolicies (aka 'psp')
- podtemplates
- replicasets (aka 'rs')
- replicationcontrollers (aka 'rc')
- resourcequotas (aka 'quota')
- rolebindings
- roles
- secrets
- serviceaccounts (aka 'sa')
- services (aka 'svc')
- statefulsets
- storageclasses
- thirdpartyresources
語法
$ kubectl get resource名稱
OPTIONS說明:
-
-o wide/yaml/json 用不同的格式檢視
-
-l key=value 看指定標籤的pods,支援’=’, ‘==’, and ‘!=’操作符
-
-n 名稱空間 檢視指定的名稱空間
示例
# 檢視Master狀態$ kubectl get componentstatuses# 檢視所有名稱空間$ kubectl get namespace# 列出所有的pods$ kubectl get pods# 顯示更多的pods列表資訊(例如 pod的ip和所處的node)$ kubectl get pods -o wide# 列出名字為web的rc$ kubectl get replicationcontroller web# 獲取名字為web-pod-13je7的pod的資訊,並以json格式輸出$ kubectl get -o json pod web-pod-13je7# 根據pod檔案查詢pod,並以json格式輸出$ kubectl get -f pod.yaml -o json# 獲取pod容器的狀態$ kubectl get -o template pod/kube-dns-795f5f6f9c-ldxxs --template {{.status.phase}}# 同時獲取所有的rc和service$ kubectl get rc,services# 獲取符合條件的所有rc,svc,pod$ kubectl get rc/web service/frontend pods/web-pod-13je7# 獲取所有resource$ kubectl get all
kubectl run建立並執行
- 建立並執行一個或多個容器映象。
- 建立一個deployment 或job 來管理容器。
語法
$ kubectl run NAME --image=image [--env="key=value"] [--port=port] [--replicas=replicas] [--dry-run=bool] [--overrides=inline-json] [--command] -- [COMMAND] [args...]
示例:
# 啟動nginx例項。$ kubectl run nginx --image=nginx# hazelcast例項,暴露容器埠 5701。$ kubectl run hazelcast --image=hazelcast --port=5701# 啟動hazelcast例項,在容器中設定環境變數“DNS_DOMAIN = cluster”和“POD_NAMESPACE = default”。$ kubectl run hazelcast --image=hazelcast --env="DNS_DOMAIN=cluster" --env="POD_NAMESPACE=default"# 啟動nginx例項,設定副本數5。$ kubectl run nginx --image=nginx --replicas=5# Dry 列印相應的API物件而不建立它們。$ kubectl run nginx --image=nginx --dry-run
kubectl expose 建立資源的service
將資源暴露為新的Kubernetes Service。
指定deployment、service、replica set、replication controller或pod ,並使用該資源的選擇器作為指定埠上新服務的選擇器。deployment 或 replica set只有當其選擇器可轉換為service支援的選擇器時,即當選擇器僅包含matchLabels元件時才會作為暴露新的Service。
資源包括(不區分大小寫):
pod(po),service(svc),replication controller(rc),deployment(deploy),replica set(rs)
語法
$ kubectl expose (-f FILENAME | TYPE NAME) [--port=port] [--protocol=TCP|UDP] [--target-port=number-or-name] [--name=name] [--external-ip=external-ip-of-service] [--type=type]
示例
# 為RC的deployment建立service,並通過Service的80埠轉發至宿主機埠上。$ kubectl expose deployment centos7-test2 --port=22 --type=NodePort
kubectl set配置應用資源
配置應用資源。
使用這些命令能幫你更改現有應用資源一些資訊。
語法
$ kubectl set SUBCOMMAND
子命令
- image
- resources
- selector
- subject
kubectl edit 使用預設編輯器 編輯伺服器上定義的資源。
使用命令列工具獲取的任何資源都可以使用edit命令編輯。edit命令會開啟使用KUBE_EDITOR,GIT_EDITOR 或者EDITOR環境變數定義的編輯器,可以同時編輯多個資源,但所編輯過的資源只會一次性提交。edit除命令引數外還接受檔名形式。
檔案預設輸出格式為YAML。要以JSON格式編輯,請指定“-o json”選項。
如果在更新資源時報錯,將會在磁碟上建立一個臨時檔案來記錄。在更新資源時最常見的錯誤是幾個使用者同時使用編輯器更改伺服器上資源,發生這種情況,你需要將你的更改應用到最新版本的資源上,或者更新儲存的臨時副本。
語法
$ kubectl edit (RESOURCE/NAME | -f FILENAME)
示例
# 編輯名為'centos7-test2'的service:$ kubectl edit svc centos7-test2 -n test
故障排查和除錯命令
kubtctl describe輸出指定的一個/多個資源的詳細資訊
輸出指定的一個/多個資源的詳細資訊。
此命令組合呼叫多條API,輸出指定的一個或者一組資源的詳細描述。
語法
$ kubectl describe (-f FILENAME | TYPE [NAME_PREFIX | -l label] | TYPE/NAME)
示例
# 描述一個node$ kubectl describe nodes k8s-master# 描述一個pod$ kubectl describe pods/nginx# 描述deployment_centos7.yaml中的資源型別和名稱指定的pod$ kubectl describe -f deployment_centos7.yaml -n test# 描述所有的pod$ kubectl describe pods -n test
kubectl logs日誌檢視
檢視容器日誌
語法
$ kubectl logs [-f] [-p] (POD | TYPE/NAME) [-c CONTAINER] [options]
示例
# 輸出一個單容器pod my-pod的日誌到標準輸出$ kubectl logs pod/centos7-test2-5dbbc849f4-f6w77 -n test# 輸出多容器pod中的某個nginx容器的日誌$ kubectl logs nginx-78f5d695bd-czm8z -c nginx# 輸出所有包含app-nginx標籤的pod日誌$ kubectl logs -l app=nginx# 加上-f引數跟蹤日誌,類似tail -f$ kubectl logs -f my-pod # 輸出該pod的上一個退出的容器例項日誌。在pod容器異常退出時很有用$ kubectl logs my-pod -p# 指定時間戳輸出日誌 $ kubectl logs my-pod --since-time=2018-11-01T15:00:00Z# 指定時間段輸出日誌,單位s/m/h$ kubectl logs my-pod --since=1h
kubectl exec 執行容器的命令
exec主要作用是在容器內部執行命令(一般為檢視容器內部日誌
語法
$ kubectl exec -it podName -c containerName -n namespace -- shell comand
示例
# 進入centos 的pod $ kubectl exec -it pod/centos7-test2-5dbbc849f4-f6w77 /bin/bash -n test
kubectl cp檔案傳輸
檔案傳輸
語法:
$ kubectl cp <file-spec-src> <file-spec-dest> [options]
示例
# 拷貝宿主機本地資料夾到pod$ kubectl cp /tmp/foo_dir <some-pod>:/tmp/bar_dir # 指定namespace的拷貝pod檔案到宿主機本地目錄$ kubectl cp <some-namespace>/<some-pod>:/tmp/foo /tmp/bar # 對於多容器pod,用-c指定容器名$ kubectl cp /tmp/foo <some-pod>:/tmp/bar -c <specific-container>
kubectl 部署命令
kubectl rollout對資源進行管理
可用資源包括:
- deployments
- daemonsets
語法
$ kubectl rollout SUBCOMMAND
示例
# 回滾到之前的deployment$ $ kubectl rollout undo deployment/abc# 檢視daemonet的狀態$ kubectl rollout status daemonset/foo
kubectl rolling-update執行指定ReplicationController的滾動更新。
該命令建立了一個新的RC, 然後一次更新一個pod方式逐步使用新的PodTemplate,最終實現Pod滾動更新,new-controller.json需要與之前RC在相同的namespace下。
語法:
$ kubectl rolling-update OLD_CONTROLLER_NAME ([NEW_CONTROLLER_NAME] --image=NEW_CONTAINER_IMAGE | -f NEW_CONTROLLER_SPEC)
示例
# 使用frontend-v2.json中的新RC資料更新frontend-v1的pod$ kubectl rolling-update frontend-v1 -f frontend-v2.json# 使用JSON資料更新frontend-v1的pod。$ cat frontend-v2.json | kubectl rolling-update frontend-v1 -f -
kubectl scale擴容或縮容 Deployment、ReplicaSet、Replication Controller或 Job 中Pod數量。
scale也可以指定多個前提條件,如:當前副本數量或 --resource-version ,進行伸縮比例設定前,系統會先驗證前提條件是否成立。
語法
$ kubectl scale [--resource-version=version] [--current-replicas=count] --replicas=COUNT (-f FILENAME | TYPE NAME)
示例
# 將名為centos7-test2的pod副本數設定為3$ kubectl scale --replicas=3 deployment/centos7-test2 -n test
kubectl autoscale使用 autoscaler 自動設定在kubernetes叢集中執行的pod數量(水平自動伸縮)
指定Deployment、ReplicaSet或ReplicationController,並建立已經定義好資源的自動伸縮器。使用自動伸縮器可以根據需要自動增加或減少系統中部署的pod數量。
語法
$ kubectl autoscale (-f FILENAME | TYPE NAME | TYPE/NAME) [--min=MINPODS] --max=MAXPODS [--cpu-percent=CPU] [flags]
示例
# 使用 Deployment “centos7-test2”設定,使用預設的自動伸縮策略,指定目標CPU使用率,使其Pod數量在2到10之間。$ kubectl autoscale deployment centos7-test2 --min=2 --max=10
Dockerfile 定製映象
映象的定製實際上就是定製每一層所新增的配置、檔案。如果我們可以把每一層修改、安裝、構建、操作的命令都寫入一個指令碼,用這個指令碼來構建、定製映象,那麼無法重複的問題、映象構建透明性的問題、體積的問題就都會解決。這個指令碼就是 Dockerfile
。
Dockerfile
是一個文字檔案,其內包含了一條條的指令
(Instruction),每一條指令構建一層,因此每一條指令的內容,就是描述該層應當如何構建。
FROM nginxRUN echo '<h1>Hello, Docker!</h1>' > /usr/share/nginx/html/index.html
Dockerfile 指令詳解
FROM 指定基礎映象
所謂定製映象,那一定是以一個映象為基礎,在其上進行定製。而 FROM 就是指定基礎映象,因此一個 Dockerfile
中 FROM
是必備的指令,並且必須是第一條指令
。
在 Docker Store 上有非常多的高質量的官方映象,有可以直接拿來使用的服務類的映象,如nginx 、 redis 、 mongo 、mysql 等;也有一些方便開發、構建、執行各種語言應用的映象,如 node 、 openjdk 、 python 等。可以在其中尋找一個最符合我們最終目標的映象為基礎映象進行定製。
如果沒有找到對應服務的映象,官方映象中還提供了一些更為基礎的作業系統映象,如ubuntu 、 debian 、 centos 等,這些作業系統的軟體庫為我們提供了更廣闊的擴充套件空間。
除了選擇現有映象為基礎映象外,Docker 還存在一個特殊的映象,名為 scratch 。這個映象是虛擬的概念,並不實際存在,它表示一個空白的映象。
FROM scratch...
如果你以 scratch 為基礎映象的話,意味著你不以任何映象為基礎,接下來所寫的指令將作為映象第一層開始存在。
不以任何系統為基礎,直接將可執行檔案複製進映象的做法並不罕見,比如 swarm 、 coreos/etcd 。對於 Linux 下靜態編譯的程式來說,並不需要有作業系統提供執行時支援,所需的一切庫都已經在可執行檔案裡了,因此直接 FROM scratch 會讓映象體積更加小巧。使用 Go 語言 開發的應用很多會使用這種方式來製作映象,這也是為什麼有人認為 Go是特別適合容器微服務架構的語言的原因之一。
RUN 執行命令
語法:
RUN
指令是用來執行命令列命令的。由於命令列的強大能力, RUN 指令在定製映象時是最常用的指令之一。其格式有兩種:
- shell 格式:
RUN <命令>
,就像直接在命令列中輸入的命令一樣。剛才寫的 Dockerfile 中的 RUN 指令就是這種格式。
RUN echo '<h1>Hello, Docker!</h1>' > /usr/share/nginx/html/index.html
- exec 格式:
RUN ["可執行檔案", "引數1", "引數2"]
,這更像是函式呼叫中的格式。
注意:
既然 RUN 就像 Shell 指令碼一樣可以執行命令,那麼我們是否就可以像 Shell 指令碼一樣把每個命令對應一個 RUN 呢?比如這樣:
FROM debian:jessieRUN apt-get updateRUN apt-get install -y gcc libc6-dev makeRUN wget -O redis.tar.gz "http://download.redis.io/releases/redis-3.2.5.tar.gz"RUN mkdir -p /usr/src/redisRUN tar -xzf redis.tar.gz -C /usr/src/redis --strip-components=1RUN make -C /usr/src/redisRUN make -C /usr/src/redis install
之前說過,Dockerfile 中每一個指令都會建立一層, RUN 也不例外。每一個 RUN 的行為,就和剛才我們手工建立映象的過程一樣:新建立一層,在其上執行這些命令,執行結束後, commit 這一層的修改,構成新的映象。
而上面的這種寫法,建立了 7 層映象。這是完全沒有意義的,而且很多執行時不需要的東西,都被裝進了映象裡,比如編譯環境、更新的軟體包等等。結果就是產生非常臃腫、非常多層的映象,不僅僅增加了構建部署的時間,也很容易出錯。 這是很多初學 Docker 的人常犯的一個錯誤。
Union FS (聯合檔案系統Union File System)是有最大層數限制的,比如 AUFS(早期docker的預設檔案系統),曾經是最大不得超過 42 層,現在是不得超過127 層。
上面的 Dockerfile 正確的寫法應該是這樣:
FROM debian:jessieRUN buildDeps='gcc libc6-dev make' \ && apt-get update \ && apt-get install -y $buildDeps \ && wget -O redis.tar.gz "http://download.redis.io/releases/redis-3.2.5.tar.gz" \ && mkdir -p /usr/src/redis \ && tar -xzf redis.tar.gz -C /usr/src/redis --strip-components=1 \ && make -C /usr/src/redis \ && make -C /usr/src/redis install \ && rm -rf /var/lib/apt/lists/* \ && rm redis.tar.gz \ && rm -r /usr/src/redis \ && apt-get purge -y --auto-remove $buildDeps
示例
在 Dockerfile 檔案所在目錄執行:
$ docker build -t nginx:v3 .Sending build context to Docker daemon 2.048 kBStep 1 : FROM nginx---> e43d811ce2f4Step 2 : RUN echo '<h1>Hello, Docker!</h1>' > /usr/share/nginx/html/index.html---> Running in 9cdc27646c7b---> 44aa4490ce2cRemoving intermediate container 9cdc27646c7bSuccessfully built 44aa4490ce2c$ docker run -d -P --name nginxdemo nignx:v3
從命令的輸出結果中,我們可以清晰的看到映象的構建過程。在 Step 2 中,如同我們之前所說的那樣, RUN 指令啟動了一個容器 9cdc27646c7b ,執行了所要求的命令,並最後提交了這一層 44aa4490ce2c ,隨後刪除了所用到的這個容器 9cdc27646c7b 。
在這裡我們指定了最終映象的名稱 -t nginx:v3 ,構建成功後,我們可以直接執行這個映象,其結果就是我們的主頁被改變成了Hello, Docker!。
COPY 複製檔案
語法:
-
COPY <源路徑>... <目標路徑>COPY ["<源路徑1>",... "<目標路徑>"]
注意:
-
<源路徑> 可以是多個,甚至可以是萬用字元,其萬用字元規則要滿足 Go 的 filepath.Match 規則
COPY hom* /mydir/COPY hom?.txt /mydir/
-
<目標路徑> 可以是容器內的絕對路徑,也可以是相對於工作目錄的相對路徑(工作目錄可以用 WORKDIR 指令來指定)。目標路徑不需要事先建立,如果目錄不存在會在複製檔案前先行建立缺失目錄。
-
和 RUN 指令一樣,也有兩種格式,一種類似於命令列,一種類似於函式呼叫。COPY 指令將從構建上下文目錄中 <
源路徑
> 的檔案/目錄複製到新的一層的映象內的 <目標路徑
> 位置。比如:COPY package.json /usr/src/app/
-
使用 COPY 指令,原始檔的各種元資料都會保留。比如讀、寫、執行許可權、檔案變更時間等。這個特性對於映象定製很有用。特別是構建相關檔案都在使用 Git進行管理的時候
ADD 更高階的複製檔案
ADD 指令和 COPY 的格式和性質基本一致。但是在 COPY 基礎上增加了一些功能。比如 <源路徑> 可以是一個 URL ,這種情況下,Docker 引擎會試圖去下載這個連結的檔案放到 <目標路徑> 去。下載後的檔案許可權自動設定為 600 ,如果這並不是想要的許可權,那麼還需要增加額外的一層 RUN 進行許可權調整,另外,如果下載的是個壓縮包,需要解壓縮,也一樣還需要額外的一層 RUN 指令進行解壓縮。所以不如直接使用 RUN 指令,然後使用 wget 或者 curl 工具下載,處理許可權、解壓縮、然後清理無用檔案更合理。因此,這個功能其實並不實用,而且不推薦使用。
如果 <源路徑> 為一個 tar 壓縮檔案的話,壓縮格式為 gzip , bzip2 以及 xz 的情況下, ADD 指令將會自動解壓縮這個壓縮檔案到 <目標路徑> 去。
在某些情況下,這個自動解壓縮的功能非常有用,比如官方映象 ubuntu 中:
FROM scratchADD ubuntu-xenial-core-cloudimg-amd64-root.tar.gz /...
但在某些情況下,如果我們真的是希望複製個壓縮檔案進去,而不解壓縮,這時就不可以使用 ADD 命令了。
但在某些情況下,如果我們真的是希望複製個壓縮檔案進去,而不解壓縮,這時就不可以使用 ADD 命令了。
在 Docker 官方的 Dockerfile 最佳實踐文件 中要求,儘可能的使用 COPY ,因為 COPY 的語義很明確,就是複製檔案而已,而 ADD 則包含了更復雜的功能,其行為也不一定很清晰。最適合使用 ADD 的場合,就是所提及的需要自動解壓縮的場合。
另外需要注意的是, ADD 指令會令映象構建快取失效,從而可能會令映象構建變得比較緩慢。
因此在 COPY 和 ADD 指令中選擇的時候,可以遵循這樣的原則,所有的檔案複製均使用 COPY 指令,僅在需要自動解壓縮的場合使用 ADD 。
CMD 容器啟動命令
語法
CMD 指令的格式和 RUN 相似,也是兩種格式:
# shell 格式: CMD <命令># exec 格式: CMD ["可執行檔案", "引數1", "引數2"...]# 引數列表格式(在指定了 ENTRYPOINT 指令後,用 CMD 指定具體的引數)CMD ["引數1", "引數2"...]
注意
1.容器就是程序。既然是程序,那麼在啟動容器的時候,需要指定所執行的程式及引數。 CMD 指令就是用於指定預設的容器主程序的啟動命令的。
2.在執行時可以指定新的命令來替代映象設定中的這個預設命令,比如, ubuntu 映象預設的CMD 是 /bin/bash ,如果我們直接 docker run -it ubuntu 的話,會直接進入 bash 。我們也可以在執行時指定執行別的命令,如 docker run -it ubuntu cat /etc/os-release 。這就是用 cat /etc/os-release 命令替換了預設的 /bin/bash 命令了,輸出了系統版本資訊。
3.在指令格式上,一般推薦使用 exec
格式,這類格式在解析時會被解析為 JSON 陣列
,因此一定要使用雙引號 "
,而不要使用單引號。
4.如果使用 shell 格式的話,實際的命令會被包裝為 sh -c
的引數的形式進行執行。比如:
CMD echo $HOME
在實際執行中,會將其變更為:
CMD [ "sh", "-c", "echo $HOME" ]
ENTRYPOINT 入口點
ENTRYPOINT 的格式和 RUN 指令格式一樣,分為 exec 格式和 shell 格式。
ENTRYPOINT 的目的和 CMD 一樣,都是在指定容器啟動程式及引數。ENTRYPOINT 在執行時也可以替代,不過比 CMD 要略顯繁瑣,需要通過 docker run 的引數 –entrypoint 來指定。
當指定了 ENTRYPOINT 後, CMD 的含義就發生了改變,不再是直接的執行其命令,而是將CMD 的內容作為引數傳給 ENTRYPOINT 指令,換句話說實際執行時,將變為:
<ENTRYPOINT> "<CMD>"
ENV 設定環境變數
語法:
格式有兩種:
ENV <key> <value>
ENV <key1>=<value1> <key2>=<value2>...
示例:
ENV VERSION=1.0 DEBUG=on \ NAME="Happy Feet"
注意:
下列指令可以支援環境變數展開:
**ADD 、 COPY 、 ENV 、 EXPOSE 、 LABEL 、 USER 、 WORKDIR 、 VOLUME 、 STOPSIGNAL 、 ONBUILD **
VOLUME 定義匿名卷
格式為:
VOLUME ["<路徑1>", "<路徑2>"...]VOLUME <路徑>
之前我們說過,容器執行時應該儘量保持容器儲存層不發生寫操作,對於資料庫類需要儲存動態資料的應用,其資料庫檔案應該保存於卷(volume)中。為了防止執行時使用者忘記將動態檔案所儲存目錄掛載為卷,在 Dockerfile 中,我們可以事先指定某些目錄掛載為匿名卷,這樣在執行時如果使用者不指定掛載,其應用也可以正常執行,不會向容器儲存層寫入大量資料。
VOLUME /data
這裡的 /data 目錄就會在執行時自動掛載為匿名卷,任何向 /data 中寫入的資訊都不會記錄進容器儲存層,從而保證了容器儲存層的無狀態化。當然,執行時可以覆蓋這個掛載設定。比如:
$ docker run -d -v mydata:/data xxxx
在這行命令中,就使用了 mydata 這個命名卷掛載到了 /data 這個位置,替代了 Dockerfile 中定義的匿名卷的掛載配置。
EXPOSE 宣告埠
格式為
EXPOSE <埠1> [<埠2>...]
EXPOSE 指令是宣告執行時容器提供服務埠,這只是一個宣告,在執行時並不會因為這個宣告應用就會開啟這個埠的服務。在 Dockerfile 中寫入這樣的宣告有兩個好處,一個是幫助映象使用者理解這個映象服務的守護埠,以方便配置對映;另一個用處則是在執行時使用隨機埠對映時,也就是 docker run -P 時,會自動隨機對映 EXPOSE 的埠。
此外,在早期 Docker 版本中還有一個特殊的用處。以前所有容器都運行於預設橋接網路中,因此所有容器互相之間都可以直接訪問,這樣存在一定的安全性問題。於是有了一個 Docker 引擎引數 --icc=false ,當指定該引數後,容器間將預設無法互訪,除非互相間使用了 --links 引數的容器才可以互通,並且只有映象中 EXPOSE 所宣告的端口才可以被訪問。這個 --icc=false 的用法,在引入了 docker network 後已經基本不用了,通過自定義網路可以很輕鬆的實現容器間的互聯與隔離。
要將 EXPOSE 和在執行時使用 -p <宿主埠>:<容器埠> 區分開來。 -p ,是對映宿主埠和容器埠,換句話說,就是將容器的對應埠服務公開給外界訪問,而 EXPOSE 僅僅是宣告容器打算使用什麼埠而已,並不會自動在宿主進行埠對映。
WORKDIR 指定工作目錄
格式為
WORKDIR <工作目錄路徑> 。
使用 WORKDIR 指令可以來指定工作目錄(或者稱為當前目錄),以後各層的當前目錄就被改為指定的目錄,如該目錄不存在, WORKDIR 會幫你建立目錄。
之前提到一些初學者常犯的錯誤是把 Dockerfile 等同於 Shell 指令碼來書寫,這種錯誤的理解還可能會導致出現下面這樣的錯誤:
RUN cd /appRUN echo "hello" > world.txt
如果將這個 Dockerfile 進行構建映象執行後,會發現找不到 /app/world.txt 檔案,或者其內容不是 hello 。原因其實很簡單,在 Shell 中,連續兩行是同一個程序執行環境,因此前一個命令修改的記憶體狀態,會直接影響後一個命令;而在 Dockerfile 中,這兩行 RUN 命令的執行環境根本不同,是兩個完全不同的容器。這就是對 Dockerfile 構建分層儲存的概念不瞭解所導致的錯誤。
如果將這個 Dockerfile 進行構建映象執行後,會發現找不到 /app/world.txt 檔案,或者其內容不是 hello 。原因其實很簡單,在 Shell 中,連續兩行是同一個程序執行環境,因此前一個命令修改的記憶體狀態,會直接影響後一個命令;而在 Dockerfile 中,這兩行 RUN 命令的執行環境根本不同,是兩個完全不同的容器。這就是對 Dockerfile 構建分層儲存的概念不瞭解所導致的錯誤。
之前說過每一個 RUN 都是啟動一個容器、執行命令、然後提交儲存層檔案變更。第一層 RUNcd /app 的執行僅僅是當前程序的工作目錄變更,一個記憶體上的變化而已,其結果不會造成任何檔案變更。而到第二層的時候,啟動的是一個全新的容器,跟第一層的容器更完全沒關係,自然不可能繼承前一層構建過程中的記憶體變化。
因此如果需要改變以後各層的工作目錄的位置,那麼應該使用 WORKDIR 指令。
USER 指定當前使用者
格式: USER <使用者名稱>
USER 指令和 WORKDIR 相似,都是改變環境狀態並影響以後的層。 WORKDIR 是改變工作目錄, USER 則是改變之後層的執行 RUN , CMD 以及 ENTRYPOINT 這類命令的身份。當然,和 WORKDIR 一樣, USER 只是幫助你切換到指定使用者而已,這個使用者必須是事先建立好的,否則無法切換。
RUN groupadd -r redis && useradd -r -g redis redisUSER redisRUN [ "redis-server" ]
如果以 root 執行的指令碼,在執行期間希望改變身份,比如希望以某個已經建立好的使用者來執行某個服務程序,不要使用 su 或者 sudo ,這些都需要比較麻煩的配置,而且在 TTY
缺失的環境下經常出錯。建議使用 gosu
# 建立 redis 使用者,並使用 gosu 換另一個使用者執行命令RUN groupadd -r redis && useradd -r -g redis redis# 下載 gosuRUN wget -O /usr/local/bin/gosu "https://github.com/tianon/gosu/releases/download/1.7/gosu-amd64" \ && chmod +x /usr/local/bin/gosu \ && gosu nobody true# 設定 CMD,並以另外的使用者執行CMD [ "exec", "gosu", "redis", "redis-server" ]
練習
FROM openjdk:8-jdk-alpine# Add Maintainer InfoMAINTAINER honux <[email protected]># 設定localeENV LANG en_US.UTF-8ENV LANGUAGE en_US:enENV LC_ALL en_US.UTF-8ENV TZ=Asia/ShanghaiRUN mkdir /app \ mkdir /opt/settings && echo "env=DEV" > /opt/settings/server.propertiesWORKDIR /appCOPY e6-ms-gateway-2.0.0-SNAPSHOT-exec.jar /app/demo.jarCOPY config/* /app/config/EXPOSE 8080ENTRYPOINT ["java", "-Djava.security.egd=file:/dev/./urandom", "-Dserver.port=8080", "-jar","/app/demo.jar"]