首页
如何构建并发布自己的 docker 镜像

我们都知道使用docker pull命令可以从 Docker Hub 或其他仓库中拉取镜像。那么同样我们也可以推送自己的镜像到远程仓库中,这一点跟 Git 比较类似。

Docker CLI 提供了两组命令来完成这个操作。

  • docker build/commit:构建镜像
  • docker pull/push:拉取和推送镜像

整个过程如下图所示。通过docker build/commit命令构建完镜像后,再使用docker push推送到远程仓库。

image_1eme2udnq1psb1kk8b4h1hq159e9.png-27.2kB

构建镜像

前面讲到,在Docker CLI 中构建镜像有两个命令:docker builddocker commit。虽然它们的目的都是构建镜像,但实现的方式却不太一样。而且,很重要的一点是,在实际的使用中,是非常不推荐使用docker commit来构建镜像的。

那我们下面就来介绍一下docker commit以及为什么不推荐使用它来构建镜像。

docker commit 构建镜像步骤

docker commit 的语法格式为:

docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]]

它是基于容器的修改去创建一个镜像的。所以用这种方式去构建镜像,我们首先得有一个容器。下面我们通过一个ubuntu镜像作为一个例子来演示:

Step 1:拉取一个镜像

$ docker pull ubuntu

Step 2: 运行并进入容器

$ docker run --name ubuntu -it ubuntu:latest /bin/bash

Step 3: 对容器做一些修改

$ apt-get update
$ apt-get install vim
$ mkdir /home/test && cd /home/test
$ touch README.md
$ exit

Step 4: 提交修改到镜像

docker commit ubuntu jerrymei/ubuntu:v1

到这里,我们就用docker commit命令构建了一个我们自己的ubuntu镜像,可以使用docker images查看一下。

为什么不推荐使用 docker commit 来构建镜像

为什么说实际使用过程中不推荐使用docker commit来构建镜像呢。就拿刚才的ubuntu作为例子吧,我们使用docker diff ubuntu来对比一下对容器做了哪些修改,结果发现由于命令的执行,很多文件都被改动了:新增(A)、删除(D)、修改(C)。

大家都知道,Linux作为一个文件系统,所有对它进行的操作最终都以文件的改变体现出来。但是根据这些信息,我们是很难知道在容器里面到底执行了什么操作。

image_1emm1mn11cj51ju31r0kq1d165nm.png-327.1kB

使用docker commit意味着所有对镜像的操作都是黑箱操作,生成的镜像也被称为黑箱镜像。换句话说,就是除了制作镜像的人知道执行过什么命令、怎么生成的镜像,别人根本无从得知。而且,即使是这个制作镜像的人,过一段时间后也无法记清具体的操作。这种黑箱镜像的维护工作是非常痛苦的。

另外,后期对镜像修改的话,每一次修改都会让镜像更加臃肿一次,所删除的上一层的东西并不会丢失,会一直如影随形地跟着这个镜像,即使根本无法访问到。这会让镜像更加臃肿。

所以在实际的使用中,我们更多地是用docker build来构建镜像的。下面就介绍一下docker build构建镜像的步骤。

docker build 构建镜像步骤

docker build 的语法格式为:

docker build [OPTIONS] PATH | URL | -

docker build是利用Dockerfile来构建镜像。Dockerfile是一个文本文件,里面包含了一条条指令,比如前面在容器内部做的那些操作。所以它带来了很多好处,比如镜像的透明性。我们对镜像所有的操作都是在Dockerfile中以指令的形式呈现,任何人去看这个描述文件就知道做了什么事情。

另一个好处就是可以进行版本管理。我们通常会把Dockerfile作为项目的一部分放到源码管理库中,也就是说对镜像的操作我们可以随时回溯。它解决了传统运维的不透明性和难以管理性。

在这里我们就不过多介绍Dockerfile了,我们来讲一下刚才的ubuntu例子用docker build怎么去构建。

Step 1:新建一个ubuntu项目,里面包含一个Dockerfile文件

$ mkdir ubuntu && cd ubuntu
$ vi Dockerfile
FROM ubuntu:latest
RUN apt-get update && apt-get install -y vim
RUN mkdir /home/test && cd /home/test
RUN touch README.md

Step 2:构建镜像

docker build -t jerrymei/ubuntu:v1 .

-t 参数是给镜像命名并打标签,通常我们需要命名为我们的仓库名,比如:jerrymei/ubuntu是我在 docker hub 上创建的一个仓库。

如果构建后的镜像没有对应我们的仓库名,可以使用另一个命令docker tag来完成,比如:

docker build -t ubuntu:v1 .
docker tag ubuntu:v1 jerrymei/ubuntu:v1

推送镜像

推送镜像就比较简单了,我们以 Docker Hub 为例。首先我们创建好一个仓库,比如:jerrymei/ubuntu,创建完毕后会提示我们push的操作。

image_1emo2evu73hs19j48agnh79vb1j.png-15.5kB

我们在操作的机器上先使用docker login 登陆到远程仓库,再执行docker push即可。

管理镜像

Dockerfile 文件管理

使用Dockerfile制作镜像,我们需要对Dockerfile文件进行版本管理。对于开源的项目来说,我通常会在 Github 中建立一个库,然后关联到 Dockerhub 的仓库。其他的像Source to Image工具也可以。这样的话,我们就可以跟踪Dockerfile的变更情况。

image_1ep0kalruv5l10tdioi16331psup.png-65kB

在 Dockerhub 项目仓库的 Builds 选项中配置好对应的源代码位置,我们项目主页就会出现一个Dockerfile的分区。

image_1ep0kfvmaeg1of814d41jek1lsm1j.png-102.4kB

镜像版本管理

我们可以利用Tag来对镜像做版本管理。需要注意的是,不要只使用latest标签。我们对镜像的任何修改都需要发布新的 Tag,避免对之前的使用者造成影响。同样,作为镜像的使用者,我们也最好不要使用latest标签,而是找到具体的版本。

参考:

  1. How To Commit Changes To A Docker Image With Examples
  2. 学习Docker,新手最容易犯的11个错误!
  3. Should I use Dockerfiles or image commits?