рд╕рд┐рдВрдЧрд▓-рдкреЗрдЬ рдПрдкреНрд▓рд┐рдХреЗрд╢рди (рдПрд╕рдкреАрдП) рд╕реНрдЯреИрдЯрд┐рдХ рдЬрд╛рд╡рд╛рд╕реНрдХреНрд░рд┐рдкреНрдЯ рдФрд░ рдПрдЪрдЯреАрдПрдордПрд▓ рдлрд╛рдЗрд▓реЛрдВ рдХреЗ рд╕рд╛рде-рд╕рд╛рде рдЫрд╡рд┐рдпреЛрдВ рдФрд░ рдЕрдиреНрдп рд╕рдВрд╕рд╛рдзрдиреЛрдВ рдХрд╛ рдПрдХ рд╕реЗрдЯ рд╣реИред рдЪреВрдВрдХрд┐ рд╡реЗ рдЧрддрд┐рд╢реАрд▓ рд░реВрдк рд╕реЗ рдирд╣реАрдВ рдмрджрд▓рддреЗ рд╣реИрдВ, рдЗрд╕рд▓рд┐рдП рдЙрдиреНрд╣реЗрдВ рдЗрдВрдЯрд░рдиреЗрдЯ рдкрд░ рдкреНрд░рдХрд╛рд╢рд┐рдд рдХрд░рдирд╛ рдмрд╣реБрдд рд╕рд░рд▓ рд╣реИред рдРрд╕рд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдмрдбрд╝реА рд╕рдВрдЦреНрдпрд╛ рдореЗрдВ рд╕рд╕реНрддреА рдФрд░ рдпрд╣рд╛рдВ рддрдХ тАЛтАЛрдХрд┐ рдирд┐: рд╢реБрд▓реНрдХ рд╕реЗрд╡рд╛рдПрдВ рд╣реИрдВ, рдЬреЛ рдПрдХ рд╕рд╛рдзрд╛рд░рдг GitHub рдкреЗрдЬ рд╕реЗ рд╢реБрд░реВ рд╣реЛрддреА рд╣реИ (рдФрд░ рдХрд┐рд╕реА рдХреЗ рд▓рд┐рдП рднреА narod.ru рдХреЗ рд╕рд╛рде) рдФрд░ рдЕрдореЗрдЬрд╝реЕрди рдПрд╕ 3 рдЬреИрд╕реЗ рд╕реАрдбреАрдПрди рдХреЗ рд╕рд╛рде рд╕рдорд╛рдкреНрдд рд╣реЛрддреА рд╣реИред рд╣рд╛рд▓рд╛рдБрдХрд┐, рдореБрдЭреЗ рдХреБрдЫ рдФрд░ рдЪрд╛рд╣рд┐рдП рдерд╛ред
рдореБрдЭреЗ рдПрд╕рдкреАрдП рдХреЗ рд╕рд╛рде рдбреЙрдХрд░ рдЫрд╡рд┐ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдереА рддрд╛рдХрд┐ рдЗрд╕реЗ рдХреБрдмреЗрд░рдиреЗрдЯ рдХреНрд▓рд╕реНрдЯрд░ рдХреЗ рд╣рд┐рд╕реНрд╕реЗ рдХреЗ рд░реВрдк рдореЗрдВ рдЙрддреНрдкрд╛рджрди рдореЗрдВ рдЖрд╕рд╛рдиреА рд╕реЗ рд▓реЙрдиреНрдЪ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХреЗ рдФрд░ рдмреИрдХ-рдПрдВрдб рдбреЗрд╡рд▓рдкрд░ рдорд╢реАрди рдкрд░ рдпрд╣ рдкрддрд╛ рдЪрд▓реЗ рдХрд┐ рдПрд╕рдкреАрдП рдХреНрдпрд╛ рд╣реИред
рдореИрдВрдиреЗ рдЕрдкрдиреЗ рд▓рд┐рдП рдирд┐рдореНрди рдЫрд╡рд┐ рдЖрд╡рд╢реНрдпрдХрддрд╛рдУрдВ рдХреЛ рдирд┐рд░реНрдзрд╛рд░рд┐рдд рдХрд┐рдпрд╛:
- рдЙрдкрдпреЛрдЧ рдореЗрдВ рдЖрд╕рд╛рдиреА (рд▓реЗрдХрд┐рди рд╡рд┐рдзрд╛рдирд╕рднрд╛ рдирд╣реАрдВ);
- рдбрд┐рд╕реНрдХ рдФрд░ рд░реИрдо рдХреЗ рд╕рдВрджрд░реНрдн рдореЗрдВ рдиреНрдпреВрдирддрдо рдЖрдХрд╛рд░;
- рдкрд░реНрдпрд╛рд╡рд░рдг рдЪрд░ рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рд╕реЗрдЯрд┐рдВрдЧ рддрд╛рдХрд┐ рдЫрд╡рд┐ рдХрд╛ рдЙрдкрдпреЛрдЧ рд╡рд┐рднрд┐рдиреНрди рд╡рд╛рддрд╛рд╡рд░рдгреЛрдВ рдореЗрдВ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХреЗ;
- рд╕рдмрд╕реЗ рдХреБрд╢рд▓ рдлрд╝рд╛рдЗрд▓ рд╡рд┐рддрд░рдгред
рдЖрдЬ рдореИрдВ рдЖрдкрдХреЛ рдмрддрд╛рдКрдВрдЧрд╛ рдХреИрд╕реЗ:
- рдЖрдВрдд nginx;
- рд╕реНрд░реЛрдд рд╕реЗ рд╕рдВрдХрд▓рди рдмреНрд░реЗрдЯрд▓реА;
- рдкрд░реНрдпрд╛рд╡рд░рдг рдЪрд░ рд╕рдордЭрдиреЗ рдХреЗ рд▓рд┐рдП рд╕реНрдереИрддрд┐рдХ рдлрд╝рд╛рдЗрд▓реЗрдВ рд╕рд┐рдЦрд╛рдирд╛;
- рдФрд░ рдирд┐рд╢реНрдЪрд┐рдд рд░реВрдк рд╕реЗ рдХреИрд╕реЗ рдЗрд╕ рд╕рдм рд╕реЗ рдПрдХ рдбреЙрдХрд░ рдЫрд╡рд┐ рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдПред
рдЗрд╕ рд▓реЗрдЦ рдХрд╛ рдЙрджреНрджреЗрд╢реНрдп рдореЗрд░реЗ рдЕрдиреБрднрд╡ рдХреЛ рд╕рд╛рдЭрд╛ рдХрд░рдирд╛ рдФрд░ рдЕрдиреБрднрд╡реА рд╕рд╛рдореБрджрд╛рдпрд┐рдХ рд╕рджрд╕реНрдпреЛрдВ рдХреЛ рд░рдЪрдирд╛рддреНрдордХ рдЖрд▓реЛрдЪрдирд╛ рдХреЗ рд▓рд┐рдП рдЙрдХрд╕рд╛рдирд╛ рд╣реИред
рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рдЫрд╡рд┐ рдмрдирд╛рдПрдБ
Docker- , : . Alpine Linux, . - , Alpine , , . .
, 2 . тАУ , . .
.
, SPA-, , node.js. npm yarn. node-gyp, npm-, Brotli Google, .
Dockerfile .#
FROM node:12-alpine
LABEL maintainer="Aleksey Maydokin <amaydokin@gmail.com>"
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
, .
: https://hub.docker.com/r/alexxxnf/spa-builder. .
nginx
web-. nginx, .
nginx Docker-, . Dockerfile.
$ docker run --rm nginx:1-alpine nginx -Vnginx 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
Dockerfile, , . HTTPS, . , Brotli, , gzip. , .
Dockerfile . тАУ , тАУ .
Dockerfile# Alpine
FROM alpine:3.9
LABEL maintainer="Aleksey Maydokin <amaydokin@gmail.com>"
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 brotli . , . 404 index.html, SPA.
nginx.confuser 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 . nginx 19,7 . .
SPA ? , , RESTful API . SPA . - , . . CI, , , CD .
, . , . nginx, shell-, , , nginx.
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 "$"v}')\'
for f in "$TARGET_DIR"/main*.js; do
echo "$(envsubst "$ENV_VARS" < "$f")" > "$f"
done
}
compress () {
for i in $(find "$TARGET_DIR" | grep -E "\.css$|\.html$|\.js$|\.svg$|\.txt$|\.ttf$"); 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}
.
, SPA . , . - , , .
, , , - . , .
-.
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;"]
-.