制作镜像的最佳实践

本文以制作基于centos的nginx镜像为例,来说明如何做一个可控的镜像。

step 1. 先基于centos的基础镜像,启动一个叫mynginx的容器

1
$ docker run -it --name mynginx centos /bin/bash

step 2. 基于该容器做镜像改造,以下操作是在容器内操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 新建 nginx yum仓库文件
$ cat > /etc/yum.repos.d/nginx.repo <<EOF
[nginx]
name=nginx repo
baseurl=http://nginx.org/packages/centos/7/\$basearch/
gpgcheck=0
enabled=1
EOF
# 安装 Nginx, -y 表示自动确认
$ yum -y install nginx
# 顺便修改下主页文件
$ echo '<h1>Hello, Docker!</h1>' > /usr/share/nginx/html/index.html
# 退出容器,我们容器部分的安装就算完成了
$ exit

当然如果简单的话,可以直接写到 Dockerfile 中,这种方式适合哪种对Dockerfile的各种奇葩语法搞不懂,需要copy各种数据,安装软件比较复杂,例如需要编译需要各种依赖等等。等同于你拿到一个全新的系统做的一些初始化工作,能变成你们公司的基础镜像,后续的镜像都可以基于这个镜像来构建。

step 3. 在宿主机上提交这个容器,使它变成一个镜像

1
2
3
4
# 提交前可以看下相对于镜像更新了哪些文件
$ docker diff mynginx
# 用commit命令提交成一个名字叫做mynginx镜像
$ docker commit -a 'michael<mching.08@gmail.com>' -m'install nginx' mynginx mynginx

step 4. 使用 DockerFile 构建最终的镜像, dockerfile的的内容如下

新建一个文件夹/tmp/mknginx,编写Dockerfile,名字一定是这个。

1
2
3
4
5
FROM mynginx

EXPOSE 80
# 包装一层启动命令
CMD ["nginx", "-g", "daemon off;"]

step 5. 关于端口对外的暴露

  1. Dockfile中定义的Expose是针对容器体系来说的
  2. docker run -p 80:80中定义的是针对外部系统来说的

下用将这两种情况组合,变成四种实例:

  • Dockerfile 未定义了 Expose 运行时也没加上 run -p 参数

    只能在此容器内部使用,不能被link的container访问,不能被外部访问

  • 只在Dockerfile里定义Expose了这个端口

    能在此容器内部使用,能被link的container访问,不能被外部访问

  • 同时在Dockerfile里定义了Expose,又在运行时加上了run -p

    能在此容器内部使用,能被link的container访问,能被外部访问

  • 只有run -p

    同上面的情况,所以可以看出run -p的优先级最高,一般来说对外的服务都需要加上这个参数