美文网首页程序员
docker镜像最小化实践(php-cli 为例)

docker镜像最小化实践(php-cli 为例)

作者: 失忆的决 | 来源:发表于2018-09-21 12:25 被阅读0次

    docker的镜像有大又小,大的镜像在于功能齐全,扩展方便,实操性更多,而小的镜像则在于麻雀虽小,五脏俱全,部署方便,代价小。
    最近在工作中发现每次生成镜像极为缓慢和庞大,然后抽空对之前写的Dockefile做了梳理,重新写了一下,把镜像构建优化了30%,镜像大小缩小了2.5倍。

    实践展示

    镜像前后对比

    基础包的构建

    目前我们很多镜像都基于Ubuntu构建,但是我们在构建镜像上还是过于臃肿,所以我们采用 alpine linux 来作为基础镜像,可以看看下面的对比。


    ubuntu基础镜像
    alpine 基础镜像

    使用alpine需要注意的一点是我们的包管理工具变成了apk,需要通过apk进行操作,而alpine 默认的源是http://dl-cdn.alpinelinux.org/,其实也不是很慢,但是如果觉得速度不满意的,可以替换为aliyun

    #编辑源文件 /etc/apk/repositories
    https://mirrors.aliyun.com/alpine/v3.6/main/
    https://mirrors.aliyun.com/alpine/v3.6/community/
    

    apk的使用

    大家可以参考这篇文章,在这里不做详讲。https://blog.csdn.net/liupeifeng3514/article/details/80418887

    php 基础镜像的选择

    我所需要的php版本是php7.2,所以我一开始采用的是php:7.2的镜像,大约有200MB左右,后面特地去docker hub上查找,发现了php:7.2.10-cli-alpine3.8基础镜像,完全基于alpine环境,这个镜像大概有78MB左右,可能大概有人还觉得比较大,那可以自己基于alpine来构建,我在github找到了一个自己写的版本,构建后大概40MB左右,可惜的是7.1版本的,所以最后我没采用,使用还是官方的版本。
    这里附下链接,https://github.com/swoftcloud/alphp/blob/alpine3.8/alphp-base.Dockerfile

    时区的设置

    RUN apk add -U tzdata \
        && cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \
        && apk del tzdata
    

    因为默认的时区是UTC,所以我们需要搭建镜像时就变成中国时区

    基础库的配置变更

    我们现在需要把我们之前搭建基础库的方式从apt-get变更为apk获取,比如

    RUN apt-get update \
        && apt-get install -y \
            curl \
            wget \
            git \
            zip \
            librdkafka-dev \
        && apt-get clean \
        && apt-get autoremove
    

    这是我们之前的ubuntu的

    RUN set -ex \
            && apk update \
            && apk add --no-cache --virtual .phpize-deps $PHPIZE_DEPS \
            && apk add --no-cache libaio \
             openssl-dev \
             librdkafka-dev \
            && apk del .phpize-deps \ 
            && rm -rf /var/cache/apk/* /tmp/* /usr/share/man
    

    这个则是替换为alpine的方式,因为curl在php的基础镜像里已经有了,所以我没有重新添加。
    这里有一点很重要,即时你用了很基础很基础的镜像,也最好学会阅读它的Dockerfile,至少不会让你重复在安装一遍一些比较基础的东西。

    怎么查看基础镜像已经具备的功能或者命令?

    当然是基于镜像构建一个容器,进去试试咯

    docker run -it php:7.2.10-cli-alpine3.8 sh
    

    可以进到容器里的sh,然后你就可以试试了

    扩展的安装

    当我们把之前讲的都写进Dockerfile后,可以先build一个镜像出来,我们把它叫做my:base

    docker build . -t my:base
    

    然后建一个容器进去执行php -m,看看我们安了哪些扩展,发现扩展貌似缺了几个我们想要的,那我们就得通过Dockerfile来安装我们的扩展,假设我们还需要安装swoole,redis这两个扩展。
    因为版本可能会存在更新,所以我们会把版本号单独拿出来作为一个常量,哇,方便多了。

    ENV SWOOLE_VERSION=4.1.2 \
        REDIS_VERSION=4.0.2 
    

    接下来就是我们下载安装我们的扩展

    RUN set -ex \
            && cd /tmp \
            && curl -SL "https://github.com/swoole/swoole-src/archive/v${SWOOLE_VERSION}.tar.gz" -o swoole.tar.gz \
            && curl -SL "http://pecl.php.net/get/redis-${REDIS_VERSION}.tgz" -o redis.tgz \
            # php extension: redis
            && pecl install redis.tgz \
            && docker-php-ext-enable redis \
            # php extension: swoole
            && cd /tmp \
            && mkdir -p swoole \
            && tar -xf swoole.tar.gz -C swoole --strip-components=1 \
            && rm swoole.tar.gz \
                    && ( \
                        cd swoole \
                        && phpize \
                        && ./configure  --enable-mysqlnd --enable-coroutine --enable-openssl \
                        && make -j$(nproc) && make install \
                    ) \
           && docker-php-ext-enable swoole 
    

    可以看到我们先把网络文件全部下载到本地才开始安装,当然为了方便我们可以使用COPY命令把安装文件先下载好,拷贝进去。pecl 也是之前安装好的命令,所以我们直接安装,然后把扩展加载到php.ini可以直接用docker(docker-php-ext-enable)命令,感觉真的是极为友好方便了。至于swoole为什么不用pecl,因为我在configure阶段需要可配置项,所以没有。

    一些常用的扩展我们还可以通过下面的方式来安装

    docker-php-ext-install pdo_mysql
    

    至此

    至此,我们的一个基础的php镜像搭建完成了,我个人建议将镜像分为两部分,一部分是基础镜像,基本不会改变的,一部分是业务镜像,属于经常变更的。

    业务镜像的构建

    这个就根据自己的业务来搭建了,假设我的Dockerfile存放在我的项目根目录下

    ADD . /var/www/my
    WORKDIR /var/www/my
    

    然后我们的项目是依赖于composer的,但是代码仓库为了源代码尽量的小且整洁,我们默认是不上传vendor目录的,所以需要我们安装composer 引入依赖的包。

    RUN curl -sS https://getcomposer.org/installer | php \
        && mv composer.phar /usr/local/bin/composer \
        && apk add git \
        && composer self-update --clean-backups \
        && composer install --no-dev \
        && composer dump-autoload -o \
        && composer clearcache \
        && apk del git \
        && rm -rf /var/cache/apk/* /tmp/* /usr/share/man
    

    至于这个时候才安装git,就是因为composer需要,不需要则立马卸载,而之前那些我下载的包都放在了/tmp目录下,所以我也同时删除了所有包,这也就是我们镜像的特点,干净,整洁,统一管理。

    启动我们的cli

    EXPOSE 80
    
    CMD ["php", "/var/www/my/index", "start"]
    

    最后当然是声明我们容器的端口并且启动咯。
    当然启动的命令就可以参照下面格式了

    docker run -d -p 10002:80 --restart=always -u="root" -v /apps/:/apps -v --name "my-php" my:latest
    

    my:latest就是我们的业务镜像了。

    最后

    把我们完整的镜像文件贴出来给大家参考:
    my.base.Dockerfile

    # docker build . -f my-base.Dockerfile -t my:base
    
    FROM php:7.2.10-cli-alpine3.8
    LABEL maintainer="失忆的决 <masixun71@foxmail.com>" version="1.0"
    ENV SWOOLE_VERSION=4.1.2 \
        REDIS_VERSION=4.0.2 \
    
    
    #Timezone and lib
    RUN apk add -U tzdata \
        && cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \
        && apk del tzdata
    
    RUN set -ex \
            && cd /tmp \
            && curl -SL "https://github.com/swoole/swoole-src/archive/v${SWOOLE_VERSION}.tar.gz" -o swoole.tar.gz \
            && curl -SL "http://pecl.php.net/get/redis-${REDIS_VERSION}.tgz" -o redis.tgz \
            && ls -alh \
            && apk update \
            && apk add --no-cache --virtual .phpize-deps $PHPIZE_DEPS \
            # for swoole ext
            && apk add --no-cache libaio \
             linux-headers \
             libaio-dev \
             openssl-dev \
             libstdc++ \
             librdkafka-dev \
            # php extension: redis
            && pecl install redis.tgz \
            && docker-php-ext-enable redis \
            # php extension: pdo_mysql
            && docker-php-ext-install pdo_mysql \
            # php extension: bcmath
            && docker-php-ext-install bcmath \
            # php extension: swoole
            && cd /tmp \
            && mkdir -p swoole \
            && tar -xf swoole.tar.gz -C swoole --strip-components=1 \
            && rm swoole.tar.gz \
                    && ( \
                        cd swoole \
                        && phpize \
                        && ./configure --enable-async-redis --enable-mysqlnd --enable-coroutine --enable-openssl \
                        && make -j$(nproc) && make install \
                    ) \
                    && rm -r swoole \
                    && docker-php-ext-enable swoole \
            && apk del .phpize-deps \
    

    Dockerfile

    FROM my:base
    LABEL maintainer="失忆的决<masixun71@foxmail.com>" version="1.0"
    ADD . /var/www/my
    WORKDIR /var/www/my
    
    RUN curl -sS https://getcomposer.org/installer | php \
        && mv composer.phar /usr/local/bin/composer \
        && apk add git \
        && composer self-update --clean-backups \
        && composer install --no-dev \
        && composer dump-autoload -o \
        && composer clearcache \
        && apk del git \
        && rm -rf /var/cache/apk/* /tmp/* /usr/share/man
    
    EXPOSE 80
    
    CMD ["php", "/var/www/my/index", "start"]
    

    要注意的点

    1.docker 支持的层级是有限的,层级越少,越利于维护和镜像大小的降低,所以尽量把多层合并为1层。
    2.把不再需要的东西做好删除,不然会一直存放在镜像中。
    3.镜像注意划分基础镜像和业务镜像,提高复用性和可维护性。

    相关文章

      网友评论

        本文标题:docker镜像最小化实践(php-cli 为例)

        本文链接:https://www.haomeiwen.com/subject/wtlanftx.html