Dockerfile与Compose 环境搭建学习笔记(二)

上一篇文章对整体结构进行了简单记录,这一篇介绍下关于Dockerfile自定义镜像以及各个服务的配置。

其实 上面各种基础镜像非常完善,特别是官方的镜像质量非常之高,而我再捣腾一次完全是为了让自己掌握 Dockerfile 方面的技能而已。

在选择基础镜像方面,推荐使用 ,然后再它上面进行定制,因为它非常的小仅3M。我的 Nginx/Redis 是在 基础上定制的, 是在 上面进行的定制。截图大家可以感受下大小:

Dockerfile 与 Compose 建立关联

关于概念可以看这里:

https://yeasy.gitbooks.io/docker_practice/content/image/build.html

我这里以 PHP/Redis/Nginx 的定制来进行一些说明(我也只是现学现用,希望高手多指教)。

在上篇的 docker-compose.yml 文件中如下的配置:

这里重要的是多了 build 这个选项,设置的对应目录中可以找到 这个文件,当我们 时,docker会根据这个文件去先创建镜像,然后启动一个容器。

Dockerfile 如何写

网络上有非常多关于 该如何写的最佳实践,我觉得有几点特别重要:

一个容器只运行一个进程;

镜像层数尽可能少,当然还需要考虑可读性等方面的因素;

RUN指令应该用 \ 分成多行方便阅读;

容器镜像要尽可能的小。

更多最佳实践可以看这里:

https://yeasy.gitbooks.io/docker_practice/content/appendix/best_practices.html

接下来以 Redis 的 Dockerfile 来聊一聊实际如何编写。

第一行FROM用来指定基础镜像。也就是你要在什么镜像上进行定制,我这里选择的是 alpine,这是一个提供的基础空白对象非常小。只是它上面的包管理是 ,使用时需要掌握下它的一些参数。

LABEL可以理解成添加一些说明、描述信息。我这里仅添加了自己的联系方式。可以通过反斜线 来进行换行。

ENV用来设置环境变量,例如:定义一些系统版本、路径的环境变量,在后续RUN中可以使用(当然不仅仅是RUN中可用),也可以用改写原有的环境变量,例如:PATH。

RUN这是一个非常重要的命令,它是用来执行命令行的命令。就像上面看到的用 yum 安装更新软件,make编译代码等。可以通过反斜线 来进行换行。

COPY它是将宿主机的内容复制到容器中指定的路径。

EXPOSE指令用于指定容器将要监听的端口。一般设置为应用程序使用常见的端口,例如Redis设置为:

现在重点说下CMDENTRYPOINT两个命令。如果Dockerfile中没有ENTRYPOINT选项,CMD的内容就相当于直接执行某个命令。但是当存在时就是另外一回事。以上面的为例:

这里设置了一个ENTRYPOINT,像上面这种情况的时候如果直接启动一个容器时,相当于最后应用启动执行的命令是:。

根据这个特性, 内部可以根据相关参数进行特殊处理。来看下我的 脚本内容

可以看到如果脚本后面带的参数是则会先进行相关目录授权,然后启动redis。如果不是就会直接执行,例如:

会直接执行后面这个命令,你可以看到redis客户端的版本信息。这也就是表示,可以把镜像当成一个命令来使用了。

有了ENTRYPOINT这个功能,可以用它在服务启动时,做更多操作 。例如可以结合 docker-compose.yml 中设置的环境变量做更多事情。可以查看官方的MySQL的 文件内容。

依据Dockerfile启动容器

Dockerfile 已经写好了,通过下面的命令即可创建镜像启动容器。

在 redis/ 目录下执行上面的命令,他会先获取基础镜像,然后根据命令逐条执行,完成redis的编译、安装以及相关清理工作。

编译完成后可用通过查看当前的镜像列表数据。

然后通过 启动一个容器。

启动完成后,大家可以用redis客户端链接查看redis已经正常启动。

当然还有 PHP/Nginx 的镜像定制,以及每个服务的配置,大家可以在github上查看详情,这里就不再赘述了,剩下再介绍下这个过程中遇的到的几个错误。

遇到的错误

1. 在宿主机中无法连接Redis

这是由于bind的问题。以前在 vagrant 中安装redis也遇到过, 通过将配置修改为:

宿主机能够连接到服务器上。这样设置的含义是,让容器中的Redis监听容器ip的所有端口。这样设置而不是指定ip是因为每个镜像可以启动多个容器,而每个容器的ip地址是不确定的。

2. 镜像创建时报错

报错信息如下:

这个问题主要是:我的 文件没有可执行权限,因此在镜像创建完后,执行ENTRYPOINT指定的脚本时导致错误,解决办法当然很简单,直接执行:。然后需要重新创建镜像。

3. Nginx 无法连接php-fpm

这个错误其实与宿主机无法连接Redis很像,错误信息:

修改 php-fpm 的监听地址为:0.0.0.0:9000,Nginx可正常启动。

4. 访问php文件时找不到文件

这个错误其实与宿主机无法连接Redis很像,执行动态文件时,出现了文件找不到的提示,具体错误信息:

由于Nginx与PHP没有部署在同一个容器中,相关的项目文件只与Nginx进行了共享,而没有与PHP的容器进行共享。因此当访问静态文件时,Nginx直接在自己的容器中完成操作,而访问php文件时信息传到了PHP所在的容器,容器内部无法找到对应的php文件而导致的错误。

总结

经过2天的折腾,算是基本把环境搭建起来了。不过还有一些其他问题需要思考该如何进行:

如果我的PHP需要新的扩展,该如何去编译这个扩展包?

如何去监控docker中的应用的状态?比如:Redis/Nginx等服务的状态。

后续会继续摸索分享自己的经验。

项目地址:

https://github.com/helei112g/docker-env

微信公众号:

参考资料:

https://yeasy.gitbooks.io/docker_practice/content/

https://docs.lvrui.io/2017/06/09/%E7%BC%96%E5%86%99docker-entrypoint-sh%E5%85%A5%E5%8F%A3%E6%96%87%E4%BB%B6/

https://pkgs.alpinelinux.org/packages

  • 发表于:
  • 原文链接:https://kuaibao.qq.com/s/20180627G0PNZG00?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。

同媒体快讯

扫码关注云+社区