Docker容器的Nginx实践

做为目前最火的应用,Docker 确实存在着其独到之处,不管是程序猿仍是运维都应该据说过 Docker 的大名,Docker 已经走过了许多的坑,目前最新版本是 v1.11.0 版本,应该说是彻底能承载开发使用和运维监控,这款工具能帮助咱们高效的打包、发布和运行承载着应用程序的容器系统。并且收集日志、帮助 App 的快速开发都有很大做用。html

容器和虚拟机,常常是被拿出来对比的两款产品,实际上二者有着根本的差异,虚拟机是彻底模拟了一台真实计算机,在上面运行的系统可能或者不可能知道本身运行在虚拟化环境下,而且虚拟机承载了将用户指令转换为特权指令的功能,因此虚拟机很是复杂,可是很完备,而 Docker 则彻底不一样。Docker 使用主机自身的 Linux 内核,而后从镜像中产生磁盘目录和软件,全部的进程都运行在主机上,若是有兴趣的话彻底能够 ps aux 查询一下,就能发如今 Docker 中运行的进程,只不过 Docker 对其作了如同 chroot 差很少概念的封装。linux

Docker 真正用法

在 Docker 发展的早期,因为 busybox 等轻量化镜像不完备,因此各大发行版的缩减瘦身镜像获得了更多的使用,特别是因为 Docker 自己是在 Ubuntu 环境下开发的,因此 Ubuntu 和 Debian 在不少镜像中做为基镜像,以此做为基础产生目标镜像。可是随着在实践中的使用,其弊端也暴露出来了,就是太过于重量化,好比 systemd 的日志功能和 Docker 自己的日志功能被重复使用,镜像很难缩小到 300M 之内。并且 Docker 的推荐使用方式就是单进程模型,而并不是是多个进程如同一个完备的操做系统通常。因此就产生了 alpine 等轻量级基镜像,alpine 是什么则能够自行百度,这个镜像是 Docker 官方推荐的镜像,将来官方镜像将会迁移到 alpine 做为基础的镜像上,因此,咱们应当早日熟悉此镜像。nginx

构建 Dockerfile

本文讲述的是 Docker 容器的 Nginx 实践,不过官方实际上已经有了关于 Nginx 的 alpine 镜像。而在实际使用过程当中,笔者更多的是使用 Tengine,因此根据官方 Dockerfile 的参考,笔者自行编写了 Tengine 镜像的 Dockerfile,但愿能抛砖引玉,各位可以批评指正。docker

FROM alpine:3.3
MAINTAINER ChasonTang <chasontang@gmail.com>

ENV TENGINE_VERSION 2.1.2
ENV CONFIG "\
        --prefix=/etc/nginx \
        --sbin-path=/usr/sbin/nginx \
        --conf-path=/etc/nginx/nginx.conf \
        --error-log-path=/var/log/nginx/error.log \
        --http-log-path=/var/log/nginx/access.log \
        --pid-path=/var/run/nginx.pid \
        --lock-path=/var/run/nginx.lock \
        --http-client-body-temp-path=/var/cache/nginx/client_temp \
        --http-proxy-temp-path=/var/cache/nginx/proxy_temp \
        --http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp \
        --http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp \
        --http-scgi-temp-path=/var/cache/nginx/scgi_temp \
        --user=nginx \
        --group=nginx \
        --with-http_ssl_module \
        --with-http_realip_module \
        --with-http_addition_module \
        --with-http_sub_module \
        --with-http_dav_module \
        --with-http_flv_module \
        --with-http_mp4_module \
        --with-http_gunzip_module \
        --with-http_gzip_static_module \
        --with-http_random_index_module \
        --with-http_secure_link_module \
        --with-http_auth_request_module \
        --with-mail \
        --with-mail_ssl_module \
        --with-file-aio \
        --with-http_spdy_module \
        --with-ipv6 \
        --with-jemalloc \
        "

ADD ngx_user.patch /
ADD repositories /etc/apk/repositories

RUN \
    addgroup -S nginx \
    && adduser -D -S -h /var/cache/nginx -s /sbin/nologin -G nginx nginx \
    && apk add --no-cache --virtual .build-deps \
        gcc \
        libc-dev \
        make \
        openssl-dev \
        pcre-dev \
        zlib-dev \
        linux-headers \
        curl \
        jemalloc-dev \
    && curl "http://tengine.taobao.org/download/tengine-$TENGINE_VERSION.tar.gz" -o tengine.tar.gz \
    && mkdir -p /usr/src \
    && tar -zxC /usr/src -f tengine.tar.gz \
    && rm tengine.tar.gz \
    && cd /usr/src/tengine-$TENGINE_VERSION/src/os/unix/ \
    && mv /ngx_user.patch ./ngx_user.patch \
    && patch ngx_user.c ngx_user.patch \
    && rm ngx_user.patch \
    && cd ../../../ \
#    && cd /usr/src/tengine-$TENGINE_VERSION \
    && ./configure $CONFIG --with-debug \
    && make \
    && mv objs/nginx objs/nginx-debug \
    && ./configure $CONFIG \
    && make \
    && make install \
    && rm -rf /etc/nginx/html/ \
    && mkdir /etc/nginx/conf.d/ \
    && mkdir -p /usr/share/nginx/html/ \
    && install -m644 html/index.html /usr/share/nginx/html/ \
    && install -m644 html/50x.html /usr/share/nginx/html/ \
    && install -m755 objs/nginx-debug /usr/sbin/nginx-debug \
    && strip /usr/sbin/nginx* \
    && runDeps="$( \
        scanelf --needed --nobanner /usr/sbin/nginx \
            | awk '{ gsub(/,/, "\nso:", $2); print "so:" $2 }' \
            | sort -u \
            | xargs -r apk info --installed \
            | sort -u \
    )" \
    && apk add --virtual .nginx-rundeps $runDeps \
    && apk del .build-deps \
    && rm -rf /usr/src/nginx-$NGINX_VERSION \
    && apk add --no-cache gettext \
    \
    # forward request and error logs to docker log collector
    && ln -sf /dev/stdout /var/log/nginx/access.log \
    && ln -sf /dev/stderr /var/log/nginx/error.log

COPY nginx.conf /etc/nginx/nginx.conf
COPY nginx.vh.default.conf /etc/nginx/conf.d/default.conf

EXPOSE 80 443

CMD ["nginx", "-g", "daemon off;"]

咱们知道,Docker 能够根据 Dockerfile 构建镜像,上面就是笔者写的 Dockerfile。首先,使用 FROM 指令指定此镜像的基镜像为 alpine:3.3,第二行为 Dockerfile 维护者声明,而后使用两个 ENV 指令声明两个环境变量,一个指定 Tengine 须要获取的版本号,一个则是编译安装选项。这里暂时不讲解,而后将一个补丁文件和 alpine 镜像源配置文件复制到容器内,其实是由于 tengine v2.1.2 存在着一个遗留的 glibc bug,会致使编译时出错,上游 Nginx 的最新代码已经修复,而 tengine 的开发分支上面也已经修复了这个问题,笔者前不久提 issue 将此补丁修正了 tengine v2.1.3 分支的代码,可是很惋惜,v2.1.3 版本还没有有正式发布,因此只能先使用补丁手动修复此问题。至于镜像源,则是由于国内存在着网络问题,致使 apk 包管理命令没法成功下载各个依赖项,因此将其指定为了国内源,若是正式使用则能够移除这两个文件。网络

而后就是使用 RUN 命令执行代码,这里你们能够看到笔者使用 &&\ 将全部的指令都压缩为了一行,这里是有两个缘由:运维

  1. RUN 指令不会保存上一条指令的工做路径,每条 RUN 指令都只会将工做目录指定为 / 目录dom

  2. 一条 Dockerfile 中的指令就会产生一次镜像的提交,换言之,减小 Dockerfile 中的指令就能够提升镜像的复用水平curl

而后就是使用 apk 包管理命令下载安装包括编译器等依赖项,而且将这些依赖项标记为 .build-deps 组,便于后面将其卸载清理。而后就是很是常规的思路,./configure && make && make install,编译选项都是很是中规中矩的,基本熟悉 Nginx 编译的朋友都能看懂。可是上面能够注意到,Nginx 被编译了两次,一次开启了 --with-debug 参数,一次没有,这是由于在不少状况下,咱们须要 Nginx 提供 debug 级别的监控日志,特别是在开发环境下,因此就编译了两次,便于使用。而后后面使用字符串分析处理将 Tengine 的运行时依赖项提取出来,标记为 .nginx-rundeps 而后卸载 .build-deps,最后则是两个符号连接将 accessLogerrorLog 连接到标准输入输出,这样咱们就能使用 docker logs 命令方便的查看日志了。最后则是复制自定义的 Nginx 配置文件,而后使用 nginx -g daemon off; 让 Nginx 之前台进程方式运行。工具

总结

到这里已经讲完了 Docker 在生产开发中的正确使用方法,Docker 也确实是同样不可多得的好工具,祝愿你们早日使用 Docker 提高本身的生产力。ui

相关文章
相关标签/搜索