すきま風

勉強したことのメモとか

Docker Container の軽量化 あるいはAWS ECS Taskの起動速度改善

以前の記事PHP ApplicationのDockerfileを書きましたが Apacheモジュールバージョンではなく fpmで運用したくなったので書き直します。

また、せっかくなのでdebian baseとalpine baseを用意して サイズの比較と、実際にAWS ECSでの起動速度をカジュアルに計測してみます。

debian base

php

Redis Accessを想定したPHP Application

FROM php:7.4-fpm
## config file copy
COPY ./config/php/* /tmp/
## project directory copy
COPY . /var/www/html/sample-app

RUN apt-get update \
    && pecl install redis-5.2.2 \
    && docker-php-ext-enable redis \
    && mv /tmp/php.ini-development "$PHP_INI_DIR/php.ini-development" \
    && mv "$PHP_INI_DIR/php.ini-development" "$PHP_INI_DIR/php.ini" \
    && mv /tmp/www.conf /usr/local/etc/php-fpm.d/www.conf \
    ## directory権限をwww-dataにしてpermission && SGID変更
    ## directory -> 770, file -> 660
    && chown -R www-data:www-data /var/www/html \
    && find /var/www/html -type d -exec chmod 770 {} \; \
    && find /var/www/html -type f -exec chmod 660 {} \; \
    && chmod -R 2770 /var/www/html \
    ## userを作成してwww-data groupに入れる
    && useradd webdev \
    && usermod -g www-data webdev

EXPOSE 9000

USER webdev

nginx

FROM nginx:1.19.0

ARG PHP_HOST="127.0.0.1:9000"

## config file copy
COPY ./config/nginx/* /tmp/

RUN apt-get update \
    # docker-composeとawsでhostの形式を書き換える
    && sed -i -e "s/127.0.0.1:9000/$PHP_HOST/g" /tmp/default.conf \
    && mv /tmp/nginx.conf /etc/nginx/nginx.conf \
    && mv /tmp/default.conf /etc/nginx/conf.d/default.conf \
    && touch /var/run/nginx.pid \
    && chown -R nginx:nginx /var/run/nginx.pid \
    && chown -R nginx:nginx /var/cache/nginx

USER nginx

EXPOSE 8080

alpine base

php

FROM php:7.4-fpm-alpine
## config file copy
COPY ./config/php/* /tmp/
## project directory copy
COPY . /var/www/html/sample-app

RUN apk update \
    && apk add --no-cache --update --virtual .build-deps \
        autoconf gcc g++ make \
    && pecl channel-update pecl.php.net \
    && pecl install redis-5.2.2 \
    && docker-php-ext-enable redis \
    && mv /tmp/php.ini-development "$PHP_INI_DIR/php.ini-development" \
    && mv "$PHP_INI_DIR/php.ini-development" "$PHP_INI_DIR/php.ini" \
    && mv /tmp/www.conf /usr/local/etc/php-fpm.d/www.conf \
    ## directory権限をwww-dataにしてpermission && SGID変更
    ## directory -> 770, file -> 660
    && chown -R www-data:www-data /var/www/html \
    && find /var/www/html -type d -exec chmod 770 {} \; \
    && find /var/www/html -type f -exec chmod 660 {} \; \
    && chmod -R 2770 /var/www/html \
    ## userを作成してwww-data groupに入れる
    && adduser -D -u 1000 -G www-data webdev \
    && apk del .build-deps \
    && rm -rf /tmp/* /var/tmp/*

EXPOSE 9000

USER webdev

nginx

alpine-baseで containerをnginxで起動した際に unlink() /var/run/nginx.pid failed permission denied が出るようになったのでcontainer自体はとりあえず root user で起動することにしました。

FROM nginx:1.19.0-alpine

ARG PHP_HOST="127.0.0.1:9000"

## config file copy
COPY ./config/nginx/* /tmp/

RUN apk update \
    && apk add --no-cache --update --virtual .build-deps sed \
    # docker-composeとawsでhostの形式を書き換える
    && sed -i -e "s/127.0.0.1:9000/$PHP_HOST/g" /tmp/default.conf \
    && mv /tmp/nginx.conf /etc/nginx/nginx.conf \
    && mv /tmp/default.conf /etc/nginx/conf.d/default.conf \
    && touch /var/run/nginx.pid \
    && chown -R nginx:nginx /var/run/nginx.pid \
    && chown -R nginx:nginx /var/cache/nginx \
    && apk del .build-deps \
    && rm -rf /tmp/* /var/tmp/*

EXPOSE 8080

nginx.conf

user  nginx;
worker_processes  auto;

error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;

events {
    worker_connections  1024;
}

http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    sendfile        on;
    #tcp_nopush     on;

    # https://dev.classmethod.jp/articles/set_keepalivetimeout_on_apache_for_resolve_elb_timeout/
    # https://yomon.hatenablog.com/entry/2016/10/08/220338
    keepalive_timeout  120;

    # https://aws.amazon.com/jp/blogs/compute/nginx-reverse-proxy-sidecar-container-on-amazon-ecs/
    gzip  on;
    gzip_proxied any;
    gzip_types application/javascript application/json;
    gzip_min_length 1000;

    include /etc/nginx/conf.d/*.conf;
}

default.conf

server {
    listen 8080 default;
    server_name _;
    root  /var/www/html/sample-app;

    # code igniter用の redirect
    location / {
        try_files $uri $uri/ /public/index.php$request_uri;
    }

    location ~ [^/]\.php(/|$) {
        fastcgi_pass 127.0.0.1:9000;
        fastcgi_read_timeout 120;
        fastcgi_split_path_info ^(.+?\.php)(/.*)$;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME     $document_root$fastcgi_script_name;
        fastcgi_param PATH_INFO $fastcgi_path_info;
    }
}

docker-compose.yaml

version: "3.4"

services:
  php:
    build:
      context: .
    environment:
      - REDIS_HOST=localhost
    ports:
      - "9000:9000"
    volumes:
      - .:/var/www/html/sample-app

  nginx:
    build:
      context: .
      dockerfile: Dockerfile-nginx
      # docker-compose起動のときはdocker container network
      args:
        - PHP_HOST=php:9000
    ports:
      - "8080:8080"
    depends_on:
      - php

container size

Container Size
php-debian 436 MB
nginx-debian 150 MB
php-alpine 96 MB
nginx-alpine 23 MB

ぜんぜん違う 🧐

ECS (FARGATE) 起動速度

Provisioning 開始から Runningになるまでの秒数で計測
それぞれ3回試して、平均値を取りました。当初もっと試行回数を取ろうと思っていましたが、速度が安定していたので十分と判断しました。

Type Sec
debian base 41
alpine base 30

alpine baseの方が 10 sec ほど早くなりました。10 secの起動速度差は結構大きいのでは。やはり、軽いは正義。

まとめ

早くなってよかった (konami kan)