Docker ΠΎΠ±Ρ€Π°Π· Π·Π° разпространСниС Π½Π° Single Page Application

Едностраничното ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ (SPA) Π΅ Π½Π°Π±ΠΎΡ€ ΠΎΡ‚ статични JavaScript ΠΈ HTML Ρ„Π°ΠΉΠ»ΠΎΠ²Π΅, ΠΊΠ°ΠΊΡ‚ΠΎ ΠΈ изобраТСния ΠΈ Π΄Ρ€ΡƒΠ³ΠΈ рСсурси. Въй ΠΊΠ°Ρ‚ΠΎ Ρ‚Π΅ Π½Π΅ сС промСнят Π΄ΠΈΠ½Π°ΠΌΠΈΡ‡Π½ΠΎ, ΠΏΡƒΠ±Π»ΠΈΠΊΡƒΠ²Π°Π½Π΅Ρ‚ΠΎ ΠΈΠΌ Π² ΠΈΠ½Ρ‚Π΅Ρ€Π½Π΅Ρ‚ Π΅ ΠΌΠ½ΠΎΠ³ΠΎ просто. Π—Π° Ρ†Π΅Π»Ρ‚Π° ΡΡŠΡ‰Π΅ΡΡ‚Π²ΡƒΠ²Π° голямо количСство Π΅Π²Ρ‚ΠΈΠ½ΠΈ ΠΈ Π΄ΠΎΡ€ΠΈ Π±Π΅Π·ΠΏΠ»Π°Ρ‚Π½ΠΈ услуги, Π·Π°ΠΏΠΎΡ‡Π²Π°ΠΉΠΊΠΈ ΠΎΡ‚ простия GitHub Pages (Π° Π·Π° някои Π΄ΠΎΡ€ΠΈ ΠΎΡ‚ narod.ru) ΠΈ стигайки Π΄ΠΎ CDN ΠΊΠ°Ρ‚ΠΎ Amazon S3. Но Π°Π· сС Π½ΡƒΠΆΠ΄Π°Π΅Ρ… ΠΎΡ‚ Π½Π΅Ρ‰ΠΎ Ρ€Π°Π·Π»ΠΈΡ‡Π½ΠΎ.

Π’Ρ€ΡΠ±Π²Π°ΡˆΠ΅ ΠΌΠΈ Docker ΠΎΠ±Ρ€Π°Π· с SPA, Π·Π° Π΄Π° ΠΌΠΎΠΆΠ΅ лСсно Π΄Π° бъдС стартиран ΠΊΠ°ΠΊΡ‚ΠΎ Π² продукция Π² ΡΡŠΡΡ‚Π°Π²Π° Π½Π° Kubernetes ΠΊΠ»ΡŠΡΡ‚Π΅Ρ€Π°, Ρ‚Π°ΠΊΠ° ΠΈ Π½Π° ΠΌΠ°ΡˆΠΈΠ½Π°Ρ‚Π° Π½Π° back-end Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊΠ°, ΠΊΠΎΠΉΡ‚ΠΎ няма прСдстава ΠΊΠ°ΠΊΠ²ΠΎ Π΅ SPA.

ΠžΠΏΡ€Π΅Π΄Π΅Π»ΠΈΡ… слСднитС изисквания Π·Π° ΠΎΠ±Ρ€Π°Π·Π°:

  • лСсСн Π·Π° ΡƒΠΏΠΎΡ‚Ρ€Π΅Π±Π° (Π½ΠΎ Π½Π΅ ΠΏΠΎ Π²Ρ€Π΅ΠΌΠ΅ Π½Π° ΠΈΠ·Π³Ρ€Π°ΠΆΠ΄Π°Π½Π΅);
  • ΠΌΠΈΠ½ΠΈΠΌΠ°Π»Π΅Π½ Ρ€Π°Π·ΠΌΠ΅Ρ€ ΠΊΠ°ΠΊΡ‚ΠΎ ΠΏΠΎ ΠΎΡ‚Π½ΠΎΡˆΠ΅Π½ΠΈΠ΅ Π½Π° диска, Ρ‚Π°ΠΊΠ° ΠΈ ΠΏΠΎ ΠΎΡ‚Π½ΠΎΡˆΠ΅Π½ΠΈΠ΅ Π½Π° RAM;
  • конфигурация Ρ‡Ρ€Π΅Π· ΠΏΡ€ΠΎΠΌΠ΅Π½Π»ΠΈΠ²ΠΈ Π½Π° срСдата, Ρ‚Π°ΠΊΠ° Ρ‡Π΅ ΠΎΠ±Ρ€Π°Π·ΡŠΡ‚ Π΄Π° ΠΌΠΎΠΆΠ΅ Π΄Π° сС ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π° Π² Ρ€Π°Π·Π»ΠΈΡ‡Π½ΠΈ срСди;
  • максимално Π΅Ρ„Π΅ΠΊΡ‚ΠΈΠ²Π½ΠΎ разпространСниС Π½Π° Ρ„Π°ΠΉΠ»ΠΎΠ²Π΅.

ДнСс Ρ‰Π΅ Π²ΠΈ Ρ€Π°Π·ΠΊΠ°ΠΆΠ° ΠΊΠ°ΠΊ:

  • Π΄Π° ΠΈΠ·Π²Π»Π΅ΠΊΠ° nginx;
  • Π΄Π° ΡΡŠΠ±Π΅Ρ€Π° brotli ΠΎΡ‚ изходния ΠΊΠΎΠ΄;
  • Π΄Π° Π½Π°ΡƒΡ‡Π° статичнитС Ρ„Π°ΠΉΠ»ΠΎΠ²Π΅ Π΄Π° Ρ€Π°Π·Π±ΠΈΡ€Π°Ρ‚ ΠΏΡ€ΠΎΠΌΠ΅Π½Π»ΠΈΠ²ΠΈ Π½Π° срСдата;
  • ΠΈ, Ρ€Π°Π·Π±ΠΈΡ€Π° сС, ΠΊΠ°ΠΊ Π΄Π° ΡΡŠΡΡ‚Π°Π²Ρ ΠΎΡ‚ всичко Ρ‚ΠΎΠ²Π° Docker ΠΎΠ±Ρ€Π°Π·.

Π¦Π΅Π»Ρ‚Π° Π½Π° Ρ‚Π°Π·ΠΈ статия Π΅ Π΄Π° сподСли моят ΠΎΠΏΠΈΡ‚ ΠΈ Π΄Π° ΠΏΡ€Π΅Π΄ΠΈΠ·Π²ΠΈΠΊΠ° ΠΎΠΏΠΈΡ‚Π½ΠΈ участници Π² общността Π½Π° конструктивна ΠΊΡ€ΠΈΡ‚ΠΈΠΊΠ°.

БглобяванС Π½Π° ΠΎΠ±Ρ€Π°Π· Π·Π° ΠΈΠ·Π³Ρ€Π°ΠΆΠ΄Π°Π½Π΅

Π—Π° Π΄Π° бъдС финалният Docker ΠΎΠ±Ρ€Π°Π· малък ΠΏΠΎ Ρ€Π°Π·ΠΌΠ΅Ρ€, трябва Π΄Π° сС спазват Π΄Π²Π΅ ΠΏΡ€Π°Π²ΠΈΠ»Π°: ΠΌΠΈΠ½ΠΈΠΌΡƒΠΌ слоСвС ΠΈ минималистичСн Π±Π°Π·ΠΎΠ² ΠΎΠ±Ρ€Π°Π·. Π•Π΄ΠΈΠ½ ΠΎΡ‚ Π½Π°ΠΉ-ΠΌΠ°Π»ΠΊΠΈΡ‚Π΅ Π±Π°Π·ΠΎΠ²ΠΈ ΠΎΠ±Ρ€Π°Π·ΠΈ Π΅ ΠΎΠ±Ρ€Π°Π·ΡŠΡ‚ Alpine Linux, Π·Π°Ρ‚ΠΎΠ²Π° ΠΈΠΌΠ΅Π½Π½ΠΎ Π½Π΅Π³ΠΎ Ρ‰Π΅ ΠΈΠ·Π±Π΅Ρ€Π°. Някой ΠΌΠΎΠΆΠ΅ Π΄Π° Π²ΡŠΠ·Ρ€Π°Π·ΠΈ, Ρ‡Π΅ Alpine Π½Π΅ Π΅ подходящ Π·Π° продукция ΠΈ вСроятно Ρ‰Π΅ бъдС ΠΏΡ€Π°Π². Но Π»ΠΈΡ‡Π½ΠΎ Π°Π· Π½ΠΈΠΊΠΎΠ³Π° Π½Π΅ съм ΠΈΠΌΠ°Π» ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌΠΈ с Π½Π΅Π³ΠΎ ΠΈ нямам Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚ΠΈ срСщу Π½Π΅Π³ΠΎ.

Π—Π° Π΄Π° ΠΈΠΌΠ° ΠΏΠΎ-ΠΌΠ°Π»ΠΊΠΎ слоСвС, Ρ‰Π΅ ΠΈΠ·Π³Ρ€Π°ΠΆΠ΄Π°ΠΌ ΠΎΠ±Ρ€Π°Π·Π° Π½Π° 2 Π΅Ρ‚Π°ΠΏΠ°. ΠŸΡŠΡ€Π²ΠΈΡΡ‚ – Ρ‡Π΅Ρ€Π½ΠΎΠ²ΠΈ, Π² Π½Π΅Π³ΠΎ Ρ‰Π΅ останат всички ΠΏΠΎΠΌΠΎΡ‰Π½ΠΈ ΡƒΡ‚ΠΈΠ»ΠΈΡ‚ΠΈ ΠΈ Π²Ρ€Π΅ΠΌΠ΅Π½Π½ΠΈ Ρ„Π°ΠΉΠ»ΠΎΠ²Π΅. А Π² чистовия Ρ‰Π΅ запиша само Ρ„ΠΈΠ½Π°Π»Π½Π°Ρ‚Π° вСрсия Π½Π° ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅Ρ‚ΠΎ.

НСка Π·Π°ΠΏΠΎΡ‡Π½Π΅ΠΌ с помощния ΠΎΠ±Ρ€Π°Π·.

Π—Π° Π΄Π° ΠΊΠΎΠΌΠΏΠΈΠ»ΠΈΡ€Π°ΠΌΠ΅ SPA ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅Ρ‚ΠΎ, ΠΎΠ±ΠΈΠΊΠ½ΠΎΠ²Π΅Π½ΠΎ Π΅ Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌ node.js. Π©Π΅ Π²Π·Π΅ΠΌΠ° официалния ΠΎΠ±Ρ€Π°Π·, Π² ΠΊΠΎΠΌΠΏΠ»Π΅ΠΊΡ‚ с ΠΊΠΎΠΉΡ‚ΠΎ ΠΈΠΌΠ° ΠΈ ΠΏΠ°ΠΊΠ΅Ρ‚Π½ΠΈ ΠΌΠ΅Π½ΠΈΠ΄ΠΆΡŠΡ€ΠΈ npm ΠΈ yarn. ΠžΡ‚ сСбС си Ρ‰Π΅ добавя node-gyp, ΠΊΠΎΠΉΡ‚ΠΎ Π΅ Π½ΡƒΠΆΠ΅Π½ Π·Π° ΠΈΠ·Π³Ρ€Π°ΠΆΠ΄Π°Π½Π΅ Π½Π° някои npm ΠΏΠ°ΠΊΠ΅Ρ‚ΠΈ, ΠΈ компрСсор Brotli ΠΎΡ‚ Google, ΠΊΠΎΠΉΡ‚ΠΎ Ρ‰Π΅ Π½ΠΈ Π΅ ΠΏΠΎΠ»Π΅Π·Π΅Π½ ΠΏΠΎ-късно.

Dockerfile с ΠΊΠΎΠΌΠ΅Π½Ρ‚Π°Ρ€ΠΈ.

# Π‘Π°Π·ΠΎΠ²Ρ‹ΠΉ ΠΎΠ±Ρ€Π°Π·
FROM node:12-alpine
LABEL maintainer="Aleksey Maydokin <amaydokin@gmail.com>"
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

Π—Π° разпространСниС Π½Π° статични Ρ„Π°ΠΉΠ»ΠΎΠ²Π΅ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ Π΄Π° ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π°Ρ‚Π΅ всСки web-сСрвСр. Аз ΠΈΠΌΠ°ΠΌ Π½Π°Π²ΠΈΠΊΠ° Π΄Π° работя с 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 ΠΏΠΎΠ»ΡƒΡ‡ΠΈΡ…. ΠšΠΎΠΌΠ΅Π½Ρ‚Π°Ρ€ΠΈΡ‚Π΅ Π½Π° руски – ΠΌΠΎΠΈ, Π½Π° английски – ΠΎΡ‚ ΠΎΡ€ΠΈΠ³ΠΈΠ½Π°Π»Π°.

Dockerfile

# Π‘Π°Π·ΠΎΠ²Ρ‹ΠΉ ΠΎΠ±Ρ€Π°Π· снова Alpine
FROM alpine:3.9
LABEL maintainer="Aleksey Maydokin <amaydokin@gmail.com>"
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 MB. ΠžΡ€ΠΈΠ³ΠΈΠ½Π°Π»Π½ΠΈΡΡ‚ nginx Π·Π°Π΅ΠΌΠ° 19,7 MB. Π£Π΄ΠΎΠ²Π»Π΅Ρ‚Π²ΠΎΡ€ΠΈΡ… спортния си интСрСс.

Π£Ρ‡ΠΈΠΌ статичното Π΄Π° Ρ€Π°Π·Π±ΠΈΡ€Π° ΠΏΡ€ΠΎΠΌΠ΅Π½Π»ΠΈΠ²ΠΈ Π½Π° срСдата

Π—Π° ΠΊΠ°ΠΊΠ²ΠΎ са Π½ΡƒΠΆΠ½ΠΈ настройкитС Π² SPA? НапримСр, Π·Π° Π΄Π° ΡƒΠΊΠ°ΠΆΠ΅ΠΌ ΠΊΠΎΠΉ RESTful API Π΄Π° ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π°ΠΌΠ΅. ОбикновСно настройкитС Π·Π° Π½ΡƒΠΆΠ½Π°Ρ‚Π° срСда сС ΠΏΡ€Π΅Π΄Π°Π²Π°Ρ‚ Π½Π° SPA ΠΏΠΎ Π²Ρ€Π΅ΠΌΠ΅ Π½Π° сглобяванСто. Ако трябва Π½Π΅Ρ‰ΠΎ Π΄Π° ΠΏΡ€ΠΎΠΌΠ΅Π½ΠΈΠΌ, Ρ‰Π΅ трябва Π΄Π° ΠΏΡ€Π΅Π³Ρ€ΡƒΠΏΠΈΡ€Π°ΠΌΠ΅ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅Ρ‚ΠΎ. НС искам Ρ‚ΠΎΠ²Π°. Искам ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅Ρ‚ΠΎ Π΄Π° сС сглобява вСднъТ Π½Π° Π΅Ρ‚Π°ΠΏ CI, Π° Π΄Π° сС ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€ΠΈΡ€Π° Ρ‚ΠΎΠ»ΠΊΠΎΠ²Π°, ΠΊΠΎΠ»ΠΊΠΎΡ‚ΠΎ Π΅ Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠΎ, Π½Π° Π΅Ρ‚Π°ΠΏ CD с ΠΏΠΎΠΌΠΎΡ‰Ρ‚Π° Π½Π° ΠΏΡ€ΠΎΠΌΠ΅Π½Π»ΠΈΠ²ΠΈ Π½Π° срСдата.

Π Π°Π·Π±ΠΈΡ€Π° сС, статичнитС Ρ„Π°ΠΉΠ»ΠΎΠ²Π΅ сами ΠΏΠΎ сСбС си Π½Π΅ Ρ€Π°Π·Π±ΠΈΡ€Π°Ρ‚ Π½ΠΈΠΊΠ°ΠΊΠ²ΠΈ ΠΏΡ€ΠΎΠΌΠ΅Π½Π»ΠΈΠ²ΠΈ Π½Π° срСдата. Π—Π°Ρ‚ΠΎΠ²Π° Ρ‰Π΅ трябва Π΄Π° ΠΏΡ€ΠΈΠ±Π΅Π³Π½Π΅ΠΌ Π΄ΠΎ хитрост. Π’ крайния ΠΎΠ±Ρ€Π°Π· Ρ‰Π΅ стартирам Π½Π΅ nginx, Π° спСциалСн shell скрипт, ΠΊΠΎΠΉΡ‚ΠΎ Ρ‰Π΅ ΠΏΡ€ΠΎΡ‡Π΅Ρ‚Π΅ ΠΏΡ€ΠΎΠΌΠ΅Π½Π»ΠΈΠ²ΠΈΡ‚Π΅ Π½Π° срСдата, Ρ‰Π΅ Π³ΠΈ запишС Π² статичнитС Ρ„Π°ΠΉΠ»ΠΎΠ²Π΅, Ρ‰Π΅ Π³ΠΈ компрСсира ΠΈ Π΅Π΄Π²Π° слСд Ρ‚ΠΎΠ²Π° Ρ‰Π΅ ΠΏΡ€Π΅Π΄Π°Π΄Π΅ ΡƒΠΏΡ€Π°Π²Π»Π΅Π½ΠΈΠ΅Ρ‚ΠΎ Π½Π° 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-Ρ„Π°ΠΉΠ»Π°Ρ…
Π·Π° f Π² "$TARGET_DIR"/main*.js; Π½Π°ΠΏΡ€Π°Π²ΠΈ
# envsubst замСняСт Π² Ρ„Π°ΠΉΠ»Π°Ρ… плСйсхолдСры Π½Π° значСния ΠΈΠ· ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½Ρ‹Ρ… окруТСния
echo "$(envsubst "$ENV_VARS" "$f"
Π³ΠΎΡ‚ΠΎΠ²ΠΎ
}
компрСс () {
for i in $(find "$TARGET_DIR" | grep -E ".css$|.html$|.js$|.svg$|.txt$|.ttf

quot;); Π½Π°ΠΏΡ€Π°Π²ΠΈ
# Π˜ΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌ ΠΌΠ°ΠΊΡΠΈΠΌΠ°Π»ΡŒΠ½ΡƒΡŽ ΡΡ‚Π΅ΠΏΠ΅Π½ΡŒ сТатия
gzip -9kf "$i" && brotli -fZ "$i"
Π³ΠΎΡ‚ΠΎΠ²ΠΎ
}
Π°ΠΊΠΎ [ "$1" = 'nginx' ]; Ρ‚ΠΎΠ³Π°Π²Π°
# Π€Π»Π°Π³ Π½ΡƒΠΆΠ΅Π½, Ρ‡Ρ‚ΠΎΠ±Ρ‹ Π²Ρ‹ΠΏΠΎΠ»Π½ΠΈΡ‚ΡŒ скрипт Ρ‚ΠΎΠ»ΡŒΠΊΠΎ ΠΏΡ€ΠΈ самом ΠΏΠ΅Ρ€Π²ΠΎΠΌ запускС
Π°ΠΊΠΎ [ ! -e "$FLAG_FILE" ]; Ρ‚ΠΎΠ³Π°Π²Π°
echo "Π‘Ρ‚Π°Ρ€Ρ‚ΠΈΡ€Π°Π½Π΅ Π½Π° инициализационния скрипт"
echo "Замяна Π½Π° ΠΏΡ€ΠΎΠΌΠ΅Π½Π»ΠΈΠ²ΠΈ Π½Π° срСдата"
replace_vars
echo "ΠšΠΎΠΌΠΏΡ€Π΅ΡΠΈΡ€Π°Π½Π΅ Π½Π° Ρ„Π°ΠΉΠ»ΠΎΠ²Π΅"
компрСс
touch $FLAG_FILE
echo "Π“ΠΎΡ‚ΠΎΠ²ΠΎ"
Ρ„ΠΈ
Ρ„ΠΈ
exec "$@"


Π—Π° Π΄Π° ΠΌΠΎΠΆΠ΅ ΡΠΊΡ€ΠΈΠΏΡ‚ΡŠΡ‚ Π΄Π° ΡΠ²ΡŠΡ€ΡˆΠΈ Ρ€Π°Π±ΠΎΡ‚Π°Ρ‚Π° си, Π² js Ρ„Π°ΠΉΠ»ΠΎΠ²Π΅Ρ‚Π΅ настройкитС трябва Π΄Π° Π±ΡŠΠ΄Π°Ρ‚ записани ΠΏΠΎ слСдния Π½Π°Ρ‡ΠΈΠ½: ${API_URL}.

Π‘Ρ‚Ρ€ΡƒΠ²Π° си Π΄Π° сС ΠΎΡ‚Π±Π΅Π»Π΅ΠΆΠΈ, Ρ‡Π΅ ΠΏΠΎΠ²Π΅Ρ‡Π΅Ρ‚ΠΎ ΡΡŠΠ²Ρ€Π΅ΠΌΠ΅Π½Π½ΠΈ SPA ΠΏΡ€ΠΈ сглобяванС добавят Ρ…Π΅ΡˆΠΎΠ²Π΅ към Ρ„Π°ΠΉΠ»ΠΎΠ²Π΅Ρ‚Π΅ си. Π’ΠΎΠ²Π° Π΅ Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠΎ, Π·Π° Π΄Π° ΠΌΠΎΠΆΠ΅ Π±Ρ€Π°ΡƒΠ·ΡŠΡ€ΡŠΡ‚ спокойно Π΄Π° ΠΊΠ΅ΡˆΠΈΡ€Π° Ρ„Π°ΠΉΠ»Π° Π·Π° дълъг ΠΏΠ΅Ρ€ΠΈΠΎΠ΄. Ако Ρ„Π°ΠΉΠ»ΡŠΡ‚ всС ΠΏΠ°ΠΊ сС ΠΏΡ€ΠΎΠΌΠ΅Π½ΠΈ, Ρ…Π΅ΡˆΡŠΡ‚ ΠΌΡƒ ΡΡŠΡ‰ΠΎ Ρ‰Π΅ сС ΠΏΡ€ΠΎΠΌΠ΅Π½ΠΈ, ΠΊΠΎΠ΅Ρ‚ΠΎ ΠΎΡ‚ своя страна Ρ‰Π΅ Π½Π°ΠΊΠ°Ρ€Π° Π±Ρ€Π°ΡƒΠ·ΡŠΡ€Π° Π΄Π° ΠΈΠ·Ρ‚Π΅Π³Π»ΠΈ Ρ„Π°ΠΉΠ»Π° ΠΎΡ‚Π½ΠΎΠ²ΠΎ.

Π—Π° съТалСниС, Π² моя ΠΌΠ΅Ρ‚ΠΎΠ΄, промяната Π½Π° конфигурацията Ρ‡Ρ€Π΅Π· ΠΏΡ€ΠΎΠΌΠ΅Π½Π»ΠΈΠ²ΠΈ Π½Π° срСдата Π½Π΅ Π²ΠΎΠ΄ΠΈ Π΄ΠΎ промяна Π½Π° Ρ…Π΅Ρˆ стойността Π½Π° Ρ„Π°ΠΉΠ»Π°, ΠΊΠΎΠ΅Ρ‚ΠΎ ΠΎΠ·Π½Π°Ρ‡Π°Π²Π°, Ρ‡Π΅ кСша Π½Π° Π±Ρ€Π°ΡƒΠ·ΡŠΡ€Π° трябва Π΄Π° бъдС ΠΈΠ½Π²Π°Π»ΠΈΠ΄ΠΈΡ€Π°Π½ ΠΏΠΎ Π΄Ρ€ΡƒΠ³ Π½Π°Ρ‡ΠΈΠ½. Аз нямам Ρ‚ΠΎΠ·ΠΈ ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌ, Π·Π°Ρ‰ΠΎΡ‚ΠΎ Ρ€Π°Π·Π»ΠΈΡ‡Π½ΠΈ ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΠΈ сС Ρ€Π°Π·Π²ΡŠΡ€Ρ‚Π°Ρ‚ Π² Ρ€Π°Π·Π»ΠΈΡ‡Π½ΠΈ срСди.

Π‘ΡŠΠ±ΠΈΡ€Π°ΠΌΠ΅ финалния ΠΎΠ±Ρ€Π°Π·

Най-сСтнС.

Dockerfile

# ΠŸΠ΅Ρ€Π²Ρ‹ΠΉ Π±Π°Π·ΠΎΠ²Ρ‹ΠΉ ΠΎΠ±Ρ€Π°Π· для сборки
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;"]

Π‘Π΅Π³Π° получСният ΠΎΠ±Ρ€Π°Π· ΠΌΠΎΠΆΠ΅ Π΄Π° бъдС ΡΡŠΠ±Ρ€Π°Π½ ΠΈ ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π°Π½ навсякъдС.

Π˜Π·Ρ‚ΠΎΡ‡Π½ΠΈΠΊ: habr.com

ΠšΡƒΠΏΠ΅Ρ‚Π΅ Π½Π°Π΄Π΅ΠΆΠ΄Π΅Π½ хостинг Π·Π° сайтовС с Π·Π°Ρ‰ΠΈΡ‚Π° ΠΎΡ‚ DDoS, VPS VDS ΡΡŠΡ€Π²ΡŠΡ€ΠΈ πŸ”₯ ΠšΡƒΠΏΠ΅Ρ‚Π΅ Π½Π°Π΄Π΅ΠΆΠ΄Π΅Π½ хостинг Π·Π° сайтовС с Π·Π°Ρ‰ΠΈΡ‚Π° ΠΎΡ‚ DDoS, VPS VDS ΡΡŠΡ€Π²ΡŠΡ€ΠΈ | ProHoster