本文主要討論的是Docker鏡像(image)的創建,以下實驗參考自Sébastien Goasguen撰寫的Docker Cookbook (ISBN 978-1-491-91971-2)第二章Page37~Page43。

具體章節為 * 2.1 Keeping Changes Made to a Container by Committing to an Image * 2.2 Saving Images and Containers as Tar Files for Sharing * 2.3 Writing Your First Dockerfile

創建鏡像,主要有如下幾種方式 * docker commit:基於變化的容器(container)創建鏡像(image) * docker exportdocker importdocker savedocker load: 通過tarball(tar歸檔文件)創建鏡像(image) * Dockerfile: 通過Dockerfile自動創建鏡像

以下是相關命令 * docker commit: Create a new image from a container’s changes * docker save: Save an image(s) to a tar archive (streamed to STDOUT by default) * docker load: Load an image from a tar archive or STDIN * docker import: Import the contents from a tarball to create a filesystem image * docker import [OPTIONS] file|URL|- [REPOSITORY[:TAG]] * docker export: Export a container’s filesystem as a tar archive * docker build: Build an image from a Dockerfile * docker diff: Inspect changes on a container’s filesystem * docker run: Run a command in a new container

本文使用的Docker image是alpine,使用命令docker pull alpine即可下載,以下操作過程是連貫進行的。

Committing a image from changed container

在對容器進行操作並退出容器後,使用docker commit提交變化後的容器,創建新鏡像,鏡像名稱由 名稱tag 組成,如ubuntu:update

使用docker commit創建鏡像,使用docker diff檢查容器的變化

官方文檔 * docker commit * docker diff

操作過程

#查看名爲alpine的鏡像
[flying@lemp ~]$ docker images | grep alpine
alpine                 latest              d7a513a663c1        4 days ago          4.794 MB

#以交互模式運行鏡像
[flying@lemp ~]$ docker run -ti alpine /bin/sh
/ # mkdir -pv data
created directory: 'data'

#創建測試文件
/ # echo 'Docker commit test.' > data/test.txt
/ # ls data/
test.txt

#退出容器
/ # exit

#查看容器ID
[flying@lemp ~]$ docker ps -qa
5652d1f5af0c

#創建名爲alpine,tag 爲update的鏡像
[flying@lemp ~]$ docker commit 5652d1f5af0c alpine:update
sha256:f5c52e7026bc835b67ea9cc3c9ee772898673ac8cfed3fc0d2d984106256ace1

#再次查看名爲alpine的鏡像
[flying@lemp ~]$ docker images | grep alpine
alpine                 update              f5c52e7026bc        11 seconds ago      4.794 MB
alpine                 latest              d7a513a663c1        4 days ago          4.794 MB

#運行鏡像alpine:update
[flying@lemp ~]$ docker run -ti alpine:update /bin/sh
/ # ls data/
test.txt
/ # cat data/test.txt
Docker commit test.
/ # exit

#使用diff檢查容器的變化
[flying@lemp ~]$ docker diff 5652d1f5af0c
A /data
A /data/test.txt
C /root
A /root/.ash_history
[flying@lemp ~]$

可以看到,執行docker commit後,使用docker images新生成了名爲alpine,tag爲update的鏡像。

Saving Images and Containers as Tar Files

官方文檔 * Docker export * Docker import * Docker save * Docker load

docker export

docker export是對容器進行操作

[flying@lemp ~]$ docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                      PORTS               NAMES
5e622fac95e0        alpine:update       "/bin/sh"           10 minutes ago      Exited (0) 9 minutes ago                        mad_wescoff
5652d1f5af0c        alpine              "/bin/sh"           12 minutes ago      Exited (0) 11 minutes ago                       condescending_banach

#根據容器ID將容器導出爲tar文件
[flying@lemp ~]$ docker export 5e622fac95e0 > alpine_update.tar
[flying@lemp ~]$ ls -lh alpine_update.tar
-rw-rw-r-- 1 flying flying 4.9M Apr  6 12:28 alpine_update.tar
[flying@lemp ~]$

docker import

docker commit是基於變化的容器創建新的鏡像,而docker import是通過tarball創建鏡像

用法: docker import [OPTIONS] file|URL|- [REPOSITORY[:TAG]]

通過alpine_update.tar創建名爲lemp,tag爲stacker的鏡像

操作過程

[flying@lemp ~]$ ls -lh alpine_update.tar
-rw-rw-r-- 1 flying flying 4.9M Apr  6 12:28 alpine_update.tar

#將tar文件導入,創建名爲lemp,tag爲stacker的鏡像
[flying@lemp ~]$ docker import - lemp:stacker < alpine_update.tar
sha256:0f3c7cc12056ede4ff348d46a8d3bbe41df5ca3b08123e14b104befc692f9b59
[flying@lemp ~]$ docker images | grep lemp
lemp                   stacker             0f3c7cc12056        8 seconds ago       4.794 MB
[flying@lemp ~]$

docker save

docker save對鏡像進行操作,創建tarball

docker save * -o, --output: Write to a file, instead of STDOUT

操作過程

#將鏡像lemp:stacker保存爲名爲lemp.tar的tarball
[flying@lemp ~]$ docker save -o lemp.tar lemp:stacker
[flying@lemp ~]$ ls -lh *.tar
-rw-rw-r-- 1 flying flying 4.9M Apr  6 12:28 alpine_update.tar
-rw-rw-r-- 1 flying flying 4.9M Apr  6 12:37 lemp.tar

#移除鏡像lemp:stacker
[flying@lemp ~]$ docker rmi lemp:stacker
Untagged: lemp:stacker
Deleted: sha256:0f3c7cc12056ede4ff348d46a8d3bbe41df5ca3b08123e14b104befc692f9b59
Deleted: sha256:9ab7ea657f1eea768576b31b1697b4aaa7e8ae61fd73663c55d1096294033733
[flying@lemp ~]$ docker images | grep lemp
[flying@lemp ~]$

docker load

類似docker import

docker load * -i, --input: Read from a tar archive file, instead of STDIN

操作過程

  • 使用選項-i ``` [flying@lemp ~]$ docker images | grep lemp

#使用參數-i導入lemp.tar [flying@lemp ~]$ docker load -i lemp.tar [flying@lemp ~]$ docker images | grep lemp lemp stacker 0f3c7cc12056 9 minutes ago 4.794 MB [flying@lemp ~]$


* 使用重定向符號`<`

[flying@lemp ~]$ docker rmi lemp:stacker Untagged: lemp:stacker Deleted: sha256:0f3c7cc12056ede4ff348d46a8d3bbe41df5ca3b08123e14b104befc692f9b59 Deleted: sha256:9ab7ea657f1eea768576b31b1697b4aaa7e8ae61fd73663c55d1096294033733 [flying@lemp ~]$ docker images | grep lemp

#使用符號<導入lemp.tar [flying@lemp ~]$ docker load < lemp.tar [flying@lemp ~]$ docker images | grep lemp lemp stacker 0f3c7cc12056 10 minutes ago 4.794 MB [flying@lemp ~]$


## Using Dockerfile Automate Building images

>Docker can build images automatically by reading the instructions from a Dockerfile. A Dockerfile is a text document that contains all the commands a user could call on the command line to assemble an image. Using docker build users can create an automated build that executes several command-line instructions in succession. -- [Dockerfile reference](https://docs.docker.com/engine/reference/builder/)

官方文檔
* [Dockerfile reference](https://docs.docker.com/engine/reference/builder/)

文件`Dockerfile`創建完成後,使用`docker build`來創建鏡像,文件`Dockerfile`可在當前目錄下,也可在其它目錄下,手動指定目錄路徑即可。

* `docker build`: Build an image from a Dockerfile
    * `-f, --file`: Name of the Dockerfile (Default is 'PATH/Dockerfile')
    * `-t, --tag=[]`: Name and optionally a tag in the 'name:tag' format

**重要**

在`Dockerfile`中,需注意`CMD`和`ENTRYPOINT`的區別
* `ENTRYPOINT`: 指定可執行二進制命令,在容器啓動時執行,目的明確,可理解爲該鏡像 **專用於** 某具體命令
* `CMD`: 非專用於某具體命令,其不僅可指定命令,也可指定命令參數

在執行`docker run`運行容器時
* `ENTRYPOINT`: 該命令不會被其它命令覆蓋,除非顯式指定`--entrypoint`
    * `--entrypoint`: Overwrite the default ENTRYPOINT of the image
* `CMD`: 如果指定新命令,該命令會被覆蓋

一個命令被執行後,會創建一個容器,如果想在容器中運行進程,須在前端進行,否則容器會自動關閉。

在目錄`/tmp`下創建`Dockerfile`文件,執行`docker build`時,使用`-t`顯式指定名稱和tag。


操作過程

### ENTRYPOINT
在當前目錄

#創建文件Dockerfile,運行容器時直接調用/bin/echo命令 [flying@lemp ~]$ cd /tmp [flying@lemp tmp]$ ls [flying@lemp tmp]$ vim Dockerfile [flying@lemp tmp]$ cat Dockerfile FROM alpine:latest

ENTRYPOINT [“/bin/echo”]

#創建鏡像,指定名稱爲buildtest,tag爲lastest,在當前目錄,別忘了加點.表示當前目錄 [flying@lemp tmp]$ docker build -t buildtest:lastest . Error checking context: ‘can’t stat ‘/tmp/.netdata-charts.d-PXuxDGzuov”. [flying@lemp tmp]$ sudo docker build -t buildtest:lastest . Sending build context to Docker daemon 20.99 kB Step 1 : FROM alpine:latest —> d7a513a663c1 Step 2 : ENTRYPOINT /bin/echo —> Running in df25f77901c7 —> 9d6b923e61c3 Removing intermediate container df25f77901c7 Successfully built 9d6b923e61c3 [flying@lemp tmp]$ docker images | grep 9d6b923e61c3 buildtest lastest 9d6b923e61c3 About a minute ago 4.794 MB

#通過鏡像ID運行 [flying@lemp tmp]$ docker run 9d6b923e61c3 Love you, My lover! Love you, My lover! [flying@lemp tmp]$ docker run 9d6b923e61c3

[flying@lemp tmp]$ #通過鏡像名稱運行 [flying@lemp tmp]$ docker run buildtest:lastest Love you, My lover! Love you, My lover! [flying@lemp tmp]$ docker run buildtest:lastest

[flying@lemp tmp]$

#指定–entrypoint [flying@lemp tmp]$ docker run buildtest:lastest –entrypoint=/bin/date –entrypoint=/bin/date [flying@lemp tmp]$ docker run –entrypoint=/bin/date buildtest:lastest Wed Apr 6 05:18:27 UTC 2016 [flying@lemp tmp]$


注意: `--entrypoint`必須在鏡像名稱或ID之前


### CMD
在當前目錄,使用`CMD`

[flying@lemp tmp]$ cat Dockerfile FROM alpine:latest

CMD [“/bin/echo” , “Love you!”]

#創建鏡像 [flying@lemp tmp]$ sudo docker build -t buildcmd:latest . Sending build context to Docker daemon 20.99 kB Step 1 : FROM alpine:latest —> d7a513a663c1 Step 2 : CMD /bin/echo Love you! —> Running in 2280f8818eb4 —> b39128e23625 Removing intermediate container 2280f8818eb4 Successfully built b39128e23625 [flying@lemp tmp]$ docker images | grep b39128e23625 buildcmd latest b39128e23625 14 seconds ago 4.794 MB

#通過鏡像ID運行鏡像 [flying@lemp tmp]$ docker run b39128e23625 Love you!

#通過鏡像名運行鏡像 [flying@lemp tmp]$ docker run buildcmd:latest Love you!

#在命令後加參數 [flying@lemp tmp]$ docker run buildcmd Wonderful day! exec: “Wonderful”: executable file not found in $PATH docker: Error response from daemon: Container command not found or does not exist..

#在命令後加參數 [flying@lemp tmp]$ docker run buildcmd /bin/date Wed Apr 6 05:22:30 UTC 2016 [flying@lemp tmp]$


可以看到在加上命令`/bin/date`後,打印出了容器中的系統時間,說明`CMD`中指定的命令可被覆蓋。



`Dockerfile`不在當前目錄

[flying@lemp ~]$ pwd /home/flying [flying@lemp ~]$ cat /tmp/Dockerfile FROM alpine:latest

CMD [“/bin/echo” , “Love you!”]

#指定Dockerfile所在路徑 [flying@lemp ~]$ sudo docker build -t buildoutside:latest /tmp Sending build context to Docker daemon 20.99 kB Step 1 : FROM alpine:latest —> d7a513a663c1 Step 2 : CMD /bin/echo Love you! —> Running in 45b127c4d0b8 —> d06a4dbd0a28 Removing intermediate container 45b127c4d0b8 Successfully built d06a4dbd0a28 [flying@lemp ~]$ docker images | grep d06a4dbd0a28 buildoutside latest d06a4dbd0a28 12 seconds ago 4.794 MB [flying@lemp ~]$ docker run d06a4dbd0a28 Love you! [flying@lemp ~]$ docker run buildoutside Love you! [flying@lemp ~]$ docker run buildoutside /bin/date Wed Apr 6 05:28:08 UTC 2016 [flying@lemp ~]$ ```

額外提一句 >A tag is optional. If you do not specify a tag, Docker will implicitly try to use a tag called latest . If such a tag for the image being referenced does not exist in the repository, Docker will fail to download the image. –Docker Cookbook page48

於容器而言,tag是可選項,如果未顯式指定,則默認爲latest

CentOS官方为Dockerfiles建有一个GitHub仓库,里面有许多基于CentOS系统的Dockerfile文件。CentOS-Dockerfiles


Change Log

  • 2016.04.06 13:31 Wed Asia/Beijing
    • 初稿完成

  • Note Time: 2016.04.06 13:31 Wed
  • Note Location: Asia/Beijing
  • Writer: lempstacker