PHP 5 Dockerfile 改造過程

SherLock·OD發表於2019-09-20

簡介

業務 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 的二次加工

  1. 新增國內源
  • 推薦(首選科大,不好用了換網易)
    • 科大: mirrors.ustc.edu.cn
    • 網易: mirrors.163.com
    RUN sed -i "s#[a-z]\+.debian.org#mirrors.163.com#g" /etc/apt/sources.list
    複製程式碼
  1. 新增 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 \
    複製程式碼
  1. 修改 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;
    複製程式碼
  1. 安裝 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
    複製程式碼
  1. 修改 nginx 配置
  • 一般使用COPY指令,將寫好的配置匯入映象內
  1. 使用 supervisor 自啟動服務
  • supervisor配置匯入映象,並在Dockerfile中新增ENTRYPOINT指令,用於啟動php-fpmnginx服務
    # 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"]
    複製程式碼

製作過程中的一些注意

  1. 系統的倉庫源選用國內映象

    # 科大
    mirrors.ustc.edu.cn
    
    # 網易
    mirrors.163.com
    複製程式碼
  2. 儘量用官方維護的base映象Dockerfile, 網路不佳,可先pull下來然後推送到公司內部倉庫.

  3. 服務日誌儘量重定向到標準輸出中,方便檢視日誌.

    # 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。

  4. 容器內服務務必要前臺執行

    # supervisor
    nodaemon = true
    
    # nginx
    /usr/local/nginx/sbin/nginx -g 'daemon off;'
    
    # php (修改配置)
    daemonize = no
    複製程式碼
  5. OS 系統選用

    # 映象小,軟體安裝方便速度快,版本控制稍遜色
    alpine
    
    # 映象稍大,軟體安裝較為便利,版本控制做的好
    debian
    複製程式碼
  6. 編寫Dockerfile時儘可能保證版本控制,便於後續迭代釋出。

Dockerfile demo

地址: github.com/SherLockOD/…

使用時,刪除不需要的 php 擴充套件,可加速映象構建過程。

總結

Dockerfile製作過程,對於特殊環境要求,需要邊找資料邊進行測試,過於複雜的環境配置,可以適當增加映象分層,以便構建映象過程中可以重複利用 cache。

相關文章