【Docker】使用 Dockerfile 定制镜像 (四)


摘要:在前面的基础文章中学会安装和使用Docker,但是如何使用Dockerfile来定制自己的镜像?如何深层次的理解Dockerfile的构建过程?本篇文章会通过理论并结合一些具体的案例进一步来掌握Dockerfile的相关知识。本文对构建过程进行解析,并对大部分保留字指令进行汇总,最后会基于基础镜像,利用 Dockerfile构建CentOS7-PHP7-Nginx1.12-MySQL5.6-Laravel5.5

关于Dockerfile

Dockerfile实质其实是一个文本文件,其内包含了一条条的指令(Instruction),每一条指令构建一层,因此每一条指令的内容,就是描述该层应当如何构建。

Dockerfile 涉及的内容包括执行代码或者是文件、环境变量、依赖包、运行时环境、动态链接库、操作系统的发行版、服务进程和内核进程。

Dockerfile 基础镜像

我们以最基础的CentOS7原镜像为例,先来了解一下文件及内容:

1
2
3
4
5
6
7
8
FROM scratch
ADD centos-7-docker.tar.xz /
LABEL org.label-schema.schema-version="1.0" \
org.label-schema.name="CentOS Base Image" \
org.label-schema.vendor="CentOS" \
org.label-schema.license="GPLv2" \
org.label-schema.build-date="20180804"
CMD ["/bin/bash"]

简单了解下镜像中的内容,FROM 指定基础镜像,LABEL添加元数据到镜像,ADD 复制并解压文件,CMD容器启动命令。

构建过程解析

语法要求

① 每条保留字指令都必须为大写字母,后面要跟随至少一个参数。
② 指令按照从上到下,顺序执行。
③ 注释使用#
④ 每条指令都会创建一个新的镜像层,并对镜像进行提交。

执行流程

Docker从基础镜像运行一个容器。
② 执行一条指令并对容器作出修改。
③ 执行类似docker commit的操作提交一个新的镜像层。
Docker 再基于刚提交的镜像运行一个新的容器。
⑤ 执行Dockfile中的下一条指令直到所有的指令都执行完成。

相互关系

从应用软件的角度来看,DockfileDocker镜像、Docker容器分别代表软件的三个不同阶段:

  • Dockfile 是软件的原材料。
  • Docker 镜像是软件的交付品。
  • Docker 容器是软件的运行态。

Dockfile面向开发、Docker镜像成为交付标准、Docker容器则涉及部署与运维。

保留字指令

保留字 解释说明
FROM 基础镜像,当前新镜像是基于哪个镜像的
MAINTAINER 镜像创建者的姓名和邮箱
RUN 容器构建时需要运行的命令
EXPOSE 当前容器对外暴露的端口
WORKDIR 指定创建容器后,终端默认登录进来的工作目录
ENV 用来在构建镜像过程中设置环境变量
ADD 将宿主机目录下的文件拷贝进镜像且ADD命令会自动处理URL和解压tar压缩包
COPY 类似ADD,拷贝文件和目录,但没ADD强大
VOLUME 容器数据卷,用于数据保存和持久化工作
CMD 覆盖一个容器启动时要运行的命令
ENTRYPOINT 追加一个容器启动时要运行的命令
ONBUILD 当构建一个被继承的Docckerfile时运行命令,父镜像在被子镜像继承后父镜像的ONBUILD被触发

定制镜像

以下为使用Dockerfile定制镜像:

版本信息

软件名称 版本号
PHP 7.1.15
MySQL 5.6.40
Nginx 1.12.2
Composer 1.7.2
Laravel Installer 2.0.1
Laravel Framework 5.5.42

Dockerfile文件

因自身对于Dockerfile也是在不断的学习和改进中,详细迭代版本可参考Github-dockerfile

新建目录,并切换进目录后,创建Dockerfile文件:

1
2
3
[root@wx home]# mkdir /home/centos7-lnmp-laravel5.5
[root@wx home]# cd /home/centos7-lnmp-laravel5.5
[root@wx home]# touch Dockerfile

将以下内容复制进入Dockerfile文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
# 制定基础镜像
FROM wangxiong/lnmp-laravel5.5:v1.0
# 作者(维护者)
MAINTAINER wangxiong lensxiong@gmail.com
# ENV 环境变量
# 网站运行目录
ENV WEBSITEDIR=/wdata/www \
# 软件下载目录
SERVERDIR=/wdata/server \
# 网站应用名称
WEBSITENAME=website \
# 全局环境变量
PROFILE=/etc/profile \
# LARAVEL 配置
# LARAVEL 版本
LARAVELVERSION=5.5 \
# NGINX 配置
# NGINX服务器文件夹名称及版本号
NGINXVERSION=nginx-1.12.2 \
# NGINX源码下载包
NGINXSOURCE=nginx-1.12.2.tar.gz \
# NGINX源码下载地址
NGINXDOWNLOADURL=https://nginx.org/download/nginx-1.12.2.tar.gz \
# MYSQL 配置
# MYSQL文件夹名称及版本号(下载不同版本的只需更改版本即可,对应的包为.tar.gz)
MYSQLVERSION=mysql-5.6.40 \
# MYSQL源码下载包
MYSQLSOURCE=mysql-5.6.40.tar.gz \
# MYSQL源码下载地址
MYSQLDOWNLOADURL=https://downloads.mysql.com/archives/get/file/mysql-5.6.40.tar.gz
# 指定工作目录
WORKDIR $WEBSITEDIR
# Linux 工具
# 常用工具
RUN yum -y install gcc gcc-c++ wget make vim lrzsz htop git unzip \
# 清理 yum 缓存
&& yum clean all
# MySQL-image
# 源码下载
RUN cd $SERVERDIR \
&& wget $MYSQLDOWNLOADURL \
# 解压源码包
&& tar xzf $MYSQLSOURCE \
# 删除源码包
&& rm -f $MYSQLSOURCE \
# 更新 yum 源
&& yum -y update \
# 创建 MySQL 的使用用户 mysql
&& useradd mysql -s /sbin/nologin -M \
# 安装 MySQL 编译依赖包
&& yum install gcc gcc-c++ ncurses ncurses-devel cmake -y \
# 进入 MySQL 源码下载解压的目录
&& cd $SERVERDIR/$MYSQLVERSION \
# 设置编译参数
&& cmake . -DCMAKE_INSTALL_PREFIX=/usr/local/mysql -DMYSQL_DATADIR=/usr/local/mysql/data -DDOWNLOAD_BOOST=1 -DWITH_BOOST=/wdata/server/$MYSQLVERSION/boost -DSYSCONFDIR=/etc -DWITH_INNOBASE_STORAGE_ENGINE=1 -DWITH_PARTITION_STORAGE_ENGINE=1 -DWITH_FEDERATED_STORAGE_ENGINE=1 -DWITH_BLACKHOLE_STORAGE_ENGINE=1 -DWITH_MYISAM_STORAGE_ENGINE=1 -DENABLED_LOCAL_INFILE=1 -DENABLE_DTRACE=0 -DDEFAULT_CHARSET=utf8mb4 -DDEFAULT_COLLATION=utf8mb4_general_ci -DWITH_EMBEDDED_SERVER=1 \
# 编译并安装
&& make && make install \
# 配置全局变量
&& echo 'PATH=/usr/local/mysql/bin/:$PATH' >> $PROFILE \
# 重新执行系统环境变量
&& source $PROFILE
# Nginx-image
# 进入下载目录
RUN cd $SERVERDIR \
# 下载 Nginx 源码
&& wget $NGINXDOWNLOADURL \
# 解压源码包
&& tar xzf $NGINXSOURCE \
# 删除源码包
&& rm -f $NGINXSOURCE \
# 更新 yum 源
&& yum -y update \
# 创建 Nginx 的使用用户 www
&& useradd www -s /sbin/nologin -M \
# 安装Nginx编译依赖包
&& yum -y install gcc gcc-c++ pcre pcre-devel zlib-devel openssl-devel jemalloc-devel \
# 进入 Nginx 源码下载解压的目录
&& cd $SERVERDIR/$NGINXVERSION \
# 设置编译参数
&& ./configure --user=www --group=www --prefix=/usr/local/nginx --with-http_stub_status_module --with-http_ssl_module --with-http_v2_module --with-http_gzip_static_module --with-http_sub_module \
# 编译并安装
&& make && make install \
# Nginx 全局环境变量设置
&& echo 'PATH=/usr/local/nginx/sbin/:$PATH' >> $PROFILE \
# 重新执行系统环境变量
&& source $PROFILE
# Composer-image (方法一推荐)
# RUN source $PROFILE && curl -sS https://getcomposer.org/installer | php && mv composer.phar /usr/local/bin/composer
# Composer-image (方法二)
# 运行全局环境变量
RUN source $PROFILE \
# 下载安装脚本 - composer-setup.php - 到当前目录
&& php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" \
# Verify the installer SHA-384
&& php -r "if (hash_file('SHA384', 'composer-setup.php') === '544e09ee996cdf60ece3804abc52599c22b1f40f4323403c44d44fdfdd586475ca9813a858088ffbc1f233e9b180f061') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;" \
# 执行安装过程
&& php composer-setup.php \
# 删除安装脚本
&& php -r "unlink('composer-setup.php');" \
# 设置全局使用composer
&& mv composer.phar /usr/local/bin/composer
# Laravel-image(使用Laravel安装工具安装)
# 运行全局环境变量
RUN source $PROFILE \
# 使用 Composer 下载 Laravel 安装包
&& composer global require "laravel/installer" \
# 配置系统中的 laravel 执行文件
&& echo 'PATH=/root/.composer/vendor/bin/:$PATH' >>/etc/profile \
# 运行全局环境变量
&& source $PROFILE \
# 查看Laravel安装工具版本
&& laravel -v \
# 网站应用目录
&& cd $WEBSITEDIR && composer create-project --prefer-dist laravel/laravel=$LARAVELVERSION $WEBSITENAME
# 解决每次进入容器命令都要重新source /etc/profile 才能生效的问题
RUN echo 'source $PROFILE' >> /root/.bashrc

注:因MySQL源码编译安装所需的时间比较长,建议可将MySQL-image该层镜像去除,直接从Nginx-image开始构建。

构建镜像的命令

使用以下命令构建镜像:

1
[root@wx home]# docker build -f /home/centos7-lnmp-laravel5.5/Dockerfile -t centos7-lnmp-laravel5.5:v1.0 .

运行容器:

1
[root@wx home]# docker run -it -d centos7-lnmp-laravel5.5:v1.0 bash

进入容器:

1
[root@wx home]# docker exec -it container_id bash

新增镜像标签:

1
[root@wx home]# docker tag centos7-lnmp-laravel5.5:v1.0 wangxiong/centos7-lnmp-laravel5.5:v1.0

推送镜像:

1
[root@wx home]# docker push wangxiong/centos7-lnmp-laravel5.5:v1.0