د واحد پاڼې غوښتنلیک ویشلو لپاره د ډاکر انځور

د واحد پاڼې غوښتنلیک (SPA) د جامد جاوا سکریپټ او HTML فایلونو یوه مجموعه ده، په بیله بیا د انځورونو او نورو سرچینو. ځکه چې دوی په متحرک ډول نه بدلیږي، د دوی آنلاین خپرول خورا اسانه دي. د دې لپاره ډیری ارزانه او حتی وړیا خدمتونه شتون لري، د ساده GitHub پاڼو سره پیل کیږي (او د ځینو لپاره حتی د narod.ru سره) او د ایمیزون S3 په څیر د CDN سره پای ته رسیږي. په هرصورت، ما بل څه ته اړتیا درلوده.

ما د SPA سره د ډاکر عکس ته اړتیا درلوده ترڅو دا په اسانۍ سره د کوبرنیټس کلستر برخې په توګه په تولید کې دواړه په اسانۍ سره پیل شي ، او د شاته پای پراختیا کونکي ماشین کې چې نه پوهیږي SPA څه شی دی.

ما د ځان لپاره د لاندې عکس اړتیاوې ټاکلې دي:

  • د کارولو اسانتیا (مګر مجلس نه)؛
  • د ډیسک او رام په شرایطو کې لږترلږه اندازه؛
  • د چاپیریال متغیرونو له لارې ترتیب کول ترڅو عکس په مختلف چاپیریال کې وکارول شي؛
  • د فایلونو خورا مؤثره توزیع.

نن به تاسو ته ووایم چې څنګه:

  • کولمو nginx;
  • د سرچینو څخه بروټلي جوړول؛
  • د چاپیریال متغیرونو د پوهیدو لپاره جامد فایلونه زده کړئ؛
  • او البته د دې ټولو څخه د ډاکر عکس راټولولو څرنګوالی.

د دې لیکنې موخه زما د تجربې شریکول او د ټولنې تجربه لرونکي غړي رغنده نیوکې ته هڅول دي.

د غونډې لپاره د انځور جوړول

د وروستي ډاکر عکس د اندازې کوچني کولو لپاره ، تاسو اړتیا لرئ دوه مقرراتو ته غاړه کیږئ: لږترلږه پرتونه او لږترلږه بیس عکس. یو له کوچني بیس عکسونو څخه د الپین لینکس عکس دی ، نو دا هغه څه دي چې زه به یې غوره کړم. ځینې ​​​​ممکن استدلال وکړي چې الپین د تولید لپاره مناسب نه دی، او دوی ممکن سم وي. مګر په شخصي توګه، ما هیڅکله د هغه سره کومه ستونزه نه درلوده او د هغه په ​​​​وړاندې هیڅ دلیل شتون نلري.

د دې لپاره چې لږ پرتونه ولرئ، زه به عکس په 2 مرحلو کې راټول کړم. لومړی یوه مسوده ده؛ ټول مرستندویه اسانتیاوې او لنډمهاله فایلونه به په کې پاتې شي. او په وروستي مرحله کې به زه یوازې د غوښتنلیک وروستۍ نسخه لیکم.

راځئ چې د مرستندویه انځور سره پیل وکړو.

د SPA غوښتنلیک ترتیبولو لپاره، تاسو معمولا node.js ته اړتیا لرئ. زه به رسمي عکس واخلم، کوم چې د npm او یارن کڅوړې مدیرانو سره هم راځي. زما په استازیتوب، زه به نوډ-جیپ اضافه کړم، کوم چې د ځینې npm کڅوړو جوړولو لپاره اړین دی، او د ګوګل څخه د بروټلي کمپرسور، چې وروسته به زموږ لپاره ګټور وي.

د نظرونو سره ډاکر فایل.

# Базовый образ
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

لا دمخه دلته زه د minimalism لپاره مبارزه کوم ، نو عکس د یوې لوی ټیم لخوا یوځای شوی.

بشپړ شوی انځور دلته موندلی شئ: https://hub.docker.com/r/alexxxnf/spa-builder. که څه هم زه وړاندیز کوم چې د نورو خلکو عکسونو باندې تکیه ونه کړئ او خپل ځان راټول کړئ.

نګینکس

تاسو کولی شئ د جامد مینځپانګې ویشلو لپاره هر ویب سرور وکاروئ. زه د نګینکس سره کار کولو عادت یم، نو زه به یې اوس وکاروم.

نګینکس رسمي ډاکر عکس لري ، مګر دا د ساده جامد توزیع لپاره ډیری ماډلونه لري. کوم چې په تحویل کې شامل دي د ځانګړي ټیم لخوا یا په رسمي ډاکر فایل کې لیدل کیدی شي.

$ 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

زه به د ډاکر فایل د اساس په توګه وکاروم ، مګر زه به پدې کې یوازې هغه څه پریږدم چې د جامد مینځپانګې توزیع کولو ته اړتیا وي. زما نسخه به د HTTPS په اړه کار ونکړي، د اختیار ملاتړ به ونه کړي، او نور ډیر څه. مګر زما نسخه به وکولی شي د بروټلي الګوریتم سره فشار شوي فایلونه توزیع کړي ، کوم چې د gzip په پرتله یو څه ډیر موثر دی. موږ به یوځل فایلونه کمپریس کړو؛ په الوتنه کې دا کولو ته اړتیا نشته.

دا هغه ډاکر فایل دی چې ما ورسره پای ته رسولی. په روسي کې تبصرې زما دي، په انګلیسي کې - له اصلي څخه.

ډکولر

# Базовый образ снова 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 او بروټلي په ډیفالټ فعال شي. زه به د کیشینګ سرلیکونه هم شامل کړم، ځکه چې موږ به هیڅکله جامد بدل نه کړو. او وروستی تماس به دا وي چې ټولې 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 وخت نیسي. اصلي نګینکس 19,7 MB اخیستی. زما د سپورت علاقه مطمین ده.

د چاپیریال متغیرونو د پوهیدو لپاره د احصایې تدریس

ولې په SPA کې ترتیباتو ته اړتیا لیدل کیدی شي؟ د مثال په توګه، د دې مشخص کولو لپاره چې کوم RESTful API کارول کیږي. عموما، د مطلوب چاپیریال لپاره ترتیبات د جوړولو په مرحله کې SPA ته لیږدول کیږي. که تاسو یو څه بدلولو ته اړتیا لرئ، نو تاسو باید غوښتنلیک بیا جوړ کړئ. زه دا نه غواړم. زه غواړم چې غوښتنلیک یو ځل د CI په مرحله کې جوړ شي، او د چاپیریال متغیرونو په کارولو سره د CD په مرحله کې څومره چې اړین وي تنظیم شوی.

البته، جامد فایلونه پخپله د چاپیریال تغیرات نه پوهیږي. له همدې امله، تاسو باید یو چال وکاروئ. په وروستي عکس کې ، زه به نګینکس لانچ نه کړم ، مګر یو ځانګړی شیل سکریپټ چې د چاپیریال متغیرونه به ولولي ، جامد فایلونو ته یې ولیکئ ، فشار یې کړئ ، او یوازې بیا یې نګینکس ته کنټرول لیږدئ.

د دې هدف لپاره، 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 د جوړولو په وخت کې خپلو فایلونو ته هش اضافه کوي. دا اړینه ده چې براوزر کولی شي فایل د اوږدې مودې لپاره خوندي کړي. که فایل بدل شي، نو د هغې هش به بدل شي، چې په پایله کې به براوزر مجبور کړي چې فایل بیا ډاونلوډ کړي.

بدبختانه ، زما په میتود کې ، د چاپیریال متغیرونو له لارې ترتیب بدلول د فایل هش کې بدلون لامل نه کیږي ، پدې معنی چې د براوزر کیچ باید په بل ډول باطل شي. زه دا ستونزه نلرم ځکه چې مختلف تشکیلات په مختلف چاپیریال کې ځای په ځای شوي.

وروستی انځور سره یوځای کول

په پای کې.

ډکولر

# Первый базовый образ для сборки
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