Ìomhaigh docker airson tagradh aon-dhuilleag a sgaoileadh

Tha Iarrtas aon-dhuilleag (SPA) na sheata de fhaidhlichean JavaScript agus HTML statach, a bharrachd air ìomhaighean agus goireasan eile. Leis nach eil iad ag atharrachadh gu fiùghantach, tha e glè fhurasta am foillseachadh air-loidhne. Tha àireamh mhòr de sheirbheisean saor agus eadhon an-asgaidh airson seo, a 'tòiseachadh le GitHub Pages sìmplidh (agus airson cuid eadhon le narod.ru) agus a' crìochnachadh le CDN mar Amazon S3. Ach, bha feum agam air rudeigin eile.

Bha feum agam air ìomhaigh Docker le SPA gus am biodh e furasta a chuir air bhog an dà chuid ann an cinneasachadh mar phàirt de bhuidheann Kubernetes, agus air inneal leasaiche deireadh cùil aig nach eil fios dè a th’ ann an SPA.

Tha mi air na riatanasan ìomhaigh a leanas a dhearbhadh dhomh fhìn:

  • furasta a chleachdadh (ach chan e co-chruinneachadh);
  • meud as ìsle an dà chuid a thaobh diosc agus RAM;
  • rèiteachadh tro chaochladairean àrainneachd gus an gabh an ìomhaigh a chleachdadh ann an àrainneachdan eadar-dhealaichte;
  • an sgaoileadh as èifeachdaiche de fhaidhlichean.

An-diugh innsidh mi dhut mar:

  • gut nginx;
  • togail brotli bho thùsan;
  • teagasg faidhlichean statach gus caochladairean àrainneachd a thuigsinn;
  • agus gu dearbh mar a chruinnicheas tu ìomhaigh Docker bho seo uile.

Is e adhbhar an artaigil seo m’ eòlas a cho-roinn agus buill eòlach den choimhearsnachd a bhrosnachadh gu càineadh cuideachail.

A 'togail ìomhaigh airson co-chruinneachadh

Gus an ìomhaigh Docker mu dheireadh a dhèanamh beag ann am meud, feumaidh tu cumail ri dà riaghailt: co-dhiù sreathan agus ìomhaigh bunaiteach minimalistic. Is e aon de na h-ìomhaighean bunaiteach as lugha an ìomhaigh Alpine Linux, mar sin is e sin a thaghas mi. Dh’ fhaodadh cuid a bhith ag argamaid nach eil an Alpach freagarrach airson cinneasachadh, agus dh’ fhaodadh iad a bhith ceart. Ach gu pearsanta, cha robh duilgheadas sam bith agam a-riamh leis agus chan eil argamaidean sam bith na aghaidh.

Gus am bi nas lugha de shreathan ann, cruinnichidh mi an ìomhaigh ann an 2 ìre. Is e dreach a th’ anns a’ chiad fhear; fuirichidh a h-uile goireas taice agus faidhle sealach ann. Agus anns an ìre mu dheireadh cha sgrìobh mi sìos ach an dreach mu dheireadh den tagradh.

Feuch an tòisich sinn leis an ìomhaigh taice.

Gus tagradh SPA a chur ri chèile, mar as trice bidh feum agad air node.js. Gabhaidh mi an ìomhaigh oifigeil, a thig cuideachd leis na manaidsearan pacaid npm agus snàth. Às mo leth fhìn, cuiridh mi node-gyp, a tha a dhìth gus cuid de phasgan npm a thogail, agus an compressor Brotli bho Google, a bhios feumail dhuinn nas fhaide air adhart.

Dockerfile le beachdan.

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

A-cheana an seo tha mi a ’sabaid airson minimalism, agus mar sin tha an ìomhaigh air a chuir ri chèile le aon sgioba mòr.

Gheibhear an dealbh chrìochnaichte an seo: https://hub.docker.com/r/alexxxnf/spa-builder. Ged a tha mi a 'moladh gun a bhith an urra ri ìomhaighean dhaoine eile agus a bhith a' cruinneachadh do chuid fhèin.

nginx

Faodaidh tu frithealaiche lìn sam bith a chleachdadh gus susbaint statach a sgaoileadh. Tha mi cleachdte ri bhith ag obair le nginx, agus mar sin cleachdaidh mi e a-nis.

Tha ìomhaigh oifigeil Docker aig Nginx, ach tha cus mhodalan ann airson cuairteachadh statach sìmplidh. Chithear an fheadhainn a tha air an toirt a-steach don lìbhrigeadh le sgioba sònraichte no anns an Dockerfile oifigeil.

ruith $ docker --rm nginx: 1-alpach 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

Cleachdaidh mi an Dockerfile mar bhunait, ach fàgaidh mi ann dìreach na tha a dhìth gus susbaint statach a sgaoileadh. Cha bhith e comasach don dreach agam obrachadh thairis air HTTPS, cha toir e taic do chead, agus mòran a bharrachd. Ach bidh an dreach agam comasach air faidhlichean a sgaoileadh air an teannachadh leis an algairim Brotli, a tha beagan nas èifeachdaiche na gzip. Bidh sinn a’ teannachadh faidhlichean aon uair; chan eil feum air seo a dhèanamh air an itealan.

Is e seo an Dockerfile a chrìochnaich mi. Is ann leamsa a tha beachdan ann an Ruisis, sa Bheurla - bhon fhear thùsail.

Faidhle docker

# Базовый образ снова 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;"]

Ceartaichidh mi nginx.conf sa bhad gus am bi gzip agus brotli air an comasachadh gu bunaiteach. Bidh mi cuideachd a’ toirt a-steach cinn caching, oir cha bhith sinn air atharrachadh stait a-riamh. Agus is e an suathadh mu dheireadh na 404 iarrtas gu lèir ath-stiùireadh gu index.html, tha seo riatanach airson seòladh san 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";
            }
        }
    }
}

Faodaidh tu an dealbh chrìochnaichte a luchdachadh sìos an seo: https://hub.docker.com/r/alexxxnf/nginx-spa. Bheir e suas 10,5 MB. Ghabh an nginx tùsail suas 19,7 MB. Tha m’ ùidh ann an spòrs riaraichte.

Teagasg stats gus caochladairean àrainneachd a thuigsinn

Carson a dh’ fhaodadh gum biodh feum air suidheachaidhean ann an SPA? Mar eisimpleir, gus sònrachadh dè an API RESTful a chleachdas. Mar as trice, bidh suidheachaidhean airson na h-àrainneachd a tha thu ag iarraidh air an gluasad gu SPA aig ìre togail. Ma dh'fheumas tu rudeigin atharrachadh, feumaidh tu an tagradh ath-thogail. Chan eil mi ga iarraidh. Tha mi airson gum bi an tagradh air a thogail aon uair aig ìre CI, agus air a rèiteachadh cho mòr ‘s a tha riatanach aig ìre CD a’ cleachdadh caochladairean àrainneachd.

Gu dearbh, chan eil faidhlichean statach iad fhèin a’ tuigsinn caochladairean àrainneachd sam bith. Mar sin, feumaidh tu cleas a chleachdadh. Anns an ìomhaigh mu dheireadh, cha chuir mi nginx air bhog, ach sgriobt shligean sònraichte a leughas caochladairean àrainneachd, a sgrìobhas iad gu faidhlichean statach, gan teannachadh, agus dìreach an uairsin a ghluaiseas smachd gu nginx.

Airson an adhbhair seo, tha an Dockerfile a’ toirt seachad am paramadair ENTRYPOINT. Bheir sinn dha an sgriobt a leanas (a’ cleachdadh Angular mar eisimpleir):

docker-inntrigeadh.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 "$@"

Gus an dèan an sgriobt an obair aige, feumaidh na roghainnean a bhith sgrìobhte anns na faidhlichean js san fhoirm seo: ${API_URL}.

Is fhiach a bhith mothachail gu bheil a’ mhòr-chuid de SPAan an latha an-diugh a’ cur hashes ris na faidhlichean aca nuair a bhios iad a’ togail. Tha seo riatanach gus an urrainn don bhrobhsair am faidhle a thasgadh gu sàbhailte airson ùine mhòr. Ma dh’ atharraicheas am faidhle, atharraichidh an hash aige, agus bheir sin air a’ bhrobhsair am faidhle a luchdachadh sìos a-rithist.

Gu mì-fhortanach, anns an dòigh agam, chan eil atharrachadh an rèiteachaidh tro chaochladairean àrainneachd a’ leantainn gu atharrachadh ann an hash an fhaidhle, a tha a’ ciallachadh gum feumar tasgadan a’ bhrobhsair a dhì-dhligheachadh ann an dòigh air choireigin eile. Chan eil an duilgheadas seo agam oir tha diofar rèiteachaidhean gan cleachdadh ann an àrainneachdan eadar-dhealaichte.

A 'cur ri chèile an dealbh mu dheireadh

Mu dheireadh thall.

Faidhle docker

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

A-nis faodar an ìomhaigh a thig às a chruinneachadh agus a chleachdadh an àite sam bith.

Source: www.habr.com