Creating Laravel Image with Docker Multi-Stage Builds

Docker: 18.09

Laravel: 6.9

在製作 Container Images 時,基本上 Images 的大小是越小越好,而瘦身的面向很多,在 Dockerfile 中使用 Multi-Stage Builds 也是方法之一。

Docker 在 17.05 以後提供了一個 Multi-Stage Builds(多階段構建)功能,這個功能可以將整個產線的 Images 整合進同一個 Dockerfile ,讓其變為 Intermediate Image(中繼映象檔),而後續的映象檔也可以取得中繼映象檔產生的 artifacts(檔案),這樣一來便可以有效地控管流程及降低不必要的安裝。

Usage

Laravel 為例,要完整的部署 Laravel,必須先經過 composernpm or yarn 安裝一些套件,但這些套件只負責安裝或編譯,在網站部署以後是不需要的。

最原始的作法,就是將從安裝到部署需要用到的東西都裝進去 Image

範例

# Base image
FROM php:7.4.1-apache

# Install npm
RUN apt-get update && apt-get install -y npm

# Install composer
RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer

# Copy Laravel app to Container
COPY . .

# Composer Install
RUN composer install \
        --ignore-platform-reqs \
        --no-interaction \
        --no-plugins \
        --no-scripts \
        --prefer-dist

# Npm install and Compile
RUN npm install \
        && npm run production

其實我們真正需要的只是特定的產物,因此可以使用 Multi-Stage Builds ,讓套件先在 Intermediate Image 安裝完成,最後再使用其產生的檔案就好了。

範例

# 使用 composer image 建立 vendor stage
FROM composer:1.9 as vendor

COPY database/ database/
COPY composer.json composer.json
COPY composer.lock composer.lock

RUN composer install \
        --ignore-platform-reqs \
        --no-interaction \
        --no-plugins \
        --no-scripts \
        --prefer-dist

# 使用 node image 建立 nodejs stage
FROM node:10.18 as nodejs

RUN mkdir -p /app/public

COPY package.json webpack.mix.js /app/
COPY resources/sass/ /app/resources/sass/
COPY resources/js/ /app/resources/js/

WORKDIR ./app

RUN npm install && npm run production

# Base image
FROM php:7.4.1-apache

COPY . /var/www/html
# 拿出 vendor stage 安裝的檔案
COPY --from=vendor /app/vendor/ /var/www/html/vendor/

# 拿出 nodejs stage 安裝及編譯完成的檔案
COPY --from=nodejs /app/public/js/ /var/www/html/public/js/
COPY --from=nodejs /app/public/css/ /var/www/html/public/css/
COPY --from=nodejs /app/mix-manifest.json /var/www/html/mix-manifest.json