ืชืžื•ื ืช Docker ืœื”ืคืฆื” ืฉืœ ื™ื™ืฉื•ื ืขืžื•ื“ ื‘ื•ื“ื“

ื™ื™ืฉื•ื ืฉืœ ืขืžื•ื“ ื‘ื•ื“ื“ (SPA) ื”ื•ื ืงื‘ื•ืฆื” ืฉืœ ืงื•ื‘ืฆื™ JavaScript ื•-HTML ืกื˜ื˜ื™ื™ื, ื›ืžื• ื’ื ืชืžื•ื ื•ืช ื•ืžืฉืื‘ื™ื ืื—ืจื™ื. ืžื›ื™ื•ื•ืŸ ืฉื”ื ืื™ื ื ืžืฉืชื ื™ื ื‘ืื•ืคืŸ ื“ื™ื ืžื™, ืคืจืกื•ื ืื•ืชื ื‘ืื™ื ื˜ืจื ื˜ ื”ื•ื ืงืœ ืžืื•ื“. ื™ืฉ ืžืกืคืจ ืจื‘ ืฉืœ ืฉื™ืจื•ืชื™ื ื–ื•ืœื™ื ื•ืืคื™ืœื• ื—ื™ื ืžื™ื™ื ืขื‘ื•ืจ ื–ื”, ื”ื—ืœ ืž-GitHub Pages ืคืฉื•ื˜ (ื•ืขื‘ื•ืจ ื—ืœืงื ืืคื™ืœื• ืขื narod.ru) ื•ื›ืœื” ื‘-CDN ื›ืžื• Amazon S3. ืขื ื–ืืช, ื”ื™ื™ืชื™ ืฆืจื™ืš ืžืฉื”ื• ืื—ืจ.

ื”ื™ื™ืชื™ ืฆืจื™ืš ืชืžื•ื ืช Docker ืขื SPA ื›ื“ื™ ืฉื ื™ืชืŸ ื™ื”ื™ื” ืœื”ืฉื™ืง ืื•ืชื” ื‘ืงืœื•ืช ื’ื ื‘ื™ื™ืฆื•ืจ ื›ื—ืœืง ืžืืฉื›ื•ืœ Kubernetes, ื•ื’ื ื‘ืžื›ื•ื ื” ืฉืœ ืžืคืชื— ืื—ื•ืจื™ ืฉืื™ืŸ ืœื• ืžื•ืฉื’ ืžื” ื–ื” SPA.

ืงื‘ืขืชื™ ืœืขืฆืžื™ ืืช ื“ืจื™ืฉื•ืช ื”ืชืžื•ื ื” ื”ื‘ืื•ืช:

  • ืงืœื•ืช ืฉื™ืžื•ืฉ (ืืš ืœื ื”ืจื›ื‘ื”);
  • ื’ื•ื“ืœ ืžื™ื ื™ืžืœื™ ื”ืŸ ืžื‘ื—ื™ื ืช ื“ื™ืกืง ื•ื”ืŸ ืžื‘ื—ื™ื ืช ื–ื™ื›ืจื•ืŸ RAM;
  • ืชืฆื•ืจื” ื‘ืืžืฆืขื•ืช ืžืฉืชื ื™ ืกื‘ื™ื‘ื” ื›ืš ืฉื ื™ืชืŸ ื™ื”ื™ื” ืœื”ืฉืชืžืฉ ื‘ืชืžื•ื ื” ื‘ืกื‘ื™ื‘ื•ืช ืฉื•ื ื•ืช;
  • ื”ื”ืคืฆื” ื”ื™ืขื™ืœื” ื‘ื™ื•ืชืจ ืฉืœ ืงื‘ืฆื™ื.

ื”ื™ื•ื ืืกืคืจ ืœื›ื ืื™ืš:

  • nginx ื‘ื˜ืŸ;
  • ืœื‘ื ื•ืช ื‘ืจื•ื˜ืœื™ ืžืžืงื•ืจื•ืช;
  • ืœืœืžื“ ืงื‘ืฆื™ื ืกื˜ื˜ื™ื™ื ืœื”ื‘ื™ืŸ ืžืฉืชื ื™ ืกื‘ื™ื‘ื”;
  • ื•ื›ืžื•ื‘ืŸ ืื™ืš ืœื”ืจื›ื™ื‘ ืชืžื•ื ืช Docker ืžื›ืœ ื–ื”.

ืžื˜ืจืช ืžืืžืจ ื–ื” ื”ื™ื ืœืฉืชืฃ ืžื ื™ืกื™ื•ื ื™ ื•ืœืขื•ืจืจ ืืช ื—ื‘ืจื™ ื”ืงื”ื™ืœื” ื”ืžื ื•ืกื™ื ืœื‘ื™ืงื•ืจืช ื‘ื•ื ื”.

ื‘ื ื™ื™ืช ืชืžื•ื ื” ืœื”ืจื›ื‘ื”

ื›ื“ื™ ืœื”ืคื•ืš ืืช ืชืžื•ื ืช ื”-Docker ื”ืกื•ืคื™ืช ืœืงื˜ื ื” ื‘ื’ื•ื“ืœื”, ืขืœื™ืš ืœื”ืงืคื™ื“ ืขืœ ืฉื ื™ ื›ืœืœื™ื: ืžื™ื ื™ืžื•ื ืฉื›ื‘ื•ืช ื•ืชืžื•ื ืช ื‘ืกื™ืก ืžื™ื ื™ืžืœื™ืกื˜ื™ืช. ืื—ืช ืžืชืžื•ื ื•ืช ื”ื‘ืกื™ืก ื”ืงื˜ื ื•ืช ื‘ื™ื•ืชืจ ื”ื™ื ืชืžื•ื ืช Alpine Linux, ืื– ื–ื” ืžื” ืฉืื ื™ ืื‘ื—ืจ. ื™ืฉ ืฉื™ื˜ืขื ื• ืฉื”ืืœืคื™ืŸ ืื™ื ื• ืžืชืื™ื ืœื™ื™ืฆื•ืจ, ื•ืื•ืœื™ ื”ื ืฆื•ื“ืงื™ื. ืื‘ืœ ืื™ืฉื™ืช, ืžืขื•ืœื ืœื ื”ื™ื• ืœื™ ื‘ืขื™ื•ืช ืื™ืชื• ื•ืื™ืŸ ื˜ืขื ื•ืช ื ื’ื“ื•.

ื›ื“ื™ ืฉื™ื”ื™ื• ืคื—ื•ืช ืฉื›ื‘ื•ืช, ืืจื›ื™ื‘ ืืช ื”ืชืžื•ื ื” ื‘-2 ืฉืœื‘ื™ื. ื”ืจืืฉื•ืŸ ื”ื•ื ื˜ื™ื•ื˜ื”; ื›ืœ ื›ืœื™ ื”ืขื–ืจ ื•ื”ืงื‘ืฆื™ื ื”ื–ืžื ื™ื™ื ื™ื™ืฉืืจื• ื‘ื”. ื•ื‘ืฉืœื‘ ื”ืกื•ืคื™ ืื›ืชื•ื‘ ืจืง ืืช ื”ื’ืจืกื” ื”ืกื•ืคื™ืช ืฉืœ ื”ืืคืœื™ืงืฆื™ื”.

ื ืชื—ื™ืœ ื‘ืชืžื•ื ืช ื”ืขื–ืจ.

ื›ื“ื™ ืœื”ืจื›ื™ื‘ ืืคืœื™ืงืฆื™ื™ืช SPA, ืืชื” ื‘ื“ืจืš ื›ืœืœ ืฆืจื™ืš node.js. ืื ื™ ืืงื— ืืช ื”ืชืžื•ื ื” ื”ืจืฉืžื™ืช, ืฉืžื’ื™ืขื” ื’ื ืขื ืžื ื”ืœื™ npm ื•ื—ื‘ื™ืœื•ืช ื—ื•ื˜ื™ื. ื‘ืฉืžื™, ืื•ืกื™ืฃ ืืช node-gyp, ืฉื“ืจื•ืฉ ืœื‘ื ื™ื™ืช ื›ืžื” ื—ื‘ื™ืœื•ืช npm, ื•ืืช ื”ืžื“ื—ืก Brotli ืžื’ื•ื’ืœ, ืฉื™ื”ื™ื” ืฉื™ืžื•ืฉื™ ืขื‘ื•ืจื ื• ื‘ื”ืžืฉืš.

Dockerfile ืขื ื”ืขืจื•ืช.

# ะ‘ะฐะทะพะฒั‹ะน ะพะฑั€ะฐะท
FROM node:12-alpine
LABEL maintainer="Aleksey Maydokin <[email protected]>"
ENV BROTLI_VERSION 1.0.7
# ะŸะฐะบะตั‚ั‹, ะบะพั‚ะพั€ั‹ะต ะฝัƒะถะฝั‹, ั‡ั‚ะพะฑั‹ ัะพะฑั€ะฐั‚ัŒ ะธะท ะธัั…ะพะดะฝะธะบะพะฒ Brotli
RUN apk add --no-cache --virtual .build-deps 
        bash 
        gcc 
        libc-dev 
        make 
        linux-headers 
        cmake 
        curl 
    && mkdir -p /usr/src 
    # ะ˜ัั…ะพะดะฝะธะบะธ Brotli ัะบะฐั‡ะธะฒะฐะตะผ ะธะท ะพั„ะธั†ะธะฐะปัŒะฝะพะณะพ ั€ะตะฟะพะทะธั‚ะพั€ะธั
    && curl -LSs https://github.com/google/brotli/archive/v$BROTLI_VERSION.tar.gz | tar xzf - -C /usr/src 
    && cd /usr/src/brotli-$BROTLI_VERSION 
    # ะšะพะผะฟะธะปะธั€ัƒะตะผ Brotli
    && ./configure-cmake --disable-debug && make -j$(getconf _NPROCESSORS_ONLN) && make install 
    # ะ”ะพะฑะฐะฒะปัะตะผ node-gyp
    && yarn global add node-gyp 
    # ะฃะฑะธั€ะฐะตะผ ะทะฐ ัะพะฑะพะน ะผัƒัะพั€
    && apk del .build-deps && yarn cache clean && rm -rf /usr/src

ื›ื‘ืจ ื›ืืŸ ืื ื™ ื ืœื—ื ืœืžื™ื ื™ืžืœื™ื–ื, ืื– ื”ืชืžื•ื ื” ืžื•ืจื›ื‘ืช ืขืœ ื™ื“ื™ ืฆื•ื•ืช ืื—ื“ ื’ื“ื•ืœ.

ืืช ื”ืชืžื•ื ื” ื”ืžื•ื’ืžืจืช ื ื™ืชืŸ ืœืžืฆื•ื ื›ืืŸ: https://hub.docker.com/r/alexxxnf/spa-builder. ืœืžืจื•ืช ืฉืื ื™ ืžืžืœื™ืฅ ืœื ืœื”ืกืชืžืš ืขืœ ืชืžื•ื ื•ืช ืฉืœ ืื—ืจื™ื ื•ืœืืกื•ืฃ ืชืžื•ื ื•ืช ืžืฉืœืš.

nginx

ืืชื” ื™ื›ื•ืœ ืœื”ืฉืชืžืฉ ื‘ื›ืœ ืฉืจืช ืื™ื ื˜ืจื ื˜ ื›ื“ื™ ืœื”ืคื™ืฅ ืชื•ื›ืŸ ืกื˜ื˜ื™. ืื ื™ ืจื’ื™ืœ ืœืขื‘ื•ื“ ืขื nginx, ืื– ืื ื™ ืืฉืชืžืฉ ื‘ื• ืขื›ืฉื™ื•.

ืœ-Nginx ื™ืฉ ืชืžื•ื ืช Docker ืจืฉืžื™ืช, ืื‘ืœ ื™ืฉ ืœื” ื™ื•ืชืจ ืžื“ื™ ืžื•ื“ื•ืœื™ื ืœื”ืคืฆื” ืกื˜ื˜ื™ืช ืคืฉื•ื˜ื”. ืื™ืœื• ืžื”ื ื›ืœื•ืœื™ื ื‘ืžืฉืœื•ื— ื ื™ืชืŸ ืœืจืื•ืช ืขืœ ื™ื“ื™ ืฆื•ื•ืช ืžื™ื•ื—ื“ ืื• ื‘-Dockerfile ื”ืจืฉืžื™.

$ docker run --rm nginx:1-alpine nginx -V

nginx version: nginx/1.17.9
built by gcc 8.3.0 (Alpine 8.3.0) 
built with OpenSSL 1.1.1d  10 Sep 2019
TLS SNI support enabled
configure arguments: --prefix=/etc/nginx --sbin-path=/usr/sbin/nginx --modules-path=/usr/lib/nginx/modules --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --pid-path=/var/run/nginx.pid --lock-path=/var/run/nginx.lock --http-client-body-temp-path=/var/cache/nginx/client_temp --http-proxy-temp-path=/var/cache/nginx/proxy_temp --http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp --http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp --http-scgi-temp-path=/var/cache/nginx/scgi_temp --with-perl_modules_path=/usr/lib/perl5/vendor_perl --user=nginx --group=nginx --with-compat --with-file-aio --with-threads --with-http_addition_module --with-http_auth_request_module --with-http_dav_module --with-http_flv_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_mp4_module --with-http_random_index_module --with-http_realip_module --with-http_secure_link_module --with-http_slice_module --with-http_ssl_module --with-http_stub_status_module --with-http_sub_module --with-http_v2_module --with-mail --with-mail_ssl_module --with-stream --with-stream_realip_module --with-stream_ssl_module --with-stream_ssl_preread_module --with-cc-opt='-Os -fomit-frame-pointer' --with-ld-opt=-Wl,--as-needed

ืื ื™ ืืฉืชืžืฉ ื‘-Dockerfile ื›ื‘ืกื™ืก, ืื‘ืœ ืืฉืื™ืจ ื‘ื• ืจืง ืืช ืžื” ืฉืฆืจื™ืš ื›ื“ื™ ืœื”ืคื™ืฅ ืชื•ื›ืŸ ืกื˜ื˜ื™. ื”ื’ืจืกื” ืฉืœื™ ืœื ืชื•ื›ืœ ืœืขื‘ื•ื“ ืขืœ HTTPS, ืœื ืชืชืžื•ืš ื‘ื”ืจืฉืื” ื•ืขื•ื“ ื”ืจื‘ื” ื™ื•ืชืจ. ืื‘ืœ ื”ื’ืจืกื” ืฉืœื™ ืชื•ื›ืœ ืœื”ืคื™ืฅ ืงื‘ืฆื™ื ื“ื—ื•ืกื™ื ืขื ืืœื’ื•ืจื™ืชื Brotli, ืฉื”ื•ื ืžืขื˜ ื™ื•ืชืจ ื™ืขื™ืœ ืž-gzip. ื ื“ื—ื•ืก ืงื‘ืฆื™ื ืคืขื ืื—ืช; ืื™ืŸ ืฆื•ืจืš ืœืขืฉื•ืช ื–ืืช ืชื•ืš ื›ื“ื™ ืชื ื•ืขื”.

ื–ื” ื”-Dockerfile ืฉื”ื’ืขืชื™ ืืœื™ื•. ื”ื”ืขืจื•ืช ื‘ืจื•ืกื™ืช ื”ืŸ ืฉืœื™, ื‘ืื ื’ืœื™ืช - ืžื”ืžืงื•ืจ.

ื“ื•ืงืจืคื™ืœ

# ะ‘ะฐะทะพะฒั‹ะน ะพะฑั€ะฐะท ัะฝะพะฒะฐ Alpine
FROM alpine:3.9
LABEL maintainer="Aleksey Maydokin <[email protected]>"
ENV NGINX_VERSION 1.16.0
ENV NGX_BROTLI_VERSION 0.1.2
ENV BROTLI_VERSION 1.0.7
RUN set -x 
    && addgroup -S nginx 
    && adduser -D -S -h /var/cache/nginx -s /sbin/nologin -G nginx nginx 
# ะฃัั‚ะฐะฝะฐะฒะปะธะฒะฐะตะผ ะฟะฐะบะตั‚ั‹, ะบะพั‚ะพั€ั‹ะต ะฝัƒะถะฝั‹ ั‡ั‚ะพะฑั‹ ัะพะฑั€ะฐั‚ัŒ nginx ะธ ะผะพะดัƒะปัŒ ngx_brotli ะบ ะฝะตะผัƒ
    && apk add --no-cache --virtual .build-deps 
            gcc 
            libc-dev 
            make 
            linux-headers 
            curl 
    && mkdir -p /usr/src 
# ะกะบะฐั‡ะธะฒะฐะตะผ ะธัั…ะพะดะฝะธะบะธ
    && curl -LSs https://nginx.org/download/nginx-$NGINX_VERSION.tar.gz | tar xzf - -C /usr/src 
    && curl -LSs https://github.com/eustas/ngx_brotli/archive/v$NGX_BROTLI_VERSION.tar.gz | tar xzf - -C /usr/src 
    && curl -LSs https://github.com/google/brotli/archive/v$BROTLI_VERSION.tar.gz | tar xzf - -C /usr/src 
    && rm -rf /usr/src/ngx_brotli-$NGX_BROTLI_VERSION/deps/brotli/ 
    && ln -s /usr/src/brotli-$BROTLI_VERSION /usr/src/ngx_brotli-$NGX_BROTLI_VERSION/deps/brotli 
    && cd /usr/src/nginx-$NGINX_VERSION 
    && CNF="
            --prefix=/etc/nginx 
            --sbin-path=/usr/sbin/nginx 
            --modules-path=/usr/lib/nginx/modules 
            --conf-path=/etc/nginx/nginx.conf 
            --error-log-path=/var/log/nginx/error.log 
            --http-log-path=/var/log/nginx/access.log 
            --pid-path=/var/run/nginx.pid 
            --lock-path=/var/run/nginx.lock 
            --http-client-body-temp-path=/var/cache/nginx/client_temp 
            --http-proxy-temp-path=/var/cache/nginx/proxy_temp 
            --http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp 
            --http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp 
            --http-scgi-temp-path=/var/cache/nginx/scgi_temp 
            --user=nginx 
            --group=nginx 
            --without-http_ssi_module 
            --without-http_userid_module 
            --without-http_access_module 
            --without-http_auth_basic_module 
            --without-http_mirror_module 
            --without-http_autoindex_module 
            --without-http_geo_module 
            --without-http_split_clients_module 
            --without-http_referer_module 
            --without-http_rewrite_module 
            --without-http_proxy_module 
            --without-http_fastcgi_module 
            --without-http_uwsgi_module 
            --without-http_scgi_module 
            --without-http_grpc_module 
            --without-http_memcached_module 
            --without-http_limit_conn_module 
            --without-http_limit_req_module 
            --without-http_empty_gif_module 
            --without-http_browser_module 
            --without-http_upstream_hash_module 
            --without-http_upstream_ip_hash_module 
            --without-http_upstream_least_conn_module 
            --without-http_upstream_keepalive_module 
            --without-http_upstream_zone_module 
            --without-http_gzip_module 
            --with-http_gzip_static_module 
            --with-threads 
            --with-compat 
            --with-file-aio 
            --add-dynamic-module=/usr/src/ngx_brotli-$NGX_BROTLI_VERSION 
    " 
# ะกะพะฑะธั€ะฐะตะผ
    && ./configure $CNF 
    && make -j$(getconf _NPROCESSORS_ONLN) 
    && make install 
    && rm -rf /usr/src/ 
# ะฃะดะฐะปัะตะผ ะดะธะฝะฐะผะธั‡ะตัะบะธะน brotli ะผะพะดัƒะปัŒ, ะพัั‚ะฐะฒะปัั ั‚ะพะปัŒะบะพ ัั‚ะฐั‚ะธั‡ะตัะบะธะน
    && rm /usr/lib/nginx/modules/ngx_http_brotli_filter_module.so 
    && sed -i '$ d' /etc/apk/repositories 
# Bring in gettext so we can get `envsubst`, then throw
# the rest away. To do this, we need to install `gettext`
# then move `envsubst` out of the way so `gettext` can
# be deleted completely, then move `envsubst` back.
    && apk add --no-cache --virtual .gettext gettext 
    && mv /usr/bin/envsubst /tmp/ 
    && runDeps="$( 
        scanelf --needed --nobanner /usr/sbin/nginx /usr/lib/nginx/modules/*.so /tmp/envsubst 
            | awk '{ gsub(/,/, "nso:", $2); print "so:" $2 }' 
            | sort -u 
            | xargs -r apk info --installed 
            | sort -u 
    )" 
    && apk add --no-cache $runDeps 
    && apk del .build-deps 
    && apk del .gettext 
    && mv /tmp/envsubst /usr/local/bin/ 
# Bring in tzdata so users could set the timezones through the environment
# variables
    && apk add --no-cache tzdata 
# forward request and error logs to docker log collector
    && ln -sf /dev/stdout /var/log/nginx/access.log 
    && ln -sf /dev/stderr /var/log/nginx/error.log
COPY nginx.conf /etc/nginx/nginx.conf
EXPOSE 80
STOPSIGNAL SIGTERM
CMD ["nginx", "-g", "daemon off;"]

ืื ื™ ืžื™ื“ ืืชืงืŸ ืืช nginx.conf ื›ืš ืฉ-gzip ื•-brotli ืžื•ืคืขืœื™ื ื›ื‘ืจื™ืจืช ืžื—ื“ืœ. ืื ื™ ืื›ืœื•ืœ ื’ื ื›ื•ืชืจื•ืช ืฉืœ ืžื˜ืžื•ืŸ, ื›ื™ ืœื ื™ื”ื™ื” ืœื ื• ืกื˜ื˜ื™ ืžืฉืชื ื” ืœืขื•ืœื. ื•ื”ืžื’ืข ื”ืื—ืจื•ืŸ ื™ื”ื™ื” ืœื”ืคื ื•ืช ืืช ื›ืœ 404 ื”ื‘ืงืฉื•ืช ืœ-index.html, ื–ื” ื”ื›ืจื—ื™ ืœื ื™ื•ื•ื˜ ื‘-SPA.

nginx.conf

user nginx;
worker_processes  1;
error_log /var/log/nginx/error.log warn;
pid       /var/run/nginx.pid;
load_module /usr/lib/nginx/modules/ngx_http_brotli_static_module.so;
events {
    worker_connections 1024;
}
http {
    include      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;
    keepalive_timeout 65;
    gzip_static   on;
    brotli_static on;
    server {
        listen      80;
        server_name localhost;
        charset utf-8;
        location / {
            root html;
            try_files $uri /index.html;
            etag on;
            expires max;
            add_header Cache-Control public;
            location = /index.html {
                expires 0;
                add_header Cache-Control "no-cache, public, must-revalidate, proxy-revalidate";
            }
        }
    }
}

ืืชื” ื™ื›ื•ืœ ืœื”ื•ืจื™ื“ ืืช ื”ืชืžื•ื ื” ื”ืžื•ื’ืžืจืช ื›ืืŸ: https://hub.docker.com/r/alexxxnf/nginx-spa. ื–ื” ืชื•ืคืก 10,5 ืžื’ื”-ื‘ื™ื™ื˜. ื”-nginx ื”ืžืงื•ืจื™ ืชืคืก 19,7 ืžื’ื”-ื‘ื™ื™ื˜. ื”ืขื ื™ื™ืŸ ื”ืกืคื•ืจื˜ื™ื‘ื™ ืฉืœื™ ืžืจื•ืฆื”.

ื”ื•ืจืืช ืกื˜ื˜ื™ืงื” ืœื”ื‘ื ืช ืžืฉืชื ื™ ืกื‘ื™ื‘ื”

ืžื“ื•ืข ื™ื™ืชื›ืŸ ืฉื™ื”ื™ื” ืฆื•ืจืš ื‘ื”ื’ื“ืจื•ืช ื‘ืกืคื? ืœื“ื•ื’ืžื”, ืขืœ ืžื ืช ืœืฆื™ื™ืŸ ื‘ืื™ื–ื” RESTful API ืœื”ืฉืชืžืฉ. ื‘ื“ืจืš ื›ืœืœ, ื”ื’ื“ืจื•ืช ืขื‘ื•ืจ ื”ืกื‘ื™ื‘ื” ื”ืจืฆื•ื™ื” ืžื•ืขื‘ืจื•ืช ืœ-SPA ื‘ืฉืœื‘ ื”ื‘ื ื™ื™ื”. ืื ืืชื” ืฆืจื™ืš ืœืฉื ื•ืช ืžืฉื”ื•, ืชืฆื˜ืจืš ืœื‘ื ื•ืช ืžื—ื“ืฉ ืืช ื”ื™ื™ืฉื•ื. ืื ื™ ืœื ืจื•ืฆื” ืืช ื–ื”. ืื ื™ ืจื•ืฆื” ืฉื”ืืคืœื™ืงืฆื™ื” ืชื™ื‘ื ื” ืคืขื ืื—ืช ื‘ืฉืœื‘ ื”-CI, ื•ืชืฆื•ืจื” ื›ื›ืœ ื”ื“ืจื•ืฉ ื‘ืฉืœื‘ ื”ืชืงืœื™ื˜ื•ืจ ื‘ืืžืฆืขื•ืช ืžืฉืชื ื™ ืกื‘ื™ื‘ื”.

ื›ืžื•ื‘ืŸ, ืงื‘ืฆื™ื ืกื˜ื˜ื™ื™ื ืขืฆืžื ืื™ื ื ืžื‘ื™ื ื™ื ืืฃ ืžืฉืชื ื™ ืกื‘ื™ื‘ื”. ืœื›ืŸ, ืชืฆื˜ืจืš ืœื”ืฉืชืžืฉ ื‘ื˜ืจื™ืง. ื‘ืชืžื•ื ื” ื”ืกื•ืคื™ืช ืื ื™ ืœื ืืฉื™ืง nginx, ืืœื ืกืงืจื™ืคื˜ ืžืขื˜ืคืช ืžื™ื•ื—ื“ ืฉื™ืงืจื ืžืฉืชื ื™ ืกื‘ื™ื‘ื”, ื™ื›ืชื•ื‘ ืื•ืชื ืœืงื‘ืฆื™ื ืกื˜ื˜ื™ื™ื, ื™ื“ื—ื•ืก ืื•ืชื ื•ืจืง ืื– ื™ืขื‘ื™ืจ ืืช ื”ืฉืœื™ื˜ื” ืœ-nginx.

ืœืžื˜ืจื” ื–ื•, ื”-Dockerfile ืžืกืคืง ืืช ื”ืคืจืžื˜ืจ ENTRYPOINT. ื‘ื•ืื• ื ื™ืชืŸ ืœื• ืืช ื”ืชืกืจื™ื˜ ื”ื‘ื (ื‘ืืžืฆืขื•ืช Angular ื›ื“ื•ื’ืžื”):

docker-entrypoint.sh

#!/bin/sh
set -e
FLAG_FILE="/configured"
TARGET_DIR="/etc/nginx/html"
replace_vars () {
  ENV_VARS='$(awk 'BEGIN{for(v in ENVIRON) print "

quot;v}')'
# ะ’ Angular ะธั‰ะตะผ ะฟะปะตะนัั…ะพะปะดะตั€ั‹ ะฒ main-ั„ะฐะนะปะฐั…
for f in "$TARGET_DIR"/main*.js; do
# envsubst ะทะฐะผะตะฝัะตั‚ ะฒ ั„ะฐะนะปะฐั… ะฟะปะตะนัั…ะพะปะดะตั€ั‹ ะฝะฐ ะทะฝะฐั‡ะตะฝะธั ะธะท ะฟะตั€ะตะผะตะฝะฝั‹ั… ะพะบั€ัƒะถะตะฝะธั
echo "$(envsubst "$ENV_VARS" < "$f")" > "$f"
done
}
compress () {
for i in $(find "$TARGET_DIR" | grep -E ".css$|.html$|.js$|.svg$|.txt$|.ttf


quot;); do
# ะ˜ัะฟะพะปัŒะทัƒะตะผ ะผะฐะบัะธะผะฐะปัŒะฝัƒัŽ ัั‚ะตะฟะตะฝัŒ ัะถะฐั‚ะธั
gzip -9kf "$i" && brotli -fZ "$i"
done
}
if [ "$1" = 'nginx' ]; then
# ะคะปะฐะณ ะฝัƒะถะตะฝ, ั‡ั‚ะพะฑั‹ ะฒั‹ะฟะพะปะฝะธั‚ัŒ ัะบั€ะธะฟั‚ ั‚ะพะปัŒะบะพ ะฟั€ะธ ัะฐะผะพะผ ะฟะตั€ะฒะพะผ ะทะฐะฟัƒัะบะต
if [ ! -e "$FLAG_FILE" ]; then
echo "Running init script"
echo "Replacing env vars"
replace_vars
echo "Compressing files"
compress
touch $FLAG_FILE
echo "Done"
fi
fi
exec "$@"

ืขืœ ืžื ืช ืฉื”ืกืงืจื™ืคื˜ ื™ืขืฉื” ืืช ืขื‘ื•ื“ืชื•, ื™ืฉ ืœื›ืชื•ื‘ ืืช ื”ื”ื’ื“ืจื•ืช ื‘ืงื‘ืฆื™ js ื‘ืฆื•ืจื” ื–ื•: ${API_URL}.

ืจืื•ื™ ืœืฆื™ื™ืŸ ืฉืจื•ื‘ ื”-SPAs ื”ืžื•ื“ืจื ื™ื™ื ืžื•ืกื™ืคื™ื ื’ื™ื‘ื•ื‘ ืœืงื‘ืฆื™ื ืฉืœื”ื ื‘ืขืช ื”ื‘ื ื™ื™ื”. ื–ื” ื”ื›ืจื—ื™ ื›ื“ื™ ืฉื”ื“ืคื“ืคืŸ ื™ื•ื›ืœ ืœืฉืžื•ืจ ืืช ื”ืงื•ื‘ืฅ ื‘ื‘ื˜ื—ื” ื‘ืžืฉืš ื–ืžืŸ ืจื‘. ืื ื”ืงื•ื‘ืฅ ืื›ืŸ ื™ืฉืชื ื”, ื”-hash ืฉืœื• ื™ืฉืชื ื”, ืžื” ืฉื‘ืชื•ืจื• ื™ืืœืฅ ืืช ื”ื“ืคื“ืคืŸ ืœื”ื•ืจื™ื“ ืืช ื”ืงื•ื‘ืฅ ืฉื•ื‘.

ืœืฆืขืจื™, ื‘ืฉื™ื˜ื” ืฉืœื™, ืฉื™ื ื•ื™ ื”ืชืฆื•ืจื” ื‘ืืžืฆืขื•ืช ืžืฉืชื ื™ ืกื‘ื™ื‘ื” ืœื ืžื•ื‘ื™ืœ ืœืฉื™ื ื•ื™ ื‘-hash ืฉืœ ื”ืงื•ื‘ืฅ, ืžื” ืฉืื•ืžืจ ืฉื™ืฉ ืœื‘ื˜ืœ ืืช ืžื˜ืžื•ืŸ ื”ื“ืคื“ืคืŸ ื‘ื“ืจืš ืื—ืจืช. ืื™ืŸ ืœื™ ื‘ืขื™ื” ื–ื• ื›ื™ ืชืฆื•ืจื•ืช ืฉื•ื ื•ืช ืคืจื•ืกื•ืช ื‘ืกื‘ื™ื‘ื•ืช ืฉื•ื ื•ืช.

ืžืจื›ื™ื‘ื™ื ืืช ื”ืชืžื•ื ื” ื”ืกื•ืคื™ืช

ืกื•ืฃ ื›ืœ ืกื•ืฃ.

ื“ื•ืงืจืคื™ืœ

# ะŸะตั€ะฒั‹ะน ะฑะฐะทะพะฒั‹ะน ะพะฑั€ะฐะท ะดะปั ัะฑะพั€ะบะธ
FROM alexxxnf/spa-builder as builder
# ะงั‚ะพะฑั‹ ัั„ั„ะบั‚ะธะฒะฝะตะต ะธัะฟะพะปัŒะทะพะฒะฐั‚ัŒ ะบััˆ Docker-ะฐ, ัะฝะฐั‡ะฐะปะฐ ัƒัั‚ะฐะฝะฐะฒะปะธะฒะฐะตะผ ั‚ะพะปัŒะบะพ ะทะฐะฒะธัะธะผะพัั‚ะธ
COPY ./package.json ./package-lock.json /app/
RUN cd /app && npm ci --no-audit
# ะŸะพั‚ะพะผ ัะพะฑะธั€ะฐะตะผ ัะฐะผะพ ะฟั€ะธะปะพะถะตะฝะธะต
COPY . /app
RUN cd /app && npm run build -- --prod --configuration=docker

# ะ’ั‚ะพั€ะพะน ะฑะฐะทะพะฒั‹ะน ะพะฑั€ะฐะท ะดะปั ั€ะฐะทะดะฐั‡ะธ
FROM alexxxnf/nginx-spa
# ะ—ะฐะฑะธั€ะฐะตะผ ะธะท ะฟะตั€ะฒะพะณะพ ะพะฑั€ะฐะทะฐ ัะฝะฐั‡ะฐะปะฐ ะบะพะผะฟั€ะตััะพั€
COPY --from=builder /usr/local/bin/brotli /usr/local/bin
# ะŸะพั‚ะพะผ ะดะพะฑะฐะฒะปัะตะผ ั‡ัƒะดะพ-ัะบั€ะธะฟั‚
COPY ./docker/docker-entrypoint.sh /docker-entrypoint.sh
# ะ˜ ะฒ ะบะพะฝั†ะต ะทะฐะฑะธั€ะฐะตะผ ัะฐะผะพ ะฟั€ะธะปะพะถะตะฝะธะต
COPY --from=builder /app/dist/app /etc/nginx/html/
ENTRYPOINT ["/docker-entrypoint.sh"]
CMD ["nginx", "-g", "daemon off;"]

ื›ืขืช ื ื™ืชืŸ ืœื”ืจื›ื™ื‘ ืืช ื”ืชืžื•ื ื” ื”ืžืชืงื‘ืœืช ื•ืœื”ืฉืชืžืฉ ื‘ื” ื‘ื›ืœ ืžืงื•ื.

ืžืงื•ืจ: www.habr.com