Home

Awesome

Smalte

CircleCI GitHub tag GitHub

Smalte – is a small template engine. Dynamically configure applications that require static configuration in docker container. This is best replacement for envsubst. Example of usage.

Written in nim-lang and compiled to C. Fast. Binary size (197kb).

TL;DR

Replaces env variables with values from global system scope:

smalte build /etc/nginx/nginx_spa.conf.tmpl:/etc/nginx/nginx_spa.conf

Why?

If you using envsubst utility for dynamically configure the application, you have to go ugly compromises, like this:

# Example of nginx config template for envsubst.
server {
    listen       $PORT;
    server_name  localhost;
    root $NGINX_WEBROOT;

    client_header_timeout $NGINX_CLIENT_HEADER_TIMEOUT;
    client_body_timeout $NGINX_CLIENT_BODY_TIMEOUT;
    client_max_body_size $NGINX_MAX_BODY_SIZE;

    location / {
        try_files ${DOLLAR}uri ${DOLLAR}uri/ @rewrites;
    }

    location @rewrites {
        rewrite ^(.+)$ /index.html last;
    }

    location ~* \.(?:ico|css|js|gif|jpe?g|png)$ {
        # Some basic cache-control for static files to be sent to the browser
        expires max;
        add_header Pragma public;
        add_header Cache-Control "public, must-revalidate, proxy-revalidate";
    }

    # redirect server error pages to the static page /50x.html
    #
    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   $NGINX_WEBROOT;
    }
}

Do you see ugly ${DOLLAR} solution? It's not readable and just terrible. Also envsubst if not found any variable in the system scope, he replaces her with an empty string (if replace ${DOLLAR}uri with $uri in this config and was run envsubst again, variable $url will be replaced to empty string). It is not comfortable.

To resolve this problem I was created this small template engine.

Guide

This is a full guide includes work with docker image.

  1. Create a new template file with environment variables which need to be replaced. How example, the same config on the top:
server {
    listen       $PORT;
    server_name  localhost;
    root $NGINX_WEBROOT;

    client_header_timeout $NGINX_CLIENT_HEADER_TIMEOUT;
    client_body_timeout $NGINX_CLIENT_BODY_TIMEOUT;
    client_max_body_size $NGINX_MAX_BODY_SIZE;

    location / {
        try_files $uri $uri/ @rewrites;
    }

    location @rewrites {
        rewrite ^(.+)$ /index.html last;
    }

    location ~* \.(?:ico|css|js|gif|jpe?g|png)$ {
        # Some basic cache-control for static files to be sent to the browser
        expires max;
        add_header Pragma public;
        add_header Cache-Control "public, must-revalidate, proxy-revalidate";
    }

    # redirect server error pages to the static page /50x.html
    #
    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   $NGINX_WEBROOT;
    }
}

Real example.

  1. Give the name to him and add .tmpl extension (extension not required, but this more readable), for example: nginx_spa.conf.tmpl

Real example.

  1. Create a new entry.sh the script, define default env variables and write command to replace theirs.
#!/usr/bin/env sh

export PORT=${PORT:=8080}
export NGINX_WEBROOT=${NGINX_WEBROOT:="/srv/www"}
export NGINX_CLIENT_HEADER_TIMEOUT=${NGINX_HEADER_TIMEOUT:="120s"}
export NGINX_CLIENT_BODY_TIMEOUT=${NGINX_BODY_TIMEOUT:="120s"}
export NGINX_MAX_BODY_SIZE=${NGINX_MAX_BODY_SIZE:="2G"}

# replace variables before start
smalte build --scope PORT --scope NGINX\.* \
    /etc/nginx/nginx_spa.conf.tmpl:/etc/nginx/conf.d/default.conf

# run nginx as main container process
nginx -g "daemon off;"

Before : symbol places path to the template file, after – to result of the build. --scope option reduces the list of global env variables to the selected. Supports regular expressions.

Real example

  1. Copy config template file and smalte binary to you Docker-image:
FROM nginx:mainline-alpine

ENV NGINX_WEBROOT /usr/share/nginx/html
ENV PORT 8080

COPY nginx_spa.conf.tmpl /etc/nginx/nginx_spa.conf.tmpl
# chmod +x ./entry.sh before copy paste to image.
COPY entry.sh /
COPY --from=roquie/smalte:latest-alpine /app/smalte /usr/local/bin/smalte

WORKDIR /usr/share/nginx/html

CMD ["/entry.sh"]

Real example

  1. Build docker-image and run. Enjoy.

Files used in guide located in the example directory. More examples can be found in the tests folder. Also, available Docker-image where using this helper: https://github.com/roquie/docker-php-webapp

Example how to overwrite env variable at run

Just pass defined variables to -e options of docker run command, like this:

docker run -it --rm -e PORT=3000 -p 9090:3000 roquie/docker-php-webapp:latest

By default, this container uses 8080 port for nginx. At startup, I replaced the port with a different value (3000) uses the $PORT environment variable.

Test it:

$ curl http://localhost:9090
$ Hello world

Depends

Docker

Available Docker images for Ubuntu 18.04 and Alpine 3.8

CLI Help

> Smalte - is a dead simple and lightweight template engine.

  Example:
    ./smalte build --scope NGINX\.* --scope NPM \
                test.conf.tmpl:test.conf \
                test.conf.tmpl:test2.conf \
                test.conf.tmpl:testN.conf

  Usage:
    smalte build [--scope=<scope> ...] <inputfile:outputfile>...
    smalte (-h | --help)
    smalte (-v | --version)

  Options:

    -h --help      Show this screen.
    -v --version   Show version.

Usage from a Docker container

FROM ubuntu:18.04
COPY --from=roquie/smalte:latest /app/smalte /usr/local/bin/smalte

CMD ["/usr/local/bin/smalte"]

The MIT License (MIT)

Copyright (c)

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.