docker映象最小化實踐(php-cli 為例)
docker的映象有大又小,大的映象在於功能齊全,擴充套件方便,實操性更多,而小的映象則在於麻雀雖小,五臟俱全,部署方便,代價小。
最近在工作中發現每次生成映象極為緩慢和龐大,然後抽空對之前寫的Dockefile做了梳理,重新寫了一下,把映象構建優化了30%,映象大小縮小了2.5倍。
實踐展示

映象前後對比
基礎包的構建
目前我們很多映象都基於Ubuntu構建,但是我們在構建映象上還是過於臃腫,所以我們採用 alpine linux 來作為基礎映象,可以看看下面的對比。

ubuntu基礎映象

alpine 基礎映象
使用alpine需要注意的一點是我們的包管理工具變成了 apk ,需要通過 apk 進行操作,而alpine 預設的源是 ofollow,noindex">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版本的,所以最後我沒采用,使用還是官方的版本。
這裡附下連結, Dockerfile" target="_blank" rel="nofollow,noindex">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="失憶的決 <[email protected]>" 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="失憶的決<[email protected]>" 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.映象注意劃分基礎映象和業務映象,提高複用性和可維護性。