Docker duab rau kev faib tawm ntawm Ib Daim Ntawv Thov Ib Ntus

Ib nplooj ntawv Daim Ntawv Thov (SPA) yog txheej txheem JavaScript thiab HTML cov ntaub ntawv zoo li qub, nrog rau cov duab thiab lwm yam kev pabcuam. Vim lawv tsis hloov dynamically, tshaj tawm lawv online yog ib qho yooj yim heev. Muaj ntau tus nqi pheej yig thiab kev pabcuam pub dawb rau qhov no, pib nrog GitHub Nplooj ntawv yooj yim (thiab rau qee qhov txawm tias nrog narod.ru) thiab xaus nrog CDN zoo li Amazon S3. Txawm li cas los xij, kuv xav tau lwm yam.

Kuv xav tau daim duab Docker nrog SPA kom nws tuaj yeem yooj yim tsim tawm ob qho tib si hauv kev tsim khoom ua ib feem ntawm Kubernetes pawg, thiab ntawm lub tshuab ntawm tus tsim tawm rov qab uas tsis paub tias SPA yog dab tsi.

Kuv tau txiav txim siab cov duab hauv qab no rau kuv tus kheej:

  • yooj yim siv (tab sis tsis sib dhos);
  • yam tsawg kawg nkaus ntawm ob qho tib si ntawm disk thiab RAM;
  • configuration los ntawm ib puag ncig variables kom cov duab yuav siv tau nyob rau hauv txawv ib puag ncig;
  • kev faib cov ntaub ntawv zoo tshaj plaws.

Hnub no kuv yuav qhia koj li cas:

  • plab nginx;
  • tsim brotli los ntawm qhov chaw;
  • qhia cov ntaub ntawv zoo li qub kom nkag siab txog qhov hloov pauv ib puag ncig;
  • thiab tau kawg yuav ua li cas sib sau Docker duab los ntawm tag nrho cov no.

Lub hom phiaj ntawm tsab xov xwm no yog los qhia kuv cov kev paub dhau los thiab ua rau cov neeg muaj kev paub dhau los hauv zej zog kom muaj kev thuam.

Tsim ib daim duab rau kev sib dhos

Txhawm rau ua kom cov duab Docker zaum kawg me me, koj yuav tsum ua raws li ob txoj cai: yam tsawg kawg ntawm cov khaubncaws sab nraud povtseg thiab cov duab minimalistic. Ib qho ntawm cov duab me tshaj plaws yog Alpine Linux duab, yog li kuv yuav xaiv. Qee tus yuav sib cav tias Alpine tsis haum rau kev tsim khoom, thiab lawv yuav yog. Tab sis tus kheej, kuv tsis tau muaj teeb meem nrog nws thiab tsis muaj kev sib cav tawm tsam nws.

Kom muaj tsawg txheej txheej, kuv yuav sib sau ua ke cov duab hauv 2 theem. Thawj yog ib daim qauv; tag nrho cov kev pabcuam pabcuam thiab cov ntaub ntawv ib ntus yuav nyob hauv nws. Thiab nyob rau theem kawg kuv tsuas yog sau cov ntawv kawg ntawm daim ntawv thov.

Cia peb pib nrog cov duab pab.

Txhawm rau sau daim ntawv thov SPA, koj feem ntau xav tau node.js. Kuv mam li coj cov duab official, uas kuj tuaj nrog npm thiab xov paj tus thawj tswj pob. Ntawm kuv tus kheej, kuv yuav ntxiv node-gyp, uas yuav tsum tau tsim ib co npm pob, thiab Brotli compressor los ntawm Google, uas yuav pab tau rau peb tom qab.

Dockerfile nrog cov lus pom.

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

Twb tau ntawm no kuv tab tom sib ntaus sib tua rau minimalism, yog li cov duab tau muab tso ua ke los ntawm ib pab pawg loj.

Daim duab tiav tuaj yeem pom ntawm no: https://hub.docker.com/r/alexxxnf/spa-builder. Txawm hais tias kuv pom zoo kom tsis txhob cia siab rau lwm tus neeg cov duab thiab sau koj tus kheej.

nginx

Koj tuaj yeem siv txhua lub web server los faib cov ntsiab lus zoo li qub. Kuv tau siv los ua haujlwm nrog nginx, yog li kuv yuav siv tam sim no.

Nginx muaj cov duab Docker, tab sis nws muaj ntau lub modules rau kev faib tawm yooj yim. Cov uas suav nrog hauv kev xa khoom tuaj yeem pom los ntawm pab pawg tshwj xeeb lossis hauv Dockerfile official.

$ 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

Kuv yuav siv Dockerfile ua lub hauv paus, tab sis kuv yuav tawm hauv nws tsuas yog qhov xav tau los faib cov ntsiab lus zoo li qub. Kuv version yuav tsis tuaj yeem ua haujlwm dhau HTTPS, yuav tsis txhawb kev tso cai, thiab ntau ntxiv. Tab sis kuv version yuav muaj peev xwm faib cov ntaub ntawv compressed nrog Brotli algorithm, uas yog me ntsis npaum li gzip. Peb yuav compress cov ntaub ntawv ib zaug; tsis tas yuav ua qhov no ntawm ya.

Nov yog Dockerfile kuv tau xaus nrog. Cov lus hauv Lavxias yog kuv li, hauv lus Askiv - los ntawm tus thawj.

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

Kuv mam li kho nginx.conf tam sim ntawd kom gzip thiab brotli tau qhib los ntawm lub neej ntawd. Kuv tseem yuav suav nrog caching headers, vim tias peb yuav tsis hloov li qub. Thiab qhov kawg kov yuav yog redirect tag nrho 404 thov rau index.html, qhov no yog tsim nyog rau navigation nyob rau hauv lub SPA.

nginx.conf ib

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

Koj tuaj yeem rub tawm cov duab tiav ntawm no: https://hub.docker.com/r/alexxxnf/nginx-spa. Nws yuav siv li 10,5 MB. Thawj nginx tau nce 19,7 MB. Kuv nyiam kev ncaws pob txaus siab.

Qhia statics kom nkag siab txog qhov sib txawv ntawm ib puag ncig

Vim li cas thiaj xav tau kev teeb tsa hauv SPA? Piv txwv li, txhawm rau txheeb xyuas qhov twg RESTful API siv. Feem ntau, kev teeb tsa rau qhov xav tau ib puag ncig raug xa mus rau SPA ntawm theem tsim. Yog tias koj xav tau hloov ib yam dab tsi, koj yuav tsum rov tsim daim ntawv thov. Kuv tsis xav tau. Kuv xav kom daim ntawv thov tsim ib zaug nyob rau theem CI, thiab teeb tsa ntau npaum li qhov tsim nyog ntawm theem CD siv qhov hloov pauv ib puag ncig.

Tau kawg, cov ntaub ntawv zoo li qub lawv tus kheej tsis nkag siab ib puag ncig hloov pauv. Yog li ntawd, koj yuav tau siv ib tug dag. Nyob rau hauv daim duab kawg, kuv yuav tsis tso nginx, tab sis ib daim ntawv plhaub tshwj xeeb uas yuav nyeem ib puag ncig hloov pauv, sau lawv rau cov ntaub ntawv zoo li qub, compress lawv, thiab tsuas yog tom qab ntawd hloov kev tswj mus rau nginx.

Rau lub hom phiaj no, Dockerfile muab ENTRYPOINT parameter. Cia peb muab nws cov ntawv hauv qab no (siv Angular ua piv txwv):

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

Txhawm rau kom tsab ntawv ua nws txoj haujlwm, cov chaw yuav tsum tau sau rau hauv cov ntaub ntawv js hauv daim ntawv no: ${API_URL}.

Nws yog tsim nyog sau cia tias feem ntau niaj hnub SPAs ntxiv hashes rau lawv cov ntaub ntawv thaum lub tsev. Qhov no yog qhov tsim nyog kom lub browser tuaj yeem ruaj ntseg cache cov ntaub ntawv ntev. Yog hais tias cov ntaub ntawv hloov, ces nws hash yuav hloov, uas nyob rau hauv lem yuav yuam kom lub browser mus download tau cov ntaub ntawv dua.

Hmoov tsis zoo, hauv kuv txoj kev, hloov qhov kev teeb tsa los ntawm ib puag ncig kev hloov pauv tsis ua rau muaj kev hloov pauv hauv cov ntaub ntawv hash, uas txhais tau hais tias browser cache yuav tsum tsis raug siv rau lwm txoj hauv kev. Kuv tsis muaj qhov teeb meem no vim hais tias txawv configurations yog deployed nyob rau hauv txawv ib puag ncig.

Muab daim duab kawg ua ke

Thaum kawg.

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

Tam sim no cov duab tau tuaj yeem sib sau ua ke thiab siv txhua qhov chaw.

Tau qhov twg los: www.hab.com