Isithombe se-Docker sokusatshalaliswa kohlelo lokusebenza lwekhasi elilodwa

I-Single-page Application (SPA) iyisethi yamafayela e-JavaScript amile kanye ne-HTML, kanye nemifanekiso nezinye izinsiza. Ngenxa yokuthi azishintshi ngokushintshashintshayo, ukuzishicilela ku-inthanethi kulula kakhulu. Kunenombolo enkulu yezinsizakalo ezishibhile futhi zamahhala zalokhu, eziqala nge-GitHub Pages elula (nakwabanye ngisho ne-narod.ru) futhi iphethe nge-CDN efana ne-Amazon S3. Nokho, ngangidinga okunye.

Bengidinga isithombe se-Docker esine-SPA ukuze sethulwe kalula kokubili ekukhiqizweni njengengxenye yeqoqo le-Kubernetes, kanye nasemshinini wonjiniyela ongasemuva ongazi ukuthi iyini i-SPA.

Ngizinqumele izimfuneko zesithombe ezilandelayo:

  • ukusetshenziswa kalula (kodwa hhayi ukuhlanganisa);
  • ubuncane besayizi kokubili ngokuya ngediski kanye ne-RAM;
  • ukumisa ngokusebenzisa okuguquguqukayo kwemvelo ukuze isithombe sisetshenziswe ezindaweni ezahlukene;
  • ukusatshalaliswa okusebenza kahle kakhulu kwamafayela.

Namuhla ngizokutshela ukuthi kanjani:

  • amathumbu nginx;
  • ukwakha i-brotli kusuka emithonjeni;
  • fundisa amafayela amile ukuze aqonde okuguquguqukayo kwemvelo;
  • futhi nakanjani ungahlanganisa kanjani isithombe se-Docker kukho konke lokhu.

Inhloso yalesi sihloko ukwabelana ngolwazi lwami futhi ngivuse amalungu omphakathi anolwazi ekugxekeni okwakhayo.

Ukwakha isithombe sokuhlanganisa

Ukuze wenze isithombe sokugcina se-Docker sibe sincane ngosayizi, udinga ukunamathela emithethweni emibili: ubuncane bezendlalelo nesithombe sesisekelo esincane. Esinye sezithombe ezincane kunazo zonke yisithombe se-Alpine Linux, ngakho-ke yilokho engizokhetha. Abanye bangase baphikise ngokuthi i-Alpine ayifanele ukukhiqizwa, futhi bangase baqinisile. Kodwa ngokwami ​​angikaze ngibe nezinkinga naye futhi azikho izingxabano ezimelene naye.

Ukuze sibe nezendlalelo ezimbalwa, ngizohlanganisa isithombe ngezigaba ezi-2. Esokuqala siwuhlaka; zonke izinsiza namafayela esikhashana azohlala kuwo. Futhi esigabeni sokugcina ngizobhala kuphela inguqulo yokugcina yesicelo.

Ake siqale ngesithombe esiyisizayo.

Ukuze uhlanganise uhlelo lwe-SPA, ngokuvamile udinga i-node.js. Ngizothatha isithombe esisemthethweni, esifika nabaphathi bephakheji ye-npm nentambo. Egameni lami, ngizongeza i-node-gyp, edingekayo ukuze kwakhiwe amanye amaphakheji we-npm, kanye ne-Compressor ye-Brotli evela ku-Google, ezoba usizo kithi kamuva.

I-Dockerfile enamazwana.

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

Kakade lapha ngilwela i-minimalism, ngakho isithombe sihlanganiswa yiqembu elilodwa elikhulu.

Isithombe esiqediwe singatholakala lapha: https://hub.docker.com/r/alexxxnf/spa-builder. Nakuba ngincoma ukuthi ungathembeli ezithombeni zabanye abantu futhi uqoqe ezakho.

nginx

Ungasebenzisa noma iyiphi iseva yewebhu ukusabalalisa okuqukethwe okumile. Ngijwayele ukusebenza nge-nginx, ngakho-ke ngizoyisebenzisa manje.

I-Nginx inesithombe se-Docker esisemthethweni, kodwa inamamojula amaningi kakhulu okusabalalisa okulula okumile. Yiziphi ezifakwe ekulethweni zingabonwa yiqembu elikhethekile noma ku-Dockerfile esemthethweni.

$ 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

Ngizosebenzisa i-Dockerfile njengesisekelo, kodwa ngizoshiya kuyo kuphela lokho okudingekayo ukusabalalisa okuqukethwe okumile. Inguqulo yami ngeke ikwazi ukusebenza nge-HTTPS, ngeke isekele ukugunyazwa, nokunye okuningi. Kodwa inguqulo yami izokwazi ukusabalalisa amafayela acindezelwe nge-algorithm ye-Brotli, esebenza kahle kakhulu kune-gzip. Sizocindezela amafayela kanye; asikho isidingo sokwenza lokhu ngokuhamba kwesikhathi.

Le yi-Dockerfile engagcina ngayo. Amazwana ngesiRashiya awami, ngesiNgisi - asuka kowangempela.

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

Ngizolungisa ngokushesha i-nginx.conf ukuze i-gzip ne-brotli zisebenze ngokuzenzakalelayo. Ngizofaka nezihloko ze-caching, ngoba ngeke siphinde sishintshe ukuma. Futhi ukuthinta kokugcina kuzoba ukuqondisa kabusha zonke izicelo ezingu-404 ku-index.html, lokhu kuyadingeka ukuze uzulazule ku-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";
            }
        }
    }
}

Ungalanda isithombe esiqediwe lapha: https://hub.docker.com/r/alexxxnf/nginx-spa. Kuthatha 10,5 MB. I-nginx yasekuqaleni ithathe u-19,7 MB. Intshisekelo yami yezemidlalo yanelisekile.

Ukufundisa ama-statics ukuqonda okuguquguqukayo kwemvelo

Kungani izilungiselelo zingadingeka ku-SPA? Isibonelo, ukuze ucacise ukuthi iyiphi i-RESTful API ongayisebenzisa. Ngokuvamile, izilungiselelo zendawo oyifunayo zidluliselwa ku-SPA esigabeni sokwakha. Uma udinga ukushintsha okuthile, kuzomele uphinde wakhe uhlelo lokusebenza. Angiyifuni. Ngifuna ukuthi uhlelo lokusebenza lwakhiwe kanye esigabeni se-CI, futhi lulungiswe ngendlela edingekayo esiteji se-CD kusetshenziswa okuguquguqukayo kwemvelo.

Kunjalo, amafayela amile ngokwawo awaqondi noma yikuphi okuguquguqukayo kwendawo. Ngakho-ke, kuzodingeka usebenzise iqhinga. Esithombeni sokugcina, ngeke ngiqalise i-nginx, kodwa iskripthi segobolondo esikhethekile esizofunda okuguquguqukayo kwemvelo, ngibhale kumafayela amile, ngiwacindezele, bese kuphela ukudlulisa ukulawula ku-nginx.

Ngale njongo, i-Dockerfile inikeza ipharamitha ye-ENTRYPOINT. Ake simnikeze umbhalo olandelayo (sisebenzisa i-Angular njengesibonelo):

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

Ukuze umbhalo wenze umsebenzi waso, izilungiselelo kufanele zibhalwe kumafayela we-js kuleli fomu: ${API_URL}.

Kuyaphawuleka ukuthi ama-SPA amaningi esimanje engeza ama-hashes kumafayela awo lapho akha. Lokhu kuyadingeka ukuze isiphequluli sikwazi ukugcina inqolobane ngokuphepha isikhathi eside. Uma ifayela lishintsha, i-hashi yalo izoshintsha, okuzophoqa isiphequluli ukuthi silande ifayela futhi.

Ngeshwa, endleleni yami, ukushintsha ukucushwa ngokusebenzisa okuguquguqukayo kwemvelo akuholeli ekushintsheni kwe-hashi yefayela, okusho ukuthi inqolobane yesiphequluli kufanele ingavumelekile ngenye indlela. Anginayo le nkinga ngoba ukucushwa okuhlukile kuthunyelwa ezindaweni ezihlukene.

Ukuhlanganisa isithombe sokugcina

Ekugcineni.

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

Manje isithombe esiwumphumela singahlanganiswa futhi sisetshenziswe noma kuphi.

Source: www.habr.com