Docker 创建镜像有多种方式,比如之前介绍过的docker commit 命令可以把我们在容器中的修改保存并生成一个新的镜像,除此之外,我们还可以编写一个Dockerfile,然后根据这个Dockerfile去构建镜像,而Dockerfile包含了生成这个镜像的基本信息。
一个Dockerfile一般由四部分组成:基础镜像信息、维护者信息、镜像操作指令和容器启动时执行指令
首先我们来看一个简单的Dockerfile样例:
FROM scratch
ADD ubuntu-trusty-core-cloudimg-amd64-root.tar.gz /
# a few minor docker-specific tweaks
# see https://github.com/docker/docker/blob/9a9fc01af8fb5d98b8eec0740716226fadb3735c/contrib/mkimage/debootstrap
RUN set -xe \
\
# https://github.com/docker/docker/blob/9a9fc01af8fb5d98b8eec0740716226fadb3735c/contrib/mkimage/debootstrap#L40-L48
&& echo '#!/bin/sh' > /usr/sbin/policy-rc.d \
&& echo 'exit 101' >> /usr/sbin/policy-rc.d \
&& chmod +x /usr/sbin/policy-rc.d \
\
# https://github.com/docker/docker/blob/9a9fc01af8fb5d98b8eec0740716226fadb3735c/contrib/mkimage/debootstrap#L54-L56
&& dpkg-divert --local --rename --add /sbin/initctl \
&& cp -a /usr/sbin/policy-rc.d /sbin/initctl \
&& sed -i 's/^exit.*/exit 0/' /sbin/initctl \
\
# https://github.com/docker/docker/blob/9a9fc01af8fb5d98b8eec0740716226fadb3735c/contrib/mkimage/debootstrap#L71-L78
&& echo 'force-unsafe-io' > /etc/dpkg/dpkg.cfg.d/docker-apt-speedup \
\
# https://github.com/docker/docker/blob/9a9fc01af8fb5d98b8eec0740716226fadb3735c/contrib/mkimage/debootstrap#L85-L105
&& echo 'DPkg::Post-Invoke { "rm -f /var/cache/apt/archives/*.deb /var/cache/apt/archives/partial/*.deb /var/cache/apt/*.bin || true"; };' > /etc/apt/apt.conf.d/docker-clean \
&& echo 'APT::Update::Post-Invoke { "rm -f /var/cache/apt/archives/*.deb /var/cache/apt/archives/partial/*.deb /var/cache/apt/*.bin || true"; };' >> /etc/apt/apt.conf.d/docker-clean \
&& echo 'Dir::Cache::pkgcache ""; Dir::Cache::srcpkgcache "";' >> /etc/apt/apt.conf.d/docker-clean \
\
# https://github.com/docker/docker/blob/9a9fc01af8fb5d98b8eec0740716226fadb3735c/contrib/mkimage/debootstrap#L109-L115
&& echo 'Acquire::Languages "none";' > /etc/apt/apt.conf.d/docker-no-languages \
\
# https://github.com/docker/docker/blob/9a9fc01af8fb5d98b8eec0740716226fadb3735c/contrib/mkimage/debootstrap#L118-L130
&& echo 'Acquire::GzipIndexes "true"; Acquire::CompressionTypes::Order:: "gz";' > /etc/apt/apt.conf.d/docker-gzip-indexes \
\
# https://github.com/docker/docker/blob/9a9fc01af8fb5d98b8eec0740716226fadb3735c/contrib/mkimage/debootstrap#L134-L151
&& echo 'Apt::AutoRemove::SuggestsImportant "false";' > /etc/apt/apt.conf.d/docker-autoremove-suggests
# delete all the apt list files since they're big and get stale quickly
RUN rm -rf /var/lib/apt/lists/*
# this forces "apt-get update" in dependent images, which is also good
# enable the universe
RUN sed -i 's/^#\s*\(deb.*universe\)$/\1/g' /etc/apt/sources.list
# make systemd-detect-virt return "docker"
# See: https://github.com/systemd/systemd/blob/aa0c34279ee40bce2f9681b496922dedbadfca19/src/basic/virt.c#L434
RUN mkdir -p /run/systemd && echo 'docker' > /run/systemd/container
# overwrite this with 'CMD []' in a dependent Dockerfile
CMD ["/bin/bash"]
Dockerfile 的注释以 ‘#’ 开头
Dockerfile 的第一句非注释指令是基础镜像信息,用 FROM 关键字指定,比如这里的 FROMscratch 表示该镜像是在 scratch镜像基础上制作的
ADD 关键字可以把宿主机的文件添加到镜像中的指定位置, ADD ubuntu-trusty-core-cloudimg-amd64-root.tar.gz /
表示把宿主机中ubuntu-trusty-core-cloudimg-amd64-root.tar.gz 复制到容器中的 / 目录下
RUN 关键字可以用来运行shell命令,每一个RUN关键字会提交一次(相当于docker commit一次),产生一个层(Layer),所以如果不想有太多的层,应该在一个RUN关键字下执行多个命令,比如
RUN mkdir -p /run/systemd && echo 'docker' > /run/systemd/container
这条RUN命令 就执行了 mkdir 和 echo 两个shell命令
CMD 指令指定容器运行时默认执行的命令,当你在启动容器时没有明确指定执行的COMMAND时就会使用该CMD
常用指令介绍
1.FROM
指定所创建镜像的基础镜像,如果本地不存在,则默认会去Docker Hub下载指定镜像。
格式为FROM <image>,或FROM <image>:<tag>,或FROM <image>@<digest>。
2.RUN
运行指定命令。
格式为RUN <command>或 RUN ["executable","param1","param2"]。注意,后一个指令会被解析为Json数组,因此必须用
双引号。前者默认将在shell终端中运行命令,即/bin/sh -c;后者则使用exec执行,不会启动shell环境。
指定使用其他终端类型可以通过第二种方式实现,例如RUN ["/bin/bash","-c","echo hello"]。
每条RUN指令将在当前镜像的基础上执行指定命令,并提交为新的镜像。当命令较长时可以使用\来换行。
3.CMD
CMD指令用来指定启动容器时默认执行的命令。它支持三种格式:
CMD ["executable","param1","param2"] 使用exec执行,是推荐使用的方式;
CMD command param1 param2 在/bin/sh中执行,提供给需要交互的应用;
CMD ["param1","param2"]提供给ENTRYPOINT的默认参数。
每个Dockerfile只能有一条CMD命令。如果指定了多条命令,只有最后一条会被执行。
如果用户启动容器时手动指定了运行的命令(作为run的参数),则会覆盖掉CMD指定的命令。
4.LABEL
LABEL指令用来指定生成镜像的元数据标签信息。
格式为LABEL<key>=<value><key>=<value><key>=<value>...。
例如:
LABEL maintainer="SvenDowideit@home.org.au"
来指定作者
5.EXPOSE
声明镜像内服务所监听的端口。
格式为EXPOSE <port> [<port>...]。
例如:
EXPOSE 22 80
注意,该指令只是起到声明作用,并不会自动完成端口映射。
6.ENV
指定环境变量,在镜像生成过程中会被后续RUN指令使用,在镜像启动的容器中也会存在。
格式为ENV <key> <value> 或 ENV <key>=<value>...。
例如:
ENV VERSION 14.04
7.ADD
该命令将复制指定的<src>路径下的内容到容器中的<dest>路径下。
格式为ADD <src> <dest>。
其中<src>可以是Dockerfile所在目录的一个相对路径(文件或目录),也可以是一个URL,还可以是
一个tar文件(如果为tar文件,会自动解压到<dest>路径下)。
<dest>可以是镜像内的绝对路径,或者相对于工作目录(WORKDIR)的相对路径。
8.COPY
格式为COPY <src> <dest>。
COPY 命令和ADD 非常类似,只是COPY命令只支持把宿主机的文件拷贝到镜像中,一般这种情况下推荐使用COPY命令。
目标路径不存在时,会自动创建。
9.WORKDIR
为后续的RUN、CMD和ENTRYPOINT指令配置工作目录。
格式为WORKDIR/path/to/workdir。
可以使用多个WORKDIR指令,后续命令如果参数是相对路径,则会基于之前命令指定的路径。
完整的指令请查阅:Dockerfile reference
接下来,我们使用 centos:6.9 作为基础镜像,搭建一个Nginx镜像
Dockerfile:
#设置基础镜像
FROM centos:6.9
#作者信息
LABEL maintainer=zhangy@tv189.com
#开放端口
EXPOSE 80
#安装Nginx
RUN yum makecache && yum install -y --nogpgcheck epel-release && yum install -y --nogpgcheck nginx
#关闭Nginx守护进程
RUN sed -in '3a daemon off;' /etc/nginx/nginx.conf
#启动Nginx
CMD ["/usr/sbin/nginx", "-c", "/etc/nginx/nginx.conf"]
然后使用docker build 命令来构建镜像
[root@localhost sshd_ubuntu]# docker build --help
Usage: docker build [OPTIONS] PATH | URL | -
Build a new image from the source code at PATH
-c, --cpu-shares=0 CPU shares (relative weight)
--cgroup-parent= Optional parent cgroup for the container
--cpu-period=0 Limit the CPU CFS (Completely Fair Scheduler) period
--cpu-quota=0 Limit the CPU CFS (Completely Fair Scheduler) quota
--cpuset-cpus= CPUs in which to allow execution (0-3, 0,1)
--cpuset-mems= MEMs in which to allow execution (0-3, 0,1)
-f, --file= Name of the Dockerfile (Default is 'PATH/Dockerfile')
--force-rm=false Always remove intermediate containers
--help=false Print usage
-m, --memory= Memory limit
--memory-swap= Total memory (memory + swap), '-1' to disable swap
--no-cache=false Do not use cache when building the image
--pull=false Always attempt to pull a newer version of the image
-q, --quiet=false Suppress the verbose output generated by the containers
--rm=true Remove intermediate containers after a successful build
-t, --tag= Repository name (and optionally a tag) for the image
在Dockerfile所在的目录执行 docker build -t lamp:nginx .
[root@localhost sshd_ubuntu]# ls
Dockerfile
[root@localhost sshd_ubuntu]# docker build -t lnmp:nginx .
Sending build context to Docker daemon 2.048 kB
Sending build context to Docker daemon
Step 0 : FROM centos:6.9
---> e071bce628ba
Step 1 : LABEL maintainer zhangy@tv189.com
---> Using cache
---> 0d618389ca76
Step 2 : EXPOSE 80
---> Using cache
---> fc6a935299ab
Step 3 : RUN yum makecache && yum install -y --nogpgcheck epel-release && yum install -y --nogpgcheck nginx
---> Running in 62cacd14c2ed
Loaded plugins: fastestmirror, ovl
............
Complete!
---> ad23365869fb
Removing intermediate container 62cacd14c2ed
Step 4 : RUN sed -in '3a daemon off;' /etc/nginx/nginx.conf
---> Running in b763f003f645
---> 302402a29363
Removing intermediate container b763f003f645
Step 5 : CMD /usr/sbin/nginx -c /etc/nginx/nginx.conf
---> Running in b0c755098664
---> 7befb6b4f77a
Removing intermediate container b0c755098664
Successfully built 7befb6b4f77a
看到 Successfully build xxx 表示构建成功,使用docker images 查看
[root@localhost sshd_ubuntu]# docker images
REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE
lnmp nginx 7befb6b4f77a 46 seconds ago 948.1 MB
nginx myself ffbf82fc975d 3 hours ago 108.3 MB
ubuntu sshd2 f5e51900b258 8 hours ago 382.9 MB
centos 6.9 e071bce628ba 3 weeks ago 194.7 MB
php 5.6.32-fpm 57a62c38abf7 4 weeks ago 369.2 MB
nginx latest 2ecc072be0ec 7 weeks ago 108.3 MB
ubuntu 14.04 b44ce450cb60 10 weeks ago 188 MB
quay.io/coreos/etcd v3.0.4 3b17a5f34e6c 16 months ago 43.3 MB
测试运行该镜像
[root@localhost sshd_ubuntu]# docker run -d -p 8080:80 lnmp:nginx
f49435d6ccb956cad18535a3b40fa8c89d1fbd14e6d3e326e175221823d23858
[root@localhost sshd_ubuntu]# docker ps --no-trunc
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
f49435d6ccb956cad18535a3b40fa8c89d1fbd14e6d3e326e175221823d23858 lnmp:nginx "/usr/sbin/nginx -c /etc/nginx/nginx.conf" 14 seconds ago Up 14 seconds 0.0.0.0:8080->80/tcp happy_einstein
[root@localhost sshd_ubuntu]# curl '127.0.0.1:8080'
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<title>Test Page for the Nginx HTTP Server on EPEL</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<style type="text/css">
/*<![CDATA[*/
body {
background-color: #fff;
这样一个基于centos的nginx镜像就构建好了,你可以把该镜像push到Docker Hub上供别人下载使用 :)
That's it!