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

相關文章
相關標籤/搜索