简介
业务 API 1.0 服务,因服务器迁移需要对线上服务编写 Dockerfile 进行容器化改造,由于之前接触 Docker 较少,故用本文档记录 Dockerfile 编写过程。
需求分析
现有情况(线上)
- PHP : 5.3.8
- nginx: 1.0.2
- PHP 扩展: 若干
改造目标
不变动代码的情况下,进行容器化支持
遇到阻碍
- PHP 版本过低,没有现成的官方镜像
- 研发对代码服务不熟悉(离职交接问题)
- PHP 环境使用过多第三方扩展,需要下载编译安装
操作流程
Dockerfile 组成
- 基础镜像系统: Debian:jessie
- PHP 版本: 5.3.29
- NGINX 版本: 1.6.2
Dockerfile 引用
Dockerfile
选用,官方历史维护的PHP 5.3.29
版本。由 Github 上某热心网友官方停止维护前 fork 下来并进行修改的。
借鉴地址为: www.github.com/helderco/do…
Dockerfile 的二次加工
- 添加国内源
- 推荐(首选科大,不好用了换网易)
- 科大: mirrors.ustc.edu.cn
- 网易: mirrors.163.com
RUN sed -i "s#[a-z]\+.debian.org#mirrors.163.com#g" /etc/apt/sources.list
- 添加 PHP 扩展
- 三种安装方式
- 使用
docker-php-ext*
等脚本进行安装 - 使用
pecl
工具安装,需要将扩展的配置添加到php.ini
中 - 使用
源码
编译安装(phpize),需要在php.ini
中,添加对应配置
# No.1 - docker 脚本 RUN set -ex \ && docker-php-ext-install \ bcmath \ bz2 \ ftp \ mbstring \ mcrypt \ pcntl \ pdo_mysql \ mysqli \ shmop \ soap \ sockets \ sysvsem # No.2 - pecl (适用于高版本php镜像) RUN pecl install redis \ && docker-php-ext-enable redis # No.3 - 源码 RUN set -ex \ && cd /tmp \ && curl -sL -C - --retry 5 --retry-delay 3 http://pecl.php.net/get/memcache-2.2.5.tgz -o memcache-2.2.5.tgz \ && tar -xzf memcache-2.2.5.tgz \ && cd /tmp/memcache-2.2.5 \ && phpize \ && ./configure && make && make install \ && rm -rf /tmp/memcache-2.2.5* \ && echo 'extension="memcache.so"' >> $PHP_INI_CONF \
- 使用
- 修改 php-fpm 配置
- 一般通过以下两种方式:
- sed: 使用
RUN
指令,sed
进行文件修改。 - COPY: 使用
COPY
指令,将写好的php-fpm.conf
导入镜像内。
# No.1 - sed RUN set -ex; \ sed -i -e "" $PHP_FPM_CONF; \ sed -i "s|;daemonize = .*|daemonize = no|" $PHP_FPM_CONF; \ sed -i "s|listen = .*|listen = 9000|" $PHP_FPM_CONF; \ sed -i "s|;emergency_restart_threshold = .*|emergency_restart_threshold = 10|" $PHP_FPM_CONF; \ sed -i "s|;emergency_restart_interval = .*|emergency_restart_interval = 1m|" $PHP_FPM_CONF; \ sed -i "s|;process_control_timeout = .*|process_control_timeout = 5s|" $PHP_FPM_CONF; \ sed -i "s|;rlimit_files = .*|rlimit_files = 51200|" $PHP_FPM_CONF; \ sed -i "s|;rlimit_core = .*|rlimit_core = 0|" $PHP_FPM_CONF; \ sed -i "s|pm.max_children = .*|pm.max_children = 14|" $PHP_FPM_CONF; \ sed -i "s|pm.start_servers = .*|pm.start_servers = 6|" $PHP_FPM_CONF; \ sed -i "s|pm.min_spare_servers = .*|pm.min_spare_servers = 3|" $PHP_FPM_CONF; \ sed -i "s|pm.max_spare_servers = .*|pm.max_spare_servers = 10|" $PHP_FPM_CONF; \ sed -i "s|;pm.max_requests = .*|pm.max_requests = 512|" $PHP_FPM_CONF; \ sed -i "s|;catch_workers_output = yes|catch_workers_output = yes|g" $PHP_FPM_CONF;
- sed: 使用
- 安装 nginx
- 一般通过以下两种方式:
apt
安装 :apt-get install nginx-full
源码
安装: 下载官方源码包,然后编译安装
# No.1 - apt 安装 RUN apt-get update && apt-get install -y --no-install-recommends \ nginx-full \ && ln -sf /dev/stdout /var/log/nginx/access.log \ && ln -sf /dev/stderr /var/log/nginx/error.log \ && apt-get clean \ && rm -r /var/lib/apt/lists/ # No.2 - 源码安装 (未测试,仅列逻辑) # 1. 可能需要提前 apt-get install 安装 libpcre3-dev 包 # 2. curl -sL https://nginx.org/download/nginx-${NGX_VERSION}.tar.gz -o nginx-${NGX_VERSION}.tar.gz # 3. ./configure \ --prefix=/usr/local/nginx \ --with-http_stub_status_module \ --with-http_ssl_module \ --with-http_realip_module \ --http-log-path=/var/log/nginx/access.log \ --error-log-path=/var/log/nginx/error.log
- 修改 nginx 配置
- 一般使用
COPY
指令,将写好的配置导入镜像内
- 使用 supervisor 自启动服务
- 将
supervisor
配置导入镜像,并在Dockerfile
中添加ENTRYPOINT
指令,用于启动php-fpm
和nginx
服务# supervisor config [supervisord] nodaemon=true loglevel=error [program:php] command=/usr/local/sbin/php-fpm stdout_logfile=/dev/stdout stderr_logfile=/dev/stderr stdout_logfile_maxbytes = 0 stderr_logfile_maxbytes = 0 [program:nginx] command=/usr/sbin/nginx stdout_logfile=/dev/stdout stderr_logfile=/dev/stderr stdout_logfile_maxbytes = 0 stderr_logfile_maxbytes = 0 # Dockerfile ENTRYPOINT ["supervisord", "-c", "/etc/supervisor/supervisord.conf"]
制作过程中的一些注意
-
系统的仓库源选用国内镜像
# 科大 mirrors.ustc.edu.cn # 网易 mirrors.163.com
-
尽量用官方维护的
base镜像
或Dockerfile
, 网络不佳,可先pull
下来然后推送到公司内部仓库. -
服务日志尽量重定向到标准输出中,方便查看日志.
# nginx RUN ln -sf /dev/stdout /xxx/nginx/logs/access.log \ && ln -sf /dev/stderr /xxx/nginx/logs/error.log # php sed -i "s|;error_log = .*|error_log = /dev/stderr|g" /etc/php7/php-fpm.conf && \ sed -i "s|;catch_workers_output = yes|catch_workers_output = yes|g" /etc/php7/php-fpm.d/www.conf \ # supervisor [supervisord] ... loglevel=error [program:php] ... stdout_logfile=/dev/stdout stderr_logfile=/dev/stderr ... [program:nginx] ... stdout_logfile=/dev/stdout stderr_logfile=/dev/stderr ...
nginx 设置软连到 stdout 或 stderr 即可。
php 需要在配置文件([global]下)把 error_log 设置为 /dev/stderr, ([www])并添加参数 catch_workers_output = yes (如有 slow log ,同样设置 stderr 即可)。
supervisor 注意配置里,每个 program 都要设置对应的 logfile 位置,同样是 stdout 或 stderr。
-
容器内服务务必要前台运行
# supervisor nodaemon = true # nginx /usr/local/nginx/sbin/nginx -g 'daemon off;' # php (修改配置) daemonize = no
-
OS 系统选用
# 镜像小,软件安装方便速度快,版本控制稍逊色 alpine # 镜像稍大,软件安装较为便利,版本控制做的好 debian
-
编写
Dockerfile
时尽可能保证版本控制,便于后续迭代发布。
Dockerfile demo
使用时,删除不需要的 php 扩展,可加速镜像构建过程。
总结
Dockerfile
制作过程,对于特殊环境要求,需要边找资料边进行测试,过于复杂的环境配置,可以适当增加镜像分层,以便构建镜像过程中可以重复利用 cache。