Docker ΠΈΠ·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠ΅ Π·Π° разпространСниС Π½Π° Сдностранично ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅

Едностранично ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ (SPA) Π΅ Π½Π°Π±ΠΎΡ€ ΠΎΡ‚ статични JavaScript ΠΈ HTML Ρ„Π°ΠΉΠ»ΠΎΠ²Π΅, ΠΊΠ°ΠΊΡ‚ΠΎ ΠΈ изобраТСния ΠΈ Π΄Ρ€ΡƒΠ³ΠΈ рСсурси. Въй ΠΊΠ°Ρ‚ΠΎ Ρ‚Π΅ Π½Π΅ сС промСнят Π΄ΠΈΠ½Π°ΠΌΠΈΡ‡Π½ΠΎ, ΠΏΡƒΠ±Π»ΠΈΠΊΡƒΠ²Π°Π½Π΅Ρ‚ΠΎ ΠΈΠΌ ΠΎΠ½Π»Π°ΠΉΠ½ Π΅ ΠΌΠ½ΠΎΠ³ΠΎ лСсно. Има голям Π±Ρ€ΠΎΠΉ Π΅Π²Ρ‚ΠΈΠ½ΠΈ ΠΈ Π΄ΠΎΡ€ΠΈ Π±Π΅Π·ΠΏΠ»Π°Ρ‚Π½ΠΈ услуги Π·Π° Ρ‚ΠΎΠ²Π°, ΠΊΠ°Ρ‚ΠΎ сС Π·Π°ΠΏΠΎΡ‡Π½Π΅ с прости страници Π½Π° GitHub (Π° Π·Π° някои Π΄ΠΎΡ€ΠΈ с 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, ΠΊΠΎΠΉΡ‚ΠΎ Ρ‰Π΅ Π½ΠΈ бъдС ΠΏΠΎΠ»Π΅Π·Π΅Π½ ΠΏΠΎ-късно.

Docker Ρ„Π°ΠΉΠ» с ΠΊΠΎΠΌΠ΅Π½Ρ‚Π°Ρ€ΠΈ.

# Π‘Π°Π·ΠΎΠ²Ρ‹ΠΉ ΠΎΠ±Ρ€Π°Π·
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 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-Ρ„Π°ΠΉΠ»Π°Ρ…
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}.

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

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

БглобяванС Π½Π° ΠΎΠΊΠΎΠ½Ρ‡Π°Ρ‚Π΅Π»Π½ΠΎΡ‚ΠΎ ΠΈΠ·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠ΅

Накрая.

Π”ΠΎΠΊΠ΅Ρ€ Ρ„Π°ΠΉΠ»

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