对于 Docker 用户来说,最好的情况是不需要自己创建镜像。几乎所有常用的数据库、中间件、应用软件等都有现成的 Docker 官方镜像或其他人和组织创建的镜像,我们只需要稍作配置就可以直接使用。 使用现成镜像的好处除了省去自己做镜像的工作量外,更重要的是可以利用前人的经验。特别是使用那些官方镜像,因为 Docker 的工程师知道如何更好的在容器中运行软件。 当然,某些情况下我们也不得不自己构建镜像,比如: 1. 找不到现成的镜像,比如自己开发的应用程序。 2. 需要在镜像中加入特定的功能,比如官方镜像几乎都不提供 ssh。 所以本节我们将介绍构建镜像的方法。同时分析构建的过程也能够加深我们对前面镜像分层结构的理解。 Docker 提供了两种构建镜像的方法: 1. docker commit 命令 2. Dockerfile 构建文件 docker commit docker commit 命令是创建新镜像最直观的方法,其过程包含三个步骤: 1. 运行容器 2. 修改容器 3. 将容器保存为新的镜像 举个例子:在 centos base 镜像中安装 vim 并保存为新镜像。 1. 第一步, 运行容器 root@ubuntu:~# docker run -it centos [root@0e18d71acfc9 /]# vim bash: vim: command not found 2. 第二步,安装vim [root@0e18d71acfc9 /]# yum install vim 3.第三步,保存为新镜像 root@ubuntu:~# docker container list CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 0e18d71acfc9 centos "/bin/bash" 13 minutes ago Up 13 minutes vibrant_bartik root@ubuntu:~# docker commit vibrant_bartik centos-with-vim root@ubuntu:~# docker images centos-with-vim REPOSITORY TAG IMAGE ID CREATED SIZE centos-with-vim latest 784c09cb21e9 6 minutes ago 355MB 4,第四步,确认OK root@ubuntu:~# docker images centos-with-vim REPOSITORY TAG IMAGE ID CREATED SIZE centos-with-vim latest 784c09cb21e9 55 seconds ago 355MB root@ubuntu:~# docker run -it centos-with-vim [root@f8d4115aaba5 /]# vim [root@f8d4115aaba5 /]# which vim /usr/bin/vim root@ubuntu:~# cat Dockerfile FROM centos RUN yum install vim -y #创建目标是centos-with-vim-by-dockerfile的镜像 从.搜索dockerfile #经验:dockerfile不要放在/或者/usr下,否则创建过程会缓慢 root@ubuntu:~# docker build -t centos-with-vim-by-dockerfile . Sending build context to Docker daemon 25.09kB Step 1/2 : FROM centos ---> 36540f359ca3 Step 2/2 : RUN yum install vim -y ---> Running in ed8192367e3c ...... ...... Complete! ---> b432585c3309 Removing intermediate container ed8192367e3c #删除临时容器 Successfully built b432585c3309 #创建成功,可和docker images结果比对 Successfully tagged centos-with-vim-by-dockerfile:latest root@ubuntu:~# docker images REPOSITORY TAG IMAGE ID CREATED SIZE centos-with-vim-by-dockerfile latest b432585c3309 8 seconds ago 355MB centos-with-vim latest 784c09cb21e9 17 minutes ago 355MB <none> <none> 6f41b997b02b 3 days ago 355MB httpd latest e0ceae115daa 10 days ago 177MB centos latest 36540f359ca3 2 weeks ago 193MB hello-world latest 1815c82652c0 5 weeks ago 1.84kB #查看docker创建镜像的history root@ubuntu:~# docker history centos-with-vim-by-dockerfile IMAGE CREATED CREATED BY SIZE COMMENT b432585c3309 5 minutes ago /bin/sh -c yum install vim -y 162MB 36540f359ca3 2 weeks ago /bin/sh -c #(nop) CMD ["/bin/bash"] 0B <missing> 2 weeks ago /bin/sh -c #(nop) LABEL name=CentOS Base ... 0B <missing> 2 weeks ago /bin/sh -c #(nop) ADD file:23c65acc4aae2af... 193MB root@ubuntu:~# cat Dockerfile FROM centos RUN yum install vim -y COPY testfile / root@ubuntu:~# cat testfile test root@ubuntu:~# docker build -t centos-with-vim-by-dockerfile-version02 . Sending build context to Docker daemon 26.11kB Step 1/3 : FROM centos ---> 36540f359ca3 Step 2/3 : RUN yum install vim -y ---> Using cache #缓存特性,如果docker file内容变化,则不会用此缓存,哪怕只是顺序的改变 ---> b432585c3309 Step 3/3 : COPY testfile / ---> 2a0b28b04f3c Removing intermediate container a1fd7cbb591a Successfully built 2a0b28b04f3c Successfully tagged centos-with-vim-by-dockerfile-version02:latest dockerfile调试: root@ubuntu:~# docker build -t image-debug . Sending build context to Docker daemon 30.21kB Step 1/4 : FROM busybox ---> efe10ee6727f Step 2/4 : RUN touch tmpfile ---> Running in a97ccdea299d ---> 48359bfa38a3 #第三步报错可用第二步的缓存进行调试 Removing intermediate container a97ccdea299d Step 3/4 : RUN /bin/bash -c echo "continue to build....." ---> Running in ec4d96bc56d5 /bin/sh: /bin/bash: not found The command '/bin/sh -c /bin/bash -c echo "continue to build....."' returned a non-zero code: 127 root@ubuntu:~# docker run -it 48359bfa38a3 / # /bin/bash -c echo "continue to build....." sh: /bin/bash: not found / # /bin/bash -c echo "continue to build....."^C debug: root@ubuntu:~# docker run -it 48359bfa38a3 ...... 手工执行 RUN 指令很容易定位失败的原因是 busybox 镜像中没有 bash。虽然这是个极其简单的例子,但它很好地展示了调试 Dockerfile 的方法。 FROM 指定 base 镜像。 MAINTAINER 设置镜像的作者,可以是任意字符串。 COPY 将文件从 build context 复制到镜像。 COPY 支持两种形式: COPY src dest COPY ["src", "dest"] 注意:src 只能指定 build context 中的文件或目录。 ADD 与 COPY 类似,从 build context 复制文件到镜像。不同的是,如果 src 是归档文件(tar, zip, tgz, xz 等),文件会被自动解压到 dest。 ENV 设置环境变量,环境变量可被后面的指令使用。例如: ... ENV MY_VERSION 1.3 RUN apt-get install -y mypackage=$MY_VERSION ... 常用命令: EXPOSE 指定容器中的进程会监听某个端口,Docker 可以将该端口暴露出来。我们会在容器网络部分详细讨论。 VOLUME 将文件或目录声明为 volume。我们会在容器存储部分详细讨论。 WORKDIR 为后面的 RUN, CMD, ENTRYPOINT, ADD 或 COPY 指令设置镜像中的当前工作目录。 RUN 在容器中运行指定的命令。 CMD 容器启动时运行指定的命令。 Dockerfile 中可以有多个 CMD 指令,但只有最后一个生效。CMD 可以被 docker run 之后的参数替换。 ENTRYPOINT 设置容器启动时运行的命令。 Dockerfile 中可以有多个 ENTRYPOINT 指令,但只有最后一个生效。CMD 或 docker run 之后的参数会被当做参数传递给 ENTRYPOINT。 017:RUN CMD ENTRYPOINT 018:镜像命名[image name] = [repository]:[tag] 019: docker hub,username:dockerforwjw #login root@ubuntu:~# docker login -u dockerforwjw Password: Login Succeeded #查看本地镜像 root@ubuntu:~# docker images REPOSITORY TAG IMAGE ID CREATED SIZE image-debug latest 3fe0ec534582 9 hours ago 1.13MB centos-with-vim-by-dockerfile-version02 latest 2a0b28b04f3c 31 hours ago 355MB centos-with-vim-by-dockerfile latest b432585c3309 31 hours ago 355MB centos-with-vim latest 784c09cb21e9 31 hours ago 355MB busybox latest efe10ee6727f 3 days ago 1.13MB <none> <none> 6f41b997b02b 4 days ago 355MB httpd latest e0ceae115daa 11 days ago 177MB centos latest 36540f359ca3 2 weeks ago 193MB hello-world latest 1815c82652c0 5 weeks ago 1.84kB #打标记 root@ubuntu:~# docker tag httpd dockerforwjw/httpd:v1 #打标记后再次查看 #root@ubuntu:~# docker images REPOSITORY TAG IMAGE ID CREATED SIZE image-debug latest 3fe0ec534582 9 hours ago 1.13MB centos-with-vim-by-dockerfile-version02 latest 2a0b28b04f3c 31 hours ago 355MB centos-with-vim-by-dockerfile latest b432585c3309 31 hours ago 355MB centos-with-vim latest 784c09cb21e9 31 hours ago 355MB busybox latest efe10ee6727f 3 days ago 1.13MB <none> <none> 6f41b997b02b 4 days ago 355MB dockerforwjw/httpd v1 e0ceae115daa 11 days ago 177MB httpd latest e0ceae115daa 11 days ago 177MB centos latest 36540f359ca3 2 weeks ago 193MB hello-world latest 1815c82652c0 5 weeks ago 1.84kB #上传和下载 root@ubuntu:~# docker push dockerforwjw/httpd:v1 The push refers to a repository [docker.io/dockerforwjw/httpd] cf8213cf12e6: Mounted from library/httpd 4cea9efa0efd: Mounted from library/httpd 88100ed9d5fc: Mounted from library/httpd a7090b99c87f: Mounted from library/httpd ca4b576930e7: Mounted from library/httpd 27c884880e0f: Mounted from library/httpd 0d960f1d4fba: Mounted from library/httpd v1: digest: sha256:1989458ded44c5cfdb4e5b4e37ac435937564d52450db79c972b1b59dda0c7db size: 1780 root@ubuntu:~# docker pull dockerforwjw/httpd:v1 v1: Pulling from dockerforwjw/httpd Digest: sha256:1989458ded44c5cfdb4e5b4e37ac435937564d52450db79c972b1b59dda0c7db Status: Image is up to date for dockerforwjw/httpd:v1 020.private docker registry #用官方提供的镜像运行服务 root@ubuntu:~# docker run -d -p 5000:5000 -v /myregistry:/var/lib/registry registry:2 Unable to find image 'registry:2' locally 2: Pulling from library/registry 90f4dba627d6: Pull complete 3a754cdc94a5: Pull complete bf16d9b6d4c1: Pull complete 7eea83c9b7bb: Pull complete 23293c727551: Pull complete Digest: sha256:f5552e60ffd56fecbe2f04b61a3089a9cd755bd9352b6b5ab22cf2208af6a3a8 Status: Downloaded newer image for registry:2 d19d1c95874feb3c5d2f44f21931bc61d22767aa00c17b21bd7e2367c7045a3c #打标记 root@ubuntu:~# docker tag dockerforwjw/httpd:v1 127.0.0.1:5000/dockerforwjw/httpd:v1 #push root@ubuntu:~# docker push 127.0.0.1:5000/dockerforwjw/httpd:v1 The push refers to a repository [127.0.0.1:5000/dockerforwjw/httpd] cf8213cf12e6: Pushed 4cea9efa0efd: Pushed 88100ed9d5fc: Pushed a7090b99c87f: Pushed ca4b576930e7: Pushed 27c884880e0f: Pushed 0d960f1d4fba: Pushed v1: digest: sha256:a11a4ea20a7060ecee8c1c6a9406f22f09bc56d9aff0bccc7b54143d9cf8c66a size: 1780 #pull root@ubuntu:~# docker pull 127.0.0.1:5000/dockerforwjw/httpd:v1 v1: Pulling from dockerforwjw/httpd Digest: sha256:a11a4ea20a7060ecee8c1c6a9406f22f09bc56d9aff0bccc7b54143d9cf8c66a Status: Image is up to date for 127.0.0.1:5000/dockerforwjw/httpd:v1