Skip to content

Commit 516b4dc

Browse files
authored
Merge pull request #81 from SensorsIot/udpate-documentation-custom-settings
Expanded upon custom services and settings
2 parents d85d5b1 + ff99331 commit 516b4dc

File tree

2 files changed

+146
-11
lines changed

2 files changed

+146
-11
lines changed

docs/Custom.md

Lines changed: 132 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,41 @@
1-
# Custom containers and settings for docker-compose
1+
# Custom services and overriding default settings for IOTstack
22
You can specify modifcations to the `docker-compose.yml` file, including your own networks and custom containers/services.
33

44
Create a file called `compose-override.yml` in the main directory, and place your modifications into it. These changes will be merged into the `docker-compose.yml` file next time you run the build script.
55

6+
The `compose-override.yml` file has been added to the `.gitignore` file, so it shouldn't be touched when upgrading IOTstack. It has been added to the backup script, and so will be included when you back up and restore IOTstack. Always test your backups though! New versions of IOTstack may break previous builds.
7+
68
## How it works
79
1. After the build process has been completed, a temporary docker compose file is created in the `tmp` directory.
810
2. The script then checks if `compose-override.yml` exists:
9-
1. If it exists, then continue to step `3`
10-
2. If it does not exist, copy the temporary docker compose file to the main directory and rename to `docker-compose.yml`.
11+
* If it exists, then continue to step `3`
12+
* If it does not exist, copy the temporary docker compose file to the main directory and rename it to `docker-compose.yml`.
1113
3. Using the `yaml_merge.py` script, merge both the `compose-override.yml` and the temporary docker compose file together; Using the temporary file as the default values and interating through each level of the yaml structure, check to see if the `compose-override.yml` has a value set.
1214
4. Output the final file to the main directory, calling it `docker-compose.yml`.
1315

14-
## Example
15-
For example, lets assume you put the following into the `compose-override.yml` file:
16+
## A word of caution
17+
If you specify an override for a service, and then rebuild the `docker-compose.yml` file, but deselect the service from the list, then the YAML merging will still produce that override.
18+
19+
For example, lets say NodeRed was selected to have have the following override specified in `compose-override.yml`:
20+
```
21+
services:
22+
nodered:
23+
restart: always
24+
```
25+
26+
When rebuilding the menu, ensure to have NodeRed service always included because if it's no longer included, the only values showing in the final `docker-compose.yml` file for NodeRed will be the `restart` key and its value. Docker Compose will error with the following message:
27+
```
28+
Service nodered has neither an image nor a build context specified. At least one must be provided.
29+
```
30+
31+
When attempting to bring the services up with `docker-compose up -d`.
32+
33+
Either remove the override for NodeRed in `compose-override.yml` and rebuild the stack, or ensure that NodeRed is built with the stack to fix this.
34+
35+
## Examples
36+
37+
### Overriding default settings
38+
Lets assume you put the following into the `compose-override.yml` file:
1639
```
1740
services:
1841
mosquitto:
@@ -89,3 +112,107 @@ services:
89112
- ./services/mosquitto/mosquitto.conf:/mosquitto/config/mosquitto.conf
90113
- ./services/mosquitto/filter.acl:/mosquitto/config/filter.acl
91114
```
115+
116+
### Adding custom services
117+
118+
Custom services can be added in a similar way to overriding default settings for standard services. Lets add a Minecraft and rcon server to IOTstack.
119+
Firstly, put the following into `compose-override.yml`:
120+
```
121+
services:
122+
mosquitto:
123+
ports:
124+
- 1996:1996
125+
- 9001:9001
126+
minecraft:
127+
image: itzg/minecraft-server
128+
ports:
129+
- "25565:25565"
130+
volumes:
131+
- "./volumes/minecraft:/data"
132+
environment:
133+
EULA: "TRUE"
134+
TYPE: "PAPER"
135+
ENABLE_RCON: "true"
136+
RCON_PASSWORD: "PASSWORD"
137+
RCON_PORT: 28016
138+
VERSION: "1.15.2"
139+
REPLACE_ENV_VARIABLES: "TRUE"
140+
ENV_VARIABLE_PREFIX: "CFG_"
141+
CFG_DB_HOST: "http://localhost:3306"
142+
CFG_DB_NAME: "IOTstack Minecraft"
143+
CFG_DB_PASSWORD_FILE: "/run/secrets/db_password"
144+
restart: unless-stopped
145+
rcon:
146+
image: itzg/rcon
147+
ports:
148+
- "4326:4326"
149+
- "4327:4327"
150+
volumes:
151+
- "./volumes/rcon_data:/opt/rcon-web-admin/db"
152+
secrets:
153+
db_password:
154+
file: ./db_password
155+
```
156+
157+
Then create the service directory that the new instance will use to store persistant data:
158+
159+
`mkdir -p ./volumes/minecraft`
160+
161+
and
162+
163+
`mkdir -p ./volumes/rcon_data`
164+
165+
Obviously you will need to give correct folder names depending on the `volumes` you specify for your custom services. If your new service doesn't require persistant storage, then you can skip this step.
166+
167+
Then simply run the `./menu.sh` command, and rebuild the stack with what ever services you had before.
168+
169+
Using the Mosquitto example above, the final `docker-compose.yml` file will look like:
170+
171+
```
172+
version: '3.6'
173+
services:
174+
mosquitto:
175+
ports:
176+
- 1996:1996
177+
- 9001:9001
178+
container_name: mosquitto
179+
image: eclipse-mosquitto
180+
restart: unless-stopped
181+
user: '1883'
182+
volumes:
183+
- ./volumes/mosquitto/data:/mosquitto/data
184+
- ./volumes/mosquitto/log:/mosquitto/log
185+
- ./services/mosquitto/mosquitto.conf:/mosquitto/config/mosquitto.conf
186+
- ./services/mosquitto/filter.acl:/mosquitto/config/filter.acl
187+
minecraft:
188+
image: itzg/minecraft-server
189+
ports:
190+
- 25565:25565
191+
volumes:
192+
- ./volumes/minecraft:/data
193+
environment:
194+
EULA: 'TRUE'
195+
TYPE: PAPER
196+
ENABLE_RCON: 'true'
197+
RCON_PASSWORD: PASSWORD
198+
RCON_PORT: 28016
199+
VERSION: 1.15.2
200+
REPLACE_ENV_VARIABLES: 'TRUE'
201+
ENV_VARIABLE_PREFIX: CFG_
202+
CFG_DB_HOST: http://localhost:3306
203+
CFG_DB_NAME: IOTstack Minecraft
204+
CFG_DB_PASSWORD_FILE: /run/secrets/db_password
205+
restart: unless-stopped
206+
rcon:
207+
image: itzg/rcon
208+
ports:
209+
- 4326:4326
210+
- 4327:4327
211+
volumes:
212+
- ./volumes/rcon_data:/opt/rcon-web-admin/db
213+
secrets:
214+
db_password:
215+
file: ./db_password
216+
```
217+
218+
Do note that the order of the YAML keys is not guaranteed.

scripts/yaml_merge.py

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,21 @@
2727
pathOutput = sys.argv[3]
2828

2929
def mergeYaml(priorityYaml, defaultYaml):
30-
if isinstance(priorityYaml, dict) and isinstance(defaultYaml, dict):
31-
for k, v in defaultYaml.iteritems():
32-
if k not in priorityYaml:
33-
priorityYaml[k] = v
30+
finalYaml = {}
31+
if isinstance(defaultYaml, dict):
32+
for dk, dv in defaultYaml.items():
33+
if dk in priorityYaml:
34+
finalYaml[dk] = mergeYaml(priorityYaml[dk], dv)
3435
else:
35-
priorityYaml[k] = mergeYaml(priorityYaml[k], v)
36-
return defaultYaml
36+
finalYaml[dk] = dv
37+
for pk, pv in priorityYaml.items():
38+
if pk in finalYaml:
39+
finalYaml[pk] = mergeYaml(finalYaml[pk], pv)
40+
else:
41+
finalYaml[pk] = pv
42+
else:
43+
finalYaml = defaultYaml
44+
return finalYaml
3745

3846
with open(r'%s' % pathTempDockerCompose) as fileTempDockerCompose:
3947
yamlTempDockerCompose = yaml.load(fileTempDockerCompose, Loader=yaml.SafeLoader)

0 commit comments

Comments
 (0)