-
Notifications
You must be signed in to change notification settings - Fork 15
Templates
A Taisun stack template is a single YAML file that will render as a web form for a normal user to launch a Docker Compose command with their variables swapped into the compose file.
A Docker compose file can be a single container or a series of containers that make up a complex application deployment, more here:
https://docs.docker.com/compose/compose-file/
The file is broken into 3 main sections:
- name/description- Here you can define the listed name of the application and a Markdown description of the application.
- form- This is used to define the inputs you want to capture from the user.
- compose- This is the actual compose file that will be executed on the users machine.
Example:
name: Hello World
description: |
An h1 header
============
Paragraphs are separated by a blank line.
2nd paragraph. *Italic*, **bold**, and `monospace`. Itemized lists
look like:
* this one
* that one
* the other one
Here we can see we are using the Pipe symbol in YAML to define a multi line string that is our markdown description. When the Template is loaded in the Taisun application it will be rendered and presented to the user above the input form. IE for this example:
The form section of the template file accepts the following input types:
- input- Basic text box used for single string input.
- select- Dropdown with predefined options for the user.
- textarea- A large text box used to capture arrays of values from the user with line breaks as the delimiter.
- checkbox- Simple on off switch for the user, presents true/false for templating.
- hidden- If you need no user input, this will present nothing in the form area.
We recommend including an input type labeled as "name" so the stackname in the web interface is shown as this versus a randomly generated guid.
Form input will be grabbed and passed to the compose template based on the "label" string that it is set to.
Example:
- type: input
label: name
FormName: Name
placeholder: Unique Name to identify
Every one of these variables is required and will produce the following output:
If you have a requirement to pre-fill in the form you can also pass a value:
- type: input
label: name
FormName: Name
placeholder: Unique Name to identify
value: myname
Producing:
Example:
- type: select
label: myvar
FormName: My Variable
options:
- option1
- option2
Here the user will be able to choose two hard coded values:
Example:
- type: textarea
label: ports
FormName: Application Ports
placeholder: To enter multiple use line breaks (enter) Format <hostport>:<containerport>
As stated earlier the textarea form type is useful when you need to capture an unknown amount of variables. The input of this form will always be presented to the compose rendering as an Array, so even if only one value is passed by the user you will still need to "for loop" it in order to add the value to your compose file.
The example above will yield:
Example:
- type: checkbox
label: test
FormName: Test?
Yielding:
The checkbox form type will return either:
- true
- false
This can be used in basic if statements for Compose file rendering logic.
The simplelest way to implement form validation is to simply pass the required: true in the form section of your template. IE:
- type: input
label: name
FormName: Name
placeholder: Unique Name to identify
required: true
If the user fails to fill out this field they will be prompted to do so.
If you wish to do more advanced form checking you can do so in the form of regexp sequences. These validations work in a pair of values:
- validation- the regexp string
- errormessage- the text that will be displayed to the user if it does not pass your regexp.
Any regexp string will be valid here so you can customize it to your needs, here are some common examples:
- type: textarea
label: ports
FormName: Ports
placeholder: To enter multiple use line breaks (enter) Format hostport:containerport
validation: ^([1-9]|[1-8][0-9]|9[0-9]|[1-8][0-9]{2}|9[0-8][0-9]|99[0-9]|[1-8][0-9]{3}|9[0-8][0-9]{2}|99[0-8][0-9]|999[0-9]|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5])+(:([1-9]|[1-8][0-9]|9[0-9]|[1-8][0-9]{2}|9[0-8][0-9]|99[0-9]|[1-8][0-9]{3}|9[0-8][0-9]{2}|99[0-8][0-9]|999[0-9]|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5]))$
errormessage: Values must be in the format hostport:containerport 1-65535
- type: textarea
label: volumes
FormName: Volumes
placeholder: To enter multiple use line breaks (enter) Format /hostfolder:/containerfolder
validation: ^([\/A-Za-z0-9._~()'!*:@,;+?-]+:[\/A-Za-z0-9._~()'!*:@,;+?-]+)*$
errormessage: Values must be in the format /hostfolder:/containerfolder
- type: textarea
label: envars
FormName: Environment Variables
placeholder: To enter multiple use line breaks (enter) Format MYENVVALUE=SOMEVALUE
validation: ^([\/A-Za-z0-9._~()'!*:@,;+?-]+=[\/A-Za-z0-9._~()'!*:@,;+?-]+)*$
errormessage: Values must be in the format MYENVVALUE=SOMEVALUE
- type: input
format: text
label: myappport
FormName: My App Port
placeholder: This port is the default port for the application
validation: ^([1-9]|[1-8][0-9]|9[0-9]|[1-8][0-9]{2}|9[0-8][0-9]|99[0-9]|[1-8][0-9]{3}|9[0-8][0-9]{2}|99[0-8][0-9]|999[0-9]|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5])$
errormessage: Values must be in a valid port range 1-65535
This is useful if your container needs to communicate with the host for some reason or proxy a connection to it as the host IP is not available to the container.
- type: input
format: text
label: serverip
FormName: Server IP
placeholder: The local IP of your server
validation: ^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$
errormessage: Value must be a valid IP IE 192.168.1.100
The compose section of the Stack Template is where all of the user input will be parsed into a usable Docker Compose file. The engine used for templating is NunJucks . Any logic baked into the NunJucks engine can be used inside of this section.
Lets take a look at a minimum Compose file example:
compose: |
version: "3"
services:
{{ name }}:
image: hello-world:latest
network_mode: bridge
labels:
- "stackname={{ stackname }}"
- "stacktype={{ stacktype }}"
- "stackurl={{ stackurl }}"
- "appport=8888"
The following variables are required as meta data on all containers:
- stackname
- stacktype
- stackurl
The input for these variables is automatically generated by Taisun no need to put them in your form section.
Also on exactly one container in your stack you need to define
- appport
This will be the clickable link for the user to launch your application.
If multiple web applications links are needed you can pass an array here IE:
- appport=[{"Rocket.Chat":"{{ rocketport }}"},{"Mongo-Express":"{{ mongoport }}"}]
This format will present the user with a drop down menu when launching the application to select which web based app to open:
If they are left out the compose file Taisun will be unable to render the access link or information on the Stacks page of the application.
Lets assemble everything we have entered into a single file:
name: Hello World
description: |
An h1 header
============
Paragraphs are separated by a blank line.
2nd paragraph. *Italic*, **bold**, and `monospace`. Itemized lists
look like:
* this one
* that one
* the other one
form:
- type: input
label: name
FormName: Name
placeholder: Unique Name to identify
- type: select
label: myvar
FormName: My Variable
options:
- option1
- option2
- type: textarea
label: ports
FormName: Application Ports
placeholder: To enter multiple use line breaks (enter) Format <hostport>:<containerport>
- type: checkbox
label: test
FormName: Test?
compose: |
version: "3"
services:
{{ name }}:
image: hello-world:latest
network_mode: bridge
labels:
- "stackname={{ stackname }}"
- "stacktype={{ stacktype }}"
- "stackurl={{ stackurl }}"
- "appport=8888"
Presented to the user this will look like:
Now in this example we are not using any of our variables so lets look at a more complex example building on these inputs:
name: Hello World
description: |
An h1 header
============
Paragraphs are separated by a blank line.
2nd paragraph. *Italic*, **bold**, and `monospace`. Itemized lists
look like:
* this one
* that one
* the other one
form:
- type: input
label: name
FormName: Name
placeholder: Unique Name to identify
- type: select
label: myvar
FormName: My Variable
options:
- option1
- option2
- type: textarea
label: ports
FormName: Application Ports
placeholder: To enter multiple use line breaks (enter) Format <hostport>:<containerport>
- type: checkbox
label: test
FormName: Test?
compose: |
version: "3"
services:
{{ name }}:
image: hello-world:{% if test == 'true' %}testing{% else %}latest{% endif %}
network_mode: bridge
ports:
- "8888:8888"
{% if ports %}{% for port in ports %}- "{{ port }}"
{% endfor %}{% endif %}
labels:
- "stackname={{ stackname }}"
- "stacktype={{ stacktype }}"
- "stackurl={{ stackurl }}"
- "appport=8888"
environment:
- "MYVAR={{ myvar }}"
Best practice is to wrap potentially non existent variables (if the user does not fill them out) in an if statement, we used that for the ports variable here.
So above we are using a different image tag based on the user checking the "Test?" box. If the user entered port mapping we will loop through the entries and add them to the container.
NunJucks is very versatile, to read more about the options you can use:
https://mozilla.github.io/nunjucks/templating.html
Lets take a look at a more complex real world example :
name: Rocket.Chat
description: |
Rocket.Chat [_/rocket.chat](https://hub.docker.com/_/rocket.chat/)
============
[Rocket.Chat](https://rocket.chat/) is free, unlimited and open source. Replace email & Slack with the ultimate team chat software solution.
### Parameters
* Rocket.Chat Port - Port Rocket.Chat will listen on the host standard is 3000
* Mongo-Express Port - Port Mongo-Express will listen on the host standard is 8081
* Mongo Directory - Host folder for the MongoDB data tied into Rocket Chat
* Rocket Directory - Optional folder to store RocketChat Uploads, the application will use GridFS by default, set this folder if you want to use local folders
form:
- type: input
label: name
FormName: Stack Name
placeholder: Single word to identify this application IE RocketChat
validation: ^[\w\d-\_]+$
errormessage: Name must only container letters, numbers, and - or _
required: true
- type: input
label: rocketport
FormName: RocketChat Port
placeholder: Port RocketChat will listen on the host standard is 3000
validation: ^([1-9]|[1-8][0-9]|9[0-9]|[1-8][0-9]{2}|9[0-8][0-9]|99[0-9]|[1-8][0-9]{3}|9[0-8][0-9]{2}|99[0-8][0-9]|999[0-9]|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5])$
errormessage: Values must be in a valid port range 1-65535
required: true
- type: input
label: mongoport
FormName: Mongo-Express Port
placeholder: Port Mongo-Express will listen on the host standard is 8081
validation: ^([1-9]|[1-8][0-9]|9[0-9]|[1-8][0-9]{2}|9[0-8][0-9]|99[0-9]|[1-8][0-9]{3}|9[0-8][0-9]{2}|99[0-8][0-9]|999[0-9]|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5])$
errormessage: Values must be in a valid port range 1-65535
required: true
- type: input
label: mongodir
FormName: Mongo Directory
placeholder: The folder to store MongoDB data IE /home/user/mongodb
required: true
- type: input
label: rocketdir
FormName: Rocket Directory
placeholder: Optional folder to store RocketChat Uploads Default is in Mongo GridFS
compose: |
version: "3"
services:
mongo:
image: mongo:latest
container_name: {{ name }}_mongo
restart: always
labels:
- "stackname={{ stackname }}"
- "stacktype={{ stacktype }}"
- "stackurl={{ stackurl }}"
volumes:
- {{ mongodir }}:/data/db
- {{ mongodir }}/configdb:/data/configdb
rocketchat:
image: rocket.chat:latest
container_name: {{ name }}_rocketchat
restart: always
depends_on:
- mongo
labels:
- "stackname={{ stackname }}"
- "stacktype={{ stacktype }}"
- "stackurl={{ stackurl }}"
- appport=[{"Rocket.Chat":"{{ rocketport }}"},{"Mongo-Express":"{{ mongoport }}"}]
{% if rocketdir %}volumes:
- {{ rocketdir }}:/app/uploads{% endif %}
environment:
- MONGO_URL=mongodb://mongo:27017/rocketchat
ports:
- "{{ rocketport }}:3000"
mongoexpress:
restart: always
depends_on:
- mongo
labels:
- "stackname={{ stackname }}"
- "stacktype={{ stacktype }}"
- "stackurl={{ stackurl }}"
image: mongo-express:latest
environment:
- ME_CONFIG_MONGODB_SERVER=mongo
ports:
- {{ mongoport }}:8081
In this stack we will be spinning up a total of 3 containers and linking them all to eachother.
In order to vet a Template or to use one not shared at https://stacks.taisun.io/ you can manually upload and edit YAML in the Taisun web interface.
After clicking on the Upload YAML button under the Stacks page:
You will be presented with a YAML syntax highlighting editor:
From here you can review and modify the template.
When you are satisfied clicking "Upload" will bring you to the same launch page a user will be presented. This is not just an example of the input, you can use this form to proceed to launch your stack.
If your stack can be used by other users on the platform there is a central repository of stack files located at:
Uploading to the central site requires that you have a github account https://github.com/join .
After you login a button will be available to upload your stack:
Simply fill out the form with the information you want to include for your stack including entering the yaml template in the built in editor:
If you ever want to remove your stack click on the delete button next to it and confirm:
All stacks on this page will be available to install from the User UI of Taisun