Chithunzi cha Docker chogawira Single Page Application

Single-page Application (SPA) ndi gulu la mafayilo a JavaScript ndi HTML osasunthika, komanso zithunzi ndi zinthu zina. Chifukwa sasintha kwambiri, kuwasindikiza pa intaneti ndikosavuta. Pali ntchito zambiri zotsika mtengo komanso zaulere pa izi, kuyambira ndi Masamba osavuta a GitHub (ndipo ena ngakhale ndi narod.ru) ndikutha ndi CDN ngati Amazon S3. Komabe, ndinafunikira chinthu china.

Ndinkafuna chithunzi cha Docker chokhala ndi SPA kuti chizikhazikitsidwa mosavuta popanga ngati gawo la gulu la Kubernetes, komanso pamakina a wopanga kumbuyo yemwe sadziwa kuti SPA ndi chiyani.

Ndadzipangira izi:

  • kumasuka kugwiritsa ntchito (koma osati kusonkhana);
  • kukula kochepa pa disk ndi RAM;
  • kasinthidwe kudzera muzosintha zachilengedwe kuti chithunzicho chigwiritsidwe ntchito m'malo osiyanasiyana;
  • kugawa bwino kwambiri mafayilo.

Lero ndikuuzani momwe:

  • matumbo nginx;
  • kumanga brotli kuchokera ku magwero;
  • phunzitsani mafayilo osasunthika kuti amvetsetse zosintha zachilengedwe;
  • komanso momwe mungasonkhanitsire chithunzi cha Docker kuchokera ku zonsezi.

Cholinga cha nkhaniyi ndikugawana zomwe ndakumana nazo ndikupangitsa anthu odziwa zambiri kuti azidzudzula.

Kupanga chithunzi cha msonkhano

Kuti chithunzi chomaliza cha Docker chikhale chaching'ono, muyenera kutsatira malamulo awiri: magawo ochepa ndi chithunzi chochepa cha minimalistic. Chimodzi mwazithunzi zazing'ono kwambiri ndi chithunzi cha Alpine Linux, ndizomwe ndisankhe. Ena angatsutse kuti Alpine si yoyenera kupanga, ndipo iwo angakhale olondola. Koma panokha, sindinakhalepo ndi vuto lililonse ndi iye ndipo palibe zotsutsana naye.

Kuti ndikhale ndi zigawo zochepa, ndisonkhanitsa chithunzicho mu magawo awiri. Yoyamba ndikulemba; zida zonse zothandizira ndi mafayilo osakhalitsa azikhala momwemo. Ndipo pomaliza ndingolemba zomaliza za pulogalamuyi.

Tiyeni tiyambe ndi chithunzi chothandizira.

Kuti mupange pulogalamu ya SPA, nthawi zambiri mumafunika node.js. Nditenga chithunzi chovomerezeka, chomwe chimabweranso ndi oyang'anira phukusi la npm ndi ulusi. M'malo mwa ine ndekha, ndiwonjezera node-gyp, yomwe ikufunika kuti ipange mapaketi a npm, ndi kompresa ya Brotli yochokera ku Google, yomwe itithandiza mtsogolo.

Dockerfile ndi ndemanga.

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

Kale pano ndikulimbana ndi minimalism, kotero chithunzicho chimayikidwa pamodzi ndi gulu limodzi lalikulu.

Chithunzi chomalizidwa chikupezeka apa: https://hub.docker.com/r/alexxxnf/spa-builder. Ngakhale ndikupangira kuti musadalire zithunzi za anthu ena ndikusonkhanitsa zanu.

nginx

Mutha kugwiritsa ntchito seva iliyonse yapaintaneti kuti mugawire zomwe zili zokhazikika. Ndazolowera kugwira ntchito ndi nginx, ndiye ndizigwiritsa ntchito tsopano.

Nginx ili ndi chithunzi chovomerezeka cha Docker, koma ili ndi ma module ambiri osavuta kugawa. Zomwe zikuphatikizidwa pakubweretsa zitha kuwonedwa ndi gulu lapadera kapena mu Dockerfile yovomerezeka.

$ 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

Ndigwiritsa ntchito Dockerfile ngati maziko, koma ndingosiya zomwe zimafunikira kuti ndigawire zomwe zili zokhazikika. Mtundu wanga sungathe kugwira ntchito pa HTTPS, sugwirizana ndi chilolezo, ndi zina zambiri. Koma mtundu wanga udzatha kugawa mafayilo oponderezedwa ndi algorithm ya Brotli, yomwe ndi yothandiza pang'ono kuposa gzip. Tidzakakamiza mafayilo kamodzi; palibe chifukwa chochitira izi pouluka.

Iyi ndiye Dockerfile yomwe ndidamaliza nayo. Ndemanga mu Russian ndi anga, mu Chingerezi - kuchokera pachiyambi.

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;"]

Ndikonza nthawi yomweyo nginx.conf kuti gzip ndi brotli aziyatsidwa mwachisawawa. Ndiphatikizanso mitu ya caching, chifukwa sitidzasinthanso static. Ndipo kukhudza komaliza kudzakhala kulondolera zopempha zonse za 404 ku index.html, izi ndizofunikira pakuyenda mu 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";
            }
        }
    }
}

Mutha kukopera chithunzi chomalizidwa apa: https://hub.docker.com/r/alexxxnf/nginx-spa. Zimatengera 10,5 MB. Nginx yoyambirira idatenga 19,7 MB. Zokonda zanga zamasewera zakhutitsidwa.

Kuphunzitsa ma statics kuti mumvetsetse zosintha zachilengedwe

Chifukwa chiyani makonda angafunike mu SPA? Mwachitsanzo, kuti mufotokozere RESTful API yoti mugwiritse ntchito. Nthawi zambiri, makonda a malo omwe mukufuna amasamutsidwa ku SPA pomanga. Ngati mukufuna kusintha china chake, muyenera kumanganso pulogalamuyo. sindikuzifuna. Ndikufuna kuti pulogalamuyo imangidwe kamodzi pagawo la CI, ndikukonzedwa momwe zingafunikire pagawo la CD pogwiritsa ntchito zosintha zachilengedwe.

Zachidziwikire, mafayilo osasunthika okha samamvetsetsa zosintha zilizonse zachilengedwe. Chifukwa chake, muyenera kugwiritsa ntchito chinyengo. Pachithunzi chomaliza, sindidzayambitsa nginx, koma chipolopolo chapadera chomwe chidzawerenge kusintha kwa chilengedwe, kuwalembera ku mafayilo osasunthika, kuwapanikiza, ndiyeno tumizani ku nginx.

Pachifukwa ichi, Dockerfile imapereka gawo la ENTRYPOINT. Tiyeni timupatse zotsatirazi (pogwiritsa ntchito Angular monga chitsanzo):

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 "$@"

Kuti script igwire ntchito yake, zoikamo ziyenera kulembedwa m'mafayilo a js mu fomu iyi: ${API_URL}.

Ndizofunikira kudziwa kuti ma SPA amakono amawonjezera ma hashes pamafayilo awo pomanga. Izi ndizofunikira kuti osatsegula athe kusunga fayiloyo kwa nthawi yayitali. Ngati fayilo isintha, ndiye kuti hashi yake idzasintha, zomwe zidzakakamiza osatsegula kutsitsanso fayiloyo.

Tsoka ilo, mu njira yanga, kusintha kasinthidwe kudzera muzosintha zachilengedwe sikubweretsa kusintha kwa fayilo hashi, zomwe zikutanthauza kuti cache ya msakatuli iyenera kukhala yosavomerezeka mwanjira ina. Ndilibe vuto ili chifukwa masinthidwe osiyanasiyana amayikidwa m'malo osiyanasiyana.

Kuyika pamodzi chithunzi chomaliza

Pomaliza.

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;"]

Tsopano chithunzi chotsatira chikhoza kusonkhanitsidwa ndikugwiritsidwa ntchito kulikonse.

Source: www.habr.com